diff options
-rw-r--r-- | gtk/gtkcellareabox.c | 57 | ||||
-rw-r--r-- | gtk/gtkcellareaboxcontext.c | 303 | ||||
-rw-r--r-- | gtk/gtkcellareaboxcontext.h | 27 | ||||
-rw-r--r-- | gtk/gtkcellareacontext.c | 363 | ||||
-rw-r--r-- | gtk/gtkcellareacontext.h | 32 |
5 files changed, 762 insertions, 20 deletions
diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c index 8950c53c0f..02ec53f9e3 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -1284,7 +1284,8 @@ compute_size (GtkCellAreaBox *box, for (i = 0; i < priv->groups->len; i++) { CellGroup *group = &g_array_index (priv->groups, CellGroup, i); - gint group_min = 0, group_nat = 0; + gint group_min_size = 0; + gint group_nat_size = 0; for (list = group->cells; list; list = list->next) { @@ -1304,33 +1305,42 @@ compute_size (GtkCellAreaBox *box, min_size += priv->spacing; nat_size += priv->spacing; } - - if (group_min > 0) + + if (group_min_size > 0) { - group_min += priv->spacing; - group_nat += priv->spacing; + group_min_size += priv->spacing; + group_nat_size += priv->spacing; } - - min_size += renderer_min_size; - nat_size += renderer_nat_size; - group_min += renderer_min_size; - group_nat += renderer_nat_size; + + min_size += renderer_min_size; + nat_size += renderer_nat_size; + group_min_size += renderer_min_size; + group_nat_size += renderer_nat_size; } else { - min_size = MAX (min_size, renderer_min_size); - nat_size = MAX (nat_size, renderer_nat_size); - group_min = MAX (group_min, renderer_min_size); - group_nat = MAX (group_nat, renderer_nat_size); + min_size = MAX (min_size, renderer_min_size); + nat_size = MAX (nat_size, renderer_nat_size); + group_min_size = MAX (group_min_size, renderer_min_size); + group_nat_size = MAX (group_nat_size, renderer_nat_size); } } - if (for_size < 0) + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (for_size < 0) + gtk_cell_area_box_context_push_group_width (context, group->id, group_min_size, group_nat_size); + else + gtk_cell_area_box_context_push_group_width_for_height (context, group->id, for_size, + group_min_size, group_nat_size); + } + else { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_cell_area_box_context_push_group_width (context, group->id, group_min, group_nat); + if (for_size < 0) + gtk_cell_area_box_context_push_group_height (context, group->id, group_min_size, group_nat_size); else - gtk_cell_area_box_context_push_group_height (context, group->id, group_min, group_nat); + gtk_cell_area_box_context_push_group_height_for_width (context, group->id, for_size, + group_min_size, group_nat_size); } } @@ -1519,6 +1529,17 @@ compute_size_for_opposing_orientation (GtkCellAreaBox *box, min_size = MAX (min_size, group_min); nat_size = MAX (nat_size, group_nat); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_cell_area_box_context_push_group_height_for_width (context, group_idx, for_size, + group_min, group_nat); + } + else + { + gtk_cell_area_box_context_push_group_width_for_height (context, group_idx, for_size, + group_min, group_nat); + } } *minimum_size = min_size; diff --git a/gtk/gtkcellareaboxcontext.c b/gtk/gtkcellareaboxcontext.c index 6ba773c0ee..caf23df071 100644 --- a/gtk/gtkcellareaboxcontext.c +++ b/gtk/gtkcellareaboxcontext.c @@ -32,15 +32,31 @@ static void gtk_cell_area_box_context_finalize (GOb /* 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); + +/* CachedSize management */ +typedef struct { + gint min_size; + gint nat_size; +} CachedSize; + typedef struct { gint min_size; gint nat_size; @@ -53,6 +69,10 @@ struct _GtkCellAreaBoxContextPrivate GArray *base_widths; GArray *base_heights; + /* Table of per height/width hash tables of per renderer CachedSizes */ + GHashTable *widths; + GHashTable *heights; + /* Allocation info for this context if any */ gint alloc_width; gint alloc_height; @@ -63,6 +83,12 @@ struct _GtkCellAreaBoxContextPrivate G_DEFINE_TYPE (GtkCellAreaBoxContext, gtk_cell_area_box_context, GTK_TYPE_CELL_AREA_CONTEXT); static void +free_cache_array (GArray *array) +{ + g_array_free (array, TRUE); +} + +static void gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context) { GtkCellAreaBoxContextPrivate *priv; @@ -75,6 +101,11 @@ gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context) priv->base_widths = g_array_new (FALSE, TRUE, sizeof (BaseSize)); priv->base_heights = g_array_new (FALSE, TRUE, sizeof (BaseSize)); + priv->widths = g_hash_table_new_full (g_direct_hash, g_direct_equal, + 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; @@ -91,11 +122,15 @@ gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class) 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; @@ -114,6 +149,8 @@ gtk_cell_area_box_context_finalize (GObject *object) g_array_free (priv->base_widths, TRUE); g_array_free (priv->base_heights, TRUE); + g_hash_table_destroy (priv->widths); + g_hash_table_destroy (priv->heights); g_free (priv->orientation_allocs); @@ -143,6 +180,23 @@ 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) +{ + 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); @@ -162,6 +216,23 @@ 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) +{ + 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)); + + 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); @@ -215,6 +286,55 @@ 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) +{ + 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) + { + 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); + } +} + +static void gtk_cell_area_box_context_sum_preferred_height (GtkCellAreaContext *context) { GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context); @@ -256,6 +376,55 @@ gtk_cell_area_box_context_sum_preferred_height (GtkCellAreaContext *context) gtk_cell_area_context_push_preferred_height (context, min_size, nat_size); } +static void +gtk_cell_area_box_context_sum_preferred_width_for_height (GtkCellAreaContext *context, + gint 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); + } +} + static GtkRequestedSize * gtk_cell_area_box_context_get_requests (GtkCellAreaBoxContext *box_context, GtkOrientation orientation, @@ -490,6 +659,36 @@ gtk_cell_area_box_context_push_group_width (GtkCellAreaBoxContext *box_context, } 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) +{ + GtkCellAreaBoxContextPrivate *priv; + GArray *group_array; + 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); + + 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); + + g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_array); + } + + size = &g_array_index (group_array, CachedSize, group_idx); + size->min_size = MAX (size->min_size, minimum_height); + size->nat_size = MAX (size->nat_size, natural_height); +} + +void gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context, gint group_idx, gint minimum_height, @@ -509,6 +708,36 @@ gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context, } 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) +{ + GtkCellAreaBoxContextPrivate *priv; + GArray *group_array; + 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); + + 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); + + g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_array); + } + + size = &g_array_index (group_array, CachedSize, group_idx); + size->min_size = MAX (size->min_size, minimum_width); + size->nat_size = MAX (size->nat_size, natural_width); +} + +void gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context, gint group_idx, gint *minimum_width, @@ -532,6 +761,43 @@ gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context, } 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) +{ + GtkCellAreaBoxContextPrivate *priv; + GArray *group_array; + + 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); + + group_array = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); + + if (group_array) + { + CachedSize *size = &g_array_index (group_array, CachedSize, group_idx); + + if (minimum_height) + *minimum_height = size->min_size; + + if (natural_height) + *natural_height = size->nat_size; + } + else + { + if (minimum_height) + *minimum_height = -1; + + if (natural_height) + *natural_height = -1; + } +} + +void gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context, gint group_idx, gint *minimum_height, @@ -554,6 +820,43 @@ gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context, *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) +{ + GtkCellAreaBoxContextPrivate *priv; + GArray *group_array; + + 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); + + group_array = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); + + if (group_array) + { + CachedSize *size = &g_array_index (group_array, CachedSize, group_idx); + + if (minimum_width) + *minimum_width = size->min_size; + + if (natural_width) + *natural_width = size->nat_size; + } + else + { + if (minimum_width) + *minimum_width = -1; + + if (natural_width) + *natural_width = -1; + } +} + GtkRequestedSize * gtk_cell_area_box_context_get_widths (GtkCellAreaBoxContext *box_context, gint *n_widths) diff --git a/gtk/gtkcellareaboxcontext.h b/gtk/gtkcellareaboxcontext.h index 29d9f80a7a..01f7dc6cba 100644 --- a/gtk/gtkcellareaboxcontext.h +++ b/gtk/gtkcellareaboxcontext.h @@ -72,20 +72,47 @@ void gtk_cell_area_box_context_push_group_width (GtkCellAreaBoxCo gint group_idx, gint minimum_width, gint natural_width); + +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); + void gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context, gint group_idx, gint minimum_height, gint natural_height); +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); + /* Fetch cell-group sizes */ void gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context, gint group_idx, gint *minimum_width, gint *natural_width); + +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); + void gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context, gint group_idx, gint *minimum_height, gint *natural_height); + +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); + GtkRequestedSize *gtk_cell_area_box_context_get_widths (GtkCellAreaBoxContext *box_context, gint *n_widths); GtkRequestedSize *gtk_cell_area_box_context_get_heights (GtkCellAreaBoxContext *box_context, diff --git a/gtk/gtkcellareacontext.c b/gtk/gtkcellareacontext.c index 1d0598f793..61646708db 100644 --- a/gtk/gtkcellareacontext.c +++ b/gtk/gtkcellareacontext.c @@ -28,6 +28,7 @@ #include "gtkprivate.h" /* GObjectClass */ +static void gtk_cell_area_context_finalize (GObject *object); static void gtk_cell_area_context_dispose (GObject *object); static void gtk_cell_area_context_get_property (GObject *object, guint prop_id, @@ -40,13 +41,26 @@ static void gtk_cell_area_context_set_property (GObject /* GtkCellAreaContextClass */ static void gtk_cell_area_context_real_flush_preferred_width (GtkCellAreaContext *context); +static void gtk_cell_area_context_real_flush_preferred_height_for_width (GtkCellAreaContext *context, + gint width); static void gtk_cell_area_context_real_flush_preferred_height (GtkCellAreaContext *context); +static void gtk_cell_area_context_real_flush_preferred_width_for_height (GtkCellAreaContext *context, + gint height); static void gtk_cell_area_context_real_flush_allocation (GtkCellAreaContext *context); static void gtk_cell_area_context_real_allocate_width (GtkCellAreaContext *context, gint width); static void gtk_cell_area_context_real_allocate_height (GtkCellAreaContext *context, gint height); +/* CachedSize management */ +typedef struct { + gint min_size; + gint nat_size; +} CachedSize; + +static CachedSize *cached_size_new (gint min_size, gint nat_size); +static void cached_size_free (CachedSize *size); + struct _GtkCellAreaContextPrivate { GtkCellArea *cell_area; @@ -57,6 +71,9 @@ struct _GtkCellAreaContextPrivate gint nat_height; gint alloc_width; gint alloc_height; + + GHashTable *widths; + GHashTable *heights; }; enum { @@ -68,6 +85,14 @@ enum { PROP_NAT_HEIGHT }; +enum { + SIGNAL_WIDTH_CHANGED, + SIGNAL_HEIGHT_CHANGED, + LAST_SIGNAL +}; + +static guint cell_area_context_signals[LAST_SIGNAL] = { 0 }; + G_DEFINE_TYPE (GtkCellAreaContext, gtk_cell_area_context, G_TYPE_OBJECT); static void @@ -84,6 +109,10 @@ gtk_cell_area_context_init (GtkCellAreaContext *context) priv->nat_width = -1; priv->min_height = -1; priv->nat_height = -1; + priv->widths = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)cached_size_free); + priv->heights = g_hash_table_new_full (g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)cached_size_free); } static void @@ -92,21 +121,46 @@ gtk_cell_area_context_class_init (GtkCellAreaContextClass *class) GObjectClass *object_class = G_OBJECT_CLASS (class); /* GObjectClass */ + object_class->finalize = gtk_cell_area_context_finalize; object_class->dispose = gtk_cell_area_context_dispose; object_class->get_property = gtk_cell_area_context_get_property; object_class->set_property = gtk_cell_area_context_set_property; /* GtkCellAreaContextClass */ class->flush_preferred_width = gtk_cell_area_context_real_flush_preferred_width; + class->flush_preferred_height_for_width = gtk_cell_area_context_real_flush_preferred_height_for_width; class->flush_preferred_height = gtk_cell_area_context_real_flush_preferred_height; + class->flush_preferred_width_for_height = gtk_cell_area_context_real_flush_preferred_width_for_height; class->flush_allocation = gtk_cell_area_context_real_flush_allocation; - class->sum_preferred_width = NULL; - class->sum_preferred_height = NULL; + class->sum_preferred_width = NULL; + class->sum_preferred_height_for_width = NULL; + class->sum_preferred_height = NULL; + class->sum_preferred_width_for_height = NULL; class->allocate_width = gtk_cell_area_context_real_allocate_width; class->allocate_height = gtk_cell_area_context_real_allocate_height; + cell_area_context_signals[SIGNAL_HEIGHT_CHANGED] = + g_signal_new (I_("height-changed"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, /* Class offset (just a notification, no class handler) */ + NULL, NULL, + _gtk_marshal_VOID__INT_INT_INT, + G_TYPE_NONE, 3, + G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + + cell_area_context_signals[SIGNAL_WIDTH_CHANGED] = + g_signal_new (I_("width-changed"), + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, /* Class offset (just a notification, no class handler) */ + NULL, NULL, + _gtk_marshal_VOID__INT_INT_INT, + G_TYPE_NONE, 3, + G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + g_object_class_install_property (object_class, PROP_CELL_AREA, g_param_spec_object ("area", @@ -158,10 +212,45 @@ gtk_cell_area_context_class_init (GtkCellAreaContextClass *class) g_type_class_add_private (object_class, sizeof (GtkCellAreaContextPrivate)); } + + +/************************************************************* + * Cached Sizes * + *************************************************************/ +static CachedSize * +cached_size_new (gint min_size, + gint nat_size) +{ + CachedSize *size = g_slice_new (CachedSize); + + size->min_size = min_size; + size->nat_size = nat_size; + + return size; +} + +static void +cached_size_free (CachedSize *size) +{ + g_slice_free (CachedSize, size); +} + /************************************************************* * GObjectClass * *************************************************************/ static void +gtk_cell_area_context_finalize (GObject *object) +{ + GtkCellAreaContext *context = GTK_CELL_AREA_CONTEXT (object); + GtkCellAreaContextPrivate *priv = context->priv; + + g_hash_table_destroy (priv->widths); + g_hash_table_destroy (priv->heights); + + G_OBJECT_CLASS (gtk_cell_area_context_parent_class)->finalize (object); +} + +static void gtk_cell_area_context_dispose (GObject *object) { GtkCellAreaContext *context = GTK_CELL_AREA_CONTEXT (object); @@ -247,6 +336,40 @@ gtk_cell_area_context_real_flush_preferred_width (GtkCellAreaContext *context) } static void +notify_invalid_height (gpointer width_ptr, + CachedSize *size, + GtkCellAreaContext *context) +{ + gint width = GPOINTER_TO_INT (width_ptr); + + /* Notify size invalidated */ + g_signal_emit (context, cell_area_context_signals[SIGNAL_HEIGHT_CHANGED], + 0, width, -1, -1); +} + +static void +gtk_cell_area_context_real_flush_preferred_height_for_width (GtkCellAreaContext *context, + gint width) +{ + GtkCellAreaContextPrivate *priv = context->priv; + + /* Flush all sizes for special -1 value */ + if (width < 0) + { + g_hash_table_foreach (priv->heights, (GHFunc)notify_invalid_height, context); + g_hash_table_remove_all (priv->heights); + } + else + { + g_hash_table_remove (priv->heights, GINT_TO_POINTER (width)); + + /* Notify size invalidated */ + g_signal_emit (context, cell_area_context_signals[SIGNAL_HEIGHT_CHANGED], + 0, width, -1, -1); + } +} + +static void gtk_cell_area_context_real_flush_preferred_height (GtkCellAreaContext *context) { GtkCellAreaContextPrivate *priv = context->priv; @@ -261,6 +384,40 @@ gtk_cell_area_context_real_flush_preferred_height (GtkCellAreaContext *context) } static void +notify_invalid_width (gpointer height_ptr, + CachedSize *size, + GtkCellAreaContext *context) +{ + gint height = GPOINTER_TO_INT (height_ptr); + + /* Notify size invalidated */ + g_signal_emit (context, cell_area_context_signals[SIGNAL_WIDTH_CHANGED], + 0, height, -1, -1); +} + +static void +gtk_cell_area_context_real_flush_preferred_width_for_height (GtkCellAreaContext *context, + gint height) +{ + GtkCellAreaContextPrivate *priv = context->priv; + + /* Flush all sizes for special -1 value */ + if (height < 0) + { + g_hash_table_foreach (priv->widths, (GHFunc)notify_invalid_width, context); + g_hash_table_remove_all (priv->widths); + } + else + { + g_hash_table_remove (priv->widths, GINT_TO_POINTER (height)); + + /* Notify size invalidated */ + g_signal_emit (context, cell_area_context_signals[SIGNAL_WIDTH_CHANGED], + 0, height, -1, -1); + } +} + +static void gtk_cell_area_context_real_flush_allocation (GtkCellAreaContext *context) { GtkCellAreaContextPrivate *priv = context->priv; @@ -309,7 +466,9 @@ gtk_cell_area_context_flush (GtkCellAreaContext *context) g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); gtk_cell_area_context_flush_preferred_width (context); + gtk_cell_area_context_flush_preferred_height_for_width (context, -1); gtk_cell_area_context_flush_preferred_height (context); + gtk_cell_area_context_flush_preferred_width_for_height (context, -1); gtk_cell_area_context_flush_allocation (context); } @@ -322,6 +481,15 @@ gtk_cell_area_context_flush_preferred_width (GtkCellAreaContext *context) } void +gtk_cell_area_context_flush_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width) +{ + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->flush_preferred_height_for_width (context, for_width); +} + +void gtk_cell_area_context_flush_preferred_height (GtkCellAreaContext *context) { g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); @@ -330,6 +498,15 @@ gtk_cell_area_context_flush_preferred_height (GtkCellAreaContext *context) } void +gtk_cell_area_context_flush_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height) +{ + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->flush_preferred_width_for_height (context, for_height); +} + +void gtk_cell_area_context_flush_allocation (GtkCellAreaContext *context) { g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); @@ -351,6 +528,20 @@ gtk_cell_area_context_sum_preferred_width (GtkCellAreaContext *context) } void +gtk_cell_area_context_sum_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width) +{ + GtkCellAreaContextClass *class; + + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + class = GTK_CELL_AREA_CONTEXT_GET_CLASS (context); + + if (class->sum_preferred_height_for_width) + class->sum_preferred_height_for_width (context, for_width); +} + +void gtk_cell_area_context_sum_preferred_height (GtkCellAreaContext *context) { GtkCellAreaContextClass *class; @@ -364,6 +555,20 @@ gtk_cell_area_context_sum_preferred_height (GtkCellAreaContext *context) } void +gtk_cell_area_context_sum_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height) +{ + GtkCellAreaContextClass *class; + + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + class = GTK_CELL_AREA_CONTEXT_GET_CLASS (context); + + if (class->sum_preferred_width_for_height) + class->sum_preferred_width_for_height (context, for_height); +} + +void gtk_cell_area_context_allocate_width (GtkCellAreaContext *context, gint width) { @@ -408,6 +613,39 @@ gtk_cell_area_context_get_preferred_width (GtkCellAreaContext *context, } void +gtk_cell_area_context_get_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width, + gint *minimum_height, + gint *natural_height) +{ + GtkCellAreaContextPrivate *priv; + CachedSize *size; + + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + priv = context->priv; + + size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); + + if (size) + { + if (minimum_height) + *minimum_height = size->min_size; + + if (natural_height) + *natural_height = size->nat_size; + } + else + { + if (minimum_height) + *minimum_height = -1; + + if (natural_height) + *natural_height = -1; + } +} + +void gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context, gint *minimum_height, gint *natural_height) @@ -426,6 +664,39 @@ gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context, } void +gtk_cell_area_context_get_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height, + gint *minimum_width, + gint *natural_width) +{ + GtkCellAreaContextPrivate *priv; + CachedSize *size; + + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + priv = context->priv; + + size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); + + if (size) + { + if (minimum_width) + *minimum_width = size->min_size; + + if (natural_width) + *natural_width = size->nat_size; + } + else + { + if (minimum_width) + *minimum_width = -1; + + if (natural_width) + *natural_width = -1; + } +} + +void gtk_cell_area_context_get_allocation (GtkCellAreaContext *context, gint *width, gint *height) @@ -474,6 +745,50 @@ gtk_cell_area_context_push_preferred_width (GtkCellAreaContext *context, } void +gtk_cell_area_context_push_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width, + gint minimum_height, + gint natural_height) +{ + GtkCellAreaContextPrivate *priv; + CachedSize *size; + gboolean changed = FALSE; + + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + priv = context->priv; + + size = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); + + if (!size) + { + size = cached_size_new (minimum_height, natural_height); + + g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), size); + + changed = TRUE; + } + else + { + if (minimum_height > size->min_size) + { + size->min_size = minimum_height; + changed = TRUE; + } + + if (natural_height > size->nat_size) + { + size->nat_size = natural_height; + changed = TRUE; + } + } + + if (changed) + g_signal_emit (context, cell_area_context_signals[SIGNAL_HEIGHT_CHANGED], 0, + for_width, size->min_size, size->nat_size); +} + +void gtk_cell_area_context_push_preferred_height (GtkCellAreaContext *context, gint minimum_height, gint natural_height) @@ -502,3 +817,47 @@ gtk_cell_area_context_push_preferred_height (GtkCellAreaContext *context, g_object_thaw_notify (G_OBJECT (context)); } + +void +gtk_cell_area_context_push_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height, + gint minimum_width, + gint natural_width) +{ + GtkCellAreaContextPrivate *priv; + CachedSize *size; + gboolean changed = FALSE; + + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + priv = context->priv; + + size = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); + + if (!size) + { + size = cached_size_new (minimum_width, natural_width); + + g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), size); + + changed = TRUE; + } + else + { + if (minimum_width > size->min_size) + { + size->min_size = minimum_width; + changed = TRUE; + } + + if (natural_width > size->nat_size) + { + size->nat_size = natural_width; + changed = TRUE; + } + } + + if (changed) + g_signal_emit (context, cell_area_context_signals[SIGNAL_WIDTH_CHANGED], 0, + for_height, size->min_size, size->nat_size); +} diff --git a/gtk/gtkcellareacontext.h b/gtk/gtkcellareacontext.h index 0782f78364..8e3621f313 100644 --- a/gtk/gtkcellareacontext.h +++ b/gtk/gtkcellareacontext.h @@ -55,14 +55,22 @@ struct _GtkCellAreaContextClass /* Subclasses can use this to flush their alignments/allocations */ void (* flush_preferred_width) (GtkCellAreaContext *context); + void (* flush_preferred_height_for_width) (GtkCellAreaContext *context, + gint width); void (* flush_preferred_height) (GtkCellAreaContext *context); + void (* flush_preferred_width_for_height) (GtkCellAreaContext *context, + gint height); void (* flush_allocation) (GtkCellAreaContext *context); /* These must be invoked after a series of requests before consulting * the context values, implementors use this to push the overall * requests while acconting for any internal alignments */ void (* sum_preferred_width) (GtkCellAreaContext *context); + void (* sum_preferred_height_for_width) (GtkCellAreaContext *context, + gint width); void (* sum_preferred_height) (GtkCellAreaContext *context); + void (* sum_preferred_width_for_height) (GtkCellAreaContext *context, + gint height); /* Store an allocation value for a GtkCellArea contextual to a range of * treemodel rows */ @@ -85,13 +93,21 @@ GtkCellArea *gtk_cell_area_context_get_area (GtkCellArea /* Apis for GtkCellArea clients to flush the cache */ void gtk_cell_area_context_flush (GtkCellAreaContext *context); void gtk_cell_area_context_flush_preferred_width (GtkCellAreaContext *context); +void gtk_cell_area_context_flush_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width); void gtk_cell_area_context_flush_preferred_height (GtkCellAreaContext *context); +void gtk_cell_area_context_flush_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height); void gtk_cell_area_context_flush_allocation (GtkCellAreaContext *context); /* Apis for GtkCellArea clients to sum up the results of a series of requests, this * call is required to reduce the processing while calculating the size of each row */ void gtk_cell_area_context_sum_preferred_width (GtkCellAreaContext *context); +void gtk_cell_area_context_sum_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width); void gtk_cell_area_context_sum_preferred_height (GtkCellAreaContext *context); +void gtk_cell_area_context_sum_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height); /* Apis to set an allocation size in one dimension or another, the subclass specific context * will store allocated positions/sizes for individual cells or groups of cells */ @@ -104,9 +120,17 @@ void gtk_cell_area_context_allocate_height (GtkCellArea void gtk_cell_area_context_get_preferred_width (GtkCellAreaContext *context, gint *minimum_width, gint *natural_width); +void gtk_cell_area_context_get_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width, + gint *minimum_height, + gint *natural_height); void gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context, gint *minimum_height, gint *natural_height); +void gtk_cell_area_context_get_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height, + gint *minimum_width, + gint *natural_width); void gtk_cell_area_context_get_allocation (GtkCellAreaContext *context, gint *width, gint *height); @@ -115,9 +139,17 @@ void gtk_cell_area_context_get_allocation (GtkCellArea void gtk_cell_area_context_push_preferred_width (GtkCellAreaContext *context, gint minimum_width, gint natural_width); +void gtk_cell_area_context_push_preferred_height_for_width (GtkCellAreaContext *context, + gint for_width, + gint minimum_height, + gint natural_height); void gtk_cell_area_context_push_preferred_height (GtkCellAreaContext *context, gint minimum_height, gint natural_height); +void gtk_cell_area_context_push_preferred_width_for_height (GtkCellAreaContext *context, + gint for_height, + gint minimum_width, + gint natural_width); G_END_DECLS |