[gtk+/native-layout] Added get_height_for_width/get_width_for_height implementation to GtkBox.



commit 1041a186c73d705e6aecad1b8c288083e3eaf278
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Fri Apr 9 21:50:33 2010 -0400

    Added get_height_for_width/get_width_for_height implementation to GtkBox.
    
    In order for natural size information to cascade correctly up through
    the ancestry GtkBox needs to report height-for-width and width-for-height,
    this patch includes an implementation for both in both orientations, one
    of them is commented for now as its much too cpu intensive to actually use.

 gtk/gtkbox.c |  477 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 351 insertions(+), 126 deletions(-)
---
diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c
index 9daf89a..144124a 100644
--- a/gtk/gtkbox.c
+++ b/gtk/gtkbox.c
@@ -76,12 +76,8 @@ struct _GtkBoxSpreading
   gint index;
 };
 
-static void gtk_box_get_desired_size      (GtkExtendedLayout      *layout,
-                                           GtkRequisition         *minimum_size,
-                                           GtkRequisition         *natural_size);
 static void gtk_box_size_allocate         (GtkWidget              *widget,
                                            GtkAllocation          *allocation);
-static void gtk_box_layout_interface_init (GtkExtendedLayoutIface *iface);
 
 static void gtk_box_set_property       (GObject        *object,
                                         guint           prop_id,
@@ -113,11 +109,26 @@ static void gtk_box_get_child_property (GtkContainer   *container,
 static GType gtk_box_child_type        (GtkContainer   *container);
 
 
+static void gtk_box_extended_layout_init  (GtkExtendedLayoutIface *iface);
+static void gtk_box_get_desired_size      (GtkExtendedLayout      *layout,
+                                           GtkRequisition         *minimum_size,
+                                           GtkRequisition         *natural_size);
+static void gtk_box_get_width_for_height  (GtkExtendedLayout      *layout,
+					   gint                    height,
+					   gint                   *minimum_width,
+					   gint                   *natural_width);
+static void gtk_box_get_height_for_width  (GtkExtendedLayout      *layout,
+					   gint                    width,
+					   gint                   *minimum_height,
+					   gint                   *natural_height);
+
+GtkExtendedLayoutIface *parent_extended_layout_iface;
+
 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
                                                          NULL)
                                   G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
-                                                         gtk_box_layout_interface_init));
+                                                         gtk_box_extended_layout_init));
 
 static void
 gtk_box_class_init (GtkBoxClass *class)
@@ -200,12 +211,6 @@ gtk_box_class_init (GtkBoxClass *class)
 }
 
 static void
-gtk_box_layout_interface_init (GtkExtendedLayoutIface *iface)
-{
-  iface->get_desired_size = gtk_box_get_desired_size;
-}
-
-static void
 gtk_box_init (GtkBox *box)
 {
   GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
@@ -275,121 +280,6 @@ gtk_box_get_property (GObject    *object,
     }
 }
 
