summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk/gtkcellareabox.c204
-rw-r--r--gtk/gtkcellareabox.h9
-rw-r--r--gtk/gtkcellareaboxcontext.c385
-rw-r--r--gtk/gtkcellareaboxcontext.h3
-rw-r--r--tests/testcellarea.c12
-rw-r--r--tests/testtreeedit.c75
6 files changed, 442 insertions, 246 deletions
diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c
index 97cfc2215f..f81d1c2d9c 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 632ea93bec..cfe00e831e 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 b68002d9c5..c5e02bda9e 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 7d9f37ed83..d586cc341a 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 ec9398d6f2..be54c79b3f 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 01e1f2bbe7..712dad4128 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 ();