[gtk+/treeview-refactor] Cleaned up GtkCellAreaIter implementation to use arrays to store grouped cell information.



commit e494f102cfcd3798797cfc2ecc346da433a000ef
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sun Oct 31 13:06:10 2010 +0900

    Cleaned up GtkCellAreaIter implementation to use arrays to store grouped cell information.

 gtk/gtkcellareabox.c     |  176 ++++++--------
 gtk/gtkcellareaboxiter.c |  598 ++++++++++++++++++++++++++++------------------
 gtk/gtkcellareaboxiter.h |   26 +-
 3 files changed, 458 insertions(+), 342 deletions(-)
---
diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c
index 273da69..a341dd7 100644
--- a/gtk/gtkcellareabox.c
+++ b/gtk/gtkcellareabox.c
@@ -115,24 +115,28 @@ typedef struct {
   guint  expand : 1;
 } CellGroup;
 
-static CellInfo  *cell_info_new          (GtkCellRenderer *renderer, 
-					  GtkPackType      pack,
-					  gboolean         expand,
-					  gboolean         align);
-static void       cell_info_free         (CellInfo        *info);
-static gint       cell_info_find         (CellInfo        *info,
-					  GtkCellRenderer *renderer);
-
-static CellGroup *cell_group_new         (guint            id);
-static void       cell_group_free        (CellGroup       *group);
-
-static GList     *list_consecutive_cells (GtkCellAreaBox  *box);
-static GList     *construct_cell_groups  (GtkCellAreaBox  *box);
-static gint       count_expand_groups    (GtkCellAreaBox  *box);
-static gint       count_expand_cells     (CellGroup       *group);
-static void       iter_weak_notify       (GtkCellAreaBox  *box,
-					  GtkCellAreaIter *dead_iter);
-static void       flush_iters            (GtkCellAreaBox  *box);
+static CellInfo  *cell_info_new          (GtkCellRenderer    *renderer, 
+					  GtkPackType         pack,
+					  gboolean            expand,
+					  gboolean            align);
+static void       cell_info_free         (CellInfo           *info);
+static gint       cell_info_find         (CellInfo           *info,
+					  GtkCellRenderer    *renderer);
+
+static CellGroup *cell_group_new         (guint               id);
+static void       cell_group_free        (CellGroup          *group);
+
+static GList     *list_consecutive_cells (GtkCellAreaBox     *box);
+static GList     *construct_cell_groups  (GtkCellAreaBox     *box);
+static gint       count_expand_groups    (GtkCellAreaBox     *box);
+static gint       count_expand_cells     (CellGroup          *group);
+static void       iter_weak_notify       (GtkCellAreaBox     *box,
+					  GtkCellAreaBoxIter *dead_iter);
+static void       flush_iters            (GtkCellAreaBox     *box);
+static void       init_iter_groups       (GtkCellAreaBox     *box);
+static void       init_iter_group        (GtkCellAreaBox     *box,
+					  GtkCellAreaBoxIter *iter);
+
 
 struct _GtkCellAreaBoxPrivate
 {
@@ -387,8 +391,8 @@ count_expand_cells (CellGroup *group)
 }
 
 static void 
-iter_weak_notify (GtkCellAreaBox  *box,
-		  GtkCellAreaIter *dead_iter)
+iter_weak_notify (GtkCellAreaBox     *box,
+		  GtkCellAreaBoxIter *dead_iter)
 {
   GtkCellAreaBoxPrivate *priv = box->priv;
 
@@ -396,95 +400,61 @@ iter_weak_notify (GtkCellAreaBox  *box,
 }
 
 static void
-flush_iters (GtkCellAreaBox *box)
+init_iter_group (GtkCellAreaBox     *box,
+		 GtkCellAreaBoxIter *iter)
 {
   GtkCellAreaBoxPrivate *priv = box->priv;
-  GSList                *l;
+  gint                   n_groups, *expand_groups, i;
+  GList                 *l;
 
-  /* When the box layout changes, iters need to
-   * be flushed and sizes for the box get requested again
-   */
-  for (l = priv->iters; l; l = l->next)
+  n_groups      = g_list_length (priv->groups);
+  expand_groups = g_new (gboolean, n_groups);
+
+  for (i = 0, l = priv->groups; l; l = l->next, i++)
     {
-      GtkCellAreaIter *iter = l->data;
+      CellGroup *group = l->data;
 
-      gtk_cell_area_iter_flush (iter);
+      expand_groups[i] = group->expand;
     }
-}
 
+  gtk_cell_area_box_init_groups (iter, n_groups, expand_groups);
+  g_free (expand_groups);
+}
 
