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