[gtk+] box gadget: Implement cross-axis alignment



commit 87171469b7dba8ec8ae3397ed292b9d004ef5e90
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jan 15 06:47:31 2016 -0500

    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

 gtk/gtkboxgadget.c        |  127 ++++++++++++++++++++++++++++++++++++++++++---
 gtk/gtkboxgadgetprivate.h |    5 ++-
 gtk/gtknotebook.c         |   14 +++---
 3 files changed, 131 insertions(+), 15 deletions(-)
---
diff --git a/gtk/gtkboxgadget.c b/gtk/gtkboxgadget.c
index 15fe036..e02c8e3 100644
--- a/gtk/gtkboxgadget.c
+++ b/gtk/gtkboxgadget.c
@@ -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));
 }
-
diff --git a/gtk/gtkboxgadgetprivate.h b/gtk/gtkboxgadgetprivate.h
index ce64e41..8063fcc 100644
--- a/gtk/gtkboxgadgetprivate.h
+++ b/gtk/gtkboxgadgetprivate.h
@@ -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__ */
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 6f61384..203e2a8 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]