decorated_textfield.cc revision f2477e01787aa58f445919b809d89e252beef54f
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
15namespace {
16
17// Padding around icons inside DecoratedTextfields.
18const int kTextfieldIconPadding = 3;
19
20}  // namespace
21
22namespace autofill {
23
24// static
25const char DecoratedTextfield::kViewClassName[] = "autofill/DecoratedTextfield";
26
27const int DecoratedTextfield::kMagicInsetNumber = 6;
28
29DecoratedTextfield::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
48DecoratedTextfield::~DecoratedTextfield() {}
49
50void 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
62void 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
80void 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
97void 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
112base::string16 DecoratedTextfield::GetPlaceholderText() const {
113  if (!editable_)
114    return base::string16();
115
116  return views::Textfield::GetPlaceholderText();
117}
118
119const char* DecoratedTextfield::GetClassName() const {
120  return kViewClassName;
121}
122
123views::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
130void DecoratedTextfield::OnFocus() {
131  border_->set_has_focus(true);
132  views::Textfield::OnFocus();
133  SchedulePaint();
134}
135
136void DecoratedTextfield::OnBlur() {
137  border_->set_has_focus(false);
138  views::Textfield::OnBlur();
139  SchedulePaint();
140}
141
142gfx::Size DecoratedTextfield::GetPreferredSize() {
143  int w = views::Textfield::GetPreferredSize().width();
144  views::LabelButton button(NULL, string16());
145  button.SetStyle(views::Button::STYLE_BUTTON);
146  int h = button.GetPreferredSize().height();
147  return gfx::Size(w, h - kMagicInsetNumber);
148}
149
150void DecoratedTextfield::Layout() {
151  views::Textfield::Layout();
152
153  if (icon_view_ && icon_view_->visible()) {
154    gfx::Rect bounds = GetContentsBounds();
155    gfx::Size icon_size = icon_view_->GetPreferredSize();
156    int x = base::i18n::IsRTL() ?
157        kTextfieldIconPadding :
158        bounds.right() - icon_size.width() - kTextfieldIconPadding;
159    // Vertically centered.
160    int y = bounds.y() + (bounds.height() - icon_size.height()) / 2;
161    icon_view_->SetBounds(x,
162                          y,
163                          icon_size.width(),
164                          icon_size.height());
165  }
166}
167
168void DecoratedTextfield::UpdateBackground() {
169  set_background(
170      views::Background::CreateSolidBackground(GetBackgroundColor()));
171}
172
173void DecoratedTextfield::IconChanged() {
174  // Don't show the icon if nothing else is showing.
175  icon_view_->SetVisible(editable_ || !text().empty());
176
177  int icon_space = icon_view_ ?
178      icon_view_->GetPreferredSize().width() + 2 * kTextfieldIconPadding : 0;
179
180  bool is_rtl = base::i18n::IsRTL();
181  SetHorizontalMargins(is_rtl ? icon_space : 0, is_rtl ? 0 : icon_space);
182
183  Layout();
184  SchedulePaint();
185}
186
187} // namespace autofill
188