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 "gtkbbox.h"
29 #include "gtkhbbox.h"
30 #include "gtkvbbox.h"
31 #include "gtkorientable.h"
32 #include "gtkprivate.h"
33 #include "gtkintl.h"
34 #include "gtkalias.h"
35 
36 enum {
37   PROP_0,
38   PROP_LAYOUT_STYLE
39 };
40 
41 enum {
42   CHILD_PROP_0,
43   CHILD_PROP_SECONDARY
44 };
45 
46 static void gtk_button_box_set_property       (GObject           *object,
47 					       guint              prop_id,
48 					       const GValue      *value,
49 					       GParamSpec        *pspec);
50 static void gtk_button_box_get_property       (GObject           *object,
51 					       guint              prop_id,
52 					       GValue            *value,
53 					       GParamSpec        *pspec);
54 static void gtk_button_box_size_request       (GtkWidget         *widget,
55                                                GtkRequisition    *requisition);
56 static void gtk_button_box_size_allocate      (GtkWidget         *widget,
57                                                GtkAllocation     *allocation);
58 static void gtk_button_box_set_child_property (GtkContainer      *container,
59 					       GtkWidget         *child,
60 					       guint              property_id,
61 					       const GValue      *value,
62 					       GParamSpec        *pspec);
63 static void gtk_button_box_get_child_property (GtkContainer      *container,
64 					       GtkWidget         *child,
65 					       guint              property_id,
66 					       GValue            *value,
67 					       GParamSpec        *pspec);
68 
69 #define DEFAULT_CHILD_MIN_WIDTH 85
70 #define DEFAULT_CHILD_MIN_HEIGHT 27
71 #define DEFAULT_CHILD_IPAD_X 4
72 #define DEFAULT_CHILD_IPAD_Y 0
73 
G_DEFINE_ABSTRACT_TYPE(GtkButtonBox,gtk_button_box,GTK_TYPE_BOX)74 G_DEFINE_ABSTRACT_TYPE (GtkButtonBox, gtk_button_box, GTK_TYPE_BOX)
75 
76 static void
77 gtk_button_box_class_init (GtkButtonBoxClass *class)
78 {
79   GtkWidgetClass *widget_class;
80   GObjectClass *gobject_class;
81   GtkContainerClass *container_class;
82 
83   gobject_class = G_OBJECT_CLASS (class);
84   widget_class = (GtkWidgetClass*) class;
85   container_class = (GtkContainerClass*) class;
86 
87   gobject_class->set_property = gtk_button_box_set_property;
88   gobject_class->get_property = gtk_button_box_get_property;
89 
90   widget_class->size_request = gtk_button_box_size_request;
91   widget_class->size_allocate = gtk_button_box_size_allocate;
92 
93   container_class->set_child_property = gtk_button_box_set_child_property;
94   container_class->get_child_property = gtk_button_box_get_child_property;
95 
96   /* FIXME we need to override the "spacing" property on GtkBox once
97    * libgobject allows that.
98    */
99   gtk_widget_class_install_style_property (widget_class,
100 					   g_param_spec_int ("child-min-width",
101 							     P_("Minimum child width"),
102 							     P_("Minimum width of buttons inside the box"),
103 							     0,
104 							     G_MAXINT,
105                                                              DEFAULT_CHILD_MIN_WIDTH,
106 							     GTK_PARAM_READABLE));
107 
108   gtk_widget_class_install_style_property (widget_class,
109 					   g_param_spec_int ("child-min-height",
110 							     P_("Minimum child height"),
111 							     P_("Minimum height of buttons inside the box"),
112 							     0,
113 							     G_MAXINT,
114                                                              DEFAULT_CHILD_MIN_HEIGHT,
115 							     GTK_PARAM_READABLE));
116 
117   gtk_widget_class_install_style_property (widget_class,
118 					   g_param_spec_int ("child-internal-pad-x",
119 							     P_("Child internal width padding"),
120 							     P_("Amount to increase child's size on either side"),
121 							     0,
122 							     G_MAXINT,
123                                                              DEFAULT_CHILD_IPAD_X,
124 							     GTK_PARAM_READABLE));
125 
126   gtk_widget_class_install_style_property (widget_class,
127 					   g_param_spec_int ("child-internal-pad-y",
128 							     P_("Child internal height padding"),
129 							     P_("Amount to increase child's size on the top and bottom"),
130 							     0,
131 							     G_MAXINT,
132                                                              DEFAULT_CHILD_IPAD_Y,
133 							     GTK_PARAM_READABLE));
134   g_object_class_install_property (gobject_class,
135                                    PROP_LAYOUT_STYLE,
136                                    g_param_spec_enum ("layout-style",
137                                                       P_("Layout style"),
138                                                       P_("How to lay out the buttons in the box. Possible values are: default, spread, edge, start and end"),
139 						      GTK_TYPE_BUTTON_BOX_STYLE,
140 						      GTK_BUTTONBOX_DEFAULT_STYLE,
141                                                       GTK_PARAM_READWRITE));
142 
143   gtk_container_class_install_child_property (container_class,
144 					      CHILD_PROP_SECONDARY,
145 					      g_param_spec_boolean ("secondary",
146 								    P_("Secondary"),
147 								    P_("If TRUE, the child appears in a secondary group of children, suitable for, e.g., help buttons"),
148 								    FALSE,
149 								    GTK_PARAM_READWRITE));
150 }
151 
152 static void
gtk_button_box_init(GtkButtonBox * button_box)153 gtk_button_box_init (GtkButtonBox *button_box)
154 {
155   GTK_BOX (button_box)->spacing = 0;
156   button_box->child_min_width = GTK_BUTTONBOX_DEFAULT;
157   button_box->child_min_height = GTK_BUTTONBOX_DEFAULT;
158   button_box->child_ipad_x = GTK_BUTTONBOX_DEFAULT;
159   button_box->child_ipad_y = GTK_BUTTONBOX_DEFAULT;
160   button_box->layout_style = GTK_BUTTONBOX_DEFAULT_STYLE;
161 }
162 
163 static void
gtk_button_box_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)164 gtk_button_box_set_property (GObject         *object,
165 			     guint            prop_id,
166 			     const GValue    *value,
167 			     GParamSpec      *pspec)
168 {
169   switch (prop_id)
170     {
171     case PROP_LAYOUT_STYLE:
172       gtk_button_box_set_layout (GTK_BUTTON_BOX (object),
173 				 g_value_get_enum (value));
174       break;
175     default:
176       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
177       break;
178     }
179 }
180 
181 static void
gtk_button_box_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)182 gtk_button_box_get_property (GObject         *object,
183 			     guint            prop_id,
184 			     GValue          *value,
185 			     GParamSpec      *pspec)
186 {
187   switch (prop_id)
188     {
189     case PROP_LAYOUT_STYLE:
190       g_value_set_enum (value, GTK_BUTTON_BOX (object)->layout_style);
191       break;
192     default:
193       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
194       break;
195     }
196 }
197 
198 static void
gtk_button_box_set_child_property(GtkContainer * container,GtkWidget * child,guint property_id,const GValue * value,GParamSpec * pspec)199 gtk_button_box_set_child_property (GtkContainer    *container,
200 				   GtkWidget       *child,
201 				   guint            property_id,
202 				   const GValue    *value,
203 				   GParamSpec      *pspec)
204 {
205   switch (property_id)
206     {
207     case CHILD_PROP_SECONDARY:
208       gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (container), child,
209 					  g_value_get_boolean (value));
210       break;
211     default:
212       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
213       break;
214     }
215 }
216 
217 static void
gtk_button_box_get_child_property(GtkContainer * container,GtkWidget * child,guint property_id,GValue * value,GParamSpec * pspec)218 gtk_button_box_get_child_property (GtkContainer *container,
219 				   GtkWidget    *child,
220 				   guint         property_id,
221 				   GValue       *value,
222 				   GParamSpec   *pspec)
223 {
224   switch (property_id)
225     {
226     case CHILD_PROP_SECONDARY:
227       g_value_set_boolean (value,
228 			   gtk_button_box_get_child_secondary (GTK_BUTTON_BOX (container),
229 							       child));
230       break;
231     default:
232       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
233       break;
234     }
235 }
236 
237 /* set per widget values for spacing, child size and child internal padding */
238 
239 void
gtk_button_box_set_child_size(GtkButtonBox * widget,gint width,gint height)240 gtk_button_box_set_child_size (GtkButtonBox *widget,
241                                gint width, gint height)
242 {
243   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
244 
245   widget->child_min_width = width;
246   widget->child_min_height = height;
247 }
248 
249 void
gtk_button_box_set_child_ipadding(GtkButtonBox * widget,gint ipad_x,gint ipad_y)250 gtk_button_box_set_child_ipadding (GtkButtonBox *widget,
251                                    gint ipad_x, gint ipad_y)
252 {
253   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
254 
255   widget->child_ipad_x = ipad_x;
256   widget->child_ipad_y = ipad_y;
257 }
258 
259 void
gtk_button_box_set_layout(GtkButtonBox * widget,GtkButtonBoxStyle layout_style)260 gtk_button_box_set_layout (GtkButtonBox      *widget,
261                            GtkButtonBoxStyle  layout_style)
262 {
263   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
264   g_return_if_fail (layout_style >= GTK_BUTTONBOX_DEFAULT_STYLE &&
265 		    layout_style <= GTK_BUTTONBOX_CENTER);
266 
267   if (widget->layout_style != layout_style)
268     {
269       widget->layout_style = layout_style;
270       g_object_notify (G_OBJECT (widget), "layout-style");
271       gtk_widget_queue_resize (GTK_WIDGET (widget));
272     }
273 }
274 
275 
276 /* get per widget values for spacing, child size and child internal padding */
277 
278 void
gtk_button_box_get_child_size(GtkButtonBox * widget,gint * width,gint * height)279 gtk_button_box_get_child_size (GtkButtonBox *widget,
280                                gint *width, gint *height)
281 {
282   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
283   g_return_if_fail (width != NULL);
284   g_return_if_fail (height != NULL);
285 
286   *width  = widget->child_min_width;
287   *height = widget->child_min_height;
288 }
289 
290 void
gtk_button_box_get_child_ipadding(GtkButtonBox * widget,gint * ipad_x,gint * ipad_y)291 gtk_button_box_get_child_ipadding (GtkButtonBox *widget,
292                                    gint* ipad_x, gint *ipad_y)
293 {
294   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
295   g_return_if_fail (ipad_x != NULL);
296   g_return_if_fail (ipad_y != NULL);
297 
298   *ipad_x = widget->child_ipad_x;
299   *ipad_y = widget->child_ipad_y;
300 }
301 
302 GtkButtonBoxStyle
gtk_button_box_get_layout(GtkButtonBox * widget)303 gtk_button_box_get_layout (GtkButtonBox *widget)
304 {
305   g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), GTK_BUTTONBOX_SPREAD);
306 
307   return widget->layout_style;
308 }
309 
310 /**
311  * gtk_button_box_get_child_secondary:
312  * @widget: a #GtkButtonBox
313  * @child: a child of @widget
314  *
315  * Returns whether @child should appear in a secondary group of children.
316  *
317  * Return value: whether @child should appear in a secondary group of children.
318  *
319  * Since: 2.4
320  **/
321 gboolean
gtk_button_box_get_child_secondary(GtkButtonBox * widget,GtkWidget * child)322 gtk_button_box_get_child_secondary (GtkButtonBox *widget,
323 				    GtkWidget    *child)
324 {
325   GList *list;
326   GtkBoxChild *child_info;
327 
328   g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
329   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
330 
331   child_info = NULL;
332   list = GTK_BOX (widget)->children;
333   while (list)
334     {
335       child_info = list->data;
336       if (child_info->widget == child)
337 	break;
338 
339       list = list->next;
340     }
341 
342   g_return_val_if_fail (list != NULL, FALSE);
343 
344   return child_info->is_secondary;
345 }
346 
347 /**
348  * gtk_button_box_set_child_secondary
349  * @widget: a #GtkButtonBox
350  * @child: a child of @widget
351  * @is_secondary: if %TRUE, the @child appears in a secondary group of the
352  *                button box.
353  *
354  * Sets whether @child should appear in a secondary group of children.
355  * A typical use of a secondary child is the help button in a dialog.
356  *
357  * This group appears after the other children if the style
358  * is %GTK_BUTTONBOX_START, %GTK_BUTTONBOX_SPREAD or
359  * %GTK_BUTTONBOX_EDGE, and before the other children if the style
360  * is %GTK_BUTTONBOX_END. For horizontal button boxes, the definition
361  * of before/after depends on direction of the widget (see
362  * gtk_widget_set_direction()). If the style is %GTK_BUTTONBOX_START
363  * or %GTK_BUTTONBOX_END, then the secondary children are aligned at
364  * the other end of the button box from the main children. For the
365  * other styles, they appear immediately next to the main children.
366  **/
367 void
gtk_button_box_set_child_secondary(GtkButtonBox * widget,GtkWidget * child,gboolean is_secondary)368 gtk_button_box_set_child_secondary (GtkButtonBox *widget,
369 				    GtkWidget    *child,
370 				    gboolean      is_secondary)
371 {
372   GList *list;
373 
374   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
375   g_return_if_fail (GTK_IS_WIDGET (child));
376   g_return_if_fail (child->parent == GTK_WIDGET (widget));
377 
378   list = GTK_BOX (widget)->children;
379   while (list)
380     {
381       GtkBoxChild *child_info = list->data;
382       if (child_info->widget == child)
383 	{
384 	  child_info->is_secondary = is_secondary;
385 	  break;
386 	}
387 
388       list = list->next;
389     }
390 
391   gtk_widget_child_notify (child, "secondary");
392 
393   if (gtk_widget_get_visible (GTK_WIDGET (widget))
394       && gtk_widget_get_visible (child))
395     gtk_widget_queue_resize (child);
396 }
397 
398 /* Ask children how much space they require and round up
399    to match minimum size and internal padding.
400    Returns the size each single child should have. */
401 void
_gtk_button_box_child_requisition(GtkWidget * widget,int * nvis_children,int * nvis_secondaries,int * width,int * height)402 _gtk_button_box_child_requisition (GtkWidget *widget,
403                                    int       *nvis_children,
404 				   int       *nvis_secondaries,
405                                    int       *width,
406                                    int       *height)
407 {
408   GtkButtonBox *bbox;
409   GtkBoxChild *child;
410   GList *children;
411   gint nchildren;
412   gint nsecondaries;
413   gint needed_width;
414   gint needed_height;
415   GtkRequisition child_requisition;
416   gint ipad_w;
417   gint ipad_h;
418   gint width_default;
419   gint height_default;
420   gint ipad_x_default;
421   gint ipad_y_default;
422 
423   gint child_min_width;
424   gint child_min_height;
425   gint ipad_x;
426   gint ipad_y;
427 
428   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
429 
430   bbox = GTK_BUTTON_BOX (widget);
431 
432   gtk_widget_style_get (widget,
433                         "child-min-width", &width_default,
434                         "child-min-height", &height_default,
435                         "child-internal-pad-x", &ipad_x_default,
436                         "child-internal-pad-y", &ipad_y_default,
437 			NULL);
438 
439   child_min_width = bbox->child_min_width   != GTK_BUTTONBOX_DEFAULT
440 	  ? bbox->child_min_width : width_default;
441   child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT
442 	  ? bbox->child_min_height : height_default;
443   ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT
444 	  ? bbox->child_ipad_x : ipad_x_default;
445   ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT
446 	  ? bbox->child_ipad_y : ipad_y_default;
447 
448   nchildren = 0;
449   nsecondaries = 0;
450   children = GTK_BOX(bbox)->children;
451   needed_width = child_min_width;
452   needed_height = child_min_height;
453   ipad_w = ipad_x * 2;
454   ipad_h = ipad_y * 2;
455 
456   while (children)
457     {
458       child = children->data;
459       children = children->next;
460 
461       if (gtk_widget_get_visible (child->widget))
462 	{
463 	  nchildren += 1;
464 	  gtk_widget_size_request (child->widget, &child_requisition);
465 
466 	  if (child_requisition.width + ipad_w > needed_width)
467 	    needed_width = child_requisition.width + ipad_w;
468 	  if (child_requisition.height + ipad_h > needed_height)
469 	    needed_height = child_requisition.height + ipad_h;
470 	  if (child->is_secondary)
471 	    nsecondaries++;
472 	}
473     }
474 
475   if (nvis_children)
476     *nvis_children = nchildren;
477   if (nvis_secondaries)
478     *nvis_secondaries = nsecondaries;
479   if (width)
480     *width = needed_width;
481   if (height)
482     *height = needed_height;
483 }
484 
485 /* this is a kludge function to support the deprecated
486  * gtk_[vh]button_box_set_layout_default() just in case anyone is still
487  * using it (why?)
488  */
489 static GtkButtonBoxStyle
gtk_button_box_kludge_get_layout_default(GtkButtonBox * widget)490 gtk_button_box_kludge_get_layout_default (GtkButtonBox *widget)
491 {
492   GtkOrientation orientation;
493 
494   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
495 
496   if (orientation == GTK_ORIENTATION_HORIZONTAL)
497     return _gtk_hbutton_box_get_layout_default ();
498   else
499     return _gtk_vbutton_box_get_layout_default ();
500 }
501 
502 static void
gtk_button_box_size_request(GtkWidget * widget,GtkRequisition * requisition)503 gtk_button_box_size_request (GtkWidget      *widget,
504                              GtkRequisition *requisition)
505 {
506   GtkBox *box;
507   GtkButtonBox *bbox;
508   gint nvis_children;
509   gint child_width;
510   gint child_height;
511   gint spacing;
512   GtkButtonBoxStyle layout;
513   GtkOrientation orientation;
514 
515   box = GTK_BOX (widget);
516   bbox = GTK_BUTTON_BOX (widget);
517 
518   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
519   spacing = box->spacing;
520   layout = bbox->layout_style != GTK_BUTTONBOX_DEFAULT_STYLE
521 	  ? bbox->layout_style : gtk_button_box_kludge_get_layout_default (GTK_BUTTON_BOX (widget));
522 
523   _gtk_button_box_child_requisition (widget,
524                                      &nvis_children,
525 				     NULL,
526                                      &child_width,
527                                      &child_height);
528 
529   if (nvis_children == 0)
530     {
531       requisition->width = 0;
532       requisition->height = 0;
533     }
534   else
535     {
536       switch (layout)
537         {
538           case GTK_BUTTONBOX_SPREAD:
539             if (orientation == GTK_ORIENTATION_HORIZONTAL)
540               requisition->width =
541                       nvis_children*child_width + ((nvis_children+1)*spacing);
542             else
543               requisition->height =
544                       nvis_children*child_height + ((nvis_children+1)*spacing);
545 
546             break;
547           case GTK_BUTTONBOX_EDGE:
548           case GTK_BUTTONBOX_START:
549           case GTK_BUTTONBOX_END:
550           case GTK_BUTTONBOX_CENTER:
551             if (orientation == GTK_ORIENTATION_HORIZONTAL)
552               requisition->width =
553                       nvis_children*child_width + ((nvis_children-1)*spacing);
554             else
555               requisition->height =
556                       nvis_children*child_height + ((nvis_children-1)*spacing);
557 
558             break;
559           default:
560             g_assert_not_reached ();
561             break;
562         }
563 
564       if (orientation == GTK_ORIENTATION_HORIZONTAL)
565         requisition->height = child_height;
566       else
567         requisition->width = child_width;
568     }
569 
570   requisition->width += GTK_CONTAINER (box)->border_width * 2;
571   requisition->height += GTK_CONTAINER (box)->border_width * 2;
572 }
573 
574 static void
gtk_button_box_size_allocate(GtkWidget * widget,GtkAllocation * allocation)575 gtk_button_box_size_allocate (GtkWidget     *widget,
576                               GtkAllocation *allocation)
577 {
578   GtkBox *base_box;
579   GtkButtonBox *box;
580   GtkBoxChild *child;
581   GList *children;
582   GtkAllocation child_allocation;
583   gint nvis_children;
584   gint n_secondaries;
585   gint child_width;
586   gint child_height;
587   gint x = 0;
588   gint y = 0;
589   gint secondary_x = 0;
590   gint secondary_y = 0;
591   gint width = 0;
592   gint height = 0;
593   gint childspace;
594   gint childspacing = 0;
595   GtkButtonBoxStyle layout;
596   gint spacing;
597   GtkOrientation orientation;
598 
599   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
600   base_box = GTK_BOX (widget);
601   box = GTK_BUTTON_BOX (widget);
602   spacing = base_box->spacing;
603   layout = box->layout_style != GTK_BUTTONBOX_DEFAULT_STYLE
604 	  ? box->layout_style : gtk_button_box_kludge_get_layout_default (GTK_BUTTON_BOX (widget));
605   _gtk_button_box_child_requisition (widget,
606                                      &nvis_children,
607                                      &n_secondaries,
608                                      &child_width,
609                                      &child_height);
610   widget->allocation = *allocation;
611 
612   if (orientation == GTK_ORIENTATION_HORIZONTAL)
613     width = allocation->width - GTK_CONTAINER (box)->border_width*2;
614   else
615     height = allocation->height - GTK_CONTAINER (box)->border_width*2;
616 
617   switch (layout)
618     {
619       case GTK_BUTTONBOX_SPREAD:
620 
621         if (orientation == GTK_ORIENTATION_HORIZONTAL)
622           {
623             childspacing = (width - (nvis_children * child_width))
624                     / (nvis_children + 1);
625             x = allocation->x + GTK_CONTAINER (box)->border_width
626                     + childspacing;
627             secondary_x = x + ((nvis_children - n_secondaries)
628                             * (child_width + childspacing));
629           }
630         else
631           {
632             childspacing = (height - (nvis_children * child_height))
633                     / (nvis_children + 1);
634             y = allocation->y + GTK_CONTAINER (box)->border_width
635                     + childspacing;
636             secondary_y = y + ((nvis_children - n_secondaries)
637                             * (child_height + childspacing));
638           }
639 
640         break;
641 
642       case GTK_BUTTONBOX_EDGE:
643 
644         if (orientation == GTK_ORIENTATION_HORIZONTAL)
645           {
646             if (nvis_children >= 2)
647               {
648                 childspacing = (width - (nvis_children * child_width))
649                       / (nvis_children - 1);
650                 x = allocation->x + GTK_CONTAINER (box)->border_width;
651                 secondary_x = x + ((nvis_children - n_secondaries)
652                                    * (child_width + childspacing));
653               }
654             else
655               {
656                 /* one or zero children, just center */
657                 childspacing = width;
658                 x = secondary_x = allocation->x
659                       + (allocation->width - child_width) / 2;
660               }
661           }
662         else
663           {
664             if (nvis_children >= 2)
665               {
666                 childspacing = (height - (nvis_children*child_height))
667                         / (nvis_children-1);
668                 y = allocation->y + GTK_CONTAINER (box)->border_width;
669                 secondary_y = y + ((nvis_children - n_secondaries)
670                                 * (child_height + childspacing));
671               }
672             else
673               {
674                 /* one or zero children, just center */
675                 childspacing = height;
676                 y = secondary_y = allocation->y
677                         + (allocation->height - child_height) / 2;
678               }
679           }
680 
681         break;
682 
683       case GTK_BUTTONBOX_START:
684 
685         if (orientation == GTK_ORIENTATION_HORIZONTAL)
686           {
687             childspacing = spacing;
688             x = allocation->x + GTK_CONTAINER (box)->border_width;
689             secondary_x = allocation->x + allocation->width
690               - child_width * n_secondaries
691               - spacing * (n_secondaries - 1)
692               - GTK_CONTAINER (box)->border_width;
693           }
694         else
695           {
696             childspacing = spacing;
697             y = allocation->y + GTK_CONTAINER (box)->border_width;
698             secondary_y = allocation->y + allocation->height
699               - child_height * n_secondaries
700               - spacing * (n_secondaries - 1)
701               - GTK_CONTAINER (box)->border_width;
702           }
703 
704         break;
705 
706       case GTK_BUTTONBOX_END:
707 
708         if (orientation == GTK_ORIENTATION_HORIZONTAL)
709           {
710             childspacing = spacing;
711             x = allocation->x + allocation->width
712               - child_width * (nvis_children - n_secondaries)
713               - spacing * (nvis_children - n_secondaries - 1)
714               - GTK_CONTAINER (box)->border_width;
715             secondary_x = allocation->x + GTK_CONTAINER (box)->border_width;
716           }
717         else
718           {
719             childspacing = spacing;
720             y = allocation->y + allocation->height
721               - child_height * (nvis_children - n_secondaries)
722               - spacing * (nvis_children - n_secondaries - 1)
723               - GTK_CONTAINER (box)->border_width;
724             secondary_y = allocation->y + GTK_CONTAINER (box)->border_width;
725           }
726 
727         break;
728 
729       case GTK_BUTTONBOX_CENTER:
730 
731         if (orientation == GTK_ORIENTATION_HORIZONTAL)
732           {
733             childspacing = spacing;
734             x = allocation->x +
735               (allocation->width
736                - (child_width * (nvis_children - n_secondaries)
737                + spacing * (nvis_children - n_secondaries - 1))) / 2
738               + (n_secondaries * child_width + n_secondaries * spacing) / 2;
739             secondary_x = allocation->x + GTK_CONTAINER (box)->border_width;
740           }
741         else
742           {
743             childspacing = spacing;
744             y = allocation->y +
745               (allocation->height
746                - (child_height * (nvis_children - n_secondaries)
747                   + spacing * (nvis_children - n_secondaries - 1))) / 2
748               + (n_secondaries * child_height + n_secondaries * spacing) / 2;
749             secondary_y = allocation->y + GTK_CONTAINER (box)->border_width;
750           }
751 
752         break;
753 
754       default:
755         g_assert_not_reached ();
756         break;
757     }
758 
759     if (orientation == GTK_ORIENTATION_HORIZONTAL)
760       {
761         y = allocation->y + (allocation->height - child_height) / 2;
762         childspace = child_width + childspacing;
763       }
764     else
765       {
766         x = allocation->x + (allocation->width - child_width) / 2;
767         childspace = child_height + childspacing;
768       }
769 
770   children = GTK_BOX (box)->children;
771 
772   while (children)
773     {
774       child = children->data;
775       children = children->next;
776 
777       if (gtk_widget_get_visible (child->widget))
778         {
779           child_allocation.width = child_width;
780           child_allocation.height = child_height;
781 
782           if (orientation == GTK_ORIENTATION_HORIZONTAL)
783             {
784               child_allocation.y = y;
785 
786               if (child->is_secondary)
787                 {
788                   child_allocation.x = secondary_x;
789                   secondary_x += childspace;
790                 }
791               else
792                 {
793                   child_allocation.x = x;
794                   x += childspace;
795                 }
796 
797               if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
798                   child_allocation.x = (allocation->x + allocation->width)
799                           - (child_allocation.x + child_width - allocation->x);
800             }
801           else
802             {
803               child_allocation.x = x;
804 
805               if (child->is_secondary)
806                 {
807                   child_allocation.y = secondary_y;
808                   secondary_y += childspace;
809                 }
810               else
811                 {
812                   child_allocation.y = y;
813                   y += childspace;
814                 }
815             }
816 
817           gtk_widget_size_allocate (child->widget, &child_allocation);
818         }
819     }
820 }
821 
822 #define __GTK_BUTTON_BOX_C__
823 #include "gtkaliasdef.c"
824