]> Pileus Git - ~andy/gtk/commitdiff
Cleaned up GtkCellAreaIter implementation to use arrays to store grouped cell informa...
authorTristan Van Berkom <tristan.van.berkom@gmail.com>
Sun, 31 Oct 2010 04:06:10 +0000 (13:06 +0900)
committerTristan Van Berkom <tristan.van.berkom@gmail.com>
Sun, 31 Oct 2010 04:06:10 +0000 (13:06 +0900)
gtk/gtkcellareabox.c
gtk/gtkcellareaboxiter.c
gtk/gtkcellareaboxiter.h

index 273da69700adaf1e57851c3ef2aa759f74d7d9fc..a341dd7f08a5427a1aff2b1125c348ac67f1a203 100644 (file)
@@ -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
index 779315c178576cd121ad6dff166857994e7e23cf..d16aa968dbc5257e31c71fa6448a62c9e317bed7 100644 (file)
@@ -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;
@@ -79,6 +82,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)
 {
@@ -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;
@@ -131,27 +138,6 @@ gtk_cell_area_box_iter_class_init (GtkCellAreaBoxIterClass *class)
   g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxIterPrivate));
 }
 
-/*************************************************************
- *                      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                         *
  *************************************************************/
@@ -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;
 }
index 631a67cd90dface7e5a622409e52f2a9c0e724d7..73b4166ec3bf48d05656d2b6ae79a2303e1e3ef8 100644 (file)
@@ -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);