Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / autofill / autofill_popup_base_view.cc
blob5563d2eed23e9f02b21e53ce76c4b491f38dbbe0
1 // Copyright 2014 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_base_view.h"
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "chrome/browser/ui/autofill/popup_constants.h"
12 #include "ui/views/border.h"
13 #include "ui/views/focus/focus_manager.h"
14 #include "ui/views/widget/widget.h"
16 namespace autofill {
18 const SkColor AutofillPopupBaseView::kBorderColor =
19 SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE);
20 const SkColor AutofillPopupBaseView::kHoveredBackgroundColor =
21 SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD);
22 const SkColor AutofillPopupBaseView::kItemTextColor =
23 SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F);
24 const SkColor AutofillPopupBaseView::kPopupBackground =
25 SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
26 const SkColor AutofillPopupBaseView::kValueTextColor =
27 SkColorSetARGB(0xFF, 0x00, 0x00, 0x00);
28 const SkColor AutofillPopupBaseView::kWarningTextColor =
29 SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F);
31 AutofillPopupBaseView::AutofillPopupBaseView(
32 AutofillPopupViewDelegate* delegate,
33 views::Widget* parent_widget)
34 : delegate_(delegate),
35 parent_widget_(parent_widget),
36 weak_ptr_factory_(this) {}
38 AutofillPopupBaseView::~AutofillPopupBaseView() {
39 if (delegate_) {
40 delegate_->ViewDestroyed();
42 RemoveObserver();
46 void AutofillPopupBaseView::DoShow() {
47 const bool initialize_widget = !GetWidget();
48 if (initialize_widget) {
49 parent_widget_->AddObserver(this);
50 views::FocusManager* focus_manager = parent_widget_->GetFocusManager();
51 focus_manager->RegisterAccelerator(
52 ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE),
53 ui::AcceleratorManager::kNormalPriority,
54 this);
55 focus_manager->RegisterAccelerator(
56 ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE),
57 ui::AcceleratorManager::kNormalPriority,
58 this);
60 // The widget is destroyed by the corresponding NativeWidget, so we use
61 // a weak pointer to hold the reference and don't have to worry about
62 // deletion.
63 views::Widget* widget = new views::Widget;
64 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
65 params.delegate = this;
66 params.parent = container_view();
67 widget->Init(params);
68 widget->SetContentsView(this);
70 // No animation for popup appearance (too distracting).
71 widget->SetVisibilityAnimationTransition(views::Widget::ANIMATE_HIDE);
73 show_time_ = base::Time::Now();
76 SetBorder(views::Border::CreateSolidBorder(kPopupBorderThickness,
77 kBorderColor));
79 DoUpdateBoundsAndRedrawPopup();
80 GetWidget()->Show();
82 // Showing the widget can change native focus (which would result in an
83 // immediate hiding of the popup). Only start observing after shown.
84 if (initialize_widget)
85 views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this);
88 void AutofillPopupBaseView::DoHide() {
89 // The controller is no longer valid after it hides us.
90 delegate_ = NULL;
92 RemoveObserver();
94 if (GetWidget()) {
95 // Don't call CloseNow() because some of the functions higher up the stack
96 // assume the the widget is still valid after this point.
97 // http://crbug.com/229224
98 // NOTE: This deletes |this|.
99 GetWidget()->Close();
100 } else {
101 delete this;
105 void AutofillPopupBaseView::OnWidgetBoundsChanged(views::Widget* widget,
106 const gfx::Rect& new_bounds) {
107 DCHECK_EQ(widget, parent_widget_);
108 #if defined(OS_WIN)
109 HideController();
110 #endif
113 void AutofillPopupBaseView::RemoveObserver() {
114 parent_widget_->GetFocusManager()->UnregisterAccelerators(this);
115 parent_widget_->RemoveObserver(this);
116 views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
119 void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() {
120 GetWidget()->SetBounds(delegate_->popup_bounds());
121 SchedulePaint();
124 void AutofillPopupBaseView::OnNativeFocusChanged(gfx::NativeView focused_now) {
125 if (GetWidget() && GetWidget()->GetNativeView() != focused_now)
126 HideController();
129 void AutofillPopupBaseView::OnMouseCaptureLost() {
130 ClearSelection();
133 bool AutofillPopupBaseView::OnMouseDragged(const ui::MouseEvent& event) {
134 if (HitTestPoint(event.location())) {
135 SetSelection(event.location());
137 // We must return true in order to get future OnMouseDragged and
138 // OnMouseReleased events.
139 return true;
142 // If we move off of the popup, we lose the selection.
143 ClearSelection();
144 return false;
147 void AutofillPopupBaseView::OnMouseExited(const ui::MouseEvent& event) {
148 // Pressing return causes the cursor to hide, which will generate an
149 // OnMouseExited event. Pressing return should activate the current selection
150 // via AcceleratorPressed, so we need to let that run first.
151 base::ThreadTaskRunnerHandle::Get()->PostTask(
152 FROM_HERE, base::Bind(&AutofillPopupBaseView::ClearSelection,
153 weak_ptr_factory_.GetWeakPtr()));
156 void AutofillPopupBaseView::OnMouseMoved(const ui::MouseEvent& event) {
157 // A synthesized mouse move will be sent when the popup is first shown.
158 // Don't preview a suggestion if the mouse happens to be hovering there.
159 #if defined(OS_WIN)
160 // TODO(rouslan): Use event.time_stamp() and ui::EventTimeForNow() when they
161 // become comparable. http://crbug.com/453559
162 if (base::Time::Now() - show_time_ <= base::TimeDelta::FromMilliseconds(50))
163 return;
164 #else
165 if (event.flags() & ui::EF_IS_SYNTHESIZED)
166 return;
167 #endif
169 if (HitTestPoint(event.location()))
170 SetSelection(event.location());
171 else
172 ClearSelection();
175 bool AutofillPopupBaseView::OnMousePressed(const ui::MouseEvent& event) {
176 return event.GetClickCount() == 1;
179 void AutofillPopupBaseView::OnMouseReleased(const ui::MouseEvent& event) {
180 // We only care about the left click.
181 if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location()))
182 AcceptSelection(event.location());
185 void AutofillPopupBaseView::OnGestureEvent(ui::GestureEvent* event) {
186 switch (event->type()) {
187 case ui::ET_GESTURE_TAP_DOWN:
188 case ui::ET_GESTURE_SCROLL_BEGIN:
189 case ui::ET_GESTURE_SCROLL_UPDATE:
190 if (HitTestPoint(event->location()))
191 SetSelection(event->location());
192 else
193 ClearSelection();
194 break;
195 case ui::ET_GESTURE_TAP:
196 case ui::ET_GESTURE_SCROLL_END:
197 if (HitTestPoint(event->location()))
198 AcceptSelection(event->location());
199 else
200 ClearSelection();
201 break;
202 case ui::ET_GESTURE_TAP_CANCEL:
203 case ui::ET_SCROLL_FLING_START:
204 ClearSelection();
205 break;
206 default:
207 return;
209 event->SetHandled();
212 bool AutofillPopupBaseView::AcceleratorPressed(
213 const ui::Accelerator& accelerator) {
214 DCHECK_EQ(accelerator.modifiers(), ui::EF_NONE);
216 if (accelerator.key_code() == ui::VKEY_ESCAPE) {
217 HideController();
218 return true;
221 if (accelerator.key_code() == ui::VKEY_RETURN)
222 return delegate_->AcceptSelectedLine();
224 NOTREACHED();
225 return false;
228 void AutofillPopupBaseView::SetSelection(const gfx::Point& point) {
229 if (delegate_)
230 delegate_->SetSelectionAtPoint(point);
233 void AutofillPopupBaseView::AcceptSelection(const gfx::Point& point) {
234 if (!delegate_)
235 return;
237 delegate_->SetSelectionAtPoint(point);
238 delegate_->AcceptSelectedLine();
241 void AutofillPopupBaseView::ClearSelection() {
242 if (delegate_)
243 delegate_->SelectionCleared();
246 void AutofillPopupBaseView::HideController() {
247 if (delegate_)
248 delegate_->Hide();
251 gfx::NativeView AutofillPopupBaseView::container_view() {
252 return delegate_->container_view();
255 } // namespace autofill