1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
4 * gimpcellrenderertoggle.c
5 * Copyright (C) 2003-2004 Sven Neumann <sven@gimp.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
25 #include "gimpwidgetsmarshal.h"
26 #include "gimpcellrenderertoggle.h"
29 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
46 static void gimp_cell_renderer_toggle_finalize (GObject *object);
47 static void gimp_cell_renderer_toggle_get_property (GObject *object,
51 static void gimp_cell_renderer_toggle_set_property (GObject *object,
55 static void gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
57 GdkRectangle *rectangle,
62 static void gimp_cell_renderer_toggle_render (GtkCellRenderer *cell,
63 #if GTK_CHECK_VERSION (2, 90, 8)
69 #if GTK_CHECK_VERSION (2, 90, 8)
70 const GdkRectangle *background_area,
71 const GdkRectangle *cell_area,
73 GdkRectangle *background_area,
74 GdkRectangle *cell_area,
75 GdkRectangle *expose_area,
77 GtkCellRendererState flags);
78 static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
82 GdkRectangle *background_area,
83 GdkRectangle *cell_area,
84 GtkCellRendererState flags);
85 static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
89 G_DEFINE_TYPE (GimpCellRendererToggle, gimp_cell_renderer_toggle,
90 GTK_TYPE_CELL_RENDERER_TOGGLE)
92 #define parent_class gimp_cell_renderer_toggle_parent_class
94 static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
98 gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass)
100 GObjectClass *object_class = G_OBJECT_CLASS (klass);
101 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
103 toggle_cell_signals[CLICKED] =
104 g_signal_new ("clicked",
105 G_OBJECT_CLASS_TYPE (object_class),
107 G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked),
109 _gimp_widgets_marshal_VOID__STRING_FLAGS,
112 GDK_TYPE_MODIFIER_TYPE);
114 object_class->finalize = gimp_cell_renderer_toggle_finalize;
115 object_class->get_property = gimp_cell_renderer_toggle_get_property;
116 object_class->set_property = gimp_cell_renderer_toggle_set_property;
118 cell_class->get_size = gimp_cell_renderer_toggle_get_size;
119 cell_class->render = gimp_cell_renderer_toggle_render;
120 cell_class->activate = gimp_cell_renderer_toggle_activate;
122 g_object_class_install_property (object_class,
124 g_param_spec_string ("stock-id",
129 g_object_class_install_property (object_class,
131 g_param_spec_int ("stock-size",
140 gimp_cell_renderer_toggle_init (GimpCellRendererToggle *toggle)
145 gimp_cell_renderer_toggle_finalize (GObject *object)
147 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
149 if (toggle->stock_id)
151 g_free (toggle->stock_id);
152 toggle->stock_id = NULL;
157 g_object_unref (toggle->pixbuf);
158 toggle->pixbuf = NULL;
161 G_OBJECT_CLASS (parent_class)->finalize (object);
165 gimp_cell_renderer_toggle_get_property (GObject *object,
170 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
175 g_value_set_string (value, toggle->stock_id);
177 case PROP_STOCK_SIZE:
178 g_value_set_int (value, toggle->stock_size);
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
188 gimp_cell_renderer_toggle_set_property (GObject *object,
193 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
198 if (toggle->stock_id)
199 g_free (toggle->stock_id);
200 toggle->stock_id = g_value_dup_string (value);
202 case PROP_STOCK_SIZE:
203 toggle->stock_size = g_value_get_int (value);
207 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
213 g_object_unref (toggle->pixbuf);
214 toggle->pixbuf = NULL;
219 gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
221 GdkRectangle *cell_area,
227 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
228 GtkStyle *style = gtk_widget_get_style (widget);
238 if (! toggle->stock_id)
240 GTK_CELL_RENDERER_CLASS (parent_class)->get_size (cell,
248 gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
249 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
251 if (! toggle->pixbuf)
252 gimp_cell_renderer_toggle_create_pixbuf (toggle, widget);
254 pixbuf_width = gdk_pixbuf_get_width (toggle->pixbuf);
255 pixbuf_height = gdk_pixbuf_get_height (toggle->pixbuf);
257 calc_width = (pixbuf_width +
258 (gint) xpad * 2 + style->xthickness * 2);
259 calc_height = (pixbuf_height +
260 (gint) ypad * 2 + style->ythickness * 2);
266 *height = calc_height;
272 *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
273 (1.0 - xalign) : xalign) *
274 (cell_area->width - calc_width));
275 *x_offset = MAX (*x_offset, 0);
280 *y_offset = yalign * (cell_area->height - calc_height);
281 *y_offset = MAX (*y_offset, 0);
287 gimp_cell_renderer_toggle_render (GtkCellRenderer *cell,
288 #if GTK_CHECK_VERSION (2, 90, 8)
294 #if GTK_CHECK_VERSION (2, 90, 8)
295 const GdkRectangle *background_area,
296 const GdkRectangle *cell_area,
298 GdkRectangle *background_area,
299 GdkRectangle *cell_area,
300 GdkRectangle *expose_area,
302 GtkCellRendererState flags)
304 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
305 GtkStyle *style = gtk_widget_get_style (widget);
306 GdkRectangle toggle_rect;
307 GdkRectangle draw_rect;
313 if (! toggle->stock_id)
315 GTK_CELL_RENDERER_CLASS (parent_class)->render (cell,
316 #if GTK_CHECK_VERSION (2, 90, 8)
324 #if !GTK_CHECK_VERSION (2, 90, 8)
331 gtk_cell_renderer_get_size (cell, widget, cell_area,
335 &toggle_rect.height);
337 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
338 toggle_rect.x += cell_area->x + xpad;
339 toggle_rect.y += cell_area->y + ypad;
340 toggle_rect.width -= xpad * 2;
341 toggle_rect.height -= ypad * 2;
343 if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
347 gtk_cell_renderer_toggle_get_active (GTK_CELL_RENDERER_TOGGLE (cell));
349 if (!gtk_cell_renderer_get_sensitive (cell))
351 state = GTK_STATE_INSENSITIVE;
353 else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
355 if (gtk_widget_has_focus (widget))
356 state = GTK_STATE_SELECTED;
358 state = GTK_STATE_ACTIVE;
362 if (gtk_cell_renderer_toggle_get_activatable (GTK_CELL_RENDERER_TOGGLE (cell)))
363 state = GTK_STATE_NORMAL;
365 state = GTK_STATE_INSENSITIVE;
368 #if !GTK_CHECK_VERSION (2, 90, 8)
369 if (gdk_rectangle_intersect (expose_area, cell_area, &draw_rect) &&
370 (flags & GTK_CELL_RENDERER_PRELIT))
371 gtk_paint_shadow (style,
374 active ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
377 toggle_rect.x, toggle_rect.y,
378 toggle_rect.width, toggle_rect.height);
383 GdkPixbuf *insensitive = NULL;
384 GdkPixbuf *pixbuf = toggle->pixbuf;
386 toggle_rect.x += style->xthickness;
387 toggle_rect.y += style->ythickness;
388 toggle_rect.width -= style->xthickness * 2;
389 toggle_rect.height -= style->ythickness * 2;
391 if (state == GTK_STATE_INSENSITIVE)
393 GtkIconSource *source;
395 source = gtk_icon_source_new ();
396 gtk_icon_source_set_pixbuf (source, pixbuf);
397 /* The size here is arbitrary; since size isn't
398 * wildcarded in the source, it isn't supposed to be
399 * scaled by the engine function
401 gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
402 gtk_icon_source_set_size_wildcarded (source, FALSE);
404 insensitive = gtk_style_render_icon (gtk_widget_get_style (widget),
406 gtk_widget_get_direction (widget),
407 GTK_STATE_INSENSITIVE,
411 "gimpcellrenderertoggle");
413 gtk_icon_source_free (source);
415 pixbuf = insensitive;
418 if (gdk_rectangle_intersect (&draw_rect, &toggle_rect, &draw_rect))
420 #if !GTK_CHECK_VERSION (2, 90, 8)
423 cr = gdk_cairo_create (window);
426 gdk_cairo_set_source_pixbuf (cr, pixbuf, toggle_rect.x, toggle_rect.y);
427 gdk_cairo_rectangle (cr, &draw_rect);
430 #if !GTK_CHECK_VERSION (2, 90, 8)
436 g_object_unref (insensitive);
441 gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
445 GdkRectangle *background_area,
446 GdkRectangle *cell_area,
447 GtkCellRendererState flags)
449 GtkCellRendererToggle *toggle = GTK_CELL_RENDERER_TOGGLE (cell);
451 if (gtk_cell_renderer_toggle_get_activatable (toggle))
453 GdkModifierType state = 0;
455 GTK_CELL_RENDERER_CLASS (parent_class)->activate (cell, event, widget,
456 path, background_area,
459 if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
460 state = ((GdkEventButton *) event)->state;
462 gimp_cell_renderer_toggle_clicked (GIMP_CELL_RENDERER_TOGGLE (cell),
472 gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
476 g_object_unref (toggle->pixbuf);
478 toggle->pixbuf = gtk_widget_render_icon (widget,
480 toggle->stock_size, NULL);
485 * gimp_cell_renderer_toggle_new:
486 * @stock_id: the stock_id of the icon to use for the active state
488 * Creates a custom version of the #GtkCellRendererToggle. Instead of
489 * showing the standard toggle button, it shows a stock icon if the
490 * cell is active and no icon otherwise. This cell renderer is for
491 * example used in the Layers treeview to indicate and control the
492 * layer's visibility by showing %GIMP_STOCK_VISIBLE.
494 * Return value: a new #GimpCellRendererToggle
499 gimp_cell_renderer_toggle_new (const gchar *stock_id)
501 return g_object_new (GIMP_TYPE_CELL_RENDERER_TOGGLE,
502 "stock_id", stock_id,
507 * gimp_cell_renderer_toggle_clicked:
508 * @cell: a #GimpCellRendererToggle
512 * Emits the "clicked" signal from a #GimpCellRendererToggle.
517 gimp_cell_renderer_toggle_clicked (GimpCellRendererToggle *cell,
519 GdkModifierType state)
521 g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell));
522 g_return_if_fail (path != NULL);
524 g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, path, state);