X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcellareaboxcontext.c;h=d00316578a377fdaedd3015e9c41f9c950ff016a;hb=79695ee64d41c9aadfe2c6f18dc7dd1e3fd44852;hp=e0501e6944fc1d2a1d44ae8d2dbe2ce4f9463a5b;hpb=1bca6349fb5b5b8130e5a7a7cad275cfc12e7346;p=~andy%2Fgtk diff --git a/gtk/gtkcellareaboxcontext.c b/gtk/gtkcellareaboxcontext.c index e0501e694..d00316578 100644 --- a/gtk/gtkcellareaboxcontext.c +++ b/gtk/gtkcellareaboxcontext.c @@ -16,40 +16,46 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ #include "config.h" #include "gtkintl.h" #include "gtkcellareabox.h" -#include "gtkcellareaboxcontext.h" +#include "gtkcellareaboxcontextprivate.h" #include "gtkorientable.h" /* GObjectClass */ -static void gtk_cell_area_box_context_finalize (GObject *object); +static void _gtk_cell_area_box_context_finalize (GObject *object); /* GtkCellAreaContextClass */ -static void gtk_cell_area_box_context_flush_preferred_width (GtkCellAreaContext *context); -static void gtk_cell_area_box_context_flush_preferred_height_for_width (GtkCellAreaContext *context, - gint width); -static void gtk_cell_area_box_context_flush_preferred_height (GtkCellAreaContext *context); -static void gtk_cell_area_box_context_flush_preferred_width_for_height (GtkCellAreaContext *context, - gint height); -static void gtk_cell_area_box_context_flush_allocation (GtkCellAreaContext *context); -static void gtk_cell_area_box_context_sum_preferred_width (GtkCellAreaContext *context); -static void gtk_cell_area_box_context_sum_preferred_height_for_width (GtkCellAreaContext *context, - gint width); -static void gtk_cell_area_box_context_sum_preferred_height (GtkCellAreaContext *context); -static void gtk_cell_area_box_context_sum_preferred_width_for_height (GtkCellAreaContext *context, - gint height); -static void gtk_cell_area_box_context_allocate_width (GtkCellAreaContext *context, - gint width); -static void gtk_cell_area_box_context_allocate_height (GtkCellAreaContext *context, - gint height); - -static void free_cache_array (GArray *array); +static void _gtk_cell_area_box_context_reset (GtkCellAreaContext *context); +static void _gtk_cell_area_box_context_get_preferred_height_for_width (GtkCellAreaContext *context, + gint width, + gint *minimum_height, + gint *natural_height); +static void _gtk_cell_area_box_context_get_preferred_width_for_height (GtkCellAreaContext *context, + gint height, + gint *minimum_width, + gint *natural_width); + + + +/* Internal functions */ +static void _gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context, + GtkOrientation orientation, + gint for_size, + gint *minimum_size, + gint *natural_size); +static void free_cache_array (GArray *array); +static GArray *group_array_new (GtkCellAreaBoxContext *context); +static GArray *get_array (GtkCellAreaBoxContext *context, + GtkOrientation orientation, + gint for_size); +static gboolean group_expands (GtkCellAreaBoxContext *context, + gint group_idx); +static gint count_expand_groups (GtkCellAreaBoxContext *context); + /* CachedSize management */ typedef struct { @@ -57,12 +63,6 @@ typedef struct { gint nat_size; } CachedSize; -typedef struct { - gint min_size; - gint nat_size; - gboolean expand; -} BaseSize; - struct _GtkCellAreaBoxContextPrivate { /* Table of per renderer CachedSizes */ @@ -73,14 +73,14 @@ struct _GtkCellAreaBoxContextPrivate GHashTable *widths; GHashTable *heights; - /* Allocation info for this context if any */ - gint alloc_width; - gint alloc_height; - gint n_orientation_allocs; - GtkCellAreaBoxAllocation *orientation_allocs; + /* Whether each group expands */ + gboolean *expand; + + /* Whether each group is aligned */ + gboolean *align; }; -G_DEFINE_TYPE (GtkCellAreaBoxContext, gtk_cell_area_box_context, GTK_TYPE_CELL_AREA_CONTEXT); +G_DEFINE_TYPE (GtkCellAreaBoxContext, _gtk_cell_area_box_context, GTK_TYPE_CELL_AREA_CONTEXT); static void free_cache_array (GArray *array) @@ -88,52 +88,111 @@ free_cache_array (GArray *array) g_array_free (array, TRUE); } +static GArray * +group_array_new (GtkCellAreaBoxContext *context) +{ + GtkCellAreaBoxContextPrivate *priv = context->priv; + GArray *group_array; + + group_array = g_array_new (FALSE, TRUE, sizeof (CachedSize)); + g_array_set_size (group_array, priv->base_widths->len); + + return group_array; +} + +static GArray * +get_array (GtkCellAreaBoxContext *context, + GtkOrientation orientation, + gint for_size) +{ + GtkCellAreaBoxContextPrivate *priv = context->priv; + GArray *array; + + if (for_size < 0) + { + if (orientation == GTK_ORIENTATION_HORIZONTAL) + array = priv->base_widths; + else + array = priv->base_heights; + } + else + { + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_size)); + + if (!array) + array = priv->base_widths; + } + else + { + array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_size)); + + if (!array) + array = priv->base_heights; + } + } + + return array; +} + +static gboolean +group_expands (GtkCellAreaBoxContext *context, + gint group_idx) +{ + GtkCellAreaBoxContextPrivate *priv = context->priv; + + g_assert (group_idx >= 0 && group_idx < priv->base_widths->len); + + return priv->expand[group_idx]; +} + +static gint +count_expand_groups (GtkCellAreaBoxContext *context) +{ + GtkCellAreaBoxContextPrivate *priv = context->priv; + gint i, expand = 0; + + for (i = 0; i < priv->base_widths->len; i++) + { + if (priv->expand[i]) + expand++; + } + + return expand; +} + static void -gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context) +_gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context) { GtkCellAreaBoxContextPrivate *priv; box_context->priv = G_TYPE_INSTANCE_GET_PRIVATE (box_context, - GTK_TYPE_CELL_AREA_BOX_CONTEXT, - GtkCellAreaBoxContextPrivate); + GTK_TYPE_CELL_AREA_BOX_CONTEXT, + GtkCellAreaBoxContextPrivate); priv = box_context->priv; - priv->base_widths = g_array_new (FALSE, TRUE, sizeof (BaseSize)); - priv->base_heights = g_array_new (FALSE, TRUE, sizeof (BaseSize)); + priv->base_widths = g_array_new (FALSE, TRUE, sizeof (CachedSize)); + priv->base_heights = g_array_new (FALSE, TRUE, sizeof (CachedSize)); priv->widths = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify)free_cache_array); + 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; + NULL, (GDestroyNotify)free_cache_array); } static void -gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class) +_gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkCellAreaContextClass *context_class = GTK_CELL_AREA_CONTEXT_CLASS (class); /* GObjectClass */ - object_class->finalize = gtk_cell_area_box_context_finalize; + object_class->finalize = _gtk_cell_area_box_context_finalize; - context_class->flush_preferred_width = gtk_cell_area_box_context_flush_preferred_width; - context_class->flush_preferred_height_for_width = gtk_cell_area_box_context_flush_preferred_height_for_width; - context_class->flush_preferred_height = gtk_cell_area_box_context_flush_preferred_height; - context_class->flush_preferred_width_for_height = gtk_cell_area_box_context_flush_preferred_width_for_height; - context_class->flush_allocation = gtk_cell_area_box_context_flush_allocation; - - context_class->sum_preferred_width = gtk_cell_area_box_context_sum_preferred_width; - context_class->sum_preferred_height_for_width = gtk_cell_area_box_context_sum_preferred_height_for_width; - context_class->sum_preferred_height = gtk_cell_area_box_context_sum_preferred_height; - context_class->sum_preferred_width_for_height = gtk_cell_area_box_context_sum_preferred_width_for_height; - - context_class->allocate_width = gtk_cell_area_box_context_allocate_width; - context_class->allocate_height = gtk_cell_area_box_context_allocate_height; + context_class->reset = _gtk_cell_area_box_context_reset; + 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; g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxContextPrivate)); } @@ -142,7 +201,7 @@ gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class) * GObjectClass * *************************************************************/ static void -gtk_cell_area_box_context_finalize (GObject *object) +_gtk_cell_area_box_context_finalize (GObject *object) { GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (object); GtkCellAreaBoxContextPrivate *priv = box_context->priv; @@ -152,517 +211,263 @@ 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); + G_OBJECT_CLASS (_gtk_cell_area_box_context_parent_class)->finalize (object); } /************************************************************* - * GtkCellAreaContextClass * + * GtkCellAreaContextClass * *************************************************************/ static void -gtk_cell_area_box_context_flush_preferred_width (GtkCellAreaContext *context) +_gtk_cell_area_box_context_reset (GtkCellAreaContext *context) { GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); GtkCellAreaBoxContextPrivate *priv = box_context->priv; + CachedSize *size; gint i; for (i = 0; i < priv->base_widths->len; i++) { - BaseSize *size = &g_array_index (priv->base_widths, BaseSize, i); + size = &g_array_index (priv->base_widths, CachedSize, i); size->min_size = 0; size->nat_size = 0; - } - - GTK_CELL_AREA_CONTEXT_CLASS - (gtk_cell_area_box_context_parent_class)->flush_preferred_width (context); -} - -static void -gtk_cell_area_box_context_flush_preferred_height_for_width (GtkCellAreaContext *context, - gint width) -{ - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - /* Flush all sizes for special -1 value */ - if (width < 0) - g_hash_table_remove_all (priv->heights); - else - g_hash_table_remove (priv->heights, GINT_TO_POINTER (width)); - - GTK_CELL_AREA_CONTEXT_CLASS - (gtk_cell_area_box_context_parent_class)->flush_preferred_height_for_width (context, width); -} - -static void -gtk_cell_area_box_context_flush_preferred_height (GtkCellAreaContext *context) -{ - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - gint i; - - for (i = 0; i < priv->base_heights->len; i++) - { - BaseSize *size = &g_array_index (priv->base_heights, BaseSize, i); + size = &g_array_index (priv->base_heights, CachedSize, i); size->min_size = 0; size->nat_size = 0; } - GTK_CELL_AREA_CONTEXT_CLASS - (gtk_cell_area_box_context_parent_class)->flush_preferred_height (context); -} - -static void -gtk_cell_area_box_context_flush_preferred_width_for_height (GtkCellAreaContext *context, - gint height) -{ - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - - /* Flush all sizes for special -1 value */ - if (height < 0) - g_hash_table_remove_all (priv->widths); - else - g_hash_table_remove (priv->widths, GINT_TO_POINTER (height)); + /* Reset context sizes as well */ + g_hash_table_remove_all (priv->widths); + g_hash_table_remove_all (priv->heights); GTK_CELL_AREA_CONTEXT_CLASS - (gtk_cell_area_box_context_parent_class)->flush_preferred_width_for_height (context, height); -} - -static void -gtk_cell_area_box_context_flush_allocation (GtkCellAreaContext *context) -{ - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - - g_free (priv->orientation_allocs); - priv->orientation_allocs = NULL; - priv->n_orientation_allocs = 0; + (_gtk_cell_area_box_context_parent_class)->reset (context); } static void -gtk_cell_area_box_context_sum_preferred_width (GtkCellAreaContext *context) +_gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context, + GtkOrientation orientation, + gint for_size, + gint *minimum_size, + gint *natural_size) { - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - GtkCellArea *area; - GtkOrientation orientation; - gint spacing, i; - gint min_size = 0, nat_size = 0; - - area = gtk_cell_area_context_get_area (context); - spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area)); - - for (i = 0; i < priv->base_widths->len; i++) + GtkCellAreaBoxContextPrivate *priv = context->priv; + GtkCellAreaBox *area; + GtkOrientation box_orientation; + GArray *array; + gint spacing, i, last_aligned_group_idx; + gint min_size = 0, nat_size = 0; + + 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--) { - BaseSize *size = &g_array_index (priv->base_widths, BaseSize, i); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - /* Dont add spacing for 0 size groups, they can be 0 size because - * they contain only invisible cells for this round of requests - */ - if (min_size > 0 && size->nat_size > 0) - { - min_size += spacing; - nat_size += spacing; - } - - min_size += size->min_size; - nat_size += size->nat_size; - } - else - { - min_size = MAX (min_size, size->min_size); - nat_size = MAX (nat_size, size->nat_size); - } + if (priv->align[i] && + _gtk_cell_area_box_group_visible (area, i)) + break; } + last_aligned_group_idx = i >= 0 ? i : 0; - gtk_cell_area_context_push_preferred_width (context, min_size, nat_size); -} - -static void -gtk_cell_area_box_context_sum_preferred_height_for_width (GtkCellAreaContext *context, - gint width) -{ - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - GArray *group_array; - GtkCellArea *area; - GtkOrientation orientation; - gint spacing, i; - gint min_size = 0, nat_size = 0; - - group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (width)); - - if (group_array) + for (i = 0; i < array->len; i++) { - area = gtk_cell_area_context_get_area (context); - spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area)); - - for (i = 0; i < group_array->len; i++) - { - CachedSize *size = &g_array_index (group_array, CachedSize, i); - - if (orientation == GTK_ORIENTATION_VERTICAL) - { - /* Dont add spacing for 0 size groups, they can be 0 size because - * they contain only invisible cells for this round of requests - */ - if (min_size > 0 && size->nat_size > 0) - { - min_size += spacing; - nat_size += spacing; - } - - min_size += size->min_size; - nat_size += size->nat_size; - } - else - { - min_size = MAX (min_size, size->min_size); - nat_size = MAX (nat_size, size->nat_size); - } - } - - gtk_cell_area_context_push_preferred_height_for_width (context, width, min_size, nat_size); + 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 + */ + if (min_size > 0 && size->nat_size > 0) + { + min_size += spacing; + nat_size += spacing; + } + + min_size += size->min_size; + nat_size += size->nat_size; + } + else + { + min_size = MAX (min_size, size->min_size); + nat_size = MAX (nat_size, size->nat_size); + } } -} - -static void -gtk_cell_area_box_context_sum_preferred_height (GtkCellAreaContext *context) -{ - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - GtkCellArea *area; - GtkOrientation orientation; - gint spacing, i; - gint min_size = 0, nat_size = 0; - - area = gtk_cell_area_context_get_area (context); - spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area)); - for (i = 0; i < priv->base_heights->len; i++) + if (for_size < 0) { - BaseSize *size = &g_array_index (priv->base_heights, BaseSize, i); - - if (orientation == GTK_ORIENTATION_VERTICAL) - { - /* Dont add spacing for 0 size groups, they can be 0 size because - * they contain only invisible cells for this round of requests - */ - if (min_size > 0 && size->nat_size > 0) - { - min_size += spacing; - nat_size += spacing; - } - - min_size += size->min_size; - nat_size += size->nat_size; - } + if (orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_cell_area_context_push_preferred_width (GTK_CELL_AREA_CONTEXT (context), min_size, nat_size); else - { - min_size = MAX (min_size, size->min_size); - nat_size = MAX (nat_size, size->nat_size); - } + gtk_cell_area_context_push_preferred_height (GTK_CELL_AREA_CONTEXT (context), min_size, nat_size); } - gtk_cell_area_context_push_preferred_height (context, min_size, nat_size); + if (minimum_size) + *minimum_size = min_size; + if (natural_size) + *natural_size = nat_size; } static void -gtk_cell_area_box_context_sum_preferred_width_for_height (GtkCellAreaContext *context, - gint height) +_gtk_cell_area_box_context_get_preferred_height_for_width (GtkCellAreaContext *context, + gint width, + gint *minimum_height, + gint *natural_height) { - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - GArray *group_array; - GtkCellArea *area; - GtkOrientation orientation; - gint spacing, i; - gint min_size = 0, nat_size = 0; - - group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (height)); - - if (group_array) - { - area = gtk_cell_area_context_get_area (context); - spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area)); - - for (i = 0; i < group_array->len; i++) - { - CachedSize *size = &g_array_index (group_array, CachedSize, i); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - /* Dont add spacing for 0 size groups, they can be 0 size because - * they contain only invisible cells for this round of requests - */ - if (min_size > 0 && size->nat_size > 0) - { - min_size += spacing; - nat_size += spacing; - } - - min_size += size->min_size; - nat_size += size->nat_size; - } - else - { - min_size = MAX (min_size, size->min_size); - nat_size = MAX (nat_size, size->nat_size); - } - } - - gtk_cell_area_context_push_preferred_width_for_height (context, height, min_size, nat_size); - } + _gtk_cell_area_box_context_sum (GTK_CELL_AREA_BOX_CONTEXT (context), GTK_ORIENTATION_VERTICAL, + width, minimum_height, natural_height); } -static GtkRequestedSize * -gtk_cell_area_box_context_get_requests (GtkCellAreaBoxContext *box_context, - GtkOrientation orientation, - gint *n_requests) +static void +_gtk_cell_area_box_context_get_preferred_width_for_height (GtkCellAreaContext *context, + gint height, + gint *minimum_width, + gint *natural_width) { - GtkCellAreaBoxContextPrivate *priv; - GtkRequestedSize *requests; - GArray *base_array; - BaseSize *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; - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - base_array = priv->base_widths; - else - base_array = priv->base_heights; - - for (i = 0; i < base_array->len; i++) - { - size = &g_array_index (base_array, BaseSize, i); - - if (size->nat_size > 0) - visible_groups++; - } - - requests = g_new (GtkRequestedSize, visible_groups); - - for (j = 0, i = 0; i < base_array->len; i++) - { - size = &g_array_index (base_array, BaseSize, 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; + _gtk_cell_area_box_context_sum (GTK_CELL_AREA_BOX_CONTEXT (context), GTK_ORIENTATION_HORIZONTAL, + height, minimum_width, natural_width); } -static GtkCellAreaBoxAllocation * -allocate_for_orientation (GtkCellAreaBoxContext *context, - GtkOrientation orientation, - gint spacing, - gint size, - gint *n_allocs) +/************************************************************* + * API * + *************************************************************/ +static void +copy_size_array (GArray *src_array, + GArray *dest_array) { - GtkCellAreaBoxContextPrivate *priv = context->priv; - GtkRequestedSize *orientation_sizes; - GtkCellAreaBoxAllocation *allocs; - gint n_expand_groups = 0; - gint i, n_groups, position; - gint extra_size, extra_extra; - gint avail_size = size; - - orientation_sizes = - gtk_cell_area_box_context_get_requests (context, orientation, &n_groups); + gint i; - /* Count groups that expand */ - for (i = 0; i < n_groups; i++) - { - BaseSize *size; - gint group_idx = GPOINTER_TO_INT (orientation_sizes[i].data); - - if (orientation == GTK_ORIENTATION_HORIZONTAL) - size = &g_array_index (priv->base_widths, BaseSize, group_idx); - else - size = &g_array_index (priv->base_heights, BaseSize, group_idx); - - if (size->expand) - n_expand_groups++; - } - - /* First start by naturally allocating space among groups */ - avail_size -= (n_groups - 1) * spacing; - for (i = 0; i < n_groups; i++) - avail_size -= orientation_sizes[i].minimum_size; - - avail_size = gtk_distribute_natural_allocation (avail_size, n_groups, orientation_sizes); - - /* Calculate/distribute expand for groups */ - if (n_expand_groups > 0) - { - extra_size = avail_size / n_expand_groups; - extra_extra = avail_size % n_expand_groups; - } - else - extra_size = extra_extra = 0; - - allocs = g_new (GtkCellAreaBoxAllocation, n_groups); - - for (position = 0, i = 0; i < n_groups; i++) + for (i = 0; i < src_array->len; i++) { - BaseSize *base_size = &g_array_index (priv->base_widths, BaseSize, i); - - allocs[i].group_idx = GPOINTER_TO_INT (orientation_sizes[i].data); - allocs[i].position = position; - allocs[i].size = orientation_sizes[i].minimum_size; - - if (base_size->expand) - { - allocs[i].size += extra_size; - if (extra_extra) - { - allocs[i].size++; - extra_extra--; - } - } + CachedSize *src = &g_array_index (src_array, CachedSize, i); + CachedSize *dest = &g_array_index (dest_array, CachedSize, i); - position += allocs[i].size; - position += spacing; + memcpy (dest, src, sizeof (CachedSize)); } - - if (n_allocs) - *n_allocs = n_groups; - - g_free (orientation_sizes); - - return allocs; } static void -gtk_cell_area_box_context_allocate_width (GtkCellAreaContext *context, - gint width) +for_size_copy (gpointer key, + GArray *size_array, + GHashTable *dest_hash) { - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - GtkCellArea *area; - GtkOrientation orientation; - - area = gtk_cell_area_context_get_area (context); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area)); + GArray *new_array; - if (orientation == GTK_ORIENTATION_HORIZONTAL) - { - gint spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); + new_array = g_array_new (FALSE, TRUE, sizeof (CachedSize)); + g_array_set_size (new_array, size_array->len); - g_free (priv->orientation_allocs); - priv->orientation_allocs = allocate_for_orientation (box_context, orientation, spacing, width, - &priv->n_orientation_allocs); - } + copy_size_array (size_array, new_array); - GTK_CELL_AREA_CONTEXT_CLASS (gtk_cell_area_box_context_parent_class)->allocate_width (context, width); + g_hash_table_insert (dest_hash, key, new_array); } -static void -gtk_cell_area_box_context_allocate_height (GtkCellAreaContext *context, - gint height) +GtkCellAreaBoxContext * +_gtk_cell_area_box_context_copy (GtkCellAreaBox *box, + GtkCellAreaBoxContext *context) { - GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); - GtkCellAreaBoxContextPrivate *priv = box_context->priv; - GtkCellArea *area; - GtkOrientation orientation; + GtkCellAreaBoxContext *copy; - area = gtk_cell_area_context_get_area (context); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area)); + copy = g_object_new (GTK_TYPE_CELL_AREA_BOX_CONTEXT, + "area", box, NULL); - if (orientation == GTK_ORIENTATION_VERTICAL) - { - gint spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); + _gtk_cell_area_box_init_groups (copy, + context->priv->base_widths->len, + context->priv->expand, + context->priv->align); + + /* Copy the base arrays */ + copy_size_array (context->priv->base_widths, + copy->priv->base_widths); + copy_size_array (context->priv->base_heights, + copy->priv->base_heights); + + /* Copy each for size */ + g_hash_table_foreach (context->priv->heights, + (GHFunc)for_size_copy, copy->priv->heights); + g_hash_table_foreach (context->priv->widths, + (GHFunc)for_size_copy, copy->priv->widths); - g_free (priv->orientation_allocs); - priv->orientation_allocs = allocate_for_orientation (box_context, orientation, spacing, height, - &priv->n_orientation_allocs); - } - GTK_CELL_AREA_CONTEXT_CLASS (gtk_cell_area_box_context_parent_class)->allocate_height (context, height); + return copy; } -/************************************************************* - * API * - *************************************************************/ void -gtk_cell_area_box_init_groups (GtkCellAreaBoxContext *box_context, - guint n_groups, - gboolean *expand_groups) +_gtk_cell_area_box_init_groups (GtkCellAreaBoxContext *box_context, + guint n_groups, + gboolean *expand_groups, + gboolean *align_groups) { GtkCellAreaBoxContextPrivate *priv; - gint i; g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context)); g_return_if_fail (n_groups == 0 || expand_groups != NULL); - /* When the group dimensions change, all info must be flushed - * Note this already clears the min/nat values on the BaseSizes + /* When the group dimensions change, all info must be reset + * Note this already clears the min/nat values on the CachedSizes */ - gtk_cell_area_context_flush (GTK_CELL_AREA_CONTEXT (box_context)); + gtk_cell_area_context_reset (GTK_CELL_AREA_CONTEXT (box_context)); priv = box_context->priv; g_array_set_size (priv->base_widths, n_groups); g_array_set_size (priv->base_heights, n_groups); - /* Now set the expand info */ - for (i = 0; i < n_groups; i++) - { - BaseSize *base_width = &g_array_index (priv->base_widths, BaseSize, i); - BaseSize *base_height = &g_array_index (priv->base_heights, BaseSize, i); + g_free (priv->expand); + priv->expand = g_memdup (expand_groups, n_groups * sizeof (gboolean)); - base_width->expand = expand_groups[i]; - base_height->expand = expand_groups[i]; - } + g_free (priv->align); + priv->align = g_memdup (align_groups, n_groups * sizeof (gboolean)); } void -gtk_cell_area_box_context_push_group_width (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint minimum_width, - gint natural_width) +_gtk_cell_area_box_context_push_group_width (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint minimum_width, + gint natural_width) { GtkCellAreaBoxContextPrivate *priv; - BaseSize *size; + CachedSize *size; + gboolean grew = FALSE; g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context)); priv = box_context->priv; g_return_if_fail (group_idx < priv->base_widths->len); - size = &g_array_index (priv->base_widths, BaseSize, group_idx); - size->min_size = MAX (size->min_size, minimum_width); - size->nat_size = MAX (size->nat_size, natural_width); + size = &g_array_index (priv->base_widths, CachedSize, group_idx); + if (minimum_width > size->min_size) + { + size->min_size = minimum_width; + grew = TRUE; + } + if (natural_width > size->nat_size) + { + size->nat_size = natural_width; + grew = TRUE; + } + + if (grew) + _gtk_cell_area_box_context_sum (box_context, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL); } void -gtk_cell_area_box_context_push_group_height_for_width (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint for_width, - gint minimum_height, - gint natural_height) +_gtk_cell_area_box_context_push_group_height_for_width (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint for_width, + gint minimum_height, + gint natural_height) { GtkCellAreaBoxContextPrivate *priv; GArray *group_array; @@ -676,9 +481,7 @@ gtk_cell_area_box_context_push_group_height_for_width (GtkCellAreaBoxContext *b group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); if (!group_array) { - group_array = g_array_new (FALSE, TRUE, sizeof (CachedSize)); - g_array_set_size (group_array, priv->base_heights->len); - + group_array = group_array_new (box_context); g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_array); } @@ -688,34 +491,46 @@ gtk_cell_area_box_context_push_group_height_for_width (GtkCellAreaBoxContext *b } void -gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint minimum_height, - gint natural_height) +_gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint minimum_height, + gint natural_height) { GtkCellAreaBoxContextPrivate *priv; - BaseSize *size; + CachedSize *size; + gboolean grew = FALSE; g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context)); priv = box_context->priv; g_return_if_fail (group_idx < priv->base_heights->len); - size = &g_array_index (priv->base_heights, BaseSize, group_idx); - size->min_size = MAX (size->min_size, minimum_height); - size->nat_size = MAX (size->nat_size, natural_height); + size = &g_array_index (priv->base_heights, CachedSize, group_idx); + if (minimum_height > size->min_size) + { + size->min_size = minimum_height; + grew = TRUE; + } + if (natural_height > size->nat_size) + { + size->nat_size = natural_height; + grew = TRUE; + } + + if (grew) + _gtk_cell_area_box_context_sum (box_context, GTK_ORIENTATION_VERTICAL, -1, NULL, NULL); } void -gtk_cell_area_box_context_push_group_width_for_height (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint for_height, - gint minimum_width, - gint natural_width) +_gtk_cell_area_box_context_push_group_width_for_height (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint for_height, + gint minimum_width, + gint natural_width) { GtkCellAreaBoxContextPrivate *priv; - GArray *group_array; - CachedSize *size; + GArray *group_array; + CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context)); @@ -725,9 +540,7 @@ gtk_cell_area_box_context_push_group_width_for_height (GtkCellAreaBoxContext *bo group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); if (!group_array) { - group_array = g_array_new (FALSE, TRUE, sizeof (CachedSize)); - g_array_set_size (group_array, priv->base_heights->len); - + group_array = group_array_new (box_context); g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_array); } @@ -737,34 +550,34 @@ gtk_cell_area_box_context_push_group_width_for_height (GtkCellAreaBoxContext *bo } void -gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint *minimum_width, - gint *natural_width) +_gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint *minimum_width, + gint *natural_width) { GtkCellAreaBoxContextPrivate *priv; - BaseSize *size; + CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context)); priv = box_context->priv; g_return_if_fail (group_idx < priv->base_widths->len); - size = &g_array_index (priv->base_widths, BaseSize, group_idx); + size = &g_array_index (priv->base_widths, CachedSize, group_idx); if (minimum_width) *minimum_width = size->min_size; - + if (natural_width) *natural_width = size->nat_size; } void -gtk_cell_area_box_context_get_group_height_for_width (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint for_width, - gint *minimum_height, - gint *natural_height) +_gtk_cell_area_box_context_get_group_height_for_width (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint for_width, + gint *minimum_height, + gint *natural_height) { GtkCellAreaBoxContextPrivate *priv; GArray *group_array; @@ -781,50 +594,50 @@ gtk_cell_area_box_context_get_group_height_for_width (GtkCellAreaBoxContext *box CachedSize *size = &g_array_index (group_array, CachedSize, group_idx); if (minimum_height) - *minimum_height = size->min_size; + *minimum_height = size->min_size; if (natural_height) - *natural_height = size->nat_size; + *natural_height = size->nat_size; } else { if (minimum_height) - *minimum_height = -1; + *minimum_height = -1; if (natural_height) - *natural_height = -1; + *natural_height = -1; } } void -gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint *minimum_height, - gint *natural_height) +_gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint *minimum_height, + gint *natural_height) { GtkCellAreaBoxContextPrivate *priv; - BaseSize *size; + CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context)); priv = box_context->priv; g_return_if_fail (group_idx < priv->base_heights->len); - size = &g_array_index (priv->base_heights, BaseSize, group_idx); + size = &g_array_index (priv->base_heights, CachedSize, group_idx); if (minimum_height) *minimum_height = size->min_size; - + if (natural_height) *natural_height = size->nat_size; } void -gtk_cell_area_box_context_get_group_width_for_height (GtkCellAreaBoxContext *box_context, - gint group_idx, - gint for_height, - gint *minimum_width, - gint *natural_width) +_gtk_cell_area_box_context_get_group_width_for_height (GtkCellAreaBoxContext *box_context, + gint group_idx, + gint for_height, + gint *minimum_width, + gint *natural_width) { GtkCellAreaBoxContextPrivate *priv; GArray *group_array; @@ -841,46 +654,205 @@ gtk_cell_area_box_context_get_group_width_for_height (GtkCellAreaBoxContext *box CachedSize *size = &g_array_index (group_array, CachedSize, group_idx); if (minimum_width) - *minimum_width = size->min_size; + *minimum_width = size->min_size; if (natural_width) - *natural_width = size->nat_size; + *natural_width = size->nat_size; } else { if (minimum_width) - *minimum_width = -1; + *minimum_width = -1; if (natural_width) - *natural_width = -1; + *natural_width = -1; } } +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; + 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); + 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) +_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, 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) +_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, 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); } -G_CONST_RETURN GtkCellAreaBoxAllocation * -gtk_cell_area_box_context_get_orientation_allocs (GtkCellAreaBoxContext *context, - gint *n_allocs) +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); - - priv = context->priv; + 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); + + 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); - return priv->orientation_allocs; + *n_allocs = alloc_count; + + return allocs; }