[gtk+/treeview-refactor] Made GtkCellAreaBox:align-cells a packing property per cell



commit 3b1c301a6627a0cf00cf0ab1f8b40198cae0bab5
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sat Oct 30 17:32:15 2010 +0900

    Made GtkCellAreaBox:align-cells a packing property per cell
    
    Implemented all request apis on GtkCellAreaBox considering
    alignment of groups of cells (some cells can be aligned while
    others fill space smartly).

 gtk/gtkcellarea.h        |    2 +-
 gtk/gtkcellareabox.c     |  697 ++++++++++++++++++++++++++++++----------------
 gtk/gtkcellareabox.h     |    9 +-
 gtk/gtkcellareaboxiter.c |  302 +++++++++++++++-----
 gtk/gtkcellareaboxiter.h |  102 ++++----
 gtk/gtkcellareaiter.c    |  226 ++++++++++++----
 gtk/gtkcellareaiter.h    |  100 ++++---
 7 files changed, 978 insertions(+), 460 deletions(-)
---
diff --git a/gtk/gtkcellarea.h b/gtk/gtkcellarea.h
index 5a9c770..9d4b16d 100644
--- a/gtk/gtkcellarea.h
+++ b/gtk/gtkcellarea.h
@@ -31,7 +31,6 @@
 #include <gtk/gtkcellrenderer.h>
 #include <gtk/gtkwidget.h>
 #include <gtk/gtktreemodel.h>
-#include <gtk/gtkcellareaiter.h>
 
 G_BEGIN_DECLS
 
@@ -45,6 +44,7 @@ G_BEGIN_DECLS
 typedef struct _GtkCellArea              GtkCellArea;
 typedef struct _GtkCellAreaClass         GtkCellAreaClass;
 typedef struct _GtkCellAreaPrivate       GtkCellAreaPrivate;
+typedef struct _GtkCellAreaIter          GtkCellAreaIter;
 
 /**
  * GtkCellCallback:
diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c
index 511e8a0..f1a7cc1 100644
--- a/gtk/gtkcellareabox.c
+++ b/gtk/gtkcellareabox.c
@@ -97,20 +97,37 @@ static void      gtk_cell_area_box_layout_reorder                 (GtkCellLayout
 								   gint                position);
 
 
-/* CellInfo metadata handling */
+/* CellInfo/CellGroup metadata handling */
 typedef struct {
   GtkCellRenderer *renderer;
 
-  guint            expand : 1;
-  guint            pack   : 1;
+  guint            expand : 1; /* Whether the cell expands */
+  guint            pack   : 1; /* Whether the cell is packed from the start or end */
+  guint            align  : 1; /* Whether to align this cell's position with adjacent rows */
 } CellInfo;
 
-static CellInfo  *cell_info_new  (GtkCellRenderer *renderer, 
-				  gboolean         expand,
-				  GtkPackType      pack);
-static void       cell_info_free (CellInfo        *info);
-static gint       cell_info_find (CellInfo        *info,
-				  GtkCellRenderer *renderer);
+typedef struct {
+  GList *cells;
+
+  guint  id : 16;
+  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);
 
 
 struct _GtkCellAreaBoxPrivate
@@ -118,17 +135,15 @@ struct _GtkCellAreaBoxPrivate
   GtkOrientation orientation;
 
   GList         *cells;
+  GList         *groups;
 
   gint           spacing;
-
-  guint          align_cells : 1;
 };
 
 enum {
   PROP_0,
   PROP_ORIENTATION,
-  PROP_SPACING,
-  PROP_ALIGN_CELLS
+  PROP_SPACING
 };
 
 G_DEFINE_TYPE_WITH_CODE (GtkCellAreaBox, gtk_cell_area_box, GTK_TYPE_CELL_AREA,
@@ -136,6 +151,10 @@ G_DEFINE_TYPE_WITH_CODE (GtkCellAreaBox, gtk_cell_area_box, GTK_TYPE_CELL_AREA,
 						gtk_cell_area_box_cell_layout_init)
 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL));
 
+#define OPPOSITE_ORIENTATION(orientation)			\
+  ((orientation) == GTK_ORIENTATION_HORIZONTAL ?		\
+   GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL)
+
 static void
 gtk_cell_area_box_init (GtkCellAreaBox *box)
 {
@@ -148,8 +167,8 @@ gtk_cell_area_box_init (GtkCellAreaBox *box)
 
   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
   priv->cells       = NULL;
+  priv->groups      = NULL;
   priv->spacing     = 0;
-  priv->align_cells = TRUE;
 }
 
 static void 
@@ -190,32 +209,25 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class)
 						     0,
 						     GTK_PARAM_READWRITE));
 
-  g_object_class_install_property (object_class,
-                                   PROP_ALIGN_CELLS,
-                                   g_param_spec_boolean ("align-cells",
-							 P_("Align Cells"),
-							 P_("Whether cells should be aligned with those "
-							    "rendered in adjacent rows"),
-							 TRUE,
-							 GTK_PARAM_READWRITE));
-
   g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxPrivate));
 }
 
 
 /*************************************************************
- *                    CellInfo Basics                        *
+ *                CellInfo/CellGroup Basics                  *
  *************************************************************/
 static CellInfo *
 cell_info_new  (GtkCellRenderer *renderer, 
+		GtkPackType      pack,
 		gboolean         expand,
-		GtkPackType      pack)
+		gboolean         align)
 {
   CellInfo *info = g_slice_new (CellInfo);
   
   info->renderer = g_object_ref_sink (renderer);
-  info->expand   = expand;
   info->pack     = pack;
+  info->expand   = expand;
+  info->align    = align;
 
   return info;
 }
@@ -235,6 +247,139 @@ cell_info_find (CellInfo        *info,
   return (info->renderer == renderer) ? 0 : -1;
 }
 
+static CellGroup *
+cell_group_new (guint id)
+{
+  CellGroup *group = g_slice_new0 (CellGroup);
+
+  group->id = id;
+
+  return group;
+}
+
+static void
+cell_group_free (CellGroup *group)
+{
+  g_list_free (group->cells);
+  g_slice_free (CellGroup, group);  
+}
+
+static GList *
+list_consecutive_cells (GtkCellAreaBox *box)
+{
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  GList                 *l, *consecutive_cells = NULL, *pack_end_cells = NULL;
+  CellInfo              *info;
+
+  /* List cells in consecutive order taking their 
+   * PACK_START/PACK_END options into account 
+   */
+  for (l = priv->cells; l; l = l->next)
+    {
+      info = l->data;
+      
+      if (info->pack == GTK_PACK_START)
+	consecutive_cells = g_list_prepend (consecutive_cells, info);
+    }
+
+  for (l = priv->cells; l; l = l->next)
+    {
+      info = l->data;
+      
+      if (info->pack == GTK_PACK_END)
+	pack_end_cells = g_list_prepend (pack_end_cells, info);
+    }
+
+  consecutive_cells = g_list_reverse (consecutive_cells);
+  consecutive_cells = g_list_concat (consecutive_cells, pack_end_cells);
+
+  return consecutive_cells;
+}
+
+static GList *
+construct_cell_groups (GtkCellAreaBox  *box)
+{
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  CellGroup             *group;
+  GList                 *cells, *l;
+  GList                 *groups = NULL;
+  guint                  id = 0;
+
+  if (!priv->cells)
+    return NULL;
+
+  cells  = list_consecutive_cells (box);
+  group  = cell_group_new (id++);
+  groups = g_list_prepend (groups, group);
+
+  for (l = cells; l; l = l->next)
+    {
+      CellInfo *info = l->data;
+
+      /* A new group starts with any aligned cell, the first group is implied */
+      if (info->align && l != cells)
+	{
+	  group  = cell_group_new (id++);
+	  groups = g_list_prepend (groups, group);
+	}
+
+      group->cells = g_list_prepend (group->cells, info);
+
+      /* A group expands if it contains any expand cells */
+      if (info->expand)
+	group->expand = TRUE;
+    }
+
+  g_list_free (cells);
+
+  for (l = cells; l; l = l->next)
+    {
+      group = l->data;
+      group->cells = g_list_reverse (group->cells);
+    }
+
+  return g_list_reverse (groups);
+}
+
+static gint
+count_expand_groups (GtkCellAreaBox  *box)
+{
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  GList                 *l;
+  gint                   expand_groups = 0;
+
+  for (l = priv->groups; l; l = l->next)
+    {
+      CellGroup *group = l->data;
+
+      if (group->expand)
+	expand_groups++;
+    }
+
+  return expand_groups;
+}
+
+static gint
+count_expand_cells (CellGroup *group)
+{
+  GList *l;
+  gint   expand_cells = 0;
+
+  if (!group->expand)
+    return 0;
+
+  for (l = group->cells; l; l = l->next)
+    {
+      CellInfo *info = l->data;
+
+      if (info->expand)
+	expand_cells++;
+    }
+
+  return expand_cells;
+}
+
+
 /*************************************************************
  *                      GObjectClass                         *
  *************************************************************/
