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