]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
removed unused widget_class.
[~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
172   box->children = NULL;
173   box->spacing = 0;
174   box->homogeneous = FALSE;
175 }
176
177 static void 
178 gtk_box_set_property (GObject         *object,
179                       guint            prop_id,
180                       const GValue    *value,
181                       GParamSpec      *pspec)
182 {
183   GtkBox *box;
184
185   box = GTK_BOX (object);
186
187   switch (prop_id)
188     {
189     case PROP_SPACING:
190       gtk_box_set_spacing (box, g_value_get_int (value));
191       break;
192     case PROP_HOMOGENEOUS:
193       gtk_box_set_homogeneous (box, g_value_get_boolean (value));
194       break;
195     default:
196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197       break;
198     }
199 }
200
201 static void gtk_box_get_property (GObject         *object,
202                                   guint            prop_id,
203                                   GValue          *value,
204                                   GParamSpec      *pspec)
205 {
206   GtkBox *box;
207
208   box = GTK_BOX (object);
209
210   switch (prop_id)
211     {
212     case PROP_SPACING:
213       g_value_set_int (value, box->spacing);
214       break;
215     case PROP_HOMOGENEOUS:
216       g_value_set_boolean (value, box->homogeneous);
217       break;
218     default:
219       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
220       break;
221     }
222 }
223
224 static GtkType
225 gtk_box_child_type      (GtkContainer   *container)
226 {
227   return GTK_TYPE_WIDGET;
228 }
229
230 static void
231 gtk_box_set_child_property (GtkContainer    *container,
232                             GtkWidget       *child,
233                             guint            property_id,
234                             const GValue    *value,
235                             GParamSpec      *pspec)
236 {
237   gboolean expand = 0;
238   gboolean fill = 0;
239   guint padding = 0;
240   GtkPackType pack_type = 0;
241
242   if (property_id != CHILD_PROP_POSITION)
243     gtk_box_query_child_packing (GTK_BOX (container),
244                                  child,
245                                  &expand,
246                                  &fill,
247                                  &padding,
248                                  &pack_type);
249   switch (property_id)
250     {
251     case CHILD_PROP_EXPAND:
252       gtk_box_set_child_packing (GTK_BOX (container),
253                                  child,
254                                  g_value_get_boolean (value),
255                                  fill,
256                                  padding,
257                                  pack_type);
258       break;
259     case CHILD_PROP_FILL:
260       gtk_box_set_child_packing (GTK_BOX (container),
261                                  child,
262                                  expand,
263                                  g_value_get_boolean (value),
264                                  padding,
265                                  pack_type);
266       break;
267     case CHILD_PROP_PADDING:
268       gtk_box_set_child_packing (GTK_BOX (container),
269                                  child,
270                                  expand,
271                                  fill,
272                                  g_value_get_uint (value),
273                                  pack_type);
274       break;
275     case CHILD_PROP_PACK_TYPE:
276       gtk_box_set_child_packing (GTK_BOX (container),
277                                  child,
278                                  expand,
279                                  fill,
280                                  padding,
281                                  g_value_get_enum (value));
282       break;
283     case CHILD_PROP_POSITION:
284       gtk_box_reorder_child (GTK_BOX (container),
285                              child,
286                              g_value_get_int (value));
287       break;
288     default:
289       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
290       break;
291     }
292 }
293
294 static void
295 gtk_box_get_child_property (GtkContainer *container,
296                             GtkWidget    *child,
297                             guint         property_id,
298                             GValue       *value,
299                             GParamSpec   *pspec)
300 {
301   gboolean expand = 0;
302   gboolean fill = 0;
303   guint padding = 0;
304   GtkPackType pack_type = 0;
305   GList *list;
306
307   if (property_id != CHILD_PROP_POSITION)
308     gtk_box_query_child_packing (GTK_BOX (container),
309                                  child,
310                                  &expand,
311                                  &fill,
312                                  &padding,
313                                  &pack_type);
314   switch (property_id)
315     {
316       guint i;
317     case CHILD_PROP_EXPAND:
318       g_value_set_boolean (value, expand);
319       break;
320     case CHILD_PROP_FILL:
321       g_value_set_boolean (value, fill);
322       break;
323     case CHILD_PROP_PADDING:
324       g_value_set_uint (value, padding);
325       break;
326     case CHILD_PROP_PACK_TYPE:
327       g_value_set_enum (value, pack_type);
328       break;
329     case CHILD_PROP_POSITION:
330       i = 0;
331       for (list = GTK_BOX (container)->children; list; list = list->next)
332         {
333           GtkBoxChild *child_entry;
334
335           child_entry = list->data;
336           if (child_entry->widget == child)
337             break;
338           i++;
339         }
340       g_value_set_int (value, list ? i : -1);
341       break;
342     default:
343       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
344       break;
345     }
346 }
347
348 void
349 gtk_box_pack_start (GtkBox    *box,
350                     GtkWidget *child,
351                     gboolean   expand,
352                     gboolean   fill,
353                     guint      padding)
354 {
355   GtkBoxChild *child_info;
356
357   g_return_if_fail (GTK_IS_BOX (box));
358   g_return_if_fail (child != NULL);
359   g_return_if_fail (child->parent == NULL);
360
361   child_info = g_new (GtkBoxChild, 1);
362   child_info->widget = child;
363   child_info->padding = padding;
364   child_info->expand = expand ? TRUE : FALSE;
365   child_info->fill = fill ? TRUE : FALSE;
366   child_info->pack = GTK_PACK_START;
367   child_info->is_secondary = FALSE;
368
369   box->children = g_list_append (box->children, child_info);
370
371   gtk_widget_freeze_child_notify (child);
372
373   gtk_widget_set_parent (child, GTK_WIDGET (box));
374   
375   gtk_widget_child_notify (child, "expand");
376   gtk_widget_child_notify (child, "fill");
377   gtk_widget_child_notify (child, "padding");
378   gtk_widget_child_notify (child, "pack_type");
379   gtk_widget_child_notify (child, "position");
380   gtk_widget_thaw_child_notify (child);
381 }
382
383 void
384 gtk_box_pack_end (GtkBox    *box,
385                   GtkWidget *child,
386                   gboolean   expand,
387                   gboolean   fill,
388                   guint      padding)
389 {
390   GtkBoxChild *child_info;
391
392   g_return_if_fail (GTK_IS_BOX (box));
393   g_return_if_fail (child != NULL);
394   g_return_if_fail (child->parent == NULL);
395
396   child_info = g_new (GtkBoxChild, 1);
397   child_info->widget = child;
398   child_info->padding = padding;
399   child_info->expand = expand ? TRUE : FALSE;
400   child_info->fill = fill ? TRUE : FALSE;
401   child_info->pack = GTK_PACK_END;
402   child_info->is_secondary = FALSE;
403
404   box->children = g_list_append (box->children, child_info);
405
406   gtk_widget_freeze_child_notify (child);
407
408   gtk_widget_set_parent (child, GTK_WIDGET (box));
409
410   gtk_widget_child_notify (child, "expand");
411   gtk_widget_child_notify (child, "fill");
412   gtk_widget_child_notify (child, "padding");
413   gtk_widget_child_notify (child, "pack_type");
414   gtk_widget_child_notify (child, "position");
415   gtk_widget_thaw_child_notify (child);
416 }
417
418 void
419 gtk_box_pack_start_defaults (GtkBox    *box,
420                              GtkWidget *child)
421 {
422   g_return_if_fail (GTK_IS_BOX (box));
423   g_return_if_fail (child != NULL);
424
425   gtk_box_pack_start (box, child, TRUE, TRUE, 0);
426 }
427
428 void
429 gtk_box_pack_end_defaults (GtkBox    *box,
430                            GtkWidget *child)
431 {
432   g_return_if_fail (GTK_IS_BOX (box));
433   g_return_if_fail (child != NULL);
434
435   gtk_box_pack_end (box, child, TRUE, TRUE, 0);
436 }
437
438 void
439 gtk_box_set_homogeneous (GtkBox  *box,
440                          gboolean homogeneous)
441 {
442   g_return_if_fail (GTK_IS_BOX (box));
443
444   if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
445     {
446       box->homogeneous = homogeneous ? TRUE : FALSE;
447       g_object_notify (G_OBJECT (box), "homogeneous");
448       gtk_widget_queue_resize (GTK_WIDGET (box));
449     }
450 }
451
452 /**
453  * gtk_box_get_homogeneous:
454  * @box: a #GtkBox
455  *
456  * Returns whether the box is homogeneous (all children are the
457  * same size). See gtk_box_set_homogeneous ().
458  *
459  * Return value: %TRUE if the box is homogeneous.
460  **/
461 gboolean
462 gtk_box_get_homogeneous (GtkBox *box)
463 {
464   g_return_val_if_fail (GTK_IS_BOX (box), FALSE);
465
466   return box->homogeneous;
467 }
468
469 void
470 gtk_box_set_spacing (GtkBox *box,
471                      gint    spacing)
472 {
473   g_return_if_fail (GTK_IS_BOX (box));
474
475   if (spacing != box->spacing)
476     {
477       box->spacing = spacing;
478       g_object_notify (G_OBJECT (box), "spacing");
479       gtk_widget_queue_resize (GTK_WIDGET (box));
480     }
481 }
482
483 /**
484  * gtk_box_get_spacing:
485  * @box: a #GtkBox
486  * 
487  * Gets the value set by gtk_box_set_spacing().
488  * 
489  * Return value: spacing between children
490  **/
491 gint
492 gtk_box_get_spacing (GtkBox *box)
493 {
494   g_return_val_if_fail (GTK_IS_BOX (box), 0);
495
496   return box->spacing;
497 }
498
499 void
500 gtk_box_reorder_child (GtkBox    *box,
501                        GtkWidget *child,
502                        gint       position)
503 {
504   GList *list;
505
506   g_return_if_fail (GTK_IS_BOX (box));
507   g_return_if_fail (child != NULL);
508
509   list = box->children;
510   while (list)
511     {
512       GtkBoxChild *child_info;
513
514       child_info = list->data;
515       if (child_info->widget == child)
516         break;
517
518       list = list->next;
519     }
520
521   if (list && box->children->next)
522     {
523       GList *tmp_list;
524
525       if (list->next)
526         list->next->prev = list->prev;
527       if (list->prev)
528         list->prev->next = list->next;
529       else
530         box->children = list->next;
531
532       tmp_list = box->children;
533       while (position && tmp_list->next)
534         {
535           position--;
536           tmp_list = tmp_list->next;
537         }
538
539       if (position)
540         {
541           tmp_list->next = list;
542           list->prev = tmp_list;
543           list->next = NULL;
544         }
545       else
546         {
547           if (tmp_list->prev)
548             tmp_list->prev->next = list;
549           else
550             box->children = list;
551           list->prev = tmp_list->prev;
552           tmp_list->prev = list;
553           list->next = tmp_list;
554         }
555
556       gtk_widget_child_notify (child, "position");
557       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
558         gtk_widget_queue_resize (child);
559     }
560 }
561
562 void
563 gtk_box_query_child_packing (GtkBox             *box,
564                              GtkWidget          *child,
565                              gboolean           *expand,
566                              gboolean           *fill,
567                              guint              *padding,
568                              GtkPackType        *pack_type)
569 {
570   GList *list;
571   GtkBoxChild *child_info = NULL;
572
573   g_return_if_fail (GTK_IS_BOX (box));
574   g_return_if_fail (child != NULL);
575
576   list = box->children;
577   while (list)
578     {
579       child_info = list->data;
580       if (child_info->widget == child)
581         break;
582
583       list = list->next;
584     }
585
586   if (list)
587     {
588       if (expand)
589         *expand = child_info->expand;
590       if (fill)
591         *fill = child_info->fill;
592       if (padding)
593         *padding = child_info->padding;
594       if (pack_type)
595         *pack_type = child_info->pack;
596     }
597 }
598
599 void
600 gtk_box_set_child_packing (GtkBox               *box,
601                            GtkWidget            *child,
602                            gboolean              expand,
603                            gboolean              fill,
604                            guint                 padding,
605                            GtkPackType           pack_type)
606 {
607   GList *list;
608   GtkBoxChild *child_info = NULL;
609
610   g_return_if_fail (GTK_IS_BOX (box));
611   g_return_if_fail (child != NULL);
612
613   list = box->children;
614   while (list)
615     {
616       child_info = list->data;
617       if (child_info->widget == child)
618         break;
619
620       list = list->next;
621     }
622
623   gtk_widget_freeze_child_notify (child);
624   if (list)
625     {
626       child_info->expand = expand != FALSE;
627       gtk_widget_child_notify (child, "expand");
628       child_info->fill = fill != FALSE;
629       gtk_widget_child_notify (child, "fill");
630       child_info->padding = padding;
631       gtk_widget_child_notify (child, "padding");
632       if (pack_type == GTK_PACK_END)
633         child_info->pack = GTK_PACK_END;
634       else
635         child_info->pack = GTK_PACK_START;
636       gtk_widget_child_notify (child, "pack_type");
637
638       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
639         gtk_widget_queue_resize (child);
640     }
641   gtk_widget_thaw_child_notify (child);
642 }
643
644 static void
645 gtk_box_add (GtkContainer *container,
646              GtkWidget    *widget)
647 {
648   g_return_if_fail (GTK_IS_BOX (container));
649   g_return_if_fail (widget != NULL);
650
651   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
652 }
653
654 static void
655 gtk_box_remove (GtkContainer *container,
656                 GtkWidget    *widget)
657 {
658   GtkBox *box;
659   GtkBoxChild *child;
660   GList *children;
661
662   g_return_if_fail (GTK_IS_BOX (container));
663   g_return_if_fail (widget != NULL);
664
665   box = GTK_BOX (container);
666
667   children = box->children;
668   while (children)
669     {
670       child = children->data;
671
672       if (child->widget == widget)
673         {
674           gboolean was_visible;
675
676           was_visible = GTK_WIDGET_VISIBLE (widget);
677           gtk_widget_unparent (widget);
678
679           box->children = g_list_remove_link (box->children, children);
680           g_list_free (children);
681           g_free (child);
682
683           /* queue resize regardless of GTK_WIDGET_VISIBLE (container),
684            * since that's what is needed by toplevels.
685            */
686           if (was_visible)
687             gtk_widget_queue_resize (GTK_WIDGET (container));
688
689           break;
690         }
691
692       children = children->next;
693     }
694 }
695
696 static void
697 gtk_box_forall (GtkContainer *container,
698                 gboolean      include_internals,
699                 GtkCallback   callback,
700                 gpointer      callback_data)
701 {
702   GtkBox *box;
703   GtkBoxChild *child;
704   GList *children;
705
706   g_return_if_fail (GTK_IS_BOX (container));
707   g_return_if_fail (callback != NULL);
708
709   box = GTK_BOX (container);
710
711   children = box->children;
712   while (children)
713     {
714       child = children->data;
715       children = children->next;
716
717       if (child->pack == GTK_PACK_START)
718         (* callback) (child->widget, callback_data);
719     }
720
721   children = g_list_last (box->children);
722   while (children)
723     {
724       child = children->data;
725       children = children->prev;
726
727       if (child->pack == GTK_PACK_END)
728         (* callback) (child->widget, callback_data);
729     }
730 }