[gtk+/combo-refactor: 146/148] Added "fixed-size" cell property to GtkCellAreaBox



commit 720612df8b66d1024ab307b899b13aa46d3018f6
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Tue Dec 21 21:11:01 2010 +0900

    Added "fixed-size" cell property to GtkCellAreaBox
    
    Now a cell can either have a "fixed" size or it can have
    an "aligned" starting point or both. "fixed" size cells take
    no space when they are invisible.

 gtk/gtkcellareabox.c        |  204 ++++++++++++++++++++---
 gtk/gtkcellareabox.h        |    9 +-
 gtk/gtkcellareaboxcontext.c |  385 ++++++++++++++++++++++---------------------
 gtk/gtkcellareaboxcontext.h |    3 +-
 tests/testcellarea.c        |   12 +-
 tests/testtreeedit.c        |   75 ++++++---
 6 files changed, 442 insertions(+), 246 deletions(-)
---
diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c
index 97cfc22..f81d1c2 100644
--- a/gtk/gtkcellareabox.c
+++ b/gtk/gtkcellareabox.c
@@ -83,6 +83,11 @@ static void      gtk_cell_area_box_foreach_alloc                  (GtkCellArea
                                                                    const GdkRectangle   *background_area,
                                                                    GtkCellAllocCallback  callback,
                                                                    gpointer              callback_data);
+static void      gtk_cell_area_box_apply_attributes               (GtkCellArea          *area,
+								   GtkTreeModel         *tree_model,
+								   GtkTreeIter          *iter,
+								   gboolean              is_expander,
+								   gboolean              is_expanded);
 static void      gtk_cell_area_box_set_cell_property              (GtkCellArea          *area,
                                                                    GtkCellRenderer      *renderer,
                                                                    guint                 prop_id,
@@ -145,6 +150,7 @@ typedef struct {
   guint            expand : 1; /* Whether the cell expands */
   guint            pack   : 1; /* Whether it is packed from the start or end */
   guint            align  : 1; /* Whether to align its position with adjacent rows */
+  guint            fixed  : 1; /* Whether to require the same size for all rows */
 } CellInfo;
 
 typedef struct {
@@ -153,6 +159,8 @@ typedef struct {
   guint  id           : 8;
   guint  n_cells      : 8;
   guint  expand_cells : 8;
+  guint  align        : 1;
+  guint  visible      : 1;
 } CellGroup;
 
 typedef struct {
@@ -165,7 +173,8 @@ typedef struct {
 static CellInfo      *cell_info_new          (GtkCellRenderer       *renderer,
                                               GtkPackType            pack,
                                               gboolean               expand,
-                                              gboolean               align);
+                                              gboolean               align,
+					      gboolean               fixed);
 static void           cell_info_free         (CellInfo              *info);
 static gint           cell_info_find         (CellInfo              *info,
                                               GtkCellRenderer       *renderer);
@@ -223,6 +232,7 @@ enum {
   CELL_PROP_0,
   CELL_PROP_EXPAND,
   CELL_PROP_ALIGN,
+  CELL_PROP_FIXED_SIZE,
   CELL_PROP_PACK_TYPE
 };
 
@@ -277,6 +287,7 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class)
   area_class->remove              = gtk_cell_area_box_remove;
   area_class->foreach             = gtk_cell_area_box_foreach;
   area_class->foreach_alloc       = gtk_cell_area_box_foreach_alloc;
+  area_class->apply_attributes    = gtk_cell_area_box_apply_attributes;
   area_class->set_cell_property   = gtk_cell_area_box_set_cell_property;
   area_class->get_cell_property   = gtk_cell_area_box_get_cell_property;
 
@@ -341,6 +352,23 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class)
                                              ("align",
                                               P_("Align"),
                                               P_("Whether cell should align with adjacent rows"),
+                                              FALSE,
+                                              GTK_PARAM_READWRITE));
+
+  /**
+   * GtkCellAreaBox:fixed-size:
+   *
+   * Whether the cell renderer should require the same size
+   * for all rows for which it was requested.
+   *
+   * Since: 3.0
+   */
+  gtk_cell_area_class_install_cell_property (area_class,
+                                             CELL_PROP_FIXED_SIZE,
+                                             g_param_spec_boolean
+                                             ("fixed-size",
+                                              P_("Fixed Size"),
+                                              P_("Whether cells should be the same size in all rows"),
                                               TRUE,
                                               GTK_PARAM_READWRITE));
 