@@ -256,7 +401,17 @@ gtk_cell_area_box_set_property (GObject       *object,
 				const GValue  *value,
 				GParamSpec    *pspec)
 {
+  GtkCellAreaBox *box = GTK_CELL_AREA_BOX (object);
 
+  switch (prop_id)
+    {
+    case PROP_SPACING:
+      gtk_cell_area_box_set_spacing (box, g_value_get_int (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
 }
 
 static void
@@ -265,7 +420,17 @@ gtk_cell_area_box_get_property (GObject     *object,
 				GValue      *value,
 				GParamSpec  *pspec)
 {
+  GtkCellAreaBox *box = GTK_CELL_AREA_BOX (object);
 
+  switch (prop_id)
+    {
+    case PROP_SPACING:
+      g_value_set_int (value, gtk_cell_area_box_get_spacing (box));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
 }
 
 /*************************************************************
@@ -276,7 +441,7 @@ gtk_cell_area_box_add (GtkCellArea        *area,
 		       GtkCellRenderer    *renderer)
 {
   gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area),
-				renderer, FALSE);
+				renderer, FALSE, TRUE);
 }
 
 static void
@@ -297,6 +462,16 @@ gtk_cell_area_box_remove (GtkCellArea        *area,
       cell_info_free (info);
 
       priv->cells = g_list_delete_link (priv->cells, node);
+
+      /* Reconstruct cell groups
+       * XXX TODO: add a list of iters and weak_ref's on them, then
+       * flush the iters when we reconstruct groups, change spacing
+       * or child expand properties (i.e. notify size needs to be
+       * recalculated).
+       */
+      g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL);
+      g_list_free (priv->groups);
+      priv->groups = construct_cell_groups (box);
     }
   else
     g_warning ("Trying to remove a cell renderer that is not present GtkCellAreaBox");
@@ -387,137 +562,279 @@ compute_size (GtkCellAreaBox     *box,
 	      GtkOrientation      orientation,
 	      GtkCellAreaBoxIter *iter,
 	      GtkWidget          *widget,
+	      gint                for_size,
 	      gint               *minimum_size,
 	      gint               *natural_size)
 {
   GtkCellAreaBoxPrivate *priv = box->priv;
+  CellGroup             *group;
   CellInfo              *info;
-  GList                 *l;
+  GList                 *cell_list, *group_list;
   gint                   min_size = 0;
   gint                   nat_size = 0;
-  gboolean               first_cell = TRUE;
   
-  for (l = priv->cells; l; l = l->next)
+  for (group_list = priv->groups; group_list; group_list = group_list->next)
     {
-      gint renderer_min_size, renderer_nat_size;
-
-      info = l->data;
+      gint group_min_size = 0;
+      gint group_nat_size = 0;
 
-      get_renderer_size (info->renderer, orientation, widget, -1, 
-			 &renderer_min_size, &renderer_nat_size);
+      group = group_list->data;
 
-      /* If we're aligning the cells we need to cache the max results
-       * for all requests performed with the same iter.
-       */
-      if (priv->align_cells)
+      for (cell_list = group->cells; cell_list; cell_list = cell_list->next)
 	{
-	  if (orientation == GTK_ORIENTATION_HORIZONTAL)
-	    gtk_cell_area_box_iter_push_cell_width (iter, info->renderer, 
-						    renderer_min_size, renderer_nat_size);
+	  gint renderer_min_size, renderer_nat_size;
+	  
+	  info = cell_list->data;
+	  
+	  get_renderer_size (info->renderer, orientation, widget, for_size, 
+			     &renderer_min_size, &renderer_nat_size);
+
+	  if (orientation == priv->orientation)
+	    {
+	      if (min_size > 0)
+		{
+		  min_size += priv->spacing;
+		  nat_size += priv->spacing;
+		}
+	      
+	      if (group_min_size > 0)
+		{
+		  group_min_size += priv->spacing;
+		  group_nat_size += priv->spacing;
+		}
+	      
+	      min_size       += renderer_min_size;
+	      nat_size       += renderer_nat_size;
+	      group_min_size += renderer_min_size;
+	      group_nat_size += renderer_nat_size;
+	    }
 	  else
-	    gtk_cell_area_box_iter_push_cell_height (iter, info->renderer, 
-						     renderer_min_size, renderer_nat_size);
+	    {
+	      min_size       = MAX (min_size, renderer_min_size);
+	      nat_size       = MAX (nat_size, renderer_nat_size);
+	      group_min_size = MAX (group_min_size, renderer_min_size);
+	      group_nat_size = MAX (group_nat_size, renderer_nat_size);
+	    }
 	}
 
-      if (orientation == priv->orientation)
+      if (orientation == GTK_ORIENTATION_HORIZONTAL)
 	{
-	  min_size += renderer_min_size;
-	  nat_size += renderer_nat_size;
-
-	  if (!first_cell)
-	    {
-	      min_size += priv->spacing;
-	      nat_size += priv->spacing;
-	    }
+	  if (for_size < 0)
+	    gtk_cell_area_box_iter_push_group_width (iter, group->id, group_min_size, group_nat_size);
+	  else
+	    gtk_cell_area_box_iter_push_group_width_for_height (iter, group->id, for_size,
+								group_min_size, group_nat_size);
 	}
       else
 	{
-	  min_size = MAX (min_size, renderer_min_size);
-	  nat_size = MAX (nat_size, renderer_nat_size);
+	  if (for_size < 0)
+	    gtk_cell_area_box_iter_push_group_height (iter, group->id, group_min_size, group_nat_size);
+	  else
+	    gtk_cell_area_box_iter_push_group_height_for_width (iter, group->id, for_size,
+								group_min_size, group_nat_size);
 	}
-
-      if (first_cell)
-	first_cell = FALSE;
     }
 
   *minimum_size = min_size;
   *natural_size = nat_size;
 }
 
+GtkRequestedSize *
+get_group_sizes (CellGroup      *group,
+		 GtkOrientation  orientation,
+		 GtkWidget      *widget,
+		 gint           *n_sizes)
+{
+  GtkRequestedSize *sizes;
+  GList            *l;
+  gint              i;
+
+  *n_sizes = g_list_length (group->cells);
+  sizes    = g_new (GtkRequestedSize, *n_sizes);
+
+  for (l = group->cells, i = 0; l; l = l->next, i++)
+    {
+      CellInfo *info = l->data;
+
+      sizes[i].data = info;
+      
+      get_renderer_size (info->renderer,
+			 orientation, widget, -1,
+			 &sizes[i].minimum_size,
+			 &sizes[i].natural_size);
+    }
+
+  return sizes;
+}
+
 static void
-update_iter_aligned (GtkCellAreaBox     *box,
-		     GtkCellAreaBoxIter *iter,
-		     gint                for_size)
+compute_group_size_for_opposing_orientation (GtkCellAreaBox     *box,
+					     CellGroup          *group,
+					     GtkWidget          *widget, 
+					     gint                for_size,
+					     gint               *minimum_size, 
+					     gint               *natural_size)
 {
   GtkCellAreaBoxPrivate *priv = box->priv;
-  CellInfo              *info;
-  GList                 *l;
-  gint                   min_size = 0;
-  gint                   nat_size = 0;
-  gboolean               first_cell = TRUE;
 
-  for (l = priv->cells; l; l = l->next)
+  /* Exception for single cell groups */
+  if (!group->cells->next)
     {
-      gint aligned_min_size, aligned_nat_size;
-      
-      info = l->data;
+      CellInfo *info = group->cells->data;
 
-      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+      get_renderer_size (info->renderer,
+			 OPPOSITE_ORIENTATION (priv->orientation),
+			 widget, for_size, minimum_size, natural_size);
+    }
+  else
+    {
+      GtkRequestedSize *orientation_sizes;
+      CellInfo         *info;
+      gint              n_sizes, i;
+      gint              n_expand_cells = count_expand_cells (group);
+      gint              avail_size     = for_size;
+      gint              extra_size, extra_extra;
+      gint              min_size = 0, nat_size = 0;
+
+      orientation_sizes = get_group_sizes (group, priv->orientation, widget, &n_sizes);
+
+      /* First naturally allocate the cells in the group into the for_size */
+      avail_size -= (n_sizes - 1) * priv->spacing;
+      for (i = 0; i < n_sizes; i++)
+	avail_size -= orientation_sizes[i].minimum_size;
+
+      avail_size = gtk_distribute_natural_allocation (avail_size, n_sizes, orientation_sizes);
+
+      /* Calculate/distribute expand for cells */
+      if (n_expand_cells > 0)
 	{
-	  if (for_size < 0)
-	    gtk_cell_area_box_iter_get_cell_width (iter, info->renderer, 
-						   &aligned_min_size,
-						   &aligned_nat_size);
-	  else
-	    gtk_cell_area_box_iter_get_cell_width_for_height (iter, info->renderer, 
-							      for_size,
-							      &aligned_min_size,
-							      &aligned_nat_size);
+	  extra_size  = avail_size / n_expand_cells;
+	  extra_extra = avail_size % n_expand_cells;
 	}
       else
-	{
-	  if (for_size < 0)
-	    gtk_cell_area_box_iter_get_cell_height (iter, info->renderer, 
-						    &aligned_min_size,
-						    &aligned_nat_size);
-	  else
-	    gtk_cell_area_box_iter_get_cell_height_for_width (iter, info->renderer, 
-							      for_size,
-							      &aligned_min_size,
-							      &aligned_nat_size);
-	}
+	extra_size = extra_extra = 0;
 
-      min_size += aligned_min_size;
-      nat_size += aligned_nat_size;
-      
-      if (!first_cell)
+      for (i = 0; i < n_sizes; i++)
 	{
-	  min_size += priv->spacing;
-	  nat_size += priv->spacing;
+	  gint cell_min, cell_nat;
+
+	  info = orientation_sizes[i].data;
+
+	  if (info->expand)
+	    {
+	      orientation_sizes[i].minimum_size += extra_size;
+	      if (extra_extra)
+		{
+		  orientation_sizes[i].minimum_size++;
+		  extra_extra--;
+		}
+	    }
+
+	  get_renderer_size (info->renderer,
+			     OPPOSITE_ORIENTATION (priv->orientation),
+			     widget, 
+			     orientation_sizes[i].minimum_size,
+			     &cell_min, &cell_nat);
+
+	  min_size = MAX (min_size, cell_min);
+	  nat_size = MAX (nat_size, cell_nat);
 	}
-      
-      if (first_cell)
-	first_cell = FALSE;
+
+      *minimum_size = min_size;
+      *natural_size = nat_size;
+
+      g_free (orientation_sizes);
     }
+}
+
+static void
+compute_size_for_opposing_orientation (GtkCellAreaBox     *box, 
+				       GtkCellAreaBoxIter *iter, 
+				       GtkWidget          *widget, 
+				       gint                for_size,
+				       gint               *minimum_size, 
+				       gint               *natural_size)
+{
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  CellGroup             *group;
+  GList                 *group_list;
+  GtkRequestedSize      *orientation_sizes;
+  gint                   n_groups, n_expand_groups, i;
+  gint                   avail_size = for_size;
+  gint                   extra_size, extra_extra;
+  gint                   min_size = 0, nat_size = 0;
+
+  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);
+
+  /* Calculate/distribute expand for groups */
+  if (n_expand_groups > 0)
     {
-      if (for_size < 0)
-	gtk_cell_area_iter_push_preferred_width (GTK_CELL_AREA_ITER (iter), min_size, nat_size);
-      else
-	gtk_cell_area_iter_push_preferred_width_for_height (GTK_CELL_AREA_ITER (iter), 
-							    for_size, min_size, nat_size);
+      extra_size  = avail_size / n_expand_groups;
+      extra_extra = avail_size % n_expand_groups;
     }
   else
+    extra_size = extra_extra = 0;
+
+  /* Now we need to naturally allocate sizes for cells in each group
+   * and push the height-for-width for each group accordingly while accumulating
+   * the overall height-for-width for this row.
+   */
+  for (group_list = priv->groups; group_list; group_list = group_list->next)
     {
-      if (for_size < 0)
-	gtk_cell_area_iter_push_preferred_height (GTK_CELL_AREA_ITER (iter), min_size, nat_size);
+      gint group_min, group_nat;
+
+      group = group_list->data;
+
+      if (group->expand)
+	{
+	  orientation_sizes[group->id].minimum_size += extra_size;
+	  if (extra_extra)
+	    {
+	      orientation_sizes[group->id].minimum_size++;
+	      extra_extra--;
+	    }
+	}
+
+      /* Now we have the allocation for the group, request it's height-for-width */
+      compute_group_size_for_opposing_orientation (box, group, widget,
+						   orientation_sizes[group->id].minimum_size,
+						   &group_min, &group_nat);
+
+      min_size = MAX (min_size, group_min);
+      nat_size = MAX (nat_size, group_nat);
+
+      if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+	{
+	  gtk_cell_area_box_iter_push_group_height_for_width (iter, group->id, for_size,
+							      group_min, group_nat);
+	}
       else
-	gtk_cell_area_iter_push_preferred_height_for_width (GTK_CELL_AREA_ITER (iter), 
-							    for_size, min_size, nat_size);
+	{
+	  gtk_cell_area_box_iter_push_group_width_for_height (iter, group->id, for_size,
+							      group_min, group_nat);
+	}
     }
+
+  *minimum_size = min_size;
+  *natural_size = nat_size;
+
+  g_free (orientation_sizes);
 }
 
+
+
 static void
 gtk_cell_area_box_get_preferred_width (GtkCellArea        *area,
 				       GtkCellAreaIter    *iter,
@@ -527,25 +844,16 @@ gtk_cell_area_box_get_preferred_width (GtkCellArea        *area,
 {
   GtkCellAreaBox        *box = GTK_CELL_AREA_BOX (area);
   GtkCellAreaBoxIter    *box_iter;
-  GtkCellAreaBoxPrivate *priv;
   gint                   min_width, nat_width;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter));
 
   box_iter = GTK_CELL_AREA_BOX_ITER (iter);
-  priv     = box->priv;
 
-  /* Compute the size of all renderers for current row data, possibly
+  /* Compute the size of all renderers for current row data, 
    * bumping cell alignments in the iter along the way */
   compute_size (box, GTK_ORIENTATION_HORIZONTAL,
-		box_iter, widget, &min_width, &nat_width);
-
-  /* Update width of the iter based on aligned cell sizes if 
-   * appropriate */
-  if (priv->align_cells && priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-    update_iter_aligned (box, box_iter, -1);
-  else
-    gtk_cell_area_iter_push_preferred_width (iter, min_width, nat_width);
+		box_iter, widget, -1, &min_width, &nat_width);
 
   if (minimum_width)
     *minimum_width = min_width;
@@ -563,25 +871,16 @@ gtk_cell_area_box_get_preferred_height (GtkCellArea        *area,
 {
   GtkCellAreaBox        *box = GTK_CELL_AREA_BOX (area);
   GtkCellAreaBoxIter    *box_iter;
-  GtkCellAreaBoxPrivate *priv;
   gint                   min_height, nat_height;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter));
 
   box_iter = GTK_CELL_AREA_BOX_ITER (iter);
-  priv     = box->priv;
 
-  /* Compute the size of all renderers for current row data, possibly
+  /* Compute the size of all renderers for current row data, 
    * bumping cell alignments in the iter along the way */
   compute_size (box, GTK_ORIENTATION_VERTICAL,
-		box_iter, widget, &min_height, &nat_height);
-
-  /* Update width of the iter based on aligned cell sizes if 
-   * appropriate */
-  if (priv->align_cells && priv->orientation == GTK_ORIENTATION_VERTICAL)
-    update_iter_aligned (box, box_iter, -1);
-  else
-    gtk_cell_area_iter_push_preferred_height (iter, min_height, nat_height);
+		box_iter, widget, -1, &min_height, &nat_height);
 
   if (minimum_height)
     *minimum_height = min_height;
@@ -591,61 +890,6 @@ gtk_cell_area_box_get_preferred_height (GtkCellArea        *area,
 }
 
 static void
-compute_size_for_orientation (GtkCellAreaBox     *box, 
-			      GtkCellAreaBoxIter *iter, 
-			      GtkWidget          *widget, 
-			      gint                for_size,
-			      gint               *minimum_size, 
-			      gint               *natural_size)
-{
-  GtkCellAreaBoxPrivate *priv = box->priv;
-  CellInfo              *info;
-  GList                 *l;
-  gint                   min_size = 0;
-  gint                   nat_size = 0;
-  gboolean               first_cell = TRUE;
-  
-  for (l = priv->cells; l; l = l->next)
-    {
-      gint renderer_min_size, renderer_nat_size;
-
-      info = l->data;
-
-      get_renderer_size (info->renderer, priv->orientation, widget, for_size, 
-			 &renderer_min_size, &renderer_nat_size);
-
-      /* If we're aligning the cells we need to cache the max results
-       * for all requests performed with the same iter.
-       */
-      if (priv->align_cells)
-	{
-	  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
-	    gtk_cell_area_box_iter_push_cell_width_for_height (iter, info->renderer, for_size,
-							       renderer_min_size, renderer_nat_size);
-	  else
-	    gtk_cell_area_box_iter_push_cell_height_for_width (iter, info->renderer, for_size,
-							       renderer_min_size, renderer_nat_size);
-	}
-
-      min_size += renderer_min_size;
-      nat_size += renderer_nat_size;
-      
-      if (!first_cell)
-	{
-	  min_size += priv->spacing;
-	  nat_size += priv->spacing;
-	}
-      
-      if (first_cell)
-	first_cell = FALSE;
-    }
-
-  *minimum_size = min_size;
-  *natural_size = nat_size;
-}
-
-
-static void
 gtk_cell_area_box_get_preferred_height_for_width (GtkCellArea        *area,
 						  GtkCellAreaIter    *iter,
 						  GtkWidget          *widget,
@@ -665,21 +909,15 @@ gtk_cell_area_box_get_preferred_height_for_width (GtkCellArea        *area,
 
   if (priv->orientation == GTK_ORIENTATION_VERTICAL)
     {
-      /* Add up vertical requests of height for width and possibly push the overall 
+      /* Add up vertical requests of height for width and push the overall 
        * cached sizes for alignments */
-      compute_size_for_orientation (box, box_iter, widget, width, &min_height, &nat_height);
-
-      /* Update the overall cached height for width based on aligned cells if appropriate */
-      if (priv->align_cells)
-	update_iter_aligned (box, box_iter, width);
-      else
-	gtk_cell_area_iter_push_preferred_height_for_width (GTK_CELL_AREA_ITER (iter),
-							    width, min_height, nat_height);
+      compute_size (box, priv->orientation, box_iter, widget, width, &min_height, &nat_height);
     }
   else
     {
-      /* XXX Juice: virtually allocate cells into the for_width possibly using the 
+      /* Juice: virtually allocate cells into the for_width using the 
        * alignments and then return the overall height for that width, and cache it */
+      compute_size_for_opposing_orientation (box, box_iter, widget, width, &min_height, &nat_height);
     }
 
   if (minimum_height)
@@ -709,21 +947,15 @@ gtk_cell_area_box_get_preferred_width_for_height (GtkCellArea        *area,
 
   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
     {
-      /* Add up vertical requests of height for width and possibly push the overall 
+      /* Add up horizontal requests of width for height and push the overall 
        * cached sizes for alignments */
-      compute_size_for_orientation (box, box_iter, widget, height, &min_width, &nat_width);
-
-      /* Update the overall cached height for width based on aligned cells if appropriate */
-      if (priv->align_cells)
-	update_iter_aligned (box, box_iter, height);
-      else
-	gtk_cell_area_iter_push_preferred_height_for_width (GTK_CELL_AREA_ITER (iter),
-							    height, min_width, nat_width);
+      compute_size (box, priv->orientation, box_iter, widget, height, &min_width, &nat_width);
     }
   else
     {
-      /* XXX Juice: virtually allocate cells into the for_width possibly using the 
-       * alignments and then return the overall height for that width, and cache it */
+      /* Juice: horizontally allocate cells into the for_height using the 
+       * alignments and then return the overall width for that height, and cache it */
+      compute_size_for_opposing_orientation (box, box_iter, widget, height, &min_width, &nat_width);
     }
 
   if (minimum_width)
@@ -750,7 +982,7 @@ gtk_cell_area_box_layout_pack_start (GtkCellLayout      *cell_layout,
 				     GtkCellRenderer    *renderer,
 				     gboolean            expand)
 {
-  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, TRUE);
 }
 
 static void
@@ -758,7 +990,7 @@ gtk_cell_area_box_layout_pack_end (GtkCellLayout      *cell_layout,
 				   GtkCellRenderer    *renderer,
 				   gboolean            expand)
 {
-  gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand);
+  gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, TRUE);
 }
 
 static void
@@ -795,7 +1027,8 @@ gtk_cell_area_box_new (void)
 void
 gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
 			       GtkCellRenderer *renderer,
-			       gboolean         expand)
+			       gboolean         expand,
+			       gboolean         align)
 {
   GtkCellAreaBoxPrivate *priv;
   CellInfo              *info;
@@ -812,15 +1045,21 @@ gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
       return;
     }
 
