PROP_0,
PROP_SPACING,
PROP_HOMOGENEOUS,
+ PROP_BASELINE_CHILD,
PROP_BASELINE_POSITION,
/* orientable */
case PROP_SPACING:
gtk_box_set_spacing (box, g_value_get_int (value));
break;
+ case PROP_BASELINE_CHILD:
+ gtk_box_set_baseline_child (box, g_value_get_int (value));
+ break;
case PROP_BASELINE_POSITION:
gtk_box_set_baseline_position (box, g_value_get_enum (value));
break;
case PROP_SPACING:
g_value_set_int (value, gtk_box_layout_get_spacing (box_layout));
break;
+ case PROP_BASELINE_CHILD:
+ g_value_set_int (value, gtk_box_layout_get_baseline_child (box_layout));
+ break;
case PROP_BASELINE_POSITION:
g_value_set_enum (value, gtk_box_layout_get_baseline_position (box_layout));
break;
FALSE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ /**
+ * GtkBox:baseline-child: (attributes org.gtk.Property.get=gtk_box_get_baseline_child org.gtk.Property.set=gtk_box_set_baseline_child)
+ *
+ * The child that determines the baseline, in vertical orientation.
+ *
+ * Since: 4.12
+ */
+ props[PROP_BASELINE_CHILD] =
+ g_param_spec_int ("baseline-child", NULL, NULL,
+ -1, G_MAXINT, -1,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
/**
* GtkBox:baseline-position: (attributes org.gtk.Property.get=gtk_box_get_baseline_position org.gtk.Property.set=gtk_box_set_baseline_position)
*
return gtk_box_layout_get_spacing (GTK_BOX_LAYOUT (box_layout));
}
+/**
+ * gtk_box_set_baseline_child: (attributes org.gtk.Method.set_property=baseline-child)
+ * @box: a `GtkBox`
+ * @child: a child, or -1
+ *
+ * Sets the baseline child of a box.
+ *
+ * This affects only vertical boxes.
+ *
+ * Since: 4.12
+ */
+void
+gtk_box_set_baseline_child (GtkBox *box,
+ int child)
+{
+ GtkBoxLayout *box_layout;
+
+ g_return_if_fail (GTK_IS_BOX (box));
+ g_return_if_fail (child >= -1);
+
+ box_layout = GTK_BOX_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (box)));
+ if (child == gtk_box_layout_get_baseline_child (box_layout))
+ return;
+
+ gtk_box_layout_set_baseline_child (box_layout, child);
+ g_object_notify_by_pspec (G_OBJECT (box), props[PROP_BASELINE_CHILD]);
+ gtk_widget_queue_resize (GTK_WIDGET (box));
+}
+
+/**
+ * gtk_box_get_baseline_child: (attributes org.gtk.Method.get_property=baseline-child)
+ * @box: a `GtkBox`
+ *
+ * Gets the value set by gtk_box_set_baseline_child().
+ *
+ * Returns: the baseline child
+ *
+ * Since: 4.12
+ */
+int
+gtk_box_get_baseline_child (GtkBox *box)
+{
+ GtkLayoutManager *box_layout;
+
+ g_return_val_if_fail (GTK_IS_BOX (box), -1);
+
+ box_layout = gtk_widget_get_layout_manager (GTK_WIDGET (box));
+
+ return gtk_box_layout_get_baseline_child (GTK_BOX_LAYOUT (box_layout));
+}
+
/**
* gtk_box_set_baseline_position: (attributes org.gtk.Method.set_property=baseline-position)
* @box: a `GtkBox`
guint spacing;
GtkOrientation orientation;
GtkBaselinePosition baseline_position;
+ int baseline_child;
};
G_DEFINE_TYPE_WITH_CODE (GtkBoxLayout, gtk_box_layout, GTK_TYPE_LAYOUT_MANAGER,
enum {
PROP_HOMOGENEOUS = 1,
PROP_SPACING,
+ PROP_BASELINE_CHILD,
PROP_BASELINE_POSITION,
/* From GtkOrientable */
gtk_box_layout_set_spacing (self, g_value_get_int (value));
break;
+ case PROP_BASELINE_CHILD:
+ gtk_box_layout_set_baseline_child (self, g_value_get_int (value));
+ break;
+
case PROP_BASELINE_POSITION:
gtk_box_layout_set_baseline_position (self, g_value_get_enum (value));
break;
g_value_set_int (value, box_layout->spacing);
break;
+ case PROP_BASELINE_CHILD:
+ g_value_set_int (value, box_layout->baseline_child);
+ break;
+
case PROP_BASELINE_POSITION:
g_value_set_enum (value, box_layout->baseline_position);
break;
GtkWidget *widget,
int for_size,
int *minimum,
- int *natural)
+ int *natural,
+ int *minimum_baseline,
+ int *natural_baseline)
{
GtkWidget *child;
int n_visible_children = 0;
int required_min = 0, required_nat = 0;
int largest_min = 0, largest_nat = 0;
int spacing = get_spacing (self, gtk_widget_get_css_node (widget));
+ int child_above_min = 0, child_above_nat = 0;
+ int above_min = 0, above_nat = 0;
+ gboolean have_baseline = FALSE;
+ int pos;
- for (child = gtk_widget_get_first_child (widget);
+ for (child = gtk_widget_get_first_child (widget), pos = 0;
child != NULL;
- child = gtk_widget_get_next_sibling (child))
+ child = gtk_widget_get_next_sibling (child), pos++)
{
int child_min = 0;
int child_nat = 0;
+ int child_min_baseline = -1;
+ int child_nat_baseline = -1;
if (!gtk_widget_should_layout (child))
continue;
gtk_widget_measure (child, self->orientation,
for_size,
&child_min, &child_nat,
- NULL, NULL);
+ &child_min_baseline, &child_nat_baseline);
largest_min = MAX (largest_min, child_min);
largest_nat = MAX (largest_nat, child_nat);
required_min += child_min;
required_nat += child_nat;
+ if (self->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ if (pos < self->baseline_child)
+ {
+ above_min += child_min;
+ above_nat += child_nat;
+ }
+ else if (pos == self->baseline_child)
+ {
+ have_baseline = TRUE;
+ if (child_min_baseline > -1)
+ {
+ child_above_min = child_min_baseline;
+ child_above_nat = child_nat_baseline;
+ }
+ else
+ {
+ child_above_min = child_min;
+ child_above_nat = child_nat;
+ }
+ }
+ }
+
n_visible_children += 1;
}
{
required_min = largest_min * n_visible_children;
required_nat = largest_nat * n_visible_children;
+
+ above_min = largest_min * MAX (self->baseline_child, 0);
+ above_nat = largest_nat * MAX (self->baseline_child, 0);
}
required_min += (n_visible_children - 1) * spacing;
required_nat += (n_visible_children - 1) * spacing;
+
+ above_min += MAX (self->baseline_child, 0) * spacing;
+ above_nat += MAX (self->baseline_child, 0) * spacing;
}
*minimum = required_min;
*natural = required_nat;
+
+ if (have_baseline)
+ {
+ *minimum_baseline = above_min + child_above_min;
+ *natural_baseline = above_nat + child_above_nat;
+ }
+ else
+ {
+ *minimum_baseline = -1;
+ *natural_baseline = -1;
+ }
}
static void
int largest_min = 0, largest_nat = 0;
int largest_min_above = -1, largest_min_below = -1;
int largest_nat_above = -1, largest_nat_below = -1;
+ gboolean have_baseline = FALSE;
for (child = gtk_widget_get_first_child (widget);
child != NULL;
{
if (child_min_baseline > -1)
{
+ have_baseline = TRUE;
largest_min_above = MAX (largest_min_above, child_min_baseline);
largest_min_below = MAX (largest_min_below, child_min - child_min_baseline);
largest_nat_above = MAX (largest_nat_above, child_nat_baseline);
*minimum = largest_min;
*natural = largest_nat;
- *min_baseline = largest_min_above;
- *nat_baseline = largest_nat_above;
+ if (have_baseline)
+ {
+ *min_baseline = largest_min_above;
+ *nat_baseline = largest_nat_above;
+ }
+ else
+ {
+ *min_baseline = -1;
+ *nat_baseline = -1;
+ }
}
/* if widgets haven't reached their min opposite size at this
&child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
- if (child_minimum_baseline >= 0)
+ if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
{
- have_baseline = TRUE;
- computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
- computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
- computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
- computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
+ if (child_minimum_baseline > -1)
+ {
+ have_baseline = TRUE;
+ computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
+ computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
+ computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
+ computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
+ }
+ else
+ {
+ computed_minimum = MAX (computed_minimum, child_minimum);
+ computed_natural = MAX (computed_natural, child_natural);
+ }
}
else
{
&child_minimum, &child_natural,
&child_minimum_baseline, &child_natural_baseline);
- if (child_minimum_baseline >= 0)
+ if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
{
- have_baseline = TRUE;
- computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
- computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
- computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
- computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
+ if (child_minimum_baseline > -1)
+ {
+ have_baseline = TRUE;
+ computed_minimum_below = MAX (computed_minimum_below, child_minimum - child_minimum_baseline);
+ computed_natural_below = MAX (computed_natural_below, child_natural - child_natural_baseline);
+ computed_minimum_above = MAX (computed_minimum_above, child_minimum_baseline);
+ computed_natural_above = MAX (computed_natural_above, child_natural_baseline);
+ }
+ else
+ {
+ computed_minimum = MAX (computed_minimum, child_minimum);
+ computed_natural = MAX (computed_natural, child_natural);
+ }
}
else
{
if (have_baseline)
{
- computed_minimum = MAX (computed_minimum, computed_minimum_below + computed_minimum_above);
- computed_natural = MAX (computed_natural, computed_natural_below + computed_natural_above);
- switch (self->baseline_position)
+ if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
{
- case GTK_BASELINE_POSITION_TOP:
- computed_minimum_baseline = computed_minimum_above;
- computed_natural_baseline = computed_natural_above;
- break;
- case GTK_BASELINE_POSITION_CENTER:
- computed_minimum_baseline = computed_minimum_above + MAX((computed_minimum - (computed_minimum_above + computed_minimum_below)) / 2, 0);
- computed_natural_baseline = computed_natural_above + MAX((computed_natural - (computed_natural_above + computed_natural_below)) / 2, 0);
- break;
- case GTK_BASELINE_POSITION_BOTTOM:
- computed_minimum_baseline = computed_minimum - computed_minimum_below;
- computed_natural_baseline = computed_natural - computed_natural_below;
- break;
- default:
- break;
+ computed_minimum = MAX (computed_minimum, computed_minimum_below + computed_minimum_above);
+ computed_natural = MAX (computed_natural, computed_natural_below + computed_natural_above);
+ switch (self->baseline_position)
+ {
+ case GTK_BASELINE_POSITION_TOP:
+ computed_minimum_baseline = computed_minimum_above;
+ computed_natural_baseline = computed_natural_above;
+ break;
+ case GTK_BASELINE_POSITION_CENTER:
+ computed_minimum_baseline = computed_minimum_above + MAX((computed_minimum - (computed_minimum_above + computed_minimum_below)) / 2, 0);
+ computed_natural_baseline = computed_natural_above + MAX((computed_natural - (computed_natural_above + computed_natural_below)) / 2, 0);
+ break;
+ case GTK_BASELINE_POSITION_BOTTOM:
+ computed_minimum_baseline = computed_minimum - computed_minimum_below;
+ computed_natural_baseline = computed_natural - computed_natural_below;
+ break;
+ default:
+ break;
+ }
}
}
else
{
gtk_box_layout_compute_size (self, widget, for_size,
- minimum, natural);
+ minimum, natural,
+ min_baseline, nat_baseline);
}
}
/* We still need to run the above loop to populate the minimum sizes for
* children that aren't going to fill.
*/
-
size_given_to_child = extra_space / nvis_children;
n_extra_widgets = extra_space % nvis_children;
}
GTK_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY);
+ /**
+ * GtkBoxLayout:baseline-child: (attributes org.gtk.Property.get=gtk_box_layout_get_baseline_child org.gtk.Property.set=gtk_box_layout_set_baseline_child)
+ *
+ * The child that determines the baseline of the box
+ * in vertical layout.
+ *
+ * If the child does baseline positioning, then its baseline
+ * is lined up with the baseline of the box. If it doesn't, then
+ * the bottom edge of the child is used.
+ *
+ * Since: 4.12
+ */
+ box_layout_props[PROP_BASELINE_CHILD] =
+ g_param_spec_int ("baseline-child", NULL, NULL,
+ -1, G_MAXINT, -1,
+ GTK_PARAM_READWRITE |
+ G_PARAM_EXPLICIT_NOTIFY);
+
/**
* GtkBoxLayout:baseline-position: (attributes org.gtk.Property.get=gtk_box_layout_get_baseline_position org.gtk.Property.set=gtk_box_layout_set_baseline_position)
*
self->spacing = 0;
self->orientation = GTK_ORIENTATION_HORIZONTAL;
self->baseline_position = GTK_BASELINE_POSITION_CENTER;
+ self->baseline_child = -1;
}
/**
return box_layout->baseline_position;
}
+
+/**
+ * gtk_box_layout_set_baseline_child: (attributes org.gtk.Method.set_property=baseline-child)
+ * @box_layout: a `GtkBoxLayout`
+ * @child: the child position, or -1
+ *
+ * Sets the index of the child that determines the baseline
+ * in vertical layout.
+ *
+ * Since: 4.12
+ */
+void
+gtk_box_layout_set_baseline_child (GtkBoxLayout *box_layout,
+ int child)
+{
+ g_return_if_fail (GTK_IS_BOX_LAYOUT (box_layout));
+ g_return_if_fail (child >= -1);
+
+ if (box_layout->baseline_child == child)
+ return;
+
+ box_layout->baseline_child = child;
+
+ g_object_notify_by_pspec (G_OBJECT (box_layout), box_layout_props[PROP_BASELINE_CHILD]);
+
+ gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (box_layout));
+}
+
+/**
+ * gtk_box_layout_get_baseline_child:
+ * @box_layout: a `GtkBoxLayout`
+ *
+ * Gets the value set by gtk_box_layout_set_baseline_child().
+ *
+ * Returns: the index of the child that determines the baseline
+ * in vertical layout, or -1
+ *
+ * Since: 4.12
+ */
+int
+gtk_box_layout_get_baseline_child (GtkBoxLayout *box_layout)
+{
+ g_return_val_if_fail (GTK_IS_BOX_LAYOUT (box_layout), -1);
+
+ return box_layout->baseline_child;
+}