]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrenderer.c
is-expander and is-expanded are boolean properties, not ints. (#118359,
[~andy/gtk] / gtk / gtkcellrenderer.c
1 /* gtkcellrenderer.c
2  * Copyright (C) 2000  Red Hat, Inc. Jonathan Blandford
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 "gtkcellrenderer.h"
21 #include "gtkintl.h"
22 #include "gtktreeprivate.h"
23
24 static void gtk_cell_renderer_init       (GtkCellRenderer      *cell);
25 static void gtk_cell_renderer_class_init (GtkCellRendererClass *class);
26 static void gtk_cell_renderer_get_property  (GObject              *object,
27                                              guint                 param_id,
28                                              GValue               *value,
29                                              GParamSpec           *pspec);
30 static void gtk_cell_renderer_set_property  (GObject              *object,
31                                              guint                 param_id,
32                                              const GValue         *value,
33                                              GParamSpec           *pspec);
34 static void set_cell_bg_color               (GtkCellRenderer      *cell,
35                                              GdkColor             *color);
36
37
38 enum {
39   PROP_ZERO,
40   PROP_MODE,
41   PROP_VISIBLE,
42   PROP_XALIGN,
43   PROP_YALIGN,
44   PROP_XPAD,
45   PROP_YPAD,
46   PROP_WIDTH,
47   PROP_HEIGHT,
48   PROP_IS_EXPANDER,
49   PROP_IS_EXPANDED,
50   PROP_CELL_BACKGROUND,
51   PROP_CELL_BACKGROUND_GDK,
52   PROP_CELL_BACKGROUND_SET
53 };
54
55 GType
56 gtk_cell_renderer_get_type (void)
57 {
58   static GType cell_type = 0;
59
60   if (!cell_type)
61     {
62       static const GTypeInfo cell_info =
63       {
64         sizeof (GtkCellRendererClass),
65         NULL,           /* base_init */
66         NULL,           /* base_finalize */
67         (GClassInitFunc) gtk_cell_renderer_class_init,
68         NULL,           /* class_finalize */
69         NULL,           /* class_data */
70         sizeof (GtkCellRenderer),
71         0,              /* n_preallocs */
72         (GInstanceInitFunc) gtk_cell_renderer_init,
73         NULL,           /* value_table */
74       };
75
76       cell_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkCellRenderer", 
77                                           &cell_info, G_TYPE_FLAG_ABSTRACT);
78     }
79
80   return cell_type;
81 }
82
83 static void
84 gtk_cell_renderer_init (GtkCellRenderer *cell)
85 {
86   GtkCellRendererInfo *cellinfo;
87
88   cell->mode = GTK_CELL_RENDERER_MODE_INERT;
89   cell->visible = TRUE;
90   cell->width = -1;
91   cell->height = -1;
92   cell->xalign = 0.5;
93   cell->yalign = 0.5;
94   cell->xpad = 0;
95   cell->ypad = 0;
96
97   cellinfo = g_new0 (GtkCellRendererInfo, 1);
98   g_object_set_data_full (G_OBJECT (cell),
99                           GTK_CELL_RENDERER_INFO_KEY, cellinfo, g_free);
100 }
101
102 static void
103 gtk_cell_renderer_class_init (GtkCellRendererClass *class)
104 {
105   GObjectClass *object_class = G_OBJECT_CLASS (class);
106
107   object_class->get_property = gtk_cell_renderer_get_property;
108   object_class->set_property = gtk_cell_renderer_set_property;
109
110   class->render = NULL;
111   class->get_size = NULL;
112
113   g_object_class_install_property (object_class,
114                                    PROP_MODE,
115                                    g_param_spec_enum ("mode",
116                                                       _("mode"),
117                                                       _("Editable mode of the CellRenderer"),
118                                                       GTK_TYPE_CELL_RENDERER_MODE,
119                                                       GTK_CELL_RENDERER_MODE_INERT,
120                                                       G_PARAM_READABLE |
121                                                       G_PARAM_WRITABLE));
122
123   g_object_class_install_property (object_class,
124                                    PROP_VISIBLE,
125                                    g_param_spec_boolean ("visible",
126                                                          _("visible"),
127                                                          _("Display the cell"),
128                                                          TRUE,
129                                                          G_PARAM_READABLE |
130                                                          G_PARAM_WRITABLE));
131
132   g_object_class_install_property (object_class,
133                                    PROP_XALIGN,
134                                    g_param_spec_float ("xalign",
135                                                        _("xalign"),
136                                                        _("The x-align"),
137                                                        0.0,
138                                                        1.0,
139                                                        0.0,
140                                                        G_PARAM_READABLE |
141                                                        G_PARAM_WRITABLE));
142
143   g_object_class_install_property (object_class,
144                                    PROP_YALIGN,
145                                    g_param_spec_float ("yalign",
146                                                        _("yalign"),
147                                                        _("The y-align"),
148                                                        0.0,
149                                                        1.0,
150                                                        0.5,
151                                                        G_PARAM_READABLE |
152                                                        G_PARAM_WRITABLE));
153
154   g_object_class_install_property (object_class,
155                                    PROP_XPAD,
156                                    g_param_spec_uint ("xpad",
157                                                       _("xpad"),
158                                                       _("The xpad"),
159                                                       0,
160                                                       100,
161                                                       2,
162                                                       G_PARAM_READABLE |
163                                                       G_PARAM_WRITABLE));
164
165   g_object_class_install_property (object_class,
166                                    PROP_YPAD,
167                                    g_param_spec_uint ("ypad",
168                                                       _("ypad"),
169                                                       _("The ypad"),
170                                                       0,
171                                                       100,
172                                                       2,
173                                                       G_PARAM_READABLE |
174                                                       G_PARAM_WRITABLE));
175
176   g_object_class_install_property (object_class,
177                                    PROP_WIDTH,
178                                    g_param_spec_int ("width",
179                                                      _("width"),
180                                                      _("The fixed width"),
181                                                      -1,
182                                                      100,
183                                                      -1,
184                                                      G_PARAM_READABLE |
185                                                      G_PARAM_WRITABLE));
186
187   g_object_class_install_property (object_class,
188                                    PROP_HEIGHT,
189                                    g_param_spec_int ("height",
190                                                      _("height"),
191                                                      _("The fixed height"),
192                                                      -1,
193                                                      100,
194                                                      -1,
195                                                      G_PARAM_READABLE |
196                                                      G_PARAM_WRITABLE));
197
198   g_object_class_install_property (object_class,
199                                    PROP_IS_EXPANDER,
200                                    g_param_spec_boolean ("is_expander",
201                                                          _("Is Expander"),
202                                                          _("Row has children"),
203                                                          FALSE,
204                                                          G_PARAM_READABLE |
205                                                          G_PARAM_WRITABLE));
206
207
208   g_object_class_install_property (object_class,
209                                    PROP_IS_EXPANDED,
210                                    g_param_spec_boolean ("is_expanded",
211                                                          _("Is Expanded"),
212                                                          _("Row is an expander row, and is expanded"),
213                                                          FALSE,
214                                                          G_PARAM_READABLE |
215                                                          G_PARAM_WRITABLE));
216
217   g_object_class_install_property (object_class,
218                                    PROP_CELL_BACKGROUND,
219                                    g_param_spec_string ("cell_background",
220                                                         _("Cell background color name"),
221                                                         _("Cell background color as a string"),
222                                                         NULL,
223                                                         G_PARAM_WRITABLE));
224
225   g_object_class_install_property (object_class,
226                                    PROP_CELL_BACKGROUND_GDK,
227                                    g_param_spec_boxed ("cell_background_gdk",
228                                                        _("Cell background color"),
229                                                        _("Cell background color as a GdkColor"),
230                                                        GDK_TYPE_COLOR,
231                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
232
233
234 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
235
236   ADD_SET_PROP ("cell_background_set", PROP_CELL_BACKGROUND_SET,
237                 _("Cell background set"),
238                 _("Whether this tag affects the cell background color"));
239 }
240
241 static void
242 gtk_cell_renderer_get_property (GObject     *object,
243                                 guint        param_id,
244                                 GValue      *value,
245                                 GParamSpec  *pspec)
246 {
247   GtkCellRenderer *cell = GTK_CELL_RENDERER (object);
248   GtkCellRendererInfo *cellinfo;
249
250   cellinfo = g_object_get_data (object,
251                                 GTK_CELL_RENDERER_INFO_KEY);
252
253   switch (param_id)
254     {
255     case PROP_MODE:
256       g_value_set_enum (value, cell->mode);
257       break;
258     case PROP_VISIBLE:
259       g_value_set_boolean (value, cell->visible);
260       break;
261     case PROP_XALIGN:
262       g_value_set_float (value, cell->xalign);
263       break;
264     case PROP_YALIGN:
265       g_value_set_float (value, cell->yalign);
266       break;
267     case PROP_XPAD:
268       g_value_set_uint (value, cell->xpad);
269       break;
270     case PROP_YPAD:
271       g_value_set_uint (value, cell->ypad);
272       break;
273     case PROP_WIDTH:
274       g_value_set_int (value, cell->width);
275       break;
276     case PROP_HEIGHT:
277       g_value_set_int (value, cell->height);
278       break;
279     case PROP_IS_EXPANDER:
280       g_value_set_boolean (value, cell->is_expander);
281       break;
282     case PROP_IS_EXPANDED:
283       g_value_set_boolean (value, cell->is_expanded);
284       break;
285     case PROP_CELL_BACKGROUND_GDK:
286       {
287         GdkColor color;
288
289         color.red = cellinfo->cell_background.red;
290         color.green = cellinfo->cell_background.green;
291         color.blue = cellinfo->cell_background.blue;
292
293         g_value_set_boxed (value, &color);
294       }
295       break;
296     case PROP_CELL_BACKGROUND_SET:
297       g_value_set_boolean (value, cell->cell_background_set);
298       break;
299     case PROP_CELL_BACKGROUND:
300     default:
301       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
302       break;
303     }
304
305 }
306
307 static void
308 gtk_cell_renderer_set_property (GObject      *object,
309                                 guint         param_id,
310                                 const GValue *value,
311                                 GParamSpec   *pspec)
312 {
313   GtkCellRenderer *cell = GTK_CELL_RENDERER (object);
314
315   switch (param_id)
316     {
317     case PROP_MODE:
318       cell->mode = g_value_get_enum (value);
319       break;
320     case PROP_VISIBLE:
321       cell->visible = g_value_get_boolean (value);
322       break;
323     case PROP_XALIGN:
324       cell->xalign = g_value_get_float (value);
325       break;
326     case PROP_YALIGN:
327       cell->yalign = g_value_get_float (value);
328       break;
329     case PROP_XPAD:
330       cell->xpad = g_value_get_uint (value);
331       break;
332     case PROP_YPAD:
333       cell->ypad = g_value_get_uint (value);
334       break;
335     case PROP_WIDTH:
336       cell->width = g_value_get_int (value);
337       break;
338     case PROP_HEIGHT:
339       cell->height = g_value_get_int (value);
340       break;
341     case PROP_IS_EXPANDER:
342       cell->is_expander = g_value_get_boolean (value);
343       break;
344     case PROP_IS_EXPANDED:
345       cell->is_expanded = g_value_get_boolean (value);
346       break;
347     case PROP_CELL_BACKGROUND:
348       {
349         GdkColor color;
350
351         if (!g_value_get_string (value))
352           set_cell_bg_color (cell, NULL);
353         else if (gdk_color_parse (g_value_get_string (value), &color))
354           set_cell_bg_color (cell, &color);
355         else
356           g_warning ("Don't know color `%s'", g_value_get_string (value));
357
358         g_object_notify (object, "cell_background_gdk");
359       }
360       break;
361     case PROP_CELL_BACKGROUND_GDK:
362       set_cell_bg_color (cell, g_value_get_boxed (value));
363       break;
364     case PROP_CELL_BACKGROUND_SET:
365       cell->cell_background_set = g_value_get_boolean (value);
366       break;
367     default:
368       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
369       break;
370     }
371 }
372
373 static void
374 set_cell_bg_color (GtkCellRenderer *cell,
375                    GdkColor        *color)
376 {
377   GtkCellRendererInfo *cellinfo;
378
379   cellinfo = g_object_get_data (G_OBJECT (cell),
380                                 GTK_CELL_RENDERER_INFO_KEY);
381
382   if (color)
383     {
384       if (!cell->cell_background_set)
385         {
386           cell->cell_background_set = TRUE;
387           g_object_notify (G_OBJECT (cell), "cell_background_set");
388         }
389
390       cellinfo->cell_background.red = color->red;
391       cellinfo->cell_background.green = color->green;
392       cellinfo->cell_background.blue = color->blue;
393     }
394   else
395     {
396       if (cell->cell_background_set)
397         {
398           cell->cell_background_set = FALSE;
399           g_object_notify (G_OBJECT (cell), "cell_background_set");
400         }
401     }
402 }
403
404 /**
405  * gtk_cell_renderer_get_size:
406  * @cell: a #GtkCellRenderer
407  * @widget: the widget the renderer is rendering to
408  * @cell_area: The area a cell will be allocated, or %NULL
409  * @x_offset: location to return x offset of cell relative to @cell_area, or %NULL
410  * @y_offset: location to return y offset of cell relative to @cell_area, or %NULL
411  * @width: location to return width needed to render a cell, or %NULL
412  * @height: location to return height needed to render a cell, or %NULL
413  *
414  * Obtains the width and height needed to render the cell. Used by view widgets
415  * to determine the appropriate size for the cell_area passed to
416  * gtk_cell_renderer_render().  If @cell_area is not %NULL, fills in the x and y
417  * offsets (if set) of the cell relative to this location.  Please note that the
418  * values set in @width and @height, as well as those in @x_offset and @y_offset
419  * are inclusive of the xpad and ypad properties.
420  **/
421 void
422 gtk_cell_renderer_get_size (GtkCellRenderer *cell,
423                             GtkWidget       *widget,
424                             GdkRectangle    *cell_area,
425                             gint            *x_offset,
426                             gint            *y_offset,
427                             gint            *width,
428                             gint            *height)
429 {
430   gint *real_width = width;
431   gint *real_height = height;
432
433   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
434   g_return_if_fail (GTK_CELL_RENDERER_GET_CLASS (cell)->get_size != NULL);
435
436   if (width && cell->width != -1)
437     {
438       real_width = NULL;
439       *width = cell->width;
440     }
441   if (height && cell->height != -1)
442     {
443       real_height = NULL;
444       *height = cell->height;
445     }
446
447   GTK_CELL_RENDERER_GET_CLASS (cell)->get_size (cell,
448                                                 widget,
449                                                 cell_area,
450                                                 x_offset,
451                                                 y_offset,
452                                                 real_width,
453                                                 real_height);
454 }
455
456 /**
457  * gtk_cell_renderer_render:
458  * @cell: a #GtkCellRenderer
459  * @window: a #GdkDrawable to draw to
460  * @widget: the widget owning @window
461  * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
462  * @cell_area: area normally rendered by a cell renderer
463  * @expose_area: area that actually needs updating
464  * @flags: flags that affect rendering
465  *
466  * Invokes the virtual render function of the #GtkCellRenderer. The three
467  * passed-in rectangles are areas of @window. Most renderers will draw within
468  * @cell_area; the xalign, yalign, xpad, and ypad fields of the #GtkCellRenderer
469  * should be honored with respect to @cell_area. @background_area includes the
470  * blank space around the cell, and also the area containing the tree expander;
471  * so the @background_area rectangles for all cells tile to cover the entire
472  * @window.  @expose_area is a clip rectangle.
473  *
474  **/
475 void
476 gtk_cell_renderer_render (GtkCellRenderer     *cell,
477                           GdkWindow           *window,
478                           GtkWidget           *widget,
479                           GdkRectangle        *background_area,
480                           GdkRectangle        *cell_area,
481                           GdkRectangle        *expose_area,
482                           GtkCellRendererState flags)
483 {
484   gboolean selected = FALSE;
485   GtkCellRendererInfo *cellinfo;
486
487   cellinfo = g_object_get_data (G_OBJECT (cell),
488                                 GTK_CELL_RENDERER_INFO_KEY);
489
490   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
491   g_return_if_fail (GTK_CELL_RENDERER_GET_CLASS (cell)->render != NULL);
492
493   selected = (flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED;
494
495   if (cell->cell_background_set && !selected)
496     {
497       GdkColor color;
498       GdkGC *gc;
499
500       color.red = cellinfo->cell_background.red;
501       color.green = cellinfo->cell_background.green;
502       color.blue = cellinfo->cell_background.blue;
503
504       gc = gdk_gc_new (window);
505       gdk_gc_set_rgb_fg_color (gc, &color);
506       gdk_draw_rectangle (window, gc, TRUE,
507                           background_area->x, background_area->y,
508                           background_area->width, background_area->height);
509       g_object_unref (gc);
510     }
511
512   GTK_CELL_RENDERER_GET_CLASS (cell)->render (cell,
513                                               window,
514                                               widget,
515                                               background_area,
516                                               cell_area,
517                                               expose_area,
518                                               flags);
519 }
520
521 /**
522  * gtk_cell_renderer_activate:
523  * @cell: a #GtkCellRenderer
524  * @event: a #GdkEvent
525  * @widget: widget that received the event
526  * @path: widget-dependent string representation of the event location; e.g. for #GtkTreeView, a string representation of #GtkTreePath
527  * @background_area: background area as passed to @gtk_cell_renderer_render
528  * @cell_area: cell area as passed to @gtk_cell_renderer_render
529  * @flags: render flags
530  *
531  * Passes an activate event to the cell renderer for possible processing.  Some
532  * cell renderers may use events; for example, #GtkCellRendererToggle toggles
533  * when it gets a mouse click.
534  *
535  * Return value: %TRUE if the event was consumed/handled
536  **/
537 gboolean
538 gtk_cell_renderer_activate (GtkCellRenderer      *cell,
539                             GdkEvent             *event,
540                             GtkWidget            *widget,
541                             const gchar          *path,
542                             GdkRectangle         *background_area,
543                             GdkRectangle         *cell_area,
544                             GtkCellRendererState  flags)
545 {
546   g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
547
548   if (cell->mode != GTK_CELL_RENDERER_MODE_ACTIVATABLE)
549     return FALSE;
550
551   if (GTK_CELL_RENDERER_GET_CLASS (cell)->activate == NULL)
552     return FALSE;
553
554   return GTK_CELL_RENDERER_GET_CLASS (cell)->activate (cell,
555                                                        event,
556                                                        widget,
557                                                        path,
558                                                        background_area,
559                                                        cell_area,
560                                                        flags);
561 }
562
563 /**
564  * gtk_cell_renderer_start_editing:
565  * @cell: a #GtkCellRenderer
566  * @event: a #GdkEvent
567  * @widget: widget that received the event
568  * @path: widget-dependent string representation of the event location; e.g. for #GtkTreeView, a string representation of #GtkTreePath
569  * @background_area: background area as passed to @gtk_cell_renderer_render
570  * @cell_area: cell area as passed to @gtk_cell_renderer_render
571  * @flags: render flags
572  * 
573  * Passes an activate event to the cell renderer for possible processing.
574  * 
575  * Return value: A new #GtkCellEditable, or %NULL
576  **/
577 GtkCellEditable *
578 gtk_cell_renderer_start_editing (GtkCellRenderer      *cell,
579                                  GdkEvent             *event,
580                                  GtkWidget            *widget,
581                                  const gchar          *path,
582                                  GdkRectangle         *background_area,
583                                  GdkRectangle         *cell_area,
584                                  GtkCellRendererState  flags)
585
586 {
587   g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), NULL);
588
589   if (cell->mode != GTK_CELL_RENDERER_MODE_EDITABLE)
590     return NULL;
591
592   if (GTK_CELL_RENDERER_GET_CLASS (cell)->start_editing == NULL)
593     return NULL;
594
595   
596   return GTK_CELL_RENDERER_GET_CLASS (cell)->start_editing (cell,
597                                                             event,
598                                                             widget,
599                                                             path,
600                                                             background_area,
601                                                             cell_area,
602                                                             flags);
603 }
604
605 /**
606  * gtk_cell_renderer_set_fixed_size:
607  * @cell: A #GtkCellRenderer
608  * @width: the width of the cell renderer, or -1
609  * @height: the height of the cell renderer, or -1
610  * 
611  * Sets the renderer size to be explicit, independent of the properties set.
612  **/
613 void
614 gtk_cell_renderer_set_fixed_size (GtkCellRenderer *cell,
615                                   gint             width,
616                                   gint             height)
617 {
618   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
619   g_return_if_fail (width >= -1 && height >= -1);
620
621   if ((width != cell->width) || (height != cell->height))
622     {
623       g_object_freeze_notify (G_OBJECT (cell));
624
625       if (width != cell->width)
626         {
627           cell->width = width;
628           g_object_notify (G_OBJECT (cell), "width");
629         }
630
631       if (height != cell->height)
632         {
633           cell->height = height;
634           g_object_notify (G_OBJECT (cell), "height");
635         }
636
637       g_object_thaw_notify (G_OBJECT (cell));
638     }
639 }
640
641 /**
642  * gtk_cell_renderer_get_fixed_size:
643  * @cell: A #GtkCellRenderer
644  * @width: location to fill in with the fixed width of the widget, or %NULL
645  * @height: location to fill in with the fixed height of the widget, or %NULL
646  * 
647  * Fills in @width and @height with the appropriate size of @cell.
648  **/
649 void
650 gtk_cell_renderer_get_fixed_size (GtkCellRenderer *cell,
651                                   gint            *width,
652                                   gint            *height)
653 {
654   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
655
656   if (width)
657     (* width) = cell->width;
658   if (height)
659     (* height) = cell->height;
660 }