[gtk/box-layout-child-expand] boxlayout: Add GtkBoxLayoutChild



commit f923e24c72a0f99ec7b0585e63236b2ff4ca1e4e
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Apr 27 18:14:04 2020 -0400

    boxlayout: Add GtkBoxLayoutChild
    
    Add a layout child for GtkBoxLayout, with an expand
    property that can be used to control local expansion
    without the propagation of GtkWidget:h/vexpand getting
    in the way.

 docs/reference/gtk/gtk4-sections.txt |   5 ++
 gtk/gtkboxlayout.c                   | 168 +++++++++++++++++++++++++++++++++--
 gtk/gtkboxlayout.h                   |  11 ++-
 3 files changed, 174 insertions(+), 10 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 2123854971..16e26c3d2c 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -6668,6 +6668,11 @@ gtk_box_layout_get_spacing
 gtk_box_layout_set_baseline_position
 gtk_box_layout_get_baseline_position
 
+<SUBSECTION>
+GtkBoxLayoutChild
+gtk_box_layout_child_set_expand
+gtk_box_layout_child_get_expand
+
 <SUBSECTION Standard>
 GTK_TYPE_BOX_LAYOUT
 gtk_box_layout_get_type
diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c
index 098375973b..dfa5bf2388 100644
--- a/gtk/gtkboxlayout.c
+++ b/gtk/gtkboxlayout.c
@@ -49,6 +49,139 @@
  * you can use the #GtkBoxLayout:spacing property.
  */
 
