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