@@ -373,7 +401,8 @@ static CellInfo *
 cell_info_new  (GtkCellRenderer *renderer,
                 GtkPackType      pack,
                 gboolean         expand,
-                gboolean         align)
+                gboolean         align,
+		gboolean         fixed)
 {
   CellInfo *info = g_slice_new (CellInfo);
 
@@ -381,6 +410,7 @@ cell_info_new  (GtkCellRenderer *renderer,
   info->pack     = pack;
   info->expand   = expand;
   info->align    = align;
+  info->fixed    = fixed;
 
   return info;
 }
@@ -476,6 +506,7 @@ cell_groups_rebuild (GtkCellAreaBox *box)
   CellGroup             *group_ptr;
   GList                 *cells, *l;
   guint                  id = 0;
+  gboolean               last_cell_fixed = FALSE;
 
   cell_groups_clear (box);
 
@@ -492,8 +523,10 @@ cell_groups_rebuild (GtkCellAreaBox *box)
     {
       CellInfo *info = l->data;
 
-      /* A new group starts with any aligned cell, the first group is implied */
-      if (info->align && l != cells)
+      /* A new group starts with any aligned cell, or
+       * at the beginning and end of a fixed size cell. 
+       * the first group is implied */
+      if ((info->align || info->fixed || last_cell_fixed) && l != cells)
         {
           memset (&group, 0x0, sizeof (CellGroup));
           group.id = ++id;
@@ -505,9 +538,16 @@ cell_groups_rebuild (GtkCellAreaBox *box)
       group_ptr->cells = g_list_prepend (group_ptr->cells, info);
       group_ptr->n_cells++;
 
+      /* Not every group is aligned, some are floating
+       * fixed size cells */
+      if (info->align)
+	group_ptr->align = TRUE;
+
       /* A group expands if it contains any expand cells */
       if (info->expand)
         group_ptr->expand_cells++;
+
+      last_cell_fixed = info->fixed;
     }
 
   g_list_free (cells);
@@ -582,20 +622,23 @@ init_context_group (GtkCellAreaBox        *box,
                     GtkCellAreaBoxContext *context)
 {
   GtkCellAreaBoxPrivate *priv = box->priv;
-  gint                  *expand_groups, i;
+  gint                  *expand_groups, *align_groups, i;
 
   expand_groups = g_new (gboolean, priv->groups->len);
+  align_groups  = g_new (gboolean, priv->groups->len);
 
   for (i = 0; i < priv->groups->len; i++)
     {
       CellGroup *group = &g_array_index (priv->groups, CellGroup, i);
 
       expand_groups[i] = (group->expand_cells > 0);
+      align_groups[i]  = group->align;
     }
 
   /* This call implies reseting the request info */
-  gtk_cell_area_box_init_groups (context, priv->groups->len, expand_groups);
+  gtk_cell_area_box_init_groups (context, priv->groups->len, expand_groups, align_groups);
   g_free (expand_groups);
+  g_free (align_groups);
 }
 
 static void
@@ -782,7 +825,7 @@ get_allocated_cells (GtkCellAreaBox        *box,
   GtkCellAreaBoxPrivate    *priv = box->priv;
   GList                    *cell_list;
   GSList                   *allocated_cells = NULL;
-  gint                      i, j, n_allocs;
+  gint                      i, j, n_allocs, position;
   gint                      for_size, full_size;
   gboolean                  rtl;
 
@@ -807,7 +850,7 @@ get_allocated_cells (GtkCellAreaBox        *box,
   rtl = (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
          gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
 
-  for (i = 0; i < n_allocs; i++)
+  for (position = 0, i = 0; i < n_allocs; i++)
     {
       /* We dont always allocate all groups, sometimes the requested
        * group has only invisible cells for every row, hence the usage
@@ -820,20 +863,43 @@ get_allocated_cells (GtkCellAreaBox        *box,
         {
           CellInfo      *info = group->cells->data;
           AllocatedCell *cell;
+	  gint           cell_position, cell_size;
+
+	  /* If were not aligned, place the cell after the last cell */
+	  if (info->align)
+	    position = cell_position = group_allocs[i].position;
+	  else
+	    cell_position = position;
+
+	  /* If not a fixed size, use only the requested size for this row */
+	  if (info->fixed)
+	    cell_size = group_allocs[i].size;
+	  else
+	    {
+	      gint dummy;
+              gtk_cell_area_request_renderer (area, info->renderer,
+                                              priv->orientation,
+                                              widget, for_size,
+                                              &dummy,
+                                              &cell_size);
+	      cell_size = MIN (cell_size, group_allocs[i].size);
+	    }
 
           if (rtl)
             cell = allocated_cell_new (info->renderer,
-                                       full_size - (group_allocs[i].position + group_allocs[i].size),
-                                       group_allocs[i].size);
+                                       full_size - (cell_position + cell_size), cell_size);
           else
-            cell = allocated_cell_new (info->renderer, group_allocs[i].position, group_allocs[i].size);
+            cell = allocated_cell_new (info->renderer, cell_position, cell_size);
+
+	  position += cell_size;
+          position += priv->spacing;
 
           allocated_cells = g_slist_prepend (allocated_cells, cell);
         }
       else
         {
           GtkRequestedSize *sizes;
-          gint              avail_size, position;
+          gint              avail_size, cell_position;
           gint              visible_cells, expand_cells;
           gint              extra_size, extra_extra;
 
@@ -845,11 +911,19 @@ get_allocated_cells (GtkCellAreaBox        *box,
           if (visible_cells == 0)
             continue;
 
-          /* Offset the allocation to the group position
-           * and allocate into the group's available size
-           */
-          position   = group_allocs[i].position;
-          avail_size = group_allocs[i].size;
+	  /* If were not aligned, place the cell after the last cell 
+	   * and eat up the extra space
+	   */
+	  if (group->align)
+	    {
+	      avail_size = group_allocs[i].size;
+	      position   = cell_position = group_allocs[i].position;
+	    }
+	  else
+	    {
+	      avail_size    = group_allocs[i].size + (group_allocs[i].position - position);
+	      cell_position = position;
+	    }
 
           sizes = g_new (GtkRequestedSize, visible_cells);
 
@@ -906,21 +980,25 @@ get_allocated_cells (GtkCellAreaBox        *box,
 
               if (rtl)
                 cell = allocated_cell_new (info->renderer,
-                                           full_size - (position + sizes[j].minimum_size),
+                                           full_size - (cell_position + sizes[j].minimum_size),
                                            sizes[j].minimum_size);
               else
-                cell = allocated_cell_new (info->renderer, position, sizes[j].minimum_size);
+                cell = allocated_cell_new (info->renderer, cell_position, sizes[j].minimum_size);
 
               allocated_cells = g_slist_prepend (allocated_cells, cell);
 
-              position += sizes[j].minimum_size;
-              position += priv->spacing;
+              cell_position += sizes[j].minimum_size;
+              cell_position += priv->spacing;
             }
 
           g_free (sizes);
+
+	  position = cell_position;
         }
     }
 
+  g_free (group_allocs);
+
   /* Note it might not be important to reverse the list here at all,
    * we have the correct positions, no need to allocate from left to right
    */
@@ -1022,7 +1100,7 @@ gtk_cell_area_box_add (GtkCellArea        *area,
                        GtkCellRenderer    *renderer)
 {
   gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area),
-                                renderer, FALSE, TRUE);
+                                renderer, FALSE, FALSE, TRUE);
 }
 
 static void
@@ -1222,6 +1300,40 @@ gtk_cell_area_box_foreach_alloc (GtkCellArea          *area,
 }
 
 static void
+gtk_cell_area_box_apply_attributes (GtkCellArea          *area,
+				    GtkTreeModel         *tree_model,
+				    GtkTreeIter          *iter,
+				    gboolean              is_expander,
+				    gboolean              is_expanded)
+{
+  GtkCellAreaBox        *box  = GTK_CELL_AREA_BOX (area);
+  GtkCellAreaBoxPrivate *priv = box->priv;
+  gint                   i;
+
+  /* Call the parent class to apply the attributes */
+  GTK_CELL_AREA_CLASS
+    (gtk_cell_area_box_parent_class)->apply_attributes (area, tree_model, iter, 
+							is_expander, is_expanded);
+
+  /* Update visible state for cell groups */
+  for (i = 0; i < priv->groups->len; i++)
+    {
+      CellGroup *group = &g_array_index (priv->groups, CellGroup, i);
+      GList     *list;
+
+      group->visible = FALSE;
+
+      for (list = group->cells; list && group->visible == FALSE; list = list->next)
+	{
+          CellInfo *info = list->data;
+
+          if (gtk_cell_renderer_get_visible (info->renderer))
+	    group->visible = TRUE;
+	}
+    }
+}
+
+static void
 gtk_cell_area_box_set_cell_property (GtkCellArea        *area,
                                      GtkCellRenderer    *renderer,
                                      guint               prop_id,
@@ -1265,6 +1377,16 @@ gtk_cell_area_box_set_cell_property (GtkCellArea        *area,
         }
       break;
 
+    case CELL_PROP_FIXED_SIZE:
+      val = g_value_get_boolean (value);
+
+      if (info->fixed != val)
+        {
+          info->fixed = val;
+          rebuild     = TRUE;
+        }
+      break;
+
     case CELL_PROP_PACK_TYPE:
       pack_type = g_value_get_enum (value);
 
@@ -1313,6 +1435,10 @@ gtk_cell_area_box_get_cell_property (GtkCellArea        *area,
       g_value_set_boolean (value, info->align);
       break;
 
+    case CELL_PROP_FIXED_SIZE:
+      g_value_set_boolean (value, info->fixed);
+      break;
+
     case CELL_PROP_PACK_TYPE:
       g_value_set_enum (value, info->pack);
       break;
@@ -1935,7 +2061,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, TRUE);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, FALSE, TRUE);
 }
 
 static void
