* SECTION:gtkbox
* @Short_description: Base class for box containers
* @Title: GtkBox
- * @See_also:i #GtkHBox, #GtkVBox, #GtkFrame, #GtkTable, #GtkLayout
+ * @See_also: #GtkHBox, #GtkVBox, #GtkFrame, #GtkTable, #GtkLayout
*
* GtkBox is an widget which encapsulates functionality for a
* particular kind of container, one that organizes a variable number of
* of the GtkBox are forced to get the same amount of space.
*
* Use gtk_box_set_spacing() to determine how much space will be
- * minimally placed between all children in the GtkBox.
+ * minimally placed between all children in the GtkBox. Note that
+ * spacing is added <emphasis>between</emphasis> the children, while
+ * padding added by gtk_box_pack_start() or gtk_box_pack_end() is added
+ * <emphasis>on either side</emphasis> of the widget it belongs to.
*
* Use gtk_box_reorder_child() to move a GtkBox child to a different
* place in the box.
* Use gtk_box_set_child_packing() to reset the #GtkBox:expand,
* #GtkBox:fill and #GtkBox:padding child properties.
* Use gtk_box_query_child_packing() to query these fields.
+ *
+ * <note>
+ * <para>
+ * Note that a single-row or single-column #GtkGrid provides exactly the
+ * same functionality as #GtkBox.
+ * </para>
+ * </note>
*/
#include "config.h"
#include "gtkbox.h"
#include "gtkorientable.h"
#include "gtksizerequest.h"
+#include "gtktypeutils.h"
#include "gtkprivate.h"
#include "gtkintl.h"
static void gtk_box_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
+static void gtk_box_compute_expand (GtkWidget *widget,
+ gboolean *hexpand,
+ gboolean *vexpand);
+
static void gtk_box_set_property (GObject *object,
guint prop_id,
const GValue *value,
guint prop_id,
GValue *value,
GParamSpec *pspec);
-
static void gtk_box_add (GtkContainer *container,
GtkWidget *widget);
static void gtk_box_remove (GtkContainer *container,
widget_class->get_preferred_height = gtk_box_get_preferred_height;
widget_class->get_preferred_height_for_width = gtk_box_get_preferred_height_for_width;
widget_class->get_preferred_width_for_height = gtk_box_get_preferred_width_for_height;
+ widget_class->compute_expand = gtk_box_compute_expand;
container_class->add = gtk_box_add;
container_class->remove = gtk_box_remove;
if (gtk_widget_get_visible (child->widget))
{
*visible_children += 1;
- if (child->expand)
+ if (child->expand || gtk_widget_compute_expand (child->widget, private->orientation))
*expand_children += 1;
}
}
{
child_size = sizes[i].minimum_size + child->padding * 2;
- if (child->expand)
+ if (child->expand || gtk_widget_compute_expand (child->widget, private->orientation))
{
child_size += extra;
}
}
+static void
+gtk_box_compute_expand (GtkWidget *widget,
+ gboolean *hexpand_p,
+ gboolean *vexpand_p)
+{
+ GtkBoxPrivate *private = GTK_BOX (widget)->priv;
+ GList *children;
+ GtkBoxChild *child;
+ gboolean our_expand;
+ gboolean opposite_expand;
+ GtkOrientation opposite_orientation;
+
+ if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
+ opposite_orientation = GTK_ORIENTATION_VERTICAL;
+ else
+ opposite_orientation = GTK_ORIENTATION_HORIZONTAL;
+
+ our_expand = FALSE;
+ opposite_expand = FALSE;
+
+ for (children = private->children; children; children = children->next)
+ {
+ child = children->data;
+
+ /* we don't recurse into children anymore as soon as we know
+ * expand=TRUE in an orientation
+ */
+
+ if (child->expand || (!our_expand && gtk_widget_compute_expand (child->widget, private->orientation)))
+ our_expand = TRUE;
+
+ if (!opposite_expand && gtk_widget_compute_expand (child->widget, opposite_orientation))
+ opposite_expand = TRUE;
+
+ if (our_expand && opposite_expand)
+ break;
+ }
+
+ if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ *hexpand_p = our_expand;
+ *vexpand_p = opposite_expand;
+ }
+ else
+ {
+ *hexpand_p = opposite_expand;
+ *vexpand_p = our_expand;
+ }
+}
+
static GType
gtk_box_child_type (GtkContainer *container)
{
{
child_size = sizes[i].minimum_size + child->padding * 2;
- if (child->expand)
+ if (child->expand || gtk_widget_compute_expand (child->widget, private->orientation))
{
child_size += extra;
/**
* gtk_box_new:
* @orientation: the box' orientation.
- * @homogeneous: %TRUE if all children are to be given equal space allocations.
* @spacing: the number of pixels to place by default between children.
*
* Creates a new #GtkBox.
**/
GtkWidget*
gtk_box_new (GtkOrientation orientation,
- gboolean homogeneous,
gint spacing)
{
return g_object_new (GTK_TYPE_BOX,
"orientation", orientation,
"spacing", spacing,
- "homogeneous", homogeneous ? TRUE : FALSE,
NULL);
}
* gtk_box_pack_start:
* @box: a #GtkBox
* @child: the #GtkWidget to be added to @box
- * @expand: %TRUE if the new child is to be given extra space allocated to
- * @box. The extra space will be divided evenly between all children of
- * @box that use this option
+ * @expand: %TRUE if the new child is to be given extra space allocated
+ * to @box. The extra space will be divided evenly between all children
+ * that use this option
* @fill: %TRUE if space given to @child by the @expand option is
- * actually allocated to @child, rather than just padding it. This
- * parameter has no effect if @expand is set to %FALSE. A child is
- * always allocated the full height of a #GtkHBox and the full width
- * of a #GtkVBox. This option affects the other dimension
+ * actually allocated to @child, rather than just padding it. This
+ * parameter has no effect if @expand is set to %FALSE. A child is
+ * always allocated the full height of a #GtkHBox and the full width
+ * of a #GtkVBox. This option affects the other dimension
* @padding: extra space in pixels to put between this child and its
* neighbors, over and above the global amount specified by
- * #GtkBox:spacing property. If @child is a widget at one of the
- * reference ends of @box, then @padding pixels are also put between
+ * #GtkBox:spacing property. If @child is a widget at one of the
+ * reference ends of @box, then @padding pixels are also put between
* @child and the reference edge of @box
*
* Adds @child to @box, packed with reference to the start of @box.
- * The @child is packed after any other child packed with reference
+ * The @child is packed after any other child packed with reference
* to the start of @box.
*/
void
gtk_widget_freeze_child_notify (child);
if (list)
{
- child_info->expand = expand != FALSE;
- gtk_widget_child_notify (child, "expand");
+ gboolean expanded;
+
+ expanded = expand != FALSE;
+
+ /* avoid setting expand if unchanged, since queue_compute_expand
+ * can be expensive-ish
+ */
+ if (child_info->expand != expanded)
+ {
+ child_info->expand = expand != FALSE;
+ gtk_widget_queue_compute_expand (GTK_WIDGET (box));
+ gtk_widget_child_notify (child, "expand");
+ }
+
child_info->fill = fill != FALSE;
gtk_widget_child_notify (child, "fill");
child_info->padding = padding;