-  info = cell_info_new (renderer, expand, GTK_PACK_START);
+  info = cell_info_new (renderer, GTK_PACK_START, expand, align);
 
   priv->cells = g_list_append (priv->cells, info);
+
+  /* Reconstruct cell groups (TODO, notify created iters that size needs renegotiation) */
+  g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL);
+  g_list_free (priv->groups);
+  priv->groups = construct_cell_groups (box);
 }
 
 void
 gtk_cell_area_box_pack_end (GtkCellAreaBox  *box,
 			    GtkCellRenderer *renderer,
-			    gboolean         expand)
+			    gboolean         expand, 
+			    gboolean         align)
 {
   GtkCellAreaBoxPrivate *priv;
   CellInfo              *info;
@@ -837,9 +1076,14 @@ gtk_cell_area_box_pack_end (GtkCellAreaBox  *box,
       return;
     }
 
-  info = cell_info_new (renderer, expand, GTK_PACK_END);
+  info = cell_info_new (renderer, GTK_PACK_END, expand, align);
 
   priv->cells = g_list_append (priv->cells, info);
+
+  /* Reconstruct cell groups (TODO, notify created iters that size needs renegotiation) */
+  g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL);
+  g_list_free (priv->groups);
+  priv->groups = construct_cell_groups (box);
 }
 
 gint
