decorated_textfield.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/autofill/decorated_textfield.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/autofill/autofill_dialog_types.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/autofill/tooltip_icon.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/background.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/button/label_button.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/focusable_border.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/textfield/textfield_controller.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding around icons inside DecoratedTextfields. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTextfieldIconPadding = 3; 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace autofill { 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char DecoratedTextfield::kViewClassName[] = "autofill/DecoratedTextfield"; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DecoratedTextfield::DecoratedTextfield( 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::string16& default_value, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const base::string16& placeholder, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) views::TextfieldController* controller) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : invalid_(false), 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) editable_(true) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateBackground(); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateBorder(); 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_placeholder_text(placeholder); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetText(default_value); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_controller(controller); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DecoratedTextfield::~DecoratedTextfield() {} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DecoratedTextfield::SetInvalid(bool invalid) { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (invalid_ == invalid) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) invalid_ = invalid; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateBorder(); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DecoratedTextfield::SetEditable(bool editable) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (editable_ == editable) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) editable_ = editable; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateBackground(); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEnabled(editable); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IconChanged(); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DecoratedTextfield::SetIcon(const gfx::Image& icon) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!icon_view_ && icon.IsEmpty()) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (icon_view_) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveChildView(icon_view_.get()); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!icon.IsEmpty()) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_view_.reset(new views::ImageView()); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_view_->set_owned_by_client(); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icon_view_->SetImage(icon.ToImageSkia()); 73 AddChildView(icon_view_.get()); 74 } 75 76 IconChanged(); 77} 78 79void DecoratedTextfield::SetTooltipIcon(const base::string16& text) { 80 if (!icon_view_ && text.empty()) 81 return; 82 83 if (icon_view_) 84 RemoveChildView(icon_view_.get()); 85 86 if (!text.empty()) { 87 icon_view_.reset(new TooltipIcon(text)); 88 AddChildView(icon_view_.get()); 89 } 90 91 IconChanged(); 92} 93 94base::string16 DecoratedTextfield::GetPlaceholderText() const { 95 return editable_ ? views::Textfield::GetPlaceholderText() : base::string16(); 96} 97 98const char* DecoratedTextfield::GetClassName() const { 99 return kViewClassName; 100} 101 102views::View* DecoratedTextfield::GetEventHandlerForRect(const gfx::Rect& rect) { 103 views::View* handler = views::Textfield::GetEventHandlerForRect(rect); 104 if (handler->GetClassName() == TooltipIcon::kViewClassName) 105 return handler; 106 return this; 107} 108 109gfx::Size DecoratedTextfield::GetPreferredSize() { 110 static const int height = 111 views::LabelButton(NULL, base::string16()).GetPreferredSize().height(); 112 const gfx::Size size = views::Textfield::GetPreferredSize(); 113 return gfx::Size(size.width(), std::max(size.height(), height)); 114} 115 116void DecoratedTextfield::Layout() { 117 views::Textfield::Layout(); 118 119 if (icon_view_ && icon_view_->visible()) { 120 gfx::Rect bounds = GetContentsBounds(); 121 gfx::Size icon_size = icon_view_->GetPreferredSize(); 122 int x = base::i18n::IsRTL() ? 123 bounds.x() - icon_size.width() - kTextfieldIconPadding : 124 bounds.right() + kTextfieldIconPadding; 125 // Vertically centered. 126 int y = bounds.y() + (bounds.height() - icon_size.height()) / 2; 127 gfx::Rect icon_bounds(x, y, icon_size.width(), icon_size.height()); 128 icon_bounds.set_x(GetMirroredXForRect(icon_bounds)); 129 icon_view_->SetBoundsRect(icon_bounds); 130 } 131} 132 133void DecoratedTextfield::UpdateBackground() { 134 if (editable_) 135 UseDefaultBackgroundColor(); 136 else 137 SetBackgroundColor(SK_ColorTRANSPARENT); 138 set_background( 139 views::Background::CreateSolidBackground(GetBackgroundColor())); 140} 141 142void DecoratedTextfield::UpdateBorder() { 143 scoped_ptr<views::FocusableBorder> border(new views::FocusableBorder()); 144 if (invalid_) 145 border->SetColor(kWarningColor); 146 else if (!editable_) 147 border->SetColor(SK_ColorTRANSPARENT); 148 149 // Adjust the border insets to include the icon and its padding. 150 if (icon_view_ && icon_view_->visible()) { 151 int w = icon_view_->GetPreferredSize().width() + 2 * kTextfieldIconPadding; 152 gfx::Insets insets = border->GetInsets(); 153 int left = insets.left() + (base::i18n::IsRTL() ? w : 0); 154 int right = insets.right() + (base::i18n::IsRTL() ? 0 : w); 155 border->SetInsets(insets.top(), left, insets.bottom(), right); 156 } 157 158 SetBorder(border.PassAs<views::Border>()); 159} 160 161void DecoratedTextfield::IconChanged() { 162 // Don't show the icon if nothing else is showing. 163 icon_view_->SetVisible(editable_ || !text().empty()); 164 UpdateBorder(); 165 Layout(); 166} 167 168} // namespace autofill 169