-/* XXX This guy makes an allocation to be stored and retrieved from the iter */
-GtkCellAreaBoxAllocation *
-gtk_cell_area_box_allocate (GtkCellAreaBox     *box,
-			    GtkCellAreaBoxIter *iter,
-			    gint                size,
-			    gint               *n_allocs)
+static void
+init_iter_groups (GtkCellAreaBox *box)
 {
   GtkCellAreaBoxPrivate *priv = box->priv;
-  CellGroup             *group;
-  GList                 *group_list;
-  GtkRequestedSize      *orientation_sizes;
-  gint                   n_groups, n_expand_groups, i;
-  gint                   avail_size = size;
-  gint                   extra_size, extra_extra;
-  gint                   position;
-  GtkCellAreaBoxAllocation *allocs;
-
-  n_expand_groups = count_expand_groups (box);
-
-  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-    orientation_sizes = gtk_cell_area_box_iter_get_widths (iter, &n_groups);
-  else
-    orientation_sizes = gtk_cell_area_box_iter_get_heights (iter, &n_groups);
-
-  /* First start by naturally allocating space among groups of cells */
-  avail_size -= (n_groups - 1) * priv->spacing;
-  for (i = 0; i < n_groups; i++)
-    avail_size -= orientation_sizes[i].minimum_size;
-
-  avail_size = gtk_distribute_natural_allocation (avail_size, n_groups, orientation_sizes);
+  GSList                *l;
 
-  /* Calculate/distribute expand for groups */
-  if (n_expand_groups > 0)
+  /* When the box's groups are reconstructed, iters need to
+   * be reinitialized.
+   */
+  for (l = priv->iters; l; l = l->next)
     {
-      extra_size  = avail_size / n_expand_groups;
-      extra_extra = avail_size % n_expand_groups;
+      GtkCellAreaBoxIter *iter = l->data;
+
+      init_iter_group (box, iter);
     }
-  else
-    extra_size = extra_extra = 0;
+}
 
-  allocs = g_new (GtkCellAreaBoxAllocation, n_groups);
+static void
+flush_iters (GtkCellAreaBox *box)
+{
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  GSList                *l;
 
-  for (position = 0, group_list = priv->groups; group_list; group_list = group_list->next)
+  /* When the box layout changes, iters need to
+   * be flushed and sizes for the box get requested again
+   */
+  for (l = priv->iters; l; l = l->next)
     {
-      group = group_list->data;
-
-      allocs[group->id].position = position;
-      allocs[group->id].size     = orientation_sizes[group->id].minimum_size;
-
-      if (group->expand)
-	{
-	  allocs[group->id].size += extra_size;
-	  if (extra_extra)
-	    {
-	      allocs[group->id].size++;
-	      extra_extra--;
-	    }
-	}
+      GtkCellAreaIter *iter = l->data;
 
-      position += allocs[group->id].size;
-      position += priv->spacing;
+      gtk_cell_area_iter_flush (iter);
     }
-
-  g_free (orientation_sizes);
-
-  if (n_allocs)
-    *n_allocs = n_groups;
-
-  return allocs;
 }
 
-
 /*************************************************************
  *                      GObjectClass                         *
  *************************************************************/
