Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "autofill_popup_view_gtk.h" | 5 #include "autofill_popup_view_gtk.h" |
| 6 | 6 |
| 7 #include <gdk/gdkkeysyms.h> | |
| 8 | |
| 7 #include "base/logging.h" | 9 #include "base/logging.h" |
| 8 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 9 #include "chrome/browser/autofill/autofill_external_delegate.h" | 11 #include "chrome/browser/autofill/autofill_external_delegate.h" |
| 10 #include "chrome/browser/ui/gtk/gtk_util.h" | 12 #include "chrome/browser/ui/gtk/gtk_util.h" |
| 13 #include "content/public/browser/render_view_host.h" | |
| 11 #include "ui/base/gtk/gtk_compat.h" | 14 #include "ui/base/gtk/gtk_compat.h" |
| 12 #include "ui/base/gtk/gtk_hig_constants.h" | 15 #include "ui/base/gtk/gtk_hig_constants.h" |
| 13 #include "ui/base/gtk/gtk_windowing.h" | 16 #include "ui/base/gtk/gtk_windowing.h" |
| 14 #include "ui/gfx/native_widget_types.h" | 17 #include "ui/gfx/native_widget_types.h" |
| 15 #include "ui/gfx/rect.h" | 18 #include "ui/gfx/rect.h" |
| 19 #include "content/public/browser/web_contents.h" | |
|
Ilya Sherman
2012/03/15 20:10:56
nit: Alpha-order
csharp
2012/03/21 15:32:28
Done.
| |
| 16 | 20 |
| 17 namespace { | 21 namespace { |
| 18 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); | 22 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); |
| 19 const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0x0CD, 0xCD, 0xCD); | 23 const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0x0CD, 0xCD, 0xCD); |
| 20 const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); | 24 const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); |
| 21 | 25 |
| 22 // The amount of minimum padding between the Autofill value and label in pixels. | 26 // The amount of minimum padding between the Autofill value and label in pixels. |
| 23 const int kMiddlePadding = 10; | 27 const int kMiddlePadding = 10; |
| 24 | 28 |
| 25 // We have a 1 pixel border around the entire results popup. | 29 // We have a 1 pixel border around the entire results popup. |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 36 } | 40 } |
| 37 | 41 |
| 38 } // namespace | 42 } // namespace |
| 39 | 43 |
| 40 AutofillPopupViewGtk::AutofillPopupViewGtk( | 44 AutofillPopupViewGtk::AutofillPopupViewGtk( |
| 41 content::WebContents* web_contents, | 45 content::WebContents* web_contents, |
| 42 AutofillExternalDelegate* external_delegate, | 46 AutofillExternalDelegate* external_delegate, |
| 43 GtkWidget* parent) | 47 GtkWidget* parent) |
| 44 : AutofillPopupView(web_contents, external_delegate), | 48 : AutofillPopupView(web_contents, external_delegate), |
| 45 parent_(parent), | 49 parent_(parent), |
| 46 window_(gtk_window_new(GTK_WINDOW_POPUP)) { | 50 window_(gtk_window_new(GTK_WINDOW_POPUP)), |
| 51 render_view_host_(web_contents->GetRenderViewHost()) { | |
| 47 CHECK(parent != NULL); | 52 CHECK(parent != NULL); |
| 48 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); | 53 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); |
| 49 gtk_widget_set_app_paintable(window_, TRUE); | 54 gtk_widget_set_app_paintable(window_, TRUE); |
| 50 gtk_widget_set_double_buffered(window_, TRUE); | 55 gtk_widget_set_double_buffered(window_, TRUE); |
| 51 | 56 |
| 52 // Setup the window to ensure it receives the expose event. | 57 // Setup the window to ensure it receives the expose event. |
| 53 gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK | | 58 gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK | |
| 54 GDK_BUTTON_RELEASE_MASK | | 59 GDK_BUTTON_RELEASE_MASK | |
| 55 GDK_EXPOSURE_MASK | | 60 GDK_EXPOSURE_MASK | |
| 56 GDK_POINTER_MOTION_MASK); | 61 GDK_POINTER_MOTION_MASK); |
| 57 g_signal_connect(window_, "expose-event", | 62 g_signal_connect(window_, "expose-event", |
| 58 G_CALLBACK(HandleExposeThunk), this); | 63 G_CALLBACK(HandleExposeThunk), this); |
| 59 | 64 |
| 60 g_signal_connect(window_, "motion-notify-event", | 65 g_signal_connect(window_, "motion-notify-event", |
| 61 G_CALLBACK(HandleMotionThunk), this); | 66 G_CALLBACK(HandleMotionThunk), this); |
| 62 g_signal_connect(window_, "button-release-event", | 67 g_signal_connect(window_, "button-release-event", |
| 63 G_CALLBACK(HandleButtonReleaseThunk), this); | 68 G_CALLBACK(HandleButtonReleaseThunk), this); |
| 64 | 69 |
| 65 // Cache the layout so we don't have to create it for every expose. | 70 // Cache the layout so we don't have to create it for every expose. |
| 66 layout_ = gtk_widget_create_pango_layout(window_, NULL); | 71 layout_ = gtk_widget_create_pango_layout(window_, NULL); |
| 67 | 72 |
| 68 row_height_ = font_.GetHeight(); | 73 row_height_ = font_.GetHeight(); |
| 69 } | 74 } |
| 70 | 75 |
| 71 AutofillPopupViewGtk::~AutofillPopupViewGtk() { | 76 AutofillPopupViewGtk::~AutofillPopupViewGtk() { |
| 72 g_object_unref(layout_); | 77 g_object_unref(layout_); |
| 73 gtk_widget_destroy(window_); | 78 gtk_widget_destroy(window_); |
| 74 } | 79 } |
| 75 | 80 |
| 76 void AutofillPopupViewGtk::ShowInternal() { | 81 bool AutofillPopupViewGtk::HandleKeyPressEvent(GdkEventKey* event) { |
| 77 // Find out the maximum bounds required by the popup. | 82 switch (event->keyval) { |
| 78 // TODO(csharp): Once the icon is also displayed it will affect the required | 83 case GDK_Up: { |
| 79 // size so it will need to be included in the calculation. | 84 DecreaseSelectedLine(); |
| 80 int popup_width = element_bounds().width(); | 85 return true; |
| 81 DCHECK_EQ(autofill_values().size(), autofill_labels().size()); | 86 } |
|
Ilya Sherman
2012/03/15 20:10:56
nit: No need for curly braces for these case stmts
csharp
2012/03/21 15:32:28
Done.
| |
| 82 for (size_t i = 0; i < autofill_values().size(); ++i) { | 87 case GDK_Down: { |
| 83 popup_width = std::max(popup_width, | 88 IncreaseSelectedLine(); |
| 84 font_.GetStringWidth(autofill_values()[i]) + | 89 return true; |
| 85 kMiddlePadding + | 90 } |
| 86 font_.GetStringWidth(autofill_labels()[i])); | 91 case GDK_Page_Up: { |
| 92 SetSelectedLine(0); | |
| 93 return true; | |
| 94 } | |
| 95 case GDK_Page_Down: { | |
| 96 SetSelectedLine(autofill_values().size() - 1); | |
| 97 return true; | |
| 98 } | |
| 99 case GDK_Escape: { | |
| 100 Hide(); | |
| 101 return true; | |
| 102 } | |
| 103 case GDK_Delete: | |
| 104 case GDK_KP_Delete: { | |
| 105 RemoveLine(selected_line()); | |
|
Ilya Sherman
2012/03/15 20:10:56
We should only remove the line if the user types s
csharp
2012/03/21 15:32:28
Ok, in my playing around I see that Autofill profi
Ilya Sherman
2012/03/21 23:35:30
I wasn't aware that Autocomplete entries behaved d
| |
| 106 return true; | |
| 107 } | |
| 108 case GDK_Return: | |
| 109 case GDK_KP_Enter: { | |
| 110 ChooseLine(selected_line()); | |
| 111 return true; | |
|
Ilya Sherman
2012/03/15 20:10:56
This should only consume the event if the popup ha
csharp
2012/03/21 15:32:28
Done.
| |
| 112 } | |
| 87 } | 113 } |
| 88 | 114 |
| 115 return false; | |
| 116 } | |
| 117 | |
| 118 void AutofillPopupViewGtk::ShowInternal() { | |
| 89 gint origin_x, origin_y; | 119 gint origin_x, origin_y; |
| 90 gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y); | 120 gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y); |
| 91 | 121 |
| 122 int popup_width = GetPopupRequiredWidth(); | |
| 123 | |
| 92 // Move the popup to appear right below the text field it is using. | 124 // Move the popup to appear right below the text field it is using. |
| 93 bounds_.SetRect( | 125 bounds_.SetRect( |
| 94 origin_x + element_bounds().x(), | 126 origin_x + element_bounds().x(), |
| 95 origin_y + element_bounds().y() + element_bounds().height(), | 127 origin_y + element_bounds().y() + element_bounds().height(), |
| 96 popup_width, | 128 popup_width, |
| 97 row_height_ * autofill_values().size()); | 129 row_height_ * autofill_values().size()); |
| 98 | 130 |
| 99 gtk_window_move(GTK_WINDOW(window_), bounds_.x(), bounds_.y()); | 131 gtk_window_move(GTK_WINDOW(window_), bounds_.x(), bounds_.y()); |
| 100 | 132 |
| 101 gtk_widget_set_size_request( | 133 gtk_widget_set_size_request( |
| 102 window_, | 134 window_, |
| 103 popup_width, | 135 popup_width, |
| 104 row_height_ * autofill_values().size()); | 136 row_height_ * autofill_values().size()); |
| 105 | 137 |
| 138 render_view_host_->AddKeyboardListener(this); | |
| 139 | |
| 106 gtk_widget_show(window_); | 140 gtk_widget_show(window_); |
| 107 | 141 |
| 108 GtkWidget* toplevel = gtk_widget_get_toplevel(parent_); | 142 GtkWidget* toplevel = gtk_widget_get_toplevel(parent_); |
| 109 CHECK(gtk_widget_is_toplevel(toplevel)); | 143 CHECK(gtk_widget_is_toplevel(toplevel)); |
| 110 ui::StackPopupWindow(window_, toplevel); | 144 ui::StackPopupWindow(window_, toplevel); |
| 111 } | 145 } |
| 112 | 146 |
| 113 void AutofillPopupViewGtk::HideInternal() { | 147 void AutofillPopupViewGtk::HideInternal() { |
| 148 render_view_host_->RemoveKeyboardListener(this); | |
| 149 | |
| 114 gtk_widget_hide(window_); | 150 gtk_widget_hide(window_); |
| 115 } | 151 } |
| 116 | 152 |
| 117 void AutofillPopupViewGtk::InvalidateRow(size_t row) { | 153 void AutofillPopupViewGtk::InvalidateRow(size_t row) { |
| 118 GdkRectangle row_rect = GetRectForRow( | 154 GdkRectangle row_rect = GetRectForRow( |
| 119 row, bounds_.width(), row_height_).ToGdkRectangle(); | 155 row, bounds_.width(), row_height_).ToGdkRectangle(); |
| 120 GdkWindow* gdk_window = gtk_widget_get_window(window_); | 156 GdkWindow* gdk_window = gtk_widget_get_window(window_); |
| 121 gdk_window_invalidate_rect(gdk_window, &row_rect, FALSE); | 157 gdk_window_invalidate_rect(gdk_window, &row_rect, FALSE); |
| 122 } | 158 } |
| 123 | 159 |
| 160 void AutofillPopupViewGtk::UpdatePopupSize() { | |
| 161 gtk_widget_set_size_request( | |
| 162 window_, | |
| 163 GetPopupRequiredWidth(), | |
| 164 row_height_ * autofill_values().size()); | |
| 165 } | |
| 166 | |
| 124 gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget, | 167 gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget, |
| 125 GdkEventButton* event) { | 168 GdkEventButton* event) { |
| 126 // We only care about the left click. | 169 // We only care about the left click. |
| 127 if (event->button != 1) | 170 if (event->button != 1) |
| 128 return FALSE; | 171 return FALSE; |
| 129 | 172 |
| 130 size_t line = LineFromY(event->y); | 173 size_t line = LineFromY(event->y); |
| 131 DCHECK_LT(line, autofill_values().size()); | 174 ChooseLine(line); |
| 132 | |
| 133 external_delegate()->DidAcceptAutofillSuggestions( | |
| 134 autofill_values()[line], | |
| 135 autofill_unique_ids()[line], | |
| 136 line); | |
| 137 | 175 |
| 138 return TRUE; | 176 return TRUE; |
| 139 } | 177 } |
| 140 | 178 |
| 141 gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, | 179 gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, |
| 142 GdkEventExpose* event) { | 180 GdkEventExpose* event) { |
| 143 gfx::Rect window_rect = GetWindowRect(event->window); | 181 gfx::Rect window_rect = GetWindowRect(event->window); |
| 144 gfx::Rect damage_rect = gfx::Rect(event->area); | 182 gfx::Rect damage_rect = gfx::Rect(event->area); |
| 145 | 183 |
| 146 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget))); | 184 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget))); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red, | 273 PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red, |
| 236 text_color.green, | 274 text_color.green, |
| 237 text_color.blue); | 275 text_color.blue); |
| 238 pango_attr_list_insert(attrs, fg_attr); // Ownership taken. | 276 pango_attr_list_insert(attrs, fg_attr); // Ownership taken. |
| 239 | 277 |
| 240 | 278 |
| 241 pango_layout_set_attributes(layout_, attrs); // Ref taken. | 279 pango_layout_set_attributes(layout_, attrs); // Ref taken. |
| 242 pango_attr_list_unref(attrs); | 280 pango_attr_list_unref(attrs); |
| 243 } | 281 } |
| 244 | 282 |
| 283 int AutofillPopupViewGtk::GetPopupRequiredWidth() { | |
| 284 // TODO(csharp): Once the icon is also displayed it will affect the required | |
| 285 // size so it will need to be included in the calculation. | |
| 286 int popup_width = element_bounds().width(); | |
| 287 DCHECK_EQ(autofill_values().size(), autofill_labels().size()); | |
| 288 for (size_t i = 0; i < autofill_values().size(); ++i) { | |
| 289 popup_width = std::max(popup_width, | |
| 290 font_.GetStringWidth(autofill_values()[i]) + | |
| 291 kMiddlePadding + | |
| 292 font_.GetStringWidth(autofill_labels()[i])); | |
| 293 } | |
| 294 | |
| 295 return popup_width; | |
| 296 } | |
| 297 | |
| 245 int AutofillPopupViewGtk::LineFromY(int y) { | 298 int AutofillPopupViewGtk::LineFromY(int y) { |
| 246 return y / row_height_; | 299 return y / row_height_; |
| 247 } | 300 } |
| OLD | NEW |