]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
Remove "draw" virtual method and signal
[~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
29 enum {
30   ARG_0,
31   ARG_SPACING,
32   ARG_HOMOGENEOUS
33 };
34
35 enum {
36   CHILD_ARG_0,
37   CHILD_ARG_EXPAND,
38   CHILD_ARG_FILL,
39   CHILD_ARG_PADDING,
40   CHILD_ARG_PACK_TYPE,
41   CHILD_ARG_POSITION
42 };
43
44 static void gtk_box_class_init (GtkBoxClass    *klass);
45 static void gtk_box_init       (GtkBox         *box);
46 static void gtk_box_get_arg    (GtkObject      *object,
47                                 GtkArg         *arg,
48                                 guint           arg_id);
49 static void gtk_box_set_arg    (GtkObject      *object,
50                                 GtkArg         *arg,
51                                 guint           arg_id);
52 static void gtk_box_map        (GtkWidget      *widget);
53 static void gtk_box_unmap      (GtkWidget      *widget);
54 static gint gtk_box_expose     (GtkWidget      *widget,
55                                 GdkEventExpose *event);
56 static void gtk_box_add        (GtkContainer   *container,
57                                 GtkWidget      *widget);
58 static void gtk_box_remove     (GtkContainer   *container,
59                                 GtkWidget      *widget);
60 static void gtk_box_forall     (GtkContainer   *container,
61                                 gboolean        include_internals,
62                                 GtkCallback     callback,
63                                 gpointer        callback_data);
64 static void gtk_box_set_child_arg (GtkContainer   *container,
65                                    GtkWidget      *child,
66                                    GtkArg         *arg,
67                                    guint           arg_id);
68 static void gtk_box_get_child_arg (GtkContainer   *container,
69                                    GtkWidget      *child,
70                                    GtkArg         *arg,
71                                    guint           arg_id);
72 static GtkType gtk_box_child_type (GtkContainer   *container);
73      
74
75 static GtkContainerClass *parent_class = NULL;
76
77
78 GtkType
79 gtk_box_get_type (void)
80 {
81   static GtkType box_type = 0;
82
83   if (!box_type)
84     {
85       static const GtkTypeInfo box_info =
86       {
87         "GtkBox",
88         sizeof (GtkBox),
89         sizeof (GtkBoxClass),
90         (GtkClassInitFunc) gtk_box_class_init,
91         (GtkObjectInitFunc) gtk_box_init,
92         /* reserved_1 */ NULL,
93         /* reserved_2 */ NULL,
94         (GtkClassInitFunc) NULL,
95       };
96
97       box_type = gtk_type_unique (GTK_TYPE_CONTAINER, &box_info);
98     }
99
100   return box_type;
101 }
102
103 static void
104 gtk_box_class_init (GtkBoxClass *class)
105 {
106   GtkObjectClass *object_class;
107   GtkWidgetClass *widget_class;
108   GtkContainerClass *container_class;
109
110   object_class = (GtkObjectClass*) class;
111   widget_class = (GtkWidgetClass*) class;
112   container_class = (GtkContainerClass*) class;
113
114   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
115
116   gtk_object_add_arg_type ("GtkBox::spacing", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_SPACING);
117   gtk_object_add_arg_type ("GtkBox::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
118   gtk_container_add_child_arg_type ("GtkBox::expand", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_EXPAND);
119   gtk_container_add_child_arg_type ("GtkBox::fill", GTK_TYPE_BOOL, GTK_ARG_READWRITE, CHILD_ARG_FILL);
120   gtk_container_add_child_arg_type ("GtkBox::padding", GTK_TYPE_ULONG, GTK_ARG_READWRITE, CHILD_ARG_PADDING);
121   gtk_container_add_child_arg_type ("GtkBox::pack_type", GTK_TYPE_PACK_TYPE, GTK_ARG_READWRITE, CHILD_ARG_PACK_TYPE);
122   gtk_container_add_child_arg_type ("GtkBox::position", GTK_TYPE_LONG, GTK_ARG_READWRITE, CHILD_ARG_POSITION);
123
124   object_class->set_arg = gtk_box_set_arg;
125   object_class->get_arg = gtk_box_get_arg;
126
127   widget_class->map = gtk_box_map;
128   widget_class->unmap = gtk_box_unmap;
129   widget_class->expose_event = gtk_box_expose;
130
131   container_class->add = gtk_box_add;
132   container_class->remove = gtk_box_remove;
133   container_class->forall = gtk_box_forall;
134   container_class->child_type = gtk_box_child_type;
135   container_class->set_child_arg = gtk_box_set_child_arg;
136   container_class->get_child_arg = gtk_box_get_child_arg;
137 }
138
139 static void
140 gtk_box_init (GtkBox *box)
141 {
142   GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW);
143
144   box->children = NULL;
145   box->spacing = 0;
146   box->homogeneous = FALSE;
147 }
148
149 static void
150 gtk_box_set_arg (GtkObject    *object,
151                  GtkArg       *arg,
152                  guint         arg_id)
153 {
154   GtkBox *box;
155
156   box = GTK_BOX (object);
157
158   switch (arg_id)
159     {
160     case ARG_SPACING:
161       gtk_box_set_spacing (box, GTK_VALUE_INT (*arg));
162       break;
163     case ARG_HOMOGENEOUS:
164       gtk_box_set_homogeneous (box, GTK_VALUE_BOOL (*arg));
165       break;
166     default:
167       break;
168     }
169 }
170
171 static void
172 gtk_box_get_arg (GtkObject    *object,
173                  GtkArg       *arg,
174                  guint         arg_id)
175 {
176   GtkBox *box;
177
178   box = GTK_BOX (object);
179
180   switch (arg_id)
181     {
182     case ARG_SPACING:
183       GTK_VALUE_INT (*arg) = box->spacing;
184       break;
185     case ARG_HOMOGENEOUS:
186       GTK_VALUE_BOOL (*arg) = box->homogeneous;
187       break;
188     default:
189       arg->type = GTK_TYPE_INVALID;
190       break;
191     }
192 }
193
194 static GtkType
195 gtk_box_child_type      (GtkContainer   *container)
196 {
197   return GTK_TYPE_WIDGET;
198 }
199
200 static void
201 gtk_box_set_child_arg (GtkContainer   *container,
202                        GtkWidget      *child,
203                        GtkArg         *arg,
204                        guint           arg_id)
205 {
206   gboolean expand = 0;
207   gboolean fill = 0;
208   guint padding = 0;
209   GtkPackType pack_type = 0;
210
211   if (arg_id != CHILD_ARG_POSITION)
212     gtk_box_query_child_packing (GTK_BOX (container),
213                                  child,
214                                  &expand,
215                                  &fill,
216                                  &padding,
217                                  &pack_type);
218   
219   switch (arg_id)
220     {
221     case CHILD_ARG_EXPAND:
222       gtk_box_set_child_packing (GTK_BOX (container),
223                                  child,
224                                  GTK_VALUE_BOOL (*arg),
225                                  fill,
226                                  padding,
227                                  pack_type);
228       break;
229     case CHILD_ARG_FILL:
230       gtk_box_set_child_packing (GTK_BOX (container),
231                                  child,
232                                  expand,
233                                  GTK_VALUE_BOOL (*arg),
234                                  padding,
235                                  pack_type);
236       break;
237     case CHILD_ARG_PADDING:
238       gtk_box_set_child_packing (GTK_BOX (container),
239                                  child,
240                                  expand,
241                                  fill,
242                                  GTK_VALUE_ULONG (*arg),
243                                  pack_type);
244       break;
245     case CHILD_ARG_PACK_TYPE:
246       gtk_box_set_child_packing (GTK_BOX (container),
247                                  child,
248                                  expand,
249                                  fill,
250                                  padding,
251                                  GTK_VALUE_ENUM (*arg));
252       break;
253     case CHILD_ARG_POSITION:
254       gtk_box_reorder_child (GTK_BOX (container),
255                              child,
256                              GTK_VALUE_LONG (*arg));
257       break;
258     default:
259       break;
260     }
261 }
262
263 static void
264 gtk_box_get_child_arg (GtkContainer   *container,
265                        GtkWidget      *child,
266                        GtkArg         *arg,
267                        guint           arg_id)
268 {
269   gboolean expand = 0;
270   gboolean fill = 0;
271   guint padding = 0;
272   GtkPackType pack_type = 0;
273   GList *list;
274
275   if (arg_id != CHILD_ARG_POSITION)
276     gtk_box_query_child_packing (GTK_BOX (container),
277                                  child,
278                                  &expand,
279                                  &fill,
280                                  &padding,
281                                  &pack_type);
282   
283   switch (arg_id)
284     {
285     case CHILD_ARG_EXPAND:
286       GTK_VALUE_BOOL (*arg) = expand;
287       break;
288     case CHILD_ARG_FILL:
289       GTK_VALUE_BOOL (*arg) = fill;
290       break;
291     case CHILD_ARG_PADDING:
292       GTK_VALUE_ULONG (*arg) = padding;
293       break;
294     case CHILD_ARG_PACK_TYPE:
295       GTK_VALUE_ENUM (*arg) = pack_type;
296       break;
297     case CHILD_ARG_POSITION:
298       GTK_VALUE_LONG (*arg) = 0;
299       for (list = GTK_BOX (container)->children; list; list = list->next)
300         {
301           GtkBoxChild *child_entry;
302
303           child_entry = list->data;
304           if (child_entry->widget == child)
305             break;
306           GTK_VALUE_LONG (*arg)++;
307         }
308       if (!list)
309         GTK_VALUE_LONG (*arg) = -1;
310       break;
311     default:
312       arg->type = GTK_TYPE_INVALID;
313       break;
314     }
315 }
316
317 void
318 gtk_box_pack_start (GtkBox    *box,
319                     GtkWidget *child,
320                     gboolean   expand,
321                     gboolean   fill,
322                     guint      padding)
323 {
324   GtkBoxChild *child_info;
325
326   g_return_if_fail (box != NULL);
327   g_return_if_fail (GTK_IS_BOX (box));
328   g_return_if_fail (child != NULL);
329   g_return_if_fail (child->parent == NULL);
330
331   child_info = g_new (GtkBoxChild, 1);
332   child_info->widget = child;
333   child_info->padding = padding;
334   child_info->expand = expand ? TRUE : FALSE;
335   child_info->fill = fill ? TRUE : FALSE;
336   child_info->pack = GTK_PACK_START;
337
338   box->children = g_list_append (box->children, child_info);
339
340   gtk_widget_set_parent (child, GTK_WIDGET (box));
341   
342   if (GTK_WIDGET_REALIZED (box))
343     gtk_widget_realize (child);
344
345   if (GTK_WIDGET_VISIBLE (box) && GTK_WIDGET_VISIBLE (child))
346     {
347       if (GTK_WIDGET_MAPPED (box))
348         gtk_widget_map (child);
349
350       gtk_widget_queue_resize (child);
351     }
352 }
353
354 void
355 gtk_box_pack_end (GtkBox    *box,
356                   GtkWidget *child,
357                   gboolean   expand,
358                   gboolean   fill,
359                   guint      padding)
360 {
361   GtkBoxChild *child_info;
362
363   g_return_if_fail (box != NULL);
364   g_return_if_fail (GTK_IS_BOX (box));
365   g_return_if_fail (child != NULL);
366   g_return_if_fail (child->parent == NULL);
367
368   child_info = g_new (GtkBoxChild, 1);
369   child_info->widget = child;
370   child_info->padding = padding;
371   child_info->expand = expand ? TRUE : FALSE;
372   child_info->fill = fill ? TRUE : FALSE;
373   child_info->pack = GTK_PACK_END;
374
375   box->children = g_list_append (box->children, child_info);
376
377   gtk_widget_set_parent (child, GTK_WIDGET (box));
378
379   if (GTK_WIDGET_REALIZED (box))
380     gtk_widget_realize (child);
381
382   if (GTK_WIDGET_VISIBLE (box) && GTK_WIDGET_VISIBLE (child))
383     {
384       if (GTK_WIDGET_MAPPED (box))
385         gtk_widget_map (child);
386
387       gtk_widget_queue_resize (child);
388     }
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 = NULL;
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 = NULL;
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 gint
633 gtk_box_expose (GtkWidget      *widget,
634                 GdkEventExpose *event)
635 {
636   GtkBox *box;
637   GtkBoxChild *child;
638   GdkEventExpose child_event;
639   GList *children;
640
641   g_return_val_if_fail (widget != NULL, FALSE);
642   g_return_val_if_fail (GTK_IS_BOX (widget), FALSE);
643   g_return_val_if_fail (event != NULL, FALSE);
644
645   if (GTK_WIDGET_DRAWABLE (widget))
646     {
647       box = GTK_BOX (widget);
648
649       child_event = *event;
650
651       children = box->children;
652       while (children)
653         {
654           child = children->data;
655           children = children->next;
656
657           if (GTK_WIDGET_DRAWABLE (child->widget) &&
658               GTK_WIDGET_NO_WINDOW (child->widget) &&
659               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
660             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
661         }
662     }
663
664   return FALSE;
665 }
666
667 static void
668 gtk_box_add (GtkContainer *container,
669              GtkWidget    *widget)
670 {
671   g_return_if_fail (container != NULL);
672   g_return_if_fail (GTK_IS_BOX (container));
673   g_return_if_fail (widget != NULL);
674
675   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
676 }
677
678 static void
679 gtk_box_remove (GtkContainer *container,
680                 GtkWidget    *widget)
681 {
682   GtkBox *box;
683   GtkBoxChild *child;
684   GList *children;
685
686   g_return_if_fail (container != NULL);
687   g_return_if_fail (GTK_IS_BOX (container));
688   g_return_if_fail (widget != NULL);
689
690   box = GTK_BOX (container);
691
692   children = box->children;
693   while (children)
694     {
695       child = children->data;
696
697       if (child->widget == widget)
698         {
699           gboolean was_visible;
700
701           was_visible = GTK_WIDGET_VISIBLE (widget);
702           gtk_widget_unparent (widget);
703
704           box->children = g_list_remove_link (box->children, children);
705           g_list_free (children);
706           g_free (child);
707
708           /* queue resize regardless of GTK_WIDGET_VISIBLE (container),
709            * since that's what is needed by toplevels.
710            */
711           if (was_visible)
712             gtk_widget_queue_resize (GTK_WIDGET (container));
713
714           break;
715         }
716
717       children = children->next;
718     }
719 }
720
721 static void
722 gtk_box_forall (GtkContainer *container,
723                 gboolean      include_internals,
724                 GtkCallback   callback,
725                 gpointer      callback_data)
726 {
727   GtkBox *box;
728   GtkBoxChild *child;
729   GList *children;
730
731   g_return_if_fail (container != NULL);
732   g_return_if_fail (GTK_IS_BOX (container));
733   g_return_if_fail (callback != NULL);
734
735   box = GTK_BOX (container);
736
737   children = box->children;
738   while (children)
739     {
740       child = children->data;
741       children = children->next;
742
743       if (child->pack == GTK_PACK_START)
744         (* callback) (child->widget, callback_data);
745     }
746
747   children = g_list_last (box->children);
748   while (children)
749     {
750       child = children->data;
751       children = children->prev;
752
753       if (child->pack == GTK_PACK_END)
754         (* callback) (child->widget, callback_data);
755     }
756 }