box gadget: Implement cross-axis alignment

So far, the box gadget is always allocating all children the
full size in the cross axis. This behavior corresponds to the
align-items: stretch behavior in
https://www.w3.org/TR/css-flexbox-1/#align-items-property
This commit implements the other modes described there.

While widgets have halign/valign properties that we can use for
this, the API for inserting gadgets has to change to take an
extra align parameter. All callers have been updated to pass
GTK_ALIGN_FILL, since that corresponds to the previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=760668
This commit is contained in:
Matthias Clasen 2016-01-15 06:47:31 -05:00
parent 662c7b87e2
commit 87171469b7
3 changed files with 131 additions and 15 deletions

View File

@ -45,6 +45,7 @@ typedef struct _GtkBoxGadgetChild GtkBoxGadgetChild;
struct _GtkBoxGadgetChild {
GObject *object;
ComputeExpandFunc compute_expand;
GtkAlign align;
};
G_DEFINE_TYPE_WITH_CODE (GtkBoxGadget, gtk_box_gadget, GTK_TYPE_CSS_GADGET,
@ -59,6 +60,26 @@ gtk_box_gadget_child_is_visible (GObject *child)
return gtk_css_gadget_get_visible (GTK_CSS_GADGET (child));
}
static GtkAlign
gtk_box_gadget_child_get_align (GtkBoxGadget *gadget,
GtkBoxGadgetChild *child)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (GTK_BOX_GADGET (gadget));
GtkAlign align;
if (GTK_IS_WIDGET (child->object))
{
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
g_object_get (child->object, "valign", &align, NULL);
else
g_object_get (child->object, "halign", &align, NULL);
}
else
align = child->align;
return align;
}
static void
gtk_box_gadget_measure_child (GObject *child,
GtkOrientation orientation,
@ -281,11 +302,69 @@ gtk_box_gadget_allocate (GtkCssGadget *gadget,
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->width, sizes);
for (i = 0 ; i < priv->children->len; i++)
if (baseline < 0)
{
for (i = 0; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
if (gtk_box_gadget_child_get_align (GTK_BOX_GADGET (gadget), child) == GTK_ALIGN_BASELINE)
{
gint child_min, child_nat;
gint child_baseline_min, child_baseline_nat;
gtk_box_gadget_measure_child (child->object,
GTK_ORIENTATION_VERTICAL,
sizes[i].minimum_size,
&child_min, &child_nat,
&child_baseline_min, &child_baseline_nat);
baseline = MAX (baseline, child_baseline_min);
}
}
}
for (i = 0; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
gint child_min, child_nat;
gint child_baseline_min, child_baseline_nat;
child_allocation.width = sizes[i].minimum_size;
gtk_box_gadget_measure_child (child->object,
GTK_ORIENTATION_VERTICAL,
child_allocation.width,
&child_min, &child_nat,
&child_baseline_min, &child_baseline_nat);
switch (gtk_box_gadget_child_get_align (GTK_BOX_GADGET (gadget), child))
{
case GTK_ALIGN_FILL:
child_allocation.height = allocation->height;
child_allocation.y = allocation->y;
break;
case GTK_ALIGN_START:
child_allocation.height = MIN(child_nat, allocation->height);
child_allocation.y = allocation->y;
break;
case GTK_ALIGN_END:
child_allocation.height = MIN(child_nat, allocation->height);
child_allocation.y = allocation->y + allocation->height - child_allocation.height;
break;
case GTK_ALIGN_BASELINE:
if (child_baseline_min >= 0 && baseline >= 0)
{
child_allocation.height = MIN(child_nat, allocation->height);
child_allocation.y = allocation->y + baseline - child_baseline_min;
break;
}
case GTK_ALIGN_CENTER:
child_allocation.height = MIN(child_nat, allocation->height);
child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2;
break;
default:
g_assert_not_reached ();
}
gtk_box_gadget_allocate_child (child->object, &child_allocation, baseline, &child_clip);
if (i == 0)
*out_clip = child_clip;
@ -297,11 +376,42 @@ gtk_box_gadget_allocate (GtkCssGadget *gadget,
else
{
gtk_box_gadget_distribute (GTK_BOX_GADGET (gadget), allocation->height, sizes);
for (i = 0 ; i < priv->children->len; i++)
{
GtkBoxGadgetChild *child = &g_array_index (priv->children, GtkBoxGadgetChild, i);
gint child_min, child_nat;
child_allocation.height = sizes[i].minimum_size;
gtk_box_gadget_measure_child (child->object,
GTK_ORIENTATION_HORIZONTAL,
child_allocation.height,
&child_min, &child_nat,
NULL, NULL);
switch (gtk_box_gadget_child_get_align (GTK_BOX_GADGET (gadget), child))
{
case GTK_ALIGN_FILL:
child_allocation.width = allocation->width;
child_allocation.x = allocation->x;
break;
case GTK_ALIGN_START:
child_allocation.width = MIN(child_nat, allocation->width);
child_allocation.x = allocation->x;
break;
case GTK_ALIGN_END:
child_allocation.width = MIN(child_nat, allocation->width);
child_allocation.x = allocation->x + allocation->width - child_allocation.width;
break;
case GTK_ALIGN_BASELINE:
case GTK_ALIGN_CENTER:
child_allocation.width = MIN(child_nat, allocation->width);
child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2;
break;
default:
g_assert_not_reached ();
}
gtk_box_gadget_allocate_child (child->object, &child_allocation, -1, &child_clip);
if (i == 0)
*out_clip = child_clip;
@ -438,13 +548,15 @@ static void
gtk_box_gadget_insert_object (GtkBoxGadget *gadget,
int pos,
GObject *object,
ComputeExpandFunc compute_expand_func)
ComputeExpandFunc compute_expand_func,
GtkAlign align)
{
GtkBoxGadgetPrivate *priv = gtk_box_gadget_get_instance_private (gadget);
GtkBoxGadgetChild child;
child.object = g_object_ref (object);
child.compute_expand = compute_expand_func;
child.align = align;
if (pos < 0 || pos >= priv->children->len)
{
@ -455,7 +567,6 @@ gtk_box_gadget_insert_object (GtkBoxGadget *gadget,
}
else
{
g_array_insert_val (priv->children, pos, child);
gtk_css_node_insert_before (gtk_css_gadget_get_node (GTK_CSS_GADGET (gadget)),
get_css_node (object),
@ -471,7 +582,8 @@ gtk_box_gadget_insert_widget (GtkBoxGadget *gadget,
gtk_box_gadget_insert_object (gadget,
pos,
G_OBJECT (widget),
(ComputeExpandFunc) gtk_widget_compute_expand);
(ComputeExpandFunc) gtk_widget_compute_expand,
GTK_ALIGN_FILL);
}
void
@ -520,13 +632,15 @@ gtk_box_gadget_insert_gadget (GtkBoxGadget *gadget,
int pos,
GtkCssGadget *cssgadget,
gboolean hexpand,
gboolean vexpand)
gboolean vexpand,
GtkAlign align)
{
gtk_box_gadget_insert_object (gadget,
pos,
G_OBJECT (cssgadget),
hexpand ? (vexpand ? (ComputeExpandFunc) gtk_true : only_horizontal)
: (vexpand ? only_vertical : (ComputeExpandFunc) gtk_false));
: (vexpand ? only_vertical : (ComputeExpandFunc) gtk_false),
align);
}
void
@ -535,4 +649,3 @@ gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget,
{
gtk_box_gadget_remove_object (gadget, G_OBJECT (cssgadget));
}

View File

@ -21,6 +21,7 @@
#define __GTK_BOX_GADGET_PRIVATE_H__
#include "gtk/gtkcssgadgetprivate.h"
#include "gtk/gtkenums.h"
G_BEGIN_DECLS
@ -65,10 +66,12 @@ void gtk_box_gadget_insert_gadget (GtkBoxGadget
int pos,
GtkCssGadget *cssgadget,
gboolean hexpand,
gboolean vexpand);
gboolean vexpand,
GtkAlign align);
void gtk_box_gadget_remove_gadget (GtkBoxGadget *gadget,
GtkCssGadget *cssgadget);
G_END_DECLS
#endif /* __GTK_BOX_GADGET_PRIVATE_H__ */

View File

@ -1312,7 +1312,7 @@ gtk_notebook_init (GtkNotebook *notebook)
NULL,
NULL);
gtk_css_gadget_set_state (priv->stack_gadget, gtk_css_node_get_state (widget_node));
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), -1, priv->stack_gadget, TRUE, TRUE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), -1, priv->stack_gadget, TRUE, TRUE, GTK_ALIGN_FILL);
priv->header_gadget = gtk_box_gadget_new ("header",
GTK_WIDGET (notebook),
@ -1321,7 +1321,7 @@ gtk_notebook_init (GtkNotebook *notebook)
gtk_css_gadget_add_class (priv->header_gadget, GTK_STYLE_CLASS_TOP);
gtk_css_gadget_set_state (priv->header_gadget, gtk_css_node_get_state (widget_node));
gtk_css_gadget_set_visible (priv->header_gadget, FALSE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE, GTK_ALIGN_FILL);
priv->tabs_gadget = gtk_css_custom_gadget_new ("tabs",
GTK_WIDGET (notebook),
@ -1333,7 +1333,7 @@ gtk_notebook_init (GtkNotebook *notebook)
NULL,
NULL);
gtk_css_gadget_set_state (priv->tabs_gadget, gtk_css_node_get_state (widget_node));
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->header_gadget), 0, priv->tabs_gadget, TRUE, TRUE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->header_gadget), 0, priv->tabs_gadget, TRUE, TRUE, GTK_ALIGN_FILL);
}
static void
@ -7014,28 +7014,28 @@ gtk_notebook_update_tab_pos (GtkNotebook *notebook)
{
case GTK_POS_TOP:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE, GTK_ALIGN_FILL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->header_gadget), GTK_ORIENTATION_HORIZONTAL);
break;
case GTK_POS_BOTTOM:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE, GTK_ALIGN_FILL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_VERTICAL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->header_gadget), GTK_ORIENTATION_HORIZONTAL);
break;
case GTK_POS_LEFT:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 0, priv->header_gadget, FALSE, FALSE, GTK_ALIGN_FILL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->header_gadget), GTK_ORIENTATION_VERTICAL);
break;
case GTK_POS_RIGHT:
if (priv->show_tabs)
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE);
gtk_box_gadget_insert_gadget (GTK_BOX_GADGET (priv->gadget), 1, priv->header_gadget, FALSE, FALSE, GTK_ALIGN_FILL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->gadget), GTK_ORIENTATION_HORIZONTAL);
gtk_box_gadget_set_orientation (GTK_BOX_GADGET (priv->header_gadget), GTK_ORIENTATION_VERTICAL);
break;