add .gitignore
[xgalaxy.git] / gtkcellrendererbutton.c
1 /* gtkcellrendererbutton.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 <config.h>
21 #include <stdlib.h>
22 #include "gtkcellrendererbutton.h"
23 //#include "gtkintl.h"
24 //#include "gtkmarshalers.h"
25 //#include "gtktreeprivate.h"
26
27 static void gtk_cell_renderer_button_get_property  (GObject                    *object,
28                                                     guint                       param_id,
29                                                     GValue                     *value,
30                                                     GParamSpec                 *pspec);
31 static void gtk_cell_renderer_button_set_property  (GObject                    *object,
32                                                     guint                       param_id,
33                                                     const GValue               *value,
34                                                     GParamSpec                 *pspec);
35 static void gtk_cell_renderer_button_init       (GtkCellRendererButton      *celltext);
36 static void gtk_cell_renderer_button_class_init (GtkCellRendererButtonClass *class);
37 static void gtk_cell_renderer_button_get_size   (GtkCellRenderer            *cell,
38                                                  GtkWidget                  *widget,
39                                                  GdkRectangle               *cell_area,
40                                                  gint                       *x_offset,
41                                                  gint                       *y_offset,
42                                                  gint                       *width,
43                                                  gint                       *height);
44 static void gtk_cell_renderer_button_render     (GtkCellRenderer            *cell,
45                                                  GdkWindow                  *window,
46                                                  GtkWidget                  *widget,
47                                                  GdkRectangle               *background_area,
48                                                  GdkRectangle               *cell_area,
49                                                  GdkRectangle               *expose_area,
50                                                  GtkCellRendererState        flags);
51 static gboolean gtk_cell_renderer_button_activate  (GtkCellRenderer            *cell,
52                                                     GdkEvent                   *event,
53                                                     GtkWidget                  *widget,
54                                                     const gchar                *path,
55                                                     GdkRectangle               *background_area,
56                                                     GdkRectangle               *cell_area,
57                                                     GtkCellRendererState        flags);
58
59
60 enum {
61   TOGGLED,
62   LAST_SIGNAL
63 };
64
65 enum {
66   PROP_ZERO,
67   PROP_ACTIVATABLE,
68   PROP_ACTIVE,
69 /*  PROP_RADIO, */
70   PROP_INCONSISTENT
71 };
72
73 #define BUTTON_WIDTH 14
74
75 static guint button_cell_signals[LAST_SIGNAL] = { 0 };
76
77 #define GTK_CELL_RENDERER_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_RENDERER_BUTTON, GtkCellRendererButtonPrivate))
78
79 typedef struct _GtkCellRendererButtonPrivate GtkCellRendererButtonPrivate;
80 struct _GtkCellRendererButtonPrivate
81 {
82   guint inconsistent : 1;
83 };
84
85
86 GType
87 gtk_cell_renderer_button_get_type (void)
88 {
89   static GType cell_button_type = 0;
90
91   if (!cell_button_type)
92     {
93       static const GTypeInfo cell_button_info =
94       {
95         sizeof (GtkCellRendererButtonClass),
96         NULL,           /* base_init */
97         NULL,           /* base_finalize */
98         (GClassInitFunc) gtk_cell_renderer_button_class_init,
99         NULL,           /* class_finalize */
100         NULL,           /* class_data */
101         sizeof (GtkCellRendererButton),
102         0,              /* n_preallocs */
103         (GInstanceInitFunc) gtk_cell_renderer_button_init,
104       };
105
106       cell_button_type =
107         g_type_register_static (GTK_TYPE_CELL_RENDERER, "GtkCellRendererButton",
108                                 &cell_button_info, 0);
109     }
110
111   return cell_button_type;
112 }
113
114 static void
115 gtk_cell_renderer_button_init (GtkCellRendererButton *cellbutton)
116 {
117   cellbutton->activatable = TRUE;
118   cellbutton->active = FALSE;
119   GTK_CELL_RENDERER (cellbutton)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
120   GTK_CELL_RENDERER (cellbutton)->xpad = 2;
121   GTK_CELL_RENDERER (cellbutton)->ypad = 2;
122 }
123
124 static void
125 gtk_cell_renderer_button_class_init (GtkCellRendererButtonClass *class)
126 {
127   GObjectClass *object_class = G_OBJECT_CLASS (class);
128   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
129
130   object_class->get_property = gtk_cell_renderer_button_get_property;
131   object_class->set_property = gtk_cell_renderer_button_set_property;
132
133   cell_class->get_size = gtk_cell_renderer_button_get_size;
134   cell_class->render = gtk_cell_renderer_button_render;
135   cell_class->activate = gtk_cell_renderer_button_activate;
136   
137   g_object_class_install_property (object_class,
138                                    PROP_ACTIVE,
139                                    g_param_spec_boolean ("active",
140                                                          "Button state",
141                                                          "The button state of the button",
142                                                          FALSE,
143                                                          G_PARAM_READABLE |
144                                                          G_PARAM_WRITABLE));
145
146   g_object_class_install_property (object_class,
147                                    PROP_INCONSISTENT,
148                                    g_param_spec_boolean ("inconsistent",
149                                                          "Inconsistent state",
150                                                          "The inconsistent state of the button",
151                                                          FALSE,
152                                                          G_PARAM_READABLE |
153                                                          G_PARAM_WRITABLE));
154   
155   g_object_class_install_property (object_class,
156                                    PROP_ACTIVATABLE,
157                                    g_param_spec_boolean ("activatable",
158                                                          "Activatable",
159                                                          "The button button can be activated",
160                                                          TRUE,
161                                                          G_PARAM_READABLE |
162                                                          G_PARAM_WRITABLE));
163
164   button_cell_signals[TOGGLED] =
165     g_signal_new ("toggled",
166                   G_OBJECT_CLASS_TYPE (object_class),
167                   G_SIGNAL_RUN_LAST,
168                   G_STRUCT_OFFSET (GtkCellRendererButtonClass, toggled),
169                   NULL, NULL,
170                   /*_gtk_marshal_VOID__STRING ,*/
171                   g_cclosure_marshal_VOID__STRING,
172                   G_TYPE_NONE, 1,
173                   G_TYPE_STRING);
174
175   g_type_class_add_private (object_class, sizeof (GtkCellRendererButtonPrivate));
176 }
177
178 static void
179 gtk_cell_renderer_button_get_property (GObject     *object,
180                                        guint        param_id,
181                                        GValue      *value,
182                                        GParamSpec  *pspec)
183 {
184   GtkCellRendererButton *cellbutton = GTK_CELL_RENDERER_BUTTON (object);
185   GtkCellRendererButtonPrivate *priv;
186
187   priv = GTK_CELL_RENDERER_BUTTON_GET_PRIVATE (object);
188   
189   switch (param_id)
190     {
191     case PROP_ACTIVE:
192       g_value_set_boolean (value, cellbutton->active);
193       break;
194     case PROP_INCONSISTENT:
195       g_value_set_boolean (value, priv->inconsistent);
196       break;
197     case PROP_ACTIVATABLE:
198       g_value_set_boolean (value, cellbutton->activatable);
199       break;
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
202       break;
203     }
204 }
205
206
207 static void
208 gtk_cell_renderer_button_set_property (GObject      *object,
209                                        guint         param_id,
210                                        const GValue *value,
211                                        GParamSpec   *pspec)
212 {
213   GtkCellRendererButton *cellbutton = GTK_CELL_RENDERER_BUTTON (object);
214   GtkCellRendererButtonPrivate *priv;
215
216   priv = GTK_CELL_RENDERER_BUTTON_GET_PRIVATE (object);
217   
218   switch (param_id)
219     {
220     case PROP_ACTIVE:
221       cellbutton->active = g_value_get_boolean (value);
222       g_object_notify (G_OBJECT(object), "active");
223       break;
224     case PROP_INCONSISTENT:
225       priv->inconsistent = g_value_get_boolean (value);
226       g_object_notify (G_OBJECT (object), "inconsistent");
227       break;
228     case PROP_ACTIVATABLE:
229       cellbutton->activatable = g_value_get_boolean (value);
230       g_object_notify (G_OBJECT(object), "activatable");
231       break;
232     default:
233       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
234       break;
235     }
236 }
237
238 /**
239  * gtk_cell_renderer_button_new:
240  * 
241  * Creates a new #GtkCellRendererButton. Adjust rendering
242  * parameters using object properties. Object properties can be set
243  * globally (with g_object_set()). Also, with #GtkTreeViewColumn, you
244  * can bind a property to a value in a #GtkTreeModel. For example, you
245  * can bind the "active" property on the cell renderer to a boolean value
246  * in the model, thus causing the check button to reflect the state of
247  * the model.
248  * 
249  * Return value: the new cell renderer
250  **/
251 GtkCellRenderer *
252 gtk_cell_renderer_button_new (void)
253 {
254   return g_object_new (GTK_TYPE_CELL_RENDERER_BUTTON, NULL);
255 }
256
257 static void
258 gtk_cell_renderer_button_get_size (GtkCellRenderer *cell,
259                                    GtkWidget       *widget,
260                                    GdkRectangle    *cell_area,
261                                    gint            *x_offset,
262                                    gint            *y_offset,
263                                    gint            *width,
264                                    gint            *height)
265 {
266   gint calc_width;
267   gint calc_height;
268
269   calc_width = (gint) cell->xpad * 2 + BUTTON_WIDTH;
270   calc_height = (gint) cell->ypad * 2 + BUTTON_WIDTH;
271
272   if (width)
273     *width = calc_width;
274
275   if (height)
276     *height = calc_height;
277
278   if (cell_area)
279     {
280       if (x_offset)
281         {
282           *x_offset = ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
283                        (1.0 - cell->xalign) : cell->xalign) * (cell_area->width - calc_width);
284           *x_offset = MAX (*x_offset, 0);
285         }
286       if (y_offset)
287         {
288           *y_offset = cell->yalign * (cell_area->height - calc_height);
289           *y_offset = MAX (*y_offset, 0);
290         }
291     }
292 }
293
294 static void
295 gtk_cell_renderer_button_render (GtkCellRenderer      *cell,
296                                  GdkDrawable          *window,
297                                  GtkWidget            *widget,
298                                  GdkRectangle         *background_area,
299                                  GdkRectangle         *cell_area,
300                                  GdkRectangle         *expose_area,
301                                  GtkCellRendererState  flags)
302 {
303   GtkCellRendererButton *cellbutton = (GtkCellRendererButton *) cell;
304   GtkCellRendererButtonPrivate *priv;
305   gint width, height;
306   gint x_offset, y_offset;
307   GtkShadowType shadow;
308   GtkStateType state = 0;
309
310   priv = GTK_CELL_RENDERER_BUTTON_GET_PRIVATE (cell);
311
312   gtk_cell_renderer_button_get_size (cell, widget, cell_area,
313                                      &x_offset, &y_offset,
314                                      &width, &height);
315   width -= cell->xpad*2;
316   height -= cell->ypad*2;
317
318   if (width <= 0 || height <= 0)
319     return;
320
321   if (priv->inconsistent)
322     shadow = GTK_SHADOW_ETCHED_IN;
323   else
324     shadow = cellbutton->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
325
326   if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
327     {
328       if (GTK_WIDGET_HAS_FOCUS (widget))
329         state = GTK_STATE_SELECTED;
330       else
331         state = GTK_STATE_ACTIVE;
332     }
333   else
334     {
335       if (cellbutton->activatable)
336         state = GTK_STATE_NORMAL;
337       else
338         state = GTK_STATE_INSENSITIVE;
339     }
340
341       gtk_paint_box (widget->style,
342                        window,
343                        state, shadow,
344                        expose_area, widget, "button",
345                        cell_area->x + x_offset + cell->xpad,
346                        cell_area->y + y_offset + cell->ypad,
347                        width - 1, height - 1);
348
349       gtk_paint_hline(
350                 widget->style,
351                 window,
352                 GTK_STATE_NORMAL,
353                 expose_area, widget, "label",
354                 cell_area->x + x_offset + cell->xpad  + 4 ,
355                 cell_area->x + x_offset + width  - 4,
356                 cell_area->y + y_offset + cell->ypad/2 + height/2
357         );
358 }
359
360 static gint
361 gtk_cell_renderer_button_activate (GtkCellRenderer      *cell,
362                                    GdkEvent             *event,
363                                    GtkWidget            *widget,
364                                    const gchar          *path,
365                                    GdkRectangle         *background_area,
366                                    GdkRectangle         *cell_area,
367                                    GtkCellRendererState  flags)
368 {
369   GtkCellRendererButton *cellbutton;
370   
371   cellbutton = GTK_CELL_RENDERER_BUTTON (cell);
372   if (cellbutton->activatable)
373     {
374       g_signal_emit (cell, button_cell_signals[TOGGLED], 0, path);
375       return TRUE;
376     }
377
378   return FALSE;
379 }
380
381 /**
382  * gtk_cell_renderer_button_get_active:
383  * @button: a #GtkCellRendererButton
384  *
385  * Returns whether the cell renderer is active. See
386  * gtk_cell_renderer_button_set_active().
387  *
388  * Return value: %TRUE if the cell renderer is active.
389  **/
390 gboolean
391 gtk_cell_renderer_button_get_active (GtkCellRendererButton *button)
392 {
393   g_return_val_if_fail (GTK_IS_CELL_RENDERER_BUTTON (button), FALSE);
394
395   return button->active;
396 }
397
398 /**
399  * gtk_cell_renderer_button_set_active:
400  * @button: a #GtkCellRendererButton.
401  * @setting: the value to set.
402  *
403  * Activates or deactivates a cell renderer.
404  **/
405 void
406 gtk_cell_renderer_button_set_active (GtkCellRendererButton *button,
407                                      gboolean               setting)
408 {
409   g_return_if_fail (GTK_IS_CELL_RENDERER_BUTTON (button));
410
411   g_object_set (button, "active", setting ? TRUE : FALSE, NULL);
412 }