X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkcellareabox.c;h=aa05220ae1d1973b89ff07fb730f6cf994babb59;hb=3a86af43fa208786b5c848c09f9c8e1d3f060931;hp=90a0a07233ed33a78e096f99b150f6fd9c27fffa;hpb=a2dda0c2bb88c1f009f7a10e0e344c4a301ff3b9;p=~andy%2Fgtk diff --git a/gtk/gtkcellareabox.c b/gtk/gtkcellareabox.c index 90a0a0723..aa05220ae 100644 --- a/gtk/gtkcellareabox.c +++ b/gtk/gtkcellareabox.c @@ -16,9 +16,7 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ @@ -52,7 +50,8 @@ #include "gtkorientable.h" #include "gtkcelllayout.h" #include "gtkcellareabox.h" -#include "gtkcellareaboxcontext.h" +#include "gtkcellareaboxcontextprivate.h" +#include "gtktypebuiltins.h" #include "gtkprivate.h" @@ -83,6 +82,11 @@ static void gtk_cell_area_box_foreach_alloc (GtkCellArea const GdkRectangle *background_area, GtkCellAllocCallback callback, gpointer callback_data); +static void gtk_cell_area_box_apply_attributes (GtkCellArea *area, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gboolean is_expander, + gboolean is_expanded); static void gtk_cell_area_box_set_cell_property (GtkCellArea *area, GtkCellRenderer *renderer, guint prop_id, @@ -145,6 +149,7 @@ typedef struct { guint expand : 1; /* Whether the cell expands */ guint pack : 1; /* Whether it is packed from the start or end */ guint align : 1; /* Whether to align its position with adjacent rows */ + guint fixed : 1; /* Whether to require the same size for all rows */ } CellInfo; typedef struct { @@ -153,6 +158,8 @@ typedef struct { guint id : 8; guint n_cells : 8; guint expand_cells : 8; + guint align : 1; + guint visible : 1; } CellGroup; typedef struct { @@ -165,7 +172,8 @@ typedef struct { static CellInfo *cell_info_new (GtkCellRenderer *renderer, GtkPackType pack, gboolean expand, - gboolean align); + gboolean align, + gboolean fixed); static void cell_info_free (CellInfo *info); static gint cell_info_find (CellInfo *info, GtkCellRenderer *renderer); @@ -191,8 +199,6 @@ static GSList *get_allocated_cells (GtkCellAreaBox *box, struct _GtkCellAreaBoxPrivate { - GtkOrientation orientation; - /* We hold on to the previously focused cell when navigating * up and down in a horizontal box (or left and right on a vertical one) * this way we always re-enter the last focused cell. @@ -205,6 +211,7 @@ struct _GtkCellAreaBoxPrivate GSList *contexts; + GtkOrientation orientation; gint spacing; /* We hold on to the rtl state from a widget we are requested for @@ -223,6 +230,7 @@ enum { CELL_PROP_0, CELL_PROP_EXPAND, CELL_PROP_ALIGN, + CELL_PROP_FIXED_SIZE, CELL_PROP_PACK_TYPE }; @@ -277,6 +285,7 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class) area_class->remove = gtk_cell_area_box_remove; area_class->foreach = gtk_cell_area_box_foreach; area_class->foreach_alloc = gtk_cell_area_box_foreach_alloc; + area_class->apply_attributes = gtk_cell_area_box_apply_attributes; area_class->set_cell_property = gtk_cell_area_box_set_cell_property; area_class->get_cell_property = gtk_cell_area_box_get_cell_property; @@ -341,6 +350,23 @@ gtk_cell_area_box_class_init (GtkCellAreaBoxClass *class) ("align", P_("Align"), P_("Whether cell should align with adjacent rows"), + FALSE, + GTK_PARAM_READWRITE)); + + /** + * GtkCellAreaBox:fixed-size: + * + * Whether the cell renderer should require the same size + * for all rows for which it was requested. + * + * Since: 3.0 + */ + gtk_cell_area_class_install_cell_property (area_class, + CELL_PROP_FIXED_SIZE, + g_param_spec_boolean + ("fixed-size", + P_("Fixed Size"), + P_("Whether cells should be the same size in all rows"), TRUE, GTK_PARAM_READWRITE)); @@ -373,7 +399,8 @@ static CellInfo * cell_info_new (GtkCellRenderer *renderer, GtkPackType pack, gboolean expand, - gboolean align) + gboolean align, + gboolean fixed) { CellInfo *info = g_slice_new (CellInfo); @@ -381,6 +408,7 @@ cell_info_new (GtkCellRenderer *renderer, info->pack = pack; info->expand = expand; info->align = align; + info->fixed = fixed; return info; } @@ -476,6 +504,7 @@ cell_groups_rebuild (GtkCellAreaBox *box) CellGroup *group_ptr; GList *cells, *l; guint id = 0; + gboolean last_cell_fixed = FALSE; cell_groups_clear (box); @@ -492,8 +521,10 @@ cell_groups_rebuild (GtkCellAreaBox *box) { CellInfo *info = l->data; - /* A new group starts with any aligned cell, the first group is implied */ - if (info->align && l != cells) + /* A new group starts with any aligned cell, or + * at the beginning and end of a fixed size cell. + * the first group is implied */ + if ((info->align || info->fixed || last_cell_fixed) && l != cells) { memset (&group, 0x0, sizeof (CellGroup)); group.id = ++id; @@ -505,9 +536,16 @@ cell_groups_rebuild (GtkCellAreaBox *box) group_ptr->cells = g_list_prepend (group_ptr->cells, info); group_ptr->n_cells++; + /* Not every group is aligned, some are floating + * fixed size cells */ + if (info->align) + group_ptr->align = TRUE; + /* A group expands if it contains any expand cells */ if (info->expand) group_ptr->expand_cells++; + + last_cell_fixed = info->fixed; } g_list_free (cells); @@ -582,20 +620,23 @@ init_context_group (GtkCellAreaBox *box, GtkCellAreaBoxContext *context) { GtkCellAreaBoxPrivate *priv = box->priv; - gint *expand_groups, i; + gint *expand_groups, *align_groups, i; expand_groups = g_new (gboolean, priv->groups->len); + align_groups = g_new (gboolean, priv->groups->len); for (i = 0; i < priv->groups->len; i++) { CellGroup *group = &g_array_index (priv->groups, CellGroup, i); expand_groups[i] = (group->expand_cells > 0); + align_groups[i] = group->align; } - /* This call implies reseting the request info */ - gtk_cell_area_box_init_groups (context, priv->groups->len, expand_groups); + /* This call implies resetting the request info */ + _gtk_cell_area_box_init_groups (context, priv->groups->len, expand_groups, align_groups); g_free (expand_groups); + g_free (align_groups); } static void @@ -782,11 +823,11 @@ get_allocated_cells (GtkCellAreaBox *box, GtkCellAreaBoxPrivate *priv = box->priv; GList *cell_list; GSList *allocated_cells = NULL; - gint i, j, n_allocs; + gint i, j, n_allocs, position; gint for_size, full_size; gboolean rtl; - group_allocs = gtk_cell_area_box_context_get_orientation_allocs (context, &n_allocs); + group_allocs = _gtk_cell_area_box_context_get_orientation_allocs (context, &n_allocs); if (!group_allocs) return allocate_cells_manually (box, widget, width, height); @@ -807,7 +848,7 @@ get_allocated_cells (GtkCellAreaBox *box, rtl = (priv->orientation == GTK_ORIENTATION_HORIZONTAL && gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); - for (i = 0; i < n_allocs; i++) + for (position = 0, i = 0; i < n_allocs; i++) { /* We dont always allocate all groups, sometimes the requested * group has only invisible cells for every row, hence the usage @@ -820,20 +861,46 @@ get_allocated_cells (GtkCellAreaBox *box, { CellInfo *info = group->cells->data; AllocatedCell *cell; + gint cell_position, cell_size; + + if (!gtk_cell_renderer_get_visible (info->renderer)) + continue; + + /* If were not aligned, place the cell after the last cell */ + if (info->align) + position = cell_position = group_allocs[i].position; + else + cell_position = position; + + /* If not a fixed size, use only the requested size for this row */ + if (info->fixed) + cell_size = group_allocs[i].size; + else + { + gint dummy; + gtk_cell_area_request_renderer (area, info->renderer, + priv->orientation, + widget, for_size, + &dummy, + &cell_size); + cell_size = MIN (cell_size, group_allocs[i].size); + } if (rtl) cell = allocated_cell_new (info->renderer, - full_size - (group_allocs[i].position + group_allocs[i].size), - group_allocs[i].size); + full_size - (cell_position + cell_size), cell_size); else - cell = allocated_cell_new (info->renderer, group_allocs[i].position, group_allocs[i].size); + cell = allocated_cell_new (info->renderer, cell_position, cell_size); + + position += cell_size; + position += priv->spacing; allocated_cells = g_slist_prepend (allocated_cells, cell); } else { GtkRequestedSize *sizes; - gint avail_size, position; + gint avail_size, cell_position; gint visible_cells, expand_cells; gint extra_size, extra_extra; @@ -845,11 +912,19 @@ get_allocated_cells (GtkCellAreaBox *box, if (visible_cells == 0) continue; - /* Offset the allocation to the group position - * and allocate into the group's available size - */ - position = group_allocs[i].position; - avail_size = group_allocs[i].size; + /* If were not aligned, place the cell after the last cell + * and eat up the extra space + */ + if (group->align) + { + avail_size = group_allocs[i].size; + position = cell_position = group_allocs[i].position; + } + else + { + avail_size = group_allocs[i].size + (group_allocs[i].position - position); + cell_position = position; + } sizes = g_new (GtkRequestedSize, visible_cells); @@ -906,21 +981,25 @@ get_allocated_cells (GtkCellAreaBox *box, if (rtl) cell = allocated_cell_new (info->renderer, - full_size - (position + sizes[j].minimum_size), + full_size - (cell_position + sizes[j].minimum_size), sizes[j].minimum_size); else - cell = allocated_cell_new (info->renderer, position, sizes[j].minimum_size); + cell = allocated_cell_new (info->renderer, cell_position, sizes[j].minimum_size); allocated_cells = g_slist_prepend (allocated_cells, cell); - position += sizes[j].minimum_size; - position += priv->spacing; + cell_position += sizes[j].minimum_size; + cell_position += priv->spacing; } g_free (sizes); + + position = cell_position; } } + g_free (group_allocs); + /* Note it might not be important to reverse the list here at all, * we have the correct positions, no need to allocate from left to right */ @@ -982,6 +1061,7 @@ gtk_cell_area_box_set_property (GObject *object, /* Notify that size needs to be requested again */ reset_contexts (box); + break; case PROP_SPACING: gtk_cell_area_box_set_spacing (box, g_value_get_int (value)); @@ -1022,7 +1102,7 @@ gtk_cell_area_box_add (GtkCellArea *area, GtkCellRenderer *renderer) { gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (area), - renderer, FALSE, TRUE); + renderer, FALSE, FALSE, TRUE); } static void @@ -1221,6 +1301,40 @@ gtk_cell_area_box_foreach_alloc (GtkCellArea *area, g_slist_free (allocated_cells); } +static void +gtk_cell_area_box_apply_attributes (GtkCellArea *area, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gboolean is_expander, + gboolean is_expanded) +{ + GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); + GtkCellAreaBoxPrivate *priv = box->priv; + gint i; + + /* Call the parent class to apply the attributes */ + GTK_CELL_AREA_CLASS + (gtk_cell_area_box_parent_class)->apply_attributes (area, tree_model, iter, + is_expander, is_expanded); + + /* Update visible state for cell groups */ + for (i = 0; i < priv->groups->len; i++) + { + CellGroup *group = &g_array_index (priv->groups, CellGroup, i); + GList *list; + + group->visible = FALSE; + + for (list = group->cells; list && group->visible == FALSE; list = list->next) + { + CellInfo *info = list->data; + + if (gtk_cell_renderer_get_visible (info->renderer)) + group->visible = TRUE; + } + } +} + static void gtk_cell_area_box_set_cell_property (GtkCellArea *area, GtkCellRenderer *renderer, @@ -1265,6 +1379,16 @@ gtk_cell_area_box_set_cell_property (GtkCellArea *area, } break; + case CELL_PROP_FIXED_SIZE: + val = g_value_get_boolean (value); + + if (info->fixed != val) + { + info->fixed = val; + rebuild = TRUE; + } + break; + case CELL_PROP_PACK_TYPE: pack_type = g_value_get_enum (value); @@ -1313,6 +1437,10 @@ gtk_cell_area_box_get_cell_property (GtkCellArea *area, g_value_set_boolean (value, info->align); break; + case CELL_PROP_FIXED_SIZE: + g_value_set_boolean (value, info->fixed); + break; + case CELL_PROP_PACK_TYPE: g_value_set_enum (value, info->pack); break; @@ -1349,7 +1477,7 @@ gtk_cell_area_box_copy_context (GtkCellArea *area, GtkCellAreaBox *box = GTK_CELL_AREA_BOX (area); GtkCellAreaBoxPrivate *priv = box->priv; GtkCellAreaContext *copy = - (GtkCellAreaContext *)gtk_cell_area_box_context_copy (GTK_CELL_AREA_BOX (area), + (GtkCellAreaContext *)_gtk_cell_area_box_context_copy (GTK_CELL_AREA_BOX (area), GTK_CELL_AREA_BOX_CONTEXT (context)); priv->contexts = g_slist_prepend (priv->contexts, copy); @@ -1434,17 +1562,17 @@ compute_size (GtkCellAreaBox *box, if (orientation == GTK_ORIENTATION_HORIZONTAL) { if (for_size < 0) - gtk_cell_area_box_context_push_group_width (context, group->id, group_min_size, group_nat_size); + _gtk_cell_area_box_context_push_group_width (context, group->id, group_min_size, group_nat_size); else - gtk_cell_area_box_context_push_group_width_for_height (context, group->id, for_size, + _gtk_cell_area_box_context_push_group_width_for_height (context, group->id, for_size, group_min_size, group_nat_size); } else { if (for_size < 0) - gtk_cell_area_box_context_push_group_height (context, group->id, group_min_size, group_nat_size); + _gtk_cell_area_box_context_push_group_height (context, group->id, group_min_size, group_nat_size); else - gtk_cell_area_box_context_push_group_height_for_width (context, group->id, for_size, + _gtk_cell_area_box_context_push_group_height_for_width (context, group->id, for_size, group_min_size, group_nat_size); } } @@ -1457,7 +1585,7 @@ compute_size (GtkCellAreaBox *box, gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); } -GtkRequestedSize * +static GtkRequestedSize * get_group_sizes (GtkCellArea *area, CellGroup *group, GtkOrientation orientation, @@ -1593,9 +1721,9 @@ compute_size_for_opposing_orientation (GtkCellAreaBox *box, n_expand_groups = count_expand_groups (box); if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) - orientation_sizes = gtk_cell_area_box_context_get_widths (context, &n_groups); + orientation_sizes = _gtk_cell_area_box_context_get_widths (context, &n_groups); else - orientation_sizes = gtk_cell_area_box_context_get_heights (context, &n_groups); + orientation_sizes = _gtk_cell_area_box_context_get_heights (context, &n_groups); /* First start by naturally allocating space among groups of cells */ avail_size -= (n_groups - 1) * priv->spacing; @@ -1638,7 +1766,7 @@ compute_size_for_opposing_orientation (GtkCellAreaBox *box, } /* Now we have the allocation for the group, - * request it's height-for-width + * request its height-for-width */ compute_group_size_for_opposing_orientation (box, group, widget, orientation_sizes[i].minimum_size, @@ -1649,12 +1777,12 @@ compute_size_for_opposing_orientation (GtkCellAreaBox *box, if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { - gtk_cell_area_box_context_push_group_height_for_width (context, group_idx, for_size, + _gtk_cell_area_box_context_push_group_height_for_width (context, group_idx, for_size, group_min, group_nat); } else { - gtk_cell_area_box_context_push_group_width_for_height (context, group_idx, for_size, + _gtk_cell_area_box_context_push_group_width_for_height (context, group_idx, for_size, group_min, group_nat); } } @@ -1935,7 +2063,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, TRUE); + gtk_cell_area_box_pack_start (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, FALSE, TRUE); } static void @@ -1943,7 +2071,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, TRUE); + gtk_cell_area_box_pack_end (GTK_CELL_AREA_BOX (cell_layout), renderer, expand, FALSE, TRUE); } static void @@ -1970,6 +2098,24 @@ gtk_cell_area_box_layout_reorder (GtkCellLayout *cell_layout, } } +/************************************************************* + * Private interaction with GtkCellAreaBoxContext * + *************************************************************/ +gboolean +_gtk_cell_area_box_group_visible (GtkCellAreaBox *box, + gint group_idx) +{ + GtkCellAreaBoxPrivate *priv = box->priv; + CellGroup *group; + + g_assert (group_idx >= 0 && group_idx < priv->groups->len); + + group = &g_array_index (priv->groups, CellGroup, group_idx); + + return group->visible; +} + + /************************************************************* * API * *************************************************************/ @@ -1995,6 +2141,7 @@ gtk_cell_area_box_new (void) * @expand: whether @renderer should receive extra space when the area receives * more than its natural size * @align: whether @renderer should be aligned in adjacent rows + * @fixed: whether @renderer should have the same size in all rows * * Adds @renderer to @box, packed with reference to the start of @box. * @@ -2007,7 +2154,8 @@ void gtk_cell_area_box_pack_start (GtkCellAreaBox *box, GtkCellRenderer *renderer, gboolean expand, - gboolean align) + gboolean align, + gboolean fixed) { GtkCellAreaBoxPrivate *priv; CellInfo *info; @@ -2024,7 +2172,7 @@ gtk_cell_area_box_pack_start (GtkCellAreaBox *box, return; } - info = cell_info_new (renderer, GTK_PACK_START, expand, align); + info = cell_info_new (renderer, GTK_PACK_START, expand, align, fixed); priv->cells = g_list_append (priv->cells, info); @@ -2038,6 +2186,7 @@ gtk_cell_area_box_pack_start (GtkCellAreaBox *box, * @expand: whether @renderer should receive extra space when the area receives * more than its natural size * @align: whether @renderer should be aligned in adjacent rows + * @fixed: whether @renderer should have the same size in all rows * * Adds @renderer to @box, packed with reference to the end of @box. * @@ -2050,7 +2199,8 @@ void gtk_cell_area_box_pack_end (GtkCellAreaBox *box, GtkCellRenderer *renderer, gboolean expand, - gboolean align) + gboolean align, + gboolean fixed) { GtkCellAreaBoxPrivate *priv; CellInfo *info; @@ -2067,7 +2217,7 @@ gtk_cell_area_box_pack_end (GtkCellAreaBox *box, return; } - info = cell_info_new (renderer, GTK_PACK_END, expand, align); + info = cell_info_new (renderer, GTK_PACK_END, expand, align, fixed); priv->cells = g_list_append (priv->cells, info);