@@ -1943,7 +2069,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, TRUE);
+  gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, FALSE, TRUE);
 }
 
 static void
@@ -1971,6 +2097,24 @@ gtk_cell_area_box_layout_reorder (GtkCellLayout      *cell_layout,
 }
 
 /*************************************************************
+ *       Private interaction with GtkCellAreaBoxContext      *
+ *************************************************************/
+gboolean
+_gtk_cell_area_box_group_visible (GtkCellAreaBox  *box,
+				  gint             group_idx)
+{
+  GtkCellAreaBoxPrivate *priv  = box->priv;
+  CellGroup *group;
+  
+  g_assert (group_idx >= 0 && group_idx < priv->groups->len);
+
+  group = &g_array_index (priv->groups, CellGroup, group_idx);
+
+  return group->visible;
+}
+
+
+/*************************************************************
  *                            API                            *
  *************************************************************/
 /**
@@ -1995,6 +2139,7 @@ gtk_cell_area_box_new (void)
  * @expand: whether @renderer should receive extra space when the area receives
  * more than its natural size
  * @align: whether @renderer should be aligned in adjacent rows
+ * @fixed: whether @renderer should have the same size in all rows
  *
  * Adds @renderer to @box, packed with reference to the start of @box.
  *
@@ -2007,7 +2152,8 @@ void
 gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
                                GtkCellRenderer *renderer,
                                gboolean         expand,
-                               gboolean         align)
+                               gboolean         align,
+			       gboolean         fixed)
 {
   GtkCellAreaBoxPrivate *priv;
   CellInfo              *info;
@@ -2024,7 +2170,7 @@ gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
       return;
     }
 
-  info = cell_info_new (renderer, GTK_PACK_START, expand, align);
+  info = cell_info_new (renderer, GTK_PACK_START, expand, align, fixed);
 
   priv->cells = g_list_append (priv->cells, info);
 
@@ -2038,6 +2184,7 @@ gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
  * @expand: whether @renderer should receive extra space when the area receives
  * more than its natural size
  * @align: whether @renderer should be aligned in adjacent rows
+ * @fixed: whether @renderer should have the same size in all rows
  *
  * Adds @renderer to @box, packed with reference to the end of @box.
  *
@@ -2050,7 +2197,8 @@ void
 gtk_cell_area_box_pack_end (GtkCellAreaBox  *box,
                             GtkCellRenderer *renderer,
                             gboolean         expand,
-                            gboolean         align)
+                            gboolean         align,
+			    gboolean         fixed)
 {
   GtkCellAreaBoxPrivate *priv;
   CellInfo              *info;
@@ -2067,7 +2215,7 @@ gtk_cell_area_box_pack_end (GtkCellAreaBox  *box,
       return;
     }
 
-  info = cell_info_new (renderer, GTK_PACK_END, expand, align);
+  info = cell_info_new (renderer, GTK_PACK_END, expand, align, fixed);
 
   priv->cells = g_list_append (priv->cells, info);
 
diff --git a/gtk/gtkcellareabox.h b/gtk/gtkcellareabox.h
index 632ea93..cfe00e8 100644
--- a/gtk/gtkcellareabox.h
+++ b/gtk/gtkcellareabox.h
@@ -69,15 +69,20 @@ GtkCellArea *gtk_cell_area_box_new         (void);
 void         gtk_cell_area_box_pack_start  (GtkCellAreaBox  *box,
                                             GtkCellRenderer *renderer,
                                             gboolean         expand,
-                                            gboolean         align);
+                                            gboolean         align,
+					    gboolean         fixed);
 void         gtk_cell_area_box_pack_end    (GtkCellAreaBox  *box,
                                             GtkCellRenderer *renderer,
                                             gboolean         expand,
-                                            gboolean         align);
+                                            gboolean         align,
+					    gboolean         fixed);
 gint         gtk_cell_area_box_get_spacing (GtkCellAreaBox  *box);
 void         gtk_cell_area_box_set_spacing (GtkCellAreaBox  *box,
                                             gint             spacing);
 
+/* Private interaction with GtkCellAreaBoxContext */
+gboolean    _gtk_cell_area_box_group_visible (GtkCellAreaBox  *box,
+					      gint             group_idx);
 
 G_END_DECLS
 
