autofill_popup_base_view.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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. 4 5#include "chrome/browser/ui/views/autofill/autofill_popup_base_view.h" 6 7#include "chrome/browser/ui/autofill/popup_constants.h" 8#include "ui/gfx/point.h" 9#include "ui/gfx/screen.h" 10#include "ui/views/border.h" 11#include "ui/views/event_utils.h" 12#include "ui/views/widget/widget.h" 13 14#if defined(USE_AURA) 15#include "ui/wm/core/window_animations.h" 16#endif 17 18namespace autofill { 19 20const SkColor AutofillPopupBaseView::kBorderColor = 21 SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE); 22const SkColor AutofillPopupBaseView::kHoveredBackgroundColor = 23 SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD); 24const SkColor AutofillPopupBaseView::kItemTextColor = 25 SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); 26const SkColor AutofillPopupBaseView::kPopupBackground = 27 SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF); 28const SkColor AutofillPopupBaseView::kValueTextColor = 29 SkColorSetARGB(0xFF, 0x00, 0x00, 0x00); 30const SkColor AutofillPopupBaseView::kWarningTextColor = 31 SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); 32 33AutofillPopupBaseView::AutofillPopupBaseView( 34 AutofillPopupViewDelegate* delegate, 35 views::Widget* observing_widget) 36 : delegate_(delegate), 37 observing_widget_(observing_widget) {} 38AutofillPopupBaseView::~AutofillPopupBaseView() { 39 if (delegate_) { 40 delegate_->ViewDestroyed(); 41 42 RemoveObserver(); 43 } 44} 45 46void AutofillPopupBaseView::DoShow() { 47 if (!GetWidget()) { 48 observing_widget_->AddObserver(this); 49 50 // The widget is destroyed by the corresponding NativeWidget, so we use 51 // a weak pointer to hold the reference and don't have to worry about 52 // deletion. 53 views::Widget* widget = new views::Widget; 54 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 55 params.delegate = this; 56 params.parent = container_view(); 57 widget->Init(params); 58 widget->SetContentsView(this); 59#if defined(USE_AURA) 60 // No animation for popup appearance (too distracting). 61 wm::SetWindowVisibilityAnimationTransition( 62 widget->GetNativeView(), wm::ANIMATE_HIDE); 63#endif 64 } 65 66 SetBorder(views::Border::CreateSolidBorder(kPopupBorderThickness, 67 kBorderColor)); 68 69 DoUpdateBoundsAndRedrawPopup(); 70 GetWidget()->Show(); 71 72 if (ShouldHideOnOutsideClick()) 73 GetWidget()->SetCapture(this); 74} 75 76void AutofillPopupBaseView::DoHide() { 77 // The controller is no longer valid after it hides us. 78 delegate_ = NULL; 79 80 RemoveObserver(); 81 82 if (GetWidget()) { 83 // Don't call CloseNow() because some of the functions higher up the stack 84 // assume the the widget is still valid after this point. 85 // http://crbug.com/229224 86 // NOTE: This deletes |this|. 87 GetWidget()->Close(); 88 } else { 89 delete this; 90 } 91} 92 93void AutofillPopupBaseView::RemoveObserver() { 94 observing_widget_->RemoveObserver(this); 95} 96 97void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() { 98 GetWidget()->SetBounds(delegate_->popup_bounds()); 99 SchedulePaint(); 100} 101 102void AutofillPopupBaseView::OnWidgetBoundsChanged(views::Widget* widget, 103 const gfx::Rect& new_bounds) { 104 DCHECK_EQ(widget, observing_widget_); 105 HideController(); 106} 107 108void AutofillPopupBaseView::OnMouseCaptureLost() { 109 ClearSelection(); 110} 111 112bool AutofillPopupBaseView::OnMouseDragged(const ui::MouseEvent& event) { 113 if (HitTestPoint(event.location())) { 114 SetSelection(event.location()); 115 116 // We must return true in order to get future OnMouseDragged and 117 // OnMouseReleased events. 118 return true; 119 } 120 121 // If we move off of the popup, we lose the selection. 122 ClearSelection(); 123 return false; 124} 125 126void AutofillPopupBaseView::OnMouseExited(const ui::MouseEvent& event) { 127 ClearSelection(); 128} 129 130void AutofillPopupBaseView::OnMouseMoved(const ui::MouseEvent& event) { 131 if (HitTestPoint(event.location())) 132 SetSelection(event.location()); 133 else 134 ClearSelection(); 135} 136 137bool AutofillPopupBaseView::OnMousePressed(const ui::MouseEvent& event) { 138 if (HitTestPoint(event.location())) 139 return true; 140 141 if (ShouldHideOnOutsideClick()) { 142 GetWidget()->ReleaseCapture(); 143 144 gfx::Point screen_loc = event.location(); 145 views::View::ConvertPointToScreen(this, &screen_loc); 146 147 ui::MouseEvent mouse_event = event; 148 mouse_event.set_location(screen_loc); 149 150 if (ShouldRepostEvent(mouse_event)) { 151 gfx::NativeView native_view = GetWidget()->GetNativeView(); 152 gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); 153 gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); 154 views::RepostLocatedEvent(window, mouse_event); 155 } 156 157 HideController(); 158 // |this| is now deleted. 159 } 160 161 return false; 162} 163 164void AutofillPopupBaseView::OnMouseReleased(const ui::MouseEvent& event) { 165 // Because this view can can be shown in response to a mouse press, it can 166 // receive an OnMouseReleased event just after showing. This breaks the mouse 167 // capture, so restart capturing here. 168 if (ShouldHideOnOutsideClick() && GetWidget()) 169 GetWidget()->SetCapture(this); 170 171 // We only care about the left click. 172 if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) 173 AcceptSelection(event.location()); 174} 175 176void AutofillPopupBaseView::OnGestureEvent(ui::GestureEvent* event) { 177 switch (event->type()) { 178 case ui::ET_GESTURE_TAP_DOWN: 179 case ui::ET_GESTURE_SCROLL_BEGIN: 180 case ui::ET_GESTURE_SCROLL_UPDATE: 181 if (HitTestPoint(event->location())) 182 SetSelection(event->location()); 183 else 184 ClearSelection(); 185 break; 186 case ui::ET_GESTURE_TAP: 187 case ui::ET_GESTURE_SCROLL_END: 188 if (HitTestPoint(event->location())) 189 AcceptSelection(event->location()); 190 else 191 ClearSelection(); 192 break; 193 case ui::ET_GESTURE_TAP_CANCEL: 194 case ui::ET_SCROLL_FLING_START: 195 ClearSelection(); 196 break; 197 default: 198 return; 199 } 200 event->SetHandled(); 201} 202 203void AutofillPopupBaseView::SetSelection(const gfx::Point& point) { 204 if (delegate_) 205 delegate_->SetSelectionAtPoint(point); 206} 207 208void AutofillPopupBaseView::AcceptSelection(const gfx::Point& point) { 209 if (delegate_) 210 delegate_->AcceptSelectionAtPoint(point); 211} 212 213void AutofillPopupBaseView::ClearSelection() { 214 if (delegate_) 215 delegate_->SelectionCleared(); 216} 217 218bool AutofillPopupBaseView::ShouldHideOnOutsideClick() { 219 if (delegate_) 220 return delegate_->ShouldHideOnOutsideClick(); 221 222 // |this| instance should be in the process of being destroyed, so the return 223 // value shouldn't matter. 224 return false; 225} 226 227void AutofillPopupBaseView::HideController() { 228 if (delegate_) 229 delegate_->Hide(); 230} 231 232bool AutofillPopupBaseView::ShouldRepostEvent(const ui::MouseEvent& event) { 233 return delegate_->ShouldRepostEvent(event); 234} 235 236gfx::NativeView AutofillPopupBaseView::container_view() { 237 return delegate_->container_view(); 238} 239 240 241} // namespace autofill 242