+struct _GtkBoxLayoutChild
+{
+  GtkLayoutChild parent_instance;
+
+  gboolean expand;
+};
+
+enum {
+  PROP_CHILD_EXPAND = 1,
+
+  N_CHILD_PROPERTIES
+};
+
+static GParamSpec *child_props[N_CHILD_PROPERTIES];
+
+G_DEFINE_TYPE (GtkBoxLayoutChild, gtk_box_layout_child, GTK_TYPE_LAYOUT_CHILD)
+
+static void
+gtk_box_layout_child_set_property (GObject      *gobject,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  GtkBoxLayoutChild *self = GTK_BOX_LAYOUT_CHILD (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_CHILD_EXPAND:
+      gtk_box_layout_child_set_expand (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_box_layout_child_get_property (GObject    *gobject,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GtkBoxLayoutChild *self = GTK_BOX_LAYOUT_CHILD (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_CHILD_EXPAND:
+      g_value_set_boolean (value, self->expand);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_box_layout_child_class_init (GtkBoxLayoutChildClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gtk_box_layout_child_set_property;
+  gobject_class->get_property = gtk_box_layout_child_get_property;
+
+  /**
+   * GtkBoxLayoutChild:expand:
+   *
+   * Whether the child should receive extra space when the parent grows.
+   *
+   * Note that the effective expand value for a child also takes
+   * the #GtkWidget:hexpand or #GtkWidget:vexpand property into account.
+   */
+  child_props[PROP_CHILD_EXPAND] =
+    g_param_spec_boolean ("expand",
+                          P_("xpand"),
+                          P_("Whether the child should receive extra space when the parent grows"),
+                          FALSE,
+                          GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (gobject_class, N_CHILD_PROPERTIES, child_props);
+}
+
+static void
+gtk_box_layout_child_init (GtkBoxLayoutChild *self)
+{
+}
+
+/**
+ * gtk_box_layout_child_set_expand:
+ * @self: a #GtkBoxLayoutChild
+ * @expand: whether this child should receive extra space when the parent grows
+ *
+ * Sets whether the child should receive extra space (beyond its
+ * natural size) when the parent grows.
+ *
+ * Note that the effective expand is determined from this property
+ * and the #GtkWidget:hexpand or #GtkWidget:vexpand property of the
+ * child's widget.
+ */
+void
+gtk_box_layout_child_set_expand (GtkBoxLayoutChild *self,
+                                 gboolean           expand)
+{
+  g_return_if_fail (GTK_IS_BOX_LAYOUT_CHILD (self));
+
+  if (self->expand == expand)
+    return;
+
+  self->expand = expand;
+
+  gtk_layout_manager_layout_changed (gtk_layout_child_get_layout_manager (GTK_LAYOUT_CHILD (self)));
+
+  g_object_notify_by_pspec (G_OBJECT (self), child_props[PROP_CHILD_EXPAND]);
+}
+
+/**
+ * gtk_box_layout_child_get_expand:
+ * @self: a #GtkBoxLayoutChild
+ *
+ * Determines whether the child should receive extra space (beyond its
+ * natural size) when the parent grows.
+ *
+ * Returns: %TRUE if the child is set to expand
+ */
+gboolean
+gtk_box_layout_child_get_expand (GtkBoxLayoutChild *self)
+{
+  g_return_val_if_fail (GTK_IS_BOX_LAYOUT_CHILD (self), FALSE);
+
+  return self->expand;
+}
+
 struct _GtkBoxLayout
 {
   GtkLayoutManager parent_instance;
@@ -160,11 +293,27 @@ gtk_box_layout_get_property (GObject    *gobject,
     }
 }
 
+static gboolean
+child_should_expand (GtkBoxLayout *self,
+                     GtkWidget    *widget)
+{
+  GtkLayoutManager *layout;
+  GtkLayoutChild *child;
+
+  if (gtk_widget_compute_expand (widget, self->orientation))
+    return TRUE;
+
+  layout = GTK_LAYOUT_MANAGER (self);
+  child = gtk_layout_manager_get_layout_child (layout, widget);
+
+  return GTK_BOX_LAYOUT_CHILD (child)->expand;
+}
+
 static void
-count_expand_children (GtkWidget *widget,
-                       GtkOrientation orientation,
-                       gint *visible_children,
-                       gint *expand_children)
+count_expand_children (GtkBoxLayout *self,
+                       GtkWidget    *widget,
+                       int          *visible_children,
+                       int          *expand_children)
 {
   GtkWidget *child;
 
@@ -179,7 +328,7 @@ count_expand_children (GtkWidget *widget,
 
       *visible_children += 1;
 
-      if (gtk_widget_compute_expand (child, orientation))
+      if (child_should_expand (self, child))
         *expand_children += 1;
     }
 }
@@ -281,7 +430,7 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self,
   int spacing;
   gboolean have_baseline;
 
-  count_expand_children (widget, self->orientation, &nvis_children, &nexpand_children);
+  count_expand_children (self, widget, &nvis_children, &nexpand_children);
 
   if (nvis_children <= 0)
     return;
@@ -361,7 +510,7 @@ gtk_box_layout_compute_opposite_size (GtkBoxLayout *self,
         {
           child_size = sizes[i].minimum_size;
 
-          if (gtk_widget_compute_expand (child, self->orientation))
+          if (child_should_expand (self, child))
             {
               child_size += size_given_to_child;
 
@@ -482,7 +631,7 @@ gtk_box_layout_allocate (GtkLayoutManager *layout_manager,
   gint child_size;
   gint spacing;
 
-  count_expand_children (widget, self->orientation, &nvis_children, &nexpand_children);
+  count_expand_children (self, widget, &nvis_children, &nexpand_children);
 
   /* If there is no visible child, simply return. */
   if (nvis_children <= 0)
@@ -575,7 +724,7 @@ gtk_box_layout_allocate (GtkLayoutManager *layout_manager,
         {
           child_size = sizes[i].minimum_size;
 
-          if (gtk_widget_compute_expand (child, self->orientation))
+          if (child_should_expand (self, child))
             {
               child_size += size_given_to_child;
 
@@ -701,6 +850,7 @@ gtk_box_layout_class_init (GtkBoxLayoutClass *klass)
   gobject_class->set_property = gtk_box_layout_set_property;
   gobject_class->get_property = gtk_box_layout_get_property;
 
+  layout_manager_class->layout_child_type = GTK_TYPE_BOX_LAYOUT_CHILD;
   layout_manager_class->measure = gtk_box_layout_measure;
   layout_manager_class->allocate = gtk_box_layout_allocate;
 
diff --git a/gtk/gtkboxlayout.h b/gtk/gtkboxlayout.h
index 8d394219b7..86f5d308bf 100644
--- a/gtk/gtkboxlayout.h
+++ b/gtk/gtkboxlayout.h
@@ -27,7 +27,8 @@
 
 G_BEGIN_DECLS
 
-#define GTK_TYPE_BOX_LAYOUT (gtk_box_layout_get_type())
+#define GTK_TYPE_BOX_LAYOUT       (gtk_box_layout_get_type())
+#define GTK_TYPE_BOX_LAYOUT_CHILD (gtk_box_layout_child_get_type())
 
 GDK_AVAILABLE_IN_ALL
 G_DECLARE_FINAL_TYPE (GtkBoxLayout, gtk_box_layout, GTK, BOX_LAYOUT, GtkLayoutManager)
@@ -51,4 +52,12 @@ void                    gtk_box_layout_set_baseline_position    (GtkBoxLayout
 GDK_AVAILABLE_IN_ALL
 GtkBaselinePosition     gtk_box_layout_get_baseline_position    (GtkBoxLayout        *box_layout);
 
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkBoxLayoutChild, gtk_box_layout_child, GTK, BOX_LAYOUT_CHILD, GtkLayoutChild)
+
+void                    gtk_box_layout_child_set_expand         (GtkBoxLayoutChild  *child,
+                                                                 gboolean            expand);
+GDK_AVAILABLE_IN_ALL
+gboolean               gtk_box_layout_child_get_expand         (GtkBoxLayoutChild  *child);
+
 G_END_DECLS


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