From 0431dd67f82def7af57119b27bcc4dea0b7a2167 Mon Sep 17 00:00:00 2001 From: Tristan Van Berkom Date: Mon, 13 Dec 2010 00:18:00 +0900 Subject: Added apis to GtkCellArea for GtkIconView purposes. Added a few apis, - GtkCellAreaContext get_preferred_height_for_width & width for height apis and vfuncs, this lets the icon view request the collective (and aligned) height for width for a said row. - gtk_cell_area_copy_context() this creates a duplicate of an already created and requested context, this way the icon view uses a global context to request the widths of all rows and then makes a copy with all the stored alignments and uses a separate copy to calculate the height and alignments of each row separately. --- gtk/gtkcellarea.c | 40 ++++++++++++++ gtk/gtkcellarea.h | 4 ++ gtk/gtkcellareabox.c | 20 +++++++ gtk/gtkcellareaboxcontext.c | 127 +++++++++++++++++++++++++++++++++++++++----- gtk/gtkcellareaboxcontext.h | 4 ++ gtk/gtkcellareacontext.c | 60 +++++++++++++++++++++ gtk/gtkcellareacontext.h | 52 +++++++++++------- 7 files changed, 277 insertions(+), 30 deletions(-) diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c index c21fdcd013..59a1d015d4 100644 --- a/gtk/gtkcellarea.c +++ b/gtk/gtkcellarea.c @@ -1924,6 +1924,46 @@ gtk_cell_area_create_context (GtkCellArea *area) return NULL; } +/** + * gtk_cell_area_copy_context: + * @area: a #GtkCellArea + * @context: the #GtkCellAreaContext to copy + * + * This is sometimes needed for cases where rows need to share + * alignments in one orientation but may be separately grouped + * in the opposing orientation. + * + * For instance, #GtkIconView creates all icons (rows) to have + * the same width and the cells theirin to have the same + * horizontal alignments. However each row of icons may have + * a separate collective height. #GtkIconView uses this to + * request the heights of each row based on a context which + * was already used to request all the row widths that are + * to be displayed. + * + * Return value: (transfer full): a newly created #GtkCellAreaContext copy of @context. + * + * Since: 3.0 + */ +GtkCellAreaContext * +gtk_cell_area_copy_context (GtkCellArea *area, + GtkCellAreaContext *context) +{ + GtkCellAreaClass *class; + + g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL); + g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL); + + class = GTK_CELL_AREA_GET_CLASS (area); + + if (class->copy_context) + return class->copy_context (area, context); + + g_warning ("GtkCellAreaClass::copy_context not implemented for `%s'", + g_type_name (G_TYPE_FROM_INSTANCE (area))); + + return NULL; +} /** * gtk_cell_area_get_request_mode: diff --git a/gtk/gtkcellarea.h b/gtk/gtkcellarea.h index 8c54b053d2..61579221fb 100644 --- a/gtk/gtkcellarea.h +++ b/gtk/gtkcellarea.h @@ -202,6 +202,8 @@ struct _GtkCellAreaClass /* Geometry */ GtkCellAreaContext *(* create_context) (GtkCellArea *area); + GtkCellAreaContext *(* copy_context) (GtkCellArea *area, + GtkCellAreaContext *context); GtkSizeRequestMode (* get_request_mode) (GtkCellArea *area); void (* get_preferred_width) (GtkCellArea *area, GtkCellAreaContext *context, @@ -316,6 +318,8 @@ GtkCellRenderer *gtk_cell_area_get_cell_at_position (GtkCellArea /* Geometry */ GtkCellAreaContext *gtk_cell_area_create_context (GtkCellArea *area); +GtkCellAreaContext *gtk_cell_area_copy_context (GtkCellArea *area, + GtkCellAreaContext *context); GtkSizeRequestMode gtk_cell_area_get_request_mode (GtkCellArea *area); void gtk_cell_area_get_preferred_width (GtkCellArea *area, GtkCellAreaContext *context, diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c index 286c67096d..56a856bf6a 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -92,6 +92,8 @@ static void gtk_cell_area_box_get_cell_property (GtkCellArea GValue *value, GParamSpec *pspec); static GtkCellAreaContext *gtk_cell_area_box_create_context (GtkCellArea *area); +static GtkCellAreaContext *gtk_cell_area_box_copy_context (GtkCellArea *area, + GtkCellAreaContext *context); static GtkSizeRequestMode gtk_cell_area_box_get_request_mode (GtkCellArea *area); static void gtk_cell_area_box_get_preferred_width (GtkCellArea *area, GtkCellAreaContext *context, @@ -273,6 +275,7 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class) area_class->get_cell_property = gtk_cell_area_box_get_cell_property; area_class->create_context = gtk_cell_area_box_create_context; + area_class->copy_context = gtk_cell_area_box_copy_context; area_class->get_request_mode = gtk_cell_area_box_get_request_mode; area_class->get_preferred_width = gtk_cell_area_box_get_preferred_width; area_class->get_preferred_height = gtk_cell_area_box_get_preferred_height; @@ -1301,6 +1304,23 @@ gtk_cell_area_box_create_context (GtkCellArea *area) return context; } +static GtkCellAreaContext * +gtk_cell_area_box_copy_context (GtkCellArea *area, + GtkCellAreaContext *context) +{ + GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); + GtkCellAreaBoxPrivate *priv = box->priv; + GtkCellAreaContext *copy = + (GtkCellAreaContext *)gtk_cell_area_box_context_copy (GTK_CELL_AREA_BOX (area), + GTK_CELL_AREA_BOX_CONTEXT (context)); + + priv->contexts = g_slist_prepend (priv->contexts, copy); + + g_object_weak_ref (G_OBJECT (copy), (GWeakNotify)context_weak_notify, box); + + return copy; +} + static GtkSizeRequestMode gtk_cell_area_box_get_request_mode (GtkCellArea *area) { diff --git a/gtk/gtkcellareaboxcontext.c b/gtk/gtkcellareaboxcontext.c index cc4c0b4c48..fbf6ffea1d 100644 --- a/gtk/gtkcellareaboxcontext.c +++ b/gtk/gtkcellareaboxcontext.c @@ -35,10 +35,23 @@ static void gtk_cell_area_box_context_reset (GtkCellAreaCon 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, + 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); +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, @@ -190,8 +203,10 @@ gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class) /* GObjectClass */ 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->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; g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxContextPrivate)); } @@ -402,7 +417,10 @@ gtk_cell_area_box_context_allocate (GtkCellAreaContext *context, static void gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context, - GtkOrientation orientation) + GtkOrientation orientation, + gint for_size, + gint *minimum_size, + gint *natural_size) { GtkCellArea *area; GtkOrientation box_orientation; @@ -413,7 +431,7 @@ gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context, area = gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (context)); spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); box_orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area)); - array = get_array (context, orientation, -1); + array = get_array (context, orientation, for_size); for (i = 0; i < array->len; i++) { @@ -440,15 +458,100 @@ gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context, } } - if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_cell_area_context_push_preferred_width (GTK_CELL_AREA_CONTEXT (context), min_size, nat_size); - else - gtk_cell_area_context_push_preferred_height (GTK_CELL_AREA_CONTEXT (context), min_size, nat_size); + if (for_size < 0) + { + if (orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_cell_area_context_push_preferred_width (GTK_CELL_AREA_CONTEXT (context), min_size, nat_size); + else + gtk_cell_area_context_push_preferred_height (GTK_CELL_AREA_CONTEXT (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_get_preferred_height_for_width (GtkCellAreaContext *context, + gint width, + gint *minimum_height, + gint *natural_height) +{ + gtk_cell_area_box_context_sum (GTK_CELL_AREA_BOX_CONTEXT (context), GTK_ORIENTATION_VERTICAL, + width, minimum_height, natural_height); +} + +static void +gtk_cell_area_box_context_get_preferred_width_for_height (GtkCellAreaContext *context, + gint height, + gint *minimum_width, + gint *natural_width) +{ + gtk_cell_area_box_context_sum (GTK_CELL_AREA_BOX_CONTEXT (context), GTK_ORIENTATION_HORIZONTAL, + height, minimum_width, natural_width); } /************************************************************* * API * *************************************************************/ +static void +copy_size_array (GArray *src_array, + GArray *dest_array) +{ + gint i; + + for (i = 0; i < src_array->len; i++) + { + CachedSize *src = &g_array_index (src_array, CachedSize, i); + CachedSize *dest = &g_array_index (dest_array, CachedSize, i); + + memcpy (dest, src, sizeof (CachedSize)); + } +} + +static void +for_size_copy (gpointer key, + GArray *size_array, + GHashTable *dest_hash) +{ + GArray *new_array; + + new_array = g_array_new (FALSE, TRUE, sizeof (CachedSize)); + g_array_set_size (new_array, size_array->len); + + copy_size_array (size_array, new_array); + + g_hash_table_insert (dest_hash, key, new_array); +} + +GtkCellAreaBoxContext * +gtk_cell_area_box_context_copy (GtkCellAreaBox *box, + GtkCellAreaBoxContext *box_context) +{ + GtkCellAreaBoxContext *context; + + context = g_object_new (GTK_TYPE_CELL_AREA_BOX_CONTEXT, + "area", box, NULL); + + gtk_cell_area_box_init_groups (context, + box_context->priv->base_widths->len, + box_context->priv->expand); + + /* Copy all the arrays */ + copy_size_array (box_context->priv->base_widths, + context->priv->base_widths); + copy_size_array (box_context->priv->base_heights, + context->priv->base_heights); + + g_hash_table_foreach (box_context->priv->heights, + (GHFunc)for_size_copy, context->priv->heights); + g_hash_table_foreach (box_context->priv->widths, + (GHFunc)for_size_copy, context->priv->widths); + + return context; +} + void gtk_cell_area_box_init_groups (GtkCellAreaBoxContext *box_context, guint n_groups, @@ -500,7 +603,7 @@ gtk_cell_area_box_context_push_group_width (GtkCellAreaBoxContext *box_context, } if (grew) - gtk_cell_area_box_context_sum (box_context, GTK_ORIENTATION_HORIZONTAL); + gtk_cell_area_box_context_sum (box_context, GTK_ORIENTATION_HORIZONTAL, -1, NULL, NULL); } void @@ -559,7 +662,7 @@ gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context, } if (grew) - gtk_cell_area_box_context_sum (box_context, GTK_ORIENTATION_VERTICAL); + gtk_cell_area_box_context_sum (box_context, GTK_ORIENTATION_VERTICAL, -1, NULL, NULL); } void diff --git a/gtk/gtkcellareaboxcontext.h b/gtk/gtkcellareaboxcontext.h index 7800b0fdcb..1161d38b2f 100644 --- a/gtk/gtkcellareaboxcontext.h +++ b/gtk/gtkcellareaboxcontext.h @@ -62,6 +62,10 @@ struct _GtkCellAreaBoxContextClass GType gtk_cell_area_box_context_get_type (void) G_GNUC_CONST; +/* Create a duplicate of the context */ +GtkCellAreaBoxContext *gtk_cell_area_box_context_copy (GtkCellAreaBox *box, + GtkCellAreaBoxContext *box_context); + /* Initialize group array dimensions */ void gtk_cell_area_box_init_groups (GtkCellAreaBoxContext *box_context, guint n_groups, diff --git a/gtk/gtkcellareacontext.c b/gtk/gtkcellareacontext.c index 087b590401..f3c14b00dd 100644 --- a/gtk/gtkcellareacontext.c +++ b/gtk/gtkcellareacontext.c @@ -489,6 +489,66 @@ gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context, *natural_height = priv->nat_height; } +/** + * gtk_cell_area_context_get_preferred_height_for_width: + * @context: a #GtkCellAreaContext + * @width: a proposed width for allocation + * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL + * @natural_height: (out) (allow-none): location to store the natural height, or %NULL + * + * Gets the accumulative preferred height for @width for all rows which have been + * requested for the same said @width with this context. + * + * After gtk_cell_area_context_reset() is called and/or before ever requesting + * the size of a #GtkCellArea, the returned values are -1. + * + * Since: 3.0 + */ +void +gtk_cell_area_context_get_preferred_height_for_width (GtkCellAreaContext *context, + gint width, + gint *minimum_height, + gint *natural_height) +{ + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + if (GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_height_for_width) + GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_height_for_width (context, + width, + minimum_height, + natural_height); +} + +/** + * gtk_cell_area_context_get_preferred_width_for_height: + * @context: a #GtkCellAreaContext + * @height: a proposed height for allocation + * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL + * @natural_width: (out) (allow-none): location to store the natural width, or %NULL + * + * Gets the accumulative preferred width for @height for all rows which have + * been requested for the same said @height with this context. + * + * After gtk_cell_area_context_reset() is called and/or before ever requesting + * the size of a #GtkCellArea, the returned values are -1. + * + * Since: 3.0 + */ +void +gtk_cell_area_context_get_preferred_width_for_height (GtkCellAreaContext *context, + gint height, + gint *minimum_width, + gint *natural_width) +{ + g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context)); + + if (GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_width_for_height) + GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_width_for_height (context, + height, + minimum_width, + natural_width); +} + /** * gtk_cell_area_context_get_allocation: * @context: a #GtkCellAreaContext diff --git a/gtk/gtkcellareacontext.h b/gtk/gtkcellareacontext.h index 2731a73db4..d2b462cfce 100644 --- a/gtk/gtkcellareacontext.h +++ b/gtk/gtkcellareacontext.h @@ -65,10 +65,18 @@ struct _GtkCellAreaContextClass GObjectClass parent_class; /*< public >*/ - void (* allocate) (GtkCellAreaContext *context, - gint width, - gint height); - void (* reset) (GtkCellAreaContext *context); + void (* allocate) (GtkCellAreaContext *context, + gint width, + gint height); + void (* reset) (GtkCellAreaContext *context); + void (* get_preferred_height_for_width) (GtkCellAreaContext *context, + gint width, + gint *minimum_height, + gint *natural_height); + void (* get_preferred_width_for_height) (GtkCellAreaContext *context, + gint height, + gint *minimum_width, + gint *natural_width); /*< private >*/ /* Padding for future expansion */ @@ -81,22 +89,30 @@ struct _GtkCellAreaContextClass GType gtk_cell_area_context_get_type (void) G_GNUC_CONST; /* Main apis */ -GtkCellArea *gtk_cell_area_context_get_area (GtkCellAreaContext *context); -void gtk_cell_area_context_allocate (GtkCellAreaContext *context, - gint width, - gint height); -void gtk_cell_area_context_reset (GtkCellAreaContext *context); +GtkCellArea *gtk_cell_area_context_get_area (GtkCellAreaContext *context); +void gtk_cell_area_context_allocate (GtkCellAreaContext *context, + gint width, + gint height); +void gtk_cell_area_context_reset (GtkCellAreaContext *context); /* Apis for GtkCellArea clients to consult cached values for a series of GtkTreeModel rows */ -void gtk_cell_area_context_get_preferred_width (GtkCellAreaContext *context, - gint *minimum_width, - gint *natural_width); -void gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context, - gint *minimum_height, - gint *natural_height); -void gtk_cell_area_context_get_allocation (GtkCellAreaContext *context, - gint *width, - gint *height); +void gtk_cell_area_context_get_preferred_width (GtkCellAreaContext *context, + gint *minimum_width, + gint *natural_width); +void gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context, + gint *minimum_height, + gint *natural_height); +void gtk_cell_area_context_get_preferred_height_for_width (GtkCellAreaContext *context, + gint width, + gint *minimum_height, + gint *natural_height); +void gtk_cell_area_context_get_preferred_width_for_height (GtkCellAreaContext *context, + gint height, + gint *minimum_width, + gint *natural_width); +void gtk_cell_area_context_get_allocation (GtkCellAreaContext *context, + gint *width, + gint *height); /* Apis for GtkCellArea implementations to update cached values for multiple GtkTreeModel rows */ void gtk_cell_area_context_push_preferred_width (GtkCellAreaContext *context, -- cgit v1.2.1