]> Pileus Git - ~andy/gtk/blob - gtk/gtkbbox.c
Remove depth restriction from gtk_combo_box_set_active_iter docs
[~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 (gtk_widget_get_parent (child) == 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  */
400 static void
401 gtk_button_box_child_requisition (GtkWidget  *widget,
402                                   gint       *nvis_children,
403                                   gint       *nvis_secondaries,
404                                   gint      **widths,
405                                   gint      **heights)
406 {
407   GtkButtonBoxPriv *priv;
408   GtkButtonBox *bbox;
409   GList *children, *list;
410   gint nchildren;
411   gint nsecondaries;
412   gint needed_width;
413   gint needed_height;
414   gint avg_w, avg_h;
415   GtkRequisition child_requisition;
416   gint ipad_w;
417   gint ipad_h;
418   gint child_min_width;
419   gint child_min_height;
420   gint ipad_x;
421   gint ipad_y;
422   gboolean homogeneous;
423   gint i;
424
425   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
426
427   bbox = GTK_BUTTON_BOX (widget);
428   priv = bbox->priv;
429
430   homogeneous = gtk_box_get_homogeneous (GTK_BOX (widget));
431
432   gtk_widget_style_get (widget,
433                         "child-min-width", &child_min_width,
434                         "child-min-height", &child_min_height,
435                         "child-internal-pad-x", &ipad_x,
436                         "child-internal-pad-y", &ipad_y,
437                         NULL);
438
439   nchildren = 0;
440   nsecondaries = 0;
441   list = children = _gtk_box_get_children (GTK_BOX (bbox));
442   needed_width = child_min_width;
443   needed_height = child_min_height;
444   ipad_w = ipad_x * 2;
445   ipad_h = ipad_y * 2;
446
447   avg_w = avg_h = 0;
448   while (children)
449     {
450       GtkWidget *child;
451
452       child = children->data;
453       children = children->next;
454
455       if (gtk_widget_get_visible (child))
456         {
457           nchildren += 1;
458           gtk_widget_size_request (child, &child_requisition);
459           avg_w += child_requisition.width + ipad_w;
460           avg_h += child_requisition.height + ipad_h;
461         }
462     }
463   avg_w /= nchildren;
464   avg_h /= nchildren;
465
466   *widths = g_new (gint, nchildren);
467   *heights = g_new (gint, nchildren);
468
469   i = 0;
470   children = list;
471   while (children)
472     {
473       GtkWidget *child;
474       gboolean is_secondary;
475
476       child = children->data;
477       children = children->next;
478
479       if (gtk_widget_get_visible (child))
480         {
481           is_secondary = gtk_button_box_get_child_secondary (bbox, child);
482           if (is_secondary)
483             nsecondaries++;
484
485           gtk_widget_get_child_requisition (child, &child_requisition);
486
487           if (homogeneous ||
488               (child_requisition.width + ipad_w < avg_w * 1.5)) /* &&
489                child_requisition.width + ipad_w > avg_w / 1.5)) */
490             {
491               (*widths)[i] = -1;
492               if (child_requisition.width + ipad_w > needed_width)
493                 needed_width = child_requisition.width + ipad_w;
494             }
495           else
496             {
497               (*widths)[i] = child_requisition.width + ipad_w;
498             }
499
500           if (homogeneous ||
501               (child_requisition.height + ipad_h < avg_h * 1.5)) /* &&
502                child_requisition.height + ipad_h > avg_h / 1.5)) */
503             {
504               (*heights)[i] = -1;
505               if (child_requisition.height + ipad_h > needed_height)
506                 needed_height = child_requisition.height + ipad_h;
507             }
508           else
509             {
510               (*heights)[i] = child_requisition.height + ipad_h;
511             }
512
513           i++;
514         }
515     }
516
517   g_list_free (list);
518
519   for (i = 0; i < nchildren; i++)
520     {
521       if ((*widths)[i] == -1)
522         (*widths)[i] = needed_width;
523       if ((*heights)[i] == -1)
524         (*heights)[i] = needed_height;
525     }
526
527   if (nvis_children)
528     *nvis_children = nchildren;
529
530   if (nvis_secondaries)
531     *nvis_secondaries = nsecondaries;
532 }
533
534 static void
535 gtk_button_box_size_request (GtkWidget      *widget,
536                              GtkRequisition *requisition)
537 {
538   GtkButtonBoxPriv *priv;
539   GtkButtonBox *bbox;
540   gint nvis_children;
541   gint max_size;
542   gint total_size;
543   gint spacing;
544   guint border_width;
545   GtkOrientation orientation;
546   gint *widths;
547   gint *heights;
548   gint i;
549
550   bbox = GTK_BUTTON_BOX (widget);
551   priv = bbox->priv;
552
553   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
554   spacing = gtk_box_get_spacing (GTK_BOX (widget));
555
556   gtk_button_box_child_requisition (widget,
557                                     &nvis_children,
558                                     NULL,
559                                     &widths, &heights);
560
561   max_size = 0;
562   total_size = 0;
563   for (i = 0; i < nvis_children; i++)
564     {
565       if (orientation == GTK_ORIENTATION_HORIZONTAL)
566         {
567           total_size += widths[i];
568           max_size = MAX (max_size, heights[i]);
569         }
570       else
571         {
572           total_size += heights[i];
573           max_size = MAX (max_size, widths[i]);
574         }
575     }
576   g_free (widths);
577   g_free (heights);
578
579   if (nvis_children == 0)
580     {
581       requisition->width = 0;
582       requisition->height = 0;
583     }
584   else
585     {
586       switch (priv->layout_style)
587         {
588           case GTK_BUTTONBOX_SPREAD:
589             if (orientation == GTK_ORIENTATION_HORIZONTAL)
590               requisition->width = total_size + ((nvis_children + 1)*spacing);
591             else
592               requisition->height = total_size + ((nvis_children + 1)*spacing);
593
594             break;
595           case GTK_BUTTONBOX_EDGE:
596           case GTK_BUTTONBOX_START:
597           case GTK_BUTTONBOX_END:
598           case GTK_BUTTONBOX_CENTER:
599             if (orientation == GTK_ORIENTATION_HORIZONTAL)
600               requisition->width = total_size + ((nvis_children - 1)*spacing);
601             else
602               requisition->height = total_size + ((nvis_children - 1)*spacing);
603
604             break;
605           default:
606             g_assert_not_reached ();
607             break;
608         }
609
610       if (orientation == GTK_ORIENTATION_HORIZONTAL)
611         requisition->height = max_size;
612       else
613         requisition->width = max_size;
614     }
615
616   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
617   requisition->width += border_width * 2;
618   requisition->height += border_width * 2;
619 }
620
621 static void
622 gtk_button_box_size_allocate (GtkWidget     *widget,
623                               GtkAllocation *allocation)
624 {
625   GtkButtonBoxPriv *priv;
626   GtkButtonBox *bbox;
627   GList *children, *list;
628   GtkAllocation child_allocation;
629   gint nvis_children;
630   gint n_primaries;
631   gint n_secondaries;
632   gint x = 0;
633   gint y = 0;
634   gint secondary_x = 0;
635   gint secondary_y = 0;
636   gint width = 0;
637   gint height = 0;
638   gint childspacing = 0;
639   gint spacing;
640   guint border_width;
641   GtkOrientation orientation;
642   gint ipad_x, ipad_y;
643   gint *widths;
644   gint *heights;
645   gint *sizes;
646   gint primary_size;
647   gint secondary_size;
648   gint total_size;
649   gint i;
650
651   bbox = GTK_BUTTON_BOX (widget);
652   priv = bbox->priv;
653
654   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
655   orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
656   spacing = gtk_box_get_spacing (GTK_BOX (widget));
657
658   gtk_widget_style_get (widget,
659                         "child-internal-pad-x", &ipad_x,
660                         "child-internal-pad-y", &ipad_y,
661                         NULL);
662   gtk_button_box_child_requisition (widget,
663                                     &nvis_children,
664                                     &n_secondaries,
665                                     &widths, &heights);
666
667   n_primaries = nvis_children - n_secondaries;
668   primary_size = 0;
669   secondary_size = 0;
670   if (orientation == GTK_ORIENTATION_HORIZONTAL)
671     sizes = widths;
672   else
673     sizes = heights;
674
675   i = 0;
676   list = children = _gtk_box_get_children (GTK_BOX (widget));
677   while (children)
678     {
679       GtkWidget *child;
680
681       child = children->data;
682       children = children->next;
683
684       if (gtk_widget_get_visible (child))
685         {
686           if (gtk_button_box_get_child_secondary (bbox, child))
687             secondary_size += sizes[i];
688           else
689             primary_size += sizes[i];
690           i++;
691         }
692     }
693   total_size = primary_size + secondary_size;
694
695   gtk_widget_set_allocation (widget, allocation);
696
697   if (orientation == GTK_ORIENTATION_HORIZONTAL)
698     width = allocation->width - border_width*2;
699   else
700     height = allocation->height - border_width*2;
701
702   switch (priv->layout_style)
703     {
704       case GTK_BUTTONBOX_SPREAD:
705
706         if (orientation == GTK_ORIENTATION_HORIZONTAL)
707           {
708             childspacing = (width - total_size) / (nvis_children + 1);
709             x = allocation->x + border_width + childspacing;
710             secondary_x = x + primary_size + n_primaries * childspacing;
711           }
712         else
713           {
714             childspacing = (height - total_size) / (nvis_children + 1);
715             y = allocation->y + border_width + childspacing;
716             secondary_y = y + primary_size + n_primaries * childspacing;
717           }
718
719         break;
720
721       case GTK_BUTTONBOX_EDGE:
722
723         if (orientation == GTK_ORIENTATION_HORIZONTAL)
724           {
725             if (nvis_children >= 2)
726               {
727                 childspacing = (width - total_size) / (nvis_children - 1);
728                 x = allocation->x + border_width;
729                 secondary_x = x + primary_size + n_primaries * childspacing;
730               }
731             else
732               {
733                 /* one or zero children, just center */
734                 childspacing = width;
735                 x = secondary_x = allocation->x
736                                   + (allocation->width - widths[0]) / 2;
737               }
738           }
739         else
740           {
741             if (nvis_children >= 2)
742               {
743                 childspacing = (height - total_size) / (nvis_children - 1);
744                 y = allocation->y + border_width;
745                 secondary_y = y + primary_size + n_primaries * childspacing;
746               }
747             else
748               {
749                 /* one or zero children, just center */
750                 childspacing = height;
751                 y = secondary_y = allocation->y
752                         + (allocation->height - heights[0]) / 2;
753               }
754           }
755
756         break;
757
758       case GTK_BUTTONBOX_START:
759
760         if (orientation == GTK_ORIENTATION_HORIZONTAL)
761           {
762             childspacing = spacing;
763             x = allocation->x + border_width;
764             secondary_x = allocation->x + allocation->width
765               - secondary_size - spacing * (n_secondaries - 1) - border_width;
766           }
767         else
768           {
769             childspacing = spacing;
770             y = allocation->y + border_width;
771             secondary_y = allocation->y + allocation->height
772               - secondary_size - spacing * (n_secondaries - 1) - border_width;
773           }
774
775         break;
776
777       case GTK_BUTTONBOX_END:
778
779         if (orientation == GTK_ORIENTATION_HORIZONTAL)
780           {
781             childspacing = spacing;
782             x = allocation->x + allocation->width
783               - primary_size - spacing * (n_primaries - 1) - border_width;
784             secondary_x = allocation->x + border_width;
785           }
786         else
787           {
788             childspacing = spacing;
789             y = allocation->y + allocation->height
790               - primary_size - spacing * (n_primaries - 1) - border_width;
791             secondary_y = allocation->y + border_width;
792           }
793
794         break;
795
796       case GTK_BUTTONBOX_CENTER:
797
798         if (orientation == GTK_ORIENTATION_HORIZONTAL)
799           {
800             childspacing = spacing;
801             x = allocation->x +
802               (allocation->width
803                - (primary_size + spacing * (n_primaries - 1))) / 2
804               + (secondary_size + n_secondaries * spacing) / 2;
805             secondary_x = allocation->x + border_width;
806           }
807         else
808           {
809             childspacing = spacing;
810             y = allocation->y +
811               (allocation->height
812                - (primary_size + spacing * (n_primaries - 1))) / 2
813               + (secondary_size + n_secondaries * spacing) / 2;
814             secondary_y = allocation->y + border_width;
815           }
816
817         break;
818
819       default:
820         g_assert_not_reached ();
821         break;
822     }
823
824   children = list;
825   i = 0;
826   while (children)
827     {
828       GtkWidget *child;
829
830       child = children->data;
831       children = children->next;
832
833       if (gtk_widget_get_visible (child))
834         {
835           child_allocation.width = widths[i];
836           child_allocation.height = heights[i];
837
838           if (orientation == GTK_ORIENTATION_HORIZONTAL)
839             {
840               child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
841
842               if (gtk_button_box_get_child_secondary (bbox, child))
843                 {
844                   child_allocation.x = secondary_x;
845                   secondary_x += child_allocation.width + childspacing;
846                 }
847               else
848                 {
849                   child_allocation.x = x;
850                   x += child_allocation.width + childspacing;
851                 }
852
853               if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
854                   child_allocation.x = (allocation->x + allocation->width)
855                           - (child_allocation.x + child_allocation.width - allocation->x);
856             }
857           else
858             {
859               child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2;
860
861               if (gtk_button_box_get_child_secondary (bbox, child))
862                 {
863                   child_allocation.y = secondary_y;
864                   secondary_y += child_allocation.height + childspacing;
865                 }
866               else
867                 {
868                   child_allocation.y = y;
869                   y += child_allocation.height + childspacing;
870                 }
871             }
872
873           gtk_widget_size_allocate (child, &child_allocation);
874           i++;
875         }
876     }
877
878   g_list_free (list);
879   g_free (widths);
880   g_free (heights);
881 }
882
883 /**
884  * gtk_button_box_new:
885  * @orientation: the box' orientation.
886  *
887  * Creates a new #GtkButtonBox.
888  *
889  * Return value: a new #GtkButtonBox.
890  *
891  * Since: 3.0
892  */
893 GtkWidget *
894 gtk_button_box_new (GtkOrientation orientation)
895 {
896   return g_object_new (GTK_TYPE_BUTTON_BOX,
897                        "orientation", orientation,
898                        NULL);
899 }