]> Pileus Git - ~andy/gtk/blob - gtk/gtkbox.c
new functions gtk_box_reorder_child, gtk_box_query_child_packing and
[~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     }
129 }
130
131 static void
132 gtk_box_get_arg (GtkBox       *box,
133                  GtkArg       *arg,
134                  guint         arg_id)
135 {
136   switch (arg_id)
137     {
138     case ARG_SPACING:
139       GTK_VALUE_INT (*arg) = box->spacing;
140       break;
141     case ARG_HOMOGENEOUS:
142       GTK_VALUE_BOOL (*arg) = box->homogeneous;
143       break;
144     default:
145       arg->type = GTK_TYPE_INVALID;
146       break;
147     }
148 }
149
150 void
151 gtk_box_pack_start (GtkBox    *box,
152                     GtkWidget *child,
153                     gint       expand,
154                     gint       fill,
155                     gint       padding)
156 {
157   GtkBoxChild *child_info;
158
159   g_return_if_fail (box != NULL);
160   g_return_if_fail (GTK_IS_BOX (box));
161   g_return_if_fail (child != NULL);
162
163   child_info = g_new (GtkBoxChild, 1);
164   child_info->widget = child;
165   child_info->padding = padding;
166   child_info->expand = expand ? TRUE : FALSE;
167   child_info->fill = fill ? TRUE : FALSE;
168   child_info->pack = GTK_PACK_START;
169
170   box->children = g_list_append (box->children, child_info);
171
172   gtk_widget_set_parent (child, GTK_WIDGET (box));
173
174   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box)))
175     {
176       if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) &&
177           !GTK_WIDGET_REALIZED (child))
178         gtk_widget_realize (child);
179       
180       if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) &&
181           !GTK_WIDGET_MAPPED (child))
182         gtk_widget_map (child);
183     }
184
185   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
186     gtk_widget_queue_resize (child);
187 }
188
189 void
190 gtk_box_pack_end (GtkBox    *box,
191                   GtkWidget *child,
192                   gint       expand,
193                   gint       fill,
194                   gint       padding)
195 {
196   GtkBoxChild *child_info;
197
198   g_return_if_fail (box != NULL);
199   g_return_if_fail (GTK_IS_BOX (box));
200   g_return_if_fail (child != NULL);
201
202   child_info = g_new (GtkBoxChild, 1);
203   child_info->widget = child;
204   child_info->padding = padding;
205   child_info->expand = expand ? TRUE : FALSE;
206   child_info->fill = fill ? TRUE : FALSE;
207   child_info->pack = GTK_PACK_END;
208
209   box->children = g_list_append (box->children, child_info);
210
211   gtk_widget_set_parent (child, GTK_WIDGET (box));
212
213   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (box)))
214     {
215       if (GTK_WIDGET_REALIZED (GTK_WIDGET (box)) &&
216           !GTK_WIDGET_REALIZED (child))
217         gtk_widget_realize (child);
218       
219       if (GTK_WIDGET_MAPPED (GTK_WIDGET (box)) &&
220           !GTK_WIDGET_MAPPED (child))
221         gtk_widget_map (child);
222     }
223   
224   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
225     gtk_widget_queue_resize (child);
226 }
227
228 void
229 gtk_box_pack_start_defaults (GtkBox    *box,
230                              GtkWidget *child)
231 {
232   g_return_if_fail (box != NULL);
233   g_return_if_fail (GTK_IS_BOX (box));
234   g_return_if_fail (child != NULL);
235
236   gtk_box_pack_start (box, child, TRUE, TRUE, 0);
237 }
238
239 void
240 gtk_box_pack_end_defaults (GtkBox    *box,
241                            GtkWidget *child)
242 {
243   g_return_if_fail (box != NULL);
244   g_return_if_fail (GTK_IS_BOX (box));
245   g_return_if_fail (child != NULL);
246
247   gtk_box_pack_end (box, child, TRUE, TRUE, 0);
248 }
249
250 void
251 gtk_box_set_homogeneous (GtkBox *box,
252                          gint    homogeneous)
253 {
254   g_return_if_fail (box != NULL);
255   g_return_if_fail (GTK_IS_BOX (box));
256
257   if ((homogeneous ? TRUE : FALSE) != box->homogeneous)
258     {
259       box->homogeneous = homogeneous ? TRUE : FALSE;
260       gtk_widget_queue_resize (GTK_WIDGET (box));
261     }
262 }
263
264 void
265 gtk_box_set_spacing (GtkBox *box,
266                      gint    spacing)
267 {
268   g_return_if_fail (box != NULL);
269   g_return_if_fail (GTK_IS_BOX (box));
270
271   if (spacing != box->spacing)
272     {
273       box->spacing = spacing;
274       gtk_widget_queue_resize (GTK_WIDGET (box));
275     }
276 }
277
278 void
279 gtk_box_reorder_child (GtkBox                   *box,
280                        GtkWidget                *child,
281                        guint                    pos)
282 {
283   GList *list;
284
285   g_return_if_fail (box != NULL);
286   g_return_if_fail (GTK_IS_BOX (box));
287   g_return_if_fail (child != NULL);
288
289   list = box->children;
290   while (list)
291     {
292       GtkBoxChild *child_info;
293
294       child_info = list->data;
295       if (child_info->widget == child)
296         break;
297
298       list = list->next;
299     }
300
301   if (list)
302     {
303       GList *tmp_list;
304
305       if (list->next)
306         list->next->prev = list->prev;
307       if (list->prev)
308         list->prev->next = list->next;
309
310       tmp_list = box->children;
311       while (pos && tmp_list->next)
312         {
313           pos--;
314           tmp_list = tmp_list->next;
315         }
316
317       if (pos)
318         {
319           tmp_list->next = list;
320           list->prev = tmp_list;
321           list->next = NULL;
322         }
323       else
324         {
325           if (tmp_list->prev)
326             tmp_list->prev->next = list;
327           else
328             box->children = list;
329           list->prev = tmp_list->prev;
330           tmp_list->prev = list;
331           list->next = tmp_list;
332         }
333
334       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
335         gtk_widget_queue_resize (child);
336     }
337 }
338
339 void
340 gtk_box_query_child_packing (GtkBox             *box,
341                              GtkWidget          *child,
342                              gint               *expand,
343                              gint               *fill,
344                              gint               *padding,
345                              GtkPackType        *pack_type)
346 {
347   GList *list;
348   GtkBoxChild *child_info;
349
350   g_return_if_fail (box != NULL);
351   g_return_if_fail (GTK_IS_BOX (box));
352   g_return_if_fail (child != NULL);
353
354   list = box->children;
355   while (list)
356     {
357       child_info = list->data;
358       if (child_info->widget == child)
359         break;
360
361       list = list->next;
362     }
363
364   if (list)
365     {
366       if (expand)
367         *expand = child_info->expand;
368       if (fill)
369         *fill = child_info->fill;
370       if (padding)
371         *padding = child_info->padding;
372       if (pack_type)
373         *pack_type = child_info->pack;
374     }
375 }
376
377 void
378 gtk_box_set_child_packing (GtkBox               *box,
379                            GtkWidget            *child,
380                            gint                 expand,
381                            gint                 fill,
382                            gint                 padding,
383                            GtkPackType          pack_type)
384 {
385   GList *list;
386   GtkBoxChild *child_info;
387
388   g_return_if_fail (box != NULL);
389   g_return_if_fail (GTK_IS_BOX (box));
390   g_return_if_fail (child != NULL);
391
392   list = box->children;
393   while (list)
394     {
395       child_info = list->data;
396       if (child_info->widget == child)
397         break;
398
399       list = list->next;
400     }
401
402   if (list)
403     {
404       child_info->expand = expand != FALSE;
405       child_info->fill = fill != FALSE;
406       child_info->padding = padding;
407       if (pack_type == GTK_PACK_END)
408         child_info->pack = GTK_PACK_END;
409       else
410         child_info->pack = GTK_PACK_START;
411
412       if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (box))
413         gtk_widget_queue_resize (child);
414     }
415 }
416
417
418 static void
419 gtk_box_destroy (GtkObject *object)
420 {
421   GtkBox *box;
422   GtkBoxChild *child;
423   GList *children;
424
425   g_return_if_fail (object != NULL);
426   g_return_if_fail (GTK_IS_BOX (object));
427
428   box = GTK_BOX (object);
429
430   children = box->children;
431   while (children)
432     {
433       child = children->data;
434       children = children->next;
435
436       child->widget->parent = NULL;
437       gtk_object_unref (GTK_OBJECT (child->widget));
438       gtk_widget_destroy (child->widget);
439       g_free (child);
440     }
441
442   g_list_free (box->children);
443
444   if (GTK_OBJECT_CLASS (parent_class)->destroy)
445     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
446 }
447
448 static void
449 gtk_box_map (GtkWidget *widget)
450 {
451   GtkBox *box;
452   GtkBoxChild *child;
453   GList *children;
454
455   g_return_if_fail (widget != NULL);
456   g_return_if_fail (GTK_IS_BOX (widget));
457
458   box = GTK_BOX (widget);
459   GTK_WIDGET_SET_FLAGS (box, GTK_MAPPED);
460
461   children = box->children;
462   while (children)
463     {
464       child = children->data;
465       children = children->next;
466
467       if (GTK_WIDGET_VISIBLE (child->widget) &&
468           !GTK_WIDGET_MAPPED (child->widget))
469         gtk_widget_map (child->widget);
470     }
471 }
472
473 static void
474 gtk_box_unmap (GtkWidget *widget)
475 {
476   GtkBox *box;
477   GtkBoxChild *child;
478   GList *children;
479
480   g_return_if_fail (widget != NULL);
481   g_return_if_fail (GTK_IS_BOX (widget));
482
483   box = GTK_BOX (widget);
484   GTK_WIDGET_UNSET_FLAGS (box, GTK_MAPPED);
485
486   children = box->children;
487   while (children)
488     {
489       child = children->data;
490       children = children->next;
491
492       if (GTK_WIDGET_VISIBLE (child->widget) &&
493           GTK_WIDGET_MAPPED (child->widget))
494         gtk_widget_unmap (child->widget);
495     }
496 }
497
498 static void
499 gtk_box_draw (GtkWidget    *widget,
500               GdkRectangle *area)
501 {
502   GtkBox *box;
503   GtkBoxChild *child;
504   GdkRectangle child_area;
505   GList *children;
506
507   g_return_if_fail (widget != NULL);
508   g_return_if_fail (GTK_IS_BOX (widget));
509
510   if (GTK_WIDGET_DRAWABLE (widget))
511     {
512       box = GTK_BOX (widget);
513
514       children = box->children;
515       while (children)
516         {
517           child = children->data;
518           children = children->next;
519
520           if (gtk_widget_intersect (child->widget, area, &child_area))
521             gtk_widget_draw (child->widget, &child_area);
522         }
523     }
524 }
525
526 static gint
527 gtk_box_expose (GtkWidget      *widget,
528                 GdkEventExpose *event)
529 {
530   GtkBox *box;
531   GtkBoxChild *child;
532   GdkEventExpose child_event;
533   GList *children;
534
535   g_return_val_if_fail (widget != NULL, FALSE);
536   g_return_val_if_fail (GTK_IS_BOX (widget), FALSE);
537   g_return_val_if_fail (event != NULL, FALSE);
538
539   if (GTK_WIDGET_DRAWABLE (widget))
540     {
541       box = GTK_BOX (widget);
542
543       child_event = *event;
544
545       children = box->children;
546       while (children)
547         {
548           child = children->data;
549           children = children->next;
550
551           if (GTK_WIDGET_NO_WINDOW (child->widget) &&
552               gtk_widget_intersect (child->widget, &event->area, &child_event.area))
553             gtk_widget_event (child->widget, (GdkEvent*) &child_event);
554         }
555     }
556
557   return FALSE;
558 }
559
560 static void
561 gtk_box_add (GtkContainer *container,
562              GtkWidget    *widget)
563 {
564   g_return_if_fail (container != NULL);
565   g_return_if_fail (GTK_IS_BOX (container));
566   g_return_if_fail (widget != NULL);
567
568   gtk_box_pack_start_defaults (GTK_BOX (container), widget);
569 }
570
571 static void
572 gtk_box_remove (GtkContainer *container,
573                 GtkWidget    *widget)
574 {
575   GtkBox *box;
576   GtkBoxChild *child;
577   GList *children;
578
579   g_return_if_fail (container != NULL);
580   g_return_if_fail (GTK_IS_BOX (container));
581   g_return_if_fail (widget != NULL);
582
583   box = GTK_BOX (container);
584
585   children = box->children;
586   while (children)
587     {
588       child = children->data;
589
590       if (child->widget == widget)
591         {
592           gtk_widget_unparent (widget);
593
594           box->children = g_list_remove_link (box->children, children);
595           g_list_free (children);
596           g_free (child);
597
598           if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (container))
599             gtk_widget_queue_resize (GTK_WIDGET (container));
600
601           break;
602         }
603
604       children = children->next;
605     }
606 }
607
608 static void
609 gtk_box_foreach (GtkContainer *container,
610                  GtkCallback   callback,
611                  gpointer      callback_data)
612 {
613   GtkBox *box;
614   GtkBoxChild *child;
615   GList *children;
616
617   g_return_if_fail (container != NULL);
618   g_return_if_fail (GTK_IS_BOX (container));
619   g_return_if_fail (callback != NULL);
620
621   box = GTK_BOX (container);
622
623   children = box->children;
624   while (children)
625     {
626       child = children->data;
627       children = children->next;
628
629       if (child->pack == GTK_PACK_START)
630         (* callback) (child->widget, callback_data);
631     }
632
633   children = g_list_last (box->children);
634   while (children)
635     {
636       child = children->data;
637       children = children->prev;
638
639       if (child->pack == GTK_PACK_END)
640         (* callback) (child->widget, callback_data);
641     }
642 }