diff --git a/gtk/gtkcellareaboxcontext.c b/gtk/gtkcellareaboxcontext.c
index b68002d..c5e02bd 100644
--- a/gtk/gtkcellareaboxcontext.c
+++ b/gtk/gtkcellareaboxcontext.c
@@ -32,9 +32,6 @@ static void      gtk_cell_area_box_context_finalize              (GObject
 
 /* GtkCellAreaContextClass */
 static void      gtk_cell_area_box_context_reset                 (GtkCellAreaContext    *context);
-static void      gtk_cell_area_box_context_allocate              (GtkCellAreaContext    *context,
-                                                                  gint                   width,
-                                                                  gint                   height);
 static void      gtk_cell_area_box_context_get_preferred_height_for_width (GtkCellAreaContext *context,
                                                                            gint                width,
                                                                            gint               *minimum_height,
@@ -81,11 +78,8 @@ struct _GtkCellAreaBoxContextPrivate
   /* Whether each group expands */
   gboolean  *expand;
 
-  /* Allocation info for this context if any */
-  gint                      alloc_width;
-  gint                      alloc_height;
-  gint                      n_orientation_allocs;
-  GtkCellAreaBoxAllocation *orientation_allocs;
+  /* Whether each group is aligned */
+  gboolean  *align;
 };
 
 G_DEFINE_TYPE (GtkCellAreaBoxContext, gtk_cell_area_box_context, GTK_TYPE_CELL_AREA_CONTEXT);
@@ -187,11 +181,6 @@ gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context)
                                               NULL, (GDestroyNotify)free_cache_array);
   priv->heights      = g_hash_table_new_full (g_direct_hash, g_direct_equal,
                                               NULL, (GDestroyNotify)free_cache_array);
-
-  priv->alloc_width  = 0;
-  priv->alloc_height = 0;
-  priv->orientation_allocs   = NULL;
-  priv->n_orientation_allocs = 0;
 }
 
 static void 
@@ -204,7 +193,6 @@ gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class)
   object_class->finalize = gtk_cell_area_box_context_finalize;
 
   context_class->reset                          = gtk_cell_area_box_context_reset;
-  context_class->allocate                       = gtk_cell_area_box_context_allocate;
   context_class->get_preferred_height_for_width = gtk_cell_area_box_context_get_preferred_height_for_width;
   context_class->get_preferred_width_for_height = gtk_cell_area_box_context_get_preferred_width_for_height;
 
@@ -225,8 +213,8 @@ gtk_cell_area_box_context_finalize (GObject *object)
   g_hash_table_destroy (priv->widths);
   g_hash_table_destroy (priv->heights);
 
-  g_free (priv->orientation_allocs);
   g_free (priv->expand);
+  g_free (priv->align);
 
   G_OBJECT_CLASS (gtk_cell_area_box_context_parent_class)->finalize (object);
 }
@@ -259,162 +247,10 @@ gtk_cell_area_box_context_reset (GtkCellAreaContext *context)
   g_hash_table_remove_all (priv->widths);
   g_hash_table_remove_all (priv->heights);
 
-  /* Clear the allocation */
-  g_free (priv->orientation_allocs);
-  priv->orientation_allocs   = NULL;
-  priv->n_orientation_allocs = 0;
-
   GTK_CELL_AREA_CONTEXT_CLASS
     (gtk_cell_area_box_context_parent_class)->reset (context);
 }
 
