Chromium Code Reviews| Index: chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| diff --git a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| index 5df1bdcef9f1bea5ddab2ef80c96dbcaeed4318b..a6e12d758f491abb5f869dbd5695b15835c4a03d 100644 |
| --- a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| +++ b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| @@ -5,7 +5,36 @@ |
| #include "autofill_popup_view_gtk.h" |
| #include "base/logging.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "chrome/browser/ui/gtk/gtk_util.h" |
| +#include "ui/gfx/rect.h" |
| +#include "ui/gfx/native_widget_types.h" |
| +#include "ui/base/gtk/gtk_compat.h" |
| +#include "ui/base/gtk/gtk_hig_constants.h" |
| #include "ui/base/gtk/gtk_windowing.h" |
| +#include "ui/gfx/font.h" |
| + |
| +namespace { |
| +const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); |
| +const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); |
| + |
| +// The amount of minimum padding between the autofill value and label in pixels. |
|
Ilya Sherman
2012/01/20 07:26:47
nit: "autofill" -> "Autofill"
csharp
2012/01/20 16:20:44
Done.
|
| +const int kMiddlePadding = 10; |
| + |
| +// We have a 1 pixel border around the entire results popup. |
| +const int kBorderThickness = 1; |
| + |
| +gfx::Rect GetWindowRect(GdkWindow* window) { |
| + return gfx::Rect(gdk_window_get_width(window), |
| + gdk_window_get_height(window)); |
| +} |
| + |
| +// Returns the rectangle containing the item at position |index| in the popup. |
| +gfx::Rect GetRectForRow(size_t index, int width, int height) { |
| + return gfx::Rect(0, (index * height), width, height); |
| +} |
| + |
| +} // namespace |
| AutofillPopupViewGtk::AutofillPopupViewGtk(content::WebContents* web_contents, |
| GtkWidget* parent) |
| @@ -21,9 +50,15 @@ AutofillPopupViewGtk::AutofillPopupViewGtk(content::WebContents* web_contents, |
| gtk_widget_add_events(window_, GDK_EXPOSURE_MASK); |
| g_signal_connect(window_, "expose-event", |
| G_CALLBACK(HandleExposeThunk), this); |
| + |
| + // Cache the layout so we don't have to create it for every expose. |
| + layout_ = gtk_widget_create_pango_layout(window_, NULL); |
| + |
| + row_height_ = font_.GetHeight(); |
| } |
| AutofillPopupViewGtk::~AutofillPopupViewGtk() { |
| + g_object_unref(layout_); |
| gtk_widget_destroy(window_); |
| } |
| @@ -31,23 +66,31 @@ void AutofillPopupViewGtk::Hide() { |
| gtk_widget_hide(window_); |
| } |
| -// TODO(csharp): Actually show the values. |
| -void AutofillPopupViewGtk::Show(const std::vector<string16>& autofill_values, |
| - const std::vector<string16>& autofill_labels, |
| - const std::vector<string16>& autofill_icons, |
| - const std::vector<int>& autofill_unique_ids, |
| - int separator_index) { |
| +void AutofillPopupViewGtk::ShowInternal() { |
| gint origin_x, origin_y; |
| gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y); |
| + // Move the popup to appear right below the text field it is using. |
| gtk_window_move(GTK_WINDOW(window_), |
| origin_x + element_bounds().x(), |
| origin_y + element_bounds().y() + element_bounds().height()); |
| + // Find out the maximum bounds required by the popup. |
| + // TODO(csharp): Once the icon is also displayed it will affect the required |
| + // size so it will need to be include in the calculation. |
|
Ilya Sherman
2012/01/20 07:26:47
nit: "include" -> "included"
csharp
2012/01/20 16:20:44
Done.
|
| + int popup_width = element_bounds().width(); |
| + DCHECK_EQ(autofill_values().size(), autofill_labels().size()); |
| + for (size_t i = 0; i < autofill_values().size(); ++i) { |
| + popup_width = std::max(popup_width, |
| + font_.GetStringWidth(autofill_values()[i]) + |
| + kMiddlePadding + |
| + font_.GetStringWidth(autofill_labels()[i])); |
| + } |
| + |
| gtk_widget_set_size_request( |
| window_, |
| - element_bounds().width(), |
| - element_bounds().height() * autofill_values.size()); |
| + popup_width, |
| + row_height_ * autofill_values().size()); |
| gtk_widget_show(window_); |
| @@ -58,5 +101,88 @@ void AutofillPopupViewGtk::Show(const std::vector<string16>& autofill_values, |
| gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, |
| GdkEventExpose* event) { |
| + gfx::Rect window_rect = GetWindowRect(event->window); |
| + gfx::Rect damage_rect = gfx::Rect(event->area); |
| + |
| + cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget))); |
| + gdk_cairo_rectangle(cr, &event->area); |
| + cairo_clip(cr); |
| + |
| + // This assert is kinda ugly, but it would be more currently unneeded work |
| + // to support painting a border that isn't 1 pixel thick. There is no point |
| + // in writing that code now, and explode if that day ever comes. |
| + COMPILE_ASSERT(kBorderThickness == 1, border_1px_implied); |
| + // Draw the 1px border around the entire window. |
| + gdk_cairo_set_source_color(cr, &kBorderColor); |
| + cairo_rectangle(cr, 0, 0, window_rect.width(), window_rect.height()); |
| + cairo_stroke(cr); |
| + |
| + SetupLayout(window_rect, kTextColor); |
| + |
| + int actual_content_width, actual_content_height; |
| + pango_layout_get_size(layout_, &actual_content_width, &actual_content_height); |
| + actual_content_width /= PANGO_SCALE; |
| + actual_content_height /= PANGO_SCALE; |
| + |
| + for (size_t i = 0; i < autofill_values().size(); ++i) { |
| + gfx::Rect line_rect = GetRectForRow(i, window_rect.width(), row_height_); |
| + // Only repaint and layout damaged lines. |
| + if (!line_rect.Intersects(damage_rect)) |
| + continue; |
| + |
| + if (separator_index() == static_cast<int>(i)) { |
| + int line_y = i * row_height_; |
| + |
| + cairo_save(cr); |
| + cairo_move_to(cr, 0, line_y); |
| + cairo_line_to(cr, window_rect.width(), line_y); |
| + cairo_stroke(cr); |
| + cairo_restore(cr); |
| + } |
| + |
| + // Center the text within the line. |
| + int content_y = std::max( |
| + line_rect.y(), |
| + line_rect.y() + ((row_height_ - actual_content_height) / 2)); |
| + |
| + // Draw the autofill value. |
|
Ilya Sherman
2012/01/20 07:26:47
nit: "autofill" -> "Autofill" (or just omit "Autof
csharp
2012/01/20 16:20:44
Done.
|
| + gtk_util::SetLayoutText(layout_, autofill_values()[i]); |
| + |
| + cairo_save(cr); |
| + cairo_move_to(cr, 0, content_y); |
| + pango_cairo_show_layout(cr, layout_); |
| + cairo_restore(cr); |
| + |
| + // Draw the autofill label. |
|
Ilya Sherman
2012/01/20 07:26:47
nit: Ditto
csharp
2012/01/20 16:20:44
Done.
|
| + int x_align_left = window_rect.width() - |
| + font_.GetStringWidth(autofill_labels()[i]); |
| + gtk_util::SetLayoutText(layout_, autofill_labels()[i]); |
| + |
| + cairo_save(cr); |
| + cairo_move_to(cr, x_align_left, line_rect.y()); |
| + pango_cairo_show_layout(cr, layout_); |
| + cairo_restore(cr); |
| + } |
| + |
| + cairo_destroy(cr); |
| + |
| return TRUE; |
| } |
| + |
| +void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect, |
| + const GdkColor& text_color) { |
| + int allocated_content_width = window_rect.width(); |
| + pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); |
| + pango_layout_set_height(layout_, row_height_ * PANGO_SCALE); |
| + |
| + PangoAttrList* attrs = pango_attr_list_new(); |
| + |
| + PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red, |
| + text_color.green, |
| + text_color.blue); |
| + pango_attr_list_insert(attrs, fg_attr); // Ownership taken. |
| + |
| + |
| + pango_layout_set_attributes(layout_, attrs); // Ref taken. |
| + pango_attr_list_unref(attrs); |
| +} |