]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
call the base class init fucntions from all parent types upon 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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include "gtkbox.h"
20
21 enum {
22   ARG_0,
23   ARG_SPACING,
24   ARG_HOMOGENEOUS
25 };
26
27 enum {
28   CHILD_ARG_0,
29   CHILD_ARG_EXPAND,
30   CHILD_ARG_FILL,
31   CHILD_ARG_PADDING,
32   CHILD_ARG_PACK_TYPE,
33   CHILD_ARG_POSITION
34 };
35
36 static void gtk_box_class_init (GtkBoxClass    *klass);
37 static void gtk_box_init       (GtkBox         *box);
38 static void gtk_box_get_arg    (GtkObject      *object,
39                                 GtkArg         *arg,
40                                 guint           arg_id);
41 static void gtk_box_set_arg    (GtkObject      *object,
42                                 GtkArg         *arg,
43                                 guint           arg_id);
44 static void gtk_box_map        (GtkWidget      *widget);
45 static void gtk_box_unmap      (GtkWidget      *widget);
46 static void gtk_box_draw       (GtkWidget      *widget,
47                                 GdkRectangle   *area);
48 static gint gtk_box_expose     (GtkWidget      *widget,
49                                 GdkEventExpose *event);
50 static void gtk_box_add        (GtkContainer   *container,
51                                 GtkWidget      *widget);
52 static void gtk_box_remove     (GtkContainer   *container,
53                                 GtkWidget      *widget);
54 static void gtk_box_foreach    (GtkContainer   *container,
55                                 GtkCallback     callback,
56                                 gpointer        callback_data);
57 static void gtk_box_set_child_arg (GtkContainer   *container,
58                                    GtkWidget      *child,
59                                    GtkArg         *arg,
60                                    guint           arg_id);
61 static void gtk_box_get_child_arg (GtkContainer   *container,
62                                    GtkWidget      *child,
63                                    GtkArg         *arg,
64                                    guint           arg_id);
65 static GtkType gtk_box_child_type (GtkContainer   *container);
66      
67
68 static GtkContainerClass *parent_class = NULL;
69
70
71 GtkType
72 gtk_box_get_type (void)
73 {
74   static GtkType box_type = 0;
75
76   if (!box_type)
77     {
78       GtkTypeInfo box_info =
79       {
80         "GtkBox",
81         sizeof (GtkBox),
82         sizeof (GtkBoxClass),
83         (GtkClassInitFunc) gtk_box_class_init,
84         (GtkObjectInitFunc) gtk_box_init,
85         /* reversed_1 */ NULL,
86         /* reversed_2 */ NULL,
87         (GtkClassInitFunc) NULL,
88       };
89
90       box_type = gtk_type_unique (GTK_TYPE_CONTAINER, &box_info);
91     }
92
93   return box_type;
94 }
95
96 static void
97 gtk_box_class_init (GtkBoxClass *class)
98 {
99   GtkObjectClass *object_class;
100   GtkWidgetClass *widget_class;
101   GtkContainerClass *container_class;
102
103   object_class = (GtkObjectClass*) class;
104   widget_class = (GtkWidgetClass*) class;
105   container_class = (GtkContainerClass*) class;
106
107   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
108
109   gtk_object_add_arg_type ("GtkBox::spacing", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_SPACING);
110   gtk_object_add_arg_type ("GtkBox::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
111   gtk_container_add_child_arg_type ("GtkBox::expand", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_EXPAND);
112   gtk_container_add_child_arg_type ("GtkBox::fill", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL);
113   gtk_container_add_child_arg_type ("GtkBox::padding", GTK_TYPE_ULONG, GTK_ARG_READWRITE, CHILD_ARG_PADDING);
114   gtk_container_add_child_arg_type ("GtkBox::pack_type", GTK_TYPE_PACK_TYPE, GTK_ARG_READWRITE, CHILD_ARG_PACK_TYPE);
115   gtk_container_add_child_arg_type ("GtkBox::position", GTK_TYPE_LONG, GTK_ARG_READWRITE, CHILD_ARG_POSITION);
116
117   object_class->set_arg = gtk_box_set_arg;
118   object_class->get_arg = gtk_box_get_arg;
119
120   widget_class->map = gtk_box_map;
121   widget_class->unmap = gtk_box_unmap;
122   widget_class->draw = gtk_box_draw;
123   widget_class->expose_event = gtk_box_expose;
124
125   container_class->add = gtk_box_add;
126   container_class->remove = gtk_box_remove;
127   container_class->foreach = gtk_box_foreach;
128   container_class->child_type = gtk_box_child_type;
129   container_class->set_child_arg = gtk_box_set_child_arg;
130   container_class->get_child_arg = gtk_box_get_child_arg;
131 }
132
133 static void
134 gtk_box_init (GtkBox *box)
135 {
136   GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW | GTK_BASIC);
137
138   box->children = NULL;
139   box->spacing = 0;
140   box->homogeneous = FALSE;
141 }
142
143 static void
144 gtk_box_set_arg (GtkObject    *object,
145                  GtkArg       *arg,
146                  guint         arg_id)
147 {
148   GtkBox *box;
149
150   box = GTK_BOX (object);
151
152   switch (arg_id)
153     {
154     case ARG_SPACING:
155       gtk_box_set_spacing (box, GTK_VALUE_INT (*arg));
156       break;
157     case ARG_HOMOGENEOUS:
158       gtk_box_set_homogeneous (box, GTK_VALUE_BOOL (*arg));
159       break;
160     default:
161       break;
162     }
163 }
164
165 static void
166 gtk_box_get_arg (GtkObject    *object,
167                  GtkArg       *arg,
168                  guint         arg_id)
169 {
170   GtkBox *box;
171
172   box = GTK_BOX (object);
173
174   switch (arg_id)
175     {
176     case ARG_SPACING:
177       GTK_VALUE_INT (*arg) = box->spacing;
178       break;
179     case ARG_HOMOGENEOUS:
180       GTK_VALUE_BOOL (*arg) = box->homogeneous;
181       break;
182     default:
183       arg->type = GTK_TYPE_INVALID;
184       break;
185     }
186 }
187
188 static GtkType
189 gtk_box_child_type      (GtkContainer   *container)
190 {
191   return GTK_TYPE_WIDGET;
192 }
193
194 static void
195 gtk_box_set_child_arg (GtkContainer   *container,
196                        GtkWidget      *child,
197                        GtkArg         *arg,
198                        guint           arg_id)
199 {
200   gboolean expand = 0;
201   gboolean fill = 0;
202   guint padding = 0;
203   GtkPackType pack_type = 0;
204
205   if (arg_id != CHILD_ARG_POSITION)
206     gtk_box_query_child_packing (GTK_BOX (container),
207                                  child,
208                                  &expand,
209                                  &fill,
210                                  &padding,
211                                  &pack_type);
212   
213   switch (arg_id)
214     {
215     case CHILD_ARG_EXPAND:
216       gtk_box_set_child_packing (GTK_BOX (container),
217                                  child,
218                                  GTK_VALUE_BOOL (*arg),
219                                  fill,
220                                  padding,
221                                  pack_type);
222       break;
223     case CHILD_ARG_FILL:
224       gtk_box_set_child_packing (GTK_BOX (container),
225                                  child,
226                                  expand,
227                                  GTK_VALUE_BOOL (*arg),
228                                  padding,
229                                  pack_type);
230       break;
231     case CHILD_ARG_PADDING:
232       gtk_box_set_child_packing (GTK_BOX (container),
233                                  child,
234                                  expand,
235                                  fill,
236                                  GTK_VALUE_ULONG (*arg),
237                                  pack_type);
238       break;
239     case CHILD_ARG_PACK_TYPE:
240       gtk_box_set_child_packing (GTK_BOX (container),
241                                  child,
242                                  expand,
243                                  fill,
244                                  padding,
245                                  GTK_VALUE_ENUM (*arg));
246       break;
247     case CHILD_ARG_POSITION:
248       gtk_box_reorder_child (GTK_BOX (container),
249                              child,
250                              GTK_VALUE_LONG (*arg));
251       break;
252     default:
253       break;
254     }
255 }
256
257 static void
258 gtk_box_get_child_arg (GtkContainer   *container,
259                        GtkWidget      *child,
260                        GtkArg         *arg,
261                        guint           arg_id)
262 {
263   gboolean expand = 0;
264   gboolean fill = 0;
265   guint padding = 0;
266   GtkPackType pack_type = 0;
267   GList *list;
268
269   if (arg_id != CHILD_ARG_POSITION)
270     gtk_box_query_child_packing (GTK_BOX (container),
271                                  child,
272                                  &expand,
273                                  &fill,
274                                  &padding,
275                                  &pack_type);
276   
277   switch (arg_id)
278     {
279     case CHILD_ARG_EXPAND:
280       GTK_VALUE_BOOL (*arg) = expand;
281       break;
282     case CHILD_ARG_FILL:
283       GTK_VALUE_BOOL (*arg) = fill;
284       break;
285     case CHILD_ARG_PADDING:
286       GTK_VALUE_ULONG (*arg) = padding;
287       break;
288     case CHILD_ARG_PACK_TYPE:
289       GTK_VALUE_ENUM (*arg) = pack_type;
290       break;
291     case CHILD_ARG_POSITION:
292       GTK_VALUE_LONG (*arg) = 0;
293       for (list = GTK_BOX (container)->children; list; list = list->next)
294         {
295           GtkBoxChild *child_entry;
296
297           child_entry = list->data;
298           if (child_entry->widget == child)
299             break;
300           GTK_VALUE_LONG (*arg)++;
301         }
302       if (!list)
303         GTK_VALUE_LONG (*arg) = -1;
304       break;
305     default:
306       arg->type = GTK_TYPE_INVALID;
307       break;
308     }
309 }
310
311 void
312 gtk_box_pack_start (GtkBox    *box,
313                     GtkWidget *child,
314                     gboolean   expand,
315                     gboolean   fill,
316                     guint      padding)
317 {
318   GtkBoxChild *child_info;
319
320   g_return_if_fail (box != NULL);
321   g_return_if_fail (GTK_IS_BOX (box));
322   g_return_if_fail (child != NULL);
323   g_return_if_fail (child->parent == NULL);
324
325   child_info = g_new (GtkBoxChild, 1);
326   child_info->widget = child;
327   child_info->padding = padding;
328   child_info->expand = expand ? TRUE : FALSE;
329   child_info->fill = fill ? TRUE : FALSE;
330   child_info->pack = GTK_PACK_START;
331
332   box->children = g_list_append (box->children, child_info);
333
334   gtk_widget_set_parent (child, GTK_WIDGET (box));
335
336   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box)))
337     {
338       if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) &&
339           !GTK_WIDGET_REALIZED (child))
340         gtk_widget_realize (child);
341       
342       if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) &&
343           !GTK_WIDGET_MAPPED (child))
344         gtk_widget_map (child);
345     }
346
347   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
348     gtk_widget_queue_resize (child);
349 }
350
351 void
352 gtk_box_pack_end (GtkBox    *box,
353                   GtkWidget *child,
354                   gboolean   expand,
355                   gboolean   fill,
356                   guint      padding)
357 {
358   GtkBoxChild *child_info;
359
360   g_return_if_fail (box != NULL);
361   g_return_if_fail (GTK_IS_BOX (box));
362   g_return_if_fail (child != NULL);
363   g_return_if_fail (child->parent == NULL);
364
365   child_info = g_new (GtkBoxChild, 1);
366   child_info->widget = child;
367   child_info->padding = padding;
368   child_info->expand = expand ? TRUE : FALSE;
369   child_info->fill = fill ? TRUE : FALSE;
370   child_info->pack = GTK_PACK_END;
371
372   box->children = g_list_append (box->children, child_info);
373
374   gtk_widget_set_parent (child, GTK_WIDGET (box));
375
376   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box)))
377     {
378       if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) &&
379           !GTK_WIDGET_REALIZED (child))
380         gtk_widget_realize (child);
381       
382       if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) &&
383           !GTK_WIDGET_MAPPED (child))
384         gtk_widget_map (child);
385     }
386   
387   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
388     gtk_widget_queue_resize (child);
389 }
390
391 void
392 gtk_box_pack_start_defaults (GtkBox    *box,
393                              GtkWidget *child)
394 {
395   g_return_if_fail (box != NULL);
396   g_return_if_fail (GTK_IS_BOX (box));
397   g_return_if_fail (child != NULL);
398
399   gtk_box_pack_start (box, child, TRUE, TRUE, 0);
400 }
401
402 void
403 gtk_box_pack_end_defaults (GtkBox    *box,
404                            GtkWidget *child)
405 {
406   g_return_if_fail (box != NULL);
407   g_return_if_fail (GTK_IS_BOX (box));
408   g_return_if_fail (child != NULL);
409
410   gtk_box_pack_end (box, child, TRUE, TRUE, 0);
411 }
412
413 void
414 gtk_box_set_homogeneous (GtkBox  *box,
415                          gboolean homogeneous)
416 {
417   g_return_if_fail (box != NULL);
418   g_return_if_fail (GTK_IS_BOX (box));
419
420   if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
421     {
422       box->homogeneous = homogeneous ? TRUE : FALSE;
423       gtk_widget_queue_resize (GTK_WIDGET (box));
424     }
425 }
426
427 void
428 gtk_box_set_spacing (GtkBox *box,
429                      gint    spacing)
430 {
431   g_return_if_fail (box != NULL);
432   g_return_if_fail (GTK_IS_BOX (box));
433
434   if (spacing != box->spacing)
435     {
436       box->spacing = spacing;
437       gtk_widget_queue_resize (GTK_WIDGET (box));
438     }
439 }
440
441 void
442 gtk_box_reorder_child (GtkBox                   *box,
443                        GtkWidget                *child,
444                        gint                      position)
445 {
446   GList *list;
447
448   g_return_if_fail (box != NULL);
449   g_return_if_fail (GTK_IS_BOX (box));
450   g_return_if_fail (child != NULL);
451
452   list = box->children;
453   while (list)
454     {
455       GtkBoxChild *child_info;
456
457       child_info = list->data;
458       if (child_info->widget == child)
459         break;
460
461       list = list->next;
462     }
463
464   if (list && box->children->next)
465     {
466       GList *tmp_list;
467
468       if (list->next)
469         list->next->prev = list->prev;
470       if (list->prev)
471         list->prev->next = list->next;
472       else
473         box->children = list->next;
474
475       tmp_list = box->children;
476       while (position && tmp_list->next)
477         {
478           position--;
479           tmp_list = tmp_list->next;
480         }
481
482       if (position)
483         {
484           tmp_list->next = list;
485           list->prev = tmp_list;
486           list->next = NULL;
487         }
488       else
489         {
490           if (tmp_list->prev)
491             tmp_list->prev->next = list;
492           else
493             box->children = list;
494           list->prev = tmp_list->prev;
495           tmp_list->prev = list;
496           list->next = tmp_list;
497         }
498
499       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
500         gtk_widget_queue_resize (child);
501     }
502 }
503
504 void
505 gtk_box_query_child_packing (GtkBox             *box,
506                              GtkWidget          *child,
507                              gboolean           *expand,
508                              gboolean           *fill,
509                              guint              *padding,
510                              GtkPackType        *pack_type)
511 {
512   GList *list;
513   GtkBoxChild *child_info;
514
515   g_return_if_fail (box != NULL);
516   g_return_if_fail (GTK_IS_BOX (box));
517   g_return_if_fail (child != NULL);
518
519   list = box->children;
520   while (list)
521     {
522       child_info = list->data;
523       if (child_info->widget == child)
524         break;
525
526       list = list->next;
527     }
528
529   if (list)
530     {
531       if (expand)
532         *expand = child_info->expand;
533       if (fill)
534         *fill = child_info->fill;
535       if (padding)
536         *padding = child_info->padding;
537       if (pack_type)
538         *pack_type = child_info->pack;
539     }
540 }
541
542 void
543 gtk_box_set_child_packing (GtkBox               *box,
544                            GtkWidget            *child,
545                            gboolean              expand,
546                            gboolean              fill,
547                            guint                 padding,
548                            GtkPackType           pack_type)
549 {
550   GList *list;
551   GtkBoxChild *child_info;
552
553   g_return_if_fail (box != NULL);
554   g_return_if_fail (GTK_IS_BOX (box));
555   g_return_if_fail (child != NULL);
556
557   list = box->children;
558   while (list)
559     {
560       child_info = list->data;
561       if (child_info->widget == child)
562         break;
563
564       list = list->next;
565     }
566
567   if (list)
568     {
569       child_info->expand = expand != FALSE;
570       child_info->fill = fill != FALSE;
571       child_info->padding = padding;
572       if (pack_type == GTK_PACK_END)
573         child_info->pack = GTK_PACK_END;
574       else
575         child_info->pack = GTK_PACK_START;
576
577       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
578         gtk_widget_queue_resize (child);
579     }
580 }
581
582 static void
583 gtk_box_map (GtkWidget *widget)
584 {
585   GtkBox *box;
586   GtkBoxChild *child;
587   GList *children;
588
589   g_return_if_fail (widget != NULL);
590   g_return_if_fail (GTK_IS_BOX (widget));
591
592   box = GTK_BOX (widget);
593   GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED);
594
595   children = box->children;
596   while (children)
597     {
598       child = children->data;
599       children = children->next;
600
601       if (GTK_WIDGET_VISIBLE (child->widget) &&
602           !GTK_WIDGET_MAPPED (child->widget))
603         gtk_widget_map (child->widget);
604     }
605 }
606
607 static void
608 gtk_box_unmap (GtkWidget *widget)
609 {
610   GtkBox *box;
611   GtkBoxChild *child;
612   GList *children;
613
614   g_return_if_fail (widget != NULL);
615   g_return_if_fail (GTK_IS_BOX (widget));
616
617   box = GTK_BOX (widget);
618   GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED);
619
620   children = box->children;
621   while (children)
622     {
623       child = children->data;
624       children = children->next;
625
626       if (GTK_WIDGET_VISIBLE (child->widget) &&
627           GTK_WIDGET_MAPPED (child->widget))
628         gtk_widget_unmap (child->widget);
629     }
630 }
631
632 static void
633 gtk_box_draw (GtkWidget    *widget,
634               GdkRectangle *area)
635 {
636   GtkBox *box;
637   GtkBoxChild *child;
638   GdkRectangle child_area;
639   GList *children;
640
641   g_return_if_fail (widget != NULL);
642   g_return_if_fail (GTK_IS_BOX (widget));
643
644   if (GTK_WIDGET_DRAWABLE (widget))
645     {
646       box = GTK_BOX (widget);
647
648       children = box->children;
649       while (children)
650         {
651           child = children->data;
652           children = children->next;
653
654           if (gtk_widget_intersect (child->widget, area, &child_area))
655             gtk_widget_draw (child->widget, &child_area);
656         }
657     }
658 }
659
660 static gint
661 gtk_box_expose (GtkWidget      *widget,
662                 GdkEventExpose *event)
663 {
664   GtkBox *box;
665   GtkBoxChild *child;
666   GdkEventExpose child_event;
667   GList *children;
668
669   g_return_val_if_fail (widget != NULL, FALSE);
670   g_return_val_if_fail (GTK_IS_BOX (widget), FALSE);
671   g_return_val_if_fail (event != NULL, FALSE);
672
673   if (GTK_WIDGET_DRAWABLE (widget))
674     {
675       box = GTK_BOX (widget);
676
677       child_event = *event;
678
679       children = box->children;
680       while (children)
681         {
682           child = children->data;
683           children = children->next;
684
685           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
686               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
687             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
688         }
689     }
690
691   return FALSE;
692 }
693
694 static void
695 gtk_box_add (GtkContainer *container,
696              GtkWidget    *widget)
697 {
698   g_return_if_fail (container != NULL);
699   g_return_if_fail (GTK_IS_BOX (container));
700   g_return_if_fail (widget != NULL);
701
702   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
703 }
704
705 static void
706 gtk_box_remove (GtkContainer *container,
707                 GtkWidget    *widget)
708 {
709   GtkBox *box;
710   GtkBoxChild *child;
711   GList *children;
712
713   g_return_if_fail (container != NULL);
714   g_return_if_fail (GTK_IS_BOX (container));
715   g_return_if_fail (widget != NULL);
716
717   box = GTK_BOX (container);
718
719   children = box->children;
720   while (children)
721     {
722       child = children->data;
723
724       if (child->widget == widget)
725         {
726           gboolean was_visible;
727
728           was_visible = GTK_WIDGET_VISIBLE (widget);
729           gtk_widget_unparent (widget);
730
731           box->children = g_list_remove_link (box->children, children);
732           g_list_free (children);
733           g_free (child);
734
735           /* queue resize regardless of GTK_WIDGET_VISIBLE (container),
736            * since that's what is needed by toplevels.
737            */
738           if (was_visible)
739             gtk_widget_queue_resize (GTK_WIDGET (container));
740
741           break;
742         }
743
744       children = children->next;
745     }
746 }
747
748 static void
749 gtk_box_foreach (GtkContainer *container,
750                  GtkCallback   callback,
751                  gpointer      callback_data)
752 {
753   GtkBox *box;
754   GtkBoxChild *child;
755   GList *children;
756
757   g_return_if_fail (container != NULL);
758   g_return_if_fail (GTK_IS_BOX (container));
759   g_return_if_fail (callback != NULL);
760
761   box = GTK_BOX (container);
762
763   children = box->children;
764   while (children)
765     {
766       child = children->data;
767       children = children->next;
768
769       if (child->pack == GTK_PACK_START)
770         (* callback) (child->widget, callback_data);
771     }
772
773   children = g_list_last (box->children);
774   while (children)
775     {
776       child = children->data;
777       children = children->prev;
778
779       if (child->pack == GTK_PACK_END)
780         (* callback) (child->widget, callback_data);
781     }
782 }