]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
Remove excess calls to g_return_if_fail from static and virtual functions.
[~andy/gtk] / gtk / gtkbox.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtkbox.h"
28 #include "gtkintl.h"
29
30 enum {
31   PROP_0,
32   PROP_SPACING,
33   PROP_HOMOGENEOUS
34 };
35
36 enum {
37   CHILD_PROP_0,
38   CHILD_PROP_EXPAND,
39   CHILD_PROP_FILL,
40   CHILD_PROP_PADDING,
41   CHILD_PROP_PACK_TYPE,
42   CHILD_PROP_POSITION
43 };
44
45 static void gtk_box_class_init (GtkBoxClass    *klass);
46 static void gtk_box_init       (GtkBox         *box);
47 static void gtk_box_set_property (GObject         *object,
48                                   guint            prop_id,
49                                   const GValue    *value,
50                                   GParamSpec      *pspec);
51 static void gtk_box_get_property (GObject         *object,
52                                   guint            prop_id,
53                                   GValue          *value,
54                                   GParamSpec      *pspec);
55 static void gtk_box_add        (GtkContainer   *container,
56                                 GtkWidget      *widget);
57 static void gtk_box_remove     (GtkContainer   *container,
58                                 GtkWidget      *widget);
59 static void gtk_box_forall     (GtkContainer   *container,
60                                 gboolean        include_internals,
61                                 GtkCallback     callback,
62                                 gpointer        callback_data);
63 static void gtk_box_set_child_property (GtkContainer    *container,
64                                         GtkWidget       *child,
65                                         guint            property_id,
66                                         const GValue    *value,
67                                         GParamSpec      *pspec);
68 static void gtk_box_get_child_property (GtkContainer    *container,
69                                         GtkWidget       *child,
70                                         guint            property_id,
71                                         GValue          *value,
72                                         GParamSpec      *pspec);
73 static GtkType gtk_box_child_type (GtkContainer   *container);
74      
75
76 static GtkContainerClass *parent_class = NULL;
77
78
79 GtkType
80 gtk_box_get_type (void)
81 {
82   static GtkType box_type = 0;
83
84   if (!box_type)
85     {
86       static const GtkTypeInfo box_info =
87       {
88         "GtkBox",
89         sizeof (GtkBox),
90         sizeof (GtkBoxClass),
91         (GtkClassInitFunc) gtk_box_class_init,
92         (GtkObjectInitFunc) gtk_box_init,
93         /* reserved_1 */ NULL,
94         /* reserved_2 */ NULL,
95         (GtkClassInitFunc) NULL,
96       };
97
98       box_type = gtk_type_unique (GTK_TYPE_CONTAINER, &box_info);
99     }
100
101   return box_type;
102 }
103
104 static void
105 gtk_box_class_init (GtkBoxClass *class)
106 {
107   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
108   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
109
110   parent_class = g_type_class_peek_parent (class);
111
112   gobject_class->set_property = gtk_box_set_property;
113   gobject_class->get_property = gtk_box_get_property;
114    
115   container_class->add = gtk_box_add;
116   container_class->remove = gtk_box_remove;
117   container_class->forall = gtk_box_forall;
118   container_class->child_type = gtk_box_child_type;
119   container_class->set_child_property = gtk_box_set_child_property;
120   container_class->get_child_property = gtk_box_get_child_property;
121
122   g_object_class_install_property (gobject_class,
123                                    PROP_SPACING,
124                                    g_param_spec_int ("spacing",
125                                                      _("Spacing"),
126                                                      _("The amount of space between children."),
127                                                      0,
128                                                      G_MAXINT,
129                                                      0,
130                                                      G_PARAM_READABLE | G_PARAM_WRITABLE));
131   
132   g_object_class_install_property (gobject_class,
133                                    PROP_HOMOGENEOUS,
134                                    g_param_spec_boolean ("homogeneous",
135                                                          _("Homogeneous"),
136                                                          _("Whether the children should all be the same size."),
137                                                          FALSE,
138                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
139
140   gtk_container_class_install_child_property (container_class,
141                                               CHILD_PROP_EXPAND,
142                                               g_param_spec_boolean ("expand", NULL, NULL,
143                                                                     TRUE,
144                                                                     G_PARAM_READWRITE));
145   gtk_container_class_install_child_property (container_class,
146                                               CHILD_PROP_FILL,
147                                               g_param_spec_boolean ("fill", NULL, NULL,
148                                                                     TRUE,
149                                                                     G_PARAM_READWRITE));
150   gtk_container_class_install_child_property (container_class,
151                                               CHILD_PROP_PADDING,
152                                               g_param_spec_uint ("padding", NULL, NULL,
153                                                                  0, G_MAXINT, 0,
154                                                                  G_PARAM_READWRITE));
155   gtk_container_class_install_child_property (container_class,
156                                               CHILD_PROP_PACK_TYPE,
157                                               g_param_spec_enum ("pack_type", NULL, NULL,
158                                                                  GTK_TYPE_PACK_TYPE, GTK_PACK_START,
159                                                                  G_PARAM_READWRITE));
160   gtk_container_class_install_child_property (container_class,
161                                               CHILD_PROP_POSITION,
162                                               g_param_spec_int ("position", NULL, NULL,
163                                                                 -1, G_MAXINT, 0,
164                                                                 G_PARAM_READWRITE));
165 }
166
167 static void
168 gtk_box_init (GtkBox *box)
169 {
170   GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW);
171   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (box), FALSE);
172   
173   box->children = NULL;
174   box->spacing = 0;
175   box->homogeneous = FALSE;
176 }
177
178 static void 
179 gtk_box_set_property (GObject         *object,
180                       guint            prop_id,
181                       const GValue    *value,
182                       GParamSpec      *pspec)
183 {
184   GtkBox *box;
185
186   box = GTK_BOX (object);
187
188   switch (prop_id)
189     {
190     case PROP_SPACING:
191       gtk_box_set_spacing (box, g_value_get_int (value));
192       break;
193     case PROP_HOMOGENEOUS:
194       gtk_box_set_homogeneous (box, g_value_get_boolean (value));
195       break;
196     default:
197       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
198       break;
199     }
200 }
201
202 static void gtk_box_get_property (GObject         *object,
203                                   guint            prop_id,
204                                   GValue          *value,
205                                   GParamSpec      *pspec)
206 {
207   GtkBox *box;
208
209   box = GTK_BOX (object);
210
211   switch (prop_id)
212     {
213     case PROP_SPACING:
214       g_value_set_int (value, box->spacing);
215       break;
216     case PROP_HOMOGENEOUS:
217       g_value_set_boolean (value, box->homogeneous);
218       break;
219     default:
220       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
221       break;
222     }
223 }
224
225 static GtkType
226 gtk_box_child_type      (GtkContainer   *container)
227 {
228   return GTK_TYPE_WIDGET;
229 }
230
231 static void
232 gtk_box_set_child_property (GtkContainer    *container,
233                             GtkWidget       *child,
234                             guint            property_id,
235                             const GValue    *value,
236                             GParamSpec      *pspec)
237 {
238   gboolean expand = 0;
239   gboolean fill = 0;
240   guint padding = 0;
241   GtkPackType pack_type = 0;
242
243   if (property_id != CHILD_PROP_POSITION)
244     gtk_box_query_child_packing (GTK_BOX (container),
245                                  child,
246                                  &expand,
247                                  &fill,
248                                  &padding,
249                                  &pack_type);
250   switch (property_id)
251     {
252     case CHILD_PROP_EXPAND:
253       gtk_box_set_child_packing (GTK_BOX (container),
254                                  child,
255                                  g_value_get_boolean (value),
256                                  fill,
257                                  padding,
258                                  pack_type);
259       break;
260     case CHILD_PROP_FILL:
261       gtk_box_set_child_packing (GTK_BOX (container),
262                                  child,
263                                  expand,
264                                  g_value_get_boolean (value),
265                                  padding,
266                                  pack_type);
267       break;
268     case CHILD_PROP_PADDING:
269       gtk_box_set_child_packing (GTK_BOX (container),
270                                  child,
271                                  expand,
272                                  fill,
273                                  g_value_get_uint (value),
274                                  pack_type);
275       break;
276     case CHILD_PROP_PACK_TYPE:
277       gtk_box_set_child_packing (GTK_BOX (container),
278                                  child,
279                                  expand,
280                                  fill,
281                                  padding,
282                                  g_value_get_enum (value));
283       break;
284     case CHILD_PROP_POSITION:
285       gtk_box_reorder_child (GTK_BOX (container),
286                              child,
287                              g_value_get_int (value));
288       break;
289     default:
290       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
291       break;
292     }
293 }
294
295 static void
296 gtk_box_get_child_property (GtkContainer *container,
297                             GtkWidget    *child,
298                             guint         property_id,
299                             GValue       *value,
300                             GParamSpec   *pspec)
301 {
302   gboolean expand = 0;
303   gboolean fill = 0;
304   guint padding = 0;
305   GtkPackType pack_type = 0;
306   GList *list;
307
308   if (property_id != CHILD_PROP_POSITION)
309     gtk_box_query_child_packing (GTK_BOX (container),
310                                  child,
311                                  &expand,
312                                  &fill,
313                                  &padding,
314                                  &pack_type);
315   switch (property_id)
316     {
317       guint i;
318     case CHILD_PROP_EXPAND:
319       g_value_set_boolean (value, expand);
320       break;
321     case CHILD_PROP_FILL:
322       g_value_set_boolean (value, fill);
323       break;
324     case CHILD_PROP_PADDING:
325       g_value_set_uint (value, padding);
326       break;
327     case CHILD_PROP_PACK_TYPE:
328       g_value_set_enum (value, pack_type);
329       break;
330     case CHILD_PROP_POSITION:
331       i = 0;
332       for (list = GTK_BOX (container)->children; list; list = list->next)
333         {
334           GtkBoxChild *child_entry;
335
336           child_entry = list->data;
337           if (child_entry->widget == child)
338             break;
339           i++;
340         }
341       g_value_set_int (value, list ? i : -1);
342       break;
343     default:
344       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
345       break;
346     }
347 }
348
349 void
350 gtk_box_pack_start (GtkBox    *box,
351                     GtkWidget *child,
352                     gboolean   expand,
353                     gboolean   fill,
354                     guint      padding)
355 {
356   GtkBoxChild *child_info;
357
358   g_return_if_fail (GTK_IS_BOX (box));
359   g_return_if_fail (GTK_IS_WIDGET (child));
360   g_return_if_fail (child->parent == NULL);
361
362   child_info = g_new (GtkBoxChild, 1);
363   child_info->widget = child;
364   child_info->padding = padding;
365   child_info->expand = expand ? TRUE : FALSE;
366   child_info->fill = fill ? TRUE : FALSE;
367   child_info->pack = GTK_PACK_START;
368   child_info->is_secondary = FALSE;
369
370   box->children = g_list_append (box->children, child_info);
371
372   gtk_widget_freeze_child_notify (child);
373
374   gtk_widget_set_parent (child, GTK_WIDGET (box));
375   
376   gtk_widget_child_notify (child, "expand");
377   gtk_widget_child_notify (child, "fill");
378   gtk_widget_child_notify (child, "padding");
379   gtk_widget_child_notify (child, "pack_type");
380   gtk_widget_child_notify (child, "position");
381   gtk_widget_thaw_child_notify (child);
382 }
383
384 void
385 gtk_box_pack_end (GtkBox    *box,
386                   GtkWidget *child,
387                   gboolean   expand,
388                   gboolean   fill,
389                   guint      padding)
390 {
391   GtkBoxChild *child_info;
392
393   g_return_if_fail (GTK_IS_BOX (box));
394   g_return_if_fail (GTK_IS_WIDGET (child));
395   g_return_if_fail (child->parent == NULL);
396
397   child_info = g_new (GtkBoxChild, 1);
398   child_info->widget = child;
399   child_info->padding = padding;
400   child_info->expand = expand ? TRUE : FALSE;
401   child_info->fill = fill ? TRUE : FALSE;
402   child_info->pack = GTK_PACK_END;
403   child_info->is_secondary = FALSE;
404
405   box->children = g_list_append (box->children, child_info);
406
407   gtk_widget_freeze_child_notify (child);
408
409   gtk_widget_set_parent (child, GTK_WIDGET (box));
410
411   gtk_widget_child_notify (child, "expand");
412   gtk_widget_child_notify (child, "fill");
413   gtk_widget_child_notify (child, "padding");
414   gtk_widget_child_notify (child, "pack_type");
415   gtk_widget_child_notify (child, "position");
416   gtk_widget_thaw_child_notify (child);
417 }
418
419 void
420 gtk_box_pack_start_defaults (GtkBox    *box,
421                              GtkWidget *child)
422 {
423   gtk_box_pack_start (box, child, TRUE, TRUE, 0);
424 }
425
426 void
427 gtk_box_pack_end_defaults (GtkBox    *box,
428                            GtkWidget *child)
429 {
430   gtk_box_pack_end (box, child, TRUE, TRUE, 0);
431 }
432
433 void
434 gtk_box_set_homogeneous (GtkBox  *box,
435                          gboolean homogeneous)
436 {
437   g_return_if_fail (GTK_IS_BOX (box));
438
439   if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
440     {
441       box->homogeneous = homogeneous ? TRUE : FALSE;
442       g_object_notify (G_OBJECT (box), "homogeneous");
443       gtk_widget_queue_resize (GTK_WIDGET (box));
444     }
445 }
446
447 /**
448  * gtk_box_get_homogeneous:
449  * @box: a #GtkBox
450  *
451  * Returns whether the box is homogeneous (all children are the
452  * same size). See gtk_box_set_homogeneous ().
453  *
454  * Return value: %TRUE if the box is homogeneous.
455  **/
456 gboolean
457 gtk_box_get_homogeneous (GtkBox *box)
458 {
459   g_return_val_if_fail (GTK_IS_BOX (box), FALSE);
460
461   return box->homogeneous;
462 }
463
464 void
465 gtk_box_set_spacing (GtkBox *box,
466                      gint    spacing)
467 {
468   g_return_if_fail (GTK_IS_BOX (box));
469
470   if (spacing != box->spacing)
471     {
472       box->spacing = spacing;
473       g_object_notify (G_OBJECT (box), "spacing");
474       gtk_widget_queue_resize (GTK_WIDGET (box));
475     }
476 }
477
478 /**
479  * gtk_box_get_spacing:
480  * @box: a #GtkBox
481  * 
482  * Gets the value set by gtk_box_set_spacing().
483  * 
484  * Return value: spacing between children
485  **/
486 gint
487 gtk_box_get_spacing (GtkBox *box)
488 {
489   g_return_val_if_fail (GTK_IS_BOX (box), 0);
490
491   return box->spacing;
492 }
493
494 void
495 gtk_box_reorder_child (GtkBox    *box,
496                        GtkWidget *child,
497                        gint       position)
498 {
499   GList *list;
500
501   g_return_if_fail (GTK_IS_BOX (box));
502   g_return_if_fail (GTK_IS_WIDGET (child));
503
504   list = box->children;
505   while (list)
506     {
507       GtkBoxChild *child_info;
508
509       child_info = list->data;
510       if (child_info->widget == child)
511         break;
512
513       list = list->next;
514     }
515
516   if (list && box->children->next)
517     {
518       GList *tmp_list;
519
520       if (list->next)
521         list->next->prev = list->prev;
522       if (list->prev)
523         list->prev->next = list->next;
524       else
525         box->children = list->next;
526
527       tmp_list = box->children;
528       while (position && tmp_list->next)
529         {
530           position--;
531           tmp_list = tmp_list->next;
532         }
533
534       if (position)
535         {
536           tmp_list->next = list;
537           list->prev = tmp_list;
538           list->next = NULL;
539         }
540       else
541         {
542           if (tmp_list->prev)
543             tmp_list->prev->next = list;
544           else
545             box->children = list;
546           list->prev = tmp_list->prev;
547           tmp_list->prev = list;
548           list->next = tmp_list;
549         }
550
551       gtk_widget_child_notify (child, "position");
552       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
553         gtk_widget_queue_resize (child);
554     }
555 }
556
557 void
558 gtk_box_query_child_packing (GtkBox             *box,
559                              GtkWidget          *child,
560                              gboolean           *expand,
561                              gboolean           *fill,
562                              guint              *padding,
563                              GtkPackType        *pack_type)
564 {
565   GList *list;
566   GtkBoxChild *child_info = NULL;
567
568   g_return_if_fail (GTK_IS_BOX (box));
569   g_return_if_fail (GTK_IS_WIDGET (child));
570
571   list = box->children;
572   while (list)
573     {
574       child_info = list->data;
575       if (child_info->widget == child)
576         break;
577
578       list = list->next;
579     }
580
581   if (list)
582     {
583       if (expand)
584         *expand = child_info->expand;
585       if (fill)
586         *fill = child_info->fill;
587       if (padding)
588         *padding = child_info->padding;
589       if (pack_type)
590         *pack_type = child_info->pack;
591     }
592 }
593
594 void
595 gtk_box_set_child_packing (GtkBox               *box,
596                            GtkWidget            *child,
597                            gboolean              expand,
598                            gboolean              fill,
599                            guint                 padding,
600                            GtkPackType           pack_type)
601 {
602   GList *list;
603   GtkBoxChild *child_info = NULL;
604
605   g_return_if_fail (GTK_IS_BOX (box));
606   g_return_if_fail (GTK_IS_WIDGET (child));
607
608   list = box->children;
609   while (list)
610     {
611       child_info = list->data;
612       if (child_info->widget == child)
613         break;
614
615       list = list->next;
616     }
617
618   gtk_widget_freeze_child_notify (child);
619   if (list)
620     {
621       child_info->expand = expand != FALSE;
622       gtk_widget_child_notify (child, "expand");
623       child_info->fill = fill != FALSE;
624       gtk_widget_child_notify (child, "fill");
625       child_info->padding = padding;
626       gtk_widget_child_notify (child, "padding");
627       if (pack_type == GTK_PACK_END)
628         child_info->pack = GTK_PACK_END;
629       else
630         child_info->pack = GTK_PACK_START;
631       gtk_widget_child_notify (child, "pack_type");
632
633       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
634         gtk_widget_queue_resize (child);
635     }
636   gtk_widget_thaw_child_notify (child);
637 }
638
639 static void
640 gtk_box_add (GtkContainer *container,
641              GtkWidget    *widget)
642 {
643   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
644 }
645
646 static void
647 gtk_box_remove (GtkContainer *container,
648                 GtkWidget    *widget)
649 {
650   GtkBox *box;
651   GtkBoxChild *child;
652   GList *children;
653
654   box = GTK_BOX (container);
655
656   children = box->children;
657   while (children)
658     {
659       child = children->data;
660
661       if (child->widget == widget)
662         {
663           gboolean was_visible;
664
665           was_visible = GTK_WIDGET_VISIBLE (widget);
666           gtk_widget_unparent (widget);
667
668           box->children = g_list_remove_link (box->children, children);
669           g_list_free (children);
670           g_free (child);
671
672           /* queue resize regardless of GTK_WIDGET_VISIBLE (container),
673            * since that's what is needed by toplevels.
674            */
675           if (was_visible)
676             gtk_widget_queue_resize (GTK_WIDGET (container));
677
678           break;
679         }
680
681       children = children->next;
682     }
683 }
684
685 static void
686 gtk_box_forall (GtkContainer *container,
687                 gboolean      include_internals,
688                 GtkCallback   callback,
689                 gpointer      callback_data)
690 {
691   GtkBox *box;
692   GtkBoxChild *child;
693   GList *children;
694
695   g_return_if_fail (callback != NULL);
696
697   box = GTK_BOX (container);
698
699   children = box->children;
700   while (children)
701     {
702       child = children->data;
703       children = children->next;
704
705       if (child->pack == GTK_PACK_START)
706         (* callback) (child->widget, callback_data);
707     }
708
709   children = g_list_last (box->children);
710   while (children)
711     {
712       child = children->data;
713       children = children->prev;
714
715       if (child->pack == GTK_PACK_END)
716         (* callback) (child->widget, callback_data);
717     }
718 }