-static GtkRequestedSize *
-gtk_cell_area_box_context_get_requests (GtkCellAreaBoxContext *box_context,
-                                        GtkOrientation         orientation,
-                                        gint                   for_size,
-                                        gint                  *n_requests)
-{
-  GtkCellAreaBoxContextPrivate *priv;
-  GtkRequestedSize             *requests;
-  GArray                       *array;
-  CachedSize                   *size;
-  gint                          visible_groups = 0;
-  gint                          i, j;
-
-  g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context), NULL);
-
-  priv  = box_context->priv;
-  array = get_array (box_context, orientation, for_size);
-
-  for (i = 0; i < array->len; i++)
-    {
-      size = &g_array_index (array, CachedSize, i);
-
-      if (size->nat_size > 0)
-        visible_groups++;
-    }
-
-  requests = g_new (GtkRequestedSize, visible_groups);
-
-  for (j = 0, i = 0; i < array->len; i++)
-    {
-      size = &g_array_index (array, CachedSize, i);
-
-      if (size->nat_size > 0)
-        {
-          requests[j].data         = GINT_TO_POINTER (i);
-          requests[j].minimum_size = size->min_size;
-          requests[j].natural_size = size->nat_size;
-          j++;
-        }
-    }
-
-  if (n_requests)
-    *n_requests = visible_groups;
-
-  return requests;
-}
-
-static GtkCellAreaBoxAllocation *
-allocate_for_orientation (GtkCellAreaBoxContext *context,
-                          GtkOrientation         orientation,
-                          gint                   spacing,
-                          gint                   size,
-                          gint                   for_size,
-                          gint                  *n_allocs)
-{
-  GtkCellAreaBoxAllocation     *allocs;
-  GtkRequestedSize             *sizes;
-  GArray                       *array;
-  gint                          n_expand_groups = 0;
-  gint                          i, n_groups, position;
-  gint                          extra_size, extra_extra;
-  gint                          avail_size = size;
-
-  sizes           = gtk_cell_area_box_context_get_requests (context, orientation, for_size, &n_groups);
-  array           = get_array (context, orientation, for_size);
-  n_expand_groups = count_expand_groups (context);
-
-  /* First start by naturally allocating space among groups */
-  avail_size -= (n_groups - 1) * spacing;
-  for (i = 0; i < n_groups; i++)
-    avail_size -= sizes[i].minimum_size;
-
-  if (avail_size > 0)
-    avail_size = gtk_distribute_natural_allocation (avail_size, n_groups, sizes);
-  else
-    avail_size = 0;
-
-  /* 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++)
-    {
-      allocs[i].group_idx = GPOINTER_TO_INT (sizes[i].data);
-      allocs[i].position  = position;
-      allocs[i].size      = sizes[i].minimum_size;
-
-      if (group_expands (context, allocs[i].group_idx))
-        {
-          allocs[i].size += extra_size;
-          if (extra_extra)
-            {
-              allocs[i].size++;
-              extra_extra--;
-            }
-        }
-
-      position += allocs[i].size;
-      position += spacing;
-    }
-
-  if (n_allocs)
-    *n_allocs = n_groups;
-
-  g_free (sizes);
-
-  return allocs;
-}
-
-static void
-gtk_cell_area_box_context_allocate (GtkCellAreaContext *context,
-                                    gint                width,
-                                    gint                height)
-{
-  GtkCellAreaBoxContext        *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
-  GtkCellAreaBoxContextPrivate *priv        = box_context->priv;
-  GtkCellArea                  *area;
-  GtkOrientation                orientation;
-  gint                          spacing;
-
-  area        = gtk_cell_area_context_get_area (context);
-  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
-  spacing     = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
-
-  g_free (priv->orientation_allocs);
-  priv->orientation_allocs   = NULL;
-  priv->n_orientation_allocs = 0;
-
-  if (orientation == GTK_ORIENTATION_HORIZONTAL && width > 0)
-    priv->orientation_allocs = allocate_for_orientation (box_context, orientation, 
-                                                         spacing, width, height,
-                                                         &priv->n_orientation_allocs);
-  else if (orientation == GTK_ORIENTATION_VERTICAL && height > 0)
-    priv->orientation_allocs = allocate_for_orientation (box_context, orientation, 
-                                                         spacing, height, width,
-                                                         &priv->n_orientation_allocs);
-  
-  GTK_CELL_AREA_CONTEXT_CLASS (gtk_cell_area_box_context_parent_class)->allocate (context, width, height);
-}
-
 static void
 gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context,
                                GtkOrientation         orientation,
@@ -422,23 +258,38 @@ gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context,
                                gint                  *minimum_size,
                                gint                  *natural_size)
 {
-  GtkCellArea    *area;
+  GtkCellAreaBoxContextPrivate *priv = context->priv;
+  GtkCellAreaBox *area;
   GtkOrientation  box_orientation;
   GArray         *array;
-  gint            spacing, i;
+  gint            spacing, i, last_aligned_group_idx;
   gint            min_size = 0, nat_size = 0;
 
-  area            = gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (context));
-  spacing         = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
+  area            = (GtkCellAreaBox *)gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (context));
+  spacing         = gtk_cell_area_box_get_spacing (area);
   box_orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
   array           = get_array (context, orientation, for_size);
 
+  /* Get the last visible aligned group 
+   * (we need to get space at least up till this group) */
+  for (i = array->len - 1; i >= 0; i--)
+    {
+      if (priv->align[i] && 
+	  _gtk_cell_area_box_group_visible (area, i))
+	break;
+    }
+  last_aligned_group_idx = i >= 0 ? i : 0;
+
   for (i = 0; i < array->len; i++)
     {
       CachedSize *size = &g_array_index (array, CachedSize, i);
 
       if (box_orientation == orientation)
         {
+	  if (i > last_aligned_group_idx &&
+	      !_gtk_cell_area_box_group_visible (area, i))
+	    continue;
+
           /* Dont add spacing for 0 size groups, they can be 0 size because
            * they contain only invisible cells for this round of requests
            */
@@ -536,7 +387,8 @@ gtk_cell_area_box_context_copy (GtkCellAreaBox        *box,
 
   gtk_cell_area_box_init_groups (copy,
                                  context->priv->base_widths->len,
-                                 context->priv->expand);
+                                 context->priv->expand,
+				 context->priv->align);
 
   /* Copy the base arrays */
   copy_size_array (context->priv->base_widths,
@@ -550,14 +402,6 @@ gtk_cell_area_box_context_copy (GtkCellAreaBox        *box,
   g_hash_table_foreach (context->priv->widths,
                         (GHFunc)for_size_copy, copy->priv->widths);
 
-  /* Copy any active allocation */
-  copy->priv->n_orientation_allocs =
-    context->priv->n_orientation_allocs;
-
-  if (copy->priv->n_orientation_allocs)
-    copy->priv->orientation_allocs =
-      g_memdup (context->priv->orientation_allocs,
-                copy->priv->n_orientation_allocs * sizeof (GtkCellAreaBoxAllocation));
 
   return copy;
 }
@@ -565,7 +409,8 @@ gtk_cell_area_box_context_copy (GtkCellAreaBox        *box,
 void
 gtk_cell_area_box_init_groups (GtkCellAreaBoxContext *box_context,
                                guint                  n_groups,
-                               gboolean              *expand_groups)
+                               gboolean              *expand_groups,
+			       gboolean              *align_groups)
 {
   GtkCellAreaBoxContextPrivate *priv;
 
@@ -583,6 +428,9 @@ gtk_cell_area_box_init_groups (GtkCellAreaBoxContext *box_context,
 
   g_free (priv->expand);
   priv->expand = g_memdup (expand_groups, n_groups * sizeof (gboolean));
+
+  g_free (priv->align);
+  priv->align = g_memdup (align_groups, n_groups * sizeof (gboolean));
 }
 
 void
@@ -823,31 +671,192 @@ gtk_cell_area_box_context_get_group_width_for_height (GtkCellAreaBoxContext *box
     }
 }
 
+static GtkRequestedSize *
+gtk_cell_area_box_context_get_requests (GtkCellAreaBoxContext *box_context,
+					GtkCellAreaBox        *area,
+                                        GtkOrientation         orientation,
+                                        gint                   for_size,
+                                        gint                  *n_requests)
+{
+  GtkCellAreaBoxContextPrivate *priv = box_context->priv;
+  GtkRequestedSize             *requests;
+  GArray                       *array;
+  CachedSize                   *size;
+  gint                          visible_groups = 0;
+  gint                          last_aligned_group_idx = 0;
+  gint                          i, j;
+
+  /* Get the last visible aligned group 
+   * (we need to get space at least up till this group) */
+  for (i = priv->base_widths->len - 1; i >= 0; i--)
+    {
+      if (priv->align[i] && 
+	  _gtk_cell_area_box_group_visible (area, i))
+	break;
+    }
+  last_aligned_group_idx = i >= 0 ? i : 0;
+
+  priv  = box_context->priv;
+  array = get_array (box_context, orientation, for_size);
+
+  for (i = 0; i < array->len; i++)
+    {
+      size = &g_array_index (array, CachedSize, i);
+
+      if (size->nat_size > 0 &&
+	  (i <= last_aligned_group_idx ||
+	   _gtk_cell_area_box_group_visible (area, i)))
+	visible_groups++;
+    }
+
+  requests = g_new (GtkRequestedSize, visible_groups);
+
+  for (j = 0, i = 0; i < array->len; i++)
+    {
+      size = &g_array_index (array, CachedSize, i);
+
+      if (size->nat_size > 0 &&
+	  (i <= last_aligned_group_idx ||
+	   _gtk_cell_area_box_group_visible (area, i)))
+        {
+          requests[j].data         = GINT_TO_POINTER (i);
+          requests[j].minimum_size = size->min_size;
+          requests[j].natural_size = size->nat_size;
+          j++;
+        }
+    }
+
+  if (n_requests)
+    *n_requests = visible_groups;
+
+  return requests;
+}
+
+static GtkCellAreaBoxAllocation *
+allocate_for_orientation (GtkCellAreaBoxContext *context,
+			  GtkCellAreaBox        *area,
+                          GtkOrientation         orientation,
+                          gint                   spacing,
+                          gint                   size,
+                          gint                   for_size,
+                          gint                  *n_allocs)
+{
+  GtkCellAreaBoxContextPrivate *priv = context->priv;
+  GtkCellAreaBoxAllocation     *allocs;
+  GtkRequestedSize             *sizes;
+  GArray                       *array;
+  gint                          n_expand_groups = 0;
+  gint                          i, n_groups, position, vis_position;
+  gint                          extra_size, extra_extra;
+  gint                          avail_size = size;
+
+  sizes           = gtk_cell_area_box_context_get_requests (context, area, orientation, for_size, &n_groups);
+  array           = get_array (context, orientation, for_size);
+  n_expand_groups = count_expand_groups (context);
+
+  /* First start by naturally allocating space among groups */
+  avail_size -= (n_groups - 1) * spacing;
+  for (i = 0; i < n_groups; i++)
+    avail_size -= sizes[i].minimum_size;
+
+  if (avail_size > 0)
+    avail_size = gtk_distribute_natural_allocation (avail_size, n_groups, sizes);
+  else
+    avail_size = 0;
+
+  /* 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 (vis_position = 0, position = 0, i = 0; i < n_groups; i++)
+    {
+      allocs[i].group_idx = GPOINTER_TO_INT (sizes[i].data);
+
+      if (priv->align[allocs[i].group_idx])
+	vis_position = position;
+
+      allocs[i].position  = vis_position;
+      allocs[i].size      = sizes[i].minimum_size;
+
+      if (group_expands (context, allocs[i].group_idx))
+        {
+          allocs[i].size += extra_size;
+          if (extra_extra)
+            {
+              allocs[i].size++;
+              extra_extra--;
+            }
+        }
+
+      position += allocs[i].size;
+      position += spacing;
+
+      if (_gtk_cell_area_box_group_visible (area, allocs[i].group_idx))
+	{
+	  vis_position += allocs[i].size;
+	  vis_position += spacing;
+	}
+    }
+
+  if (n_allocs)
+    *n_allocs = n_groups;
+
+  g_free (sizes);
+
+  return allocs;
+}
+
 GtkRequestedSize *
 gtk_cell_area_box_context_get_widths (GtkCellAreaBoxContext *box_context,
                                       gint                  *n_widths)
 {
-  return gtk_cell_area_box_context_get_requests (box_context, GTK_ORIENTATION_HORIZONTAL, -1, n_widths);
+  GtkCellAreaBox *area = (GtkCellAreaBox *)gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (box_context));
+
+  return gtk_cell_area_box_context_get_requests (box_context, area, GTK_ORIENTATION_HORIZONTAL, -1, n_widths);
 }
 
 GtkRequestedSize *
 gtk_cell_area_box_context_get_heights (GtkCellAreaBoxContext *box_context,
                                        gint                  *n_heights)
 {
-  return gtk_cell_area_box_context_get_requests (box_context, GTK_ORIENTATION_VERTICAL, -1, n_heights);
+  GtkCellAreaBox *area = (GtkCellAreaBox *)gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (box_context));
+
+  return gtk_cell_area_box_context_get_requests (box_context, area, GTK_ORIENTATION_VERTICAL, -1, n_heights);
 }
 
 GtkCellAreaBoxAllocation *
 gtk_cell_area_box_context_get_orientation_allocs (GtkCellAreaBoxContext *context,
                                                   gint                  *n_allocs)
 {
-  GtkCellAreaBoxContextPrivate *priv;
+  GtkCellAreaContext       *ctx  = GTK_CELL_AREA_CONTEXT (context);
+  GtkCellAreaBox           *area;
+  GtkOrientation            orientation;
+  gint                      spacing, width, height, alloc_count = 0;
+  GtkCellAreaBoxAllocation *allocs = NULL;
 
-  g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (context), NULL);
+  area        = (GtkCellAreaBox *)gtk_cell_area_context_get_area (ctx);
+  orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
+  spacing     = gtk_cell_area_box_get_spacing (area);
 
-  priv = context->priv;
+  gtk_cell_area_context_get_allocation (ctx, &width, &height);
 
-  *n_allocs = priv->n_orientation_allocs;
+  if (orientation == GTK_ORIENTATION_HORIZONTAL && width > 0)
+    allocs = allocate_for_orientation (context, area, orientation, 
+				       spacing, width, height,
+				       &alloc_count);
+  else if (orientation == GTK_ORIENTATION_VERTICAL && height > 0)
+    allocs = allocate_for_orientation (context, area, orientation, 
+				       spacing, height, width,
+				       &alloc_count);
+
+  *n_allocs = alloc_count;
 
-  return priv->orientation_allocs;
+  return allocs;
 }
diff --git a/gtk/gtkcellareaboxcontext.h b/gtk/gtkcellareaboxcontext.h
index 7d9f37e..d586cc3 100644
--- a/gtk/gtkcellareaboxcontext.h
+++ b/gtk/gtkcellareaboxcontext.h
@@ -69,7 +69,8 @@ GtkCellAreaBoxContext *gtk_cell_area_box_context_copy          (GtkCellAreaBox
 /* Initialize group array dimensions */
 void    gtk_cell_area_box_init_groups                          (GtkCellAreaBoxContext *box_context,
                                                                 guint                  n_groups,
-                                                                gboolean              *expand_groups);
+                                                                gboolean              *expand_groups,
+								gboolean              *align_groups);
 
 /* Update cell-group sizes */
 void    gtk_cell_area_box_context_push_group_width             (GtkCellAreaBoxContext *box_context,
diff --git a/tests/testcellarea.c b/tests/testcellarea.c
index ec9398d..be54c79 100644
--- a/tests/testcellarea.c
+++ b/tests/testcellarea.c
@@ -96,12 +96,12 @@ simple_scaffold (void)
   area = cell_area_scaffold_get_area (CELL_AREA_SCAFFOLD (scaffold));
 
   cell_1 = renderer = gtk_cell_renderer_text_new ();
-  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, FALSE);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, FALSE, FALSE);
   gtk_cell_area_attribute_connect (area, renderer, "text", SIMPLE_COLUMN_NAME);
 
   cell_2 = renderer = gtk_cell_renderer_pixbuf_new ();
   g_object_set (G_OBJECT (renderer), "xalign", 0.0F, NULL);
-  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, TRUE, FALSE);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, TRUE, FALSE, FALSE);
   gtk_cell_area_attribute_connect (area, renderer, "stock-id", SIMPLE_COLUMN_ICON);
 
   cell_3 = renderer = gtk_cell_renderer_text_new ();
@@ -109,7 +109,7 @@ simple_scaffold (void)
 		"wrap-mode", PANGO_WRAP_WORD,
 		"wrap-width", 215,
 		NULL);