@@ -519,6 +489,12 @@ gtk_cell_area_box_set_property (GObject       *object,
 
   switch (prop_id)
     {
+    case PROP_ORIENTATION:
+      box->priv->orientation = g_value_get_enum (value);
+
+      /* Notify that size needs to be requested again */
+      flush_iters (box);
+      break;
     case PROP_SPACING:
       gtk_cell_area_box_set_spacing (box, g_value_get_int (value));
       break;
@@ -538,6 +514,9 @@ gtk_cell_area_box_get_property (GObject     *object,
 
   switch (prop_id)
     {
+    case PROP_ORIENTATION:
+      g_value_set_enum (value, box->priv->orientation);
+      break;
     case PROP_SPACING:
       g_value_set_int (value, gtk_cell_area_box_get_spacing (box));
       break;
@@ -582,8 +561,8 @@ gtk_cell_area_box_remove (GtkCellArea        *area,
       g_list_free (priv->groups);
       priv->groups = construct_cell_groups (box);
 
-      /* Notify that size needs to be requested again */
-      flush_iters (box);
+      /* Reinitialize groups on iters */
+      init_iter_groups (box);
     }
   else
     g_warning ("Trying to remove a cell renderer that is not present GtkCellAreaBox");
@@ -640,6 +619,9 @@ gtk_cell_area_box_create_iter (GtkCellArea *area)
 
   g_object_weak_ref (G_OBJECT (iter), (GWeakNotify)iter_weak_notify, box);
 
+  /* Tell the new group about our cell layout */
+  init_iter_group (box, GTK_CELL_AREA_BOX_ITER (iter));
+
   return iter;
 }
 
@@ -1141,8 +1123,8 @@ gtk_cell_area_box_layout_reorder (GtkCellLayout      *cell_layout,
       g_list_free (priv->groups);
       priv->groups = construct_cell_groups (box);
       
-      /* Notify that size needs to be requested again */
-      flush_iters (box);
+      /* Reinitialize groups on iters */
+      init_iter_groups (box);
     }
 }
 
@@ -1185,8 +1167,8 @@ gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
   g_list_free (priv->groups);
   priv->groups = construct_cell_groups (box);
 
-  /* Notify that size needs to be requested again */
-  flush_iters (box);
+  /* Reinitialize groups on iters */
+  init_iter_groups (box);
 }
 
 void
@@ -1219,8 +1201,8 @@ gtk_cell_area_box_pack_end (GtkCellAreaBox  *box,
   g_list_free (priv->groups);
   priv->groups = construct_cell_groups (box);
 
-  /* Notify that size needs to be requested again */
-  flush_iters (box);
+  /* Reinitialize groups on iters */
+  init_iter_groups (box);
 }
 
 gint
diff --git a/gtk/gtkcellareaboxiter.c b/gtk/gtkcellareaboxiter.c
index 779315c..d16aa96 100644
--- a/gtk/gtkcellareaboxiter.c
+++ b/gtk/gtkcellareaboxiter.c
@@ -49,22 +49,25 @@ static void      gtk_cell_area_box_iter_allocate_width                   (GtkCel
 static void      gtk_cell_area_box_iter_allocate_height                  (GtkCellAreaIter *iter,
 									  gint             height);
 
-
+static void      free_cache_array                                        (GArray          *array);
 
 /* CachedSize management */
 typedef struct {
-  gint min_size;
-  gint nat_size;
+  gint     min_size;
+  gint     nat_size;
 } CachedSize;
 
-static CachedSize *cached_size_new  (gint min_size, gint nat_size);
-static void        cached_size_free (CachedSize *size);
+typedef struct {
+  gint     min_size;
+  gint     nat_size;
+  gboolean expand;
+} BaseSize;
 
 struct _GtkCellAreaBoxIterPrivate
 {
   /* Table of per renderer CachedSizes */
-  GHashTable *base_widths;
-  GHashTable *base_heights;
+  GArray *base_widths;
+  GArray *base_heights;
 
   /* Table of per height/width hash tables of per renderer CachedSizes */
   GHashTable *widths;
@@ -80,6 +83,12 @@ struct _GtkCellAreaBoxIterPrivate
 G_DEFINE_TYPE (GtkCellAreaBoxIter, gtk_cell_area_box_iter, GTK_TYPE_CELL_AREA_ITER);
 
 static void
+free_cache_array (GArray *array)
+{
+  g_array_free (array, TRUE);
+}
+
+static void
 gtk_cell_area_box_iter_init (GtkCellAreaBoxIter *box_iter)
 {
   GtkCellAreaBoxIterPrivate *priv;
@@ -89,15 +98,13 @@ gtk_cell_area_box_iter_init (GtkCellAreaBoxIter *box_iter)
 						GtkCellAreaBoxIterPrivate);
   priv = box_iter->priv;
 
-  priv->base_widths  = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-					      NULL, (GDestroyNotify)cached_size_free);
-  priv->base_heights = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-					      NULL, (GDestroyNotify)cached_size_free);
+  priv->base_widths  = g_array_new (FALSE, TRUE, sizeof (BaseSize));
+  priv->base_heights = g_array_new (FALSE, TRUE, sizeof (BaseSize));
 
   priv->widths       = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-					      NULL, (GDestroyNotify)g_hash_table_destroy);
+					      NULL, (GDestroyNotify)free_cache_array);
   priv->heights      = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-					      NULL, (GDestroyNotify)g_hash_table_destroy);
+					      NULL, (GDestroyNotify)free_cache_array);
 
   priv->alloc_width  = 0;
   priv->alloc_height = 0;
@@ -132,27 +139,6 @@ gtk_cell_area_box_iter_class_init (GtkCellAreaBoxIterClass *class)
 }
 
 /*************************************************************
- *                      Cached Sizes                         *
- *************************************************************/
-static CachedSize *
-cached_size_new (gint min_size, 
-		 gint nat_size)
-{
-  CachedSize *size = g_slice_new (CachedSize);
-
-  size->min_size = min_size;
-  size->nat_size = nat_size;
-
-  return size;
-}
-
-static void
-cached_size_free (CachedSize *size)
-{
-  g_slice_free (CachedSize, size);
-}
-
-/*************************************************************
  *                      GObjectClass                         *
  *************************************************************/
 static void
@@ -161,8 +147,8 @@ gtk_cell_area_box_iter_finalize (GObject *object)
   GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (object);
   GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
 
-  g_hash_table_destroy (priv->base_widths);
-  g_hash_table_destroy (priv->base_heights);
+  g_array_free (priv->base_widths, TRUE);
+  g_array_free (priv->base_heights, TRUE);
   g_hash_table_destroy (priv->widths);
   g_hash_table_destroy (priv->heights);
 
