From: Tristan Van Berkom Date: Sat, 30 Oct 2010 08:32:15 +0000 (+0900) Subject: Made GtkCellAreaBox:align-cells a packing property per cell X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=3b1c301a6627a0cf00cf0ab1f8b40198cae0bab5;p=~andy%2Fgtk Made GtkCellAreaBox:align-cells a packing property per cell Implemented all request apis on GtkCellAreaBox considering alignment of groups of cells (some cells can be aligned while others fill space smartly). --- diff --git a/gtk/gtkcellarea.h b/gtk/gtkcellarea.h index 5a9c770f7..9d4b16d5b 100644 --- a/gtk/gtkcellarea.h +++ b/gtk/gtkcellarea.h @@ -31,7 +31,6 @@ #include #include #include -#include G_BEGIN_DECLS @@ -45,6 +44,7 @@ G_BEGIN_DECLS typedef struct _GtkCellArea GtkCellArea; typedef struct _GtkCellAreaClass GtkCellAreaClass; typedef struct _GtkCellAreaPrivate GtkCellAreaPrivate; +typedef struct _GtkCellAreaIter GtkCellAreaIter; /** * GtkCellCallback: diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c index 511e8a056..f1a7cc1ea 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -97,20 +97,37 @@ static void gtk_cell_area_box_layout_reorder (GtkCellLayout gint position); -/* CellInfo metadata handling */ +/* CellInfo/CellGroup metadata handling */ typedef struct { GtkCellRenderer *renderer; - guint expand : 1; - guint pack : 1; + guint expand : 1; /* Whether the cell expands */ + guint pack : 1; /* Whether the cell is packed from the start or end */ + guint align : 1; /* Whether to align this cell's position with adjacent rows */ } CellInfo; -static CellInfo *cell_info_new (GtkCellRenderer *renderer, - gboolean expand, - GtkPackType pack); -static void cell_info_free (CellInfo *info); -static gint cell_info_find (CellInfo *info, - GtkCellRenderer *renderer); +typedef struct { + GList *cells; + + guint id : 16; + guint expand : 1; +} CellGroup; + +static CellInfo *cell_info_new (GtkCellRenderer *renderer, + GtkPackType pack, + gboolean expand, + gboolean align); +static void cell_info_free (CellInfo *info); +static gint cell_info_find (CellInfo *info, + GtkCellRenderer *renderer); + +static CellGroup *cell_group_new (guint id); +static void cell_group_free (CellGroup *group); + +static GList *list_consecutive_cells (GtkCellAreaBox *box); +static GList *construct_cell_groups (GtkCellAreaBox *box); +static gint count_expand_groups (GtkCellAreaBox *box); +static gint count_expand_cells (CellGroup *group); struct _GtkCellAreaBoxPrivate @@ -118,17 +135,15 @@ struct _GtkCellAreaBoxPrivate GtkOrientation orientation; GList *cells; + GList *groups; gint spacing; - - guint align_cells : 1; }; enum { PROP_0, PROP_ORIENTATION, - PROP_SPACING, - PROP_ALIGN_CELLS + PROP_SPACING }; G_DEFINE_TYPE_WITH_CODE (GtkCellAreaBox, gtk_cell_area_box, GTK_TYPE_CELL_AREA, @@ -136,6 +151,10 @@ G_DEFINE_TYPE_WITH_CODE (GtkCellAreaBox, gtk_cell_area_box, GTK_TYPE_CELL_AREA, gtk_cell_area_box_cell_layout_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)); +#define OPPOSITE_ORIENTATION(orientation) \ + ((orientation) == GTK_ORIENTATION_HORIZONTAL ? \ + GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL) + static void gtk_cell_area_box_init (GtkCellAreaBox *box) { @@ -148,8 +167,8 @@ gtk_cell_area_box_init (GtkCellAreaBox *box) priv->orientation = GTK_ORIENTATION_HORIZONTAL; priv->cells = NULL; + priv->groups = NULL; priv->spacing = 0; - priv->align_cells = TRUE; } static void @@ -190,32 +209,25 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class) 0, GTK_PARAM_READWRITE)); - g_object_class_install_property (object_class, - PROP_ALIGN_CELLS, - g_param_spec_boolean ("align-cells", - P_("Align Cells"), - P_("Whether cells should be aligned with those " - "rendered in adjacent rows"), - TRUE, - GTK_PARAM_READWRITE)); - g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxPrivate)); } /************************************************************* - * CellInfo Basics * + * CellInfo/CellGroup Basics * *************************************************************/ static CellInfo * cell_info_new (GtkCellRenderer *renderer, + GtkPackType pack, gboolean expand, - GtkPackType pack) + gboolean align) { CellInfo *info = g_slice_new (CellInfo); info->renderer = g_object_ref_sink (renderer); - info->expand = expand; info->pack = pack; + info->expand = expand; + info->align = align; return info; } @@ -235,6 +247,139 @@ cell_info_find (CellInfo *info, return (info->renderer == renderer) ? 0 : -1; } +static CellGroup * +cell_group_new (guint id) +{ + CellGroup *group = g_slice_new0 (CellGroup); + + group->id = id; + + return group; +} + +static void +cell_group_free (CellGroup *group) +{ + g_list_free (group->cells); + g_slice_free (CellGroup, group); +} + +static GList * +list_consecutive_cells (GtkCellAreaBox *box) +{ + GtkCellAreaBoxPrivate *priv = box->priv; + GList *l, *consecutive_cells = NULL, *pack_end_cells = NULL; + CellInfo *info; + + /* List cells in consecutive order taking their + * PACK_START/PACK_END options into account + */ + for (l = priv->cells; l; l = l->next) + { + info = l->data; + + if (info->pack == GTK_PACK_START) + consecutive_cells = g_list_prepend (consecutive_cells, info); + } + + for (l = priv->cells; l; l = l->next) + { + info = l->data; + + if (info->pack == GTK_PACK_END) + pack_end_cells = g_list_prepend (pack_end_cells, info); + } + + consecutive_cells = g_list_reverse (consecutive_cells); + consecutive_cells = g_list_concat (consecutive_cells, pack_end_cells); + + return consecutive_cells; +} + +static GList * +construct_cell_groups (GtkCellAreaBox *box) +{ + GtkCellAreaBoxPrivate *priv = box->priv; + CellGroup *group; + GList *cells, *l; + GList *groups = NULL; + guint id = 0; + + if (!priv->cells) + return NULL; + + cells = list_consecutive_cells (box); + group = cell_group_new (id++); + groups = g_list_prepend (groups, group); + + for (l = cells; l; l = l->next) + { + CellInfo *info = l->data; + + /* A new group starts with any aligned cell, the first group is implied */ + if (info->align && l != cells) + { + group = cell_group_new (id++); + groups = g_list_prepend (groups, group); + } + + group->cells = g_list_prepend (group->cells, info); + + /* A group expands if it contains any expand cells */ + if (info->expand) + group->expand = TRUE; + } + + g_list_free (cells); + + for (l = cells; l; l = l->next) + { + group = l->data; + group->cells = g_list_reverse (group->cells); + } + + return g_list_reverse (groups); +} + +static gint +count_expand_groups (GtkCellAreaBox *box) +{ + GtkCellAreaBoxPrivate *priv = box->priv; + GList *l; + gint expand_groups = 0; + + for (l = priv->groups; l; l = l->next) + { + CellGroup *group = l->data; + + if (group->expand) + expand_groups++; + } + + return expand_groups; +} + +static gint +count_expand_cells (CellGroup *group) +{ + GList *l; + gint expand_cells = 0; + + if (!group->expand) + return 0; + + for (l = group->cells; l; l = l->next) + { + CellInfo *info = l->data; + + if (info->expand) + expand_cells++; + } + + return expand_cells; +} + + /************************************************************* * GObjectClass * *************************************************************/ @@ -256,7 +401,17 @@ gtk_cell_area_box_set_property (GObject *object, const GValue *value, GParamSpec *pspec) { + GtkCellAreaBox *box = GTK_CELL_AREA_BOX (object); + switch (prop_id) + { + case PROP_SPACING: + gtk_cell_area_box_set_spacing (box, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -265,7 +420,17 @@ gtk_cell_area_box_get_property (GObject *object, GValue *value, GParamSpec *pspec) { + GtkCellAreaBox *box = GTK_CELL_AREA_BOX (object); + switch (prop_id) + { + case PROP_SPACING: + g_value_set_int (value, gtk_cell_area_box_get_spacing (box)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } /************************************************************* @@ -276,7 +441,7 @@ gtk_cell_area_box_add (GtkCellArea *area, GtkCellRenderer *renderer) { gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), - renderer, FALSE); + renderer, FALSE, TRUE); } static void @@ -297,6 +462,16 @@ gtk_cell_area_box_remove (GtkCellArea *area, cell_info_free (info); priv->cells = g_list_delete_link (priv->cells, node); + + /* Reconstruct cell groups + * XXX TODO: add a list of iters and weak_ref's on them, then + * flush the iters when we reconstruct groups, change spacing + * or child expand properties (i.e. notify size needs to be + * recalculated). + */ + g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL); + g_list_free (priv->groups); + priv->groups = construct_cell_groups (box); } else g_warning ("Trying to remove a cell renderer that is not present GtkCellAreaBox"); @@ -387,137 +562,279 @@ compute_size (GtkCellAreaBox *box, GtkOrientation orientation, GtkCellAreaBoxIter *iter, GtkWidget *widget, + gint for_size, gint *minimum_size, gint *natural_size) { GtkCellAreaBoxPrivate *priv = box->priv; + CellGroup *group; CellInfo *info; - GList *l; + GList *cell_list, *group_list; gint min_size = 0; gint nat_size = 0; - gboolean first_cell = TRUE; - for (l = priv->cells; l; l = l->next) + for (group_list = priv->groups; group_list; group_list = group_list->next) { - gint renderer_min_size, renderer_nat_size; - - info = l->data; + gint group_min_size = 0; + gint group_nat_size = 0; - get_renderer_size (info->renderer, orientation, widget, -1, - &renderer_min_size, &renderer_nat_size); + group = group_list->data; - /* If we're aligning the cells we need to cache the max results - * for all requests performed with the same iter. - */ - if (priv->align_cells) + for (cell_list = group->cells; cell_list; cell_list = cell_list->next) { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_cell_area_box_iter_push_cell_width (iter, info->renderer, - renderer_min_size, renderer_nat_size); + gint renderer_min_size, renderer_nat_size; + + info = cell_list->data; + + get_renderer_size (info->renderer, orientation, widget, for_size, + &renderer_min_size, &renderer_nat_size); + + if (orientation == priv->orientation) + { + if (min_size > 0) + { + min_size += priv->spacing; + nat_size += priv->spacing; + } + + if (group_min_size > 0) + { + group_min_size += priv->spacing; + group_nat_size += priv->spacing; + } + + min_size += renderer_min_size; + nat_size += renderer_nat_size; + group_min_size += renderer_min_size; + group_nat_size += renderer_nat_size; + } else - gtk_cell_area_box_iter_push_cell_height (iter, info->renderer, - renderer_min_size, 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 (orientation == priv->orientation) + if (orientation == GTK_ORIENTATION_HORIZONTAL) { - min_size += renderer_min_size; - nat_size += renderer_nat_size; - - if (!first_cell) - { - min_size += priv->spacing; - nat_size += priv->spacing; - } + if (for_size < 0) + gtk_cell_area_box_iter_push_group_width (iter, group->id, group_min_size, group_nat_size); + else + gtk_cell_area_box_iter_push_group_width_for_height (iter, group->id, for_size, + group_min_size, group_nat_size); } else { - min_size = MAX (min_size, renderer_min_size); - nat_size = MAX (nat_size, renderer_nat_size); + if (for_size < 0) + gtk_cell_area_box_iter_push_group_height (iter, group->id, group_min_size, group_nat_size); + else + gtk_cell_area_box_iter_push_group_height_for_width (iter, group->id, for_size, + group_min_size, group_nat_size); } - - if (first_cell) - first_cell = FALSE; } *minimum_size = min_size; *natural_size = nat_size; } +GtkRequestedSize * +get_group_sizes (CellGroup *group, + GtkOrientation orientation, + GtkWidget *widget, + gint *n_sizes) +{ + GtkRequestedSize *sizes; + GList *l; + gint i; + + *n_sizes = g_list_length (group->cells); + sizes = g_new (GtkRequestedSize, *n_sizes); + + for (l = group->cells, i = 0; l; l = l->next, i++) + { + CellInfo *info = l->data; + + sizes[i].data = info; + + get_renderer_size (info->renderer, + orientation, widget, -1, + &sizes[i].minimum_size, + &sizes[i].natural_size); + } + + return sizes; +} + static void -update_iter_aligned (GtkCellAreaBox *box, - GtkCellAreaBoxIter *iter, - gint for_size) +compute_group_size_for_opposing_orientation (GtkCellAreaBox *box, + CellGroup *group, + GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) { GtkCellAreaBoxPrivate *priv = box->priv; - CellInfo *info; - GList *l; - gint min_size = 0; - gint nat_size = 0; - gboolean first_cell = TRUE; - for (l = priv->cells; l; l = l->next) + /* Exception for single cell groups */ + if (!group->cells->next) { - gint aligned_min_size, aligned_nat_size; - - info = l->data; + CellInfo *info = group->cells->data; - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + get_renderer_size (info->renderer, + OPPOSITE_ORIENTATION (priv->orientation), + widget, for_size, minimum_size, natural_size); + } + else + { + GtkRequestedSize *orientation_sizes; + CellInfo *info; + gint n_sizes, i; + gint n_expand_cells = count_expand_cells (group); + gint avail_size = for_size; + gint extra_size, extra_extra; + gint min_size = 0, nat_size = 0; + + orientation_sizes = get_group_sizes (group, priv->orientation, widget, &n_sizes); + + /* First naturally allocate the cells in the group into the for_size */ + avail_size -= (n_sizes - 1) * priv->spacing; + for (i = 0; i < n_sizes; i++) + avail_size -= orientation_sizes[i].minimum_size; + + avail_size = gtk_distribute_natural_allocation (avail_size, n_sizes, orientation_sizes); + + /* Calculate/distribute expand for cells */ + if (n_expand_cells > 0) { - if (for_size < 0) - gtk_cell_area_box_iter_get_cell_width (iter, info->renderer, - &aligned_min_size, - &aligned_nat_size); - else - gtk_cell_area_box_iter_get_cell_width_for_height (iter, info->renderer, - for_size, - &aligned_min_size, - &aligned_nat_size); + extra_size = avail_size / n_expand_cells; + extra_extra = avail_size % n_expand_cells; } else - { - if (for_size < 0) - gtk_cell_area_box_iter_get_cell_height (iter, info->renderer, - &aligned_min_size, - &aligned_nat_size); - else - gtk_cell_area_box_iter_get_cell_height_for_width (iter, info->renderer, - for_size, - &aligned_min_size, - &aligned_nat_size); - } + extra_size = extra_extra = 0; - min_size += aligned_min_size; - nat_size += aligned_nat_size; - - if (!first_cell) + for (i = 0; i < n_sizes; i++) { - min_size += priv->spacing; - nat_size += priv->spacing; + gint cell_min, cell_nat; + + info = orientation_sizes[i].data; + + if (info->expand) + { + orientation_sizes[i].minimum_size += extra_size; + if (extra_extra) + { + orientation_sizes[i].minimum_size++; + extra_extra--; + } + } + + get_renderer_size (info->renderer, + OPPOSITE_ORIENTATION (priv->orientation), + widget, + orientation_sizes[i].minimum_size, + &cell_min, &cell_nat); + + min_size = MAX (min_size, cell_min); + nat_size = MAX (nat_size, cell_nat); } - - if (first_cell) - first_cell = FALSE; + + *minimum_size = min_size; + *natural_size = nat_size; + + g_free (orientation_sizes); } +} + +static void +compute_size_for_opposing_orientation (GtkCellAreaBox *box, + GtkCellAreaBoxIter *iter, + GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + GtkCellAreaBoxPrivate *priv = box->priv; + CellGroup *group; + GList *group_list; + GtkRequestedSize *orientation_sizes; + gint n_groups, n_expand_groups, i; + gint avail_size = for_size; + gint extra_size, extra_extra; + gint min_size = 0, nat_size = 0; + + n_expand_groups = count_expand_groups (box); if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + orientation_sizes = gtk_cell_area_box_iter_get_widths (iter, &n_groups); + else + orientation_sizes = gtk_cell_area_box_iter_get_heights (iter, &n_groups); + + /* First start by naturally allocating space among groups of cells */ + avail_size -= (n_groups - 1) * priv->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) { - if (for_size < 0) - gtk_cell_area_iter_push_preferred_width (GTK_CELL_AREA_ITER (iter), min_size, nat_size); - else - gtk_cell_area_iter_push_preferred_width_for_height (GTK_CELL_AREA_ITER (iter), - for_size, min_size, nat_size); + extra_size = avail_size / n_expand_groups; + extra_extra = avail_size % n_expand_groups; } else + extra_size = extra_extra = 0; + + /* Now we need to naturally allocate sizes for cells in each group + * and push the height-for-width for each group accordingly while accumulating + * the overall height-for-width for this row. + */ + for (group_list = priv->groups; group_list; group_list = group_list->next) { - if (for_size < 0) - gtk_cell_area_iter_push_preferred_height (GTK_CELL_AREA_ITER (iter), min_size, nat_size); + gint group_min, group_nat; + + group = group_list->data; + + if (group->expand) + { + orientation_sizes[group->id].minimum_size += extra_size; + if (extra_extra) + { + orientation_sizes[group->id].minimum_size++; + extra_extra--; + } + } + + /* Now we have the allocation for the group, request it's height-for-width */ + compute_group_size_for_opposing_orientation (box, group, widget, + orientation_sizes[group->id].minimum_size, + &group_min, &group_nat); + + min_size = MAX (min_size, group_min); + nat_size = MAX (nat_size, group_nat); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_cell_area_box_iter_push_group_height_for_width (iter, group->id, for_size, + group_min, group_nat); + } else - gtk_cell_area_iter_push_preferred_height_for_width (GTK_CELL_AREA_ITER (iter), - for_size, min_size, nat_size); + { + gtk_cell_area_box_iter_push_group_width_for_height (iter, group->id, for_size, + group_min, group_nat); + } } + + *minimum_size = min_size; + *natural_size = nat_size; + + g_free (orientation_sizes); } + + static void gtk_cell_area_box_get_preferred_width (GtkCellArea *area, GtkCellAreaIter *iter, @@ -527,25 +844,16 @@ gtk_cell_area_box_get_preferred_width (GtkCellArea *area, { GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); GtkCellAreaBoxIter *box_iter; - GtkCellAreaBoxPrivate *priv; gint min_width, nat_width; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter)); box_iter = GTK_CELL_AREA_BOX_ITER (iter); - priv = box->priv; - /* Compute the size of all renderers for current row data, possibly + /* Compute the size of all renderers for current row data, * bumping cell alignments in the iter along the way */ compute_size (box, GTK_ORIENTATION_HORIZONTAL, - box_iter, widget, &min_width, &nat_width); - - /* Update width of the iter based on aligned cell sizes if - * appropriate */ - if (priv->align_cells && priv->orientation == GTK_ORIENTATION_HORIZONTAL) - update_iter_aligned (box, box_iter, -1); - else - gtk_cell_area_iter_push_preferred_width (iter, min_width, nat_width); + box_iter, widget, -1, &min_width, &nat_width); if (minimum_width) *minimum_width = min_width; @@ -563,25 +871,16 @@ gtk_cell_area_box_get_preferred_height (GtkCellArea *area, { GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); GtkCellAreaBoxIter *box_iter; - GtkCellAreaBoxPrivate *priv; gint min_height, nat_height; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter)); box_iter = GTK_CELL_AREA_BOX_ITER (iter); - priv = box->priv; - /* Compute the size of all renderers for current row data, possibly + /* Compute the size of all renderers for current row data, * bumping cell alignments in the iter along the way */ compute_size (box, GTK_ORIENTATION_VERTICAL, - box_iter, widget, &min_height, &nat_height); - - /* Update width of the iter based on aligned cell sizes if - * appropriate */ - if (priv->align_cells && priv->orientation == GTK_ORIENTATION_VERTICAL) - update_iter_aligned (box, box_iter, -1); - else - gtk_cell_area_iter_push_preferred_height (iter, min_height, nat_height); + box_iter, widget, -1, &min_height, &nat_height); if (minimum_height) *minimum_height = min_height; @@ -590,61 +889,6 @@ gtk_cell_area_box_get_preferred_height (GtkCellArea *area, *natural_height = nat_height; } -static void -compute_size_for_orientation (GtkCellAreaBox *box, - GtkCellAreaBoxIter *iter, - GtkWidget *widget, - gint for_size, - gint *minimum_size, - gint *natural_size) -{ - GtkCellAreaBoxPrivate *priv = box->priv; - CellInfo *info; - GList *l; - gint min_size = 0; - gint nat_size = 0; - gboolean first_cell = TRUE; - - for (l = priv->cells; l; l = l->next) - { - gint renderer_min_size, renderer_nat_size; - - info = l->data; - - get_renderer_size (info->renderer, priv->orientation, widget, for_size, - &renderer_min_size, &renderer_nat_size); - - /* If we're aligning the cells we need to cache the max results - * for all requests performed with the same iter. - */ - if (priv->align_cells) - { - if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - gtk_cell_area_box_iter_push_cell_width_for_height (iter, info->renderer, for_size, - renderer_min_size, renderer_nat_size); - else - gtk_cell_area_box_iter_push_cell_height_for_width (iter, info->renderer, for_size, - renderer_min_size, renderer_nat_size); - } - - min_size += renderer_min_size; - nat_size += renderer_nat_size; - - if (!first_cell) - { - min_size += priv->spacing; - nat_size += priv->spacing; - } - - if (first_cell) - first_cell = FALSE; - } - - *minimum_size = min_size; - *natural_size = nat_size; -} - - static void gtk_cell_area_box_get_preferred_height_for_width (GtkCellArea *area, GtkCellAreaIter *iter, @@ -665,21 +909,15 @@ gtk_cell_area_box_get_preferred_height_for_width (GtkCellArea *area, if (priv->orientation == GTK_ORIENTATION_VERTICAL) { - /* Add up vertical requests of height for width and possibly push the overall + /* Add up vertical requests of height for width and push the overall * cached sizes for alignments */ - compute_size_for_orientation (box, box_iter, widget, width, &min_height, &nat_height); - - /* Update the overall cached height for width based on aligned cells if appropriate */ - if (priv->align_cells) - update_iter_aligned (box, box_iter, width); - else - gtk_cell_area_iter_push_preferred_height_for_width (GTK_CELL_AREA_ITER (iter), - width, min_height, nat_height); + compute_size (box, priv->orientation, box_iter, widget, width, &min_height, &nat_height); } else { - /* XXX Juice: virtually allocate cells into the for_width possibly using the + /* Juice: virtually allocate cells into the for_width using the * alignments and then return the overall height for that width, and cache it */ + compute_size_for_opposing_orientation (box, box_iter, widget, width, &min_height, &nat_height); } if (minimum_height) @@ -709,21 +947,15 @@ gtk_cell_area_box_get_preferred_width_for_height (GtkCellArea *area, if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { - /* Add up vertical requests of height for width and possibly push the overall + /* Add up horizontal requests of width for height and push the overall * cached sizes for alignments */ - compute_size_for_orientation (box, box_iter, widget, height, &min_width, &nat_width); - - /* Update the overall cached height for width based on aligned cells if appropriate */ - if (priv->align_cells) - update_iter_aligned (box, box_iter, height); - else - gtk_cell_area_iter_push_preferred_height_for_width (GTK_CELL_AREA_ITER (iter), - height, min_width, nat_width); + compute_size (box, priv->orientation, box_iter, widget, height, &min_width, &nat_width); } else { - /* XXX Juice: virtually allocate cells into the for_width possibly using the - * alignments and then return the overall height for that width, and cache it */ + /* Juice: horizontally allocate cells into the for_height using the + * alignments and then return the overall width for that height, and cache it */ + compute_size_for_opposing_orientation (box, box_iter, widget, height, &min_width, &nat_width); } if (minimum_width) @@ -750,7 +982,7 @@ gtk_cell_area_box_layout_pack_start (GtkCellLayout *cell_layout, GtkCellRenderer *renderer, gboolean expand) { - gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand); + gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, TRUE); } static void @@ -758,7 +990,7 @@ gtk_cell_area_box_layout_pack_end (GtkCellLayout *cell_layout, GtkCellRenderer *renderer, gboolean expand) { - gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand); + gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, TRUE); } static void @@ -795,7 +1027,8 @@ gtk_cell_area_box_new (void) void gtk_cell_area_box_pack_start (GtkCellAreaBox *box, GtkCellRenderer *renderer, - gboolean expand) + gboolean expand, + gboolean align) { GtkCellAreaBoxPrivate *priv; CellInfo *info; @@ -812,15 +1045,21 @@ gtk_cell_area_box_pack_start (GtkCellAreaBox *box, return; } - info = cell_info_new (renderer, expand, GTK_PACK_START); + info = cell_info_new (renderer, GTK_PACK_START, expand, align); priv->cells = g_list_append (priv->cells, info); + + /* Reconstruct cell groups (TODO, notify created iters that size needs renegotiation) */ + g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL); + g_list_free (priv->groups); + priv->groups = construct_cell_groups (box); } void gtk_cell_area_box_pack_end (GtkCellAreaBox *box, GtkCellRenderer *renderer, - gboolean expand) + gboolean expand, + gboolean align) { GtkCellAreaBoxPrivate *priv; CellInfo *info; @@ -837,9 +1076,14 @@ gtk_cell_area_box_pack_end (GtkCellAreaBox *box, return; } - info = cell_info_new (renderer, expand, GTK_PACK_END); + info = cell_info_new (renderer, GTK_PACK_END, expand, align); priv->cells = g_list_append (priv->cells, info); + + /* Reconstruct cell groups (TODO, notify created iters that size needs renegotiation) */ + g_list_foreach (priv->groups, (GFunc)cell_group_free, NULL); + g_list_free (priv->groups); + priv->groups = construct_cell_groups (box); } gint @@ -864,32 +1108,7 @@ gtk_cell_area_box_set_spacing (GtkCellAreaBox *box, { priv->spacing = spacing; + /* TODO, notify created iters that size needs renegotiation */ g_object_notify (G_OBJECT (box), "spacing"); } } - -gboolean -gtk_cell_area_box_get_align_cells (GtkCellAreaBox *box) -{ - g_return_val_if_fail (GTK_IS_CELL_AREA_BOX (box), FALSE); - - return box->priv->align_cells; -} - -void -gtk_cell_area_box_set_align_cells (GtkCellAreaBox *box, - gboolean align) -{ - GtkCellAreaBoxPrivate *priv; - - g_return_if_fail (GTK_IS_CELL_AREA_BOX (box)); - - priv = box->priv; - - if (priv->align_cells != align) - { - priv->align_cells = align; - - g_object_notify (G_OBJECT (box), "align-cells"); - } -} diff --git a/gtk/gtkcellareabox.h b/gtk/gtkcellareabox.h index ee29ffe8a..0a0c05222 100644 --- a/gtk/gtkcellareabox.h +++ b/gtk/gtkcellareabox.h @@ -67,16 +67,15 @@ GType gtk_cell_area_box_get_type (void) G_GNUC_CONST; GtkCellArea *gtk_cell_area_box_new (void); void gtk_cell_area_box_pack_start (GtkCellAreaBox *box, GtkCellRenderer *renderer, - gboolean expand); + gboolean expand, + gboolean align); void gtk_cell_area_box_pack_end (GtkCellAreaBox *box, GtkCellRenderer *renderer, - gboolean expand); + gboolean expand, + gboolean align); gint gtk_cell_area_box_get_spacing (GtkCellAreaBox *box); void gtk_cell_area_box_set_spacing (GtkCellAreaBox *box, gint spacing); -gboolean gtk_cell_area_box_get_align_cells (GtkCellAreaBox *box); -void gtk_cell_area_box_set_align_cells (GtkCellAreaBox *box, - gboolean align); G_END_DECLS diff --git a/gtk/gtkcellareaboxiter.c b/gtk/gtkcellareaboxiter.c index 791d6b404..9f3474d84 100644 --- a/gtk/gtkcellareaboxiter.c +++ b/gtk/gtkcellareaboxiter.c @@ -23,12 +23,19 @@ #include "config.h" #include "gtkintl.h" +#include "gtkcellareabox.h" #include "gtkcellareaboxiter.h" /* GObjectClass */ static void gtk_cell_area_box_iter_finalize (GObject *object); /* GtkCellAreaIterClass */ +static void gtk_cell_area_box_iter_sum_preferred_width (GtkCellAreaIter *iter); +static void gtk_cell_area_box_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter, + gint width); +static void gtk_cell_area_box_iter_sum_preferred_height (GtkCellAreaIter *iter); +static void gtk_cell_area_box_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter, + gint height); static void gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter); static void gtk_cell_area_box_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter, gint width); @@ -88,6 +95,11 @@ gtk_cell_area_box_iter_class_init (GtkCellAreaBoxIterClass *class) /* GObjectClass */ object_class->finalize = gtk_cell_area_box_iter_finalize; + iter_class->sum_preferred_width = gtk_cell_area_box_iter_sum_preferred_width; + iter_class->sum_preferred_height_for_width = gtk_cell_area_box_iter_sum_preferred_height_for_width; + iter_class->sum_preferred_height = gtk_cell_area_box_iter_sum_preferred_height; + iter_class->sum_preferred_width_for_height = gtk_cell_area_box_iter_sum_preferred_width_for_height; + iter_class->flush_preferred_width = gtk_cell_area_box_iter_flush_preferred_width; iter_class->flush_preferred_height_for_width = gtk_cell_area_box_iter_flush_preferred_height_for_width; iter_class->flush_preferred_height = gtk_cell_area_box_iter_flush_preferred_height; @@ -137,6 +149,102 @@ gtk_cell_area_box_iter_finalize (GObject *object) /************************************************************* * GtkCellAreaIterClass * *************************************************************/ +typedef struct { + gint min_size; + gint nat_size; + gint spacing; +} AccumData; + +static void +sum_base_size (gpointer group_id, + CachedSize *size, + AccumData *accum) +{ + if (accum->min_size > 0) + { + accum->min_size += accum->spacing; + accum->nat_size += accum->spacing; + } + + accum->min_size += size->min_size; + accum->nat_size += size->nat_size; +} + +static void +sum_for_size (gpointer group_id, + CachedSize *size, + AccumData *accum) +{ + accum->min_size = MAX (accum->min_size, size->min_size); + accum->nat_size = MAX (accum->nat_size, size->nat_size); +} + +static void +gtk_cell_area_box_iter_sum_preferred_width (GtkCellAreaIter *iter) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + GtkCellArea *area; + AccumData accum = { 0, }; + + area = gtk_cell_area_iter_get_area (iter); + accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); + + g_hash_table_foreach (priv->base_widths, (GHFunc)sum_base_size, &accum); + gtk_cell_area_iter_push_preferred_width (iter, accum.min_size, accum.nat_size); +} + +static void +gtk_cell_area_box_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter, + gint width) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + GHashTable *group_table; + AccumData accum = { 0, }; + + group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (width)); + + if (group_table) + { + g_hash_table_foreach (priv->base_widths, (GHFunc)sum_for_size, &accum); + gtk_cell_area_iter_push_preferred_height_for_width (iter, width, accum.min_size, accum.nat_size); + } +} + +static void +gtk_cell_area_box_iter_sum_preferred_height (GtkCellAreaIter *iter) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + GtkCellArea *area; + AccumData accum = { 0, }; + + area = gtk_cell_area_iter_get_area (iter); + accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area)); + + g_hash_table_foreach (priv->base_heights, (GHFunc)sum_base_size, &accum); + gtk_cell_area_iter_push_preferred_width (iter, accum.min_size, accum.nat_size); +} + +static void +gtk_cell_area_box_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter, + gint height) +{ + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GtkCellAreaBoxIterPrivate *priv = box_iter->priv; + GHashTable *group_table; + AccumData accum = { 0, }; + + group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (height)); + + if (group_table) + { + g_hash_table_foreach (priv->base_widths, (GHFunc)sum_for_size, &accum); + gtk_cell_area_iter_push_preferred_width_for_height (iter, height, accum.min_size, accum.nat_size); + } +} + static void gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter) { @@ -200,24 +308,23 @@ gtk_cell_area_box_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter, *************************************************************/ void -gtk_cell_area_box_iter_push_cell_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint minimum_width, - gint natural_width) +gtk_cell_area_box_iter_push_group_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint minimum_width, + gint natural_width) { GtkCellAreaBoxIterPrivate *priv; CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); priv = box_iter->priv; - size = g_hash_table_lookup (priv->base_widths, renderer); + size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id)); if (!size) { size = cached_size_new (minimum_width, natural_width); - g_hash_table_insert (priv->base_widths, renderer, size); + g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size); } else { @@ -227,36 +334,35 @@ gtk_cell_area_box_iter_push_cell_width (GtkCellAreaBoxIter *box_iter, } void -gtk_cell_area_box_iter_push_cell_height_for_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_width, - gint minimum_height, - gint natural_height) +gtk_cell_area_box_iter_push_group_height_for_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_width, + gint minimum_height, + gint natural_height) { GtkCellAreaBoxIterPrivate *priv; - GHashTable *cell_table; + GHashTable *group_table; CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - priv = box_iter->priv; - cell_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); + priv = box_iter->priv; + group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); - if (!cell_table) + if (!group_table) { - cell_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, + group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)cached_size_free); - g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), cell_table); + g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_table); } - size = g_hash_table_lookup (cell_table, renderer); + size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id)); if (!size) { size = cached_size_new (minimum_height, natural_height); - g_hash_table_insert (cell_table, renderer, size); + g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size); } else { @@ -266,24 +372,23 @@ gtk_cell_area_box_iter_push_cell_height_for_width (GtkCellAreaBoxIter *box_iter } void -gtk_cell_area_box_iter_push_cell_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint minimum_height, - gint natural_height) +gtk_cell_area_box_iter_push_group_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint minimum_height, + gint natural_height) { GtkCellAreaBoxIterPrivate *priv; CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); priv = box_iter->priv; - size = g_hash_table_lookup (priv->base_heights, renderer); + size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id)); if (!size) { size = cached_size_new (minimum_height, natural_height); - g_hash_table_insert (priv->base_widths, renderer, size); + g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size); } else { @@ -293,36 +398,35 @@ gtk_cell_area_box_iter_push_cell_height (GtkCellAreaBoxIter *box_iter, } void -gtk_cell_area_box_iter_push_cell_width_for_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_height, - gint minimum_width, - gint natural_width) +gtk_cell_area_box_iter_push_group_width_for_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_height, + gint minimum_width, + gint natural_width) { GtkCellAreaBoxIterPrivate *priv; - GHashTable *cell_table; + GHashTable *group_table; CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - priv = box_iter->priv; - cell_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); + priv = box_iter->priv; + group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); - if (!cell_table) + if (!group_table) { - cell_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, + group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)cached_size_free); - g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), cell_table); + g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_table); } - size = g_hash_table_lookup (cell_table, renderer); + size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id)); if (!size) { size = cached_size_new (minimum_width, natural_width); - g_hash_table_insert (cell_table, renderer, size); + g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size); } else { @@ -332,19 +436,18 @@ gtk_cell_area_box_iter_push_cell_width_for_height (GtkCellAreaBoxIter *box_iter, } void -gtk_cell_area_box_iter_get_cell_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint *minimum_width, - gint *natural_width) +gtk_cell_area_box_iter_get_group_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint *minimum_width, + gint *natural_width) { GtkCellAreaBoxIterPrivate *priv; CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); priv = box_iter->priv; - size = g_hash_table_lookup (priv->base_widths, renderer); + size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id)); if (size) { @@ -365,24 +468,23 @@ gtk_cell_area_box_iter_get_cell_width (GtkCellAreaBoxIter *box_iter, } void -gtk_cell_area_box_iter_get_cell_height_for_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_width, - gint *minimum_height, - gint *natural_height) +gtk_cell_area_box_iter_get_group_height_for_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_width, + gint *minimum_height, + gint *natural_height) { GtkCellAreaBoxIterPrivate *priv; - GHashTable *cell_table; + GHashTable *group_table; CachedSize *size = NULL; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - priv = box_iter->priv; - cell_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); + priv = box_iter->priv; + group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width)); - if (cell_table) - size = g_hash_table_lookup (cell_table, renderer); + if (group_table) + size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id)); if (size) { @@ -403,19 +505,18 @@ gtk_cell_area_box_iter_get_cell_height_for_width (GtkCellAreaBoxIter *box_iter, } void -gtk_cell_area_box_iter_get_cell_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint *minimum_height, - gint *natural_height) +gtk_cell_area_box_iter_get_group_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint *minimum_height, + gint *natural_height) { GtkCellAreaBoxIterPrivate *priv; CachedSize *size; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); priv = box_iter->priv; - size = g_hash_table_lookup (priv->base_heights, renderer); + size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id)); if (size) { @@ -436,24 +537,23 @@ gtk_cell_area_box_iter_get_cell_height (GtkCellAreaBoxIter *box_iter, } void -gtk_cell_area_box_iter_get_cell_width_for_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_height, - gint *minimum_width, - gint *natural_width) +gtk_cell_area_box_iter_get_group_width_for_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_height, + gint *minimum_width, + gint *natural_width) { GtkCellAreaBoxIterPrivate *priv; - GHashTable *cell_table; + GHashTable *group_table; CachedSize *size = NULL; g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter)); - g_return_if_fail (GTK_IS_CELL_RENDERER (renderer)); - priv = box_iter->priv; - cell_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); + priv = box_iter->priv; + group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height)); - if (cell_table) - size = g_hash_table_lookup (cell_table, renderer); + if (group_table) + size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id)); if (size) { @@ -472,3 +572,53 @@ gtk_cell_area_box_iter_get_cell_width_for_height (GtkCellAreaBoxIter *box_iter, *natural_width = -1; } } + +static void +fill_requested_sizes (gpointer group_id_ptr, + CachedSize *cached_size, + GtkRequestedSize *requested) +{ + gint group_id = GPOINTER_TO_INT (group_id_ptr); + + requested[group_id].data = group_id_ptr; + requested[group_id].minimum_size = cached_size->min_size; + requested[group_id].natural_size = cached_size->nat_size; +} + +GtkRequestedSize * +gtk_cell_area_box_iter_get_widths (GtkCellAreaBoxIter *box_iter, + gint *n_widths) +{ + GtkCellAreaBoxIterPrivate *priv; + GtkRequestedSize *widths; + + g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL); + + priv = box_iter->priv; + + *n_widths = g_hash_table_size (priv->widths); + widths = g_new (GtkRequestedSize, *n_widths); + + g_hash_table_foreach (priv->widths, (GHFunc)fill_requested_sizes, widths); + + return widths; +} + +GtkRequestedSize * +gtk_cell_area_box_iter_get_heights (GtkCellAreaBoxIter *box_iter, + gint *n_heights) +{ + GtkCellAreaBoxIterPrivate *priv; + GtkRequestedSize *heights; + + g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL); + + priv = box_iter->priv; + + *n_heights = g_hash_table_size (priv->heights); + heights = g_new (GtkRequestedSize, *n_heights); + + g_hash_table_foreach (priv->heights, (GHFunc)fill_requested_sizes, heights); + + return heights; +} diff --git a/gtk/gtkcellareaboxiter.h b/gtk/gtkcellareaboxiter.h index 0781c28d7..ada15a766 100644 --- a/gtk/gtkcellareaboxiter.h +++ b/gtk/gtkcellareaboxiter.h @@ -30,6 +30,7 @@ #include #include +#include G_BEGIN_DECLS @@ -57,54 +58,59 @@ struct _GtkCellAreaBoxIterClass }; -GType gtk_cell_area_box_iter_get_type (void) G_GNUC_CONST; - - -/* Update cell alignments */ -void gtk_cell_area_box_iter_push_cell_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint minimum_width, - gint natural_width); - -void gtk_cell_area_box_iter_push_cell_height_for_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_width, - gint minimum_height, - gint natural_height); - -void gtk_cell_area_box_iter_push_cell_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint minimum_height, - gint natural_height); - -void gtk_cell_area_box_iter_push_cell_width_for_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_height, - gint minimum_width, - gint natural_width); - -/* Fetch cell alignments */ -void gtk_cell_area_box_iter_get_cell_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint *minimum_width, - gint *natural_width); - -void gtk_cell_area_box_iter_get_cell_height_for_width (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_width, - gint *minimum_height, - gint *natural_height); - -void gtk_cell_area_box_iter_get_cell_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint *minimum_height, - gint *natural_height); - -void gtk_cell_area_box_iter_get_cell_width_for_height (GtkCellAreaBoxIter *box_iter, - GtkCellRenderer *renderer, - gint for_height, - gint *minimum_width, - gint *natural_width); +GType gtk_cell_area_box_iter_get_type (void) G_GNUC_CONST; + + +/* Update cell-group sizes */ +void gtk_cell_area_box_iter_push_group_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint minimum_width, + gint natural_width); + +void gtk_cell_area_box_iter_push_group_height_for_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_width, + gint minimum_height, + gint natural_height); + +void gtk_cell_area_box_iter_push_group_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint minimum_height, + gint natural_height); + +void gtk_cell_area_box_iter_push_group_width_for_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_height, + gint minimum_width, + gint natural_width); + +/* Fetch cell-group sizes */ +void gtk_cell_area_box_iter_get_group_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint *minimum_width, + gint *natural_width); + +void gtk_cell_area_box_iter_get_group_height_for_width (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_width, + gint *minimum_height, + gint *natural_height); + +void gtk_cell_area_box_iter_get_group_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint *minimum_height, + gint *natural_height); + +void gtk_cell_area_box_iter_get_group_width_for_height (GtkCellAreaBoxIter *box_iter, + gint group_id, + gint for_height, + gint *minimum_width, + gint *natural_width); + +GtkRequestedSize *gtk_cell_area_box_iter_get_widths (GtkCellAreaBoxIter *box_iter, + gint *n_widths); +GtkRequestedSize *gtk_cell_area_box_iter_get_heights (GtkCellAreaBoxIter *box_iter, + gint *n_heights); G_END_DECLS diff --git a/gtk/gtkcellareaiter.c b/gtk/gtkcellareaiter.c index d4de66b23..4257f4b75 100644 --- a/gtk/gtkcellareaiter.c +++ b/gtk/gtkcellareaiter.c @@ -25,13 +25,19 @@ #include "gtkintl.h" #include "gtkmarshalers.h" #include "gtkcellareaiter.h" +#include "gtkprivate.h" /* GObjectClass */ static void gtk_cell_area_iter_finalize (GObject *object); +static void gtk_cell_area_iter_dispose (GObject *object); static void gtk_cell_area_iter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static void gtk_cell_area_iter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); /* GtkCellAreaIterClass */ static void gtk_cell_area_iter_real_flush_preferred_width (GtkCellAreaIter *iter); @@ -52,17 +58,20 @@ static void cached_size_free (CachedSize *size); struct _GtkCellAreaIterPrivate { - gint min_width; - gint nat_width; - gint min_height; - gint nat_height; + GtkCellArea *cell_area; + + gint min_width; + gint nat_width; + gint min_height; + gint nat_height; - GHashTable *widths; - GHashTable *heights; + GHashTable *widths; + GHashTable *heights; }; enum { PROP_0, + PROP_CELL_AREA, PROP_MIN_WIDTH, PROP_NAT_WIDTH, PROP_MIN_HEIGHT, @@ -106,7 +115,9 @@ gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class) /* GObjectClass */ object_class->finalize = gtk_cell_area_iter_finalize; + object_class->dispose = gtk_cell_area_iter_dispose; object_class->get_property = gtk_cell_area_iter_get_property; + object_class->set_property = gtk_cell_area_iter_set_property; class->flush_preferred_width = gtk_cell_area_iter_real_flush_preferred_width; class->flush_preferred_height_for_width = gtk_cell_area_iter_real_flush_preferred_height_for_width; @@ -133,6 +144,14 @@ gtk_cell_area_iter_class_init (GtkCellAreaIterClass *class) 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", + P_("Area"), + P_("The Cell Area this iter was created for"), + GTK_TYPE_CELL_AREA, + GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_MIN_WIDTH, g_param_spec_int ("minimum-width", @@ -214,6 +233,42 @@ gtk_cell_area_iter_finalize (GObject *object) G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->finalize (object); } +static void +gtk_cell_area_iter_dispose (GObject *object) +{ + GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object); + GtkCellAreaIterPrivate *priv = iter->priv; + + if (priv->cell_area) + { + g_object_unref (priv->cell_area); + + priv->cell_area = NULL; + } + + G_OBJECT_CLASS (gtk_cell_area_iter_parent_class)->dispose (object); +} + +static void +gtk_cell_area_iter_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkCellAreaIter *iter = GTK_CELL_AREA_ITER (object); + GtkCellAreaIterPrivate *priv = iter->priv; + + switch (prop_id) + { + case PROP_CELL_AREA: + priv->cell_area = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void gtk_cell_area_iter_get_property (GObject *object, guint prop_id, @@ -225,6 +280,9 @@ gtk_cell_area_iter_get_property (GObject *object, switch (prop_id) { + case PROP_CELL_AREA: + g_value_set_object (value, priv->cell_area); + break; case PROP_MIN_WIDTH: g_value_set_int (value, priv->min_width); break; @@ -307,6 +365,17 @@ gtk_cell_area_iter_real_flush_preferred_width_for_height (GtkCellAreaIter *iter, /************************************************************* * API * *************************************************************/ +GtkCellArea * +gtk_cell_area_iter_get_area (GtkCellAreaIter *iter) +{ + GtkCellAreaIterPrivate *priv; + + g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), NULL); + + priv = iter->priv; + + return priv->cell_area; +} void gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter, @@ -410,6 +479,106 @@ gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter, } } +void +gtk_cell_area_iter_sum_preferred_width (GtkCellAreaIter *iter) +{ + GtkCellAreaIterClass *class; + + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + class = GTK_CELL_AREA_ITER_GET_CLASS (iter); + + if (class->sum_preferred_width) + class->sum_preferred_width (iter); +} + +void +gtk_cell_area_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter, + gint for_width) +{ + GtkCellAreaIterClass *class; + + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + class = GTK_CELL_AREA_ITER_GET_CLASS (iter); + + if (class->sum_preferred_height_for_width) + class->sum_preferred_height_for_width (iter, for_width); +} + +void +gtk_cell_area_iter_sum_preferred_height (GtkCellAreaIter *iter) +{ + GtkCellAreaIterClass *class; + + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + class = GTK_CELL_AREA_ITER_GET_CLASS (iter); + + if (class->sum_preferred_height) + class->sum_preferred_height (iter); +} + +void +gtk_cell_area_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter, + gint for_height) +{ + GtkCellAreaIterClass *class; + + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + class = GTK_CELL_AREA_ITER_GET_CLASS (iter); + + if (class->sum_preferred_width_for_height) + class->sum_preferred_width_for_height (iter, for_height); +} + +void +gtk_cell_area_iter_flush (GtkCellAreaIter *iter) +{ + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + gtk_cell_area_iter_flush_preferred_width (iter); + gtk_cell_area_iter_flush_preferred_height_for_width (iter, -1); + gtk_cell_area_iter_flush_preferred_height (iter); + gtk_cell_area_iter_flush_preferred_width_for_height (iter, -1); +} + +void +gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter) +{ + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter); +} + +void +gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter, + gint for_width) +{ + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width); +} + +void +gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter) +{ + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter); +} + +void +gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter, + gint for_height) +{ + g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); + + GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height); +} + + void gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter, @@ -558,48 +727,3 @@ gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter, g_signal_emit (iter, cell_area_iter_signals[SIGNAL_WIDTH_CHANGED], 0, for_height, size->min_size, size->nat_size); } - -void -gtk_cell_area_iter_flush (GtkCellAreaIter *iter) -{ - g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); - - gtk_cell_area_iter_flush_preferred_width (iter); - gtk_cell_area_iter_flush_preferred_height_for_width (iter, -1); - gtk_cell_area_iter_flush_preferred_height (iter); - gtk_cell_area_iter_flush_preferred_width_for_height (iter, -1); -} - -void -gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter) -{ - g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); - - GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width (iter); -} - -void -gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter, - gint for_width) -{ - g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); - - GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height_for_width (iter, for_width); -} - -void -gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter) -{ - g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); - - GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_height (iter); -} - -void -gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter, - gint for_height) -{ - g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter)); - - GTK_CELL_AREA_ITER_GET_CLASS (iter)->flush_preferred_width_for_height (iter, for_height); -} diff --git a/gtk/gtkcellareaiter.h b/gtk/gtkcellareaiter.h index 92f820fb0..b2e0e55a9 100644 --- a/gtk/gtkcellareaiter.h +++ b/gtk/gtkcellareaiter.h @@ -28,7 +28,7 @@ #ifndef __GTK_CELL_AREA_ITER_H__ #define __GTK_CELL_AREA_ITER_H__ -#include +#include G_BEGIN_DECLS @@ -39,7 +39,6 @@ G_BEGIN_DECLS #define GTK_IS_CELL_AREA_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CELL_AREA_ITER)) #define GTK_CELL_AREA_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CELL_AREA_ITER, GtkCellAreaIterClass)) -typedef struct _GtkCellAreaIter GtkCellAreaIter; typedef struct _GtkCellAreaIterPrivate GtkCellAreaIterPrivate; typedef struct _GtkCellAreaIterClass GtkCellAreaIterClass; @@ -62,6 +61,16 @@ struct _GtkCellAreaIterClass void (* flush_preferred_width_for_height) (GtkCellAreaIter *iter, gint height); + /* These must be invoked after a series of requests before consulting + * the iter values, implementors use this to push the overall + * requests while acconting for any internal alignments */ + void (* sum_preferred_width) (GtkCellAreaIter *iter); + void (* sum_preferred_height_for_width) (GtkCellAreaIter *iter, + gint width); + void (* sum_preferred_height) (GtkCellAreaIter *iter); + void (* sum_preferred_width_for_height) (GtkCellAreaIter *iter, + gint height); + /* Padding for future expansion */ void (*_gtk_reserved1) (void); void (*_gtk_reserved2) (void); @@ -69,48 +78,59 @@ struct _GtkCellAreaIterClass void (*_gtk_reserved4) (void); }; -GType gtk_cell_area_iter_get_type (void) G_GNUC_CONST; +GType gtk_cell_area_iter_get_type (void) G_GNUC_CONST; -/* Apis for GtkCellArea clients to consult cached values for multiple GtkTreeModel rows */ -void gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter, - gint *minimum_width, - gint *natural_width); -void gtk_cell_area_iter_get_preferred_height_for_width (GtkCellAreaIter *iter, - gint for_width, - gint *minimum_height, - gint *natural_height); -void gtk_cell_area_iter_get_preferred_height (GtkCellAreaIter *iter, - gint *minimum_height, - gint *natural_height); -void gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter, - gint for_height, - gint *minimum_width, - gint *natural_width); +GtkCellArea *gtk_cell_area_iter_get_area (GtkCellAreaIter *iter); -/* Apis for GtkCellArea implementations to update cached values for multiple GtkTreeModel rows */ -void gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter, - gint minimum_width, - gint natural_width); -void gtk_cell_area_iter_push_preferred_height_for_width (GtkCellAreaIter *iter, - gint for_width, - gint minimum_height, - gint natural_height); -void gtk_cell_area_iter_push_preferred_height (GtkCellAreaIter *iter, - gint minimum_height, - gint natural_height); -void gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter, - gint for_height, - gint minimum_width, - gint natural_width); +/* Apis for GtkCellArea clients to consult cached values for multiple GtkTreeModel rows */ +void gtk_cell_area_iter_get_preferred_width (GtkCellAreaIter *iter, + gint *minimum_width, + gint *natural_width); +void gtk_cell_area_iter_get_preferred_height_for_width (GtkCellAreaIter *iter, + gint for_width, + gint *minimum_height, + gint *natural_height); +void gtk_cell_area_iter_get_preferred_height (GtkCellAreaIter *iter, + gint *minimum_height, + gint *natural_height); +void gtk_cell_area_iter_get_preferred_width_for_height (GtkCellAreaIter *iter, + gint for_height, + gint *minimum_width, + gint *natural_width); + +/* 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_iter_sum_preferred_width (GtkCellAreaIter *iter); +void gtk_cell_area_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter, + gint for_width); +void gtk_cell_area_iter_sum_preferred_height (GtkCellAreaIter *iter); +void gtk_cell_area_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter, + gint for_height); /* Apis for GtkCellArea clients to flush the cache */ -void gtk_cell_area_iter_flush (GtkCellAreaIter *iter); -void gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter); -void gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter, - gint for_width); -void gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter); -void gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter, - gint for_height); +void gtk_cell_area_iter_flush (GtkCellAreaIter *iter); +void gtk_cell_area_iter_flush_preferred_width (GtkCellAreaIter *iter); +void gtk_cell_area_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter, + gint for_width); +void gtk_cell_area_iter_flush_preferred_height (GtkCellAreaIter *iter); +void gtk_cell_area_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter, + gint for_height); + +/* Apis for GtkCellArea implementations to update cached values for multiple GtkTreeModel rows */ +void gtk_cell_area_iter_push_preferred_width (GtkCellAreaIter *iter, + gint minimum_width, + gint natural_width); +void gtk_cell_area_iter_push_preferred_height_for_width (GtkCellAreaIter *iter, + gint for_width, + gint minimum_height, + gint natural_height); +void gtk_cell_area_iter_push_preferred_height (GtkCellAreaIter *iter, + gint minimum_height, + gint natural_height); +void gtk_cell_area_iter_push_preferred_width_for_height (GtkCellAreaIter *iter, + gint for_height, + gint minimum_width, + gint natural_width); G_END_DECLS