-static void
-gtk_box_get_desired_size (GtkExtendedLayout *layout,
-                          GtkRequisition    *minimum_size,
-                          GtkRequisition    *natural_size)
-{
-  GtkBox *box;
-  GtkBoxPrivate *private;
-  GList *children;
-  gint nvis_children;
-  gint border_width;
-
-  box = GTK_BOX (layout);
-  private = GTK_BOX_GET_PRIVATE (box);
-  border_width = GTK_CONTAINER (box)->border_width;
-
-  minimum_size->width = minimum_size->height = 0;
-  natural_size->width = natural_size->height = 0;
-
-  nvis_children = 0;
-  children = box->children;
-  while (children)
-    {
-      GtkBoxChild *child;
-
-      child = children->data;
-      children = children->next;
-
-      if (gtk_widget_get_visible (child->widget))
-        {
-          GtkRequisition child_minimum_size;
-          GtkRequisition child_natural_size;
-
-          gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (child->widget),
-						&child_minimum_size,
-						&child_natural_size);
-
-          if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
-            {
-              if (box->homogeneous)
-                {
-                  gint width;
-
-                  width = child_minimum_size.width + child->padding * 2;
-                  minimum_size->width = MAX (minimum_size->width, width);
-
-                  width = child_natural_size.width + child->padding * 2;
-                  natural_size->width = MAX (natural_size->width, width);
-                }
-              else
-                {
-                  minimum_size->width += child_minimum_size.width + child->padding * 2;
-                  natural_size->width += child_natural_size.width + child->padding * 2;
-                }
-
-              minimum_size->height = MAX (minimum_size->height, child_minimum_size.height);
-              natural_size->height = MAX (natural_size->height, child_natural_size.height);
-            }
-          else
-            {
-              if (box->homogeneous)
-                {
-                  gint height;
-
-                  height = child_minimum_size.height + child->padding * 2;
-                  minimum_size->height = MAX (minimum_size->height, height);
-
-                  height = child_natural_size.height + child->padding * 2;
-                  natural_size->height = MAX (natural_size->height, height);
-                }
-              else
-                {
-                  minimum_size->height += child_minimum_size.height + child->padding * 2;
-                  natural_size->height += child_natural_size.height + child->padding * 2;
-                }
-
-              minimum_size->width = MAX (minimum_size->width, child_minimum_size.width);
-              natural_size->width = MAX (natural_size->width, child_natural_size.width);
-            }
-
-
-          nvis_children += 1;
-        }
-    }
-  if (nvis_children > 0)
-    {
-      if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
-        {
-          if (box->homogeneous)
-            {
-             minimum_size->width *= nvis_children;
-             natural_size->width *= nvis_children;
-            }
-
-          minimum_size->width += (nvis_children - 1) * box->spacing;
-          natural_size->width += (nvis_children - 1) * box->spacing;
-        }
-      else
-        {
-          if (box->homogeneous)
-            {
-             minimum_size->height *= nvis_children;
-             natural_size->height *= nvis_children;
-            }
-
-          minimum_size->height += (nvis_children - 1) * box->spacing;
-          natural_size->height += (nvis_children - 1) * box->spacing;
-        }
-    }
-
-  minimum_size->width += border_width * 2;
-  minimum_size->height += border_width * 2;
-
-  natural_size->width += border_width * 2;
-  natural_size->height += border_width * 2;
-}
 
 static gint
 gtk_box_compare_gap (gconstpointer p1,
@@ -415,6 +305,7 @@ gtk_box_compare_gap (gconstpointer p1,
   return delta;
 }
 
+
 static void
 gtk_box_size_allocate (GtkWidget     *widget,
                        GtkAllocation *allocation)
@@ -849,6 +740,340 @@ gtk_box_pack (GtkBox      *box,
   gtk_widget_thaw_child_notify (child);
 }
 
+
+
+static void
+gtk_box_extended_layout_init (GtkExtendedLayoutIface *iface)
+{
+  parent_extended_layout_iface = g_type_interface_peek_parent (iface);
+
+  iface->get_desired_size     = gtk_box_get_desired_size;
+  iface->get_height_for_width = gtk_box_get_height_for_width;
+  iface->get_width_for_height = gtk_box_get_width_for_height;
+}
+
+static void
+gtk_box_get_desired_size (GtkExtendedLayout *layout,
+                          GtkRequisition    *minimum_size,
+                          GtkRequisition    *natural_size)
+{
+  GtkBox *box;
+  GtkBoxPrivate *private;
+  GList *children;
+  gint nvis_children;
+  gint border_width;
+
+  box = GTK_BOX (layout);
+  private = GTK_BOX_GET_PRIVATE (box);
+  border_width = GTK_CONTAINER (box)->border_width;
+
+  minimum_size->width = minimum_size->height = 0;
+  natural_size->width = natural_size->height = 0;
+
+  nvis_children = 0;
+  children = box->children;
+  while (children)
+    {
+      GtkBoxChild *child;
+
+      child = children->data;
+      children = children->next;
+
+      if (gtk_widget_get_visible (child->widget))
+        {
+          GtkRequisition child_minimum_size;
+          GtkRequisition child_natural_size;
+
+          gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (child->widget),
+						&child_minimum_size,
+						&child_natural_size);
+
+          if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
+            {
+              if (box->homogeneous)
+                {
+                  gint width;
+
+                  width = child_minimum_size.width + child->padding * 2;
+                  minimum_size->width = MAX (minimum_size->width, width);
+
+                  width = child_natural_size.width + child->padding * 2;
+                  natural_size->width = MAX (natural_size->width, width);
+                }
+              else
+                {
+                  minimum_size->width += child_minimum_size.width + child->padding * 2;
+                  natural_size->width += child_natural_size.width + child->padding * 2;
+                }
+
+              minimum_size->height = MAX (minimum_size->height, child_minimum_size.height);
+              natural_size->height = MAX (natural_size->height, child_natural_size.height);
+            }
+          else
+            {
+              if (box->homogeneous)
+                {
+                  gint height;
+
+                  height = child_minimum_size.height + child->padding * 2;
+                  minimum_size->height = MAX (minimum_size->height, height);
+
+                  height = child_natural_size.height + child->padding * 2;
+                  natural_size->height = MAX (natural_size->height, height);
+                }
+              else
+                {
+                  minimum_size->height += child_minimum_size.height + child->padding * 2;
+                  natural_size->height += child_natural_size.height + child->padding * 2;
+                }
+
+              minimum_size->width = MAX (minimum_size->width, child_minimum_size.width);
+              natural_size->width = MAX (natural_size->width, child_natural_size.width);
+            }
+
+
+          nvis_children += 1;
+        }
+    }
+  if (nvis_children > 0)
+    {
+      if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
+        {
+          if (box->homogeneous)
+            {
+             minimum_size->width *= nvis_children;
+             natural_size->width *= nvis_children;
+            }
+
+          minimum_size->width += (nvis_children - 1) * box->spacing;
+          natural_size->width += (nvis_children - 1) * box->spacing;
+        }
+      else
+        {
+          if (box->homogeneous)
+            {
+             minimum_size->height *= nvis_children;
+             natural_size->height *= nvis_children;
+            }
+
+          minimum_size->height += (nvis_children - 1) * box->spacing;
+          natural_size->height += (nvis_children - 1) * box->spacing;
+        }
+    }
+
+  minimum_size->width += border_width * 2;
+  minimum_size->height += border_width * 2;
+
+  natural_size->width += border_width * 2;
+  natural_size->height += border_width * 2;
+}
+
+
+/**
+ * size_fits_for_dimension:
+ * @box: a GtkBox
+ * @avail_size: the allocated size in @box's opposing orientation
+ * @check_size: the size in @box's orientation to check
+ * @check_natural: whether to check natural sizes or minimum sizes.
+ *
+ * This checks if the required size of @box and its children fit into @avail_size
+ * in @box's opposing orientation if @box were given @check_size as an allocation
+ * in @box's orientation.
+ *
+ * In context: A GtkVBox will check if it fits into the available allocated height
+ * if it were given the @check_size in width.
+ *
+ */
+static gboolean
+size_fits_for_dimension (GtkBox  *box,
+			 gint     avail_size,
+			 gint     check_size,
+			 gboolean check_natural)
+{
+  GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
+  GList         *children;
+  gint           nvis_children = 0;
+  gint           required_size = 0, child_size;
+  gint           largest_child = 0;
+
+  avail_size -= GTK_CONTAINER (box)->border_width * 2;
+
+  for (children = box->children; children != NULL; 
+       children = children->next, nvis_children++)
+    {
+      GtkBoxChild *child = children->data;
+
+      if (gtk_widget_get_visible (child->widget))
+        {
+
+          if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
+	    {
+	      if (check_natural)
+		gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (child->widget),
+							  avail_size, NULL, &child_size);
+	      else
+		gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (child->widget),
+							  avail_size, &child_size, NULL);
+	    }
+	  else
+	    {
+	      if (check_natural)
+		gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (child->widget),
+							  avail_size, NULL, &child_size);
+	      else
+		gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (child->widget),
+							  avail_size, &child_size, NULL);
+	    }
+
+	  child_size += child->padding * 2;
+
+	  if (child_size > largest_child)
+	    largest_child = child_size;
+
+	  required_size += child_size;
+        }
+    }
+
+  if (nvis_children > 0)
+    {
+      if (box->homogeneous)
+	required_size = largest_child * nvis_children;
+
+      required_size += (nvis_children - 1) * box->spacing;
+    }
+
+  required_size += GTK_CONTAINER (box)->border_width * 2;
+
+  return required_size <= check_size;
+}
+
+
+static void 
+gtk_box_compute_size_for_awkward_orientation (GtkBox *box,
+					      gint    avail_size,
+					      gint   *minimum_size,
+					      gint   *natural_size)
+{
+  gint minimum, natural;
+  
+  /* Find the smallest possible fit in the orientation of 'box' where 'avail_size' is the available
+   * size in the opposing orientation
+   */
+  for (minimum = 1; !size_fits_for_dimension (box, avail_size, minimum, FALSE); minimum++);
+
+  /* Starting from the minimum available size, do the same to find the smallest allocation where
+   * all children receive their natural size 
+   */
+  for (natural = minimum; !size_fits_for_dimension (box, avail_size, natural, TRUE); natural++);
+  
+  if (minimum_size)
+    *minimum_size = minimum;
+
+  if (natural_size)
+    *natural_size = natural;
+
+}  
+
+static void 
+gtk_box_compute_size_for_orientation (GtkBox *box,
+				      gint    avail_size,
+				      gint   *minimum_size,
+				      gint   *natural_size)
+{
+  GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (box);
+  GList         *children;
+  gint           nvis_children = 0;
+  gint           required_size = 0, required_natural = 0, child_size, child_natural;
+  gint           largest_child = 0, largest_natural = 0;
+
+  avail_size -= GTK_CONTAINER (box)->border_width * 2;
+
+  for (children = box->children; children != NULL; 
+       children = children->next, nvis_children++)
+    {
+      GtkBoxChild *child = children->data;
+
+      if (gtk_widget_get_visible (child->widget))
+        {
+
+          if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
+	    gtk_extended_layout_get_width_for_height (GTK_EXTENDED_LAYOUT (child->widget),
+						      avail_size, &child_size, &child_natural);
+	  else
+	    gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (child->widget),
+						      avail_size, &child_size, &child_natural);
+
+
+	  child_size    += child->padding * 2;
+	  child_natural += child->padding * 2;
+
+	  if (child_size > largest_child)
+	    largest_child = child_size;
+
+	  if (child_natural > largest_natural)
+	    largest_natural = child_natural;
+
+	  required_size    += child_size;
+	  required_natural += child_natural;
+        }
+    }
+
+  if (nvis_children > 0)
+    {
+      if (box->homogeneous)
+	{
+	  required_size    = largest_child   * nvis_children;
+	  required_natural = largest_natural * nvis_children;
+	}
+
+      required_size     += (nvis_children - 1) * box->spacing;
+      required_natural  += (nvis_children - 1) * box->spacing;
+    }
+
+  required_size    += GTK_CONTAINER (box)->border_width * 2;
+  required_natural += GTK_CONTAINER (box)->border_width * 2;
+
+  if (minimum_size)
+    *minimum_size = required_size;
+
+  if (natural_size)
+    *natural_size = required_natural;
+}
+
+static void 
+gtk_box_get_width_for_height (GtkExtendedLayout *layout,
+			      gint               height,
+			      gint              *minimum_width,
+			      gint              *natural_width)
+{
+  GtkBox        *box     = GTK_BOX (layout);
+  GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
+
+  if (private->orientation == GTK_ORIENTATION_VERTICAL)
+/*     gtk_box_compute_size_for_awkward_orientation (box, height, minimum_width, natural_width); */
+    /* Have the base class return the values previously computed by get_desired_size() */
+    parent_extended_layout_iface->get_width_for_height (layout, height, minimum_width, natural_width);
+  else
+    gtk_box_compute_size_for_orientation (box, height, minimum_width, natural_width);
+}
+
+static void 
+gtk_box_get_height_for_width (GtkExtendedLayout *layout,
+			      gint               width,
+			      gint              *minimum_height,
+			      gint              *natural_height)
+{
+  GtkBox        *box     = GTK_BOX (layout);
+  GtkBoxPrivate *private = GTK_BOX_GET_PRIVATE (layout);
+
+  if (private->orientation == GTK_ORIENTATION_HORIZONTAL)
+/*     gtk_box_compute_size_for_awkward_orientation (box, width, minimum_height, natural_height); */
+    /* Have the base class return the values previously computed by get_desired_size() */
+     parent_extended_layout_iface->get_height_for_width (layout, width, minimum_height, natural_height); 
+  else
+    gtk_box_compute_size_for_orientation (box, width, minimum_height, natural_height);
+}
+
 /**
  * gtk_box_new:
  * @orientation: the box' orientation.



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