@@ -179,8 +165,15 @@ gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter)
 {
   GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
   GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
-  
-  g_hash_table_remove_all (priv->base_widths);
+  gint                       i;
+
+  for (i = 0; i < priv->base_widths->len; i++)
+    {
+      BaseSize *size = &g_array_index (priv->base_widths, BaseSize, i);
+
+      size->min_size = 0;
+      size->nat_size = 0;
+    }
 
   GTK_CELL_AREA_ITER_GET_CLASS
     (gtk_cell_area_box_iter_parent_class)->flush_preferred_width (iter);
@@ -208,8 +201,15 @@ gtk_cell_area_box_iter_flush_preferred_height (GtkCellAreaIter *iter)
 {
   GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
   GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
-  
-  g_hash_table_remove_all (priv->base_heights);
+  gint                       i;
+
+  for (i = 0; i < priv->base_heights->len; i++)
+    {
+      BaseSize *size = &g_array_index (priv->base_heights, BaseSize, i);
+
+      size->min_size = 0;
+      size->nat_size = 0;
+    }
 
   GTK_CELL_AREA_ITER_GET_CLASS
     (gtk_cell_area_box_iter_parent_class)->flush_preferred_height (iter);
@@ -243,49 +243,43 @@ gtk_cell_area_box_iter_flush_allocation (GtkCellAreaIter *iter)
   priv->n_orientation_allocs = 0;
 }
 
-typedef struct {
-  gint min_size;
-  gint nat_size;
-  gint spacing;
-} AccumData;
-
-static void
-sum_base_size (gpointer    group_id,
-	       CachedSize *size,
-	       AccumData  *accum)
-{
-  if (accum->min_size > 0)
-    {
-      accum->min_size += accum->spacing;
-      accum->nat_size += accum->spacing;
-    }
-
-  accum->min_size += size->min_size;
-  accum->nat_size += size->nat_size;
-}
-
-static void
-sum_for_size (gpointer    group_id,
-	      CachedSize *size,
-	      AccumData  *accum)
-{
-  accum->min_size = MAX (accum->min_size, size->min_size);
-  accum->nat_size = MAX (accum->nat_size, size->nat_size);
-}
-
 static void
 gtk_cell_area_box_iter_sum_preferred_width (GtkCellAreaIter *iter)
 {
   GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
   GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
   GtkCellArea               *area;
-  AccumData                  accum    = { 0, };
+  GtkOrientation             orientation;
+  gint                       spacing, i;
+  gint                       min_size = 0, nat_size = 0;
 
-  area          = gtk_cell_area_iter_get_area (iter);
-  accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+  area        = gtk_cell_area_iter_get_area (iter);
+  spacing     = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
+
+  for (i = 0; i < priv->base_widths->len; i++)
+    {
+      BaseSize *size = &g_array_index (priv->base_widths, BaseSize, i);
+
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
+	{
+	  if (min_size > 0)
+	    {
+	      min_size += spacing;
+	      nat_size += spacing;
+	    }
+	  
+	  min_size += size->min_size;
+	  nat_size += size->nat_size;
+	}
+      else
+	{
+	  min_size = MAX (min_size, size->min_size);
+	  nat_size = MAX (nat_size, size->nat_size);
+	}
+    }
 
-  g_hash_table_foreach (priv->base_widths, (GHFunc)sum_base_size, &accum);
-  gtk_cell_area_iter_push_preferred_width (iter, accum.min_size, accum.nat_size);
+  gtk_cell_area_iter_push_preferred_width (iter, min_size, nat_size);
 }
 
 static void
@@ -294,15 +288,43 @@ gtk_cell_area_box_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter,
 {
   GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
   GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
-  GHashTable                *group_table;
-  AccumData                  accum    = { 0, };
+  GArray                    *group_array;
+  GtkCellArea               *area;
+  GtkOrientation             orientation;
+  gint                       spacing, i;
+  gint                       min_size = 0, nat_size = 0;
 
-  group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (width));
+  group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (width));
 
-  if (group_table)
+  if (group_array)
     {
-      g_hash_table_foreach (priv->base_widths, (GHFunc)sum_for_size, &accum);
-      gtk_cell_area_iter_push_preferred_height_for_width (iter, width, accum.min_size, accum.nat_size);
+      area        = gtk_cell_area_iter_get_area (iter);
+      spacing     = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+      orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
+      
+      for (i = 0; i < group_array->len; i++)
+	{
+	  CachedSize *size = &g_array_index (group_array, CachedSize, i);
+	  
+	  if (orientation == GTK_ORIENTATION_VERTICAL)
+	    {
+	      if (min_size > 0)
+		{
+		  min_size += spacing;
+		  nat_size += spacing;
+		}
+	      
+	      min_size += size->min_size;
+	      nat_size += size->nat_size;
+	    }
+	  else
+	    {
+	      min_size = MAX (min_size, size->min_size);
+	      nat_size = MAX (nat_size, size->nat_size);
+	    }
+	}
+
+      gtk_cell_area_iter_push_preferred_height_for_width (iter, width, min_size, nat_size);
     }
 }
 
@@ -312,13 +334,37 @@ gtk_cell_area_box_iter_sum_preferred_height (GtkCellAreaIter *iter)
   GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
   GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
   GtkCellArea               *area;
-  AccumData                  accum    = { 0, };
+  GtkOrientation             orientation;
+  gint                       spacing, i;
+  gint                       min_size = 0, nat_size = 0;
 
-  area          = gtk_cell_area_iter_get_area (iter);
-  accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+  area        = gtk_cell_area_iter_get_area (iter);
+  spacing     = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
 
