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 const GdkRectangle *rectangle,
62 static void gimp_cell_renderer_toggle_render (GtkCellRenderer *cell,
65 const GdkRectangle *background_area,
66 const GdkRectangle *cell_area,
67 GtkCellRendererState flags);
68 static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
72 const GdkRectangle *background_area,
73 const GdkRectangle *cell_area,
74 GtkCellRendererState flags);
75 static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
79 G_DEFINE_TYPE (GimpCellRendererToggle, gimp_cell_renderer_toggle,
80 GTK_TYPE_CELL_RENDERER_TOGGLE)
82 #define parent_class gimp_cell_renderer_toggle_parent_class
84 static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
88 gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass)
90 GObjectClass *object_class = G_OBJECT_CLASS (klass);
91 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
93 toggle_cell_signals[CLICKED] =
94 g_signal_new ("clicked",
95 G_OBJECT_CLASS_TYPE (object_class),
97 G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked),
99 _gimp_widgets_marshal_VOID__STRING_FLAGS,
102 GDK_TYPE_MODIFIER_TYPE);
104 object_class->finalize = gimp_cell_renderer_toggle_finalize;
105 object_class->get_property = gimp_cell_renderer_toggle_get_property;
106 object_class->set_property = gimp_cell_renderer_toggle_set_property;
108 cell_class->get_size = gimp_cell_renderer_toggle_get_size;
109 cell_class->render = gimp_cell_renderer_toggle_render;
110 cell_class->activate = gimp_cell_renderer_toggle_activate;
112 g_object_class_install_property (object_class,
114 g_param_spec_string ("stock-id",
119 g_object_class_install_property (object_class,
121 g_param_spec_int ("stock-size",
130 gimp_cell_renderer_toggle_init (GimpCellRendererToggle *toggle)
135 gimp_cell_renderer_toggle_finalize (GObject *object)
137 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
139 if (toggle->stock_id)
141 g_free (toggle->stock_id);
142 toggle->stock_id = NULL;
147 g_object_unref (toggle->pixbuf);
148 toggle->pixbuf = NULL;
151 G_OBJECT_CLASS (parent_class)->finalize (object);
155 gimp_cell_renderer_toggle_get_property (GObject *object,
160 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
165 g_value_set_string (value, toggle->stock_id);
167 case PROP_STOCK_SIZE:
168 g_value_set_int (value, toggle->stock_size);
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
178 gimp_cell_renderer_toggle_set_property (GObject *object,
183 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
188 if (toggle->stock_id)
189 g_free (toggle->stock_id);
190 toggle->stock_id = g_value_dup_string (value);
192 case PROP_STOCK_SIZE:
193 toggle->stock_size = g_value_get_int (value);
197 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
203 g_object_unref (toggle->pixbuf);
204 toggle->pixbuf = NULL;
209 gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
211 const GdkRectangle *cell_area,
217 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
218 GtkStyleContext *context = gtk_widget_get_style_context (widget);
229 if (! toggle->stock_id)
231 GTK_CELL_RENDERER_CLASS (parent_class)->get_size (cell,
239 gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
240 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
242 gtk_style_context_get_border (context, 0, &border);
244 if (! toggle->pixbuf)
245 gimp_cell_renderer_toggle_create_pixbuf (toggle, widget);
247 pixbuf_width = gdk_pixbuf_get_width (toggle->pixbuf);
248 pixbuf_height = gdk_pixbuf_get_height (toggle->pixbuf);
250 calc_width = (pixbuf_width + (gint) xpad * 2 + (border.left + border.right));
251 calc_height = (pixbuf_height + (gint) ypad * 2 + (border.top + border.bottom));
257 *height = calc_height;
263 *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
264 (1.0 - xalign) : xalign) *
265 (cell_area->width - calc_width));
266 *x_offset = MAX (*x_offset, 0);
271 *y_offset = yalign * (cell_area->height - calc_height);
272 *y_offset = MAX (*y_offset, 0);
278 gimp_cell_renderer_toggle_render (GtkCellRenderer *cell,
281 const GdkRectangle *background_area,
282 const GdkRectangle *cell_area,
283 GtkCellRendererState flags)
285 GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
286 GtkStyleContext *context = gtk_widget_get_style_context (widget);
287 GdkRectangle toggle_rect;
288 GdkRectangle draw_rect;
289 GdkRectangle clip_rect;
295 if (! toggle->stock_id)
297 GTK_CELL_RENDERER_CLASS (parent_class)->render (cell,
306 gtk_cell_renderer_get_size (cell, widget, cell_area,
310 &toggle_rect.height);
312 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
313 toggle_rect.x += cell_area->x + xpad;
314 toggle_rect.y += cell_area->y + ypad;
315 toggle_rect.width -= xpad * 2;
316 toggle_rect.height -= ypad * 2;
318 if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
322 gtk_cell_renderer_toggle_get_active (GTK_CELL_RENDERER_TOGGLE (cell));
324 if (!gtk_cell_renderer_get_sensitive (cell))
326 state = GTK_STATE_FLAG_INSENSITIVE;
328 else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
330 if (gtk_widget_has_focus (widget))
331 state = GTK_STATE_FLAG_SELECTED;
333 state = GTK_STATE_FLAG_ACTIVE;
337 if (gtk_cell_renderer_toggle_get_activatable (GTK_CELL_RENDERER_TOGGLE (cell)))
340 state = GTK_STATE_FLAG_INSENSITIVE;
343 if ((flags & GTK_CELL_RENDERER_PRELIT) &&
344 gdk_cairo_get_clip_rectangle(cr, &clip_rect) &&
345 gdk_rectangle_intersect (&clip_rect, cell_area, &draw_rect))
348 gtk_style_context_save (context);
349 gdk_cairo_rectangle (cr, &draw_rect);
351 gtk_render_frame (context, //gtk_widget_get_style_context (widget),
353 toggle_rect.x, toggle_rect.y,
354 toggle_rect.width, toggle_rect.height);
355 gtk_style_context_restore (context);
361 GdkPixbuf *insensitive = NULL;
362 GdkPixbuf *pixbuf = toggle->pixbuf;
363 GtkBorder border = { 1, 1, 1, 1 };
366 /* FIXME: for some reason calling gtk_style_context_get_border
367 * makes the icon only visible on hover, so use border = 1
368 * for now as a workaround
370 gtk_style_context_get_border (context, state, &border);
373 toggle_rect.x += border.left;
374 toggle_rect.y += border.top;
375 toggle_rect.width -= (border.left + border.right);
376 toggle_rect.height -= (border.top + border.bottom);
378 if (state & GTK_STATE_FLAG_INSENSITIVE)
380 GtkIconSource *source;
382 source = gtk_icon_source_new ();
383 gtk_icon_source_set_pixbuf (source, pixbuf);
384 /* The size here is arbitrary; since size isn't
385 * wildcarded in the source, it isn't supposed to be
386 * scaled by the engine function
388 gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
389 gtk_icon_source_set_size_wildcarded (source, FALSE);
391 gtk_style_context_save (context);
392 gtk_style_context_set_state (context, GTK_STATE_FLAG_INSENSITIVE);
393 insensitive = gtk_render_icon_pixbuf (context, source, (GtkIconSize)-1);
394 gtk_style_context_restore (context);
396 gtk_icon_source_free (source);
398 pixbuf = insensitive;
401 if (gdk_rectangle_intersect (&draw_rect, &toggle_rect, &draw_rect))
403 gdk_cairo_set_source_pixbuf (cr, pixbuf, toggle_rect.x, toggle_rect.y);
404 gdk_cairo_rectangle (cr, &draw_rect);
409 g_object_unref (insensitive);
414 gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
418 const GdkRectangle *background_area,
419 const GdkRectangle *cell_area,
420 GtkCellRendererState flags)
422 GtkCellRendererToggle *toggle = GTK_CELL_RENDERER_TOGGLE (cell);
424 if (gtk_cell_renderer_toggle_get_activatable (toggle))
426 GdkModifierType state = 0;
428 GTK_CELL_RENDERER_CLASS (parent_class)->activate (cell, event, widget,
429 path, background_area,
432 if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
433 state = ((GdkEventButton *) event)->state;
435 gimp_cell_renderer_toggle_clicked (GIMP_CELL_RENDERER_TOGGLE (cell),
445 gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
449 g_object_unref (toggle->pixbuf);
451 toggle->pixbuf = gtk_widget_render_icon_pixbuf (widget,
458 * gimp_cell_renderer_toggle_new:
459 * @stock_id: the stock_id of the icon to use for the active state
461 * Creates a custom version of the #GtkCellRendererToggle. Instead of
462 * showing the standard toggle button, it shows a stock icon if the
463 * cell is active and no icon otherwise. This cell renderer is for
464 * example used in the Layers treeview to indicate and control the
465 * layer's visibility by showing %GIMP_STOCK_VISIBLE.
467 * Return value: a new #GimpCellRendererToggle
472 gimp_cell_renderer_toggle_new (const gchar *stock_id)
474 return g_object_new (GIMP_TYPE_CELL_RENDERER_TOGGLE,
475 "stock_id", stock_id,
480 * gimp_cell_renderer_toggle_clicked:
481 * @cell: a #GimpCellRendererToggle
485 * Emits the "clicked" signal from a #GimpCellRendererToggle.
490 gimp_cell_renderer_toggle_clicked (GimpCellRendererToggle *cell,
492 GdkModifierType state)
494 g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell));
495 g_return_if_fail (path != NULL);
497 g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, path, state);