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