Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gimpcellrenderertoggle.c
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include <config.h>
24 
25 #include "gimpcellrenderertoggle.h"
26 
27 
28 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
29 
30 
31 enum
32 {
35 };
36 
37 enum
38 {
42 };
43 
44 
45 static void gimp_cell_renderer_toggle_finalize (GObject *object);
46 static void gimp_cell_renderer_toggle_get_property (GObject *object,
47  guint param_id,
48  GValue *value,
49  GParamSpec *pspec);
50 static void gimp_cell_renderer_toggle_set_property (GObject *object,
51  guint param_id,
52  const GValue *value,
53  GParamSpec *pspec);
54 static void gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
55  GtkWidget *widget,
56  const GdkRectangle *rectangle,
57  gint *x_offset,
58  gint *y_offset,
59  gint *width,
60  gint *height);
61 static void gimp_cell_renderer_toggle_render (GtkCellRenderer *cell,
62  cairo_t *cr,
63  GtkWidget *widget,
64  const GdkRectangle *background_area,
65  const GdkRectangle *cell_area,
66  GtkCellRendererState flags);
67 static gboolean gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
68  GdkEvent *event,
69  GtkWidget *widget,
70  const gchar *path,
71  const GdkRectangle *background_area,
72  const GdkRectangle *cell_area,
73  GtkCellRendererState flags);
75  GtkWidget *widget);
76 
77 
78 G_DEFINE_TYPE (GimpCellRendererToggle, gimp_cell_renderer_toggle,
79  GTK_TYPE_CELL_RENDERER_TOGGLE)
80 
81 #define parent_class gimp_cell_renderer_toggle_parent_class
82 
83 static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
84 
85 
86 static void
88 {
89  GObjectClass *object_class = G_OBJECT_CLASS (klass);
90  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
91 
92  toggle_cell_signals[CLICKED] =
93  g_signal_new ("clicked",
94  G_OBJECT_CLASS_TYPE (object_class),
95  G_SIGNAL_RUN_LAST,
96  G_STRUCT_OFFSET (GimpCellRendererToggleClass, clicked),
97  NULL, NULL,
98  g_cclosure_marshal_generic,
99  G_TYPE_NONE, 2,
100  G_TYPE_STRING,
101  GDK_TYPE_MODIFIER_TYPE);
102 
103  object_class->finalize = gimp_cell_renderer_toggle_finalize;
104  object_class->get_property = gimp_cell_renderer_toggle_get_property;
105  object_class->set_property = gimp_cell_renderer_toggle_set_property;
106 
107  cell_class->get_size = gimp_cell_renderer_toggle_get_size;
108  cell_class->render = gimp_cell_renderer_toggle_render;
109  cell_class->activate = gimp_cell_renderer_toggle_activate;
110 
111  g_object_class_install_property (object_class,
113  g_param_spec_string ("stock-id",
114  NULL, NULL,
115  NULL,
116  G_PARAM_READWRITE |
117  G_PARAM_CONSTRUCT));
118  g_object_class_install_property (object_class,
120  g_param_spec_int ("stock-size",
121  NULL, NULL,
122  0, G_MAXINT,
124  G_PARAM_READWRITE |
125  G_PARAM_CONSTRUCT));
126 }
127 
128 static void
130 {
131 }
132 
133 static void
135 {
137 
138  if (toggle->stock_id)
139  {
140  g_free (toggle->stock_id);
141  toggle->stock_id = NULL;
142  }
143 
144  if (toggle->pixbuf)
145  {
146  g_object_unref (toggle->pixbuf);
147  toggle->pixbuf = NULL;
148  }
149 
150  G_OBJECT_CLASS (parent_class)->finalize (object);
151 }
152 
153 static void
155  guint param_id,
156  GValue *value,
157  GParamSpec *pspec)
158 {
160 
161  switch (param_id)
162  {
163  case PROP_STOCK_ID:
164  g_value_set_string (value, toggle->stock_id);
165  break;
166  case PROP_STOCK_SIZE:
167  g_value_set_int (value, toggle->stock_size);
168  break;
169 
170  default:
171  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
172  break;
173  }
174 }
175 
176 static void
178  guint param_id,
179  const GValue *value,
180  GParamSpec *pspec)
181 {
183 
184  switch (param_id)
185  {
186  case PROP_STOCK_ID:
187  if (toggle->stock_id)
188  g_free (toggle->stock_id);
189  toggle->stock_id = g_value_dup_string (value);
190  break;
191  case PROP_STOCK_SIZE:
192  toggle->stock_size = g_value_get_int (value);
193  break;
194 
195  default:
196  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
197  break;
198  }
199 
200  if (toggle->pixbuf)
201  {
202  g_object_unref (toggle->pixbuf);
203  toggle->pixbuf = NULL;
204  }
205 }
206 
207 static void
208 gimp_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
209  GtkWidget *widget,
210  const GdkRectangle *cell_area,
211  gint *x_offset,
212  gint *y_offset,
213  gint *width,
214  gint *height)
215 {
217  GtkStyleContext *context = gtk_widget_get_style_context (widget);
218  GtkBorder border;
219  gint calc_width;
220  gint calc_height;
221  gint pixbuf_width;
222  gint pixbuf_height;
223  gfloat xalign;
224  gfloat yalign;
225  gint xpad;
226  gint ypad;
227 
228  if (! toggle->stock_id)
229  {
230  GTK_CELL_RENDERER_CLASS (parent_class)->get_size (cell,
231  widget,
232  cell_area,
233  x_offset, y_offset,
234  width, height);
235  return;
236  }
237 
238  gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
239  gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
240 
241  gtk_style_context_get_border (context, 0, &border);
242 
243  if (! toggle->pixbuf)
245 
246  pixbuf_width = gdk_pixbuf_get_width (toggle->pixbuf);
247  pixbuf_height = gdk_pixbuf_get_height (toggle->pixbuf);
248 
249  calc_width = (pixbuf_width + (gint) xpad * 2 + (border.left + border.right));
250  calc_height = (pixbuf_height + (gint) ypad * 2 + (border.top + border.bottom));
251 
252  if (width)
253  *width = calc_width;
254 
255  if (height)
256  *height = calc_height;
257 
258  if (cell_area)
259  {
260  if (x_offset)
261  {
262  *x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
263  (1.0 - xalign) : xalign) *
264  (cell_area->width - calc_width));
265  *x_offset = MAX (*x_offset, 0);
266  }
267 
268  if (y_offset)
269  {
270  *y_offset = yalign * (cell_area->height - calc_height);
271  *y_offset = MAX (*y_offset, 0);
272  }
273  }
274 }
275 
276 static void
277 gimp_cell_renderer_toggle_render (GtkCellRenderer *cell,
278  cairo_t *cr,
279  GtkWidget *widget,
280  const GdkRectangle *background_area,
281  const GdkRectangle *cell_area,
282  GtkCellRendererState flags)
283 {
285  GtkStyleContext *context = gtk_widget_get_style_context (widget);
286  GdkRectangle toggle_rect;
287  GdkRectangle draw_rect;
288  GdkRectangle clip_rect;
289  GtkStateFlags state;
290  gboolean active;
291  gint xpad;
292  gint ypad;
293 
294  if (! toggle->stock_id)
295  {
296  GTK_CELL_RENDERER_CLASS (parent_class)->render (cell,
297  cr,
298  widget,
299  background_area,
300  cell_area,
301  flags);
302  return;
303  }
304 
305  gtk_cell_renderer_get_size (cell, widget, cell_area,
306  &toggle_rect.x,
307  &toggle_rect.y,
308  &toggle_rect.width,
309  &toggle_rect.height);
310 
311  gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
312  toggle_rect.x += cell_area->x + xpad;
313  toggle_rect.y += cell_area->y + ypad;
314  toggle_rect.width -= xpad * 2;
315  toggle_rect.height -= ypad * 2;
316 
317  if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
318  return;
319 
320  active =
321  gtk_cell_renderer_toggle_get_active (GTK_CELL_RENDERER_TOGGLE (cell));
322 
323  if (!gtk_cell_renderer_get_sensitive (cell))
324  {
325  state = GTK_STATE_FLAG_INSENSITIVE;
326  }
327  else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
328  {
329  if (gtk_widget_has_focus (widget))
330  state = GTK_STATE_FLAG_SELECTED;
331  else
332  state = GTK_STATE_FLAG_ACTIVE;
333  }
334  else
335  {
336  if (gtk_cell_renderer_toggle_get_activatable (GTK_CELL_RENDERER_TOGGLE (cell)))
337  state = 0;
338  else
339  state = GTK_STATE_FLAG_INSENSITIVE;
340  }
341 
342  if ((flags & GTK_CELL_RENDERER_PRELIT) &&
343  gdk_cairo_get_clip_rectangle(cr, &clip_rect) &&
344  gdk_rectangle_intersect (&clip_rect, cell_area, &draw_rect))
345  {
346  cairo_save (cr);
347  gtk_style_context_save (context);
348  gdk_cairo_rectangle (cr, &draw_rect);
349  cairo_clip (cr);
350  gtk_render_frame (context, //gtk_widget_get_style_context (widget),
351  cr,
352  toggle_rect.x, toggle_rect.y,
353  toggle_rect.width, toggle_rect.height);
354  gtk_style_context_restore (context);
355  cairo_restore (cr);
356  }
357 
358  if (active)
359  {
360  GdkPixbuf *insensitive = NULL;
361  GdkPixbuf *pixbuf = toggle->pixbuf;
362  GtkBorder border = { 1, 1, 1, 1 };
363 
364 #if 0
365  /* FIXME: for some reason calling gtk_style_context_get_border
366  * makes the icon only visible on hover, so use border = 1
367  * for now as a workaround
368  */
369  gtk_style_context_get_border (context, state, &border);
370 #endif
371 
372  toggle_rect.x += border.left;
373  toggle_rect.y += border.top;
374  toggle_rect.width -= (border.left + border.right);
375  toggle_rect.height -= (border.top + border.bottom);
376 
377  if (state & GTK_STATE_FLAG_INSENSITIVE)
378  {
379  GtkIconSource *source;
380 
381  source = gtk_icon_source_new ();
382  gtk_icon_source_set_pixbuf (source, pixbuf);
383  /* The size here is arbitrary; since size isn't
384  * wildcarded in the source, it isn't supposed to be
385  * scaled by the engine function
386  */
387  gtk_icon_source_set_size (source, GTK_ICON_SIZE_SMALL_TOOLBAR);
388  gtk_icon_source_set_size_wildcarded (source, FALSE);
389 
390  gtk_style_context_save (context);
391  gtk_style_context_set_state (context, GTK_STATE_FLAG_INSENSITIVE);
392  insensitive = gtk_render_icon_pixbuf (context, source, (GtkIconSize)-1);
393  gtk_style_context_restore (context);
394 
395  gtk_icon_source_free (source);
396 
397  pixbuf = insensitive;
398  }
399 
400  if (gdk_rectangle_intersect (&draw_rect, &toggle_rect, &draw_rect))
401  {
402  gdk_cairo_set_source_pixbuf (cr, pixbuf, toggle_rect.x, toggle_rect.y);
403  gdk_cairo_rectangle (cr, &draw_rect);
404  cairo_fill (cr);
405  }
406 
407  if (insensitive)
408  g_object_unref (insensitive);
409  }
410 }
411 
412 static gboolean
413 gimp_cell_renderer_toggle_activate (GtkCellRenderer *cell,
414  GdkEvent *event,
415  GtkWidget *widget,
416  const gchar *path,
417  const GdkRectangle *background_area,
418  const GdkRectangle *cell_area,
419  GtkCellRendererState flags)
420 {
421  GtkCellRendererToggle *toggle = GTK_CELL_RENDERER_TOGGLE (cell);
422 
423  if (gtk_cell_renderer_toggle_get_activatable (toggle))
424  {
425  GdkModifierType state = 0;
426 
427  GTK_CELL_RENDERER_CLASS (parent_class)->activate (cell, event, widget,
428  path, background_area,
429  cell_area, flags);
430 
431  if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
432  state = ((GdkEventButton *) event)->state;
433 
435  path, state);
436 
437  return TRUE;
438  }
439 
440  return FALSE;
441 }
442 
443 static void
445  GtkWidget *widget)
446 {
447  if (toggle->pixbuf)
448  g_object_unref (toggle->pixbuf);
449 
450  toggle->pixbuf = gtk_widget_render_icon_pixbuf (widget,
451  toggle->stock_id,
452  toggle->stock_size);
453 }
454 
455 
470 GtkCellRenderer *
471 gimp_cell_renderer_toggle_new (const gchar *stock_id)
472 {
473  return g_object_new (GIMP_TYPE_CELL_RENDERER_TOGGLE,
474  "stock_id", stock_id,
475  NULL);
476 }
477 
488 void
490  const gchar *path,
491  GdkModifierType state)
492 {
493  g_return_if_fail (GIMP_IS_CELL_RENDERER_TOGGLE (cell));
494  g_return_if_fail (path != NULL);
495 
496  g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, path, state);
497 }