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