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