@@ -864,32 +1108,7 @@ gtk_cell_area_box_set_spacing (GtkCellAreaBox  *box,
     {
       priv->spacing = spacing;
 
+      /* TODO, notify created iters that size needs renegotiation */
       g_object_notify (G_OBJECT (box), "spacing");
     }
 }
-
-gboolean
-gtk_cell_area_box_get_align_cells (GtkCellAreaBox  *box)
-{
-  g_return_val_if_fail (GTK_IS_CELL_AREA_BOX (box), FALSE);
-
-  return box->priv->align_cells;
-}
-
-void
-gtk_cell_area_box_set_align_cells (GtkCellAreaBox  *box,
-				   gboolean         align)
-{
-  GtkCellAreaBoxPrivate *priv;
-
-  g_return_if_fail (GTK_IS_CELL_AREA_BOX (box));
-
-  priv = box->priv;
-
-  if (priv->align_cells != align)
-    {
-      priv->align_cells = align;
-
-      g_object_notify (G_OBJECT (box), "align-cells");
-    }
-}
diff --git a/gtk/gtkcellareabox.h b/gtk/gtkcellareabox.h
index ee29ffe..0a0c052 100644
--- a/gtk/gtkcellareabox.h
+++ b/gtk/gtkcellareabox.h
@@ -67,16 +67,15 @@ GType              gtk_cell_area_box_get_type        (void) G_GNUC_CONST;
 GtkCellArea       *gtk_cell_area_box_new             (void);
 void               gtk_cell_area_box_pack_start      (GtkCellAreaBox  *box,
 						      GtkCellRenderer *renderer,
-						      gboolean         expand);
+						      gboolean         expand,
+						      gboolean         align);
 void               gtk_cell_area_box_pack_end        (GtkCellAreaBox  *box,
 						      GtkCellRenderer *renderer,
-						      gboolean         expand);
+						      gboolean         expand,
+						      gboolean         align);
 gint               gtk_cell_area_box_get_spacing     (GtkCellAreaBox  *box);
 void               gtk_cell_area_box_set_spacing     (GtkCellAreaBox  *box,
 						      gint             spacing);
