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

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

Issue 10396003: Add Icon Support for New Autofill Gtk UI (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 7 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 <gdk/gdkkeysyms.h> 7 #include <gdk/gdkkeysyms.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/utf_string_conversions.h" 10 #include "base/utf_string_conversions.h"
11 #include "chrome/browser/autofill/autofill_external_delegate.h" 11 #include "chrome/browser/autofill/autofill_external_delegate.h"
12 #include "chrome/browser/ui/gtk/gtk_util.h" 12 #include "chrome/browser/ui/gtk/gtk_util.h"
13 #include "chrome/browser/ui/gtk/gtk_theme_service.h"
13 #include "content/public/browser/render_view_host.h" 14 #include "content/public/browser/render_view_host.h"
14 #include "content/public/browser/web_contents.h" 15 #include "content/public/browser/web_contents.h"
15 #include "ui/base/gtk/gtk_compat.h" 16 #include "ui/base/gtk/gtk_compat.h"
16 #include "ui/base/gtk/gtk_hig_constants.h" 17 #include "ui/base/gtk/gtk_hig_constants.h"
17 #include "ui/base/gtk/gtk_windowing.h" 18 #include "ui/base/gtk/gtk_windowing.h"
18 #include "ui/gfx/native_widget_types.h" 19 #include "ui/gfx/native_widget_types.h"
19 #include "ui/gfx/rect.h" 20 #include "ui/gfx/rect.h"
20 21
21 namespace { 22 namespace {
22 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); 23 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce);
23 const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0x0CD, 0xCD, 0xCD); 24 const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0x0CD, 0xCD, 0xCD);
24 const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); 25 const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00);
25 26
27 // The vertical height of each row in pixels.
28 const int kRowHeight = 24;
29
26 // The amount of minimum padding between the Autofill value and label in pixels. 30 // The amount of minimum padding between the Autofill value and label in pixels.
27 const int kMiddlePadding = 10; 31 const int kMiddlePadding = 10;
28 32
33 // The amount of padding between the label and icon or edge and icon in pixels.
34 const int kIconPadding = 5;
35
29 // We have a 1 pixel border around the entire results popup. 36 // We have a 1 pixel border around the entire results popup.
30 const int kBorderThickness = 1; 37 const int kBorderThickness = 1;
31 38
39 // Width of the icons in pixels.
40 const int kIconWidth = 25;
41
42 // Height of the icons in pixels.
43 const int kIconHeight = 16;
44
32 gfx::Rect GetWindowRect(GdkWindow* window) { 45 gfx::Rect GetWindowRect(GdkWindow* window) {
33 return gfx::Rect(gdk_window_get_width(window), 46 return gfx::Rect(gdk_window_get_width(window),
34 gdk_window_get_height(window)); 47 gdk_window_get_height(window));
35 } 48 }
36 49
37 // Returns the rectangle containing the item at position |index| in the popup. 50 // Returns the rectangle containing the item at position |index| in the popup.
38 gfx::Rect GetRectForRow(size_t index, int width, int height) { 51 gfx::Rect GetRectForRow(size_t index, int width) {
39 return gfx::Rect(0, (index * height), width, height); 52 return gfx::Rect(0, (index * kRowHeight), width, kRowHeight);
40 } 53 }
41 54
42 } // namespace 55 } // namespace
43 56
44 AutofillPopupViewGtk::AutofillPopupViewGtk( 57 AutofillPopupViewGtk::AutofillPopupViewGtk(
45 content::WebContents* web_contents, 58 content::WebContents* web_contents,
59 GtkThemeService* theme_service,
46 AutofillExternalDelegate* external_delegate, 60 AutofillExternalDelegate* external_delegate,
47 GtkWidget* parent) 61 GtkWidget* parent)
48 : AutofillPopupView(web_contents, external_delegate), 62 : AutofillPopupView(web_contents, external_delegate),
49 parent_(parent), 63 parent_(parent),
50 window_(gtk_window_new(GTK_WINDOW_POPUP)), 64 window_(gtk_window_new(GTK_WINDOW_POPUP)),
65 theme_service_(theme_service),
51 render_view_host_(web_contents->GetRenderViewHost()) { 66 render_view_host_(web_contents->GetRenderViewHost()) {
52 CHECK(parent != NULL); 67 CHECK(parent != NULL);
53 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); 68 gtk_window_set_resizable(GTK_WINDOW(window_), FALSE);
54 gtk_widget_set_app_paintable(window_, TRUE); 69 gtk_widget_set_app_paintable(window_, TRUE);
55 gtk_widget_set_double_buffered(window_, TRUE); 70 gtk_widget_set_double_buffered(window_, TRUE);
56 71
57 // Setup the window to ensure it receives the expose event. 72 // Setup the window to ensure it receives the expose event.
58 gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK | 73 gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK |
59 GDK_BUTTON_RELEASE_MASK | 74 GDK_BUTTON_RELEASE_MASK |
60 GDK_EXPOSURE_MASK | 75 GDK_EXPOSURE_MASK |
61 GDK_POINTER_MOTION_MASK); 76 GDK_POINTER_MOTION_MASK);
62 g_signal_connect(window_, "expose-event", 77 g_signal_connect(window_, "expose-event",
63 G_CALLBACK(HandleExposeThunk), this); 78 G_CALLBACK(HandleExposeThunk), this);
64 79
65 g_signal_connect(window_, "motion-notify-event", 80 g_signal_connect(window_, "motion-notify-event",
66 G_CALLBACK(HandleMotionThunk), this); 81 G_CALLBACK(HandleMotionThunk), this);
67 g_signal_connect(window_, "button-release-event", 82 g_signal_connect(window_, "button-release-event",
68 G_CALLBACK(HandleButtonReleaseThunk), this); 83 G_CALLBACK(HandleButtonReleaseThunk), this);
69 84
70 // Cache the layout so we don't have to create it for every expose. 85 // Cache the layout so we don't have to create it for every expose.
71 layout_ = gtk_widget_create_pango_layout(window_, NULL); 86 layout_ = gtk_widget_create_pango_layout(window_, NULL);
72
73 row_height_ = font_.GetHeight();
74 } 87 }
75 88
76 AutofillPopupViewGtk::~AutofillPopupViewGtk() { 89 AutofillPopupViewGtk::~AutofillPopupViewGtk() {
77 g_object_unref(layout_); 90 g_object_unref(layout_);
78 gtk_widget_destroy(window_); 91 gtk_widget_destroy(window_);
79 } 92 }
80 93
81 void AutofillPopupViewGtk::ShowInternal() { 94 void AutofillPopupViewGtk::ShowInternal() {
82 SetBounds(); 95 SetBounds();
83 gtk_window_move(GTK_WINDOW(window_), bounds_.x(), bounds_.y()); 96 gtk_window_move(GTK_WINDOW(window_), bounds_.x(), bounds_.y());
84 97
85 ResizePopup(); 98 ResizePopup();
86 99
87 render_view_host_->AddKeyboardListener(this); 100 render_view_host_->AddKeyboardListener(this);
88 101
89 gtk_widget_show(window_); 102 gtk_widget_show(window_);
90 103
91 GtkWidget* toplevel = gtk_widget_get_toplevel(parent_); 104 GtkWidget* toplevel = gtk_widget_get_toplevel(parent_);
92 CHECK(gtk_widget_is_toplevel(toplevel)); 105 CHECK(gtk_widget_is_toplevel(toplevel));
93 ui::StackPopupWindow(window_, toplevel); 106 ui::StackPopupWindow(window_, toplevel);
94 } 107 }
95 108
96 void AutofillPopupViewGtk::HideInternal() { 109 void AutofillPopupViewGtk::HideInternal() {
97 render_view_host_->RemoveKeyboardListener(this); 110 render_view_host_->RemoveKeyboardListener(this);
98 111
99 gtk_widget_hide(window_); 112 gtk_widget_hide(window_);
100 } 113 }
101 114
102 void AutofillPopupViewGtk::InvalidateRow(size_t row) { 115 void AutofillPopupViewGtk::InvalidateRow(size_t row) {
103 GdkRectangle row_rect = GetRectForRow( 116 GdkRectangle row_rect = GetRectForRow(row, bounds_.width()).ToGdkRectangle();
104 row, bounds_.width(), row_height_).ToGdkRectangle();
105 GdkWindow* gdk_window = gtk_widget_get_window(window_); 117 GdkWindow* gdk_window = gtk_widget_get_window(window_);
106 gdk_window_invalidate_rect(gdk_window, &row_rect, FALSE); 118 gdk_window_invalidate_rect(gdk_window, &row_rect, FALSE);
107 } 119 }
108 120
109 void AutofillPopupViewGtk::ResizePopup() { 121 void AutofillPopupViewGtk::ResizePopup() {
110 gtk_widget_set_size_request( 122 gtk_widget_set_size_request(
111 window_, 123 window_,
112 GetPopupRequiredWidth(), 124 GetPopupRequiredWidth(),
113 row_height_ * autofill_values().size()); 125 kRowHeight * autofill_values().size());
114 } 126 }
115 127
116 gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget, 128 gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget,
117 GdkEventButton* event) { 129 GdkEventButton* event) {
118 // We only care about the left click. 130 // We only care about the left click.
119 if (event->button != 1) 131 if (event->button != 1)
120 return FALSE; 132 return FALSE;
121 133
122 DCHECK_EQ(selected_line(), LineFromY(event->y)); 134 DCHECK_EQ(selected_line(), LineFromY(event->y));
123 135
(...skipping 21 matching lines...) Expand all
145 cairo_stroke(cr); 157 cairo_stroke(cr);
146 158
147 SetupLayout(window_rect, kTextColor); 159 SetupLayout(window_rect, kTextColor);
148 160
149 int actual_content_width, actual_content_height; 161 int actual_content_width, actual_content_height;
150 pango_layout_get_size(layout_, &actual_content_width, &actual_content_height); 162 pango_layout_get_size(layout_, &actual_content_width, &actual_content_height);
151 actual_content_width /= PANGO_SCALE; 163 actual_content_width /= PANGO_SCALE;
152 actual_content_height /= PANGO_SCALE; 164 actual_content_height /= PANGO_SCALE;
153 165
154 for (size_t i = 0; i < autofill_values().size(); ++i) { 166 for (size_t i = 0; i < autofill_values().size(); ++i) {
155 gfx::Rect line_rect = GetRectForRow(i, window_rect.width(), row_height_); 167 gfx::Rect line_rect = GetRectForRow(i, window_rect.width());
156 // Only repaint and layout damaged lines. 168 // Only repaint and layout damaged lines.
157 if (!line_rect.Intersects(damage_rect)) 169 if (!line_rect.Intersects(damage_rect))
158 continue; 170 continue;
159 171
160 if (IsSeparatorIndex(i)) { 172 if (IsSeparatorIndex(i)) {
161 int line_y = i * row_height_; 173 int line_y = i * kRowHeight;
162 174
163 cairo_save(cr); 175 cairo_save(cr);
164 cairo_move_to(cr, 0, line_y); 176 cairo_move_to(cr, 0, line_y);
165 cairo_line_to(cr, window_rect.width(), line_y); 177 cairo_line_to(cr, window_rect.width(), line_y);
166 cairo_stroke(cr); 178 cairo_stroke(cr);
167 cairo_restore(cr); 179 cairo_restore(cr);
168 } 180 }
169 181
170 if (selected_line() == static_cast<int>(i)) { 182 if (selected_line() == static_cast<int>(i)) {
171 gdk_cairo_set_source_color(cr, &kHoveredBackgroundColor); 183 gdk_cairo_set_source_color(cr, &kHoveredBackgroundColor);
172 cairo_rectangle(cr, line_rect.x(), line_rect.y(), 184 cairo_rectangle(cr, line_rect.x(), line_rect.y(),
173 line_rect.width(), line_rect.height()); 185 line_rect.width(), line_rect.height());
174 cairo_fill(cr); 186 cairo_fill(cr);
175 } 187 }
176 188
177 // Center the text within the line. 189 // Center the text within the line.
178 int content_y = std::max( 190 int content_y = std::max(
179 line_rect.y(), 191 line_rect.y(),
180 line_rect.y() + ((row_height_ - actual_content_height) / 2)); 192 line_rect.y() + ((kRowHeight - actual_content_height) / 2));
181 193
182 // Draw the value. 194 // Draw the value.
183 gtk_util::SetLayoutText(layout_, autofill_values()[i]); 195 gtk_util::SetLayoutText(layout_, autofill_values()[i]);
184 196
185 cairo_save(cr); 197 cairo_save(cr);
186 cairo_move_to(cr, 0, content_y); 198 cairo_move_to(cr, 0, content_y);
187 pango_cairo_show_layout(cr, layout_); 199 pango_cairo_show_layout(cr, layout_);
188 cairo_restore(cr); 200 cairo_restore(cr);
189 201
190 // Draw the label. 202 // Draw the label.
191 int x_align_left = window_rect.width() - 203 int x_align_left = window_rect.width() -
192 font_.GetStringWidth(autofill_labels()[i]); 204 font_.GetStringWidth(autofill_labels()[i]);
205
206 if (!autofill_icons()[i].empty())
207 x_align_left -= 2 * kIconPadding + kIconWidth;
208
193 gtk_util::SetLayoutText(layout_, autofill_labels()[i]); 209 gtk_util::SetLayoutText(layout_, autofill_labels()[i]);
194 210
195 cairo_save(cr); 211 cairo_save(cr);
196 cairo_move_to(cr, x_align_left, line_rect.y()); 212 cairo_move_to(cr, x_align_left, content_y);
197 pango_cairo_show_layout(cr, layout_); 213 pango_cairo_show_layout(cr, layout_);
198 cairo_restore(cr); 214 cairo_restore(cr);
215
216 // Draw the icon, if one exists
217 if (!autofill_icons()[i].empty()) {
218 int icon = GetIconResourceID(autofill_icons()[i]);
219 DCHECK_NE(-1, icon);
220 int icon_y = line_rect.y() + ((kRowHeight - kIconHeight) / 2);
221
222 cairo_save(cr);
223 gtk_util::DrawFullImage(cr,
224 window_,
225 theme_service_->GetImageNamed(icon),
226 window_rect.width() -
227 (kIconPadding + kIconWidth),
228 icon_y);
229 cairo_restore(cr);
230 }
199 } 231 }
200 232
201 cairo_destroy(cr); 233 cairo_destroy(cr);
202 234
203 return TRUE; 235 return TRUE;
204 } 236 }
205 237
206 gboolean AutofillPopupViewGtk::HandleMotion(GtkWidget* widget, 238 gboolean AutofillPopupViewGtk::HandleMotion(GtkWidget* widget,
207 GdkEventMotion* event) { 239 GdkEventMotion* event) {
208 int line = LineFromY(event->y); 240 int line = LineFromY(event->y);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 return AcceptSelectedLine(); 272 return AcceptSelectedLine();
241 } 273 }
242 274
243 return false; 275 return false;
244 } 276 }
245 277
246 void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect, 278 void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect,
247 const GdkColor& text_color) { 279 const GdkColor& text_color) {
248 int allocated_content_width = window_rect.width(); 280 int allocated_content_width = window_rect.width();
249 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); 281 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE);
250 pango_layout_set_height(layout_, row_height_ * PANGO_SCALE); 282 pango_layout_set_height(layout_, kRowHeight * PANGO_SCALE);
251 283
252 PangoAttrList* attrs = pango_attr_list_new(); 284 PangoAttrList* attrs = pango_attr_list_new();
253 285
254 PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red, 286 PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red,
255 text_color.green, 287 text_color.green,
256 text_color.blue); 288 text_color.blue);
257 pango_attr_list_insert(attrs, fg_attr); // Ownership taken. 289 pango_attr_list_insert(attrs, fg_attr); // Ownership taken.
258 290
259 291
260 pango_layout_set_attributes(layout_, attrs); // Ref taken. 292 pango_layout_set_attributes(layout_, attrs); // Ref taken.
261 pango_attr_list_unref(attrs); 293 pango_attr_list_unref(attrs);
262 } 294 }
263 295
264 void AutofillPopupViewGtk::SetBounds() { 296 void AutofillPopupViewGtk::SetBounds() {
265 gint origin_x, origin_y; 297 gint origin_x, origin_y;
266 gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y); 298 gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y);
267 299
268 GdkScreen* screen = gtk_widget_get_screen(parent_); 300 GdkScreen* screen = gtk_widget_get_screen(parent_);
269 gint screen_height = gdk_screen_get_height(screen); 301 gint screen_height = gdk_screen_get_height(screen);
270 302
271 int bottom_of_field = origin_y + element_bounds().y() + 303 int bottom_of_field = origin_y + element_bounds().y() +
272 element_bounds().height(); 304 element_bounds().height();
273 int popup_size = row_height_ * autofill_values().size(); 305 int popup_size = kRowHeight * autofill_values().size();
274 306
275 // Find the correct top position of the popup so that is doesn't go off 307 // Find the correct top position of the popup so that is doesn't go off
276 // the screen. 308 // the screen.
277 int top_of_popup = 0; 309 int top_of_popup = 0;
278 if (screen_height < bottom_of_field + popup_size) { 310 if (screen_height < bottom_of_field + popup_size) {
279 // The popup must appear above the field. 311 // The popup must appear above the field.
280 top_of_popup = origin_y + element_bounds().y() - popup_size; 312 top_of_popup = origin_y + element_bounds().y() - popup_size;
281 } else { 313 } else {
282 // The popup can appear below the field. 314 // The popup can appear below the field.
283 top_of_popup = bottom_of_field; 315 top_of_popup = bottom_of_field;
284 } 316 }
285 317
286 bounds_.SetRect( 318 bounds_.SetRect(
287 origin_x + element_bounds().x(), 319 origin_x + element_bounds().x(),
288 top_of_popup, 320 top_of_popup,
289 GetPopupRequiredWidth(), 321 GetPopupRequiredWidth(),
290 popup_size); 322 popup_size);
291 } 323 }
292 324
293 int AutofillPopupViewGtk::GetPopupRequiredWidth() { 325 int AutofillPopupViewGtk::GetPopupRequiredWidth() {
294 // TODO(csharp): Once the icon is also displayed it will affect the required
295 // size so it will need to be included in the calculation.
296 int popup_width = element_bounds().width(); 326 int popup_width = element_bounds().width();
297 DCHECK_EQ(autofill_values().size(), autofill_labels().size()); 327 DCHECK_EQ(autofill_values().size(), autofill_labels().size());
298 for (size_t i = 0; i < autofill_values().size(); ++i) { 328 for (size_t i = 0; i < autofill_values().size(); ++i) {
299 popup_width = std::max(popup_width, 329 int row_size = font_.GetStringWidth(autofill_values()[i]) +
300 font_.GetStringWidth(autofill_values()[i]) + 330 kMiddlePadding +
301 kMiddlePadding + 331 font_.GetStringWidth(autofill_labels()[i]);
302 font_.GetStringWidth(autofill_labels()[i])); 332
333 // Add the icon size if required.
334 if (!autofill_icons()[i].empty())
335 row_size += kIconWidth + 2 * kIconPadding;
336
337 popup_width = std::max(popup_width, row_size);
303 } 338 }
304 339
305 return popup_width; 340 return popup_width;
306 } 341 }
307 342
308 int AutofillPopupViewGtk::LineFromY(int y) { 343 int AutofillPopupViewGtk::LineFromY(int y) {
309 return y / row_height_; 344 return y / kRowHeight;
310 } 345 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.h ('k') | chrome/browser/ui/gtk/gtk_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698