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