-  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, TRUE);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, TRUE, FALSE);
   gtk_cell_area_attribute_connect (area, renderer, "text", SIMPLE_COLUMN_DESCRIPTION);
 
   return scaffold;
@@ -360,7 +360,7 @@ focus_scaffold (gboolean color_bg, GtkCellRenderer **focus, GtkCellRenderer **si
 
   renderer = gtk_cell_renderer_text_new ();
   g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
-  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, TRUE, FALSE);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, TRUE, FALSE, FALSE);
   gtk_cell_area_attribute_connect (area, renderer, "text", FOCUS_COLUMN_NAME);
 
   if (color_bg)
@@ -371,7 +371,7 @@ focus_scaffold (gboolean color_bg, GtkCellRenderer **focus, GtkCellRenderer **si
 
   toggle = renderer = gtk_cell_renderer_toggle_new ();
   g_object_set (G_OBJECT (renderer), "xalign", 0.0F, NULL);
-  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, TRUE);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, TRUE, FALSE);
   gtk_cell_area_attribute_connect (area, renderer, "active", FOCUS_COLUMN_CHECK);
 
   if (color_bg)
@@ -395,7 +395,7 @@ focus_scaffold (gboolean color_bg, GtkCellRenderer **focus, GtkCellRenderer **si
   if (sibling)
     *sibling = renderer;
 
-  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, TRUE);
+  gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), renderer, FALSE, TRUE, FALSE);
   gtk_cell_area_attribute_connect (area, renderer, "text", FOCUS_COLUMN_STATIC_TEXT);
 
   gtk_cell_area_add_focus_sibling (area, toggle, renderer);
