1 /* cellrenderericon.c, based on:
3 * gtkcellrendererpixbuf.c
4 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 #include "cellrenderericon.h"
27 #define FIXED_ICON_SIZE_MAX 512
29 static void gqv_cell_renderer_icon_get_property(GObject *object,
33 static void gqv_cell_renderer_icon_set_property(GObject *object,
37 static void gqv_cell_renderer_icon_init(GQvCellRendererIcon *celltext);
38 static void gqv_cell_renderer_icon_class_init(GQvCellRendererIconClass *class);
39 static void gqv_cell_renderer_icon_finalize(GObject *object);
40 static void gqv_cell_renderer_icon_get_size(GtkCellRenderer *cell,
42 GdkRectangle *rectangle,
47 static void gqv_cell_renderer_icon_render(GtkCellRenderer *cell,
50 GdkRectangle *background_area,
51 GdkRectangle *cell_area,
52 GdkRectangle *expose_area,
53 GtkCellRendererState flags);
71 static gpointer parent_class;
74 gqv_cell_renderer_icon_get_type(void)
76 static GType cell_icon_type = 0;
80 static const GTypeInfo cell_icon_info =
82 sizeof(GQvCellRendererIconClass),
84 NULL, /* base_finalize */
85 (GClassInitFunc) gqv_cell_renderer_icon_class_init,
86 NULL, /* class_finalize */
87 NULL, /* class_data */
88 sizeof(GQvCellRendererIcon),
90 (GInstanceInitFunc) gqv_cell_renderer_icon_init,
93 cell_icon_type = g_type_register_static(GTK_TYPE_CELL_RENDERER,
94 "GQvCellRendererIcon",
98 return cell_icon_type;
102 gqv_cell_renderer_icon_init(GQvCellRendererIcon *cellicon)
104 GTK_CELL_RENDERER(cellicon)->xpad = 2;
105 GTK_CELL_RENDERER(cellicon)->ypad = 2;
109 gqv_cell_renderer_icon_class_init(GQvCellRendererIconClass *class)
111 GObjectClass *object_class = G_OBJECT_CLASS(class);
112 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(class);
114 parent_class = g_type_class_peek_parent(class);
116 object_class->finalize = gqv_cell_renderer_icon_finalize;
118 object_class->get_property = gqv_cell_renderer_icon_get_property;
119 object_class->set_property = gqv_cell_renderer_icon_set_property;
121 cell_class->get_size = gqv_cell_renderer_icon_get_size;
122 cell_class->render = gqv_cell_renderer_icon_render;
124 g_object_class_install_property(object_class,
126 g_param_spec_object("pixbuf",
128 _("The pixbuf to render"),
132 g_object_class_install_property(object_class,
134 g_param_spec_string("text",
140 g_object_class_install_property(object_class,
142 g_param_spec_boxed("background_gdk",
143 _("Background color"),
144 _("Background color as a GdkColor"),
148 g_object_class_install_property(object_class,
150 g_param_spec_boxed("foreground_gdk",
151 _("Foreground color"),
152 _("Foreground color as a GdkColor"),
156 g_object_class_install_property(object_class,
158 g_param_spec_boolean("has_focus",
160 _("Draw focus indicator"),
164 g_object_class_install_property(object_class,
166 g_param_spec_int("fixed_width",
169 -1, FIXED_ICON_SIZE_MAX,
173 g_object_class_install_property(object_class,
175 g_param_spec_int("fixed_height",
177 _("Height of icon excluding text"),
178 -1, FIXED_ICON_SIZE_MAX,
182 g_object_class_install_property(object_class,
184 g_param_spec_boolean("background_set",
186 _("Whether this tag affects the background color"),
190 g_object_class_install_property(object_class,
192 g_param_spec_boolean("foreground_set",
194 _("Whether this tag affects the foreground color"),
198 g_object_class_install_property(object_class,
200 g_param_spec_boolean("show_text",
202 _("Whether the text is displayed"),
208 gqv_cell_renderer_icon_finalize(GObject *object)
210 GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON(object);
212 if (cellicon->pixbuf) g_object_unref(cellicon->pixbuf);
214 g_free(cellicon->text);
216 (*(G_OBJECT_CLASS(parent_class))->finalize)(object);
220 gqv_cell_renderer_icon_get_property(GObject *object,
225 GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON(object);
230 g_value_set_object(value,
231 cellicon->pixbuf ? G_OBJECT(cellicon->pixbuf) : NULL);
234 g_value_set_string(value, cellicon->text);
236 case PROP_BACKGROUND_GDK:
240 color.red = cellicon->background.red;
241 color.green = cellicon->background.green;
242 color.blue = cellicon->background.blue;
244 g_value_set_boxed(value, &color);
247 case PROP_FOREGROUND_GDK:
251 color.red = cellicon->foreground.red;
252 color.green = cellicon->foreground.green;
253 color.blue = cellicon->foreground.blue;
255 g_value_set_boxed(value, &color);
259 g_value_set_boolean(value, cellicon->focused);
261 case PROP_FIXED_WIDTH:
262 g_value_set_int(value, cellicon->fixed_width);
264 case PROP_FIXED_HEIGHT:
265 g_value_set_int(value, cellicon->fixed_height);
267 case PROP_BACKGROUND_SET:
268 g_value_set_boolean(value, cellicon->background_set);
270 case PROP_FOREGROUND_SET:
271 g_value_set_boolean(value, cellicon->foreground_set);
274 g_value_set_boolean(value, cellicon->show_text);
277 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
283 set_bg_color(GQvCellRendererIcon *cellicon,
288 if (!cellicon->background_set)
290 cellicon->background_set = TRUE;
291 g_object_notify(G_OBJECT(cellicon), "background_set");
294 cellicon->background.red = color->red;
295 cellicon->background.green = color->green;
296 cellicon->background.blue = color->blue;
300 if (cellicon->background_set)
302 cellicon->background_set = FALSE;
303 g_object_notify(G_OBJECT(cellicon), "background_set");
308 static void set_fg_color(GQvCellRendererIcon *cellicon,
313 if (!cellicon->foreground_set)
315 cellicon->foreground_set = TRUE;
316 g_object_notify(G_OBJECT(cellicon), "foreground_set");
319 cellicon->foreground.red = color->red;
320 cellicon->foreground.green = color->green;
321 cellicon->foreground.blue = color->blue;
325 if (cellicon->foreground_set)
327 cellicon->foreground_set = FALSE;
328 g_object_notify(G_OBJECT(cellicon), "foreground_set");
334 gqv_cell_renderer_icon_set_property(GObject *object,
339 GQvCellRendererIcon *cellicon = GQV_CELL_RENDERER_ICON(object);
347 pixbuf = (GdkPixbuf*) g_value_get_object(value);
348 if (pixbuf) g_object_ref(pixbuf);
349 if (cellicon->pixbuf) g_object_unref(cellicon->pixbuf);
350 cellicon->pixbuf = pixbuf;
357 text = cellicon->text;
358 cellicon->text = g_strdup(g_value_get_string(value));
361 g_object_notify(object, "text");
364 case PROP_BACKGROUND_GDK:
365 set_bg_color(cellicon, g_value_get_boxed(value));
367 case PROP_FOREGROUND_GDK:
368 set_fg_color(cellicon, g_value_get_boxed(value));
371 cellicon->focused = g_value_get_boolean(value);
373 case PROP_FIXED_WIDTH:
374 cellicon->fixed_width = g_value_get_int(value);
376 case PROP_FIXED_HEIGHT:
377 cellicon->fixed_height = g_value_get_int(value);
379 case PROP_BACKGROUND_SET:
380 cellicon->background_set = g_value_get_boolean(value);
382 case PROP_FOREGROUND_SET:
383 cellicon->foreground_set = g_value_get_boolean(value);
386 cellicon->show_text = g_value_get_boolean(value);
389 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
395 gqv_cell_renderer_icon_get_layout(GQvCellRendererIcon *cellicon, GtkWidget *widget, gboolean will_render)
400 width = (cellicon->fixed_width > 0) ? cellicon->fixed_width * PANGO_SCALE : -1;
402 layout = gtk_widget_create_pango_layout(widget, cellicon->text);
403 pango_layout_set_width(layout, width);
404 pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
405 pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
409 PangoAttrList *attr_list;
411 attr_list = pango_attr_list_new();
413 if (cellicon->foreground_set)
416 PangoAttribute *attr;
418 color = cellicon->foreground;
420 attr = pango_attr_foreground_new(color.red, color.green, color.blue);
422 attr->start_index = 0;
423 attr->end_index = G_MAXINT;
424 pango_attr_list_insert(attr_list, attr);
427 pango_layout_set_attributes(layout, attr_list);
428 pango_attr_list_unref(attr_list);
435 * gqv_cell_renderer_icon_new:
437 * Creates a new #GQvCellRendererIcon. Adjust rendering
438 * parameters using object properties. Object properties can be set
439 * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you
440 * can bind a property to a value in a #GtkTreeModel. For example, you
441 * can bind the "pixbuf" property on the cell renderer to a pixbuf value
442 * in the model, thus rendering a different image in each row of the
445 * Return value: the new cell renderer
448 gqv_cell_renderer_icon_new(void)
450 return g_object_new (GQV_TYPE_CELL_RENDERER_ICON, NULL);
454 gqv_cell_renderer_icon_get_size(GtkCellRenderer *cell,
456 GdkRectangle *cell_area,
462 GQvCellRendererIcon *cellicon = (GQvCellRendererIcon *) cell;
466 if (cellicon->fixed_width > 0)
468 calc_width = cellicon->fixed_width;
472 calc_width = (cellicon->pixbuf) ? gdk_pixbuf_get_width(cellicon->pixbuf) : 0;
475 if (cellicon->fixed_height > 0)
477 calc_height = cellicon->fixed_height;
481 calc_height = (cellicon->pixbuf) ? gdk_pixbuf_get_height(cellicon->pixbuf) : 0;
484 if (cellicon->show_text && cellicon->text)
489 layout = gqv_cell_renderer_icon_get_layout(cellicon, widget, FALSE);
490 pango_layout_get_pixel_extents(layout, NULL, &rect);
491 g_object_unref(layout);
493 calc_width = MAX(calc_width, rect.width);
494 calc_height += rect.height;
497 calc_width += (gint)cell->xpad * 2;
498 calc_height += (gint)cell->ypad * 2;
500 if (x_offset) *x_offset = 0;
501 if (y_offset) *y_offset = 0;
503 if (cell_area && calc_width > 0 && calc_height > 0)
507 *x_offset = (cell->xalign * (cell_area->width - calc_width - 2 * cell->xpad));
508 *x_offset = MAX(*x_offset, 0) + cell->xpad;
512 *y_offset = (cell->yalign * (cell_area->height - calc_height - 2 * cell->ypad));
513 *y_offset = MAX(*y_offset, 0) + cell->ypad;
517 if (width) *width = calc_width;
518 if (height) *height = calc_height;
522 gqv_cell_renderer_icon_render(GtkCellRenderer *cell,
525 GdkRectangle *background_area,
526 GdkRectangle *cell_area,
527 GdkRectangle *expose_area,
528 GtkCellRendererState flags)
531 GQvCellRendererIcon *cellicon = (GQvCellRendererIcon *) cell;
534 GdkRectangle cell_rect;
537 pixbuf = cellicon->pixbuf;
538 text = cellicon->text;
540 if (!pixbuf && !text) return;
542 gqv_cell_renderer_icon_get_size(cell, widget, cell_area,
543 &cell_rect.x, &cell_rect.y,
544 &cell_rect.width, &cell_rect.height);
546 cell_rect.x += cell->xpad;
547 cell_rect.y += cell->ypad;
548 cell_rect.width -= cell->xpad * 2;
549 cell_rect.height -= cell->ypad * 2;
551 if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
553 if (GTK_WIDGET_HAS_FOCUS(widget))
554 state = GTK_STATE_SELECTED;
556 state = GTK_STATE_ACTIVE;
560 if (GTK_WIDGET_STATE(widget) == GTK_STATE_INSENSITIVE)
561 state = GTK_STATE_INSENSITIVE;
563 state = GTK_STATE_NORMAL;
568 GdkRectangle pix_rect;
569 GdkRectangle draw_rect;
571 pix_rect.width = gdk_pixbuf_get_width(pixbuf);
572 pix_rect.height = gdk_pixbuf_get_height(pixbuf);
574 pix_rect.x = cell_area->x + (cell_area->width - pix_rect.width) / 2;
576 if (cellicon->fixed_height > 0)
578 pix_rect.y = cell_area->y + cell->ypad + (cellicon->fixed_height - pix_rect.height) / 2;
582 pix_rect.y = cell_area->y + cell_rect.y;
585 if (gdk_rectangle_intersect(cell_area, &pix_rect, &draw_rect) &&
586 gdk_rectangle_intersect(expose_area, &draw_rect, &draw_rect))
588 gdk_draw_pixbuf(window,
589 widget->style->black_gc,
591 /* pixbuf 0, 0 is at pix_rect.x, pix_rect.y */
592 draw_rect.x - pix_rect.x,
593 draw_rect.y - pix_rect.y,
598 GDK_RGB_DITHER_NORMAL,
603 if (cellicon->show_text && text)
606 PangoRectangle text_rect;
607 GdkRectangle pix_rect;
608 GdkRectangle draw_rect;
610 layout = gqv_cell_renderer_icon_get_layout(cellicon, widget, TRUE);
611 pango_layout_get_pixel_extents(layout, NULL, &text_rect);
613 pix_rect.width = text_rect.width;
614 pix_rect.height = text_rect.height;
615 pix_rect.x = cell_area->x + cell->xpad + (cell_rect.width - text_rect.width + 1) / 2;
616 pix_rect.y = cell_area->y + cell->ypad + (cell_rect.height - text_rect.height);
618 if (gdk_rectangle_intersect(cell_area, &pix_rect, &draw_rect) &&
619 gdk_rectangle_intersect(expose_area, &draw_rect, &draw_rect))
621 gtk_paint_layout(widget->style, window,
625 pix_rect.x - text_rect.x, pix_rect.y,
629 g_object_unref(layout);
632 if (cellicon->focused &&
633 GTK_WIDGET_HAS_FOCUS(widget))
635 gtk_paint_focus(widget->style, window,
639 cell_area->x, cell_area->y,
640 cell_area->width, cell_area->height);