-gboolean           gtk_cell_area_box_get_align_cells (GtkCellAreaBox  *box);
-void               gtk_cell_area_box_set_align_cells (GtkCellAreaBox  *box,
-						      gboolean         align);
 
 G_END_DECLS
 
diff --git a/gtk/gtkcellareaboxiter.c b/gtk/gtkcellareaboxiter.c
index 791d6b4..9f3474d 100644
--- a/gtk/gtkcellareaboxiter.c
+++ b/gtk/gtkcellareaboxiter.c
@@ -23,12 +23,19 @@
 
 #include "config.h"
 #include "gtkintl.h"
+#include "gtkcellareabox.h"
 #include "gtkcellareaboxiter.h"
 
 /* GObjectClass */
 static void      gtk_cell_area_box_iter_finalize                         (GObject            *object);
 
 /* GtkCellAreaIterClass */
+static void      gtk_cell_area_box_iter_sum_preferred_width              (GtkCellAreaIter *iter);
+static void      gtk_cell_area_box_iter_sum_preferred_height_for_width   (GtkCellAreaIter *iter,
+									  gint             width);
+static void      gtk_cell_area_box_iter_sum_preferred_height             (GtkCellAreaIter *iter);
+static void      gtk_cell_area_box_iter_sum_preferred_width_for_height   (GtkCellAreaIter *iter,
+									  gint             height);
 static void      gtk_cell_area_box_iter_flush_preferred_width            (GtkCellAreaIter *iter);
 static void      gtk_cell_area_box_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
 									  gint             width);
@@ -88,6 +95,11 @@ gtk_cell_area_box_iter_class_init (GtkCellAreaBoxIterClass *class)
   /* GObjectClass */
   object_class->finalize = gtk_cell_area_box_iter_finalize;
 
+  iter_class->sum_preferred_width            = gtk_cell_area_box_iter_sum_preferred_width;
+  iter_class->sum_preferred_height_for_width = gtk_cell_area_box_iter_sum_preferred_height_for_width;
+  iter_class->sum_preferred_height           = gtk_cell_area_box_iter_sum_preferred_height;
+  iter_class->sum_preferred_width_for_height = gtk_cell_area_box_iter_sum_preferred_width_for_height;
+
   iter_class->flush_preferred_width            = gtk_cell_area_box_iter_flush_preferred_width;
   iter_class->flush_preferred_height_for_width = gtk_cell_area_box_iter_flush_preferred_height_for_width;
   iter_class->flush_preferred_height           = gtk_cell_area_box_iter_flush_preferred_height;
@@ -137,6 +149,102 @@ gtk_cell_area_box_iter_finalize (GObject *object)
 /*************************************************************
  *                    GtkCellAreaIterClass                   *
  *************************************************************/
+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, };
+
+  area          = gtk_cell_area_iter_get_area (iter);
+  accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+
+  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);
+}
+
+static void
+gtk_cell_area_box_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter,
+						       gint             width)
+{
+  GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
+  GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
+  GHashTable                *group_table;
+  AccumData                  accum    = { 0, };
+
+  group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (width));
+
+  if (group_table)
+    {
+      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);
+    }
+}
+
+static void
+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, };
+
+  area          = gtk_cell_area_iter_get_area (iter);
+  accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (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);
+}
+
+static void
+gtk_cell_area_box_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter,
+						       gint             height)
+{
+  GtkCellAreaBoxIter        *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
+  GtkCellAreaBoxIterPrivate *priv     = box_iter->priv;
+  GHashTable                *group_table;
+  AccumData                  accum    = { 0, };
+
+  group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (height));
+
+  if (group_table)
+    {
+      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);
+    }
+}
+
 static void
 gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter)
 {
@@ -200,24 +308,23 @@ gtk_cell_area_box_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
  *************************************************************/
 
 void
-gtk_cell_area_box_iter_push_cell_width (GtkCellAreaBoxIter *box_iter,
-					GtkCellRenderer    *renderer,
-					gint                minimum_width,
-					gint                natural_width)
+gtk_cell_area_box_iter_push_group_width (GtkCellAreaBoxIter *box_iter,
+					 gint                group_id,
+					 gint                minimum_width,
+					 gint                natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_widths, renderer);
+  size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id));
 
   if (!size)
     {
       size = cached_size_new (minimum_width, natural_width);
-      g_hash_table_insert (priv->base_widths, renderer, size);
+      g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size);
     }
   else
     {
@@ -227,36 +334,35 @@ gtk_cell_area_box_iter_push_cell_width (GtkCellAreaBoxIter *box_iter,
 }
 
 void
-gtk_cell_area_box_iter_push_cell_height_for_width  (GtkCellAreaBoxIter *box_iter,
-						    GtkCellRenderer    *renderer,
-						    gint                for_width,
-						    gint                minimum_height,
-						    gint                natural_height)
+gtk_cell_area_box_iter_push_group_height_for_width  (GtkCellAreaBoxIter *box_iter,
+						     gint                group_id,
+						     gint                for_width,
+						     gint                minimum_height,
+						     gint                natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *cell_table;
+  GHashTable                *group_table;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
-  priv       = box_iter->priv;
-  cell_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+  priv        = box_iter->priv;
+  group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
 
-  if (!cell_table)
+  if (!group_table)
     {
-      cell_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
 					  NULL, (GDestroyNotify)cached_size_free);
 
-      g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), cell_table);
+      g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_table);
     }
 