diff --git a/tests/testtreeedit.c b/tests/testtreeedit.c
index 01e1f2b..712dad4 100644
--- a/tests/testtreeedit.c
+++ b/tests/testtreeedit.c
@@ -156,27 +156,50 @@ expand_cell_toggled (GtkToggleButton  *toggle,
 }
 
 static void
-create_control (GtkWidget *box, gint number, gboolean align, CallbackData *data)
+fixed_cell_toggled (GtkToggleButton  *toggle,
+		    CallbackData     *data)
+{
+  gboolean active = gtk_toggle_button_get_active (toggle);
+
+  gtk_cell_area_cell_set (data->area, data->renderer, "fixed-size", active, NULL);
+}
+
+enum {
+  CNTL_EXPAND,
+  CNTL_ALIGN,
+  CNTL_FIXED
+};
+
+static void
+create_control (GtkWidget *box, gint number, gint cntl, CallbackData *data)
 {
   GtkWidget *checkbutton;
-  gchar *name;
+  GCallback  callback = NULL;
+  gchar *name = NULL;
 
-  if (align)
-    name = g_strdup_printf ("Align Cell #%d", number);
-  else
-    name = g_strdup_printf ("Expand Cell #%d", number);
+  switch (cntl)
+    {
+    case CNTL_EXPAND: 
+      name = g_strdup_printf ("Expand Cell #%d", number); 
+      callback = G_CALLBACK (expand_cell_toggled);
+      break;
+    case CNTL_ALIGN: 
+      name = g_strdup_printf ("Align Cell #%d", number); 
+      callback = G_CALLBACK (align_cell_toggled);
+      break;
+    case CNTL_FIXED: 
+      name = g_strdup_printf ("Fix size Cell #%d", number); 
+      callback = G_CALLBACK (fixed_cell_toggled);
+      break;
+    }
 
   checkbutton = gtk_check_button_new_with_label (name);
   gtk_widget_show (checkbutton);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), align);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton), cntl == CNTL_FIXED);
   gtk_box_pack_start (GTK_BOX (box), checkbutton, FALSE, FALSE, 0);
 
