diff options
-rw-r--r-- | libempathy-gtk/empathy-cell-renderer-activatable.c | 342 | ||||
-rw-r--r-- | libempathy-gtk/empathy-cell-renderer-activatable.h | 1 |
2 files changed, 283 insertions, 60 deletions
diff --git a/libempathy-gtk/empathy-cell-renderer-activatable.c b/libempathy-gtk/empathy-cell-renderer-activatable.c index 6c7982682..29393f14c 100644 --- a/libempathy-gtk/empathy-cell-renderer-activatable.c +++ b/libempathy-gtk/empathy-cell-renderer-activatable.c @@ -1,7 +1,6 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2007 Raphael Slinckx <raphael@slinckx.net> - * Copyright (C) 2007-2008 Collabora Ltd. + * Copyright (C) 2007-2009 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,100 +17,323 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: Raphael Slinckx <raphael@slinckx.net> + * Cosimo Cecchi <cosimo.cecchi@collabora.co.uk> */ +#include <config.h> + #include <gtk/gtk.h> +#include <libempathy/empathy-utils.h> + #include "empathy-cell-renderer-activatable.h" -static void empathy_cell_renderer_activatable_init (EmpathyCellRendererActivatable *cell); -static void empathy_cell_renderer_activatable_class_init (EmpathyCellRendererActivatableClass *klass); -static gboolean cell_renderer_activatable_activate (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags); +enum { + PATH_ACTIVATED, + LAST_SIGNAL +}; enum { - PATH_ACTIVATED, - LAST_SIGNAL + PROP_SHOW_ON_SELECT = 1 }; +typedef struct { + gboolean show_on_select; +} EmpathyCellRendererActivatablePriv; + static guint signals[LAST_SIGNAL]; -G_DEFINE_TYPE (EmpathyCellRendererActivatable, empathy_cell_renderer_activatable, GTK_TYPE_CELL_RENDERER_PIXBUF) +G_DEFINE_TYPE (EmpathyCellRendererActivatable, + empathy_cell_renderer_activatable, GTK_TYPE_CELL_RENDERER_PIXBUF) + +#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCellRendererActivatable) static void empathy_cell_renderer_activatable_init (EmpathyCellRendererActivatable *cell) { - g_object_set (cell, - "xpad", 0, - "ypad", 0, - "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, - "follow-state", TRUE, - NULL); + cell->priv = G_TYPE_INSTANCE_GET_PRIVATE (cell, + EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE, + EmpathyCellRendererActivatablePriv); + + g_object_set (cell, + "xpad", 0, + "ypad", 0, + "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, + "follow-state", TRUE, + NULL); +} + +static void +cell_renderer_activatable_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyCellRendererActivatablePriv *priv = GET_PRIV (object); + + switch (prop_id) + { + case PROP_SHOW_ON_SELECT: + g_value_set_boolean (value, priv->show_on_select); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void -empathy_cell_renderer_activatable_class_init (EmpathyCellRendererActivatableClass *klass) +cell_renderer_activatable_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - GtkCellRendererClass *cell_class; - - cell_class = GTK_CELL_RENDERER_CLASS (klass); - cell_class->activate = cell_renderer_activatable_activate; - - signals[PATH_ACTIVATED] = - g_signal_new ("path-activated", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, - 1, G_TYPE_STRING); + EmpathyCellRendererActivatablePriv *priv = GET_PRIV (object); + + switch (prop_id) + { + case PROP_SHOW_ON_SELECT: + priv->show_on_select = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } GtkCellRenderer * empathy_cell_renderer_activatable_new (void) { - return g_object_new (EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE, NULL); + return g_object_new (EMPATHY_TYPE_CELL_RENDERER_ACTIVATABLE, NULL); } static gboolean cell_renderer_activatable_activate (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path_string, - GdkRectangle *background_area, - GdkRectangle *cell_area, - GtkCellRendererState flags) + GdkEvent *event, + GtkWidget *widget, + const gchar *path_string, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags) { - EmpathyCellRendererActivatable *activatable; - gint ex, ey, bx, by, bw, bh; + EmpathyCellRendererActivatable *activatable; + gint ex, ey, bx, by, bw, bh; - activatable = EMPATHY_CELL_RENDERER_ACTIVATABLE (cell); + activatable = EMPATHY_CELL_RENDERER_ACTIVATABLE (cell); - if (!GTK_IS_TREE_VIEW (widget) || event == NULL || - event->type != GDK_BUTTON_PRESS) { - return FALSE; - } + if (!GTK_IS_TREE_VIEW (widget) || event == NULL || + event->type != GDK_BUTTON_PRESS) { + return FALSE; + } - ex = (gint) ((GdkEventButton *) event)->x; - ey = (gint) ((GdkEventButton *) event)->y; - bx = background_area->x; - by = background_area->y; - bw = background_area->width; - bh = background_area->height; + ex = (gint) ((GdkEventButton *) event)->x; + ey = (gint) ((GdkEventButton *) event)->y; + bx = background_area->x; + by = background_area->y; + bw = background_area->width; + bh = background_area->height; + + if (ex < bx || ex > (bx+bw) || ey < by || ey > (by+bh)){ + /* Click wasn't on the icon */ + return FALSE; + } + + g_signal_emit (activatable, signals[PATH_ACTIVATED], 0, path_string); + + return TRUE; +} + +/* copied from gtkcellrendererpixbuf.c */ + +static GdkPixbuf * +create_colorized_pixbuf (GdkPixbuf *src, + GdkColor *new_color) +{ + gint i, j; + gint width, height, has_alpha, src_row_stride, dst_row_stride; + gint red_value, green_value, blue_value; + guchar *target_pixels; + guchar *original_pixels; + guchar *pixsrc; + guchar *pixdest; + GdkPixbuf *dest; + + red_value = new_color->red / 255.0; + green_value = new_color->green / 255.0; + blue_value = new_color->blue / 255.0; + + dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + gdk_pixbuf_get_has_alpha (src), + gdk_pixbuf_get_bits_per_sample (src), + gdk_pixbuf_get_width (src), + gdk_pixbuf_get_height (src)); + + has_alpha = gdk_pixbuf_get_has_alpha (src); + width = gdk_pixbuf_get_width (src); + height = gdk_pixbuf_get_height (src); + src_row_stride = gdk_pixbuf_get_rowstride (src); + dst_row_stride = gdk_pixbuf_get_rowstride (dest); + target_pixels = gdk_pixbuf_get_pixels (dest); + original_pixels = gdk_pixbuf_get_pixels (src); + + for (i = 0; i < height; i++) + { + pixdest = target_pixels + i*dst_row_stride; + pixsrc = original_pixels + i*src_row_stride; + for (j = 0; j < width; j++) + { + *pixdest++ = (*pixsrc++ * red_value) >> 8; + *pixdest++ = (*pixsrc++ * green_value) >> 8; + *pixdest++ = (*pixsrc++ * blue_value) >> 8; + if (has_alpha) + *pixdest++ = *pixsrc++; + } + } + + return dest; +} - if (ex < bx || ex > (bx+bw) || ey < by || ey > (by+bh)){ - /* Click wasn't on the icon */ - return FALSE; +static void +cell_renderer_activatable_render ( + GtkCellRenderer *cell, + GdkWindow *window, + GtkWidget *widget, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GdkRectangle *expose_area, + GtkCellRendererState flags) +{ + GdkPixbuf *pixbuf; + GdkPixbuf *invisible = NULL; + GdkPixbuf *colorized = NULL; + GdkRectangle pix_rect; + GdkRectangle draw_rect; + GtkStyle *style; + gboolean follow_state; + cairo_t *cr; + int xpad, ypad; + EmpathyCellRendererActivatablePriv *priv = GET_PRIV (cell); + + if (priv->show_on_select && !(flags & (GTK_CELL_RENDERER_SELECTED))) + return; + + g_object_get (cell, + "follow-state", &follow_state, + "xpad", &xpad, + "ypad", &ypad, + "pixbuf", &pixbuf, + NULL); + style = gtk_widget_get_style (widget); + + gtk_cell_renderer_get_size (cell, widget, cell_area, + &pix_rect.x, + &pix_rect.y, + &pix_rect.width, + &pix_rect.height); + + pix_rect.x += cell_area->x + xpad; + pix_rect.y += cell_area->y + ypad; + pix_rect.width -= xpad * 2; + pix_rect.height -= ypad * 2; + + if (!gdk_rectangle_intersect (cell_area, &pix_rect, &draw_rect) || + !gdk_rectangle_intersect (expose_area, &draw_rect, &draw_rect)) + return; + + if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE || !cell->sensitive) + { + GtkIconSource *source; + + source = gtk_icon_source_new (); + gtk_icon_source_set_pixbuf (source, pixbuf); + /* The size here is arbitrary; since size isn't + * wildcarded in the source, it isn't supposed to be + * scaled by the engine function + */ + gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR); + gtk_icon_source_set_size_wildcarded (source, FALSE); + + invisible = gtk_style_render_icon (style, + source, + gtk_widget_get_direction (widget), + GTK_STATE_INSENSITIVE, + /* arbitrary */ + (GtkIconSize)-1, + widget, + "gtkcellrendererpixbuf"); + + gtk_icon_source_free (source); + + pixbuf = invisible; + } + else if (follow_state && + (flags & (GTK_CELL_RENDERER_SELECTED|GTK_CELL_RENDERER_PRELIT)) != 0) + { + GtkStateType state; + + if ((flags & GTK_CELL_RENDERER_SELECTED) != 0) + { + if (GTK_WIDGET_HAS_FOCUS (widget)) + state = GTK_STATE_SELECTED; + else + state = GTK_STATE_ACTIVE; } + else + state = GTK_STATE_PRELIGHT; - g_signal_emit (activatable, signals[PATH_ACTIVATED], 0, path_string); + colorized = create_colorized_pixbuf (pixbuf, + &style->base[state]); - return TRUE; + pixbuf = colorized; + } + + cr = gdk_cairo_create (window); + + gdk_cairo_set_source_pixbuf (cr, pixbuf, pix_rect.x, pix_rect.y); + gdk_cairo_rectangle (cr, &draw_rect); + cairo_fill (cr); + + cairo_destroy (cr); + + if (invisible != NULL) + g_object_unref (invisible); + + if (colorized != NULL) + g_object_unref (colorized); } +static void +empathy_cell_renderer_activatable_class_init ( + EmpathyCellRendererActivatableClass *klass) +{ + GtkCellRendererClass *cell_class; + GObjectClass *oclass; + + oclass = G_OBJECT_CLASS (klass); + oclass->get_property = cell_renderer_activatable_get_property; + oclass->set_property = cell_renderer_activatable_set_property; + + cell_class = GTK_CELL_RENDERER_CLASS (klass); + cell_class->activate = cell_renderer_activatable_activate; + cell_class->render = cell_renderer_activatable_render; + + signals[PATH_ACTIVATED] = + g_signal_new ("path-activated", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + + g_object_class_install_property (oclass, PROP_SHOW_ON_SELECT, + g_param_spec_boolean ("show-on-select", + "Show on select", + "Whether the cell renderer should be shown only when it's selected", + FALSE, + G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); + + g_type_class_add_private (klass, + sizeof (EmpathyCellRendererActivatablePriv)); +} diff --git a/libempathy-gtk/empathy-cell-renderer-activatable.h b/libempathy-gtk/empathy-cell-renderer-activatable.h index d58a082da..b4564ee72 100644 --- a/libempathy-gtk/empathy-cell-renderer-activatable.h +++ b/libempathy-gtk/empathy-cell-renderer-activatable.h @@ -39,6 +39,7 @@ typedef struct _EmpathyCellRendererActivatableClass EmpathyCellRendererActivatab struct _EmpathyCellRendererActivatable { GtkCellRendererPixbuf parent; + gpointer priv; }; struct _EmpathyCellRendererActivatableClass { |