-  size = g_hash_table_lookup (cell_table, renderer);
+  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 (cell_table, renderer, size);
+      g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size);
     }
   else
     {
@@ -266,24 +372,23 @@ gtk_cell_area_box_iter_push_cell_height_for_width  (GtkCellAreaBoxIter *box_iter
 }
 
 void
-gtk_cell_area_box_iter_push_cell_height (GtkCellAreaBoxIter *box_iter,
-					 GtkCellRenderer    *renderer,
-					 gint                minimum_height,
-					 gint                natural_height)
+gtk_cell_area_box_iter_push_group_height (GtkCellAreaBoxIter *box_iter,
+					  gint                group_id,
+					  gint                minimum_height,
+					  gint                natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_heights, renderer);
+  size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id));
 
   if (!size)
     {
       size = cached_size_new (minimum_height, natural_height);
-      g_hash_table_insert (priv->base_widths, renderer, size);
+      g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size);
     }
   else
     {
@@ -293,36 +398,35 @@ gtk_cell_area_box_iter_push_cell_height (GtkCellAreaBoxIter *box_iter,
 }
 
 void
-gtk_cell_area_box_iter_push_cell_width_for_height (GtkCellAreaBoxIter *box_iter,
-						   GtkCellRenderer    *renderer,
-						   gint                for_height,
-						   gint                minimum_width,
-						   gint                natural_width)
+gtk_cell_area_box_iter_push_group_width_for_height (GtkCellAreaBoxIter *box_iter,
+						    gint                group_id,
+						    gint                for_height,
+						    gint                minimum_width,
+						    gint                natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *cell_table;
+  GHashTable                *group_table;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
-  priv       = box_iter->priv;
-  cell_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+  priv        = box_iter->priv;
+  group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
 
-  if (!cell_table)
+  if (!group_table)
     {
-      cell_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
 					  NULL, (GDestroyNotify)cached_size_free);
 
-      g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), cell_table);
+      g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_table);
     }
 
-  size = g_hash_table_lookup (cell_table, renderer);
+  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 (cell_table, renderer, size);
+      g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size);
     }
   else
     {
@@ -332,19 +436,18 @@ gtk_cell_area_box_iter_push_cell_width_for_height (GtkCellAreaBoxIter *box_iter,
 }
 
 void
-gtk_cell_area_box_iter_get_cell_width (GtkCellAreaBoxIter *box_iter,
-				       GtkCellRenderer    *renderer,
-				       gint               *minimum_width,
-				       gint               *natural_width)
+gtk_cell_area_box_iter_get_group_width (GtkCellAreaBoxIter *box_iter,
+					gint                group_id,
+					gint               *minimum_width,
+					gint               *natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_widths, renderer);
+  size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id));
 
   if (size)
     {
@@ -365,24 +468,23 @@ gtk_cell_area_box_iter_get_cell_width (GtkCellAreaBoxIter *box_iter,
 }
 
 void
-gtk_cell_area_box_iter_get_cell_height_for_width (GtkCellAreaBoxIter *box_iter,
-						  GtkCellRenderer    *renderer,
-						  gint                for_width,
-						  gint               *minimum_height,
-						  gint               *natural_height)
+gtk_cell_area_box_iter_get_group_height_for_width (GtkCellAreaBoxIter *box_iter,
+						   gint                group_id,
+						   gint                for_width,
+						   gint               *minimum_height,
+						   gint               *natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *cell_table;
+  GHashTable                *group_table;
   CachedSize                *size = NULL;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
-  priv       = box_iter->priv;
-  cell_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
+  priv        = box_iter->priv;
+  group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
 
-  if (cell_table)
-    size = g_hash_table_lookup (cell_table, renderer);
+  if (group_table)
+    size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
 
   if (size)
     {
@@ -403,19 +505,18 @@ gtk_cell_area_box_iter_get_cell_height_for_width (GtkCellAreaBoxIter *box_iter,
 }
 
 void
-gtk_cell_area_box_iter_get_cell_height (GtkCellAreaBoxIter *box_iter,
-					GtkCellRenderer    *renderer,
-					gint               *minimum_height,
-					gint               *natural_height)
+gtk_cell_area_box_iter_get_group_height (GtkCellAreaBoxIter *box_iter,
+					 gint                group_id,
+					 gint               *minimum_height,
+					 gint               *natural_height)
 {
   GtkCellAreaBoxIterPrivate *priv;
   CachedSize                *size;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
   priv = box_iter->priv;
-  size = g_hash_table_lookup (priv->base_heights, renderer);
+  size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id));
 
   if (size)
     {
@@ -436,24 +537,23 @@ gtk_cell_area_box_iter_get_cell_height (GtkCellAreaBoxIter *box_iter,
 }
 
 void
-gtk_cell_area_box_iter_get_cell_width_for_height (GtkCellAreaBoxIter *box_iter,
-						  GtkCellRenderer    *renderer,
-						  gint                for_height,
-						  gint               *minimum_width,
-						  gint               *natural_width)
+gtk_cell_area_box_iter_get_group_width_for_height (GtkCellAreaBoxIter *box_iter,
+						   gint                group_id,
+						   gint                for_height,
+						   gint               *minimum_width,
+						   gint               *natural_width)
 {
   GtkCellAreaBoxIterPrivate *priv;
-  GHashTable                *cell_table;
+  GHashTable                *group_table;
   CachedSize                *size = NULL;
 
   g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
-  g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
 
-  priv       = box_iter->priv;
-  cell_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
+  priv        = box_iter->priv;
+  group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
 
-  if (cell_table)
-    size = g_hash_table_lookup (cell_table, renderer);
+  if (group_table)
+    size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
 
   if (size)
     {
@@ -472,3 +572,53 @@ gtk_cell_area_box_iter_get_cell_width_for_height (GtkCellAreaBoxIter *box_iter,
 	*natural_width = -1;      
     }
 }
+
+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;
+
+  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);
+
+  g_hash_table_foreach (priv->widths, (GHFunc)fill_requested_sizes, widths);
+
+  return widths;
+}
+
+GtkRequestedSize *
+gtk_cell_area_box_iter_get_heights (GtkCellAreaBoxIter *box_iter,
+				    gint               *n_heights)
+{
+  GtkCellAreaBoxIterPrivate *priv;
+  GtkRequestedSize          *heights;
+
+  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);
+
+  g_hash_table_foreach (priv->heights, (GHFunc)fill_requested_sizes, heights);
+
+  return heights;
+}
diff --git a/gtk/gtkcellareaboxiter.h b/gtk/gtkcellareaboxiter.h
index 0781c28..ada15a7 100644
--- a/gtk/gtkcellareaboxiter.h
+++ b/gtk/gtkcellareaboxiter.h
@@ -30,6 +30,7 @@
 
 #include <gtk/gtkcellareaiter.h>
 #include <gtk/gtkcellrenderer.h>
+#include <gtk/gtksizerequest.h>
 
 G_BEGIN_DECLS
 
@@ -57,54 +58,59 @@ struct _GtkCellAreaBoxIterClass
 
 };
 
-GType   gtk_cell_area_box_iter_get_type               (void) G_GNUC_CONST;
-
-
-/* Update cell alignments */
-void    gtk_cell_area_box_iter_push_cell_width             (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint                minimum_width,
-							    gint                natural_width);
-
-void    gtk_cell_area_box_iter_push_cell_height_for_width  (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint                for_width,
-							    gint                minimum_height,
-							    gint                natural_height);
-
-void    gtk_cell_area_box_iter_push_cell_height            (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint                minimum_height,
-							    gint                natural_height);
-
-void    gtk_cell_area_box_iter_push_cell_width_for_height  (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint                for_height,
-							    gint                minimum_width,
-							    gint                natural_width);
-
-/* Fetch cell alignments */
-void    gtk_cell_area_box_iter_get_cell_width              (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint               *minimum_width,
-							    gint               *natural_width);
-
-void    gtk_cell_area_box_iter_get_cell_height_for_width   (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint                for_width,
-							    gint               *minimum_height,
-							    gint               *natural_height);
-
-void    gtk_cell_area_box_iter_get_cell_height             (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint               *minimum_height,
-							    gint               *natural_height);
-
-void    gtk_cell_area_box_iter_get_cell_width_for_height   (GtkCellAreaBoxIter *box_iter,
-							    GtkCellRenderer    *renderer,
-							    gint                for_height,
-							    gint               *minimum_width,
-							    gint               *natural_width);
+GType   gtk_cell_area_box_iter_get_type                     (void) G_GNUC_CONST;
+
+
+/* Update cell-group sizes */
+void    gtk_cell_area_box_iter_push_group_width             (GtkCellAreaBoxIter *box_iter,
+							     gint                group_id,
+							     gint                minimum_width,
+							     gint                natural_width);
+
+void    gtk_cell_area_box_iter_push_group_height_for_width  (GtkCellAreaBoxIter *box_iter,
+							     gint                group_id,
+							     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                minimum_height,
+							     gint                natural_height);
+
+void    gtk_cell_area_box_iter_push_group_width_for_height  (GtkCellAreaBoxIter *box_iter,
+							     gint                group_id,
+							     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               *minimum_width,
+							     gint               *natural_width);
+
+void    gtk_cell_area_box_iter_get_group_height_for_width   (GtkCellAreaBoxIter *box_iter,
+							     gint                group_id,
+							     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               *minimum_height,
+							     gint               *natural_height);
+
+void    gtk_cell_area_box_iter_get_group_width_for_height   (GtkCellAreaBoxIter *box_iter,
+							     gint                group_id,
+							     gint                for_height,
+							     gint               *minimum_width,
+							     gint               *natural_width);
+
+GtkRequestedSize *gtk_cell_area_box_iter_get_widths         (GtkCellAreaBoxIter *box_iter,
+							     gint               *n_widths);
+GtkRequestedSize *gtk_cell_area_box_iter_get_heights        (GtkCellAreaBoxIter *box_iter,
+							     gint               *n_heights);
 
 G_END_DECLS
 
