]> Pileus Git - ~andy/gtk/blob - gtk/gtkvbox.c
Initial revision
[~andy/gtk] / gtk / gtkvbox.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 "gtkvbox.h"
19
20
21 static void gtk_vbox_class_init    (GtkVBoxClass   *klass);
22 static void gtk_vbox_init          (GtkVBox        *box);
23 static void gtk_vbox_size_request  (GtkWidget      *widget,
24                                     GtkRequisition *requisition);
25 static void gtk_vbox_size_allocate (GtkWidget      *widget,
26                                     GtkAllocation  *allocation);
27
28
29 guint
30 gtk_vbox_get_type ()
31 {
32   static guint vbox_type = 0;
33
34   if (!vbox_type)
35     {
36       GtkTypeInfo vbox_info =
37       {
38         "GtkVBox",
39         sizeof (GtkVBox),
40         sizeof (GtkVBoxClass),
41         (GtkClassInitFunc) gtk_vbox_class_init,
42         (GtkObjectInitFunc) gtk_vbox_init,
43         (GtkArgFunc) NULL,
44       };
45
46       vbox_type = gtk_type_unique (gtk_box_get_type (), &vbox_info);
47     }
48
49   return vbox_type;
50 }
51
52 static void
53 gtk_vbox_class_init (GtkVBoxClass *class)
54 {
55   GtkWidgetClass *widget_class;
56
57   widget_class = (GtkWidgetClass*) class;
58
59   widget_class->size_request = gtk_vbox_size_request;
60   widget_class->size_allocate = gtk_vbox_size_allocate;
61 }
62
63 static void
64 gtk_vbox_init (GtkVBox *vbox)
65 {
66 }
67
68 GtkWidget*
69 gtk_vbox_new (gint homogeneous,
70               gint spacing)
71 {
72   GtkVBox *vbox;
73
74   vbox = gtk_type_new (gtk_vbox_get_type ());
75
76   GTK_BOX (vbox)->spacing = spacing;
77   GTK_BOX (vbox)->homogeneous = homogeneous ? TRUE : FALSE;
78
79   return GTK_WIDGET (vbox);
80 }
81
82
83 static void
84 gtk_vbox_size_request (GtkWidget      *widget,
85                        GtkRequisition *requisition)
86 {
87   GtkBox *box;
88   GtkBoxChild *child;
89   GList *children;
90   gint nvis_children;
91   gint height;
92
93   g_return_if_fail (widget != NULL);
94   g_return_if_fail (GTK_IS_VBOX (widget));
95   g_return_if_fail (requisition != NULL);
96
97   box = GTK_BOX (widget);
98   requisition->width = 0;
99   requisition->height = 0;
100   nvis_children = 0;
101
102   children = box->children;
103   while (children)
104     {
105       child = children->data;
106       children = children->next;
107
108       if (GTK_WIDGET_VISIBLE (child->widget))
109         {
110           gtk_widget_size_request (child->widget, &child->widget->requisition);
111
112           if (box->homogeneous)
113             {
114               height = child->widget->requisition.height + child->padding * 2;
115               requisition->height = MAX (requisition->height, height);
116             }
117           else
118             {
119               requisition->height += child->widget->requisition.height + child->padding * 2;
120             }
121
122           requisition->width = MAX (requisition->width, child->widget->requisition.width);
123
124           nvis_children += 1;
125         }
126     }
127
128   if (nvis_children > 0)
129     {
130       if (box->homogeneous)
131         requisition->height *= nvis_children;
132       requisition->height += (nvis_children - 1) * box->spacing;
133     }
134
135   requisition->width += GTK_CONTAINER (box)->border_width * 2;
136   requisition->height += GTK_CONTAINER (box)->border_width * 2;
137 }
138
139 static void
140 gtk_vbox_size_allocate (GtkWidget     *widget,
141                         GtkAllocation *allocation)
142 {
143   GtkBox *box;
144   GtkBoxChild *child;
145   GList *children;
146   GtkAllocation child_allocation;
147   gint nvis_children;
148   gint nexpand_children;
149   gint child_height;
150   gint height;
151   gint extra;
152   gint y;
153
154   g_return_if_fail (widget != NULL);
155   g_return_if_fail (GTK_IS_VBOX (widget));
156   g_return_if_fail (allocation != NULL);
157
158   box = GTK_BOX (widget);
159   widget->allocation = *allocation;
160
161   nvis_children = 0;
162   nexpand_children = 0;
163   children = box->children;
164
165   while (children)
166     {
167       child = children->data;
168       children = children->next;
169
170       if (GTK_WIDGET_VISIBLE (child->widget))
171         {
172           nvis_children += 1;
173           if (child->expand)
174             nexpand_children += 1;
175         }
176     }
177
178   if (nvis_children > 0)
179     {
180       if (box->homogeneous)
181         {
182           height = (allocation->height -
183                    GTK_CONTAINER (box)->border_width * 2 -
184                    (nvis_children - 1) * box->spacing);
185           extra = height / nvis_children;
186         }
187       else if (nexpand_children > 0)
188         {
189           height = allocation->height - widget->requisition.height;
190           extra = height / nexpand_children;
191         }
192       else
193         {
194           height = 0;
195           extra = 0;
196         }
197
198       y = allocation->y + GTK_CONTAINER (box)->border_width;
199       child_allocation.x = allocation->x + GTK_CONTAINER (box)->border_width;
200       child_allocation.width = allocation->width - GTK_CONTAINER (box)->border_width * 2;
201
202       children = box->children;
203       while (children)
204         {
205           child = children->data;
206           children = children->next;
207
208           if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
209             {
210               if (box->homogeneous)
211                 {
212                   if (nvis_children == 1)
213                     child_height = height;
214                   else
215                     child_height = extra;
216
217                   nvis_children -= 1;
218                   height -= extra;
219                 }
220               else
221                 {
222                   child_height = child->widget->requisition.height + child->padding * 2;
223
224                   if (child->expand)
225                     {
226                       if (nexpand_children == 1)
227                         child_height += height;
228                       else
229                         child_height += extra;
230
231                       nexpand_children -= 1;
232                       height -= extra;
233                     }
234                 }
235
236               if (child->fill)
237                 {
238                   child_allocation.height = child_height - child->padding * 2;
239                   child_allocation.y = y + child->padding;
240                 }
241               else
242                 {
243                   child_allocation.height = child->widget->requisition.height;
244                   child_allocation.y = y + (child_height - child_allocation.height) / 2;
245                 }
246
247               gtk_widget_size_allocate (child->widget, &child_allocation);
248
249               y += child_height + box->spacing;
250             }
251         }
252
253       y = allocation->y + allocation->height - GTK_CONTAINER (box)->border_width;
254
255       children = box->children;
256       while (children)
257         {
258           child = children->data;
259           children = children->next;
260
261           if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
262             {
263               if (box->homogeneous)
264                 {
265                   if (nvis_children == 1)
266                     child_height = height;
267                   else
268                     child_height = extra;
269
270                   nvis_children -= 1;
271                   height -= extra;
272                 }
273               else
274                 {
275                   child_height = child->widget->requisition.height + child->padding * 2;
276
277                   if (child->expand)
278                     {
279                       if (nexpand_children == 1)
280                         child_height += height;
281                       else
282                         child_height += extra;
283
284                       nexpand_children -= 1;
285                       height -= extra;
286                     }
287                 }
288
289               if (child->fill)
290                 {
291                   child_allocation.height = child_height - child->padding * 2;
292                   child_allocation.y = y + child->padding - child_height;
293                 }
294               else
295                 {
296                   child_allocation.height = child->widget->requisition.height;
297                   child_allocation.y = y + (child_height - child_allocation.height) / 2 - child_height;
298                 }
299
300               gtk_widget_size_allocate (child->widget, &child_allocation);
301
302               y -= (child_height + box->spacing);
303             }
304         }
305     }
306 }