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 #include "ui/views/view_targeter.h" 15 16 namespace { 17 18 // Padding around icons inside DecoratedTextfields. 19 const int kTextfieldIconPadding = 3; 20 21 } // namespace 22 23 namespace autofill { 24 25 // static 26 const char DecoratedTextfield::kViewClassName[] = "autofill/DecoratedTextfield"; 27 28 DecoratedTextfield::DecoratedTextfield( 29 const base::string16& default_value, 30 const base::string16& placeholder, 31 views::TextfieldController* controller) 32 : invalid_(false), 33 editable_(true) { 34 UpdateBackground(); 35 UpdateBorder(); 36 37 set_placeholder_text(placeholder); 38 SetText(default_value); 39 set_controller(controller); 40 41 SetEventTargeter( 42 scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); 43 } 44 45 DecoratedTextfield::~DecoratedTextfield() {} 46 47 void DecoratedTextfield::SetInvalid(bool invalid) { 48 if (invalid_ == invalid) 49 return; 50 51 invalid_ = invalid; 52 UpdateBorder(); 53 SchedulePaint(); 54 } 55 56 void DecoratedTextfield::SetEditable(bool editable) { 57 if (editable_ == editable) 58 return; 59 60 editable_ = editable; 61 UpdateBackground(); 62 SetEnabled(editable); 63 IconChanged(); 64 } 65 66 void DecoratedTextfield::SetIcon(const gfx::Image& icon) { 67 if (!icon_view_ && icon.IsEmpty()) 68 return; 69 70 if (icon_view_) 71 RemoveChildView(icon_view_.get()); 72 73 if (!icon.IsEmpty()) { 74 icon_view_.reset(new views::ImageView()); 75 icon_view_->set_owned_by_client(); 76 icon_view_->SetImage(icon.ToImageSkia()); 77 AddChildView(icon_view_.get()); 78 } 79 80 IconChanged(); 81 } 82 83 void DecoratedTextfield::SetTooltipIcon(const base::string16& text) { 84 if (!icon_view_ && text.empty()) 85 return; 86 87 if (icon_view_) 88 RemoveChildView(icon_view_.get()); 89 90 if (!text.empty()) { 91 icon_view_.reset(new TooltipIcon(text)); 92 AddChildView(icon_view_.get()); 93 } 94 95 IconChanged(); 96 } 97 98 base::string16 DecoratedTextfield::GetPlaceholderText() const { 99 return editable_ ? views::Textfield::GetPlaceholderText() : base::string16(); 100 } 101 102 const char* DecoratedTextfield::GetClassName() const { 103 return kViewClassName; 104 } 105 106 gfx::Size DecoratedTextfield::GetPreferredSize() const { 107 static const int height = 108 views::LabelButton(NULL, base::string16()).GetPreferredSize().height(); 109 const gfx::Size size = views::Textfield::GetPreferredSize(); 110 return gfx::Size(size.width(), std::max(size.height(), height)); 111 } 112 113 void DecoratedTextfield::Layout() { 114 views::Textfield::Layout(); 115 116 if (icon_view_ && icon_view_->visible()) { 117 gfx::Rect bounds = GetContentsBounds(); 118 gfx::Size icon_size = icon_view_->GetPreferredSize(); 119 int x = base::i18n::IsRTL() ? 120 bounds.x() - icon_size.width() - kTextfieldIconPadding : 121 bounds.right() + kTextfieldIconPadding; 122 // Vertically centered. 123 int y = bounds.y() + (bounds.height() - icon_size.height()) / 2; 124 gfx::Rect icon_bounds(x, y, icon_size.width(), icon_size.height()); 125 icon_bounds.set_x(GetMirroredXForRect(icon_bounds)); 126 icon_view_->SetBoundsRect(icon_bounds); 127 } 128 } 129 130 views::View* DecoratedTextfield::TargetForRect(views::View* root, 131 const gfx::Rect& rect) { 132 CHECK_EQ(root, this); 133 134 views::View* handler = views::ViewTargeterDelegate::TargetForRect(root, rect); 135 if (handler->GetClassName() == TooltipIcon::kViewClassName) 136 return handler; 137 return this; 138 } 139 140 void DecoratedTextfield::UpdateBackground() { 141 if (editable_) 142 UseDefaultBackgroundColor(); 143 else 144 SetBackgroundColor(SK_ColorTRANSPARENT); 145 set_background( 146 views::Background::CreateSolidBackground(GetBackgroundColor())); 147 } 148 149 void DecoratedTextfield::UpdateBorder() { 150 scoped_ptr<views::FocusableBorder> border(new views::FocusableBorder()); 151 if (invalid_) 152 border->SetColor(kWarningColor); 153 else if (!editable_) 154 border->SetColor(SK_ColorTRANSPARENT); 155 156 // Adjust the border insets to include the icon and its padding. 157 if (icon_view_ && icon_view_->visible()) { 158 int w = icon_view_->GetPreferredSize().width() + 2 * kTextfieldIconPadding; 159 gfx::Insets insets = border->GetInsets(); 160 int left = insets.left() + (base::i18n::IsRTL() ? w : 0); 161 int right = insets.right() + (base::i18n::IsRTL() ? 0 : w); 162 border->SetInsets(insets.top(), left, insets.bottom(), right); 163 } 164 165 SetBorder(border.PassAs<views::Border>()); 166 } 167 168 void DecoratedTextfield::IconChanged() { 169 // Don't show the icon if nothing else is showing. 170 icon_view_->SetVisible(editable_ || !text().empty()); 171 UpdateBorder(); 172 Layout(); 173 } 174 175 } // namespace autofill 176