+
+ g_list_free (list);
+
+ for (i = 0; i < nchildren; i++)
+ {
+ if ((*widths)[i] == -1)
+ (*widths)[i] = needed_width;
+ if ((*heights)[i] == -1)
+ (*heights)[i] = needed_height;
+ }
+
+ if (nvis_children)
+ *nvis_children = nchildren;
+
+ if (nvis_secondaries)
+ *nvis_secondaries = nsecondaries;
+}
+
+static void
+gtk_button_box_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkButtonBoxPrivate *priv;
+ GtkButtonBox *bbox;
+ gint nvis_children;
+ gint max_size;
+ gint total_size;
+ gint spacing;
+ GtkOrientation orientation;
+ gint *widths;
+ gint *heights;
+ gint i;
+
+ bbox = GTK_BUTTON_BOX (widget);
+ priv = bbox->priv;
+
+ orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
+ spacing = gtk_box_get_spacing (GTK_BOX (widget));
+
+ gtk_button_box_child_requisition (widget,
+ &nvis_children,
+ NULL,
+ &widths, &heights);
+
+ max_size = 0;
+ total_size = 0;
+ for (i = 0; i < nvis_children; i++)
+ {
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ total_size += widths[i];
+ max_size = MAX (max_size, heights[i]);
+ }
+ else
+ {
+ total_size += heights[i];
+ max_size = MAX (max_size, widths[i]);
+ }
+ }
+ g_free (widths);
+ g_free (heights);
+
+ if (nvis_children == 0)
+ {
+ requisition->width = 0;
+ requisition->height = 0;
+ }
+ else
+ {
+ switch (priv->layout_style)
+ {
+ case GTK_BUTTONBOX_SPREAD:
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ requisition->width = total_size + ((nvis_children + 1)*spacing);
+ else
+ requisition->height = total_size + ((nvis_children + 1)*spacing);
+
+ break;
+ case GTK_BUTTONBOX_EDGE:
+ case GTK_BUTTONBOX_START:
+ case GTK_BUTTONBOX_END:
+ case GTK_BUTTONBOX_CENTER:
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ requisition->width = total_size + ((nvis_children - 1)*spacing);
+ else
+ requisition->height = total_size + ((nvis_children - 1)*spacing);
+
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ requisition->height = max_size;
+ else
+ requisition->width = max_size;
+ }
+}
+
+static void
+gtk_button_box_get_preferred_width (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ GtkRequisition requisition;
+
+ gtk_button_box_size_request (widget, &requisition);
+
+ *minimum = *natural = requisition.width;
+}
+
+static void
+gtk_button_box_get_preferred_height (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ GtkRequisition requisition;
+
+ gtk_button_box_size_request (widget, &requisition);
+
+ *minimum = *natural = requisition.height;
+}
+
+static void
+gtk_button_box_get_preferred_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_button_box_get_preferred_width (widget, minimum, natural);
+}
+
+static void
+gtk_button_box_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum,
+ gint *natural)
+{
+ gtk_button_box_get_preferred_height (widget, minimum, natural);
+}
+
+static void
+gtk_button_box_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkButtonBoxPrivate *priv;
+ GtkButtonBox *bbox;
+ GList *children, *list;
+ GtkAllocation child_allocation;
+ gint nvis_children;
+ gint n_primaries;
+ gint n_secondaries;
+ gint x = 0;
+ gint y = 0;
+ gint secondary_x = 0;
+ gint secondary_y = 0;
+ gint width = 0;
+ gint height = 0;
+ gint childspacing = 0;
+ gint spacing;
+ GtkOrientation orientation;
+ gint ipad_x, ipad_y;
+ gint *widths;
+ gint *heights;
+ gint *sizes;
+ gint primary_size;
+ gint secondary_size;
+ gint total_size;
+ gint i;
+
+ bbox = GTK_BUTTON_BOX (widget);
+ priv = bbox->priv;
+
+ orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (widget));
+ spacing = gtk_box_get_spacing (GTK_BOX (widget));
+
+ gtk_widget_style_get (widget,
+ "child-internal-pad-x", &ipad_x,
+ "child-internal-pad-y", &ipad_y,
+ NULL);
+ gtk_button_box_child_requisition (widget,
+ &nvis_children,
+ &n_secondaries,
+ &widths, &heights);
+
+ n_primaries = nvis_children - n_secondaries;
+ primary_size = 0;
+ secondary_size = 0;
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ sizes = widths;
+ else
+ sizes = heights;
+
+ i = 0;
+ list = children = _gtk_box_get_children (GTK_BOX (widget));
+ while (children)
+ {
+ GtkWidget *child;
+
+ child = children->data;
+ children = children->next;
+
+ if (gtk_widget_get_visible (child))
+ {
+ if (gtk_button_box_get_child_secondary (bbox, child))
+ secondary_size += sizes[i];
+ else
+ primary_size += sizes[i];
+ i++;
+ }
+ }
+ total_size = primary_size + secondary_size;
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ width = allocation->width;
+ else
+ height = allocation->height;
+
+ switch (priv->layout_style)
+ {
+ case GTK_BUTTONBOX_SPREAD:
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ childspacing = (width - total_size) / (nvis_children + 1);
+ x = allocation->x + childspacing;
+ secondary_x = x + primary_size + n_primaries * childspacing;
+ }
+ else
+ {
+ childspacing = (height - total_size) / (nvis_children + 1);
+ y = allocation->y + childspacing;
+ secondary_y = y + primary_size + n_primaries * childspacing;
+ }
+
+ break;
+
+ case GTK_BUTTONBOX_EDGE:
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (nvis_children >= 2)
+ {
+ childspacing = (width - total_size) / (nvis_children - 1);
+ x = allocation->x;
+ secondary_x = x + primary_size + n_primaries * childspacing;
+ }
+ else if (nvis_children == 1)
+ {
+ /* one child, just center */
+ childspacing = width;
+ x = secondary_x = allocation->x
+ + (allocation->width - widths[0]) / 2;
+ }
+ else
+ {
+ /* zero children, meh */
+ childspacing = width;
+ x = secondary_x = allocation->x + allocation->width / 2;
+ }
+ }
+ else
+ {
+ if (nvis_children >= 2)
+ {
+ childspacing = (height - total_size) / (nvis_children - 1);
+ y = allocation->y;
+ secondary_y = y + primary_size + n_primaries * childspacing;
+ }
+ else if (nvis_children == 1)
+ {
+ /* one child, just center */
+ childspacing = height;
+ y = secondary_y = allocation->y
+ + (allocation->height - heights[0]) / 2;
+ }
+ else
+ {
+ /* zero children, meh */
+ childspacing = height;
+ y = secondary_y = allocation->y + allocation->height / 2;
+ }
+ }
+
+ break;
+
+ case GTK_BUTTONBOX_START:
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ childspacing = spacing;
+ x = allocation->x;
+ secondary_x = allocation->x + allocation->width
+ - secondary_size - spacing * (n_secondaries - 1);
+ }
+ else
+ {
+ childspacing = spacing;
+ y = allocation->y;
+ secondary_y = allocation->y + allocation->height
+ - secondary_size - spacing * (n_secondaries - 1);
+ }
+
+ break;
+
+ case GTK_BUTTONBOX_END:
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ childspacing = spacing;
+ x = allocation->x + allocation->width
+ - primary_size - spacing * (n_primaries - 1);
+ secondary_x = allocation->x;
+ }
+ else
+ {
+ childspacing = spacing;
+ y = allocation->y + allocation->height
+ - primary_size - spacing * (n_primaries - 1);
+ secondary_y = allocation->y;
+ }
+
+ break;
+
+ case GTK_BUTTONBOX_CENTER:
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ childspacing = spacing;
+ x = allocation->x +
+ (allocation->width
+ - (primary_size + spacing * (n_primaries - 1))) / 2
+ + (secondary_size + n_secondaries * spacing) / 2;
+ secondary_x = allocation->x;
+ }
+ else
+ {
+ childspacing = spacing;
+ y = allocation->y +
+ (allocation->height
+ - (primary_size + spacing * (n_primaries - 1))) / 2
+ + (secondary_size + n_secondaries * spacing) / 2;
+ secondary_y = allocation->y;
+ }
+
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ children = list;
+ i = 0;
+ while (children)
+ {
+ GtkWidget *child;
+
+ child = children->data;
+ children = children->next;
+
+ if (gtk_widget_get_visible (child))
+ {
+ child_allocation.width = widths[i];
+ child_allocation.height = heights[i];
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
+
+ if (gtk_button_box_get_child_secondary (bbox, child))
+ {
+ child_allocation.x = secondary_x;
+ secondary_x += child_allocation.width + childspacing;
+ }
+ else
+ {
+ child_allocation.x = x;
+ x += child_allocation.width + childspacing;
+ }
+
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ child_allocation.x = (allocation->x + allocation->width)
+ - (child_allocation.x + child_allocation.width - allocation->x);
+ }
+ else
+ {
+ child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2;
+
+ if (gtk_button_box_get_child_secondary (bbox, child))
+ {
+ child_allocation.y = secondary_y;
+ secondary_y += child_allocation.height + childspacing;
+ }
+ else
+ {
+ child_allocation.y = y;
+ y += child_allocation.height + childspacing;
+ }
+ }
+
+ gtk_widget_size_allocate (child, &child_allocation);
+ i++;
+ }
+ }
+
+ g_list_free (list);
+ g_free (widths);
+ g_free (heights);
+}
+
+/**
+ * gtk_button_box_new:
+ * @orientation: the box' orientation.
+ *
+ * Creates a new #GtkButtonBox.
+ *
+ * Return value: a new #GtkButtonBox.
+ *
+ * Since: 3.0
+ */
+GtkWidget *
+gtk_button_box_new (GtkOrientation orientation)
+{
+ return g_object_new (GTK_TYPE_BUTTON_BOX,
+ "orientation", orientation,
+ NULL);
+}
+
+/**
+ * gtk_button_box_get_child_non_homogeneous:
+ * @widget: a #GtkButtonBox
+ * @child: a child of @widget
+ *
+ * Returns whether the child is exempted from homogenous
+ * sizing.
+ *
+ * Returns: %TRUE if the child is not subject to homogenous sizing
+ *
+ * Since: 3.2
+ */
+gboolean
+gtk_button_box_get_child_non_homogeneous (GtkButtonBox *widget,
+ GtkWidget *child)
+{
+ g_return_val_if_fail (GTK_IS_BUTTON_BOX (widget), FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
+
+ return (g_object_get_data (G_OBJECT (child), GTK_BOX_NON_HOMOGENEOUS) != NULL);
+}
+
+/**
+ * gtk_button_box_set_child_non_homogeneous:
+ * @widget: a #GtkButtonBox
+ * @child: a child of @widget
+ * @non_homogeneous: the new value
+ *
+ * Sets whether the child is exempted from homogeous sizing.
+ *
+ * Since: 3.2
+ */
+void
+gtk_button_box_set_child_non_homogeneous (GtkButtonBox *widget,
+ GtkWidget *child,
+ gboolean non_homogeneous)
+{
+ g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
+ g_return_if_fail (GTK_IS_WIDGET (child));
+ g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (widget));
+
+ g_object_set_data (G_OBJECT (child),
+ GTK_BOX_NON_HOMOGENEOUS,
+ non_homogeneous ? GINT_TO_POINTER (1) : NULL);
+ gtk_widget_child_notify (child, "non-homogeneous");
+
+ if (gtk_widget_get_visible (GTK_WIDGET (widget)) &&
+ gtk_widget_get_visible (child))
+ gtk_widget_queue_resize (child);