1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/views/autofill/decorated_textfield.h" 6 7 #include "chrome/browser/ui/autofill/autofill_dialog_types.h" 8 #include "chrome/browser/ui/views/autofill/tooltip_icon.h" 9 #include "ui/gfx/canvas.h" 10 #include "ui/views/background.h" 11 #include "ui/views/controls/button/label_button.h" 12 #include "ui/views/controls/focusable_border.h" 13 #include "ui/views/controls/textfield/textfield_controller.h" 14 15 namespace { 16 17 // Padding around icons inside DecoratedTextfields. 18 const int kTextfieldIconPadding = 3; 19 20 } // namespace 21 22 namespace autofill { 23 24 // static 25 const char DecoratedTextfield::kViewClassName[] = "autofill/DecoratedTextfield"; 26 27 const int DecoratedTextfield::kMagicInsetNumber = 6; 28 29 DecoratedTextfield::DecoratedTextfield( 30 const base::string16& default_value, 31 const base::string16& placeholder, 32 views::TextfieldController* controller) 33 : border_(new views::FocusableBorder()), 34 invalid_(false), 35 editable_(true) { 36 UpdateBackground(); 37 38 set_border(border_); 39 // Removes the border from |native_wrapper_|. 40 RemoveBorder(); 41 42 set_placeholder_text(placeholder); 43 SetText(default_value); 44 SetController(controller); 45 SetHorizontalMargins(0, 0); 46 } 47 48 DecoratedTextfield::~DecoratedTextfield() {} 49 50 void DecoratedTextfield::SetInvalid(bool invalid) { 51 invalid_ = invalid; 52 if (!editable_) 53 return; 54 55 if (invalid) 56 border_->SetColor(kWarningColor); 57 else 58 border_->UseDefaultColor(); 59 SchedulePaint(); 60 } 61 62 void DecoratedTextfield::SetEditable(bool editable) { 63 if (editable_ == editable) 64 return; 65 66 editable_ = editable; 67 if (editable) { 68 SetInvalid(invalid_); 69 UseDefaultBackgroundColor(); 70 } else { 71 border_->SetColor(SK_ColorTRANSPARENT); 72 SetBackgroundColor(SK_ColorTRANSPARENT); 73 } 74 75 UpdateBackground(); 76 SetEnabled(editable); 77 IconChanged(); 78 } 79 80 void DecoratedTextfield::SetIcon(const gfx::Image& icon) { 81 if (!icon_view_ && icon.IsEmpty()) 82 return; 83 84 if (icon_view_) 85 RemoveChildView(icon_view_.get()); 86 87 if (!icon.IsEmpty()) { 88 icon_view_.reset(new views::ImageView()); 89 icon_view_->set_owned_by_client(); 90 icon_view_->SetImage(icon.ToImageSkia()); 91 AddChildView(icon_view_.get()); 92 } 93 94 IconChanged(); 95 } 96 97 void DecoratedTextfield::SetTooltipIcon(const base::string16& text) { 98 if (!icon_view_ && text.empty()) 99 return; 100 101 if (icon_view_) 102 RemoveChildView(icon_view_.get()); 103 104 if (!text.empty()) { 105 icon_view_.reset(new TooltipIcon(text)); 106 AddChildView(icon_view_.get()); 107 } 108 109 IconChanged(); 110 } 111 112 base::string16 DecoratedTextfield::GetPlaceholderText() const { 113 if (!editable_) 114 return base::string16(); 115 116 return views::Textfield::GetPlaceholderText(); 117 } 118 119 const char* DecoratedTextfield::GetClassName() const { 120 return kViewClassName; 121 } 122 123 views::View* DecoratedTextfield::GetEventHandlerForRect(const gfx::Rect& rect) { 124 views::View* handler = views::Textfield::GetEventHandlerForRect(rect); 125 if (handler->GetClassName() == TooltipIcon::kViewClassName) 126 return handler; 127 return native_wrapper_->GetView(); 128 } 129 130 void DecoratedTextfield::OnFocus() { 131 views::Textfield::OnFocus(); 132 SchedulePaint(); 133 } 134 135 void DecoratedTextfield::OnBlur() { 136 views::Textfield::OnBlur(); 137 SchedulePaint(); 138 } 139 140 gfx::Size DecoratedTextfield::GetPreferredSize() { 141 int w = views::Textfield::GetPreferredSize().width(); 142 views::LabelButton button(NULL, base::string16()); 143 button.SetStyle(views::Button::STYLE_BUTTON); 144 int h = button.GetPreferredSize().height(); 145 return gfx::Size(w, h - kMagicInsetNumber); 146 } 147 148 void DecoratedTextfield::Layout() { 149 views::Textfield::Layout(); 150 151 if (icon_view_ && icon_view_->visible()) { 152 gfx::Rect bounds = GetContentsBounds(); 153 gfx::Size icon_size = icon_view_->GetPreferredSize(); 154 int x = base::i18n::IsRTL() ? 155 kTextfieldIconPadding : 156 bounds.right() - icon_size.width() - kTextfieldIconPadding; 157 // Vertically centered. 158 int y = bounds.y() + (bounds.height() - icon_size.height()) / 2; 159 icon_view_->SetBounds(x, 160 y, 161 icon_size.width(), 162 icon_size.height()); 163 } 164 } 165 166 void DecoratedTextfield::UpdateBackground() { 167 set_background( 168 views::Background::CreateSolidBackground(GetBackgroundColor())); 169 } 170 171 void DecoratedTextfield::IconChanged() { 172 // Don't show the icon if nothing else is showing. 173 icon_view_->SetVisible(editable_ || !text().empty()); 174 175 int icon_space = icon_view_ ? 176 icon_view_->GetPreferredSize().width() + 2 * kTextfieldIconPadding : 0; 177 178 bool is_rtl = base::i18n::IsRTL(); 179 SetHorizontalMargins(is_rtl ? icon_space : 0, is_rtl ? 0 : icon_space); 180 181 Layout(); 182 SchedulePaint(); 183 } 184 185 } // namespace autofill 186