diff options
author | Tristan Van Berkom <tristan.van.berkom@gmail.com> | 2010-12-21 21:11:01 +0900 |
---|---|---|
committer | Tristan Van Berkom <tristan.van.berkom@gmail.com> | 2010-12-22 00:28:18 +0900 |
commit | 49273f227770052f99dcb4be6fbe8224712d0944 (patch) | |
tree | f73c997370d252a7fbd57fc5615abeb4aae44dc1 /gtk | |
parent | c8ae68c33dc65dc4407863553d059caa1d41e464 (diff) | |
download | gtk+-49273f227770052f99dcb4be6fbe8224712d0944.tar.gz |
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.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkcellareabox.c | 204 | ||||
-rw-r--r-- | gtk/gtkcellareabox.h | 9 | ||||
-rw-r--r-- | gtk/gtkcellareaboxcontext.c | 385 | ||||
-rw-r--r-- | gtk/gtkcellareaboxcontext.h | 3 |
4 files changed, 382 insertions, 219 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, |