diff --git a/gtk/gtkcellareaiter.c b/gtk/gtkcellareaiter.c
index d4de66b..4257f4b 100644
--- a/gtk/gtkcellareaiter.c
+++ b/gtk/gtkcellareaiter.c
@@ -25,13 +25,19 @@
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 #include "gtkcellareaiter.h"
+#include "gtkprivate.h"
 
 /* GObjectClass */
 static void      gtk_cell_area_iter_finalize                       (GObject            *object);
+static void      gtk_cell_area_iter_dispose                        (GObject            *object);
 static void      gtk_cell_area_iter_get_property                   (GObject           *object,
 								   guint               prop_id,
 								   GValue             *value,
 								   GParamSpec         *pspec);
+static void      gtk_cell_area_iter_set_property                  (GObject            *object,
+								   guint               prop_id,
+								   const GValue       *value,
+								   GParamSpec         *pspec);
 
 /* GtkCellAreaIterClass */
 static void      gtk_cell_area_iter_real_flush_preferred_width            (GtkCellAreaIter *iter);
@@ -52,17 +58,20 @@ static void        cached_size_free (CachedSize *size);
 
 struct _GtkCellAreaIterPrivate
 {
-  gint        min_width;
-  gint        nat_width;
-  gint        min_height;
-  gint        nat_height;
+  GtkCellArea *cell_area;
+
+  gint         min_width;
+  gint         nat_width;
+  gint         min_height;
+  gint         nat_height;
 
-  GHashTable *widths;
-  GHashTable *heights;
+  GHashTable  *widths;
+  GHashTable  *heights;
 };
 
 enum {
   PROP_0,
+  PROP_CELL_AREA,
   PROP_MIN_WIDTH,
   PROP_NAT_WIDTH,
   PROP_MIN_HEIGHT,
@@ -106,7 +115,9 @@ gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class)
 
   /* GObjectClass */
   object_class->finalize     = gtk_cell_area_iter_finalize;
+  object_class->dispose      = gtk_cell_area_iter_dispose;
   object_class->get_property = gtk_cell_area_iter_get_property;
+  object_class->set_property = gtk_cell_area_iter_set_property;
 
   class->flush_preferred_width            = gtk_cell_area_iter_real_flush_preferred_width;
   class->flush_preferred_height_for_width = gtk_cell_area_iter_real_flush_preferred_height_for_width;
@@ -134,6 +145,14 @@ gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class)
 		  G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
 
   g_object_class_install_property (object_class,
+                                   PROP_CELL_AREA,
+                                   g_param_spec_object ("area",
+							P_("Area"),
+							P_("The Cell Area this iter was created for"),
+							GTK_TYPE_CELL_AREA,
+							GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
                                    PROP_MIN_WIDTH,
                                    g_param_spec_int ("minimum-width",
 						     P_("Minimum Width"),
@@ -215,6 +234,42 @@ gtk_cell_area_iter_finalize (GObject *object)
 }
 
 static void
+gtk_cell_area_iter_dispose (GObject *object)
+{
+  GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
+  GtkCellAreaIterPrivate *priv = iter->priv;
+
+  if (priv->cell_area)
+    {
+      g_object_unref (priv->cell_area);
+
+      priv->cell_area = NULL;
+    }
+
+  G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->dispose (object);
+}
+
+static void
+gtk_cell_area_iter_set_property (GObject      *object,
+				 guint         prop_id,
+				 const GValue *value,
+				 GParamSpec   *pspec)
+{
+  GtkCellAreaIter        *iter = GTK_CELL_AREA_ITER (object);
+  GtkCellAreaIterPrivate *priv = iter->priv;
+
+  switch (prop_id)
+    {
+    case PROP_CELL_AREA:
+      priv->cell_area = g_value_dup_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
 gtk_cell_area_iter_get_property (GObject     *object,
 				 guint        prop_id,
 				 GValue      *value,
@@ -225,6 +280,9 @@ gtk_cell_area_iter_get_property (GObject     *object,
 
   switch (prop_id)
     {
+    case PROP_CELL_AREA:
+      g_value_set_object (value, priv->cell_area);
+      break;
     case PROP_MIN_WIDTH:
       g_value_set_int (value, priv->min_width);
       break;
@@ -307,6 +365,17 @@ gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter,
 /*************************************************************
  *                            API                            *
  *************************************************************/
+GtkCellArea *
+gtk_cell_area_iter_get_area (GtkCellAreaIter *iter)
+{
+  GtkCellAreaIterPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), NULL);
+
+  priv = iter->priv;
+
+  return priv->cell_area;
+}
 
 void
 gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter,
@@ -410,6 +479,106 @@ gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter,
     }
 }
 
+void
+gtk_cell_area_iter_sum_preferred_width (GtkCellAreaIter *iter)
+{
+  GtkCellAreaIterClass *class;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
+
+  if (class->sum_preferred_width)
+    class->sum_preferred_width (iter);
+}
+
+void
+gtk_cell_area_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter,
+						   gint             for_width)
+{
+  GtkCellAreaIterClass *class;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
+
+  if (class->sum_preferred_height_for_width)
+    class->sum_preferred_height_for_width (iter, for_width);
+}
+
+void
+gtk_cell_area_iter_sum_preferred_height (GtkCellAreaIter *iter)
+{
+  GtkCellAreaIterClass *class;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
+
+  if (class->sum_preferred_height)
+    class->sum_preferred_height (iter);
+}
+
+void
+gtk_cell_area_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter,
+						   gint             for_height)
+{
+  GtkCellAreaIterClass *class;
+
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  class = GTK_CELL_AREA_ITER_GET_CLASS (iter);
+
+  if (class->sum_preferred_width_for_height)
+    class->sum_preferred_width_for_height (iter, for_height);
+}
+
+void
+gtk_cell_area_iter_flush (GtkCellAreaIter *iter)
+{
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  gtk_cell_area_iter_flush_preferred_width (iter);
+  gtk_cell_area_iter_flush_preferred_height_for_width (iter, -1);
+  gtk_cell_area_iter_flush_preferred_height (iter);
+  gtk_cell_area_iter_flush_preferred_width_for_height (iter, -1);
+}
+
+void
+gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter)
+{
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter);
+}
+
+void
+gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
+						     gint             for_width)
+{
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width);
+}
+
+void
+gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter)
+{
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter);
+}
+
+void
+gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
+						     gint             for_height)
+{
+  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
+
+  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height);
+}
+
+
 
 void
 gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter,
@@ -558,48 +727,3 @@ gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter,
     g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 0, 
 		   for_height, size->min_size, size->nat_size);
 }
