]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellareabox.c
ad4dcfa7ecdbf20fbd09123e4dc09e25aba6c008
[~andy/gtk] / gtk / gtkcellareabox.c
1 /* gtkcellareabox.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 "gtkorientable.h"
25 #include "gtkcelllayout.h"
26 #include "gtkcellareabox.h"
27 #include "gtkcellareaboxiter.h"
28
29 /* GObjectClass */
30 static void      gtk_cell_area_box_finalize                       (GObject            *object);
31 static void      gtk_cell_area_box_dispose                        (GObject            *object);
32 static void      gtk_cell_area_box_set_property                   (GObject            *object,
33                                                                    guint               prop_id,
34                                                                    const GValue       *value,
35                                                                    GParamSpec         *pspec);
36 static void      gtk_cell_area_box_get_property                   (GObject            *object,
37                                                                    guint               prop_id,
38                                                                    GValue             *value,
39                                                                    GParamSpec         *pspec);
40
41 /* GtkCellAreaClass */
42 static void      gtk_cell_area_box_add                            (GtkCellArea        *area,
43                                                                    GtkCellRenderer    *renderer);
44 static void      gtk_cell_area_box_remove                         (GtkCellArea        *area,
45                                                                    GtkCellRenderer    *renderer);
46 static void      gtk_cell_area_box_forall                         (GtkCellArea        *area,
47                                                                    GtkCellCallback     callback,
48                                                                    gpointer            callback_data);
49 static gint      gtk_cell_area_box_event                          (GtkCellArea        *area,
50                                                                    GtkWidget          *widget,
51                                                                    GdkEvent           *event,
52                                                                    const GdkRectangle *cell_area);
53 static void      gtk_cell_area_box_render                         (GtkCellArea        *area,
54                                                                    cairo_t            *cr,
55                                                                    GtkWidget          *widget,
56                                                                    const GdkRectangle *cell_area);
57
58 static GtkCellAreaIter    *gtk_cell_area_box_create_iter          (GtkCellArea        *area);
59 static GtkSizeRequestMode  gtk_cell_area_box_get_request_mode     (GtkCellArea        *area);
60 static void      gtk_cell_area_box_get_preferred_width            (GtkCellArea        *area,
61                                                                    GtkCellAreaIter    *iter,
62                                                                    GtkWidget          *widget,
63                                                                    gint               *minimum_width,
64                                                                    gint               *natural_width);
65 static void      gtk_cell_area_box_get_preferred_height           (GtkCellArea        *area,
66                                                                    GtkCellAreaIter    *iter,
67                                                                    GtkWidget          *widget,
68                                                                    gint               *minimum_height,
69                                                                    gint               *natural_height);
70 static void      gtk_cell_area_box_get_preferred_height_for_width (GtkCellArea        *area,
71                                                                    GtkCellAreaIter    *iter,
72                                                                    GtkWidget          *widget,
73                                                                    gint                width,
74                                                                    gint               *minimum_height,
75                                                                    gint               *natural_height);
76 static void      gtk_cell_area_box_get_preferred_width_for_height (GtkCellArea        *area,
77                                                                    GtkCellAreaIter    *iter,
78                                                                    GtkWidget          *widget,
79                                                                    gint                height,
80                                                                    gint               *minimum_width,
81                                                                    gint               *natural_width);
82
83 /* GtkCellLayoutIface */
84 static void      gtk_cell_area_box_cell_layout_init               (GtkCellLayoutIface *iface);
85 static void      gtk_cell_area_box_layout_pack_start              (GtkCellLayout      *cell_layout,
86                                                                    GtkCellRenderer    *renderer,
87                                                                    gboolean            expand);
88 static void      gtk_cell_area_box_layout_pack_end                (GtkCellLayout      *cell_layout,
89                                                                    GtkCellRenderer    *renderer,
90                                                                    gboolean            expand);
91 static void      gtk_cell_area_box_layout_reorder                 (GtkCellLayout      *cell_layout,
92                                                                    GtkCellRenderer    *renderer,
93                                                                    gint                position);
94
95
96 /* CellInfo metadata handling */
97 typedef struct {
98   GtkCellRenderer *renderer;
99
100   guint            expand : 1;
101   guint            pack   : 1;
102 } CellInfo;
103
104 static CellInfo  *cell_info_new  (GtkCellRenderer *renderer, 
105                                   gboolean         expand,
106                                   GtkPackType      pack);
107 static void       cell_info_free (CellInfo        *info);
108 static gint       cell_info_find (CellInfo        *info,
109                                   GtkCellRenderer *renderer);
110
111
112 struct _GtkCellAreaBoxPrivate
113 {
114   GtkOrientation orientation;
115
116   GList *cells;
117 };
118
119 enum {
120   PROP_0,
121   PROP_ORIENTATION
122 };
123
124 G_DEFINE_TYPE_WITH_CODE (GtkCellAreaBox, gtk_cell_area_box, GTK_TYPE_CELL_AREA,
125                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
126                                                 gtk_cell_area_box_cell_layout_init)
127                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL));
128
129 static void
130 gtk_cell_area_box_init (GtkCellAreaBox *box)
131 {
132   GtkCellAreaBoxPrivate *priv;
133
134   box->priv = G_TYPE_INSTANCE_GET_PRIVATE (box,
135                                            GTK_TYPE_CELL_AREA_BOX,
136                                            GtkCellAreaBoxPrivate);
137   priv = box->priv;
138
139   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
140   priv->cells       = NULL;
141 }
142
143 static void 
144 gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class)
145 {
146   GObjectClass     *object_class = G_OBJECT_CLASS (class);
147   GtkCellAreaClass *area_class   = GTK_CELL_AREA_CLASS (class);
148
149   /* GObjectClass */
150   object_class->finalize     = gtk_cell_area_box_finalize;
151   object_class->dispose      = gtk_cell_area_box_dispose;
152   object_class->set_property = gtk_cell_area_box_set_property;
153   object_class->get_property = gtk_cell_area_box_get_property;
154
155   /* GtkCellAreaClass */
156   area_class->add                            = gtk_cell_area_box_add;
157   area_class->remove                         = gtk_cell_area_box_remove;
158   area_class->forall                         = gtk_cell_area_box_forall;
159   area_class->event                          = gtk_cell_area_box_event;
160   area_class->render                         = gtk_cell_area_box_render;
161   
162   area_class->create_iter                    = gtk_cell_area_box_create_iter;
163   area_class->get_request_mode               = gtk_cell_area_box_get_request_mode;
164   area_class->get_preferred_width            = gtk_cell_area_box_get_preferred_width;
165   area_class->get_preferred_height           = gtk_cell_area_box_get_preferred_height;
166   area_class->get_preferred_height_for_width = gtk_cell_area_box_get_preferred_height_for_width;
167   area_class->get_preferred_width_for_height = gtk_cell_area_box_get_preferred_width_for_height;
168
169   g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
170
171
172   g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxPrivate));
173 }
174
175
176 /*************************************************************
177  *                    CellInfo Basics                        *
178  *************************************************************/
179 static CellInfo *
180 cell_info_new  (GtkCellRenderer *renderer, 
181                 gboolean         expand,
182                 GtkPackType      pack)
183 {
184   CellInfo *info = g_slice_new (CellInfo);
185   
186   info->renderer = g_object_ref_sink (renderer);
187   info->expand   = expand;
188   info->pack     = pack;
189
190   return info;
191 }
192
193 static void
194 cell_info_free (CellInfo *info)
195 {
196   g_object_unref (info->renderer);
197
198   g_slice_free (CellInfo, info);
199 }
200
201 static gint
202 cell_info_find (CellInfo        *info,
203                 GtkCellRenderer *renderer)
204 {
205   return (info->renderer == renderer) ? 0 : -1;
206 }
207
208 /*************************************************************
209  *                      GObjectClass                         *
210  *************************************************************/
211 static void
212 gtk_cell_area_box_finalize (GObject *object)
213 {
214   G_OBJECT_CLASS (gtk_cell_area_box_parent_class)->finalize (object);
215 }
216
217 static void
218 gtk_cell_area_box_dispose (GObject *object)
219 {
220   G_OBJECT_CLASS (gtk_cell_area_box_parent_class)->dispose (object);
221 }
222
223 static void
224 gtk_cell_area_box_set_property (GObject       *object,
225                                 guint          prop_id,
226                                 const GValue  *value,
227                                 GParamSpec    *pspec)
228 {
229
230 }
231
232 static void
233 gtk_cell_area_box_get_property (GObject     *object,
234                                 guint        prop_id,
235                                 GValue      *value,
236                                 GParamSpec  *pspec)
237 {
238
239 }
240
241 /*************************************************************
242  *                    GtkCellAreaClass                       *
243  *************************************************************/
244 static void      
245 gtk_cell_area_box_add (GtkCellArea        *area,
246                        GtkCellRenderer    *renderer)
247 {
248   gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area),
249                                 renderer, FALSE);
250 }
251
252 static void
253 gtk_cell_area_box_remove (GtkCellArea        *area,
254                           GtkCellRenderer    *renderer)
255 {
256   GtkCellAreaBox        *box  = GTK_CELL_AREA_BOX (area);
257   GtkCellAreaBoxPrivate *priv = box->priv;
258   GList                 *node;
259
260   node = g_list_find_custom (priv->cells, renderer, 
261                              (GCompareFunc)cell_info_find);
262
263   if (node)
264     {
265       CellInfo *info = node->data;
266
267       cell_info_free (info);
268
269       priv->cells = g_list_delete_link (priv->cells, node);
270     }
271   else
272     g_warning ("Trying to remove a cell renderer that is not present GtkCellAreaBox");
273 }
274
275 static void
276 gtk_cell_area_box_forall (GtkCellArea        *area,
277                           GtkCellCallback     callback,
278                           gpointer            callback_data)
279 {
280   GtkCellAreaBox        *box  = GTK_CELL_AREA_BOX (area);
281   GtkCellAreaBoxPrivate *priv = box->priv;
282   GList                 *list;
283
284   for (list = priv->cells; list; list = list->next)
285     {
286       CellInfo *info = list->data;
287
288       callback (info->renderer, callback_data);
289     }
290 }
291
292 static gint
293 gtk_cell_area_box_event (GtkCellArea        *area,
294                          GtkWidget          *widget,
295                          GdkEvent           *event,
296                          const GdkRectangle *cell_area)
297 {
298
299
300   return 0;
301 }
302
303 static void
304 gtk_cell_area_box_render (GtkCellArea        *area,
305                           cairo_t            *cr,
306                           GtkWidget          *widget,
307                           const GdkRectangle *cell_area)
308 {
309
310 }
311
312 static GtkCellAreaIter *
313 gtk_cell_area_box_create_iter (GtkCellArea *area)
314 {
315   return (GtkCellAreaIter *)g_object_new (GTK_TYPE_CELL_AREA_BOX_ITER, NULL);
316 }
317
318 static GtkSizeRequestMode 
319 gtk_cell_area_box_get_request_mode (GtkCellArea *area)
320 {
321   GtkCellAreaBox        *box  = GTK_CELL_AREA_BOX (area);
322   GtkCellAreaBoxPrivate *priv = box->priv;
323
324   return (priv->orientation) == GTK_ORIENTATION_HORIZONTAL ?
325     GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH :
326     GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
327 }
328
329 static void
330 gtk_cell_area_box_get_preferred_width (GtkCellArea        *area,
331                                        GtkCellAreaIter    *iter,
332                                        GtkWidget          *widget,
333                                        gint               *minimum_width,
334                                        gint               *natural_width)
335 {
336   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter));
337 }
338
339 static void
340 gtk_cell_area_box_get_preferred_height (GtkCellArea        *area,
341                                         GtkCellAreaIter    *iter,
342                                         GtkWidget          *widget,
343                                         gint               *minimum_height,
344                                         gint               *natural_height)
345 {
346   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter));
347
348
349 }
350
351 static void
352 gtk_cell_area_box_get_preferred_height_for_width (GtkCellArea        *area,
353                                                   GtkCellAreaIter    *iter,
354                                                   GtkWidget          *widget,
355                                                   gint                width,
356                                                   gint               *minimum_height,
357                                                   gint               *natural_height)
358 {
359   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter));
360
361 }
362
363 static void
364 gtk_cell_area_box_get_preferred_width_for_height (GtkCellArea        *area,
365                                                   GtkCellAreaIter    *iter,
366                                                   GtkWidget          *widget,
367                                                   gint                height,
368                                                   gint               *minimum_width,
369                                                   gint               *natural_width)
370 {
371   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter));
372
373 }
374
375
376 /*************************************************************
377  *                    GtkCellLayoutIface                     *
378  *************************************************************/
379 static void
380 gtk_cell_area_box_cell_layout_init (GtkCellLayoutIface *iface)
381 {
382   iface->pack_start = gtk_cell_area_box_layout_pack_start;
383   iface->pack_end   = gtk_cell_area_box_layout_pack_end;
384   iface->reorder    = gtk_cell_area_box_layout_reorder;
385 }
386
387 static void
388 gtk_cell_area_box_layout_pack_start (GtkCellLayout      *cell_layout,
389                                      GtkCellRenderer    *renderer,
390                                      gboolean            expand)
391 {
392   gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand);
393 }
394
395 static void
396 gtk_cell_area_box_layout_pack_end (GtkCellLayout      *cell_layout,
397                                    GtkCellRenderer    *renderer,
398                                    gboolean            expand)
399 {
400   gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand);
401 }
402
403 static void
404 gtk_cell_area_box_layout_reorder (GtkCellLayout      *cell_layout,
405                                   GtkCellRenderer    *renderer,
406                                   gint                position)
407 {
408   GtkCellAreaBox        *box  = GTK_CELL_AREA_BOX (cell_layout);
409   GtkCellAreaBoxPrivate *priv = box->priv;
410   GList                 *node;
411   CellInfo              *info;
412   
413   node = g_list_find_custom (priv->cells, renderer, 
414                              (GCompareFunc)cell_info_find);
415
416   if (node)
417     {
418       info = node->data;
419
420       priv->cells = g_list_delete_link (priv->cells, node);
421       priv->cells = g_list_insert (priv->cells, info, position);
422     }
423 }
424
425 /*************************************************************
426  *                            API                            *
427  *************************************************************/
428 GtkCellArea *
429 gtk_cell_area_box_new (void)
430 {
431   return (GtkCellArea *)g_object_new (GTK_TYPE_CELL_AREA_BOX, NULL);
432 }
433
434 void
435 gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
436                                GtkCellRenderer *renderer,
437                                gboolean         expand)
438 {
439   GtkCellAreaBoxPrivate *priv;
440   CellInfo              *info;
441
442   g_return_if_fail (GTK_IS_CELL_AREA_BOX (box));
443   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
444
445   priv = box->priv;
446
447   if (g_list_find_custom (priv->cells, renderer, 
448                           (GCompareFunc)cell_info_find))
449     {
450       g_warning ("Refusing to add the same cell renderer to a GtkCellAreaBox twice");
451       return;
452     }
453
454   info = cell_info_new (renderer, expand, GTK_PACK_START);
455
456   priv->cells = g_list_append (priv->cells, info);
457 }
458
459 void
460 gtk_cell_area_box_pack_end (GtkCellAreaBox  *box,
461                             GtkCellRenderer *renderer,
462                             gboolean         expand)
463 {
464   GtkCellAreaBoxPrivate *priv;
465   CellInfo              *info;
466
467   g_return_if_fail (GTK_IS_CELL_AREA_BOX (box));
468   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
469
470   priv = box->priv;
471
472   if (g_list_find_custom (priv->cells, renderer, 
473                           (GCompareFunc)cell_info_find))
474     {
475       g_warning ("Refusing to add the same cell renderer to a GtkCellArea twice");
476       return;
477     }
478
479   info = cell_info_new (renderer, expand, GTK_PACK_END);
480
481   priv->cells = g_list_append (priv->cells, info);
482 }