]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellarea.c
cb85f5a7a8560bcab0118a93903769d81cf2c1b4
[~andy/gtk] / gtk / gtkcellarea.c
1 /* gtkcellarea.c
2  *
3  * Copyright (C) 2010 Openismus GmbH
4  *
5  * Authors:
6  *      Tristan Van Berkom <tristanvb@openismus.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #include "gtkcelllayout.h"
25 #include "gtkcellarea.h"
26
27 /* GtkCellAreaClass */
28 static void      gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
29                                                                     GtkWidget          *widget,
30                                                                     gint                width,
31                                                                     gint               *minimum_height,
32                                                                     gint               *natural_height);
33 static void      gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
34                                                                     GtkWidget          *widget,
35                                                                     gint                height,
36                                                                     gint               *minimum_width,
37                                                                     gint               *natural_width);
38
39
40 /* GtkCellLayoutIface */
41 static void      gtk_cell_area_cell_layout_init              (GtkCellLayoutIface    *iface);
42 static void      gtk_cell_area_pack_default                  (GtkCellLayout         *cell_layout,
43                                                               GtkCellRenderer       *renderer,
44                                                               gboolean               expand);
45 static void      gtk_cell_area_clear                         (GtkCellLayout         *cell_layout);
46 static void      gtk_cell_area_add_attribute                 (GtkCellLayout         *cell_layout,
47                                                               GtkCellRenderer       *renderer,
48                                                               const gchar           *attribute,
49                                                               gint                   id);
50 static void      gtk_cell_area_clear_attributes              (GtkCellLayout         *cell_layout,
51                                                               GtkCellRenderer       *renderer);
52 static GList    *gtk_cell_area_get_cells                     (GtkCellLayout         *cell_layout);
53
54 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
55                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
56                                                          gtk_cell_area_cell_layout_init));
57
58
59 static void
60 gtk_cell_area_init (GtkCellArea *area)
61 {
62
63 }
64
65 static void 
66 gtk_cell_area_class_init (GtkCellAreaClass *class)
67 {
68   /* general */
69   class->add                = NULL;
70   class->remove             = NULL;
71   class->forall             = NULL;
72   class->event              = NULL;
73   class->render             = NULL;
74
75   /* attributes */
76   class->attribute_connect    = NULL;
77   class->attribute_disconnect = NULL;
78   class->attribute_apply      = NULL;
79   class->attribute_forall     = NULL;
80
81   /* geometry */
82   class->get_request_mode               = NULL;
83   class->get_preferred_width            = NULL;
84   class->get_preferred_height           = NULL;
85   class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
86   class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
87 }
88
89
90 /*************************************************************
91  *                   GtkCellLayoutIface                      *
92  *************************************************************/
93 static void
94 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
95 {
96   iface->pack_start       = gtk_cell_area_pack_default;
97   iface->pack_end         = gtk_cell_area_pack_default;
98   iface->clear            = gtk_cell_area_clear;
99   iface->add_attribute    = gtk_cell_area_add_attribute;
100   iface->clear_attributes = gtk_cell_area_clear_attributes;
101   iface->get_cells        = gtk_cell_area_get_cells;
102 }
103
104 static void
105 gtk_cell_area_pack_default (GtkCellLayout         *cell_layout,
106                             GtkCellRenderer       *renderer,
107                             gboolean               expand)
108 {
109   gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
110 }
111
112 static void
113 gtk_cell_area_clear (GtkCellLayout *cell_layout)
114 {
115   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
116   GList *l, *cells  =
117     gtk_cell_layout_get_cells (cell_layout);
118
119   for (l = cells; l; l = l->next)
120     {
121       GtkCellRenderer *renderer = l->data;
122       gtk_cell_area_remove (area, renderer);
123     }
124
125   g_list_free (cells);
126 }
127
128
129 static void
130 gtk_cell_area_add_attribute (GtkCellLayout         *cell_layout,
131                              GtkCellRenderer       *renderer,
132                              const gchar           *attribute,
133                              gint                   id)
134 {
135   gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
136                                    renderer, attribute, id);
137 }
138
139
140 typedef struct {
141   const gchar *attribute;
142   gchar        id;
143 } CellAttribute;
144
145 static void
146 accum_attributes (GtkCellArea      *area,
147                   GtkCellRenderer  *renderer,
148                   const gchar      *attribute,
149                   gint              id,
150                   GList           **accum)
151 {
152   CellAttribute *attrib = g_slice_new (CellAttribute);
153
154   attrib->attribute = attribute;
155   attrib->id        = id;
156
157   *accum = g_list_prepend (*accum, attrib);
158 }
159
160 static void
161 gtk_cell_area_clear_attributes (GtkCellLayout         *cell_layout,
162                                 GtkCellRenderer       *renderer)
163 {
164   GtkCellArea *area = GTK_CELL_AREA (cell_layout);
165   GList       *l, *attributes = NULL;
166
167   /* Get a list of attributes so we dont modify the list inline */
168   gtk_cell_area_attribute_forall (area, renderer, 
169                                   (GtkCellAttributeCallback)accum_attributes,
170                                   &attributes);
171
172   for (l = attributes; l; l = l->next)
173     {
174       CellAttribute *attrib = l->data;
175
176       gtk_cell_area_attribute_disconnect (area, renderer, 
177                                           attrib->attribute, attrib->id);
178
179       g_slice_free (CellAttribute, attrib);
180     }
181
182   g_list_free (attributes);
183 }
184
185
186 static void
187 accum_cells (GtkCellRenderer *renderer,
188              GList          **accum)
189 {
190   *accum = g_list_prepend (*accum, renderer);
191 }
192
193 static GList *
194 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
195 {
196   GList *cells = NULL;
197
198   gtk_cell_area_forall (GTK_CELL_AREA (cell_layout), 
199                         (GtkCellCallback)accum_cells,
200                         &cells);
201
202   return g_list_reverse (cells);
203 }
204
205
206 /*************************************************************
207  *                    GtkCellAreaClass                       *
208  *************************************************************/
209 static void
210 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea        *area,
211                                                    GtkWidget          *widget,
212                                                    gint                width,
213                                                    gint               *minimum_height,
214                                                    gint               *natural_height)
215 {
216   /* If the area doesnt do height-for-width, fallback on base preferred height */
217   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_height, natural_height);
218 }
219
220 static void
221 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea        *area,
222                                                    GtkWidget          *widget,
223                                                    gint                height,
224                                                    gint               *minimum_width,
225                                                    gint               *natural_width)
226 {
227   /* If the area doesnt do width-for-height, fallback on base preferred width */
228   GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, widget, minimum_width, natural_width);
229 }
230
231 /*************************************************************
232  *                            API                            *
233  *************************************************************/
234
235 /* Basic methods */
236 void
237 gtk_cell_area_add (GtkCellArea        *area,
238                    GtkCellRenderer    *renderer)
239 {
240   GtkCellAreaClass *class;
241
242   g_return_if_fail (GTK_IS_CELL_AREA (area));
243   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
244
245   class = GTK_CELL_AREA_GET_CLASS (area);
246
247   if (class->add)
248     class->add (area, renderer);
249   else
250     g_warning ("GtkCellAreaClass::add not implemented for `%s'", 
251                g_type_name (G_TYPE_FROM_INSTANCE (area)));
252 }
253
254 void
255 gtk_cell_area_remove (GtkCellArea        *area,
256                       GtkCellRenderer    *renderer)
257 {
258   GtkCellAreaClass *class;
259
260   g_return_if_fail (GTK_IS_CELL_AREA (area));
261   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
262
263   class = GTK_CELL_AREA_GET_CLASS (area);
264
265   if (class->remove)
266     class->remove (area, renderer);
267   else
268     g_warning ("GtkCellAreaClass::remove not implemented for `%s'", 
269                g_type_name (G_TYPE_FROM_INSTANCE (area)));
270 }
271
272 void
273 gtk_cell_area_forall (GtkCellArea        *area,
274                       GtkCellCallback     callback,
275                       gpointer            callback_data)
276 {
277   GtkCellAreaClass *class;
278
279   g_return_if_fail (GTK_IS_CELL_AREA (area));
280   g_return_if_fail (callback != NULL);
281
282   class = GTK_CELL_AREA_GET_CLASS (area);
283
284   if (class->forall)
285     class->forall (area, callback, callback_data);
286   else
287     g_warning ("GtkCellAreaClass::forall not implemented for `%s'", 
288                g_type_name (G_TYPE_FROM_INSTANCE (area)));
289 }
290
291 gint
292 gtk_cell_area_event (GtkCellArea        *area,
293                      GtkWidget          *widget,
294                      GdkEvent           *event,
295                      const GdkRectangle *cell_area)
296 {
297   GtkCellAreaClass *class;
298
299   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
300   g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
301   g_return_val_if_fail (event != NULL, 0);
302   g_return_val_if_fail (cell_area != NULL, 0);
303
304   class = GTK_CELL_AREA_GET_CLASS (area);
305
306   if (class->event)
307     return class->event (area, widget, event, cell_area);
308
309   g_warning ("GtkCellAreaClass::event not implemented for `%s'", 
310              g_type_name (G_TYPE_FROM_INSTANCE (area)));
311   return 0;
312 }
313
314 void
315 gtk_cell_area_render (GtkCellArea        *area,
316                       cairo_t            *cr,
317                       GtkWidget          *widget,
318                       const GdkRectangle *cell_area)
319 {
320   GtkCellAreaClass *class;
321
322   g_return_if_fail (GTK_IS_CELL_AREA (area));
323   g_return_if_fail (cr != NULL);
324   g_return_if_fail (GTK_IS_WIDGET (widget));
325   g_return_if_fail (cell_area != NULL);
326
327   class = GTK_CELL_AREA_GET_CLASS (area);
328
329   if (class->render)
330     class->render (area, cr, widget, cell_area);
331   else
332     g_warning ("GtkCellAreaClass::render not implemented for `%s'", 
333                g_type_name (G_TYPE_FROM_INSTANCE (area)));
334 }
335
336
337 /* Attributes */ 
338 void
339 gtk_cell_area_attribute_connect (GtkCellArea        *area,
340                                  GtkCellRenderer    *renderer,
341                                  const gchar        *attribute,
342                                  gint                id)
343 {
344   GtkCellAreaClass *class;
345
346   g_return_if_fail (GTK_IS_CELL_AREA (area));
347   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
348   g_return_if_fail (attribute != NULL);
349
350   class = GTK_CELL_AREA_GET_CLASS (area);
351
352   if (class->attribute_connect)
353     class->attribute_connect (area, renderer, attribute, id);
354   else
355     g_warning ("GtkCellAreaClass::attribute_connect not implemented for `%s'", 
356                g_type_name (G_TYPE_FROM_INSTANCE (area)));
357 }
358
359 void 
360 gtk_cell_area_attribute_disconnect (GtkCellArea        *area,
361                                     GtkCellRenderer    *renderer,
362                                     const gchar        *attribute,
363                                     gint                id)
364 {
365   GtkCellAreaClass *class;
366
367   g_return_if_fail (GTK_IS_CELL_AREA (area));
368   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
369   g_return_if_fail (attribute != NULL);
370
371   class = GTK_CELL_AREA_GET_CLASS (area);
372
373   if (class->attribute_disconnect)
374     class->attribute_disconnect (area, renderer, attribute, id);
375   else
376     g_warning ("GtkCellAreaClass::attribute_disconnect not implemented for `%s'", 
377                g_type_name (G_TYPE_FROM_INSTANCE (area)));
378 }
379
380 void
381 gtk_cell_area_attribute_apply (GtkCellArea        *area,
382                                gint                id,
383                                GValue             *value)
384 {
385   GtkCellAreaClass *class;
386
387   g_return_if_fail (GTK_IS_CELL_AREA (area));
388   g_return_if_fail (G_IS_VALUE (value));
389
390   class = GTK_CELL_AREA_GET_CLASS (area);
391
392   if (class->attribute_apply)
393     class->attribute_apply (area, id, value);
394   else
395     g_warning ("GtkCellAreaClass::attribute_apply not implemented for `%s'", 
396                g_type_name (G_TYPE_FROM_INSTANCE (area)));
397 }
398
399 void
400 gtk_cell_area_attribute_forall (GtkCellArea             *area,
401                                 GtkCellRenderer         *renderer,
402                                 GtkCellAttributeCallback callback,
403                                 gpointer                 user_data)
404 {
405   GtkCellAreaClass *class;
406
407   g_return_if_fail (GTK_IS_CELL_AREA (area));
408   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
409   g_return_if_fail (callback != NULL);
410
411   class = GTK_CELL_AREA_GET_CLASS (area);
412
413   if (class->attribute_forall)
414     class->attribute_forall (area, renderer, callback, user_data);
415   else
416     g_warning ("GtkCellAreaClass::attribute_forall not implemented for `%s'", 
417                g_type_name (G_TYPE_FROM_INSTANCE (area)));
418 }
419
420
421 /* Geometry */
422 GtkSizeRequestMode 
423 gtk_cell_area_get_request_mode (GtkCellArea *area)
424 {
425   GtkCellAreaClass *class;
426
427   g_return_val_if_fail (GTK_IS_CELL_AREA (area), 
428                         GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
429
430   class = GTK_CELL_AREA_GET_CLASS (area);
431
432   if (class->get_request_mode)
433     return class->get_request_mode (area);
434
435   g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'", 
436              g_type_name (G_TYPE_FROM_INSTANCE (area)));
437   
438   return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
439 }
440
441 void
442 gtk_cell_area_get_preferred_width (GtkCellArea        *area,
443                                    GtkWidget          *widget,
444                                    gint               *minimum_size,
445                                    gint               *natural_size)
446 {
447   GtkCellAreaClass *class;
448
449   g_return_if_fail (GTK_IS_CELL_AREA (area));
450   g_return_if_fail (GTK_IS_WIDGET (widget));
451
452   class = GTK_CELL_AREA_GET_CLASS (area);
453
454   if (class->get_preferred_width)
455     class->get_preferred_width (area, widget, minimum_size, natural_size);
456   else
457     g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'", 
458                g_type_name (G_TYPE_FROM_INSTANCE (area)));
459 }
460
461 void
462 gtk_cell_area_get_preferred_height_for_width (GtkCellArea        *area,
463                                               GtkWidget          *widget,
464                                               gint                width,
465                                               gint               *minimum_height,
466                                               gint               *natural_height)
467 {
468   GtkCellAreaClass *class;
469
470   g_return_if_fail (GTK_IS_CELL_AREA (area));
471   g_return_if_fail (GTK_IS_WIDGET (widget));
472
473   class = GTK_CELL_AREA_GET_CLASS (area);
474   class->get_preferred_height_for_width (area, widget, width, minimum_height, natural_height);
475 }
476
477 void
478 gtk_cell_area_get_preferred_height (GtkCellArea        *area,
479                                     GtkWidget          *widget,
480                                     gint               *minimum_size,
481                                     gint               *natural_size)
482 {
483   GtkCellAreaClass *class;
484
485   g_return_if_fail (GTK_IS_CELL_AREA (area));
486   g_return_if_fail (GTK_IS_WIDGET (widget));
487
488   class = GTK_CELL_AREA_GET_CLASS (area);
489
490   if (class->get_preferred_height)
491     class->get_preferred_height (area, widget, minimum_size, natural_size);
492   else
493     g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'", 
494                g_type_name (G_TYPE_FROM_INSTANCE (area)));
495 }
496
497 void
498 gtk_cell_area_get_preferred_width_for_height (GtkCellArea        *area,
499                                               GtkWidget          *widget,
500                                               gint                height,
501                                               gint               *minimum_width,
502                                               gint               *natural_width)
503 {
504   GtkCellAreaClass *class;
505
506   g_return_if_fail (GTK_IS_CELL_AREA (area));
507   g_return_if_fail (GTK_IS_WIDGET (widget));
508
509   class = GTK_CELL_AREA_GET_CLASS (area);
510   class->get_preferred_width_for_height (area, widget, height, minimum_width, natural_width);
511 }