]> Pileus Git - ~andy/gtk/blob - gtk/gtkhbox.c
Fix #137520.
[~andy/gtk] / gtk / gtkhbox.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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28 #include "gtkhbox.h"
29
30
31 static void gtk_hbox_class_init    (GtkHBoxClass   *klass);
32 static void gtk_hbox_init          (GtkHBox        *box);
33 static void gtk_hbox_size_request  (GtkWidget      *widget,
34                                     GtkRequisition *requisition);
35 static void gtk_hbox_size_allocate (GtkWidget      *widget,
36                                     GtkAllocation  *allocation);
37
38
39 GType
40 gtk_hbox_get_type (void)
41 {
42   static GType hbox_type = 0;
43
44   if (!hbox_type)
45     {
46       static const GTypeInfo hbox_info =
47       {
48         sizeof (GtkHBoxClass),
49         NULL,           /* base_init */
50         NULL,           /* base_finalize */
51         (GClassInitFunc) gtk_hbox_class_init,
52         NULL,           /* class_finalize */
53         NULL,           /* class_data */
54         sizeof (GtkHBox),
55         0,              /* n_preallocs */
56         (GInstanceInitFunc) gtk_hbox_init,
57       };
58
59       hbox_type = g_type_register_static (GTK_TYPE_BOX, "GtkHBox",
60                                           &hbox_info, 0);
61     }
62
63   return hbox_type;
64 }
65
66 static void
67 gtk_hbox_class_init (GtkHBoxClass *class)
68 {
69   GtkWidgetClass *widget_class;
70
71   widget_class = (GtkWidgetClass*) class;
72
73   widget_class->size_request = gtk_hbox_size_request;
74   widget_class->size_allocate = gtk_hbox_size_allocate;
75 }
76
77 static void
78 gtk_hbox_init (GtkHBox *hbox)
79 {
80 }
81
82 GtkWidget*
83 gtk_hbox_new (gboolean homogeneous,
84               gint spacing)
85 {
86   GtkHBox *hbox;
87
88   hbox = g_object_new (GTK_TYPE_HBOX, NULL);
89
90   GTK_BOX (hbox)->spacing = spacing;
91   GTK_BOX (hbox)->homogeneous = homogeneous ? TRUE : FALSE;
92
93   return GTK_WIDGET (hbox);
94 }
95
96
97 static void
98 gtk_hbox_size_request (GtkWidget      *widget,
99                        GtkRequisition *requisition)
100 {
101   GtkBox *box;
102   GtkBoxChild *child;
103   GList *children;
104   gint nvis_children;
105   gint width;
106
107   box = GTK_BOX (widget);
108   requisition->width = 0;
109   requisition->height = 0;
110   nvis_children = 0;
111
112   children = box->children;
113   while (children)
114     {
115       child = children->data;
116       children = children->next;
117
118       if (GTK_WIDGET_VISIBLE (child->widget))
119         {
120           GtkRequisition child_requisition;
121
122           gtk_widget_size_request (child->widget, &child_requisition);
123
124           if (box->homogeneous)
125             {
126               width = child_requisition.width + child->padding * 2;
127               requisition->width = MAX (requisition->width, width);
128             }
129           else
130             {
131               requisition->width += child_requisition.width + child->padding * 2;
132             }
133
134           requisition->height = MAX (requisition->height, child_requisition.height);
135
136           nvis_children += 1;
137         }
138     }
139
140   if (nvis_children > 0)
141     {
142       if (box->homogeneous)
143         requisition->width *= nvis_children;
144       requisition->width += (nvis_children - 1) * box->spacing;
145     }
146
147   requisition->width += GTK_CONTAINER (box)->border_width * 2;
148   requisition->height += GTK_CONTAINER (box)->border_width * 2;
149 }
150
151 static void
152 gtk_hbox_size_allocate (GtkWidget     *widget,
153                         GtkAllocation *allocation)
154 {
155   GtkBox *box;
156   GtkBoxChild *child;
157   GList *children;
158   GtkAllocation child_allocation;
159   gint nvis_children;
160   gint nexpand_children;
161   gint child_width;
162   gint width;
163   gint extra;
164   gint x;
165   GtkTextDirection direction;
166
167   box = GTK_BOX (widget);
168   widget->allocation = *allocation;
169
170   direction = gtk_widget_get_direction (widget);
171   
172   nvis_children = 0;
173   nexpand_children = 0;
174   children = box->children;
175
176   while (children)
177     {
178       child = children->data;
179       children = children->next;
180
181       if (GTK_WIDGET_VISIBLE (child->widget))
182         {
183           nvis_children += 1;
184           if (child->expand)
185             nexpand_children += 1;
186         }
187     }
188
189   if (nvis_children > 0)
190     {
191       if (box->homogeneous)
192         {
193           width = (allocation->width -
194                    GTK_CONTAINER (box)->border_width * 2 -
195                    (nvis_children - 1) * box->spacing);
196           extra = width / nvis_children;
197         }
198       else if (nexpand_children > 0)
199         {
200           width = (gint) allocation->width - (gint) widget->requisition.width;
201           extra = width / nexpand_children;
202         }
203       else
204         {
205           width = 0;
206           extra = 0;
207         }
208
209       x = allocation->x + GTK_CONTAINER (box)->border_width;
210       child_allocation.y = allocation->y + GTK_CONTAINER (box)->border_width;
211       child_allocation.height = MAX (1, (gint) allocation->height - (gint) GTK_CONTAINER (box)->border_width * 2);
212
213       children = box->children;
214       while (children)
215         {
216           child = children->data;
217           children = children->next;
218
219           if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
220             {
221               if (box->homogeneous)
222                 {
223                   if (nvis_children == 1)
224                     child_width = width;
225                   else
226                     child_width = extra;
227
228                   nvis_children -= 1;
229                   width -= extra;
230                 }
231               else
232                 {
233                   GtkRequisition child_requisition;
234
235                   gtk_widget_get_child_requisition (child->widget, &child_requisition);
236
237                   child_width = child_requisition.width + child->padding * 2;
238
239                   if (child->expand)
240                     {
241                       if (nexpand_children == 1)
242                         child_width += width;
243                       else
244                         child_width += extra;
245
246                       nexpand_children -= 1;
247                       width -= extra;
248                     }
249                 }
250
251               if (child->fill)
252                 {
253                   child_allocation.width = MAX (1, (gint) child_width - (gint) child->padding * 2);
254                   child_allocation.x = x + child->padding;
255                 }
256               else
257                 {
258                   GtkRequisition child_requisition;
259
260                   gtk_widget_get_child_requisition (child->widget, &child_requisition);
261                   child_allocation.width = child_requisition.width;
262                   child_allocation.x = x + (child_width - child_allocation.width) / 2;
263                 }
264
265               if (direction == GTK_TEXT_DIR_RTL)
266                 child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
267
268               gtk_widget_size_allocate (child->widget, &child_allocation);
269
270               x += child_width + box->spacing;
271             }
272         }
273
274       x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width;
275
276       children = box->children;
277       while (children)
278         {
279           child = children->data;
280           children = children->next;
281
282           if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
283             {
284               GtkRequisition child_requisition;
285               gtk_widget_get_child_requisition (child->widget, &child_requisition);
286
287               if (box->homogeneous)
288                 {
289                   if (nvis_children == 1)
290                     child_width = width;
291                   else
292                     child_width = extra;
293
294                   nvis_children -= 1;
295                   width -= extra;
296                 }
297               else
298                 {
299                   child_width = child_requisition.width + child->padding * 2;
300
301                   if (child->expand)
302                     {
303                       if (nexpand_children == 1)
304                         child_width += width;
305                       else
306                         child_width += extra;
307
308                       nexpand_children -= 1;
309                       width -= extra;
310                     }
311                 }
312
313               if (child->fill)
314                 {
315                   child_allocation.width = MAX (1, (gint)child_width - (gint)child->padding * 2);
316                   child_allocation.x = x + child->padding - child_width;
317                 }
318               else
319                 {
320                   child_allocation.width = child_requisition.width;
321                   child_allocation.x = x + (child_width - child_allocation.width) / 2 - child_width;
322                 }
323
324               if (direction == GTK_TEXT_DIR_RTL)
325                 child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
326
327               gtk_widget_size_allocate (child->widget, &child_allocation);
328
329               x -= (child_width + box->spacing);
330             }
331         }
332     }
333 }