]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
some gtk_*_set_arg fixes
[~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 Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include "gtkbox.h"
19
20 enum {
21   ARG_0,
22   ARG_SPACING,
23   ARG_HOMOGENEOUS
24 };
25
26 static void gtk_box_class_init (GtkBoxClass    *klass);
27 static void gtk_box_init       (GtkBox         *box);
28 static void gtk_box_get_arg    (GtkBox         *box,
29                                 GtkArg         *arg,
30                                 guint           arg_id);
31 static void gtk_box_set_arg    (GtkBox         *box,
32                                 GtkArg         *arg,
33                                 guint           arg_id);
34 static void gtk_box_destroy    (GtkObject      *object);
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, ARG_SPACING);
91   gtk_object_add_arg_type ("GtkBox::homogeneous", GTK_TYPE_BOOL, ARG_HOMOGENEOUS);
92
93   object_class->destroy = gtk_box_destroy;
94
95   widget_class->map = gtk_box_map;
96   widget_class->unmap = gtk_box_unmap;
97   widget_class->draw = gtk_box_draw;
98   widget_class->expose_event = gtk_box_expose;
99
100   container_class->add = gtk_box_add;
101   container_class->remove = gtk_box_remove;
102   container_class->foreach = gtk_box_foreach;
103 }
104
105 static void
106 gtk_box_init (GtkBox *box)
107 {
108   GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW | GTK_BASIC);
109
110   box->children = NULL;
111   box->spacing = 0;
112   box->homogeneous = FALSE;
113 }
114
115 static void
116 gtk_box_set_arg (GtkBox       *box,
117                  GtkArg       *arg,
118                  guint         arg_id)
119 {
120   switch (arg_id)
121     {
122     case ARG_SPACING:
123       gtk_box_set_spacing (box, GTK_VALUE_INT (*arg));
124       break;
125     case ARG_HOMOGENEOUS:
126       gtk_box_set_homogeneous (box, GTK_VALUE_BOOL (*arg));
127       break;
128     default:
129       arg->type = GTK_TYPE_INVALID;
130       break;
131     }
132 }
133
134 static void
135 gtk_box_get_arg (GtkBox       *box,
136                  GtkArg       *arg,
137                  guint         arg_id)
138 {
139   switch (arg_id)
140     {
141     case ARG_SPACING:
142       GTK_VALUE_INT (*arg) = box->spacing;
143       break;
144     case ARG_HOMOGENEOUS:
145       GTK_VALUE_BOOL (*arg) = box->homogeneous;
146       break;
147     default:
148       arg->type = GTK_TYPE_INVALID;
149       break;
150     }
151 }
152
153 void
154 gtk_box_pack_start (GtkBox    *box,
155                     GtkWidget *child,
156                     gint       expand,
157                     gint       fill,
158                     gint       padding)
159 {
160   GtkBoxChild *child_info;
161
162   g_return_if_fail (box != NULL);
163   g_return_if_fail (GTK_IS_BOX (box));
164   g_return_if_fail (child != NULL);
165
166   child_info = g_new (GtkBoxChild, 1);
167   child_info->widget = child;
168   child_info->padding = padding;
169   child_info->expand = expand ? TRUE : FALSE;
170   child_info->fill = fill ? TRUE : FALSE;
171   child_info->pack = GTK_PACK_START;
172
173   box->children = g_list_append (box->children, child_info);
174
175   gtk_widget_set_parent (child, GTK_WIDGET (box));
176
177   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box)))
178     {
179       if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) &&
180           !GTK_WIDGET_REALIZED (child))
181         gtk_widget_realize (child);
182       
183       if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) &&
184           !GTK_WIDGET_MAPPED (child))
185         gtk_widget_map (child);
186     }
187
188   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
189     gtk_widget_queue_resize (child);
190 }
191
192 void
193 gtk_box_pack_end (GtkBox    *box,
194                   GtkWidget *child,
195                   gint       expand,
196                   gint       fill,
197                   gint       padding)
198 {
199   GtkBoxChild *child_info;
200
201   g_return_if_fail (box != NULL);
202   g_return_if_fail (GTK_IS_BOX (box));
203   g_return_if_fail (child != 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
423 static void
424 gtk_box_destroy (GtkObject *object)
425 {
426   GtkBox *box;
427   GtkBoxChild *child;
428   GList *children;
429
430   g_return_if_fail (object != NULL);
431   g_return_if_fail (GTK_IS_BOX (object));
432
433   box = GTK_BOX (object);
434
435   children = box->children;
436   while (children)
437     {
438       child = children->data;
439       children = children->next;
440
441       child->widget->parent = NULL;
442       gtk_object_unref (GTK_OBJECT (child->widget));
443       gtk_widget_destroy (child->widget);
444       g_free (child);
445     }
446
447   g_list_free (box->children);
448
449   if (GTK_OBJECT_CLASS (parent_class)->destroy)
450     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
451 }
452
453 static void
454 gtk_box_map (GtkWidget *widget)
455 {
456   GtkBox *box;
457   GtkBoxChild *child;
458   GList *children;
459
460   g_return_if_fail (widget != NULL);
461   g_return_if_fail (GTK_IS_BOX (widget));
462
463   box = GTK_BOX (widget);
464   GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED);
465
466   children = box->children;
467   while (children)
468     {
469       child = children->data;
470       children = children->next;
471
472       if (GTK_WIDGET_VISIBLE (child->widget) &&
473           !GTK_WIDGET_MAPPED (child->widget))
474         gtk_widget_map (child->widget);
475     }
476 }
477
478 static void
479 gtk_box_unmap (GtkWidget *widget)
480 {
481   GtkBox *box;
482   GtkBoxChild *child;
483   GList *children;
484
485   g_return_if_fail (widget != NULL);
486   g_return_if_fail (GTK_IS_BOX (widget));
487
488   box = GTK_BOX (widget);
489   GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED);
490
491   children = box->children;
492   while (children)
493     {
494       child = children->data;
495       children = children->next;
496
497       if (GTK_WIDGET_VISIBLE (child->widget) &&
498           GTK_WIDGET_MAPPED (child->widget))
499         gtk_widget_unmap (child->widget);
500     }
501 }
502
503 static void
504 gtk_box_draw (GtkWidget    *widget,
505               GdkRectangle *area)
506 {
507   GtkBox *box;
508   GtkBoxChild *child;
509   GdkRectangle child_area;
510   GList *children;
511
512   g_return_if_fail (widget != NULL);
513   g_return_if_fail (GTK_IS_BOX (widget));
514
515   if (GTK_WIDGET_DRAWABLE (widget))
516     {
517       box = GTK_BOX (widget);
518
519       children = box->children;
520       while (children)
521         {
522           child = children->data;
523           children = children->next;
524
525           if (gtk_widget_intersect (child->widget, area, &child_area))
526             gtk_widget_draw (child->widget, &child_area);
527         }
528     }
529 }
530
531 static gint
532 gtk_box_expose (GtkWidget      *widget,
533                 GdkEventExpose *event)
534 {
535   GtkBox *box;
536   GtkBoxChild *child;
537   GdkEventExpose child_event;
538   GList *children;
539
540   g_return_val_if_fail (widget != NULL, FALSE);
541   g_return_val_if_fail (GTK_IS_BOX (widget), FALSE);
542   g_return_val_if_fail (event != NULL, FALSE);
543
544   if (GTK_WIDGET_DRAWABLE (widget))
545     {
546       box = GTK_BOX (widget);
547
548       child_event = *event;
549
550       children = box->children;
551       while (children)
552         {
553           child = children->data;
554           children = children->next;
555
556           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
557               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
558             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
559         }
560     }
561
562   return FALSE;
563 }
564
565 static void
566 gtk_box_add (GtkContainer *container,
567              GtkWidget    *widget)
568 {
569   g_return_if_fail (container != NULL);
570   g_return_if_fail (GTK_IS_BOX (container));
571   g_return_if_fail (widget != NULL);
572
573   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
574 }
575
576 static void
577 gtk_box_remove (GtkContainer *container,
578                 GtkWidget    *widget)
579 {
580   GtkBox *box;
581   GtkBoxChild *child;
582   GList *children;
583
584   g_return_if_fail (container != NULL);
585   g_return_if_fail (GTK_IS_BOX (container));
586   g_return_if_fail (widget != NULL);
587
588   box = GTK_BOX (container);
589
590   children = box->children;
591   while (children)
592     {
593       child = children->data;
594
595       if (child->widget == widget)
596         {
597           gtk_widget_unparent (widget);
598
599           box->children = g_list_remove_link (box->children, children);
600           g_list_free (children);
601           g_free (child);
602
603           if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
604             gtk_widget_queue_resize (GTK_WIDGET (container));
605
606           break;
607         }
608
609       children = children->next;
610     }
611 }
612
613 static void
614 gtk_box_foreach (GtkContainer *container,
615                  GtkCallback   callback,
616                  gpointer      callback_data)
617 {
618   GtkBox *box;
619   GtkBoxChild *child;
620   GList *children;
621
622   g_return_if_fail (container != NULL);
623   g_return_if_fail (GTK_IS_BOX (container));
624   g_return_if_fail (callback != NULL);
625
626   box = GTK_BOX (container);
627
628   children = box->children;
629   while (children)
630     {
631       child = children->data;
632       children = children->next;
633
634       if (child->pack == GTK_PACK_START)
635         (* callback) (child->widget, callback_data);
636     }
637
638   children = g_list_last (box->children);
639   while (children)
640     {
641       child = children->data;
642       children = children->prev;
643
644       if (child->pack == GTK_PACK_END)
645         (* callback) (child->widget, callback_data);
646     }
647 }