-  g_hash_table_foreach (priv->base_heights, (GHFunc)sum_base_size, &accum);
-  gtk_cell_area_iter_push_preferred_width (iter, accum.min_size, accum.nat_size);
+  for (i = 0; i < priv->base_heights->len; i++)
+    {
+      BaseSize *size = &g_array_index (priv->base_heights, BaseSize, i);
+
+      if (orientation == GTK_ORIENTATION_VERTICAL)
+	{
+	  if (min_size > 0)
+	    {
+	      min_size += spacing;
+	      nat_size += spacing;
+	    }
+	  
+	  min_size += size->min_size;
+	  nat_size += size->nat_size;
+	}
+      else
+	{
+	  min_size = MAX (min_size, size->min_size);
+	  nat_size = MAX (nat_size, size->nat_size);
+	}
+    }
+
+  gtk_cell_area_iter_push_preferred_height (iter, min_size, nat_size);
 }
 
 static void
@@ -327,18 +373,118 @@ gtk_cell_area_box_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter,
 {
   GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
   GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
-  GHashTable                *group_table;
-  AccumData                  accum    = { 0, };
+  GArray                    *group_array;
+  GtkCellArea               *area;
+  GtkOrientation             orientation;
+  gint                       spacing, i;
+  gint                       min_size = 0, nat_size = 0;
 
-  group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (height));
+  group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (height));
 
-  if (group_table)
+  if (group_array)
     {
-      g_hash_table_foreach (priv->base_widths, (GHFunc)sum_for_size, &accum);
-      gtk_cell_area_iter_push_preferred_width_for_height (iter, height, accum.min_size, accum.nat_size);
+      area        = gtk_cell_area_iter_get_area (iter);
+      spacing     = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+      orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
+      
+      for (i = 0; i < group_array->len; i++)
+	{
+	  CachedSize *size = &g_array_index (group_array, CachedSize, i);
+	  
+	  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+	    {
+	      if (min_size > 0)
+		{
+		  min_size += spacing;
+		  nat_size += spacing;
+		}
+	      
+	      min_size += size->min_size;
+	      nat_size += size->nat_size;
+	    }
+	  else
+	    {
+	      min_size = MAX (min_size, size->min_size);
+	      nat_size = MAX (nat_size, size->nat_size);
+	    }
+	}
+
+      gtk_cell_area_iter_push_preferred_width_for_height (iter, height, min_size, nat_size);
     }
 }
 
+static GtkCellAreaBoxAllocation *
+allocate_for_orientation (GtkCellAreaBoxIter *iter,
+			  GtkOrientation      orientation,
+			  gint                spacing,
+			  gint                size)
+{
+  GtkCellAreaBoxIterPrivate *priv = iter->priv;
+  GtkRequestedSize          *orientation_sizes;
+  GtkCellAreaBoxAllocation  *allocs;
+  gint                       n_expand_groups = 0;
+  gint                       i, n_groups, position;
+  gint                       extra_size, extra_extra;
+  gint                       avail_size = size;
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    orientation_sizes = gtk_cell_area_box_iter_get_widths (iter, &n_groups);
+  else
+    orientation_sizes = gtk_cell_area_box_iter_get_heights (iter, &n_groups);
+
+  /* Count groups that expand */
+  for (i = 0; i < n_groups; i++)
+    {
+      BaseSize *size = &g_array_index (priv->base_widths, BaseSize, i);
+
+      if (size->expand)
+	n_expand_groups++;
+    }
+
+  /* First start by naturally allocating space among groups */
+  avail_size -= (n_groups - 1) * spacing;
+  for (i = 0; i < n_groups; i++)
+    avail_size -= orientation_sizes[i].minimum_size;
+
+  avail_size = gtk_distribute_natural_allocation (avail_size, n_groups, orientation_sizes);
+
+  /* Calculate/distribute expand for groups */
+  if (n_expand_groups > 0)
+    {
+      extra_size  = avail_size / n_expand_groups;
+      extra_extra = avail_size % n_expand_groups;
+    }
+  else
+    extra_size = extra_extra = 0;
+
+  allocs = g_new (GtkCellAreaBoxAllocation, n_groups);
+
+  for (position = 0, i = 0; i < n_groups; i++)
+    {
+      BaseSize *base_size = &g_array_index (priv->base_widths, BaseSize, i);
+
+      allocs[i].position = position;
+      allocs[i].size     = orientation_sizes[i].minimum_size;
+
+      if (base_size->expand)
+	{
+	  allocs[i].size += extra_size;
+	  if (extra_extra)
+	    {
+	      allocs[i].size++;
+	      extra_extra--;
+	    }
+	}
+
+      position += allocs[i].size;
+      position += spacing;
+    }
+
+  g_free (orientation_sizes);
+
+  return allocs;
+}
+
 static void
 gtk_cell_area_box_iter_allocate_width (GtkCellAreaIter *iter,
 				       gint             width)
