Add a minor text member to ui::MenuModel.
[chromium-blink-merge.git] / chrome / browser / ui / views / autofill / autofill_popup_view_views.cc
blob2c725f5c5e97ba2ca7a7007de6b2f6b3e2a9be5e
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h"
7 #include "chrome/browser/ui/autofill/autofill_popup_controller.h"
8 #include "grit/ui_resources.h"
9 #include "third_party/WebKit/public/web/WebAutofillClient.h"
10 #include "ui/base/keycodes/keyboard_codes.h"
11 #include "ui/base/resource/resource_bundle.h"
12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/native_widget_types.h"
15 #include "ui/gfx/point.h"
16 #include "ui/gfx/rect.h"
17 #include "ui/gfx/screen.h"
18 #include "ui/views/border.h"
19 #include "ui/views/event_utils.h"
20 #include "ui/views/widget/widget.h"
22 using WebKit::WebAutofillClient;
24 namespace {
26 const SkColor kBorderColor = SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE);
27 const SkColor kHoveredBackgroundColor = SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD);
28 const SkColor kItemTextColor = SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F);
29 const SkColor kPopupBackground = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
30 const SkColor kValueTextColor = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00);
31 const SkColor kWarningTextColor = SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F);
33 } // namespace
35 namespace autofill {
37 AutofillPopupViewViews::AutofillPopupViewViews(
38 AutofillPopupController* controller, views::Widget* observing_widget)
39 : controller_(controller),
40 observing_widget_(observing_widget) {}
42 AutofillPopupViewViews::~AutofillPopupViewViews() {
43 if (controller_) {
44 controller_->ViewDestroyed();
46 HideInternal();
50 void AutofillPopupViewViews::Hide() {
51 // The controller is no longer valid after it hides us.
52 controller_ = NULL;
54 HideInternal();
56 if (GetWidget()) {
57 // Don't call CloseNow() because some of the functions higher up the stack
58 // assume the the widget is still valid after this point.
59 // http://crbug.com/229224
60 // NOTE: This deletes |this|.
61 GetWidget()->Close();
62 } else {
63 delete this;
67 void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) {
68 if (!controller_)
69 return;
71 canvas->DrawColor(kPopupBackground);
72 OnPaintBorder(canvas);
74 for (size_t i = 0; i < controller_->names().size(); ++i) {
75 gfx::Rect line_rect = controller_->GetRowBounds(i);
77 if (controller_->identifiers()[i] ==
78 WebAutofillClient::MenuItemIDSeparator) {
79 canvas->DrawRect(line_rect, kItemTextColor);
80 } else {
81 DrawAutofillEntry(canvas, i, line_rect);
86 void AutofillPopupViewViews::OnMouseCaptureLost() {
87 if (controller_)
88 controller_->MouseExitedPopup();
91 bool AutofillPopupViewViews::OnMouseDragged(const ui::MouseEvent& event) {
92 if (!controller_)
93 return false;
95 if (HitTestPoint(event.location())) {
96 controller_->MouseHovered(event.x(), event.y());
98 // We must return true in order to get future OnMouseDragged and
99 // OnMouseReleased events.
100 return true;
103 // If we move off of the popup, we lose the selection.
104 controller_->MouseExitedPopup();
105 return false;
108 void AutofillPopupViewViews::OnMouseExited(const ui::MouseEvent& event) {
109 if (controller_)
110 controller_->MouseExitedPopup();
113 void AutofillPopupViewViews::OnMouseMoved(const ui::MouseEvent& event) {
114 if (!controller_)
115 return;
117 if (HitTestPoint(event.location()))
118 controller_->MouseHovered(event.x(), event.y());
119 else
120 controller_->MouseExitedPopup();
123 bool AutofillPopupViewViews::OnMousePressed(const ui::MouseEvent& event) {
124 if (HitTestPoint(event.location()))
125 return true;
127 if (controller_->hide_on_outside_click()) {
128 GetWidget()->ReleaseCapture();
130 gfx::Point screen_loc = event.location();
131 views::View::ConvertPointToScreen(this, &screen_loc);
133 ui::MouseEvent mouse_event = event;
134 mouse_event.set_location(screen_loc);
136 if (controller_->ShouldRepostEvent(mouse_event)) {
137 gfx::NativeView native_view = GetWidget()->GetNativeView();
138 gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view);
139 gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc);
140 views::RepostLocatedEvent(window, mouse_event);
143 controller_->Hide();
144 // |this| is now deleted.
147 return false;
150 void AutofillPopupViewViews::OnMouseReleased(const ui::MouseEvent& event) {
151 if (!controller_)
152 return;
154 // Because this view can can be shown in response to a mouse press, it can
155 // receive an OnMouseReleased event just after showing. This breaks the mouse
156 // capture, so restart capturing here.
157 if (controller_->hide_on_outside_click() && GetWidget())
158 GetWidget()->SetCapture(this);
160 // We only care about the left click.
161 if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location()))
162 controller_->MouseClicked(event.x(), event.y());
165 void AutofillPopupViewViews::OnWidgetBoundsChanged(
166 views::Widget* widget,
167 const gfx::Rect& new_bounds) {
168 DCHECK_EQ(widget, observing_widget_);
169 controller_->Hide();
172 void AutofillPopupViewViews::Show() {
173 if (!GetWidget()) {
174 observing_widget_->AddObserver(this);
176 // The widget is destroyed by the corresponding NativeWidget, so we use
177 // a weak pointer to hold the reference and don't have to worry about
178 // deletion.
179 views::Widget* widget = new views::Widget;
180 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
181 params.delegate = this;
182 params.parent = controller_->container_view();
183 widget->Init(params);
184 widget->SetContentsView(this);
187 set_border(views::Border::CreateSolidBorder(kBorderThickness, kBorderColor));
189 UpdateBoundsAndRedrawPopup();
190 GetWidget()->Show();
192 if (controller_->hide_on_outside_click())
193 GetWidget()->SetCapture(this);
196 void AutofillPopupViewViews::InvalidateRow(size_t row) {
197 SchedulePaintInRect(controller_->GetRowBounds(row));
200 void AutofillPopupViewViews::UpdateBoundsAndRedrawPopup() {
201 GetWidget()->SetBounds(controller_->popup_bounds());
202 SchedulePaint();
205 void AutofillPopupViewViews::HideInternal() {
206 observing_widget_->RemoveObserver(this);
209 void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas,
210 int index,
211 const gfx::Rect& entry_rect) {
212 if (controller_->selected_line() == index)
213 canvas->FillRect(entry_rect, kHoveredBackgroundColor);
215 bool is_rtl = controller_->IsRTL();
216 int value_text_width = controller_->GetNameFontForRow(index).GetStringWidth(
217 controller_->names()[index]);
218 int value_content_x = is_rtl ?
219 entry_rect.width() - value_text_width - kEndPadding : kEndPadding;
221 canvas->DrawStringInt(
222 controller_->names()[index],
223 controller_->GetNameFontForRow(index),
224 controller_->IsWarning(index) ? kWarningTextColor : kValueTextColor,
225 value_content_x,
226 entry_rect.y(),
227 canvas->GetStringWidth(controller_->names()[index],
228 controller_->GetNameFontForRow(index)),
229 entry_rect.height(),
230 gfx::Canvas::TEXT_ALIGN_CENTER);
232 // Use this to figure out where all the other Autofill items should be placed.
233 int x_align_left = is_rtl ? kEndPadding : entry_rect.width() - kEndPadding;
235 // Draw the Autofill icon, if one exists
236 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
237 int row_height = controller_->GetRowBounds(index).height();
238 if (!controller_->icons()[index].empty()) {
239 int icon = controller_->GetIconResourceID(controller_->icons()[index]);
240 DCHECK_NE(-1, icon);
241 int icon_y = entry_rect.y() + (row_height - kAutofillIconHeight) / 2;
243 x_align_left += is_rtl ? 0 : -kAutofillIconWidth;
245 canvas->DrawImageInt(*rb.GetImageSkiaNamed(icon), x_align_left, icon_y);
247 x_align_left += is_rtl ? kAutofillIconWidth + kIconPadding : -kIconPadding;
250 // Draw the name text.
251 if (!is_rtl) {
252 x_align_left -= canvas->GetStringWidth(controller_->subtexts()[index],
253 controller_->subtext_font());
256 canvas->DrawStringInt(
257 controller_->subtexts()[index],
258 controller_->subtext_font(),
259 kItemTextColor,
260 x_align_left,
261 entry_rect.y(),
262 canvas->GetStringWidth(controller_->subtexts()[index],
263 controller_->subtext_font()),
264 entry_rect.height(),
265 gfx::Canvas::TEXT_ALIGN_CENTER);
268 AutofillPopupView* AutofillPopupView::Create(
269 AutofillPopupController* controller) {
270 views::Widget* observing_widget =
271 views::Widget::GetTopLevelWidgetForNativeView(
272 controller->container_view());
274 // If the top level widget can't be found, cancel the popup since we can't
275 // fully set it up.
276 if (!observing_widget)
277 return NULL;
279 return new AutofillPopupViewViews(controller, observing_widget);
282 } // namespace autofill