]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/gimpcellrenderertoggle/gimpcellrenderertoggle.c
47da7cad6a6dc47bfce3b0b1297d3be50ccafe46
[evince.git] / cut-n-paste / gimpcellrenderertoggle / gimpcellrenderertoggle.c
1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3  *
4  * gimpcellrenderertoggle.c
5  * Copyright (C) 2003-2004  Sven Neumann <sven@gimp.org>
6  *
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.
11  *
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.
16  *
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <config.h>
24
25 #include "gimpwidgetsmarshal.h"
26 #include "gimpcellrenderertoggle.h"
27
28
29 #define DEFAULT_ICON_SIZE  GTK_ICON_SIZE_BUTTON
30
31
32 enum
33 {
34   CLICKED,
35   LAST_SIGNAL
36 };
37
38 enum
39 {
40   PROP_0,
41   PROP_STOCK_ID,
42   PROP_STOCK_SIZE
43 };
44
45
46 static void gimp_cell_renderer_toggle_finalize     (GObject         *object);
47 static void gimp_cell_renderer_toggle_get_property (GObject         *object,
48                                                     guint            param_id,
49                                                     GValue          *value,
50                                                     GParamSpec      *pspec);
51 static void gimp_cell_renderer_toggle_set_property (GObject         *object,
52                                                     guint            param_id,
53                                                     const GValue    *value,
54                                                     GParamSpec      *pspec);
55 static void gimp_cell_renderer_toggle_get_size     (GtkCellRenderer *cell,
56                                                     GtkWidget       *widget,
57                                                     GdkRectangle    *rectangle,
58                                                     gint            *x_offset,
59                                                     gint            *y_offset,
60                                                     gint            *width,
61                                                     gint            *height);
62 static void gimp_cell_renderer_toggle_render       (GtkCellRenderer *cell,
63                                                     GdkWindow       *window,
64                                                     GtkWidget       *widget,
65                                                     GdkRectangle    *background_area,
66                                                     GdkRectangle    *cell_area,
67                                                     GdkRectangle    *expose_area,
68                                                     GtkCellRendererState flags);
69 static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
70                                                     GdkEvent        *event,
71                                                     GtkWidget       *widget,
72                                                     const gchar     *path,
73                                                     GdkRectangle    *background_area,
74                                                     GdkRectangle    *cell_area,
75                                                     GtkCellRendererState  flags);
76 static void gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
77                                                      GtkWidget              *widget);
78
79
80 G_DEFINE_TYPE (GimpCellRendererToggle, gimp_cell_renderer_toggle,
81                GTK_TYPE_CELL_RENDERER_TOGGLE)
82
83 #define parent_class gimp_cell_renderer_toggle_parent_class
84
85 static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
86
87
88 static void
89 gimp_cell_renderer_toggle_class_init (GimpCellRendererToggleClass *klass)
90 {
91   GObjectClass         *object_class = G_OBJECT_CLASS (klass);
92   GtkCellRendererClass *cell_class   = GTK_CELL_RENDERER_CLASS (klass);
93
94   toggle_cell_signals[CLICKED] =
95     g_signal_new ("clicked",
96                   G_OBJECT_CLASS_TYPE (object_class),
97                   G_SIGNAL_RUN_LAST,
98                   G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked),
99                   NULL, NULL,
100                   _gimp_widgets_marshal_VOID__STRING_FLAGS,
101                   G_TYPE_NONE, 2,
102                   G_TYPE_STRING,
103                   GDK_TYPE_MODIFIER_TYPE);
104
105   object_class->finalize     = gimp_cell_renderer_toggle_finalize;
106   object_class->get_property = gimp_cell_renderer_toggle_get_property;
107   object_class->set_property = gimp_cell_renderer_toggle_set_property;
108
109   cell_class->get_size       = gimp_cell_renderer_toggle_get_size;
110   cell_class->render         = gimp_cell_renderer_toggle_render;
111   cell_class->activate       = gimp_cell_renderer_toggle_activate;
112
113   g_object_class_install_property (object_class,
114                                    PROP_STOCK_ID,
115                                    g_param_spec_string ("stock-id",
116                                                         NULL, NULL,
117                                                         NULL,
118                                                         G_PARAM_READWRITE |
119                                                         G_PARAM_CONSTRUCT));
120   g_object_class_install_property (object_class,
121                                    PROP_STOCK_SIZE,
122                                    g_param_spec_int ("stock-size",
123                                                      NULL, NULL,
124                                                      0, G_MAXINT,
125                                                      DEFAULT_ICON_SIZE,
126                                                      G_PARAM_READWRITE |
127                                                      G_PARAM_CONSTRUCT));
128 }
129
130 static void
131 gimp_cell_renderer_toggle_init (GimpCellRendererToggle *toggle)
132 {
133 }
134
135 static void
136 gimp_cell_renderer_toggle_finalize (GObject *object)
137 {
138   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
139
140   if (toggle->stock_id)
141     {
142       g_free (toggle->stock_id);
143       toggle->stock_id = NULL;
144     }
145
146   if (toggle->pixbuf)
147     {
148       g_object_unref (toggle->pixbuf);
149       toggle->pixbuf = NULL;
150     }
151
152   G_OBJECT_CLASS (parent_class)->finalize (object);
153 }
154
155 static void
156 gimp_cell_renderer_toggle_get_property (GObject    *object,
157                                         guint       param_id,
158                                         GValue     *value,
159                                         GParamSpec *pspec)
160 {
161   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
162
163   switch (param_id)
164     {
165     case PROP_STOCK_ID:
166       g_value_set_string (value, toggle->stock_id);
167       break;
168     case PROP_STOCK_SIZE:
169       g_value_set_int (value, toggle->stock_size);
170       break;
171
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
174       break;
175     }
176 }
177
178 static void
179 gimp_cell_renderer_toggle_set_property (GObject      *object,
180                                         guint         param_id,
181                                         const GValue *value,
182                                         GParamSpec   *pspec)
183 {
184   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (object);
185
186   switch (param_id)
187     {
188     case PROP_STOCK_ID:
189       if (toggle->stock_id)
190         g_free (toggle->stock_id);
191       toggle->stock_id = g_value_dup_string (value);
192       break;
193     case PROP_STOCK_SIZE:
194       toggle->stock_size = g_value_get_int (value);
195       break;
196
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
199       break;
200     }
201
202   if (toggle->pixbuf)
203     {
204       g_object_unref (toggle->pixbuf);
205       toggle->pixbuf = NULL;
206     }
207 }
208
209 static void
210 gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
211                                     GtkWidget       *widget,
212                                     GdkRectangle    *cell_area,
213                                     gint            *x_offset,
214                                     gint            *y_offset,
215                                     gint            *width,
216                                     gint            *height)
217 {
218   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
219   GtkStyle               *style  = gtk_widget_get_style (widget);
220   gint                    calc_width;
221   gint                    calc_height;
222   gint                    pixbuf_width;
223   gint                    pixbuf_height;
224
225   if (! toggle->stock_id)
226     {
227       GTK_CELL_RENDERER_CLASS (parent_class)->get_size (cell,
228                                                         widget,
229                                                         cell_area,
230                                                         x_offset, y_offset,
231                                                         width, height);
232       return;
233     }
234
235   if (! toggle->pixbuf)
236     gimp_cell_renderer_toggle_create_pixbuf (toggle, widget);
237
238   pixbuf_width  = gdk_pixbuf_get_width  (toggle->pixbuf);
239   pixbuf_height = gdk_pixbuf_get_height (toggle->pixbuf);
240
241   calc_width  = (pixbuf_width +
242                  (gint) cell->xpad * 2 + style->xthickness * 2);
243   calc_height = (pixbuf_height +
244                  (gint) cell->ypad * 2 + style->ythickness * 2);
245
246   if (width)
247     *width  = calc_width;
248
249   if (height)
250     *height = calc_height;
251
252   if (cell_area)
253     {
254       if (x_offset)
255         {
256           *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
257                         (1.0 - cell->xalign) : cell->xalign) *
258                        (cell_area->width - calc_width));
259           *x_offset = MAX (*x_offset, 0);
260         }
261
262       if (y_offset)
263         {
264           *y_offset = cell->yalign * (cell_area->height - calc_height);
265           *y_offset = MAX (*y_offset, 0);
266         }
267     }
268 }
269
270 static void
271 gimp_cell_renderer_toggle_render (GtkCellRenderer      *cell,
272                                   GdkWindow            *window,
273                                   GtkWidget            *widget,
274                                   GdkRectangle         *background_area,
275                                   GdkRectangle         *cell_area,
276                                   GdkRectangle         *expose_area,
277                                   GtkCellRendererState  flags)
278 {
279   GimpCellRendererToggle *toggle = GIMP_CELL_RENDERER_TOGGLE (cell);
280   GtkStyle               *style  = gtk_widget_get_style (widget);
281   GdkRectangle            toggle_rect;
282   GdkRectangle            draw_rect;
283   GtkStateType            state;
284   gboolean                active;
285
286   if (! toggle->stock_id)
287     {
288       GTK_CELL_RENDERER_CLASS (parent_class)->render (cell, window, widget,
289                                                       background_area,
290                                                       cell_area, expose_area,
291                                                       flags);
292       return;
293     }
294
295   gimp_cell_renderer_toggle_get_size (cell, widget, cell_area,
296                                       &toggle_rect.x,
297                                       &toggle_rect.y,
298                                       &toggle_rect.width,
299                                       &toggle_rect.height);
300
301   toggle_rect.x      += cell_area->x + cell->xpad;
302   toggle_rect.y      += cell_area->y + cell->ypad;
303   toggle_rect.width  -= cell->xpad * 2;
304   toggle_rect.height -= cell->ypad * 2;
305
306   if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
307     return;
308
309   active =
310     gtk_cell_renderer_toggle_get_active (GTK_CELL_RENDERER_TOGGLE (cell));
311
312   if (!cell->sensitive)
313     {
314       state = GTK_STATE_INSENSITIVE;
315     }
316   else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
317     {
318       if (GTK_WIDGET_HAS_FOCUS (widget))
319         state = GTK_STATE_SELECTED;
320       else
321         state = GTK_STATE_ACTIVE;
322     }
323   else
324     {
325       if (GTK_CELL_RENDERER_TOGGLE (cell)->activatable)
326         state = GTK_STATE_NORMAL;
327       else
328         state = GTK_STATE_INSENSITIVE;
329     }
330
331   if (gdk_rectangle_intersect (expose_area, cell_area, &draw_rect) &&
332       (flags & GTK_CELL_RENDERER_PRELIT))
333     gtk_paint_shadow (style,
334                       window,
335                       state,
336                       active ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
337                       &draw_rect,
338                       widget, NULL,
339                       toggle_rect.x,     toggle_rect.y,
340                       toggle_rect.width, toggle_rect.height);
341
342   if (active)
343     {
344       GdkPixbuf *insensitive = NULL;
345       GdkPixbuf *pixbuf = toggle->pixbuf;
346       
347       toggle_rect.x      += style->xthickness;
348       toggle_rect.y      += style->ythickness;
349       toggle_rect.width  -= style->xthickness * 2;
350       toggle_rect.height -= style->ythickness * 2;
351
352       if (state == GTK_STATE_INSENSITIVE)
353         {
354           GtkIconSource *source;
355
356           source = gtk_icon_source_new ();
357           gtk_icon_source_set_pixbuf (source, pixbuf);
358           /* The size here is arbitrary; since size isn't
359            * wildcarded in the source, it isn't supposed to be
360            * scaled by the engine function
361            */
362           gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
363           gtk_icon_source_set_size_wildcarded (source, FALSE);
364
365           insensitive = gtk_style_render_icon (widget->style,
366                                                source,
367                                                gtk_widget_get_direction (widget),
368                                                GTK_STATE_INSENSITIVE,
369                                                /* arbitrary */
370                                                (GtkIconSize)-1,
371                                                widget,
372                                                "gimpcellrenderertoggle");
373
374           gtk_icon_source_free (source);
375
376           pixbuf = insensitive;
377         }
378
379       if (gdk_rectangle_intersect (&draw_rect, &toggle_rect, &draw_rect))
380         {
381           cairo_t *cr;
382           
383           cr = gdk_cairo_create (window);
384
385           gdk_cairo_set_source_pixbuf (cr, pixbuf, toggle_rect.x, toggle_rect.y);
386           gdk_cairo_rectangle (cr, &draw_rect);
387           cairo_fill (cr);
388           
389           cairo_destroy (cr);
390         }
391               
392       if (insensitive)
393         g_object_unref (insensitive);
394     }
395 }
396
397 static gboolean
398 gimp_cell_renderer_toggle_activate (GtkCellRenderer      *cell,
399                                     GdkEvent             *event,
400                                     GtkWidget            *widget,
401                                     const gchar          *path,
402                                     GdkRectangle         *background_area,
403                                     GdkRectangle         *cell_area,
404                                     GtkCellRendererState  flags)
405 {
406   GtkCellRendererToggle *toggle = GTK_CELL_RENDERER_TOGGLE (cell);
407
408   if (toggle->activatable)
409     {
410       GdkModifierType state = 0;
411
412       GTK_CELL_RENDERER_CLASS (parent_class)->activate (cell, event, widget,
413                                                         path, background_area,
414                                                         cell_area, flags);
415
416       if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
417         state = ((GdkEventButton *) event)->state;
418
419       gimp_cell_renderer_toggle_clicked (GIMP_CELL_RENDERER_TOGGLE (cell),
420                                          path, state);
421
422       return TRUE;
423     }
424
425   return FALSE;
426 }
427
428 static void
429 gimp_cell_renderer_toggle_create_pixbuf (GimpCellRendererToggle *toggle,
430                                          GtkWidget              *widget)
431 {
432   if (toggle->pixbuf)
433     g_object_unref (toggle->pixbuf);
434
435   toggle->pixbuf = gtk_widget_render_icon (widget,
436                                            toggle->stock_id,
437                                            toggle->stock_size, NULL);
438 }
439
440
441 /**
442  * gimp_cell_renderer_toggle_new:
443  * @stock_id: the stock_id of the icon to use for the active state
444  *
445  * Creates a custom version of the #GtkCellRendererToggle. Instead of
446  * showing the standard toggle button, it shows a stock icon if the
447  * cell is active and no icon otherwise. This cell renderer is for
448  * example used in the Layers treeview to indicate and control the
449  * layer's visibility by showing %GIMP_STOCK_VISIBLE.
450  *
451  * Return value: a new #GimpCellRendererToggle
452  *
453  * Since: GIMP 2.2
454  **/
455 GtkCellRenderer *
456 gimp_cell_renderer_toggle_new (const gchar *stock_id)
457 {
458   return g_object_new (GIMP_TYPE_CELL_RENDERER_TOGGLE,
459                        "stock_id", stock_id,
460                        NULL);
461 }
462
463 /**
464  * gimp_cell_renderer_toggle_clicked:
465  * @cell: a #GimpCellRendererToggle
466  * @path:
467  * @state:
468  *
469  * Emits the "clicked" signal from a #GimpCellRendererToggle.
470  *
471  * Since: GIMP 2.2
472  **/
473 void
474 gimp_cell_renderer_toggle_clicked (GimpCellRendererToggle *cell,
475                                    const gchar            *path,
476                                    GdkModifierType         state)
477 {
478   g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell));
479   g_return_if_fail (path != NULL);
480
481   g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, path, state);
482 }