-
-void
-gtk_cell_area_iter_flush (GtkCellAreaIter *iter)
-{
-  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
-
-  gtk_cell_area_iter_flush_preferred_width (iter);
-  gtk_cell_area_iter_flush_preferred_height_for_width (iter, -1);
-  gtk_cell_area_iter_flush_preferred_height (iter);
-  gtk_cell_area_iter_flush_preferred_width_for_height (iter, -1);
-}
-
-void
-gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter)
-{
-  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
-
-  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter);
-}
-
-void
-gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
-						     gint             for_width)
-{
-  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
-
-  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width);
-}
-
-void
-gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter)
-{
-  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
-
-  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter);
-}
-
-void
-gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
-						     gint             for_height)
-{
-  g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
-
-  GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height);
-}
diff --git a/gtk/gtkcellareaiter.h b/gtk/gtkcellareaiter.h
index 92f820f..b2e0e55 100644
--- a/gtk/gtkcellareaiter.h
+++ b/gtk/gtkcellareaiter.h
@@ -28,7 +28,7 @@
 #ifndef __GTK_CELL_AREA_ITER_H__
 #define __GTK_CELL_AREA_ITER_H__
 
-#include <glib-object.h>
+#include <gtk/gtkcellarea.h>
 
 G_BEGIN_DECLS
 
@@ -39,7 +39,6 @@ G_BEGIN_DECLS
 #define GTK_IS_CELL_AREA_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_AREA_ITER))
 #define GTK_CELL_AREA_ITER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_AREA_ITER, GtkCellAreaIterClass))
 
-typedef struct _GtkCellAreaIter              GtkCellAreaIter;
 typedef struct _GtkCellAreaIterPrivate       GtkCellAreaIterPrivate;
 typedef struct _GtkCellAreaIterClass         GtkCellAreaIterClass;
 
@@ -62,6 +61,16 @@ struct _GtkCellAreaIterClass
   void    (* flush_preferred_width_for_height)   (GtkCellAreaIter *iter,
 						  gint             height);
 
+  /* These must be invoked after a series of requests before consulting 
+   * the iter values, implementors use this to push the overall
+   * requests while acconting for any internal alignments */
+  void    (* sum_preferred_width)                (GtkCellAreaIter *iter);
+  void    (* sum_preferred_height_for_width)     (GtkCellAreaIter *iter,
+						  gint             width);
+  void    (* sum_preferred_height)               (GtkCellAreaIter *iter);
+  void    (* sum_preferred_width_for_height)     (GtkCellAreaIter *iter,
+						  gint             height);
+
   /* Padding for future expansion */
   void (*_gtk_reserved1) (void);
   void (*_gtk_reserved2) (void);
@@ -69,48 +78,59 @@ struct _GtkCellAreaIterClass
   void (*_gtk_reserved4) (void);
 };
 
-GType   gtk_cell_area_iter_get_type                           (void) G_GNUC_CONST;
+GType        gtk_cell_area_iter_get_type                         (void) G_GNUC_CONST;
 
-/* Apis for GtkCellArea clients to consult cached values for multiple GtkTreeModel rows */
-void    gtk_cell_area_iter_get_preferred_width                (GtkCellAreaIter *iter,
-							       gint            *minimum_width,
-							       gint            *natural_width);
-void    gtk_cell_area_iter_get_preferred_height_for_width     (GtkCellAreaIter *iter,
-							       gint             for_width,
-							       gint            *minimum_height,
-							       gint            *natural_height);
-void    gtk_cell_area_iter_get_preferred_height               (GtkCellAreaIter *iter,
-							       gint            *minimum_height,
-							       gint            *natural_height);
-void    gtk_cell_area_iter_get_preferred_width_for_height     (GtkCellAreaIter *iter,
-							       gint             for_height,
-							       gint            *minimum_width,
-							       gint            *natural_width);
+GtkCellArea *gtk_cell_area_iter_get_area                         (GtkCellAreaIter *iter);
 
-/* Apis for GtkCellArea implementations to update cached values for multiple GtkTreeModel rows */
-void    gtk_cell_area_iter_push_preferred_width               (GtkCellAreaIter *iter,
-							       gint             minimum_width,
-							       gint             natural_width);
-void    gtk_cell_area_iter_push_preferred_height_for_width    (GtkCellAreaIter *iter,
-							       gint             for_width,
-							       gint             minimum_height,
-							       gint             natural_height);
-void    gtk_cell_area_iter_push_preferred_height              (GtkCellAreaIter *iter,
-							       gint             minimum_height,
-							       gint             natural_height);
-void    gtk_cell_area_iter_push_preferred_width_for_height    (GtkCellAreaIter *iter,
-							       gint             for_height,
-							       gint             minimum_width,
-							       gint             natural_width);
+/* Apis for GtkCellArea clients to consult cached values for multiple GtkTreeModel rows */
+void         gtk_cell_area_iter_get_preferred_width              (GtkCellAreaIter *iter,
+								  gint            *minimum_width,
+								  gint            *natural_width);
+void         gtk_cell_area_iter_get_preferred_height_for_width   (GtkCellAreaIter *iter,
+								  gint             for_width,
+								  gint            *minimum_height,
+								  gint            *natural_height);
+void         gtk_cell_area_iter_get_preferred_height             (GtkCellAreaIter *iter,
+								  gint            *minimum_height,
+								  gint            *natural_height);
+void         gtk_cell_area_iter_get_preferred_width_for_height   (GtkCellAreaIter *iter,
+								  gint             for_height,
+								  gint            *minimum_width,
+								  gint            *natural_width);
+
+/* Apis for GtkCellArea clients to sum up the results of a series of requests, this
+ * call is required to reduce the processing while calculating the size of each row */
+void         gtk_cell_area_iter_sum_preferred_width              (GtkCellAreaIter *iter);
+void         gtk_cell_area_iter_sum_preferred_height_for_width   (GtkCellAreaIter *iter,
+								  gint             for_width);
+void         gtk_cell_area_iter_sum_preferred_height             (GtkCellAreaIter *iter);
+void         gtk_cell_area_iter_sum_preferred_width_for_height   (GtkCellAreaIter *iter,
+								  gint             for_height);
 
 /* Apis for GtkCellArea clients to flush the cache */
-void    gtk_cell_area_iter_flush                              (GtkCellAreaIter *iter);
-void    gtk_cell_area_iter_flush_preferred_width              (GtkCellAreaIter *iter);
-void    gtk_cell_area_iter_flush_preferred_height_for_width   (GtkCellAreaIter *iter,
-							       gint             for_width);
-void    gtk_cell_area_iter_flush_preferred_height             (GtkCellAreaIter *iter);
-void    gtk_cell_area_iter_flush_preferred_width_for_height   (GtkCellAreaIter *iter,
-							       gint             for_height);
+void         gtk_cell_area_iter_flush                            (GtkCellAreaIter *iter);
+void         gtk_cell_area_iter_flush_preferred_width            (GtkCellAreaIter *iter);
+void         gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
+								  gint             for_width);
+void         gtk_cell_area_iter_flush_preferred_height           (GtkCellAreaIter *iter);
+void         gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
+								  gint             for_height);
+
+/* Apis for GtkCellArea implementations to update cached values for multiple GtkTreeModel rows */
+void         gtk_cell_area_iter_push_preferred_width             (GtkCellAreaIter *iter,
+								  gint             minimum_width,
+								  gint             natural_width);
+void         gtk_cell_area_iter_push_preferred_height_for_width  (GtkCellAreaIter *iter,
+								  gint             for_width,
+								  gint             minimum_height,
+								  gint             natural_height);
+void         gtk_cell_area_iter_push_preferred_height            (GtkCellAreaIter *iter,
+								  gint             minimum_height,
+								  gint             natural_height);
+void         gtk_cell_area_iter_push_preferred_width_for_height  (GtkCellAreaIter *iter,
+								  gint             for_height,
+								  gint             minimum_width,
+								  gint             natural_width);
 
 G_END_DECLS
 



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