Commit 7880bcec authored by estade@chromium.org's avatar estade@chromium.org

GTK: give the findbox curvy edges.

Most of the new code concerns shaping the widget to be non-rectangular.

Also, sprinkle some "const" qualifiers on NineBox functions.

Review URL: http://codereview.chromium.org/100224

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15014 0039d316-1c4b-4281-b951-d872f2087c98
parent 814a2d33
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chrome/browser/find_bar_controller.h" #include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/gtk/browser_window_gtk.h" #include "chrome/browser/gtk/browser_window_gtk.h"
#include "chrome/browser/gtk/custom_button.h" #include "chrome/browser/gtk/custom_button.h"
#include "chrome/browser/gtk/nine_box.h"
#include "chrome/browser/gtk/tab_contents_container_gtk.h" #include "chrome/browser/gtk/tab_contents_container_gtk.h"
#include "chrome/browser/tab_contents/web_contents.h" #include "chrome/browser/tab_contents/web_contents.h"
#include "chrome/common/gtk_util.h" #include "chrome/common/gtk_util.h"
...@@ -42,9 +43,36 @@ gboolean KeyPressEvent(GtkWindow* window, GdkEventKey* event, ...@@ -42,9 +43,36 @@ gboolean KeyPressEvent(GtkWindow* window, GdkEventKey* event,
return FALSE; return FALSE;
} }
// Get the ninebox that draws the background of |container_|. It is also used
// to change the shape of |container_|. The pointer is shared by all instances
// of FindBarGtk.
const NineBox* GetDialogBackground() {
static NineBox* dialog_background = NULL;
if (!dialog_background) {
dialog_background = new NineBox(
IDR_FIND_DLG_LEFT_BACKGROUND,
IDR_FIND_DLG_MIDDLE_BACKGROUND,
IDR_FIND_DLG_RIGHT_BACKGROUND,
NULL, NULL, NULL, NULL, NULL, NULL);
dialog_background->ChangeWhiteToTransparent();
}
return dialog_background;
}
// Used to handle custom painting of |container_|.
gboolean OnExpose(GtkWidget* widget, GdkEventExpose* e, gpointer userdata) {
GetDialogBackground()->RenderToWidget(widget);
GtkWidget* child = gtk_bin_get_child(GTK_BIN(widget));
if (child)
gtk_container_propagate_expose(GTK_CONTAINER(widget), child, e);
return TRUE;
} }
FindBarGtk::FindBarGtk(BrowserWindowGtk* browser) { } // namespace
FindBarGtk::FindBarGtk(BrowserWindowGtk* browser)
: container_shaped_(false) {
InitWidgets(); InitWidgets();
// Insert the widget into the browser gtk hierarchy. // Insert the widget into the browser gtk hierarchy.
...@@ -57,7 +85,11 @@ FindBarGtk::FindBarGtk(BrowserWindowGtk* browser) { ...@@ -57,7 +85,11 @@ FindBarGtk::FindBarGtk(BrowserWindowGtk* browser) {
g_signal_connect(find_text_, "key-press-event", g_signal_connect(find_text_, "key-press-event",
G_CALLBACK(KeyPressEvent), this); G_CALLBACK(KeyPressEvent), this);
g_signal_connect(widget(), "size-allocate", g_signal_connect(widget(), "size-allocate",
G_CALLBACK(OnSizeAllocate), this); G_CALLBACK(OnFixedSizeAllocate), this);
// We can't call ContourWidget() until after |container| has been
// allocated, hence we connect to this signal.
g_signal_connect(container_, "size-allocate",
G_CALLBACK(OnContainerSizeAllocate), this);
} }
FindBarGtk::~FindBarGtk() { FindBarGtk::~FindBarGtk() {
...@@ -73,13 +105,16 @@ void FindBarGtk::InitWidgets() { ...@@ -73,13 +105,16 @@ void FindBarGtk::InitWidgets() {
GtkWidget* hbox = gtk_hbox_new(false, 0); GtkWidget* hbox = gtk_hbox_new(false, 0);
container_ = gfx::CreateGtkBorderBin(hbox, &kBackgroundColor, container_ = gfx::CreateGtkBorderBin(hbox, &kBackgroundColor,
kBarPadding, kBarPadding, kBarPadding, kBarPadding); kBarPadding, kBarPadding, kBarPadding, kBarPadding);
fixed_.Own(gtk_fixed_new()); gtk_widget_set_app_paintable(container_, TRUE);
g_signal_connect(container_, "expose-event",
G_CALLBACK(OnExpose), NULL);
// |fixed_| has to be at least one pixel tall. We color this pixel the same // |fixed_| has to be at least one pixel tall. We color this pixel the same
// color as the border that separates the toolbar from the web contents. // color as the border that separates the toolbar from the web contents.
// TODO(estade): find a better solution. (Ideally the tool bar shouldn't draw // TODO(estade): find a better solution. (Ideally the tool bar shouldn't draw
// its own border, but the border is part of the background bitmap, so // its own border, but the border is part of the background bitmap, so
// changing that would affect all platforms.) // changing that would affect all platforms.)
fixed_.Own(gtk_fixed_new());
border_ = gtk_event_box_new(); border_ = gtk_event_box_new();
gtk_widget_set_size_request(border_, 1, 1); gtk_widget_set_size_request(border_, 1, 1);
gtk_widget_modify_bg(border_, GTK_STATE_NORMAL, &kBorderColor); gtk_widget_modify_bg(border_, GTK_STATE_NORMAL, &kBorderColor);
...@@ -237,9 +272,9 @@ void FindBarGtk::OnButtonPressed(GtkWidget* button, FindBarGtk* find_bar) { ...@@ -237,9 +272,9 @@ void FindBarGtk::OnButtonPressed(GtkWidget* button, FindBarGtk* find_bar) {
} }
// static // static
void FindBarGtk::OnSizeAllocate(GtkWidget* fixed, void FindBarGtk::OnFixedSizeAllocate(GtkWidget* fixed,
GtkAllocation* allocation, GtkAllocation* allocation,
FindBarGtk* findbar) { FindBarGtk* findbar) {
// Set the background widget to the size of |fixed|. // Set the background widget to the size of |fixed|.
if (findbar->border_->allocation.width != allocation->width) { if (findbar->border_->allocation.width != allocation->width) {
// Typically it's not a good idea to use this function outside of container // Typically it's not a good idea to use this function outside of container
...@@ -261,3 +296,13 @@ void FindBarGtk::OnSizeAllocate(GtkWidget* fixed, ...@@ -261,3 +296,13 @@ void FindBarGtk::OnSizeAllocate(GtkWidget* fixed,
gtk_fixed_move(GTK_FIXED(fixed), container, xposition, kVerticalOffset); gtk_fixed_move(GTK_FIXED(fixed), container, xposition, kVerticalOffset);
} }
} }
// static
void FindBarGtk::OnContainerSizeAllocate(GtkWidget* container,
GtkAllocation* allocation,
FindBarGtk* findbar) {
if (!findbar->container_shaped_) {
GetDialogBackground()->ContourWidget(container);
findbar->container_shaped_ = true;
}
}
...@@ -72,9 +72,15 @@ class FindBarGtk : public FindBar, ...@@ -72,9 +72,15 @@ class FindBarGtk : public FindBar,
static void OnButtonPressed(GtkWidget* button, FindBarGtk* find_bar); static void OnButtonPressed(GtkWidget* button, FindBarGtk* find_bar);
// Called when |fixed_| changes sizes. Used to position |container_|. // Called when |fixed_| changes sizes. Used to position |container_|.
static void OnSizeAllocate(GtkWidget* fixed, static void OnFixedSizeAllocate(GtkWidget* fixed,
GtkAllocation* allocation, GtkAllocation* allocation,
FindBarGtk* container_); FindBarGtk* findbar);
// Called when |container_| is allocated.
static void OnContainerSizeAllocate(GtkWidget* container,
GtkAllocation* allocation,
FindBarGtk* findbar);
// GtkFixed containing the find bar widgets. // GtkFixed containing the find bar widgets.
OwnedWidgetGtk fixed_; OwnedWidgetGtk fixed_;
...@@ -88,6 +94,10 @@ class FindBarGtk : public FindBar, ...@@ -88,6 +94,10 @@ class FindBarGtk : public FindBar,
// field, the buttons, etc.). // field, the buttons, etc.).
GtkWidget* container_; GtkWidget* container_;
// This will be set to true after ContourWidget() has been called so we don't
// call it twice.
bool container_shaped_;
// The widget where text is entered. // The widget where text is entered.
GtkWidget* find_text_; GtkWidget* find_text_;
......
...@@ -51,7 +51,7 @@ NineBox::NineBox(int top_left, int top, int top_right, int left, int center, ...@@ -51,7 +51,7 @@ NineBox::NineBox(int top_left, int top, int top_right, int left, int center,
NineBox::~NineBox() { NineBox::~NineBox() {
} }
void NineBox::RenderToWidget(GtkWidget* dst) { void NineBox::RenderToWidget(GtkWidget* dst) const {
// TODO(evanm): this is stupid; it should just be implemented with SkBitmaps // TODO(evanm): this is stupid; it should just be implemented with SkBitmaps
// and convert to a GdkPixbuf at the last second. // and convert to a GdkPixbuf at the last second.
...@@ -61,7 +61,7 @@ void NineBox::RenderToWidget(GtkWidget* dst) { ...@@ -61,7 +61,7 @@ void NineBox::RenderToWidget(GtkWidget* dst) {
// This function paints one row at a time. // This function paints one row at a time.
// To make indexing sane, |images| points at the current row of images, // To make indexing sane, |images| points at the current row of images,
// so images[0] always refers to the left-most image of the current row. // so images[0] always refers to the left-most image of the current row.
GdkPixbuf** images = &images_[0]; GdkPixbuf* const* images = &images_[0];
// The upper-left and lower-right corners of the center square in the // The upper-left and lower-right corners of the center square in the
// rendering of the ninebox. // rendering of the ninebox.
...@@ -113,14 +113,63 @@ void NineBox::RenderToWidget(GtkWidget* dst) { ...@@ -113,14 +113,63 @@ void NineBox::RenderToWidget(GtkWidget* dst) {
DrawPixbuf(dst, images[2], x2, y2); DrawPixbuf(dst, images[2], x2, y2);
} }
void NineBox::RenderTopCenterStrip(GtkWidget* dst, int x1, int x2, int y1) { void NineBox::RenderTopCenterStrip(GtkWidget* dst, int x1,
int x2, int y1) const {
TileImage(dst, images_[1], TileImage(dst, images_[1],
x1, y1, x1, y1,
x2, y1); x2, y1);
} }
void NineBox::ChangeWhiteToTransparent() {
for (int image_idx = 0; image_idx < 9; ++image_idx) {
GdkPixbuf* pixbuf = images_[image_idx];
if (!pixbuf)
continue;
guchar* pixels = gdk_pixbuf_get_pixels(pixbuf);
int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
for (int i = 0; i < gdk_pixbuf_get_height(pixbuf); ++i) {
for (int j = 0; j < gdk_pixbuf_get_width(pixbuf); ++j) {
guchar* pixel = &pixels[i * rowstride + j * 4];
if (pixel[0] == 0xff && pixel[1] == 0xff && pixel[2] == 0xff) {
pixel[3] = 0;
}
}
}
}
}
void NineBox::ContourWidget(GtkWidget* widget) const {
int x1 = gdk_pixbuf_get_width(images_[0]);
int x2 = widget->allocation.width - gdk_pixbuf_get_width(images_[2]);
// Paint the left and right sides.
GdkBitmap* mask = gdk_pixmap_new(NULL, widget->allocation.width,
widget->allocation.height, 1);
gdk_pixbuf_render_threshold_alpha(images_[0], mask,
0, 0,
0, 0, -1, -1,
1);
gdk_pixbuf_render_threshold_alpha(images_[2], mask,
0, 0,
x2, 0, -1, -1,
1);
// Assume no transparency in the middle rectangle.
cairo_t* cr = gdk_cairo_create(mask);
cairo_rectangle(cr, x1, 0, x2 - x1, widget->allocation.height);
cairo_fill(cr);
// Mask the widget's window's shape.
gtk_widget_shape_combine_mask(widget, mask, 0, 0);
g_object_unref(mask);
cairo_destroy(cr);
}
void NineBox::TileImage(GtkWidget* dst, GdkPixbuf* src, void NineBox::TileImage(GtkWidget* dst, GdkPixbuf* src,
int x1, int y1, int x2, int y2) { int x1, int y1, int x2, int y2) const {
GdkGC* gc = dst->style->fg_gc[GTK_WIDGET_STATE(dst)]; GdkGC* gc = dst->style->fg_gc[GTK_WIDGET_STATE(dst)];
const int src_width = gdk_pixbuf_get_width(src); const int src_width = gdk_pixbuf_get_width(src);
const int src_height = gdk_pixbuf_get_height(src); const int src_height = gdk_pixbuf_get_height(src);
......
...@@ -28,16 +28,26 @@ class NineBox { ...@@ -28,16 +28,26 @@ class NineBox {
// Render the NineBox to |dst|. // Render the NineBox to |dst|.
// The images will be tiled to fit into the widget. // The images will be tiled to fit into the widget.
void RenderToWidget(GtkWidget* dst); void RenderToWidget(GtkWidget* dst) const;
// Render the top row of images to |dst| between |x1| and |x2|. // Render the top row of images to |dst| between |x1| and |x2|.
// This is split from RenderToWidget so the toolbar can use it. // This is split from RenderToWidget so the toolbar can use it.
void RenderTopCenterStrip(GtkWidget* dst, int x1, int x2, int y1); void RenderTopCenterStrip(GtkWidget* dst, int x1, int x2, int y1) const;
// Change all pixels that are white in |images_| to have 0 opacity.
void ChangeWhiteToTransparent();
// Set the shape of |widget| to match that of the ninebox. Note that |widget|
// must have its own window and be allocated. Also, currently only the top
// three images are used.
// TODO(estade): extend this function to use all 9 images (if it's ever
// needed).
void ContourWidget(GtkWidget* widget) const;
private: private:
// Repeatedly stamp src across dst. // Repeatedly stamp src across dst.
void TileImage(GtkWidget* dst, GdkPixbuf* src, void TileImage(GtkWidget* dst, GdkPixbuf* src,
int x1, int y1, int x2, int y2); int x1, int y1, int x2, int y2) const;
GdkPixbuf* images_[9]; GdkPixbuf* images_[9];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment