[gtk+/native-layout] Created a _gtk_distribute_allocation() helper function for size allocators.



commit 06a5095dc53510ea1a6137c439a46e62d45fb49e
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Fri Jun 18 19:40:02 2010 -0400

    Created a _gtk_distribute_allocation() helper function for size allocators.
    
    Migrated a portion of the GtkBox allocator loop to live in
    a private function and be reused for distribution of space along
    a single orientation.

 gtk/gtkbox.c                |  150 ++++---------------------------------------
 gtk/gtksizerequest.c        |  106 ++++++++++++++++++++++++++++++-
 gtk/gtksizerequestprivate.h |   45 +++++++++++++
 3 files changed, 164 insertions(+), 137 deletions(-)
---
diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c
index 82289f5..18d6670 100644
--- a/gtk/gtkbox.c
+++ b/gtk/gtkbox.c
@@ -78,6 +78,7 @@
 #include "gtkbox.h"
 #include "gtkorientable.h"
 #include "gtksizerequest.h"
+#include "gtksizerequestprivate.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
 #include "gtkalias.h"
@@ -110,21 +111,6 @@ struct _GtkBoxPrivate
 
 #define GTK_BOX_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_BOX, GtkBoxPrivate))
 
-typedef struct _GtkBoxDesiredSizes GtkBoxDesiredSizes;
-typedef struct _GtkBoxSpreading    GtkBoxSpreading;
-
-struct _GtkBoxDesiredSizes
-{
-  gint minimum_size;
-  gint natural_size;
-};
-
-struct _GtkBoxSpreading
-{
-  GtkBoxChild *child;
-  gint index;
-};
-
 static void gtk_box_size_allocate         (GtkWidget              *widget,
                                            GtkAllocation          *allocation);
 
@@ -375,30 +361,6 @@ count_expand_children (GtkBox *box, gint *visible_children, gint *expand_childre
     }
 }
 
-static gint
-gtk_box_compare_gap (gconstpointer p1,
-                      gconstpointer p2,
-                      gpointer      data)
-{
-  GtkBoxDesiredSizes *sizes = data;
-  const GtkBoxSpreading *c1 = p1;
-  const GtkBoxSpreading *c2 = p2;
-
-  const gint d1 = MAX (sizes[c1->index].natural_size -
-                       sizes[c1->index].minimum_size,
-                       0);
-  const gint d2 = MAX (sizes[c2->index].natural_size -
-                       sizes[c2->index].minimum_size,
-                       0);
-
-  gint delta = (d2 - d1);
-
-  if (0 == delta)
-    delta = (c2->index - c1->index);
-
-  return delta;
-}
-
 static void
 gtk_box_size_allocate (GtkWidget     *widget,
                        GtkAllocation *allocation)
@@ -419,8 +381,7 @@ gtk_box_size_allocate (GtkWidget     *widget,
       gint border_width = GTK_CONTAINER (box)->border_width;
       GtkTextDirection direction = gtk_widget_get_direction (widget);
       GtkAllocation child_allocation;
-      GtkBoxSpreading *spreading = g_newa (GtkBoxSpreading, nvis_children);
-      GtkBoxDesiredSizes *sizes = g_newa (GtkBoxDesiredSizes, nvis_children);
+      GtkRequestedSize *sizes = g_newa (GtkRequestedSize, nvis_children);
 
       GtkPackType packing;
 
@@ -476,9 +437,8 @@ gtk_box_size_allocate (GtkWidget     *widget,
 	      
 	      size -= sizes[i].minimum_size;
 	      size -= child->padding * 2;
-	      
-	      spreading[i].index = i;
-	      spreading[i].child = child;
+
+	      sizes[i].data = child;
 	      
 	      i += 1;
 	    }
@@ -498,47 +458,8 @@ gtk_box_size_allocate (GtkWidget     *widget,
         }
       else
 	{
-
-          /* Distribute the container's extra space c_gap. We want to assign
-           * this space such that the sum of extra space assigned to children
-           * (c^i_gap) is equal to c_cap. The case that there's not enough
-           * space for all children to take their natural size needs some
-           * attention. The goals we want to achieve are:
-           *
-           *   a) Maximize number of children taking their natural size.
-           *   b) The allocated size of children should be a continuous
-           *   function of c_gap.  That is, increasing the container size by
-           *   one pixel should never make drastic changes in the distribution.
-           *   c) If child i takes its natural size and child j doesn't,
-           *   child j should have received at least as much gap as child i.
-           *
-           * The following code distributes the additional space by following
-           * this rules.
-           */
-
-          /* Sort descending by gap and position. */
-          g_qsort_with_data (spreading,
-                             nvis_children, sizeof (GtkBoxSpreading),
-                             gtk_box_compare_gap, sizes);
-
-          /* Distribute available space.
-           * This master piece of a loop was conceived by Behdad Esfahbod.
-           */
-          for (i = nvis_children - 1; size > 0 && i >= 0; --i)
-            {
-              /* Divide remaining space by number of remaining children.
-               * Sort order and reducing remaining space by assigned space
-               * ensures that space is distributed equally.
-               */
-              gint glue = (size + i) / (i + 1);
-              gint gap = sizes[spreading[i].index].natural_size
-                       - sizes[spreading[i].index].minimum_size;
-
-              extra = MIN (glue, gap);
-              sizes[spreading[i].index].minimum_size += extra;
-
-              size -= extra;
-            }
+	  /* Bring children up to size first */
+	  size = _gtk_distribute_allocation (size, nvis_children, sizes);
 
           /* Calculate space which hasn't distributed yet,
            * and is available for expanding children.
@@ -975,12 +896,10 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
 
   if (nvis_children > 0)
     {
-      GtkBoxSpreading     *spreading    = g_newa (GtkBoxSpreading, nvis_children);
-      GtkBoxDesiredSizes  *sizes        = g_newa (GtkBoxDesiredSizes, nvis_children);
-      GtkPackType          packing;
-      gint                 size;
-      gint                 extra, i;
-      gint                 child_size, child_minimum, child_natural;
+      GtkRequestedSize *sizes = g_newa (GtkRequestedSize, nvis_children);
+      GtkPackType       packing;
+      gint              size, extra, i;
+      gint              child_size, child_minimum, child_natural;
 
       size = avail_size - border_width * 2 - (nvis_children - 1) * box->spacing;
 
@@ -1016,9 +935,8 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
 
 	      size -= sizes[i].minimum_size;
 	      size -= child->padding * 2;
-	      
-	      spreading[i].index = i;
-	      spreading[i].child = child;
+
+	      sizes[i].data = child;
 	      
 	      i += 1;
 	    }
@@ -1034,48 +952,8 @@ gtk_box_compute_size_for_opposing_orientation (GtkBox *box,
         }
       else
 	{
-
-          /* Distribute the container's extra space c_gap. We want to assign
-           * this space such that the sum of extra space assigned to children
-           * (c^i_gap) is equal to c_cap. The case that there's not enough
-           * space for all children to take their natural size needs some
-           * attention. The goals we want to achieve are:
-           *
-           *   a) Maximize number of children taking their natural size.
-           *   b) The allocated size of children should be a continuous
-           *   function of c_gap.  That is, increasing the container size by
-           *   one pixel should never make drastic changes in the distribution.
-           *   c) If child i takes its natural size and child j doesn't,
-           *   child j should have received at least as much gap as child i.
-           *
-           * The following code distributes the additional space by following
-           * this rules.
-           */
-
-          /* Sort descending by gap and position. */
-
-          g_qsort_with_data (spreading,
-                             nvis_children, sizeof (GtkBoxSpreading),
-                             gtk_box_compare_gap, sizes);
-
-          /* Distribute available space.
-           * This master piece of a loop was conceived by Behdad Esfahbod.
-           */
-          for (i = nvis_children - 1; size > 0 && i >= 0; --i)
-            {
-              /* Divide remaining space by number of remaining children.
-               * Sort order and reducing remaining space by assigned space
-               * ensures that space is distributed equally.
-               */
-              gint glue = (size + i) / (i + 1);
-              gint gap = sizes[spreading[i].index].natural_size
-                       - sizes[spreading[i].index].minimum_size;
-
-              extra = MIN (glue, gap);
-              sizes[spreading[i].index].minimum_size += extra;
-
-              size -= extra;
-            }
+	  /* Bring children up to size first */
+	  size = _gtk_distribute_allocation (size, nvis_children, sizes);
 
           /* Calculate space which hasn't distributed yet,
            * and is available for expanding children.
diff --git a/gtk/gtksizerequest.c b/gtk/gtksizerequest.c
index dd00e11..d3026bf 100644
--- a/gtk/gtksizerequest.c
+++ b/gtk/gtksizerequest.c
@@ -94,6 +94,7 @@
 
 #include <config.h>
 #include "gtksizerequest.h"
+#include "gtksizerequestprivate.h"
 #include "gtksizegroup.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
@@ -119,6 +120,11 @@ typedef struct {
   guint8      cached_height_age;
 } SizeRequestCache;
 
+typedef struct {
+  gpointer data;
+  gint     index;
+} AllocationSpreading;
+
 static GQuark quark_cache = 0;
 
 
@@ -352,7 +358,7 @@ compute_size_for_orientation (GtkSizeRequest    *request,
 }
 
 /**
- * gtk_size_request_is_height_for_width:
+ * gtk_size_request_get_request_mode:
  * @widget: a #GtkSizeRequest instance
  *
  * Gets whether the widget prefers a height-for-width layout
@@ -535,6 +541,104 @@ gtk_size_request_get_size (GtkSizeRequest    *widget,
 }
 
 
+static gint
+compare_gap (gconstpointer p1,
+	     gconstpointer p2,
+	     gpointer      data)
+{
+  GtkRequestedSize *sizes = data;
+  const guint *c1 = p1;
+  const guint *c2 = p2;
+
+  const gint d1 = MAX (sizes[*c1].natural_size -
+                       sizes[*c1].minimum_size,
+                       0);
+  const gint d2 = MAX (sizes[*c2].natural_size -
+                       sizes[*c2].minimum_size,
+                       0);
+
+  gint delta = (d2 - d1);
+
+  if (0 == delta)
+    delta = (*c2 - *c1);
+
+  return delta;
+}
+
+/**
+ * _gtk_distribute_allocation: 
+ * @extra_space: Extra space to redistribute among children after subtracting
+ *               minimum sizes and any child padding from the overall allocation
+ * @n_requested_sizes: Number of requests to fit into the allocation
+ * @sizes: An array of structs with a client pointer and a minimum/natural size
+ *         in the orientation of the allocation.
+ *
+ * Distributes @extra_space to child @sizes by bringing up smaller
+ * children up to natural size first.
+ *
+ * The remaining space will be added to the @minimum_size member of the
+ * GtkRequestedSize struct. If all sizes reach their natural size then
+ * the remaining space is returned.
+ *
+ * Returns: The remainder of @extra_space after redistributing space
+ * to @sizes if any.
+ */
+gint 
+_gtk_distribute_allocation (gint              extra_space,
+			    guint             n_requested_sizes,
+			    GtkRequestedSize *sizes)
+{
+  guint *spreading = g_newa (guint, n_requested_sizes);
+  gint   i;
+
+  for (i = 0; i < n_requested_sizes; i++)
+    spreading[i] = i;
+
+  /* Distribute the container's extra space c_gap. We want to assign
+   * this space such that the sum of extra space assigned to children
+   * (c^i_gap) is equal to c_cap. The case that there's not enough
+   * space for all children to take their natural size needs some
+   * attention. The goals we want to achieve are:
+   *
+   *   a) Maximize number of children taking their natural size.
+   *   b) The allocated size of children should be a continuous
+   *   function of c_gap.  That is, increasing the container size by
+   *   one pixel should never make drastic changes in the distribution.
+   *   c) If child i takes its natural size and child j doesn't,
+   *   child j should have received at least as much gap as child i.
+   *
+   * The following code distributes the additional space by following
+   * these rules.
+   */
+  
+  /* Sort descending by gap and position. */
+  g_qsort_with_data (spreading,
+		     n_requested_sizes, sizeof (guint),
+		     compare_gap, sizes);
+  
+  /* Distribute available space.
+   * This master piece of a loop was conceived by Behdad Esfahbod.
+   */
+  for (i = n_requested_sizes - 1; extra_space > 0 && i >= 0; --i)
+    {
+      /* Divide remaining space by number of remaining children.
+       * Sort order and reducing remaining space by assigned space
+       * ensures that space is distributed equally.
+       */
+      gint glue = (extra_space + i) / (i + 1);
+      gint gap = sizes[(spreading[i])].natural_size
+	- sizes[(spreading[i])].minimum_size;
+      
+      gint extra = MIN (glue, gap);
+      
+      sizes[spreading[i]].minimum_size += extra;
+      
+      extra_space -= extra;
+    }
+
+  return extra_space;
+}
+
 
 #define __GTK_SIZE_REQUEST_C__
 #include "gtkaliasdef.c"
diff --git a/gtk/gtksizerequestprivate.h b/gtk/gtksizerequestprivate.h
new file mode 100644
index 0000000..d980c98
--- /dev/null
+++ b/gtk/gtksizerequestprivate.h
@@ -0,0 +1,45 @@
+/* gtksizerequestprivate.h
+ * Copyright (C) 2010 Openismus GmbH
+ *
+ * Author:
+ *      Tristan Van Berkom <tristan van berkom gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_SIZE_REQUEST_PRIVATE_H__
+#define __GTK_SIZE_REQUEST_PRIVATE_H__
+
+#include <gtk/gtksizerequest.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkRequestedSize GtkRequestedSize;
+
+struct _GtkRequestedSize
+{
+  gpointer data;
+  gint     minimum_size;
+  gint     natural_size;
+};
+
+gint _gtk_distribute_allocation (gint              extra_space,
+				 guint             n_requested_sizes,
+				 GtkRequestedSize *sizes);
+
+G_END_DECLS
+
+#endif /* __GTK_SIZE_REQUEST_PRIVATE_H__ */



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