@@ -353,11 +499,10 @@ gtk_cell_area_box_iter_allocate_width (GtkCellAreaIter *iter,
 
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
     {
-      g_free (priv->orientation_allocs);
+      gint spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
 
-      priv->orientation_allocs = 
-	gtk_cell_area_box_allocate (GTK_CELL_AREA_BOX (area), box_iter, width, 
-				    &priv->n_orientation_allocs);
+      g_free (priv->orientation_allocs);
+      priv->orientation_allocs = allocate_for_orientation (box_iter, orientation, spacing, width);
     }
 
   GTK_CELL_AREA_ITER_GET_CLASS (iter)->allocate_width (iter, width);
@@ -377,11 +522,10 @@ gtk_cell_area_box_iter_allocate_height (GtkCellAreaIter *iter,
 
   if (orientation == GTK_ORIENTATION_VERTICAL)
     {
-      g_free (priv->orientation_allocs);
+      gint spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
 
-      priv->orientation_allocs = 
-	gtk_cell_area_box_allocate (GTK_CELL_AREA_BOX (area), box_iter, height, 
-				    &priv->n_orientation_allocs);
+      g_free (priv->orientation_allocs);
+      priv->orientation_allocs = allocate_for_orientation (box_iter, orientation, spacing, height);
     }
 
   GTK_CELL_AREA_ITER_GET_CLASS (iter)->allocate_height (iter, height);
@@ -390,188 +534,179 @@ gtk_cell_area_box_iter_allocate_height (GtkCellAreaIter *iter,
 /*************************************************************
  *                            API                            *
  *************************************************************/
+void
+gtk_cell_area_box_init_groups (GtkCellAreaBoxIter *box_iter,
+			       guint               n_groups,
+			       gboolean           *expand_groups)
+{
+  GtkCellAreaBoxIterPrivate *priv;
+  gint                       i;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
+  g_return_if_fail (n_groups > 0 || expand_groups != NULL);
+
+  /* When the group dimensions change, all info must be flushed 
+   * Note this already clears the min/nat values on the BaseSizes
+   */
+  gtk_cell_area_iter_flush (GTK_CELL_AREA_ITER (box_iter));
+
+  priv = box_iter->priv;
+  g_array_set_size (priv->base_widths,  n_groups);
+  g_array_set_size (priv->base_heights, n_groups);
+
+  /* Now set the expand info */
+  for (i = 0; i < n_groups; i++)
+    {
+      BaseSize *base_width  = &g_array_index (priv->base_widths,  BaseSize, i);
+      BaseSize *base_height = &g_array_index (priv->base_heights, BaseSize, i);
+
+      base_width->expand  = expand_groups[i];
+      base_height->expand = expand_groups[i];
+    }
+}
 
 void
 gtk_cell_area_box_iter_push_group_width (GtkCellAreaBoxIter *box_iter,
-					 gint                group_id,
+					 gint                group_idx,
 					 gint                minimum_width,
 					 gint                natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  CachedSize                *size;
+  BaseSize                  *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id));
+  g_return_if_fail (group_idx < priv->base_widths->len);
 
-  if (!size)
-    {
-      size = cached_size_new (minimum_width, natural_width);
-      g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size);
-    }
-  else
-    {
-      size->min_size = MAX (size->min_size, minimum_width);
-      size->nat_size = MAX (size->nat_size, natural_width);
-    }
+  size = &g_array_index (priv->base_widths, BaseSize, group_idx);
+  size->min_size = MAX (size->min_size, minimum_width);
+  size->nat_size = MAX (size->nat_size, natural_width);
 }
 
 void
 gtk_cell_area_box_iter_push_group_height_for_width  (GtkCellAreaBoxIter *box_iter,
-						     gint                group_id,
+						     gint                group_idx,
 						     gint                for_width,
 						     gint                minimum_height,
 						     gint                natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *group_table;
+  GArray                    *group_array;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv        = box_iter->priv;
-  group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+  g_return_if_fail (group_idx < priv->base_widths->len);
 
-  if (!group_table)
+  group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+  if (!group_array)
     {
-      group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-					  NULL, (GDestroyNotify)cached_size_free);
+      group_array = g_array_new (FALSE, TRUE, sizeof (CachedSize));
+      g_array_set_size (group_array, priv->base_heights->len);
 
-      g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_table);
+      g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_array);
     }
 
-  size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
-
-  if (!size)
-    {
-      size = cached_size_new (minimum_height, natural_height);
-      g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size);
-    }
-  else
-    {
-      size->min_size = MAX (size->min_size, minimum_height);
-      size->nat_size = MAX (size->nat_size, natural_height);
-    }
+  size = &g_array_index (group_array, CachedSize, group_idx);
+  size->min_size = MAX (size->min_size, minimum_height);
+  size->nat_size = MAX (size->nat_size, natural_height);
 }
 
 void
 gtk_cell_area_box_iter_push_group_height (GtkCellAreaBoxIter *box_iter,
-					  gint                group_id,
+					  gint                group_idx,
 					  gint                minimum_height,
 					  gint                natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  CachedSize                *size;
+  BaseSize                  *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id));
+  g_return_if_fail (group_idx < priv->base_heights->len);
 
