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
;
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);
37 AutofillPopupViewViews::AutofillPopupViewViews(
38 AutofillPopupController
* controller
, views::Widget
* observing_widget
)
39 : controller_(controller
),
40 observing_widget_(observing_widget
) {}
42 AutofillPopupViewViews::~AutofillPopupViewViews() {
44 controller_
->ViewDestroyed();
50 void AutofillPopupViewViews::Hide() {
51 // The controller is no longer valid after it hides us.
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|.
67 void AutofillPopupViewViews::OnPaint(gfx::Canvas
* canvas
) {
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
);
81 DrawAutofillEntry(canvas
, i
, line_rect
);
86 void AutofillPopupViewViews::OnMouseCaptureLost() {
88 controller_
->MouseExitedPopup();
91 bool AutofillPopupViewViews::OnMouseDragged(const ui::MouseEvent
& event
) {
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.
103 // If we move off of the popup, we lose the selection.
104 controller_
->MouseExitedPopup();
108 void AutofillPopupViewViews::OnMouseExited(const ui::MouseEvent
& event
) {
110 controller_
->MouseExitedPopup();
113 void AutofillPopupViewViews::OnMouseMoved(const ui::MouseEvent
& event
) {
117 if (HitTestPoint(event
.location()))
118 controller_
->MouseHovered(event
.x(), event
.y());
120 controller_
->MouseExitedPopup();
123 bool AutofillPopupViewViews::OnMousePressed(const ui::MouseEvent
& event
) {
124 if (HitTestPoint(event
.location()))
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
);
144 // |this| is now deleted.
150 void AutofillPopupViewViews::OnMouseReleased(const ui::MouseEvent
& event
) {
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_
);
172 void AutofillPopupViewViews::Show() {
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
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();
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());
205 void AutofillPopupViewViews::HideInternal() {
206 observing_widget_
->RemoveObserver(this);
209 void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas
* canvas
,
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
,
227 canvas
->GetStringWidth(controller_
->names()[index
],
228 controller_
->GetNameFontForRow(index
)),
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
]);
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.
252 x_align_left
-= canvas
->GetStringWidth(controller_
->subtexts()[index
],
253 controller_
->subtext_font());
256 canvas
->DrawStringInt(
257 controller_
->subtexts()[index
],
258 controller_
->subtext_font(),
262 canvas
->GetStringWidth(controller_
->subtexts()[index
],
263 controller_
->subtext_font()),
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
276 if (!observing_widget
)
279 return new AutofillPopupViewViews(controller
, observing_widget
);
282 } // namespace autofill