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