Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc

Issue 9235072: Adding Mouse Support for new GTK Autofill (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: First Draft Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "base/logging.h" 7 #include "base/logging.h"
8 #include "base/utf_string_conversions.h" 8 #include "base/utf_string_conversions.h"
9 #include "chrome/browser/autofill/autofill_external_delegate.h"
9 #include "chrome/browser/ui/gtk/gtk_util.h" 10 #include "chrome/browser/ui/gtk/gtk_util.h"
10 #include "ui/base/gtk/gtk_compat.h" 11 #include "ui/base/gtk/gtk_compat.h"
11 #include "ui/base/gtk/gtk_hig_constants.h" 12 #include "ui/base/gtk/gtk_hig_constants.h"
12 #include "ui/base/gtk/gtk_windowing.h" 13 #include "ui/base/gtk/gtk_windowing.h"
13 #include "ui/gfx/native_widget_types.h" 14 #include "ui/gfx/native_widget_types.h"
14 #include "ui/gfx/rect.h" 15 #include "ui/gfx/rect.h"
15 16
16 namespace { 17 namespace {
17 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); 18 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce);
19 const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0x0CD, 0xCD, 0xCD);
18 const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); 20 const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00);
19 21
20 // The amount of minimum padding between the Autofill value and label in pixels. 22 // The amount of minimum padding between the Autofill value and label in pixels.
21 const int kMiddlePadding = 10; 23 const int kMiddlePadding = 10;
22 24
23 // We have a 1 pixel border around the entire results popup. 25 // We have a 1 pixel border around the entire results popup.
24 const int kBorderThickness = 1; 26 const int kBorderThickness = 1;
25 27
26 gfx::Rect GetWindowRect(GdkWindow* window) { 28 gfx::Rect GetWindowRect(GdkWindow* window) {
27 return gfx::Rect(gdk_window_get_width(window), 29 return gfx::Rect(gdk_window_get_width(window),
28 gdk_window_get_height(window)); 30 gdk_window_get_height(window));
29 } 31 }
30 32
31 // Returns the rectangle containing the item at position |index| in the popup. 33 // Returns the rectangle containing the item at position |index| in the popup.
32 gfx::Rect GetRectForRow(size_t index, int width, int height) { 34 gfx::Rect GetRectForRow(size_t index, int width, int height) {
33 return gfx::Rect(0, (index * height), width, height); 35 return gfx::Rect(0, (index * height), width, height);
34 } 36 }
35 37
36 } // namespace 38 } // namespace
37 39
38 AutofillPopupViewGtk::AutofillPopupViewGtk(content::WebContents* web_contents, 40 AutofillPopupViewGtk::AutofillPopupViewGtk(
39 GtkWidget* parent) 41 content::WebContents* web_contents,
40 : AutofillPopupView(web_contents), 42 AutofillExternalDelegate* external_delegate,
43 GtkWidget* parent)
44 : AutofillPopupView(web_contents, external_delegate),
41 parent_(parent), 45 parent_(parent),
42 window_(gtk_window_new(GTK_WINDOW_POPUP)) { 46 window_(gtk_window_new(GTK_WINDOW_POPUP)) {
43 CHECK(parent != NULL); 47 CHECK(parent != NULL);
44 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); 48 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE);
45 gtk_widget_set_app_paintable(window_, TRUE); 49 gtk_widget_set_app_paintable(window_, TRUE);
46 gtk_widget_set_double_buffered(window_, TRUE); 50 gtk_widget_set_double_buffered(window_, TRUE);
47 51
48 // Setup the window to ensure it recieves the expose event. 52 // Setup the window to ensure it receives the expose event.
49 gtk_widget_add_events(window_, GDK_EXPOSURE_MASK); 53 gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK |
54 GDK_BUTTON_RELEASE_MASK |
55 GDK_EXPOSURE_MASK |
56 GDK_POINTER_MOTION_MASK);
50 g_signal_connect(window_, "expose-event", 57 g_signal_connect(window_, "expose-event",
51 G_CALLBACK(HandleExposeThunk), this); 58 G_CALLBACK(HandleExposeThunk), this);
52 59
60 g_signal_connect(window_, "motion-notify-event",
61 G_CALLBACK(HandleMotionThunk), this);
62 g_signal_connect(window_, "button-release-event",
63 G_CALLBACK(HandleButtonReleaseThunk), this);
64
53 // Cache the layout so we don't have to create it for every expose. 65 // Cache the layout so we don't have to create it for every expose.
54 layout_ = gtk_widget_create_pango_layout(window_, NULL); 66 layout_ = gtk_widget_create_pango_layout(window_, NULL);
55 67
56 row_height_ = font_.GetHeight(); 68 row_height_ = font_.GetHeight();
57 } 69 }
58 70
59 AutofillPopupViewGtk::~AutofillPopupViewGtk() { 71 AutofillPopupViewGtk::~AutofillPopupViewGtk() {
60 g_object_unref(layout_); 72 g_object_unref(layout_);
61 gtk_widget_destroy(window_); 73 gtk_widget_destroy(window_);
62 } 74 }
63 75
64 void AutofillPopupViewGtk::Hide() {
65 gtk_widget_hide(window_);
66 }
67
68 void AutofillPopupViewGtk::ShowInternal() { 76 void AutofillPopupViewGtk::ShowInternal() {
69 gint origin_x, origin_y;
70 gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y);
71
72 // Move the popup to appear right below the text field it is using.
73 gtk_window_move(GTK_WINDOW(window_),
74 origin_x + element_bounds().x(),
75 origin_y + element_bounds().y() + element_bounds().height());
76
77 // Find out the maximum bounds required by the popup. 77 // Find out the maximum bounds required by the popup.
78 // TODO(csharp): Once the icon is also displayed it will affect the required 78 // TODO(csharp): Once the icon is also displayed it will affect the required
79 // size so it will need to be included in the calculation. 79 // size so it will need to be included in the calculation.
80 int popup_width = element_bounds().width(); 80 int popup_width = element_bounds().width();
81 DCHECK_EQ(autofill_values().size(), autofill_labels().size()); 81 DCHECK_EQ(autofill_values().size(), autofill_labels().size());
82 for (size_t i = 0; i < autofill_values().size(); ++i) { 82 for (size_t i = 0; i < autofill_values().size(); ++i) {
83 popup_width = std::max(popup_width, 83 popup_width = std::max(popup_width,
84 font_.GetStringWidth(autofill_values()[i]) + 84 font_.GetStringWidth(autofill_values()[i]) +
85 kMiddlePadding + 85 kMiddlePadding +
86 font_.GetStringWidth(autofill_labels()[i])); 86 font_.GetStringWidth(autofill_labels()[i]));
87 } 87 }
88 88
89 gint origin_x, origin_y;
90 gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y);
91
92 // Move the popup to appear right below the text field it is using.
93 bounds_.SetRect(
94 origin_x + element_bounds().x(),
95 origin_y + element_bounds().y() + element_bounds().height(),
96 popup_width,
97 row_height_ * autofill_values().size());
98
99 gtk_window_move(GTK_WINDOW(window_), bounds_.x(), bounds_.y());
100
89 gtk_widget_set_size_request( 101 gtk_widget_set_size_request(
90 window_, 102 window_,
91 popup_width, 103 popup_width,
92 row_height_ * autofill_values().size()); 104 row_height_ * autofill_values().size());
93 105
94 gtk_widget_show(window_); 106 gtk_widget_show(window_);
95 107
96 GtkWidget* toplevel = gtk_widget_get_toplevel(parent_); 108 GtkWidget* toplevel = gtk_widget_get_toplevel(parent_);
97 CHECK(gtk_widget_is_toplevel(toplevel)); 109 CHECK(gtk_widget_is_toplevel(toplevel));
98 ui::StackPopupWindow(window_, toplevel); 110 ui::StackPopupWindow(window_, toplevel);
99 } 111 }
100 112
113 void AutofillPopupViewGtk::HideInternal() {
114 gtk_widget_hide(window_);
115 }
116
117 void AutofillPopupViewGtk::InvalidateRow(size_t row) {
118 GdkRectangle row_rect = GetRectForRow(
119 row, bounds_.width(), row_height_).ToGdkRectangle();
120 gdk_window_invalidate_rect(window_->window, &row_rect, FALSE);
121 }
122
123 gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget,
Ilya Sherman 2012/02/04 04:10:52 nit: Is there a GTK-specific reason why this funct
csharp 2012/02/07 22:30:58 I've changed it to ignore other clicks. I noticed
Ilya Sherman 2012/02/07 23:35:55 I think the new UI should behave like a system-nat
Elliot Glaysher 2012/02/07 23:44:09 Yes. The return value specifies whether other sign
124 GdkEventButton* event) {
125 size_t line = LineFromY(event->y);
Ilya Sherman 2012/02/04 04:10:52 nit: DCHECK_LT(line, autofill_values.size());
Ilya Sherman 2012/02/04 04:10:52 nit: Any reason not to move this work into the bod
csharp 2012/02/07 22:30:58 Done.
126
127 if (event->button == 1) // Left click.
Ilya Sherman 2012/02/04 04:10:52 nit: Since the body wraps to multiple lines, pleas
csharp 2012/02/07 22:30:58 Done.
128 external_delegate()->didAcceptAutofillSuggestions(
129 autofill_values()[line],
130 autofill_unique_ids()[line],
131 line);
132
133 return TRUE;
134 }
135
101 gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, 136 gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget,
102 GdkEventExpose* event) { 137 GdkEventExpose* event) {
103 gfx::Rect window_rect = GetWindowRect(event->window); 138 gfx::Rect window_rect = GetWindowRect(event->window);
104 gfx::Rect damage_rect = gfx::Rect(event->area); 139 gfx::Rect damage_rect = gfx::Rect(event->area);
105 140
106 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget))); 141 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget)));
107 gdk_cairo_rectangle(cr, &event->area); 142 gdk_cairo_rectangle(cr, &event->area);
108 cairo_clip(cr); 143 cairo_clip(cr);
109 144
110 // This assert is kinda ugly, but it would be more currently unneeded work 145 // This assert is kinda ugly, but it would be more currently unneeded work
(...skipping 21 matching lines...) Expand all
132 if (separator_index() == static_cast<int>(i)) { 167 if (separator_index() == static_cast<int>(i)) {
133 int line_y = i * row_height_; 168 int line_y = i * row_height_;
134 169
135 cairo_save(cr); 170 cairo_save(cr);
136 cairo_move_to(cr, 0, line_y); 171 cairo_move_to(cr, 0, line_y);
137 cairo_line_to(cr, window_rect.width(), line_y); 172 cairo_line_to(cr, window_rect.width(), line_y);
138 cairo_stroke(cr); 173 cairo_stroke(cr);
139 cairo_restore(cr); 174 cairo_restore(cr);
140 } 175 }
141 176
177 if (selected_line() == static_cast<int>(i)) {
178 gdk_cairo_set_source_color(cr, &kHoveredBackgroundColor);
179 cairo_rectangle(cr, line_rect.x(), line_rect.y(),
180 line_rect.width(), line_rect.height());
181 cairo_fill(cr);
182 }
183
142 // Center the text within the line. 184 // Center the text within the line.
143 int content_y = std::max( 185 int content_y = std::max(
144 line_rect.y(), 186 line_rect.y(),
145 line_rect.y() + ((row_height_ - actual_content_height) / 2)); 187 line_rect.y() + ((row_height_ - actual_content_height) / 2));
146 188
147 // Draw the value. 189 // Draw the value.
148 gtk_util::SetLayoutText(layout_, autofill_values()[i]); 190 gtk_util::SetLayoutText(layout_, autofill_values()[i]);
149 191
150 cairo_save(cr); 192 cairo_save(cr);
151 cairo_move_to(cr, 0, content_y); 193 cairo_move_to(cr, 0, content_y);
152 pango_cairo_show_layout(cr, layout_); 194 pango_cairo_show_layout(cr, layout_);
153 cairo_restore(cr); 195 cairo_restore(cr);
154 196
155 // Draw the label. 197 // Draw the label.
156 int x_align_left = window_rect.width() - 198 int x_align_left = window_rect.width() -
157 font_.GetStringWidth(autofill_labels()[i]); 199 font_.GetStringWidth(autofill_labels()[i]);
158 gtk_util::SetLayoutText(layout_, autofill_labels()[i]); 200 gtk_util::SetLayoutText(layout_, autofill_labels()[i]);
159 201
160 cairo_save(cr); 202 cairo_save(cr);
161 cairo_move_to(cr, x_align_left, line_rect.y()); 203 cairo_move_to(cr, x_align_left, line_rect.y());
162 pango_cairo_show_layout(cr, layout_); 204 pango_cairo_show_layout(cr, layout_);
163 cairo_restore(cr); 205 cairo_restore(cr);
164 } 206 }
165 207
166 cairo_destroy(cr); 208 cairo_destroy(cr);
167 209
168 return TRUE; 210 return TRUE;
169 } 211 }
170 212
213 gboolean AutofillPopupViewGtk::HandleMotion(GtkWidget* widget,
214 GdkEventMotion* event) {
215 int line = LineFromY(event->y);
216
217 SetSelectedLine(line);
218
219 return TRUE;
220 }
221
171 void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect, 222 void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect,
172 const GdkColor& text_color) { 223 const GdkColor& text_color) {
173 int allocated_content_width = window_rect.width(); 224 int allocated_content_width = window_rect.width();
174 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); 225 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE);
175 pango_layout_set_height(layout_, row_height_ * PANGO_SCALE); 226 pango_layout_set_height(layout_, row_height_ * PANGO_SCALE);
176 227
177 PangoAttrList* attrs = pango_attr_list_new(); 228 PangoAttrList* attrs = pango_attr_list_new();
178 229
179 PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red, 230 PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red,
180 text_color.green, 231 text_color.green,
181 text_color.blue); 232 text_color.blue);
182 pango_attr_list_insert(attrs, fg_attr); // Ownership taken. 233 pango_attr_list_insert(attrs, fg_attr); // Ownership taken.
183 234
184 235
185 pango_layout_set_attributes(layout_, attrs); // Ref taken. 236 pango_layout_set_attributes(layout_, attrs); // Ref taken.
186 pango_attr_list_unref(attrs); 237 pango_attr_list_unref(attrs);
187 } 238 }
239
240 int AutofillPopupViewGtk::LineFromY(int y) {
241 return y / row_height_;
242 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698