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).
This commit is contained in:
Tristan Van Berkom 2010-10-30 17:32:15 +09:00
parent 211c39c500
commit 3b1c301a66
7 changed files with 1059 additions and 541 deletions

View File

@ -31,7 +31,6 @@
#include <gtk/gtkcellrenderer.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtkcellareaiter.h>
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:

View File

@ -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;
gint group_min_size = 0;
gint group_nat_size = 0;
info = l->data;
group = group_list->data;
get_renderer_size (info->renderer, orientation, widget, -1,
&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)
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;
}
static void
update_iter_aligned (GtkCellAreaBox *box,
GtkCellAreaBoxIter *iter,
gint for_size)
GtkRequestedSize *
get_group_sizes (CellGroup *group,
GtkOrientation orientation,
GtkWidget *widget,
gint *n_sizes)
{
GtkCellAreaBoxPrivate *priv = box->priv;
CellInfo *info;
GList *l;
gint min_size = 0;
gint nat_size = 0;
gboolean first_cell = TRUE;
GtkRequestedSize *sizes;
GList *l;
gint i;
for (l = priv->cells; l; l = l->next)
*n_sizes = g_list_length (group->cells);
sizes = g_new (GtkRequestedSize, *n_sizes);
for (l = group->cells, i = 0; l; l = l->next, i++)
{
gint aligned_min_size, aligned_nat_size;
info = l->data;
CellInfo *info = l->data;
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
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);
}
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);
}
min_size += aligned_min_size;
nat_size += aligned_nat_size;
sizes[i].data = info;
if (!first_cell)
{
min_size += priv->spacing;
nat_size += priv->spacing;
}
if (first_cell)
first_cell = FALSE;
get_renderer_size (info->renderer,
orientation, widget, -1,
&sizes[i].minimum_size,
&sizes[i].natural_size);
}
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
return sizes;
}
static void
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;
/* Exception for single cell groups */
if (!group->cells->next)
{
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);
CellInfo *info = group->cells->data;
get_renderer_size (info->renderer,
OPPOSITE_ORIENTATION (priv->orientation),
widget, for_size, minimum_size, natural_size);
}
else
{
if (for_size < 0)
gtk_cell_area_iter_push_preferred_height (GTK_CELL_AREA_ITER (iter), min_size, nat_size);
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)
{
extra_size = avail_size / n_expand_cells;
extra_extra = avail_size % n_expand_cells;
}
else
gtk_cell_area_iter_push_preferred_height_for_width (GTK_CELL_AREA_ITER (iter),
for_size, min_size, nat_size);
extra_size = extra_extra = 0;
for (i = 0; i < n_sizes; i++)
{
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);
}
*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)
{
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)
{
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_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");
}
}

View File

@ -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

View File