-  if (!size)
-    {
-      size = cached_size_new (minimum_height, natural_height);
-      g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size);
-    }
-  else
-    {
-      size->min_size = MAX (size->min_size, minimum_height);
-      size->nat_size = MAX (size->nat_size, natural_height);
-    }
+  size = &g_array_index (priv->base_heights, BaseSize, group_idx);
+  size->min_size = MAX (size->min_size, minimum_height);
+  size->nat_size = MAX (size->nat_size, natural_height);
 }
 
 void
 gtk_cell_area_box_iter_push_group_width_for_height (GtkCellAreaBoxIter *box_iter,
-						    gint                group_id,
+						    gint                group_idx,
 						    gint                for_height,
 						    gint                minimum_width,
 						    gint                natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *group_table;
+  GArray                    *group_array;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv        = box_iter->priv;
-  group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+  g_return_if_fail (group_idx < priv->base_widths->len);
 
-  if (!group_table)
+  group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+  if (!group_array)
     {
-      group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
-					  NULL, (GDestroyNotify)cached_size_free);
+      group_array = g_array_new (FALSE, TRUE, sizeof (CachedSize));
+      g_array_set_size (group_array, priv->base_heights->len);
 
-      g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_table);
+      g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_array);
     }
 
-  size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
-
-  if (!size)
-    {
-      size = cached_size_new (minimum_width, natural_width);
-      g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size);
-    }
-  else
-    {
-      size->min_size = MAX (size->min_size, minimum_width);
-      size->nat_size = MAX (size->nat_size, natural_width);
-    }
+  size = &g_array_index (group_array, CachedSize, group_idx);
+  size->min_size = MAX (size->min_size, minimum_width);
+  size->nat_size = MAX (size->nat_size, natural_width);
 }
 
 void
 gtk_cell_area_box_iter_get_group_width (GtkCellAreaBoxIter *box_iter,
-					gint                group_id,
+					gint                group_idx,
 					gint               *minimum_width,
 					gint               *natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  CachedSize                *size;
+  BaseSize                  *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id));
-
-  if (size)
-    {
-      if (minimum_width)
-	*minimum_width = size->min_size;
+  g_return_if_fail (group_idx < priv->base_widths->len);
 
-      if (natural_width)
-	*natural_width = size->nat_size;
-    }
-  else
-    {
-      if (minimum_width)
-	*minimum_width = -1;
+  size = &g_array_index (priv->base_widths, BaseSize, group_idx);
 
-      if (natural_width)
-	*natural_width = -1;      
-    }
+  if (minimum_width)
+    *minimum_width = size->min_size;
+  
+  if (natural_width)
+    *natural_width = size->nat_size;
 }
 
 void
 gtk_cell_area_box_iter_get_group_height_for_width (GtkCellAreaBoxIter *box_iter,
-						   gint                group_id,
+						   gint                group_idx,
 						   gint                for_width,
 						   gint               *minimum_height,
 						   gint               *natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *group_table;
-  CachedSize                *size = NULL;
+  GArray                    *group_array;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv        = box_iter->priv;
-  group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+  g_return_if_fail (group_idx < priv->base_widths->len);
 
-  if (group_table)
-    size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
+  group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
 
-  if (size)
+  if (group_array)
     {
+      CachedSize *size = &g_array_index (group_array, CachedSize, group_idx);
+
       if (minimum_height)
 	*minimum_height = size->min_size;
 
@@ -590,57 +725,48 @@ gtk_cell_area_box_iter_get_group_height_for_width (GtkCellAreaBoxIter *box_iter,
 
 void
 gtk_cell_area_box_iter_get_group_height (GtkCellAreaBoxIter *box_iter,
-					 gint                group_id,
+					 gint                group_idx,
 					 gint               *minimum_height,
 					 gint               *natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  CachedSize                *size;
+  BaseSize                  *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id));
+  g_return_if_fail (group_idx < priv->base_heights->len);
 
-  if (size)
-    {
-      if (minimum_height)
-	*minimum_height = size->min_size;
+  size = &g_array_index (priv->base_heights, BaseSize, group_idx);
 
-      if (natural_height)
-	*natural_height = size->nat_size;
-    }
-  else
-    {
-      if (minimum_height)
-	*minimum_height = -1;
-
-      if (natural_height)
-	*natural_height = -1;      
-    }
+  if (minimum_height)
+    *minimum_height = size->min_size;
+  
+  if (natural_height)
+    *natural_height = size->nat_size;
 }
 
 void
 gtk_cell_area_box_iter_get_group_width_for_height (GtkCellAreaBoxIter *box_iter,
-						   gint                group_id,
+						   gint                group_idx,
 						   gint                for_height,
 						   gint               *minimum_width,
 						   gint               *natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *group_table;
-  CachedSize                *size = NULL;
+  GArray                    *group_array;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
 
   priv        = box_iter->priv;
-  group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+  g_return_if_fail (group_idx < priv->base_widths->len);
 
-  if (group_table)
-    size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
+  group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
 
-  if (size)
+  if (group_array)
     {
+      CachedSize *size = &g_array_index (group_array, CachedSize, group_idx);
+
       if (minimum_width)
 	*minimum_width = size->min_size;
 
@@ -657,33 +783,31 @@ gtk_cell_area_box_iter_get_group_width_for_height (GtkCellAreaBoxIter *box_iter,
     }
 }
 
-static void
-fill_requested_sizes (gpointer          group_id_ptr,
-		      CachedSize       *cached_size,
-		      GtkRequestedSize *requested)
-{
-  gint group_id = GPOINTER_TO_INT (group_id_ptr);
-
-  requested[group_id].data         = group_id_ptr;
-  requested[group_id].minimum_size = cached_size->min_size;
-  requested[group_id].natural_size = cached_size->nat_size;
-}
-
 GtkRequestedSize *
 gtk_cell_area_box_iter_get_widths (GtkCellAreaBoxIter *box_iter,
 				   gint               *n_widths)
 {
   GtkCellAreaBoxIterPrivate *priv;
   GtkRequestedSize          *widths;
+  BaseSize                  *size;
+  gint                       i;
 
   g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL);
 
   priv = box_iter->priv;
 
-  *n_widths = g_hash_table_size (priv->widths);
-  widths    = g_new (GtkRequestedSize, *n_widths);
+  widths = g_new (GtkRequestedSize, priv->base_widths->len);
+
+  for (i = 0; i < priv->base_widths->len; i++)
+    {
+      size = &g_array_index (priv->base_widths, BaseSize, i);
+      widths[i].data         = GINT_TO_POINTER (i);
+      widths[i].minimum_size = size->min_size;
+      widths[i].natural_size = size->nat_size;
+    }
 
-  g_hash_table_foreach (priv->widths, (GHFunc)fill_requested_sizes, widths);
+  if (n_widths)
+    *n_widths = priv->base_widths->len;
 
   return widths;
 }
@@ -694,15 +818,25 @@ gtk_cell_area_box_iter_get_heights (GtkCellAreaBoxIter *box_iter,
 {
   GtkCellAreaBoxIterPrivate *priv;
   GtkRequestedSize          *heights;
+  BaseSize                  *size;
+  gint                       i;
 
   g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL);
 
   priv = box_iter->priv;
 
-  *n_heights = g_hash_table_size (priv->heights);
-  heights    = g_new (GtkRequestedSize, *n_heights);
+  heights = g_new (GtkRequestedSize, priv->base_heights->len);
+
+  for (i = 0; i < priv->base_heights->len; i++)
+    {
+      size = &g_array_index (priv->base_heights, BaseSize, i);
+      heights[i].data         = GINT_TO_POINTER (i);
+      heights[i].minimum_size = size->min_size;
+      heights[i].natural_size = size->nat_size;
+    }
 
-  g_hash_table_foreach (priv->heights, (GHFunc)fill_requested_sizes, heights);
+  if (n_heights)
+    *n_heights = priv->base_heights->len;
 
   return heights;
 }
diff --git a/gtk/gtkcellareaboxiter.h b/gtk/gtkcellareaboxiter.h
index 631a67c..73b4166 100644
--- a/gtk/gtkcellareaboxiter.h
+++ b/gtk/gtkcellareaboxiter.h
@@ -62,48 +62,53 @@ struct _GtkCellAreaBoxIterClass
 GType   gtk_cell_area_box_iter_get_type                     (void) G_GNUC_CONST;
 
 
+/* Initialize group array dimensions */
+void    gtk_cell_area_box_init_groups                       (GtkCellAreaBoxIter *box_iter,
+							     guint               n_groups,
+							     gboolean           *expand_groups);
+
 /* Update cell-group sizes */
 void    gtk_cell_area_box_iter_push_group_width             (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint                minimum_width,
 							     gint                natural_width);
 
 void    gtk_cell_area_box_iter_push_group_height_for_width  (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint                for_width,
 							     gint                minimum_height,
 							     gint                natural_height);
 
 void    gtk_cell_area_box_iter_push_group_height            (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint                minimum_height,
 							     gint                natural_height);
 
 void    gtk_cell_area_box_iter_push_group_width_for_height  (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint                for_height,
 							     gint                minimum_width,
 							     gint                natural_width);
 
 /* Fetch cell-group sizes */
 void    gtk_cell_area_box_iter_get_group_width              (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint               *minimum_width,
 							     gint               *natural_width);
 
 void    gtk_cell_area_box_iter_get_group_height_for_width   (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint                for_width,
 							     gint               *minimum_height,
 							     gint               *natural_height);
 
 void    gtk_cell_area_box_iter_get_group_height             (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint               *minimum_height,
 							     gint               *natural_height);
 
 void    gtk_cell_area_box_iter_get_group_width_for_height   (GtkCellAreaBoxIter *box_iter,
-							     gint                group_id,
+							     gint                group_idx,
 							     gint                for_height,
 							     gint               *minimum_width,
 							     gint               *natural_width);
@@ -119,11 +124,6 @@ typedef struct {
   gint size;
 } GtkCellAreaBoxAllocation;
 
-GtkCellAreaBoxAllocation *gtk_cell_area_box_allocate (GtkCellAreaBox     *box,
-						      GtkCellAreaBoxIter *iter,
-						      gint                size,
-						      gint               *n_allocs);
-
 G_CONST_RETURN GtkCellAreaBoxAllocation *
 gtk_cell_area_box_iter_get_orientation_allocs (GtkCellAreaBoxIter *iter,
 					       gint               *n_allocs);



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