-  if (align)
-    g_signal_connect (G_OBJECT (checkbutton), "toggled",
-		      G_CALLBACK (align_cell_toggled), data);
-  else
-    g_signal_connect (G_OBJECT (checkbutton), "toggled",
-		      G_CALLBACK (expand_cell_toggled), data);
+  g_signal_connect (G_OBJECT (checkbutton), "toggled", callback, data);
+  g_free (name);
 }
 
 gint
@@ -296,20 +319,30 @@ main (gint argc, gchar **argv)
   gtk_widget_show (cntl_vbox);
   gtk_box_pack_start (GTK_BOX (hbox), cntl_vbox, FALSE, FALSE, 0);
 
-  create_control (cntl_vbox, 1, TRUE, &callback[0]);
-  create_control (cntl_vbox, 2, TRUE, &callback[1]);
-  create_control (cntl_vbox, 3, TRUE, &callback[2]);
-  create_control (cntl_vbox, 4, TRUE, &callback[3]);
+  create_control (cntl_vbox, 1, CNTL_ALIGN, &callback[0]);
+  create_control (cntl_vbox, 2, CNTL_ALIGN, &callback[1]);
+  create_control (cntl_vbox, 3, CNTL_ALIGN, &callback[2]);
+  create_control (cntl_vbox, 4, CNTL_ALIGN, &callback[3]);
 
   /* Expand controls */
   cntl_vbox = gtk_vbox_new (FALSE, 2);
   gtk_widget_show (cntl_vbox);
   gtk_box_pack_start (GTK_BOX (hbox), cntl_vbox, FALSE, FALSE, 0);
 
-  create_control (cntl_vbox, 1, FALSE, &callback[0]);
-  create_control (cntl_vbox, 2, FALSE, &callback[1]);
-  create_control (cntl_vbox, 3, FALSE, &callback[2]);
-  create_control (cntl_vbox, 4, FALSE, &callback[3]);
+  create_control (cntl_vbox, 1, CNTL_EXPAND, &callback[0]);
+  create_control (cntl_vbox, 2, CNTL_EXPAND, &callback[1]);
+  create_control (cntl_vbox, 3, CNTL_EXPAND, &callback[2]);
+  create_control (cntl_vbox, 4, CNTL_EXPAND, &callback[3]);
+
+  /* Fixed controls */
+  cntl_vbox = gtk_vbox_new (FALSE, 2);
+  gtk_widget_show (cntl_vbox);
+  gtk_box_pack_start (GTK_BOX (hbox), cntl_vbox, FALSE, FALSE, 0);
+
+  create_control (cntl_vbox, 1, CNTL_FIXED, &callback[0]);
+  create_control (cntl_vbox, 2, CNTL_FIXED, &callback[1]);
+  create_control (cntl_vbox, 3, CNTL_FIXED, &callback[2]);
+  create_control (cntl_vbox, 4, CNTL_FIXED, &callback[3]);
 
   gtk_widget_show_all (window);
   gtk_main ();



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