]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
Merged changes from gtk-1-0. Check ChangeLog for details.
[~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 static void gtk_box_class_init (GtkBoxClass    *klass);
28 static void gtk_box_init       (GtkBox         *box);
29 static void gtk_box_get_arg    (GtkBox         *box,
30                                 GtkArg         *arg,
31                                 guint           arg_id);
32 static void gtk_box_set_arg    (GtkBox         *box,
33                                 GtkArg         *arg,
34                                 guint           arg_id);
35 static void gtk_box_map        (GtkWidget      *widget);
36 static void gtk_box_unmap      (GtkWidget      *widget);
37 static void gtk_box_draw       (GtkWidget      *widget,
38                                 GdkRectangle   *area);
39 static gint gtk_box_expose     (GtkWidget      *widget,
40                                 GdkEventExpose *event);
41 static void gtk_box_add        (GtkContainer   *container,
42                                 GtkWidget      *widget);
43 static void gtk_box_remove     (GtkContainer   *container,
44                                 GtkWidget      *widget);
45 static void gtk_box_foreach    (GtkContainer   *container,
46                                 GtkCallback     callback,
47                                 gpointer        callback_data);
48
49
50 static GtkContainerClass *parent_class = NULL;
51
52
53 guint
54 gtk_box_get_type ()
55 {
56   static guint box_type = 0;
57
58   if (!box_type)
59     {
60       GtkTypeInfo box_info =
61       {
62         "GtkBox",
63         sizeof (GtkBox),
64         sizeof (GtkBoxClass),
65         (GtkClassInitFunc) gtk_box_class_init,
66         (GtkObjectInitFunc) gtk_box_init,
67         (GtkArgSetFunc) gtk_box_set_arg,
68         (GtkArgGetFunc) gtk_box_get_arg,
69       };
70
71       box_type = gtk_type_unique (gtk_container_get_type (), &box_info);
72     }
73
74   return box_type;
75 }
76
77 static void
78 gtk_box_class_init (GtkBoxClass *class)
79 {
80   GtkObjectClass *object_class;
81   GtkWidgetClass *widget_class;
82   GtkContainerClass *container_class;
83
84   object_class = (GtkObjectClass*) class;
85   widget_class = (GtkWidgetClass*) class;
86   container_class = (GtkContainerClass*) class;
87
88   parent_class = gtk_type_class (gtk_container_get_type ());
89
90   gtk_object_add_arg_type ("GtkBox::spacing", GTK_TYPE_INT, GTK_ARG_READWRITE, ARG_SPACING);
91   gtk_object_add_arg_type ("GtkBox::homogeneous", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_HOMOGENEOUS);
92
93   widget_class->map = gtk_box_map;
94   widget_class->unmap = gtk_box_unmap;
95   widget_class->draw = gtk_box_draw;
96   widget_class->expose_event = gtk_box_expose;
97
98   container_class->add = gtk_box_add;
99   container_class->remove = gtk_box_remove;
100   container_class->foreach = gtk_box_foreach;
101 }
102
103 static void
104 gtk_box_init (GtkBox *box)
105 {
106   GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW | GTK_BASIC);
107
108   box->children = NULL;
109   box->spacing = 0;
110   box->homogeneous = FALSE;
111 }
112
113 static void
114 gtk_box_set_arg (GtkBox       *box,
115                  GtkArg       *arg,
116                  guint         arg_id)
117 {
118   switch (arg_id)
119     {
120     case ARG_SPACING:
121       gtk_box_set_spacing (box, GTK_VALUE_INT (*arg));
122       break;
123     case ARG_HOMOGENEOUS:
124       gtk_box_set_homogeneous (box, GTK_VALUE_BOOL (*arg));
125       break;
126     default:
127       arg->type = GTK_TYPE_INVALID;
128       break;
129     }
130 }
131
132 static void
133 gtk_box_get_arg (GtkBox       *box,
134                  GtkArg       *arg,
135                  guint         arg_id)
136 {
137   switch (arg_id)
138     {
139     case ARG_SPACING:
140       GTK_VALUE_INT (*arg) = box->spacing;
141       break;
142     case ARG_HOMOGENEOUS:
143       GTK_VALUE_BOOL (*arg) = box->homogeneous;
144       break;
145     default:
146       arg->type = GTK_TYPE_INVALID;
147       break;
148     }
149 }
150
151 void
152 gtk_box_pack_start (GtkBox    *box,
153                     GtkWidget *child,
154                     gint       expand,
155                     gint       fill,
156                     gint       padding)
157 {
158   GtkBoxChild *child_info;
159
160   g_return_if_fail (box != NULL);
161   g_return_if_fail (GTK_IS_BOX (box));
162   g_return_if_fail (child != NULL);
163   g_return_if_fail (child->parent == NULL);
164
165   child_info = g_new (GtkBoxChild, 1);
166   child_info->widget = child;
167   child_info->padding = padding;
168   child_info->expand = expand ? TRUE : FALSE;
169   child_info->fill = fill ? TRUE : FALSE;
170   child_info->pack = GTK_PACK_START;
171
172   box->children = g_list_append (box->children, child_info);
173
174   gtk_widget_set_parent (child, GTK_WIDGET (box));
175
176   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box)))
177     {
178       if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) &&
179           !GTK_WIDGET_REALIZED (child))
180         gtk_widget_realize (child);
181       
182       if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) &&
183           !GTK_WIDGET_MAPPED (child))
184         gtk_widget_map (child);
185     }
186
187   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
188     gtk_widget_queue_resize (child);
189 }
190
191 void
192 gtk_box_pack_end (GtkBox    *box,
193                   GtkWidget *child,
194                   gint       expand,
195                   gint       fill,
196                   gint       padding)
197 {
198   GtkBoxChild *child_info;
199
200   g_return_if_fail (box != NULL);
201   g_return_if_fail (GTK_IS_BOX (box));
202   g_return_if_fail (child != NULL);
203   g_return_if_fail (child->parent == NULL);
204
205   child_info = g_new (GtkBoxChild, 1);
206   child_info->widget = child;
207   child_info->padding = padding;
208   child_info->expand = expand ? TRUE : FALSE;
209   child_info->fill = fill ? TRUE : FALSE;
210   child_info->pack = GTK_PACK_END;
211
212   box->children = g_list_append (box->children, child_info);
213
214   gtk_widget_set_parent (child, GTK_WIDGET (box));
215
216   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box)))
217     {
218       if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) &&
219           !GTK_WIDGET_REALIZED (child))
220         gtk_widget_realize (child);
221       
222       if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) &&
223           !GTK_WIDGET_MAPPED (child))
224         gtk_widget_map (child);
225     }
226   
227   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
228     gtk_widget_queue_resize (child);
229 }
230
231 void
232 gtk_box_pack_start_defaults (GtkBox    *box,
233                              GtkWidget *child)
234 {
235   g_return_if_fail (box != NULL);
236   g_return_if_fail (GTK_IS_BOX (box));
237   g_return_if_fail (child != NULL);
238
239   gtk_box_pack_start (box, child, TRUE, TRUE, 0);
240 }
241
242 void
243 gtk_box_pack_end_defaults (GtkBox    *box,
244                            GtkWidget *child)
245 {
246   g_return_if_fail (box != NULL);
247   g_return_if_fail (GTK_IS_BOX (box));
248   g_return_if_fail (child != NULL);
249
250   gtk_box_pack_end (box, child, TRUE, TRUE, 0);
251 }
252
253 void
254 gtk_box_set_homogeneous (GtkBox *box,
255                          gint    homogeneous)
256 {
257   g_return_if_fail (box != NULL);
258   g_return_if_fail (GTK_IS_BOX (box));
259
260   if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
261     {
262       box->homogeneous = homogeneous ? TRUE : FALSE;
263       gtk_widget_queue_resize (GTK_WIDGET (box));
264     }
265 }
266
267 void
268 gtk_box_set_spacing (GtkBox *box,
269                      gint    spacing)
270 {
271   g_return_if_fail (box != NULL);
272   g_return_if_fail (GTK_IS_BOX (box));
273
274   if (spacing != box->spacing)
275     {
276       box->spacing = spacing;
277       gtk_widget_queue_resize (GTK_WIDGET (box));
278     }
279 }
280
281 void
282 gtk_box_reorder_child (GtkBox                   *box,
283                        GtkWidget                *child,
284                        guint                    pos)
285 {
286   GList *list;
287
288   g_return_if_fail (box != NULL);
289   g_return_if_fail (GTK_IS_BOX (box));
290   g_return_if_fail (child != NULL);
291
292   list = box->children;
293   while (list)
294     {
295       GtkBoxChild *child_info;
296
297       child_info = list->data;
298       if (child_info->widget == child)
299         break;
300
301       list = list->next;
302     }
303
304   if (list && box->children->next)
305     {
306       GList *tmp_list;
307
308       if (list->next)
309         list->next->prev = list->prev;
310       if (list->prev)
311         list->prev->next = list->next;
312       else
313         box->children = list->next;
314
315       tmp_list = box->children;
316       while (pos && tmp_list->next)
317         {
318           pos--;
319           tmp_list = tmp_list->next;
320         }
321
322       if (pos)
323         {
324           tmp_list->next = list;
325           list->prev = tmp_list;
326           list->next = NULL;
327         }
328       else
329         {
330           if (tmp_list->prev)
331             tmp_list->prev->next = list;
332           else
333             box->children = list;
334           list->prev = tmp_list->prev;
335           tmp_list->prev = list;
336           list->next = tmp_list;
337         }
338
339       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
340         gtk_widget_queue_resize (child);
341     }
342 }
343
344 void
345 gtk_box_query_child_packing (GtkBox             *box,
346                              GtkWidget          *child,
347                              gint               *expand,
348                              gint               *fill,
349                              gint               *padding,
350                              GtkPackType        *pack_type)
351 {
352   GList *list;
353   GtkBoxChild *child_info;
354
355   g_return_if_fail (box != NULL);
356   g_return_if_fail (GTK_IS_BOX (box));
357   g_return_if_fail (child != NULL);
358
359   list = box->children;
360   while (list)
361     {
362       child_info = list->data;
363       if (child_info->widget == child)
364         break;
365
366       list = list->next;
367     }
368
369   if (list)
370     {
371       if (expand)
372         *expand = child_info->expand;
373       if (fill)
374         *fill = child_info->fill;
375       if (padding)
376         *padding = child_info->padding;
377       if (pack_type)
378         *pack_type = child_info->pack;
379     }
380 }
381
382 void
383 gtk_box_set_child_packing (GtkBox               *box,
384                            GtkWidget            *child,
385                            gint                 expand,
386                            gint                 fill,
387                            gint                 padding,
388                            GtkPackType          pack_type)
389 {
390   GList *list;
391   GtkBoxChild *child_info;
392
393   g_return_if_fail (box != NULL);
394   g_return_if_fail (GTK_IS_BOX (box));
395   g_return_if_fail (child != NULL);
396
397   list = box->children;
398   while (list)
399     {
400       child_info = list->data;
401       if (child_info->widget == child)
402         break;
403
404       list = list->next;
405     }
406
407   if (list)
408     {
409       child_info->expand = expand != FALSE;
410       child_info->fill = fill != FALSE;
411       child_info->padding = padding;
412       if (pack_type == GTK_PACK_END)
413         child_info->pack = GTK_PACK_END;
414       else
415         child_info->pack = GTK_PACK_START;
416
417       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
418         gtk_widget_queue_resize (child);
419     }
420 }
421
422 static void
423 gtk_box_map (GtkWidget *widget)
424 {
425   GtkBox *box;
426   GtkBoxChild *child;
427   GList *children;
428
429   g_return_if_fail (widget != NULL);
430   g_return_if_fail (GTK_IS_BOX (widget));
431
432   box = GTK_BOX (widget);
433   GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED);
434
435   children = box->children;
436   while (children)
437     {
438       child = children->data;
439       children = children->next;
440
441       if (GTK_WIDGET_VISIBLE (child->widget) &&
442           !GTK_WIDGET_MAPPED (child->widget))
443         gtk_widget_map (child->widget);
444     }
445 }
446
447 static void
448 gtk_box_unmap (GtkWidget *widget)
449 {
450   GtkBox *box;
451   GtkBoxChild *child;
452   GList *children;
453
454   g_return_if_fail (widget != NULL);
455   g_return_if_fail (GTK_IS_BOX (widget));
456
457   box = GTK_BOX (widget);
458   GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED);
459
460   children = box->children;
461   while (children)
462     {
463       child = children->data;
464       children = children->next;
465
466       if (GTK_WIDGET_VISIBLE (child->widget) &&
467           GTK_WIDGET_MAPPED (child->widget))
468         gtk_widget_unmap (child->widget);
469     }
470 }
471
472 static void
473 gtk_box_draw (GtkWidget    *widget,
474               GdkRectangle *area)
475 {
476   GtkBox *box;
477   GtkBoxChild *child;
478   GdkRectangle child_area;
479   GList *children;
480
481   g_return_if_fail (widget != NULL);
482   g_return_if_fail (GTK_IS_BOX (widget));
483
484   if (GTK_WIDGET_DRAWABLE (widget))
485     {
486       box = GTK_BOX (widget);
487
488       children = box->children;
489       while (children)
490         {
491           child = children->data;
492           children = children->next;
493
494           if (gtk_widget_intersect (child->widget, area, &child_area))
495             gtk_widget_draw (child->widget, &child_area);
496         }
497     }
498 }
499
500 static gint
501 gtk_box_expose (GtkWidget      *widget,
502                 GdkEventExpose *event)
503 {
504   GtkBox *box;
505   GtkBoxChild *child;
506   GdkEventExpose child_event;
507   GList *children;
508
509   g_return_val_if_fail (widget != NULL, FALSE);
510   g_return_val_if_fail (GTK_IS_BOX (widget), FALSE);
511   g_return_val_if_fail (event != NULL, FALSE);
512
513   if (GTK_WIDGET_DRAWABLE (widget))
514     {
515       box = GTK_BOX (widget);
516
517       child_event = *event;
518
519       children = box->children;
520       while (children)
521         {
522           child = children->data;
523           children = children->next;
524
525           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
526               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
527             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
528         }
529     }
530
531   return FALSE;
532 }
533
534 static void
535 gtk_box_add (GtkContainer *container,
536              GtkWidget    *widget)
537 {
538   g_return_if_fail (container != NULL);
539   g_return_if_fail (GTK_IS_BOX (container));
540   g_return_if_fail (widget != NULL);
541
542   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
543 }
544
545 static void
546 gtk_box_remove (GtkContainer *container,
547                 GtkWidget    *widget)
548 {
549   GtkBox *box;
550   GtkBoxChild *child;
551   GList *children;
552
553   g_return_if_fail (container != NULL);
554   g_return_if_fail (GTK_IS_BOX (container));
555   g_return_if_fail (widget != NULL);
556
557   box = GTK_BOX (container);
558
559   children = box->children;
560   while (children)
561     {
562       child = children->data;
563
564       if (child->widget == widget)
565         {
566           gint visible;
567
568           visible = GTK_WIDGET_VISIBLE (widget);
569           gtk_widget_unparent (widget);
570
571           box->children = g_list_remove_link (box->children, children);
572           g_list_free (children);
573           g_free (child);
574
575           if (visible && GTK_WIDGET_VISIBLE (container))
576             gtk_widget_queue_resize (GTK_WIDGET (container));
577
578           break;
579         }
580
581       children = children->next;
582     }
583 }
584
585 static void
586 gtk_box_foreach (GtkContainer *container,
587                  GtkCallback   callback,
588                  gpointer      callback_data)
589 {
590   GtkBox *box;
591   GtkBoxChild *child;
592   GList *children;
593
594   g_return_if_fail (container != NULL);
595   g_return_if_fail (GTK_IS_BOX (container));
596   g_return_if_fail (callback != NULL);
597
598   box = GTK_BOX (container);
599
600   children = box->children;
601   while (children)
602     {
603       child = children->data;
604       children = children->next;
605
606       if (child->pack == GTK_PACK_START)
607         (* callback) (child->widget, callback_data);
608     }
609
610   children = g_list_last (box->children);
611   while (children)
612     {
613       child = children->data;
614       children = children->prev;
615
616       if (child->pack == GTK_PACK_END)
617         (* callback) (child->widget, callback_data);
618     }
619 }