autofill_popup_view_views.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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. 4 5#include "chrome/browser/ui/views/autofill/autofill_popup_view_views.h" 6 7#include "chrome/browser/ui/autofill/autofill_popup_controller.h" 8#include "grit/ui_resources.h" 9#include "third_party/WebKit/Source/WebKit/chromium/public/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/point.h" 15#include "ui/gfx/rect.h" 16#include "ui/views/border.h" 17#include "ui/views/widget/widget.h" 18 19using WebKit::WebAutofillClient; 20 21namespace { 22 23const SkColor kBorderColor = SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE); 24const SkColor kHoveredBackgroundColor = SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD); 25const SkColor kItemTextColor = SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); 26const SkColor kPopupBackground = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF); 27const SkColor kValueTextColor = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00); 28 29} // namespace 30 31namespace autofill { 32 33AutofillPopupViewViews::AutofillPopupViewViews( 34 AutofillPopupController* controller, views::Widget* observing_widget) 35 : controller_(controller), 36 observing_widget_(observing_widget) {} 37 38AutofillPopupViewViews::~AutofillPopupViewViews() { 39 if (controller_) { 40 controller_->ViewDestroyed(); 41 42 HideInternal(); 43 } 44} 45 46void AutofillPopupViewViews::Hide() { 47 // The controller is no longer valid after it hides us. 48 controller_ = NULL; 49 50 HideInternal(); 51 52 if (GetWidget()) { 53 // Don't call CloseNow() because some of the functions higher up the stack 54 // assume the the widget is still valid after this point. 55 // http://crbug.com/229224 56 // NOTE: This deletes |this|. 57 GetWidget()->Close(); 58 } else { 59 delete this; 60 } 61} 62 63void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) { 64 if (!controller_) 65 return; 66 67 canvas->DrawColor(kPopupBackground); 68 OnPaintBorder(canvas); 69 70 for (size_t i = 0; i < controller_->names().size(); ++i) { 71 gfx::Rect line_rect = controller_->GetRowBounds(i); 72 73 if (controller_->identifiers()[i] == 74 WebAutofillClient::MenuItemIDSeparator) { 75 canvas->DrawRect(line_rect, kItemTextColor); 76 } else { 77 DrawAutofillEntry(canvas, i, line_rect); 78 } 79 } 80} 81 82void AutofillPopupViewViews::OnMouseCaptureLost() { 83 if (controller_) 84 controller_->MouseExitedPopup(); 85} 86 87bool AutofillPopupViewViews::OnMouseDragged(const ui::MouseEvent& event) { 88 if (!controller_) 89 return false; 90 91 if (HitTestPoint(event.location())) { 92 controller_->MouseHovered(event.x(), event.y()); 93 94 // We must return true in order to get future OnMouseDragged and 95 // OnMouseReleased events. 96 return true; 97 } 98 99 // If we move off of the popup, we lose the selection. 100 controller_->MouseExitedPopup(); 101 return false; 102} 103 104void AutofillPopupViewViews::OnMouseExited(const ui::MouseEvent& event) { 105 if (controller_) 106 controller_->MouseExitedPopup(); 107} 108 109void AutofillPopupViewViews::OnMouseMoved(const ui::MouseEvent& event) { 110 if (controller_) 111 controller_->MouseHovered(event.x(), event.y()); 112} 113 114bool AutofillPopupViewViews::OnMousePressed(const ui::MouseEvent& event) { 115 // We must return true in order to get the OnMouseReleased event later. 116 return true; 117} 118 119void AutofillPopupViewViews::OnMouseReleased(const ui::MouseEvent& event) { 120 if (!controller_) 121 return; 122 123 // We only care about the left click. 124 if (event.IsOnlyLeftMouseButton() && 125 HitTestPoint(event.location())) 126 controller_->MouseClicked(event.x(), event.y()); 127} 128 129void AutofillPopupViewViews::OnWidgetBoundsChanged( 130 views::Widget* widget, 131 const gfx::Rect& new_bounds) { 132 controller_->Hide(); 133} 134 135void AutofillPopupViewViews::Show() { 136 if (!GetWidget()) { 137 observing_widget_->AddObserver(this); 138 139 // The widget is destroyed by the corresponding NativeWidget, so we use 140 // a weak pointer to hold the reference and don't have to worry about 141 // deletion. 142 views::Widget* widget = new views::Widget; 143 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); 144 params.delegate = this; 145 params.parent = controller_->container_view(); 146 widget->Init(params); 147 widget->SetContentsView(this); 148 } 149 150 set_border(views::Border::CreateSolidBorder(kBorderThickness, kBorderColor)); 151 152 UpdateBoundsAndRedrawPopup(); 153 GetWidget()->Show(); 154} 155 156void AutofillPopupViewViews::InvalidateRow(size_t row) { 157 SchedulePaintInRect(controller_->GetRowBounds(row)); 158} 159 160void AutofillPopupViewViews::UpdateBoundsAndRedrawPopup() { 161 GetWidget()->SetBounds(controller_->popup_bounds()); 162 SchedulePaint(); 163} 164 165void AutofillPopupViewViews::HideInternal() { 166 AutofillPopupView::Hide(); 167 168 observing_widget_->RemoveObserver(this); 169} 170 171void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, 172 int index, 173 const gfx::Rect& entry_rect) { 174 if (controller_->selected_line() == index) 175 canvas->FillRect(entry_rect, kHoveredBackgroundColor); 176 177 bool is_rtl = base::i18n::IsRTL(); 178 int value_text_width = controller_->GetNameFontForRow(index).GetStringWidth( 179 controller_->names()[index]); 180 int value_content_x = is_rtl ? 181 entry_rect.width() - value_text_width - kEndPadding : kEndPadding; 182 183 canvas->DrawStringInt( 184 controller_->names()[index], 185 controller_->GetNameFontForRow(index), 186 kValueTextColor, 187 value_content_x, 188 entry_rect.y(), 189 canvas->GetStringWidth(controller_->names()[index], 190 controller_->GetNameFontForRow(index)), 191 entry_rect.height(), 192 gfx::Canvas::TEXT_ALIGN_CENTER); 193 194 // Use this to figure out where all the other Autofill items should be placed. 195 int x_align_left = is_rtl ? kEndPadding : entry_rect.width() - kEndPadding; 196 197 // Draw the Autofill icon, if one exists 198 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 199 int row_height = controller_->GetRowBounds(index).height(); 200 if (!controller_->icons()[index].empty()) { 201 int icon = controller_->GetIconResourceID(controller_->icons()[index]); 202 DCHECK_NE(-1, icon); 203 int icon_y = entry_rect.y() + (row_height - kAutofillIconHeight) / 2; 204 205 x_align_left += is_rtl ? 0 : -kAutofillIconWidth; 206 207 canvas->DrawImageInt(*rb.GetImageSkiaNamed(icon), x_align_left, icon_y); 208 209 x_align_left += is_rtl ? kAutofillIconWidth + kIconPadding : -kIconPadding; 210 } 211 212 // Draw the name text. 213 if (!is_rtl) { 214 x_align_left -= canvas->GetStringWidth(controller_->subtexts()[index], 215 controller_->subtext_font()); 216 } 217 218 canvas->DrawStringInt( 219 controller_->subtexts()[index], 220 controller_->subtext_font(), 221 kItemTextColor, 222 x_align_left, 223 entry_rect.y(), 224 canvas->GetStringWidth(controller_->subtexts()[index], 225 controller_->subtext_font()), 226 entry_rect.height(), 227 gfx::Canvas::TEXT_ALIGN_CENTER); 228} 229 230AutofillPopupView* AutofillPopupView::Create( 231 AutofillPopupController* controller) { 232 views::Widget* observing_widget = 233 views::Widget::GetTopLevelWidgetForNativeView( 234 controller->container_view()); 235 236 // If the top level widget can't be found, cancel the popup since we can't 237 // fully set it up. 238 if (!observing_widget) 239 return NULL; 240 241 return new AutofillPopupViewViews(controller, observing_widget); 242} 243 244} // namespace autofill 245