From: Tristan Van Berkom Date: Sun, 31 Oct 2010 06:22:39 +0000 (+0900) Subject: Finished up allocation of cells. X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=6da74b6e1e32cc976da9ef07cea59f818a0e3f5f;p=~andy%2Fgtk Finished up allocation of cells. Added get_allocated_cells() which returns a practical list of cells with allocation for render/event time, this abstracts whether the cells are individually aligned or aligned into groups, when there are groups of cells before an alignment, those groups get allocated on the fly for render time. --- diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c index a341dd7f0..537edcce6 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -111,31 +111,49 @@ typedef struct { typedef struct { GList *cells; - guint id : 16; - guint expand : 1; + guint id : 8; + guint n_cells : 8; + guint expand_cells : 8; } 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); -static void iter_weak_notify (GtkCellAreaBox *box, - GtkCellAreaBoxIter *dead_iter); -static void flush_iters (GtkCellAreaBox *box); -static void init_iter_groups (GtkCellAreaBox *box); -static void init_iter_group (GtkCellAreaBox *box, - GtkCellAreaBoxIter *iter); +typedef struct { + GtkCellRenderer *renderer; + + gint position; + gint size; +} AllocatedCell; + +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 AllocatedCell *allocated_cell_new (GtkCellRenderer *renderer, + gint position, + gint size); +static void allocated_cell_free (AllocatedCell *cell); +static GList *list_consecutive_cells (GtkCellAreaBox *box); +static GList *construct_cell_groups (GtkCellAreaBox *box); +static gint count_expand_groups (GtkCellAreaBox *box); +static void iter_weak_notify (GtkCellAreaBox *box, + GtkCellAreaBoxIter *dead_iter); +static void flush_iters (GtkCellAreaBox *box); +static void init_iter_groups (GtkCellAreaBox *box); +static void init_iter_group (GtkCellAreaBox *box, + GtkCellAreaBoxIter *iter); +static void get_renderer_size (GtkCellRenderer *renderer, + GtkOrientation orientation, + GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size); +static GSList *get_allocated_cells (GtkCellAreaBox *box, + GtkCellAreaBoxIter *iter, + GtkWidget *widget); struct _GtkCellAreaBoxPrivate @@ -150,6 +168,8 @@ struct _GtkCellAreaBoxPrivate gint spacing; }; + + enum { PROP_0, PROP_ORIENTATION, @@ -275,6 +295,26 @@ cell_group_free (CellGroup *group) g_slice_free (CellGroup, group); } +static AllocatedCell * +allocated_cell_new (GtkCellRenderer *renderer, + gint position, + gint size) +{ + AllocatedCell *cell = g_slice_new (AllocatedCell); + + cell->renderer = renderer; + cell->position = position; + cell->size = size; + + return cell; +} + +static void +allocated_cell_free (AllocatedCell *cell) +{ + g_slice_free (AllocatedCell, cell); +} + static GList * list_consecutive_cells (GtkCellAreaBox *box) { @@ -335,10 +375,11 @@ construct_cell_groups (GtkCellAreaBox *box) } group->cells = g_list_prepend (group->cells, info); + group->n_cells++; /* A group expands if it contains any expand cells */ if (info->expand) - group->expand = TRUE; + group->expand_cells ++; } g_list_free (cells); @@ -363,33 +404,13 @@ count_expand_groups (GtkCellAreaBox *box) { CellGroup *group = l->data; - if (group->expand) + if (group->expand_cells > 0) 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; -} - static void iter_weak_notify (GtkCellAreaBox *box, GtkCellAreaBoxIter *dead_iter) @@ -414,7 +435,7 @@ init_iter_group (GtkCellAreaBox *box, { CellGroup *group = l->data; - expand_groups[i] = group->expand; + expand_groups[i] = (group->expand_cells > 0); } gtk_cell_area_box_init_groups (iter, n_groups, expand_groups); @@ -455,6 +476,107 @@ flush_iters (GtkCellAreaBox *box) } } +/* Returns an allocation for each cell in the orientation of the box, + * used in ->render()/->event() implementations to get a straight-forward + * list of allocated cells to operate on. + */ +static GSList * +get_allocated_cells (GtkCellAreaBox *box, + GtkCellAreaBoxIter *iter, + GtkWidget *widget) +{ + const GtkCellAreaBoxAllocation *group_allocs; + GtkCellAreaBoxPrivate *priv = box->priv; + GList *group_list, *cell_list; + GSList *allocated_cells = NULL; + gint i, j, n_allocs; + + group_allocs = gtk_cell_area_box_iter_get_orientation_allocs (iter, &n_allocs); + if (!group_allocs) + { + g_warning ("Trying to operate on an unallocated GtkCellAreaIter, " + "GtkCellAreaBox requires that the iter be allocated at least " + "in the orientation of the box"); + return NULL; + } + + for (i = 0, group_list = priv->groups; group_list; i++, group_list = group_list->next) + { + CellGroup *group = group_list->data; + + /* Exception for single cell groups */ + if (group->n_cells == 1) + { + CellInfo *info = group->cells->data; + AllocatedCell *cell = + allocated_cell_new (info->renderer, group_allocs[i].position, group_allocs[i].size); + + allocated_cells = g_slist_prepend (allocated_cells, cell); + } + else + { + GtkRequestedSize *sizes = g_new (GtkRequestedSize, group->n_cells); + gint avail_size = group_allocs[i].size; + gint position = group_allocs[i].position; + gint extra_size, extra_extra; + + for (j = 0, cell_list = group->cells; cell_list; j++, cell_list = cell_list->next) + { + CellInfo *info = cell_list->data; + + get_renderer_size (info->renderer, + priv->orientation, + widget, -1, + &sizes[j].minimum_size, + &sizes[j].natural_size); + + avail_size -= sizes[j].minimum_size; + } + + /* Distribute cells naturally within the group */ + avail_size -= (group->n_cells - 1) * priv->spacing; + avail_size = gtk_distribute_natural_allocation (avail_size, group->n_cells, sizes); + + /* Calculate/distribute expand for cells */ + if (group->expand_cells > 0) + { + extra_size = avail_size / group->expand_cells; + extra_extra = avail_size % group->expand_cells; + } + else + extra_size = extra_extra = 0; + + /* Create the allocated cells */ + for (j = 0, cell_list = group->cells; cell_list; j++, cell_list = cell_list->next) + { + CellInfo *info = cell_list->data; + AllocatedCell *cell; + + if (info->expand) + { + sizes[j].minimum_size += extra_size; + if (extra_extra) + { + sizes[j].minimum_size++; + extra_extra--; + } + } + + cell = allocated_cell_new (info->renderer, position, sizes[j].minimum_size); + + allocated_cells = g_slist_prepend (allocated_cells, cell); + + position += sizes[j].minimum_size; + position += priv->spacing; + } + + g_free (sizes); + } + } + + return g_slist_reverse (allocated_cells); +} + /************************************************************* * GObjectClass * *************************************************************/ @@ -604,7 +726,23 @@ gtk_cell_area_box_render (GtkCellArea *area, cairo_t *cr, const GdkRectangle *cell_area) { + GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); + GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter); + GSList *allocated_cells, *l; + + /* Get a list of cells with allocation sizes decided regardless + * of alignments and pack order etc. */ + allocated_cells = get_allocated_cells (box, box_iter, widget); + + for (l = allocated_cells; l; l = l->next) + { + AllocatedCell *cell = l->data; + + + } + g_slist_foreach (allocated_cells, (GFunc)allocated_cell_free, NULL); + g_slist_free (allocated_cells); } static GtkCellAreaIter * @@ -783,7 +921,7 @@ compute_group_size_for_opposing_orientation (GtkCellAreaBox *box, GtkCellAreaBoxPrivate *priv = box->priv; /* Exception for single cell groups */ - if (!group->cells->next) + if (group->n_cells == 1) { CellInfo *info = group->cells->data; @@ -796,7 +934,6 @@ compute_group_size_for_opposing_orientation (GtkCellAreaBox *box, 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; @@ -811,10 +948,10 @@ compute_group_size_for_opposing_orientation (GtkCellAreaBox *box, avail_size = gtk_distribute_natural_allocation (avail_size, n_sizes, orientation_sizes); /* Calculate/distribute expand for cells */ - if (n_expand_cells > 0) + if (group->expand_cells > 0) { - extra_size = avail_size / n_expand_cells; - extra_extra = avail_size % n_expand_cells; + extra_size = avail_size / group->expand_cells; + extra_extra = avail_size % group->expand_cells; } else extra_size = extra_extra = 0; @@ -902,7 +1039,7 @@ compute_size_for_opposing_orientation (GtkCellAreaBox *box, group = group_list->data; - if (group->expand) + if (group->expand_cells > 0) { orientation_sizes[group->id].minimum_size += extra_size; if (extra_extra)