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 "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 Loading... | |
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 } | |
OLD | NEW |