@ -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,58 +398,162 @@ 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,
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 *group_table;
CachedSize *size;
g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
priv = box_iter->priv;
group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
if (!group_table)
{
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), group_table);
}
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 (group_table, GINT_TO_POINTER (group_id), size);
}
else
{
size->min_size = MAX (size->min_size, minimum_width);
size->nat_size = MAX (size->nat_size, natural_width);
}
}
void
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));
priv = box_iter->priv;
size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id));
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_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 *group_table;
CachedSize *size = NULL;
g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
priv = box_iter->priv;
group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
if (group_table)
size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
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_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));
priv = box_iter->priv;
size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id));
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_box_iter_get_group_width_for_height (GtkCellAreaBoxIter *box_iter,
gint group_id,
gint for_height,
gint minimum_width,
gint natural_width)
gint *minimum_width,
gint *natural_width)
{
GtkCellAreaBoxIterPrivate *priv;
GHashTable *cell_table;
CachedSize *size;
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)
{
cell_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);
}
size = g_hash_table_lookup (cell_table, renderer);
if (!size)
{
size = cached_size_new (minimum_width, natural_width);
g_hash_table_insert (cell_table, renderer, size);
}
else
{
size->min_size = MAX (size->min_size, minimum_width);
size->nat_size = MAX (size->nat_size, natural_width);
}
}
void
gtk_cell_area_box_iter_get_cell_width (GtkCellAreaBoxIter *box_iter,
GtkCellRenderer *renderer,
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);
if (group_table)
size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
if (size)
{
@ -364,111 +573,52 @@ 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)
static void
fill_requested_sizes (gpointer group_id_ptr,
CachedSize *cached_size,
GtkRequestedSize *requested)
{
GtkCellAreaBoxIterPrivate *priv;
GHashTable *cell_table;
CachedSize *size = NULL;
gint group_id = GPOINTER_TO_INT (group_id_ptr);
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));
if (cell_table)
size = g_hash_table_lookup (cell_table, renderer);
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;
}
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;
}
void
gtk_cell_area_box_iter_get_cell_height (GtkCellAreaBoxIter *box_iter,
GtkCellRenderer *renderer,
gint *minimum_height,
gint *natural_height)
GtkRequestedSize *
gtk_cell_area_box_iter_get_widths (GtkCellAreaBoxIter *box_iter,
gint *n_widths)
{
GtkCellAreaBoxIterPrivate *priv;
CachedSize *size;
GtkRequestedSize *widths;
g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL);
priv = box_iter->priv;
size = g_hash_table_lookup (priv->base_heights, renderer);
if (size)
{
if (minimum_height)
*minimum_height = size->min_size;
*n_widths = g_hash_table_size (priv->widths);
widths = g_new (GtkRequestedSize, *n_widths);
if (natural_height)
*natural_height = size->nat_size;
}
else
{
if (minimum_height)
*minimum_height = -1;
g_hash_table_foreach (priv->widths, (GHFunc)fill_requested_sizes, widths);
if (natural_height)
*natural_height = -1;
}
return widths;
}
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)
GtkRequestedSize *
gtk_cell_area_box_iter_get_heights (GtkCellAreaBoxIter *box_iter,
gint *n_heights)
{
GtkCellAreaBoxIterPrivate *priv;
GHashTable *cell_table;
CachedSize *size = NULL;
GtkRequestedSize *heights;
g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL);
priv = box_iter->priv;
cell_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
priv = box_iter->priv;
if (cell_table)
size = g_hash_table_lookup (cell_table, renderer);
*n_heights = g_hash_table_size (priv->heights);
heights = g_new (GtkRequestedSize, *n_heights);
if (size)
{
if (minimum_width)
*minimum_width = size->min_size;
g_hash_table_foreach (priv->heights, (GHFunc)fill_requested_sizes, heights);
if (natural_width)
*natural_width = size->nat_size;
}
else
{
if (minimum_width)
*minimum_width = -1;
if (natural_width)
*natural_width = -1;
}
return heights;
}

View File

@ -30,6 +30,7 @@
#include <gtk/gtkcellareaiter.h>
#include <gtk/gtkcellrenderer.h>
#include <gtk/gtksizerequest.h>
G_BEGIN_DECLS
@ -57,54 +58,59 @@ struct _GtkCellAreaBoxIterClass
};
GType gtk_cell_area_box_iter_get_type (void) G_GNUC_CONST;
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);
/* 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_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_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_cell_height (GtkCellAreaBoxIter *box_iter,
GtkCellRenderer *renderer,
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_cell_width_for_height (GtkCellAreaBoxIter *box_iter,
GtkCellRenderer *renderer,
gint for_height,
gint minimum_width,
gint natural_width);
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 alignments */
void gtk_cell_area_box_iter_get_cell_width (GtkCellAreaBoxIter *box_iter,
GtkCellRenderer *renderer,
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_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_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_cell_height (GtkCellAreaBoxIter *box_iter,
GtkCellRenderer *renderer,
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_cell_width_for_height (GtkCellAreaBoxIter *box_iter,
GtkCellRenderer *renderer,
gint for_height,
gint *minimum_width,
gint *natural_width);
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

View File

@ -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;
GHashTable *widths;
GHashTable *heights;
gint min_width;
gint nat_width;
gint min_height;
gint nat_height;
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);
}

View File

@ -28,7 +28,7 @@
#ifndef __GTK_CELL_AREA_ITER_H__
#define __GTK_CELL_AREA_ITER_H__
#include <glib-object.h>
#include <gtk/gtkcellarea.h>
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;
GtkCellArea *gtk_cell_area_iter_get_area (GtkCellAreaIter *iter);
/* 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);
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 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 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