]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrenderertoggle.c
330a2e54e71030501b4f8abe69215998ea3bb569
[~andy/gtk] / gtk / gtkcellrenderertoggle.c
1 /* gtkcellrenderertoggle.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <stdlib.h>
21 #include <gtk/gtkcellrenderertoggle.h>
22 #include "gtkintl.h"
23 #include "gtkmarshalers.h"
24 #include "gtktreeprivate.h"
25
26 static void gtk_cell_renderer_toggle_get_property  (GObject                    *object,
27                                                     guint                       param_id,
28                                                     GValue                     *value,
29                                                     GParamSpec                 *pspec);
30 static void gtk_cell_renderer_toggle_set_property  (GObject                    *object,
31                                                     guint                       param_id,
32                                                     const GValue               *value,
33                                                     GParamSpec                 *pspec);
34 static void gtk_cell_renderer_toggle_init       (GtkCellRendererToggle      *celltext);
35 static void gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class);
36 static void gtk_cell_renderer_toggle_get_size   (GtkCellRenderer            *cell,
37                                                  GtkWidget                  *widget,
38                                                  GdkRectangle               *cell_area,
39                                                  gint                       *x_offset,
40                                                  gint                       *y_offset,
41                                                  gint                       *width,
42                                                  gint                       *height);
43 static void gtk_cell_renderer_toggle_render     (GtkCellRenderer            *cell,
44                                                  GdkWindow                  *window,
45                                                  GtkWidget                  *widget,
46                                                  GdkRectangle               *background_area,
47                                                  GdkRectangle               *cell_area,
48                                                  GdkRectangle               *expose_area,
49                                                  GtkCellRendererState        flags);
50 static gboolean gtk_cell_renderer_toggle_activate  (GtkCellRenderer            *cell,
51                                                     GdkEvent                   *event,
52                                                     GtkWidget                  *widget,
53                                                     const gchar                *path,
54                                                     GdkRectangle               *background_area,
55                                                     GdkRectangle               *cell_area,
56                                                     GtkCellRendererState        flags);
57
58
59 enum {
60   TOGGLED,
61   LAST_SIGNAL
62 };
63
64 enum {
65   PROP_ZERO,
66   PROP_ACTIVATABLE,
67   PROP_ACTIVE,
68   PROP_RADIO,
69   PROP_INCONSISTENT
70 };
71
72 #define TOGGLE_WIDTH 12
73
74 static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
75
76
77 GType
78 gtk_cell_renderer_toggle_get_type (void)
79 {
80   static GType cell_toggle_type = 0;
81
82   if (!cell_toggle_type)
83     {
84       static const GTypeInfo cell_toggle_info =
85       {
86         sizeof (GtkCellRendererToggleClass),
87         NULL,           /* base_init */
88         NULL,           /* base_finalize */
89         (GClassInitFunc) gtk_cell_renderer_toggle_class_init,
90         NULL,           /* class_finalize */
91         NULL,           /* class_data */
92         sizeof (GtkCellRendererToggle),
93         0,              /* n_preallocs */
94         (GInstanceInitFunc) gtk_cell_renderer_toggle_init,
95       };
96
97       cell_toggle_type =
98         g_type_register_static (GTK_TYPE_CELL_RENDERER, "GtkCellRendererToggle",
99                                 &cell_toggle_info, 0);
100     }
101
102   return cell_toggle_type;
103 }
104
105 static void
106 gtk_cell_renderer_toggle_init (GtkCellRendererToggle *celltoggle)
107 {
108   celltoggle->activatable = TRUE;
109   celltoggle->active = FALSE;
110   celltoggle->radio = FALSE;
111   GTK_CELL_RENDERER (celltoggle)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
112   GTK_CELL_RENDERER (celltoggle)->xpad = 2;
113   GTK_CELL_RENDERER (celltoggle)->ypad = 2;
114 }
115
116 static void
117 gtk_cell_renderer_toggle_class_init (GtkCellRendererToggleClass *class)
118 {
119   GObjectClass *object_class = G_OBJECT_CLASS (class);
120   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
121
122   object_class->get_property = gtk_cell_renderer_toggle_get_property;
123   object_class->set_property = gtk_cell_renderer_toggle_set_property;
124
125   cell_class->get_size = gtk_cell_renderer_toggle_get_size;
126   cell_class->render = gtk_cell_renderer_toggle_render;
127   cell_class->activate = gtk_cell_renderer_toggle_activate;
128   
129   g_object_class_install_property (object_class,
130                                    PROP_ACTIVE,
131                                    g_param_spec_boolean ("active",
132                                                          _("Toggle state"),
133                                                          _("The toggle state of the button"),
134                                                          FALSE,
135                                                          G_PARAM_READABLE |
136                                                          G_PARAM_WRITABLE));
137
138   g_object_class_install_property (object_class,
139                                    PROP_INCONSISTENT,
140                                    g_param_spec_boolean ("inconsistent",
141                                                          _("Inconsistent state"),
142                                                          _("The inconsistent stae of the button"),
143                                                          FALSE,
144                                                          G_PARAM_READABLE |
145                                                          G_PARAM_WRITABLE));
146   
147   g_object_class_install_property (object_class,
148                                    PROP_ACTIVATABLE,
149                                    g_param_spec_boolean ("activatable",
150                                                          _("Activatable"),
151                                                          _("The toggle button can be activated"),
152                                                          TRUE,
153                                                          G_PARAM_READABLE |
154                                                          G_PARAM_WRITABLE));
155
156   g_object_class_install_property (object_class,
157                                    PROP_RADIO,
158                                    g_param_spec_boolean ("radio",
159                                                          _("Radio state"),
160                                                          _("Draw the toggle button as a radio button"),
161                                                          FALSE,
162                                                          G_PARAM_READABLE |
163                                                          G_PARAM_WRITABLE));
164
165
166   toggle_cell_signals[TOGGLED] =
167     g_signal_new ("toggled",
168                   G_OBJECT_CLASS_TYPE (object_class),
169                   G_SIGNAL_RUN_LAST,
170                   G_STRUCT_OFFSET (GtkCellRendererToggleClass, toggled),
171                   NULL, NULL,
172                   _gtk_marshal_VOID__STRING,
173                   G_TYPE_NONE, 1,
174                   G_TYPE_STRING);
175 }
176
177 static void
178 gtk_cell_renderer_toggle_get_property (GObject     *object,
179                                        guint        param_id,
180                                        GValue      *value,
181                                        GParamSpec  *pspec)
182 {
183   GtkCellRendererToggle *celltoggle = GTK_CELL_RENDERER_TOGGLE (object);
184   
185   switch (param_id)
186     {
187     case PROP_ACTIVE:
188       g_value_set_boolean (value, celltoggle->active);
189       break;
190     case PROP_INCONSISTENT:
191       {
192         /* Move out of here when more properties start to use the info
193          * thing. I put it here to not affect performance, this property
194          * is not going to be used much.
195          */
196         GtkCellRendererInfo *cellinfo;
197         cellinfo = g_object_get_data (object, GTK_CELL_RENDERER_INFO_KEY);
198
199         g_value_set_boolean (value, cellinfo->inconsistent);
200       }
201       break;
202     case PROP_ACTIVATABLE:
203       g_value_set_boolean (value, celltoggle->activatable);
204       break;
205     case PROP_RADIO:
206       g_value_set_boolean (value, celltoggle->radio);
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
210       break;
211     }
212 }
213
214
215 static void
216 gtk_cell_renderer_toggle_set_property (GObject      *object,
217                                        guint         param_id,
218                                        const GValue *value,
219                                        GParamSpec   *pspec)
220 {
221   GtkCellRendererToggle *celltoggle = GTK_CELL_RENDERER_TOGGLE (object);
222   
223   switch (param_id)
224     {
225     case PROP_ACTIVE:
226       celltoggle->active = g_value_get_boolean (value);
227       g_object_notify (G_OBJECT(object), "active");
228       break;
229     case PROP_INCONSISTENT:
230       {
231         /* read comment in _get_property */
232         GtkCellRendererInfo *cellinfo;
233         cellinfo = g_object_get_data (object, GTK_CELL_RENDERER_INFO_KEY);
234
235         cellinfo->inconsistent = g_value_get_boolean (value);
236         g_object_notify (G_OBJECT (object), "inconsistent");
237       }
238       break;
239     case PROP_ACTIVATABLE:
240       celltoggle->activatable = g_value_get_boolean (value);
241       g_object_notify (G_OBJECT(object), "activatable");
242       break;
243     case PROP_RADIO:
244       celltoggle->radio = g_value_get_boolean (value);
245       g_object_notify (G_OBJECT(object), "radio");
246       break;
247     default:
248       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
249       break;
250     }
251 }
252
253 /**
254  * gtk_cell_renderer_toggle_new:
255  * 
256  * Creates a new #GtkCellRendererToggle. Adjust rendering
257  * parameters using object properties. Object properties can be set
258  * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you
259  * can bind a property to a value in a #GtkTreeModel. For example, you
260  * can bind the "active" property on the cell renderer to a boolean value
261  * in the model, thus causing the check button to reflect the state of
262  * the model.
263  * 
264  * Return value: the new cell renderer
265  **/
266 GtkCellRenderer *
267 gtk_cell_renderer_toggle_new (void)
268 {
269   return g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE, NULL);
270 }
271
272 static void
273 gtk_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
274                                    GtkWidget       *widget,
275                                    GdkRectangle    *cell_area,
276                                    gint            *x_offset,
277                                    gint            *y_offset,
278                                    gint            *width,
279                                    gint            *height)
280 {
281   gint calc_width;
282   gint calc_height;
283
284   calc_width = (gint) cell->xpad * 2 + TOGGLE_WIDTH;
285   calc_height = (gint) cell->ypad * 2 + TOGGLE_WIDTH;
286
287   if (width)
288     *width = calc_width;
289
290   if (height)
291     *height = calc_height;
292
293   if (cell_area)
294     {
295       if (x_offset)
296         {
297           *x_offset = cell->xalign * (cell_area->width - calc_width);
298           *x_offset = MAX (*x_offset, 0);
299         }
300       if (y_offset)
301         {
302           *y_offset = cell->yalign * (cell_area->height - calc_height);
303           *y_offset = MAX (*y_offset, 0);
304         }
305     }
306 }
307
308 static void
309 gtk_cell_renderer_toggle_render (GtkCellRenderer      *cell,
310                                  GdkWindow            *window,
311                                  GtkWidget            *widget,
312                                  GdkRectangle         *background_area,
313                                  GdkRectangle         *cell_area,
314                                  GdkRectangle         *expose_area,
315                                  GtkCellRendererState  flags)
316 {
317   GtkCellRendererToggle *celltoggle = (GtkCellRendererToggle *) cell;
318   GtkCellRendererInfo *cellinfo;
319   gint width, height;
320   gint x_offset, y_offset;
321   GtkShadowType shadow;
322   GtkStateType state = 0;
323
324   gtk_cell_renderer_toggle_get_size (cell, widget, cell_area,
325                                      &x_offset, &y_offset,
326                                      &width, &height);
327   width -= cell->xpad*2;
328   height -= cell->ypad*2;
329
330   if (width <= 0 || height <= 0)
331     return;
332
333   cellinfo = g_object_get_data (G_OBJECT (cell), GTK_CELL_RENDERER_INFO_KEY);
334
335   if (cellinfo->inconsistent)
336     shadow = GTK_SHADOW_ETCHED_IN;
337   else
338     shadow = celltoggle->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
339
340   if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
341     {
342       if (GTK_WIDGET_HAS_FOCUS (widget))
343         state = GTK_STATE_SELECTED;
344       else
345         state = GTK_STATE_ACTIVE;
346     }
347   else
348     {
349       if (celltoggle->activatable)
350         state = GTK_STATE_NORMAL;
351       else
352         state = GTK_STATE_INSENSITIVE;
353     }
354
355   if (celltoggle->radio)
356     {
357       gtk_paint_option (widget->style,
358                         window,
359                         state, shadow,
360                         cell_area, widget, "cellradio",
361                         cell_area->x + x_offset + cell->xpad,
362                         cell_area->y + y_offset + cell->ypad,
363                         width - 1, height - 1);
364     }
365   else
366     {
367       gtk_paint_check (widget->style,
368                        window,
369                        state, shadow,
370                        cell_area, widget, "cellcheck",
371                        cell_area->x + x_offset + cell->xpad,
372                        cell_area->y + y_offset + cell->ypad,
373                        width - 1, height - 1);
374     }
375 }
376
377 static gint
378 gtk_cell_renderer_toggle_activate (GtkCellRenderer      *cell,
379                                    GdkEvent             *event,
380                                    GtkWidget            *widget,
381                                    const gchar          *path,
382                                    GdkRectangle         *background_area,
383                                    GdkRectangle         *cell_area,
384                                    GtkCellRendererState  flags)
385 {
386   GtkCellRendererToggle *celltoggle;
387   
388   celltoggle = GTK_CELL_RENDERER_TOGGLE (cell);
389   if (celltoggle->activatable)
390     {
391       g_signal_emit (cell, toggle_cell_signals[TOGGLED], 0, path);
392       return TRUE;
393     }
394
395   return FALSE;
396 }
397
398 /**
399  * gtk_cell_renderer_toggle_set_radio:
400  * @toggle: a #GtkCellRendererToggle
401  * @radio: %TRUE to make the toggle look like a radio button
402  * 
403  * If @radio is %TRUE, the cell renderer renders a radio toggle
404  * (i.e. a toggle in a group of mutually-exclusive toggles).
405  * If %FALSE, it renders a check toggle (a standalone boolean option).
406  * This can be set globally for the cell renderer, or changed just
407  * before rendering each cell in the model (for #GtkTreeView, you set
408  * up a per-row setting using #GtkTreeViewColumn to associate model
409  * columns with cell renderer properties).
410  **/
411 void
412 gtk_cell_renderer_toggle_set_radio (GtkCellRendererToggle *toggle,
413                                     gboolean               radio)
414 {
415   g_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle));
416
417   toggle->radio = radio;
418 }
419
420 /**
421  * gtk_cell_renderer_toggle_get_radio:
422  * @toggle: a #GtkCellRendererToggle
423  *
424  * Returns wether we're rendering radio toggles rather than checkboxes. 
425  * 
426  * Return value: %TRUE if we're rendering radio toggles rather than checkboxes
427  **/
428 gboolean
429 gtk_cell_renderer_toggle_get_radio (GtkCellRendererToggle *toggle)
430 {
431   g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle), FALSE);
432
433   return toggle->radio;
434 }
435
436 /**
437  * gtk_cell_renderer_toggle_get_active:
438  * @toggle: a #GtkCellRendererToggle
439  *
440  * Returns whether the cell renderer is active. See
441  * gtk_cell_renderer_toggle_set_active().
442  *
443  * Return value: %TRUE if the cell renderer is active.
444  **/
445 gboolean
446 gtk_cell_renderer_toggle_get_active (GtkCellRendererToggle *toggle)
447 {
448   g_return_val_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle), FALSE);
449
450   return toggle->active;
451 }
452
453 /**
454  * gtk_cell_renderer_toggle_set_active:
455  * @toggle: a #GtkCellRendererToggle.
456  * @setting: the value to set.
457  *
458  * Activates or deactivates a cell renderer.
459  **/
460 void
461 gtk_cell_renderer_toggle_set_active (GtkCellRendererToggle *toggle,
462                                      gboolean               setting)
463 {
464   g_return_if_fail (GTK_IS_CELL_RENDERER_TOGGLE (toggle));
465
466   g_object_set (G_OBJECT (toggle), "active", setting?TRUE:FALSE, NULL);
467 }