[gtk+/native-layout-incubator-2] Make treeviews/columns leverage height-for-width cell renderers
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/native-layout-incubator-2] Make treeviews/columns leverage height-for-width cell renderers
- Date: Wed, 30 Jun 2010 15:32:02 +0000 (UTC)
commit cff0582dc0dc19c5be12573af54229be388a2b47
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Wed Jun 30 11:28:21 2010 -0400
Make treeviews/columns leverage height-for-width cell renderers
For columns; these methods are added to replace
gtk_tree_view_column_get_size():
gtk_tree_view_column_get_natural_width()
gtk_tree_view_column_get_height_for_width()
gtk_tree_view_column_allocate_width()
This code includes a nasty workaround to monitor a possible
parent scrolled window's allocation - this code protects against
a possible feedback loop between the height-for-width wrapping
treeview and scrolled window (the fight occurs because the scrolled
window allocates a new width when the content height changes to
show/hide the scrollbars).
gtk/gtktreeprivate.h | 21 ++
gtk/gtktreeview.c | 653 ++++++++++++++++++++++++++-------------
gtk/gtktreeviewcolumn.c | 784 ++++++++++++++++++++++++++++-------------------
gtk/gtktreeviewcolumn.h | 12 +
4 files changed, 940 insertions(+), 530 deletions(-)
---
diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h
index e8887e0..d1aa9df 100644
--- a/gtk/gtktreeprivate.h
+++ b/gtk/gtktreeprivate.h
@@ -77,6 +77,8 @@ enum
*/
#define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*TREE_VIEW_HEADER_HEIGHT(tree_view))
+#define GTK_TREE_VIEW_COLUMN_GET_PRIVATE(column) (G_TYPE_INSTANCE_GET_PRIVATE ((column), GTK_TYPE_TREE_VIEW_COLUMN, GtkTreeViewColumnPrivate))
+
typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
struct _GtkTreeViewColumnReorder
{
@@ -99,6 +101,14 @@ struct _GtkTreeViewPrivate
gint width;
gint height;
+ /* Track parent scrolled window size to
+ * avoid feed back loops with scrollbar allocations
+ * and h4w cell renderers in the layout.
+ */
+ gint prev_parent_width;
+ gint prev_parent_height;
+ gint consecutive_allocations;
+
/* Adjustments */
GtkAdjustment *hadjustment;
GtkAdjustment *vadjustment;
@@ -298,6 +308,16 @@ struct _GtkTreeViewPrivate
/* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
guint search_entry_avoid_unhandled_binding : 1;
+
+ /* Mark dirty state for resizes that originate from changes in
+ * the full rendered content size, from resizes that originate
+ * from */
+ guint content_size_dirty : 1;
+};
+
+struct _GtkTreeViewColumnPrivate
+{
+ gint natural_width;
};
#ifdef __GNUC__
@@ -457,6 +477,7 @@ void _gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn *tree_column,
const GdkRectangle *expose_area,
guint flags);
void _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
+ gboolean recalculate_width,
gboolean install_handler);
void _gtk_tree_view_column_get_neighbor_sizes (GtkTreeViewColumn *column,
GtkCellRenderer *cell,
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 387bdde..a7846c8 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -27,6 +27,7 @@
#include "gtktreednd.h"
#include "gtktreeprivate.h"
#include "gtkcellrenderer.h"
+#include "gtksizerequest.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkbuildable.h"
@@ -43,6 +44,7 @@
#include "gtkframe.h"
#include "gtktreemodelsort.h"
#include "gtktooltip.h"
+#include "gtkscrolledwindow.h"
#include "gtkprivate.h"
#include "gtkalias.h"
@@ -165,8 +167,6 @@ static void gtk_tree_view_destroy (GtkObject *object);
static void gtk_tree_view_realize (GtkWidget *widget);
static void gtk_tree_view_unrealize (GtkWidget *widget);
static void gtk_tree_view_map (GtkWidget *widget);
-static void gtk_tree_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
static void gtk_tree_view_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_tree_view_expose (GtkWidget *widget,
@@ -299,7 +299,8 @@ static gboolean do_validate_rows (GtkTreeView *tree_view,
gboolean size_request);
static gboolean validate_rows (GtkTreeView *tree_view);
static gboolean presize_handler_callback (gpointer data);
-static void install_presize_handler (GtkTreeView *tree_view);
+static void install_presize_handler (GtkTreeView *tree_view,
+ gboolean content_dirty);
static void install_scroll_sync_handler (GtkTreeView *tree_view);
static void gtk_tree_view_set_top_row (GtkTreeView *tree_view,
GtkTreePath *path,
@@ -465,6 +466,15 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView *tree
GtkTreeViewColumn *column,
gint drop_position);
+/* GtkSizeRequest */
+static void gtk_tree_view_size_request_init (GtkSizeRequestIface *iface);
+static void gtk_tree_view_get_width (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size);
+static void gtk_tree_view_get_height (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size);
+
/* GtkBuildable */
static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
GtkBuilder *builder,
@@ -489,7 +499,10 @@ static guint tree_view_signals [LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
- gtk_tree_view_buildable_init))
+ gtk_tree_view_buildable_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST,
+ gtk_tree_view_size_request_init))
+
static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
@@ -519,7 +532,6 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
widget_class->map = gtk_tree_view_map;
widget_class->realize = gtk_tree_view_realize;
widget_class->unrealize = gtk_tree_view_unrealize;
- widget_class->size_request = gtk_tree_view_size_request;
widget_class->size_allocate = gtk_tree_view_size_allocate;
widget_class->button_press_event = gtk_tree_view_button_press;
widget_class->button_release_event = gtk_tree_view_button_release;
@@ -1866,7 +1878,7 @@ gtk_tree_view_realize (GtkWidget *widget)
gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
}
static void
@@ -2046,37 +2058,6 @@ gtk_tree_view_update_size (GtkTreeView *tree_view)
tree_view->priv->height = tree_view->priv->tree->root->offset;
}
-static void
-gtk_tree_view_size_request (GtkWidget *widget,
- GtkRequisition *requisition)
-{
- GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
- GList *tmp_list;
-
- /* we validate some rows initially just to make sure we have some size.
- * In practice, with a lot of static lists, this should get a good width.
- */
- do_validate_rows (tree_view, FALSE);
- gtk_tree_view_size_request_columns (tree_view);
- gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
-
- requisition->width = tree_view->priv->width;
- requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
-
- tmp_list = tree_view->priv->children;
-
- while (tmp_list)
- {
- GtkTreeViewChild *child = tmp_list->data;
- GtkRequisition child_requisition;
-
- tmp_list = tmp_list->next;
-
- if (gtk_widget_get_visible (child->widget))
- gtk_widget_size_request (child->widget, &child_requisition);
- }
-}
-
static int
gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
{
@@ -2185,6 +2166,28 @@ gtk_tree_view_get_real_requested_width_from_column (GtkTreeView *tree_view
return real_requested_width;
}
+static gint
+gtk_tree_view_get_real_natural_width_from_column (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column)
+{
+ GtkTreeViewColumnPrivate *column_priv;
+ gint button_natural_width;
+ gint column_natural_width;
+
+ column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
+ column_natural_width = column_priv->natural_width;
+
+ if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
+ {
+ gtk_size_request_get_width (GTK_SIZE_REQUEST (column->button),
+ NULL, &button_natural_width);
+
+ column_natural_width = MAX (column_natural_width, button_natural_width);
+ }
+
+ return column_natural_width;
+}
+
/* GtkWidget::size_allocate helper */
static void
gtk_tree_view_size_allocate_columns (GtkWidget *widget,
@@ -2195,15 +2198,23 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
GtkTreeViewColumn *column;
GtkAllocation allocation;
gint width = 0;
- gint extra, extra_per_column, extra_for_last;
- gint full_requested_width = 0;
+ gint extra, extra_per_column;
+ gint column_width, i, horizontal_separator;
+ gint grid_line_width, draw_vgrid_lines;
gint number_of_expand_columns = 0;
gboolean column_changed = FALSE;
gboolean rtl;
gboolean update_expand;
+ GArray *array;
+ GtkRequestedSize *sizes;
tree_view = GTK_TREE_VIEW (widget);
+ gtk_widget_style_get (widget,
+ "horizontal-separator", &horizontal_separator,
+ "grid-line-width", &grid_line_width,
+ NULL);
+
for (last_column = g_list_last (tree_view->priv->columns);
last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
last_column = last_column->prev)
@@ -2216,25 +2227,56 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
first_column = first_column->next)
;
+ draw_vgrid_lines =
+ tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
+ || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
+
allocation.y = 0;
allocation.height = tree_view->priv->header_height;
rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
- /* find out how many extra space and expandable columns we have */
+ extra = widget->allocation.width;
+
+ array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
+
for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
{
+ GtkRequestedSize requested;
+ gint padding;
+
column = (GtkTreeViewColumn *)list->data;
if (!column->visible)
continue;
- full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
+ /* Calculate padding for this column and store it in our client pointer for the next loop */
+ padding = horizontal_separator;
+ if (draw_vgrid_lines)
+ {
+ if (list == first_column || list == last_column)
+ padding += grid_line_width / 2.0;
+ else
+ padding += grid_line_width;
+ }
+
+ requested.data = GINT_TO_POINTER (padding);
+ requested.minimum_size = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
+ requested.natural_size = gtk_tree_view_get_real_natural_width_from_column (tree_view, column);
+ g_array_append_val (array, requested);
+
+ /* Subtract each column's request and padding from the remaining allocation */
+ extra -= requested.minimum_size;
+ extra -= padding;
if (column->expand)
number_of_expand_columns++;
}
+ /* Distribute as much of remaining 'size' as possible before sharing expand space */
+ sizes = (GtkRequestedSize *)array->data;
+ extra = gtk_distribute_natural_allocation (MAX (extra, 0), array->len, sizes);
+
/* Only update the expand value if the width of the widget has changed,
* or the number of expand columns has changed, or if there are no expand
* columns, or if we didn't have an size-allocation yet after the
@@ -2247,21 +2289,8 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
tree_view->priv->post_validation_flag = FALSE;
- if (!update_expand)
- {
- extra = tree_view->priv->last_extra_space;
- extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
- }
- else
- {
- extra = MAX (widget->allocation.width - full_requested_width, 0);
- extra_for_last = 0;
-
- tree_view->priv->last_extra_space = extra;
- }
-
if (number_of_expand_columns > 0)
- extra_per_column = extra/number_of_expand_columns;
+ extra_per_column = extra / number_of_expand_columns;
else
extra_per_column = 0;
@@ -2271,12 +2300,12 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
}
- for (list = (rtl ? last_column : first_column);
+ for (list = (rtl ? last_column : first_column), i = 0;
list != (rtl ? first_column->prev : last_column->next);
list = (rtl ? list->prev : list->next))
{
- gint real_requested_width = 0;
gint old_width;
+ gint padding;
column = list->data;
old_width = column->width;
@@ -2297,56 +2326,43 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
gtk_widget_size_allocate (tree_view->priv->drag_column->button,
&drag_allocation);
width += drag_allocation.width;
+
+ i++;
continue;
}
- real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
-
- allocation.x = width;
- column->width = real_requested_width;
+ column_width = sizes[i].minimum_size;
+ padding = GPOINTER_TO_INT (sizes[i].data);
if (column->expand)
{
- if (number_of_expand_columns == 1)
- {
- /* We add the remander to the last column as
- * */
- column->width += extra;
- }
- else
- {
- column->width += extra_per_column;
- extra -= extra_per_column;
- number_of_expand_columns --;
- }
+ column_width += extra_per_column;
}
- else if (number_of_expand_columns == 0 &&
- list == last_column)
+ /* If no columns expand, the last one takes the remaining space */
+ else if (number_of_expand_columns == 0 && list == last_column)
{
- column->width += extra;
+ column_width += extra;
}
- /* In addition to expand, the last column can get even more
- * extra space so all available space is filled up.
- */
- if (extra_for_last > 0 && list == last_column)
- column->width += extra_for_last;
+ gtk_tree_view_column_allocate_width (column, column_width);
- g_object_notify (G_OBJECT (column), "width");
+ /* Add padding between columns and allocate the buttons... */
+ allocation.x = width;
+ allocation.width = column_width + padding;
+ width += allocation.width;
- allocation.width = column->width;
- width += column->width;
+ gtk_widget_size_allocate (column->button, &allocation);
- if (column->width > old_width)
+ if (column_width > old_width)
column_changed = TRUE;
- gtk_widget_size_allocate (column->button, &allocation);
-
if (column->window)
gdk_window_move_resize (column->window,
allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
allocation.y,
TREE_VIEW_DRAG_WIDTH, allocation.height);
+
+ i++; // itterate through visible columns
}
/* We change the width here. The user might have been resizing columns,
@@ -2355,7 +2371,7 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget,
tree_view->priv->width = width;
if (width_changed)
*width_changed = TRUE;
-
+
if (column_changed)
gtk_widget_queue_draw (GTK_WIDGET (tree_view));
}
@@ -2369,6 +2385,7 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
GList *tmp_list;
gboolean width_changed = FALSE;
gint old_width = widget->allocation.width;
+ gboolean scroll_window_feedback = FALSE;
if (allocation->width != widget->allocation.width)
width_changed = TRUE;
@@ -2392,11 +2409,49 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (child->widget, &allocation);
}
+ /* If we get various width allocations while our content did not change
+ * and the parent is a scrolled window and it's own allocation has not
+ * changed:
+ *
+ * Stop setting the adjustments until
+ * a.) Treeview content size changes
+ * b.) Parent's allocation changes
+ */
+ if (GTK_IS_SCROLLED_WINDOW (gtk_widget_get_parent (widget)))
+ {
+ GtkWidget *swindow = gtk_widget_get_parent (widget);
+ GtkAllocation salloc;
+
+ gtk_widget_get_allocation (swindow, &salloc);
+
+ if (!tree_view->priv->content_size_dirty &&
+ tree_view->priv->prev_parent_width == salloc.width &&
+ tree_view->priv->prev_parent_height == salloc.height)
+ {
+ /* Feedback detected */
+ if (tree_view->priv->consecutive_allocations >= 3)
+ scroll_window_feedback = TRUE;
+ else
+ tree_view->priv->consecutive_allocations++;
+ }
+ else
+ tree_view->priv->consecutive_allocations = 0;
+
+ tree_view->priv->content_size_dirty = FALSE;
+ tree_view->priv->prev_parent_width = salloc.width;
+ tree_view->priv->prev_parent_height = salloc.height;
+ }
+ else
+ tree_view->priv->consecutive_allocations = 0;
+
+
/* We size-allocate the columns first because the width of the
* tree view (used in updating the adjustments below) might change.
*/
gtk_tree_view_size_allocate_columns (widget, &width_changed);
+ if (!scroll_window_feedback)
+ {
tree_view->priv->hadjustment->page_size = allocation->width;
tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
@@ -2438,6 +2493,7 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
gtk_adjustment_changed (tree_view->priv->vadjustment);
+ }
/* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
@@ -2513,6 +2569,32 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
gtk_widget_queue_draw (widget);
}
}
+
+ /* Need to do this when the real allocated width changes
+ * and upon the first allocation */
+ if (allocation->width != old_width &&
+ !tree_view->priv->fixed_height_mode)
+ {
+ /* Have the tree recalculate height-for-width of all rows when the width changes
+ */
+ _gtk_rbtree_mark_invalid (tree_view->priv->tree);
+ for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
+ {
+ GtkTreeViewColumn *column;
+
+ column = tmp_list->data;
+ if (! column->visible)
+ continue;
+
+ if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE ||
+ column->column_type == GTK_TREE_VIEW_COLUMN_GROW_ONLY)
+ _gtk_tree_view_column_cell_set_dirty (column, FALSE, FALSE);
+ }
+
+ install_presize_handler (tree_view, FALSE);
+
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ }
}
/* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
@@ -4436,11 +4518,12 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
- cell_offset = 0;
- highlight_x = 0; /* should match x coord of first cell */
+ cell_offset = 0;
+ highlight_x = 0; /* should match x coord of first cell */
expander_cell_width = 0;
- background_area.y = y_offset + event->area.y;
+ /* 'background_area' itterates vertically over rows in the exposed area */
+ background_area.y = y_offset + event->area.y;
background_area.height = max_height;
flags = 0;
@@ -4482,62 +4565,68 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
if (!column->visible)
continue;
- if (cell_offset > event->area.x + event->area.width ||
- cell_offset + column->width < event->area.x)
- {
- cell_offset += column->width;
- continue;
- }
-
- if (column->show_sort_indicator)
- flags |= GTK_CELL_RENDERER_SORTED;
- else
- flags &= ~GTK_CELL_RENDERER_SORTED;
-
- if (cursor == node)
- flags |= GTK_CELL_RENDERER_FOCUSED;
- else
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- background_area.x = cell_offset;
+ /* Adjust 'background_area' for this column's portion of this row */
+ background_area.x = cell_offset;
background_area.width = column->width;
- cell_area = background_area;
- cell_area.y += vertical_separator / 2;
- cell_area.x += horizontal_separator / 2;
+ /* Create 'cell_area' to render this column inside this row */
+ cell_area = background_area;
+ cell_area.y += vertical_separator / 2;
+ cell_area.x += horizontal_separator / 2;
cell_area.height -= vertical_separator;
- cell_area.width -= horizontal_separator;
+ /* Calculate padding */
if (draw_vgrid_lines)
{
if (list == first_column)
{
- cell_area.width -= grid_line_width / 2;
+ background_area.width += grid_line_width / 2;
}
else if (list == last_column)
{
cell_area.x += grid_line_width / 2;
- cell_area.width -= grid_line_width / 2;
+ background_area.width += grid_line_width / 2;
}
else
{
cell_area.x += grid_line_width / 2;
- cell_area.width -= grid_line_width;
+ background_area.width += grid_line_width;
}
}
-
+
if (draw_hgrid_lines)
{
cell_area.y += grid_line_width / 2;
cell_area.height -= grid_line_width;
}
+ /* Now that we've deduced the real rendering area,
+ * do a couple of assertions to make sure we're rendereing
+ * a relevant area.
+ */
+ if (cell_offset > event->area.x + event->area.width ||
+ cell_offset + column->width < event->area.x)
+ {
+ cell_offset += background_area.width;
+ continue;
+ }
+
if (cairo_region_contains_rectangle (event->region, &background_area) == CAIRO_REGION_OVERLAP_OUT)
{
- cell_offset += column->width;
+ cell_offset += background_area.width;
continue;
}
+ if (column->show_sort_indicator)
+ flags |= GTK_CELL_RENDERER_SORTED;
+ else
+ flags &= ~GTK_CELL_RENDERER_SORTED;
+
+ if (cursor == node)
+ flags |= GTK_CELL_RENDERER_FOCUSED;
+ else
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
+
gtk_tree_view_column_cell_set_cell_data (column,
tree_view->priv->model,
&iter,
@@ -4677,59 +4766,42 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
*/
highlight_x = cell_area.x;
expander_cell_width = cell_area.width;
-
- if (is_separator)
- gtk_paint_hline (widget->style,
- event->window,
- state,
- &cell_area,
- widget,
- NULL,
- cell_area.x,
- cell_area.x + cell_area.width,
- cell_area.y + cell_area.height / 2);
- else
- _gtk_tree_view_column_cell_render (column,
- event->window,
- &background_area,
- &cell_area,
- &event->area,
- flags);
- if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
- && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
- {
- if (!got_pointer)
- {
- gdk_window_get_pointer (tree_view->priv->bin_window,
- &pointer_x, &pointer_y, NULL);
- got_pointer = TRUE;
- }
-
- gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
- tree,
- node,
- pointer_x, pointer_y);
- }
}
+
+ /* Do the actual rendering */
+ if (is_separator)
+ gtk_paint_hline (widget->style,
+ event->window,
+ state,
+ &cell_area,
+ widget,
+ NULL,
+ cell_area.x,
+ cell_area.x + cell_area.width,
+ cell_area.y + cell_area.height / 2);
else
+ _gtk_tree_view_column_cell_render (column,
+ event->window,
+ &background_area,
+ &cell_area,
+ &event->area,
+ flags);
+
+ if (gtk_tree_view_is_expander_column (tree_view, column) &&
+ TREE_VIEW_DRAW_EXPANDERS(tree_view) &&
+ (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
{
- if (is_separator)
- gtk_paint_hline (widget->style,
- event->window,
- state,
- &cell_area,
- widget,
- NULL,
- cell_area.x,
- cell_area.x + cell_area.width,
- cell_area.y + cell_area.height / 2);
- else
- _gtk_tree_view_column_cell_render (column,
- event->window,
- &background_area,
- &cell_area,
- &event->area,
- flags);
+ if (!got_pointer)
+ {
+ gdk_window_get_pointer (tree_view->priv->bin_window,
+ &pointer_x, &pointer_y, NULL);
+ got_pointer = TRUE;
+ }
+
+ gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
+ tree,
+ node,
+ pointer_x, pointer_y);
}
if (gtk_tree_view_is_expander_column (tree_view, column) &&
@@ -4818,7 +4890,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
flags);
}
- cell_offset += column->width;
+ cell_offset += background_area.width;
}
if (node == drag_highlight)
@@ -4940,6 +5012,10 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
width, tmp_height);
}
+ /* This remaining portion of the loop finds the appropriate next GtkTreeIter
+ * to render and increments the render offset (top down row-by-row inside
+ * the dirty exposed area).
+ */
y_offset += max_height;
if (node->children)
{
@@ -5692,7 +5768,7 @@ validate_row (GtkTreeView *tree_view,
gint focus_pad;
gint grid_line_width;
gboolean wide_separators;
- gint separator_height;
+ gint separator_height, bin_window_width = -1;
/* double check the row needs validating */
if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
@@ -5701,6 +5777,9 @@ validate_row (GtkTreeView *tree_view,
is_separator = row_is_separator (tree_view, iter, NULL);
+ if (tree_view->priv->bin_window)
+ gdk_drawable_get_size (tree_view->priv->bin_window, &bin_window_width, NULL);
+
gtk_widget_style_get (GTK_WIDGET (tree_view),
"focus-padding", &focus_pad,
"focus-line-width", &focus_line_width,
@@ -5728,12 +5807,15 @@ validate_row (GtkTreeView *tree_view,
first_column = first_column->next)
;
+ /* Start by calculating the overall width of the row */
for (list = tree_view->priv->columns; list; list = list->next)
{
- gint tmp_width;
- gint tmp_height;
+ GtkTreeViewColumnPrivate *column_priv;
+ gint minimum_width, natural_width;
+ gint padding;
column = list->data;
+ column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
if (! column->visible)
continue;
@@ -5741,51 +5823,84 @@ validate_row (GtkTreeView *tree_view,
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
continue;
+ /* First time around setup the cell data for each column */
gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
node->children?TRUE:FALSE);
- gtk_tree_view_column_cell_get_size (column,
- NULL, NULL, NULL,
- &tmp_width, &tmp_height);
- if (!is_separator)
- {
- tmp_height += vertical_separator;
- height = MAX (height, tmp_height);
- height = MAX (height, tree_view->priv->expander_size);
- }
- else
- {
- if (wide_separators)
- height = separator_height + 2 * focus_pad;
- else
- height = 2 + 2 * focus_pad;
- }
+ gtk_tree_view_column_get_natural_width (column, &minimum_width, &natural_width);
if (gtk_tree_view_is_expander_column (tree_view, column))
{
- tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
+ padding = horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
- tmp_width += depth * tree_view->priv->expander_size;
+ padding += depth * tree_view->priv->expander_size;
}
else
- tmp_width = tmp_width + horizontal_separator;
+ padding = horizontal_separator;
if (draw_vgrid_lines)
{
- if (list->data == first_column || list->data == last_column)
- tmp_width += grid_line_width / 2.0;
+ if (list->data == first_column || list == last_column)
+ padding += grid_line_width / 2.0;
else
- tmp_width += grid_line_width;
+ padding += grid_line_width;
}
- if (tmp_width > column->requested_width)
+ minimum_width += padding;
+ natural_width += padding;
+
+ if (minimum_width > column->requested_width ||
+ natural_width > column_priv->natural_width)
{
retval = TRUE;
- column->requested_width = tmp_width;
+ column->requested_width = MAX (column->requested_width, minimum_width);
+ column_priv->natural_width = MAX (column_priv->natural_width, natural_width);
}
}
+
+ /* Finished calculating width of row, now get the height for the collective width */
+ if (!is_separator)
+ {
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ GtkTreeViewColumnPrivate *column_priv;
+ gint column_height;
+
+ column = list->data;
+ column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
+
+ if (!column->visible)
+ continue;
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
+ continue;
+
+
+ /* If we have an allocation then we need to fetch the row height for the
+ * allocated width of the column, otherwise we'll settle for the
+ * height for the minimum width for the initial request phase.
+ */
+ if (column->width > 0)
+ gtk_tree_view_column_get_height_for_width (column, column->width,
+ &column_height, NULL);
+ else
+ gtk_tree_view_column_get_height_for_width (column, column->requested_width,
+ &column_height, NULL);
+
+ column_height += vertical_separator;
+ height = MAX (height, column_height);
+ height = MAX (height, tree_view->priv->expander_size);
+ }
+ }
+ else /* row is a separator */
+ {
+ if (wide_separators)
+ height = separator_height + 2 * focus_pad;
+ else
+ height = 2 + 2 * focus_pad;
+ }
if (draw_hgrid_lines)
height += grid_line_width;
@@ -6419,8 +6534,12 @@ presize_handler_callback (gpointer data)
}
static void
-install_presize_handler (GtkTreeView *tree_view)
+install_presize_handler (GtkTreeView *tree_view,
+ gboolean content_dirty)
{
+ if (content_dirty)
+ tree_view->priv->content_size_dirty = TRUE;
+
if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
return;
@@ -6580,7 +6699,7 @@ _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
{
tree_view->priv->mark_rows_col_dirty = TRUE;
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, FALSE);
}
/*
@@ -6597,7 +6716,7 @@ _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
- _gtk_tree_view_column_cell_set_dirty (column, FALSE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, FALSE);
do_presize_handler (tree_view);
while (validate_rows (tree_view));
@@ -7725,7 +7844,7 @@ gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
tree_view->priv->fixed_height = -1;
/* force a revalidation */
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
}
else
{
@@ -7747,6 +7866,8 @@ gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
if (tree_view->priv->tree)
initialize_fixed_height_mode (tree_view);
+
+ tree_view->priv->content_size_dirty = TRUE;
}
g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
@@ -8055,7 +8176,7 @@ gtk_tree_view_style_set (GtkWidget *widget,
for (list = tree_view->priv->columns; list; list = list->next)
{
column = list->data;
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
tree_view->priv->fixed_height = -1;
@@ -8338,7 +8459,7 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
{
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
}
}
@@ -8346,9 +8467,12 @@ gtk_tree_view_row_changed (GtkTreeModel *model,
done:
if (!tree_view->priv->fixed_height_mode &&
gtk_widget_get_realized (GTK_WIDGET (tree_view)))
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
+
if (free_path)
gtk_tree_path_free (path);
+
+ tree_view->priv->content_size_dirty = TRUE;
}
static void
@@ -8461,9 +8585,11 @@ gtk_tree_view_row_inserted (GtkTreeModel *model,
gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
}
else
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
if (free_path)
gtk_tree_path_free (path);
+
+ tree_view->priv->content_size_dirty = TRUE;
}
static void
@@ -8523,8 +8649,7 @@ gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
for (list = tree_view->priv->columns; list; list = list->next)
if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
{
- GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
- _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
+ _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE, TRUE);
break;
}
}
@@ -8591,7 +8716,7 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
for (list = tree_view->priv->columns; list; list = list->next)
if (((GtkTreeViewColumn *)list->data)->visible &&
((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
- _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
+ _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE, TRUE);
/* Ensure we don't have a dangling pointer to a dead node */
ensure_unprelighted (tree_view);
@@ -10850,7 +10975,7 @@ gtk_tree_view_set_model (GtkTreeView *tree_view,
gtk_tree_path_free (path);
/* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
}
g_object_notify (G_OBJECT (tree_view), "model");
@@ -10860,6 +10985,8 @@ gtk_tree_view_set_model (GtkTreeView *tree_view,
if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+
+ tree_view->priv->content_size_dirty = TRUE;
}
/**
@@ -11058,7 +11185,7 @@ gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
column = list->data;
if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
continue;
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
dirty = TRUE;
}
@@ -11241,7 +11368,7 @@ gtk_tree_view_remove_column (GtkTreeView *tree_view,
tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
if (tmp_column->visible)
- _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE, TRUE);
}
if (tree_view->priv->n_columns == 0 &&
@@ -11311,7 +11438,7 @@ gtk_tree_view_insert_column (GtkTreeView *tree_view,
{
column = GTK_TREE_VIEW_COLUMN (list->data);
if (column->visible)
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
@@ -11719,7 +11846,7 @@ gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
tree_view->priv->scroll_to_row_align = row_align;
tree_view->priv->scroll_to_col_align = col_align;
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, FALSE);
}
else
{
@@ -12132,7 +12259,7 @@ gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
if (animate)
add_expand_collapse_timeout (tree_view, tree, node, TRUE);
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view, TRUE);
g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
if (open_all && node->children)
@@ -12243,7 +12370,7 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
if (column->visible == FALSE)
continue;
if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
if (tree_view->priv->destroy_count_func)
@@ -15671,5 +15798,103 @@ gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
return tree_view->priv->tooltip_column;
}
+
+static void
+gtk_tree_view_get_minimum_size (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ GList *tmp_list;
+
+ /* we validate some rows initially just to make sure we have some size.
+ * In practice, with a lot of static lists, this should get a good width.
+ */
+ do_validate_rows (tree_view, FALSE);
+ gtk_tree_view_size_request_columns (tree_view);
+ gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
+
+ requisition->width = tree_view->priv->width;
+ requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
+
+ tmp_list = tree_view->priv->children;
+
+ while (tmp_list)
+ {
+ GtkTreeViewChild *child = tmp_list->data;
+ GtkRequisition child_requisition;
+
+ tmp_list = tmp_list->next;
+
+ if (gtk_widget_get_visible (child->widget))
+ gtk_widget_size_request (child->widget, &child_requisition);
+ }
+}
+
+static void
+gtk_tree_view_size_request_init (GtkSizeRequestIface *iface)
+{
+ iface->get_width = gtk_tree_view_get_width;
+ iface->get_height = gtk_tree_view_get_height;
+}
+
+static void
+gtk_tree_view_get_size (GtkSizeRequest *widget,
+ GtkOrientation orientation,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ GtkTreeView *tree_view;
+ gint natural_width = 0;
+ GList *column_iter;
+ GtkRequisition requisition;
+
+ tree_view = GTK_TREE_VIEW (widget);
+
+ gtk_tree_view_get_minimum_size (GTK_WIDGET (widget), &requisition);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ for (column_iter = tree_view->priv->columns; column_iter; column_iter = column_iter->next)
+ {
+ GtkTreeViewColumn *column = column_iter->data;
+
+ if (!column->visible)
+ continue;
+
+ natural_width += gtk_tree_view_get_real_natural_width_from_column (tree_view, column);
+ }
+
+ if (minimum_size)
+ *minimum_size = requisition.width;
+
+ if (natural_size)
+ *natural_size = MAX (requisition.width, natural_width);
+ }
+ else
+ {
+ if (minimum_size)
+ *minimum_size = requisition.height;
+
+ if (natural_size)
+ *natural_size = requisition.height;
+ }
+}
+
+static void
+gtk_tree_view_get_width (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ gtk_tree_view_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+}
+
+static void
+gtk_tree_view_get_height (GtkSizeRequest *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ gtk_tree_view_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+}
+
#define __GTK_TREE_VIEW_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index 0d953de..90b170b 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -26,9 +26,12 @@
#include "gtkbutton.h"
#include "gtkalignment.h"
#include "gtklabel.h"
+#include "gtkcellsizerequest.h"
+#include "gtksizerequest.h"
#include "gtkhbox.h"
#include "gtkmarshalers.h"
#include "gtkarrow.h"
+#include "gtkdebug.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkalias.h"
@@ -70,6 +73,7 @@ struct _GtkTreeViewColumnCellInfo
gpointer func_data;
GDestroyNotify destroy;
gint requested_width;
+ gint natural_width;
gint real_width;
guint expand : 1;
guint pack : 1;
@@ -164,6 +168,7 @@ G_DEFINE_TYPE_WITH_CODE (GtkTreeViewColumn, gtk_tree_view_column, GTK_TYPE_OBJEC
gtk_tree_view_column_buildable_init))
+
static void
gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
{
@@ -344,6 +349,8 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
G_MAXINT,
-1,
GTK_PARAM_READWRITE));
+
+ g_type_class_add_private (class, sizeof (GtkTreeViewColumnPrivate));
}
static void
@@ -370,6 +377,8 @@ gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface)
static void
gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
{
+ GtkTreeViewColumnPrivate *priv;
+
tree_column->button = NULL;
tree_column->xalign = 0.0;
tree_column->width = 0;
@@ -395,6 +404,9 @@ gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
tree_column->fixed_width = 1;
tree_column->use_resized_width = FALSE;
tree_column->title = g_strdup ("");
+
+ priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (tree_column);
+ priv->natural_width = -1;
}
static void
@@ -719,7 +731,7 @@ gtk_tree_view_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
if (tree_column->tree_view)
- _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE, TRUE);
}
static void
@@ -751,7 +763,7 @@ gtk_tree_view_column_cell_layout_set_cell_data_func (GtkCellLayout *cell
info->destroy = destroy;
if (column->tree_view)
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE, TRUE);
}
static void
@@ -814,7 +826,7 @@ gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column,
info->attributes = NULL;
if (tree_column->tree_view)
- _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE, TRUE);
}
/* Helper functions
@@ -1723,7 +1735,7 @@ gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column,
tree_column->spacing = spacing;
if (tree_column->tree_view)
- _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE, TRUE);
}
/**
@@ -1765,7 +1777,7 @@ gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
tree_column->visible = visible;
if (tree_column->visible)
- _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE, TRUE);
gtk_tree_view_column_update_button (tree_column);
g_object_notify (G_OBJECT (tree_column), "visible");
@@ -2590,14 +2602,17 @@ gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column,
*
* Obtains the width and height needed to render the column. This is used
* primarily by the #GtkTreeView.
+ *
+ * Deprecated: 3.0: Use gtk_tree_view_column_get_natural_width() and
+ * gtk_tree_view_column_get_height_for_width() instead.
**/
void
gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
const GdkRectangle *cell_area,
gint *x_offset,
gint *y_offset,
- gint *width,
- gint *height)
+ gint *width,
+ gint *height)
{
GList *list;
gboolean first_cell = TRUE;
@@ -2687,6 +2702,7 @@ gtk_tree_view_column_cell_process_action (GtkTreeViewColumn *tree_column,
/* If we have rtl text, we need to transform our areas */
GdkRectangle rtl_cell_area;
GdkRectangle rtl_background_area;
+ GtkPackType packing;
min_x = G_MAXINT;
min_y = G_MAXINT;
@@ -2764,343 +2780,186 @@ gtk_tree_view_column_cell_process_action (GtkTreeViewColumn *tree_column,
else if (extra_space > 0 && expand_cell_count > 0)
extra_space /= expand_cell_count;
- /* iterate list for GTK_PACK_START cells */
- for (list = tree_column->cell_list; list; list = list->next)
- {
- GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
-
- if (info->pack == GTK_PACK_END)
- continue;
-
- if (! info->cell->visible)
- continue;
-
- if ((info->has_focus || special_cells == 1) && cursor_row)
- flags |= GTK_CELL_RENDERER_FOCUSED;
- else
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
- info->real_width = info->requested_width + (info->expand?extra_space:0);
+ for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
+ {
- /* We constrain ourselves to only the width available */
- if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
+ for (list = tree_column->cell_list; list; list = list->next)
{
- info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
- }
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
- if (real_cell_area.x > cell_area->x + cell_area->width)
- break;
+ if (info->pack != packing)
+ continue;
- real_cell_area.width = info->real_width;
- real_cell_area.width -= 2 * focus_line_width;
+ if (! info->cell->visible)
+ continue;
- if (list->next)
- {
- real_background_area.width = info->real_width + depth;
- }
- else
- {
- /* fill the rest of background for the last cell */
- real_background_area.width = background_area->x + background_area->width - real_background_area.x;
- }
-
- rtl_cell_area = real_cell_area;
- rtl_background_area = real_background_area;
-
- if (rtl)
- {
- rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
- rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
- }
+ if ((info->has_focus || special_cells == 1) && cursor_row)
+ flags |= GTK_CELL_RENDERER_FOCUSED;
+ else
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
- /* RENDER */
- if (action == CELL_ACTION_RENDER)
- {
- gtk_cell_renderer_render (info->cell,
- window,
- tree_column->tree_view,
- &rtl_background_area,
- &rtl_cell_area,
- &real_expose_area,
- flags);
- }
- /* FOCUS */
- else if (action == CELL_ACTION_FOCUS)
- {
- gint x_offset, y_offset, width, height;
+ /* We constrain ourselves to only the width available */
+ if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
+ {
+ info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
+ }
+
+ /* Break out of the inner loop once we itterate out of our allocation
+ * (and possibly start the other packing direction) */
+ if (real_cell_area.x > cell_area->x + cell_area->width)
+ break;
- gtk_cell_renderer_get_size (info->cell,
- tree_column->tree_view,
- &rtl_cell_area,
- &x_offset, &y_offset,
- &width, &height);
+ real_cell_area.width = info->real_width;
+ real_cell_area.width -= 2 * focus_line_width;
- if (special_cells > 1)
+ if (list->next)
{
- if (info->has_focus)
- {
- min_x = rtl_cell_area.x + x_offset;
- max_x = min_x + width;
- min_y = rtl_cell_area.y + y_offset;
- max_y = min_y + height;
- }
+ real_background_area.width = info->real_width + depth;
}
else
{
- if (min_x > (rtl_cell_area.x + x_offset))
- min_x = rtl_cell_area.x + x_offset;
- if (max_x < rtl_cell_area.x + x_offset + width)
- max_x = rtl_cell_area.x + x_offset + width;
- if (min_y > (rtl_cell_area.y + y_offset))
- min_y = rtl_cell_area.y + y_offset;
- if (max_y < rtl_cell_area.y + y_offset + height)
- max_y = rtl_cell_area.y + y_offset + height;
+ /* fill the rest of background for the last cell */
+ real_background_area.width = background_area->x + background_area->width - real_background_area.x;
}
- }
- /* EVENT */
- else if (action == CELL_ACTION_EVENT)
- {
- gboolean try_event = FALSE;
-
- if (event)
+
+ rtl_cell_area = real_cell_area;
+ rtl_background_area = real_background_area;
+
+ if (rtl)
{
- if (special_cells == 1)
- {
- /* only 1 activatable cell -> whole column can activate */
- if (cell_area->x <= ((GdkEventButton *)event)->x &&
- cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
- try_event = TRUE;
- }
- else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
- rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
- /* only activate cell if the user clicked on an individual
- * cell
- */
- try_event = TRUE;
+ rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
+ rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
}
- else if (special_cells > 1 && info->has_focus)
- try_event = TRUE;
- else if (special_cells == 1)
- try_event = TRUE;
- if (try_event)
+ /* RENDER */
+ if (action == CELL_ACTION_RENDER)
{
- gboolean visible, mode;
-
- g_object_get (info->cell,
- "visible", &visible,
- "mode", &mode,
- NULL);
- if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
+ gtk_cell_renderer_render (info->cell,
+ window,
+ tree_column->tree_view,
+ &rtl_background_area,
+ &rtl_cell_area,
+ &real_expose_area,
+ flags);
+ }
+ /* FOCUS */
+ else if (action == CELL_ACTION_FOCUS)
+ {
+ gint x_offset, y_offset;
+ GtkRequisition min_size;
+
+ gtk_cell_size_request_get_size (GTK_CELL_SIZE_REQUEST (info->cell),
+ tree_column->tree_view,
+ &min_size, NULL);
+
+ _gtk_cell_renderer_calc_offset (info->cell, &rtl_cell_area,
+ gtk_widget_get_direction (tree_column->tree_view),
+ min_size.width, min_size.height, &x_offset, &y_offset);
+
+ if (special_cells > 1)
{
- if (gtk_cell_renderer_activate (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags))
+ if (info->has_focus)
{
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
- return TRUE;
+ min_x = rtl_cell_area.x + x_offset;
+ max_x = min_x + min_size.width;
+ min_y = rtl_cell_area.y + y_offset;
+ max_y = min_y + min_size.height;
}
}
- else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
+ else
{
- *editable_widget =
- gtk_cell_renderer_start_editing (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags);
-
- if (*editable_widget != NULL)
- {
- g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
- info->in_editing_mode = TRUE;
- gtk_tree_view_column_focus_cell (tree_column, info->cell);
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- return TRUE;
- }
- }
- }
- }
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
- real_background_area.x += real_background_area.width + tree_column->spacing;
-
- /* Only needed for first cell */
- depth = 0;
- }
-
- /* iterate list for PACK_END cells */
- for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
- {
- GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
-
- if (info->pack == GTK_PACK_START)
- continue;
-
- if (! info->cell->visible)
- continue;
-
- if ((info->has_focus || special_cells == 1) && cursor_row)
- flags |= GTK_CELL_RENDERER_FOCUSED;
- else
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- info->real_width = info->requested_width + (info->expand?extra_space:0);
-
- /* We constrain ourselves to only the width available */
- if (real_cell_area.x - focus_line_width + info->real_width > cell_area->x + cell_area->width)
- {
- info->real_width = cell_area->x + cell_area->width - real_cell_area.x;
- }
-
- if (real_cell_area.x > cell_area->x + cell_area->width)
- break;
-
- real_cell_area.width = info->real_width;
- real_cell_area.width -= 2 * focus_line_width;
- real_background_area.width = info->real_width + depth;
-
- rtl_cell_area = real_cell_area;
- rtl_background_area = real_background_area;
- if (rtl)
- {
- rtl_cell_area.x = cell_area->x + cell_area->width - (real_cell_area.x - cell_area->x) - real_cell_area.width;
- rtl_background_area.x = background_area->x + background_area->width - (real_background_area.x - background_area->x) - real_background_area.width;
- }
-
- /* RENDER */
- if (action == CELL_ACTION_RENDER)
- {
- gtk_cell_renderer_render (info->cell,
- window,
- tree_column->tree_view,
- &rtl_background_area,
- &rtl_cell_area,
- &real_expose_area,
- flags);
- }
- /* FOCUS */
- else if (action == CELL_ACTION_FOCUS)
- {
- gint x_offset, y_offset, width, height;
-
- gtk_cell_renderer_get_size (info->cell,
- tree_column->tree_view,
- &rtl_cell_area,
- &x_offset, &y_offset,
- &width, &height);
-
- if (special_cells > 1)
- {
- if (info->has_focus)
- {
- min_x = rtl_cell_area.x + x_offset;
- max_x = min_x + width;
- min_y = rtl_cell_area.y + y_offset;
- max_y = min_y + height;
+ if (min_x > (rtl_cell_area.x + x_offset))
+ min_x = rtl_cell_area.x + x_offset;
+ if (max_x < rtl_cell_area.x + x_offset + min_size.width)
+ max_x = rtl_cell_area.x + x_offset + min_size.width;
+ if (min_y > (rtl_cell_area.y + y_offset))
+ min_y = rtl_cell_area.y + y_offset;
+ if (max_y < rtl_cell_area.y + y_offset + min_size.height)
+ max_y = rtl_cell_area.y + y_offset + min_size.height;
}
}
- else
- {
- if (min_x > (rtl_cell_area.x + x_offset))
- min_x = rtl_cell_area.x + x_offset;
- if (max_x < rtl_cell_area.x + x_offset + width)
- max_x = rtl_cell_area.x + x_offset + width;
- if (min_y > (rtl_cell_area.y + y_offset))
- min_y = rtl_cell_area.y + y_offset;
- if (max_y < rtl_cell_area.y + y_offset + height)
- max_y = rtl_cell_area.y + y_offset + height;
- }
- }
- /* EVENT */
- else if (action == CELL_ACTION_EVENT)
- {
- gboolean try_event = FALSE;
-
- if (event)
+ /* EVENT */
+ else if (action == CELL_ACTION_EVENT)
{
- if (special_cells == 1)
- {
- /* only 1 activatable cell -> whole column can activate */
- if (cell_area->x <= ((GdkEventButton *)event)->x &&
- cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
+ gboolean try_event = FALSE;
+
+ if (event)
+ {
+ if (special_cells == 1)
+ {
+ /* only 1 activatable cell -> whole column can activate */
+ if (cell_area->x <= ((GdkEventButton *)event)->x &&
+ cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
+ try_event = TRUE;
+ }
+ else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
+ rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
+ /* only activate cell if the user clicked on an individual
+ * cell
+ */
try_event = TRUE;
}
- else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
- rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
- /* only activate cell if the user clicked on an individual
- * cell
- */
+ else if (special_cells > 1 && info->has_focus)
try_event = TRUE;
- }
- else if (special_cells > 1 && info->has_focus)
- try_event = TRUE;
- else if (special_cells == 1)
- try_event = TRUE;
-
- if (try_event)
- {
- gboolean visible, mode;
-
- g_object_get (info->cell,
- "visible", &visible,
- "mode", &mode,
- NULL);
- if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
- {
- if (gtk_cell_renderer_activate (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags))
+ else if (special_cells == 1)
+ try_event = TRUE;
+
+ if (try_event)
+ {
+ gboolean visible, mode;
+
+ g_object_get (info->cell,
+ "visible", &visible,
+ "mode", &mode,
+ NULL);
+ if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
{
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
- return TRUE;
+ if (gtk_cell_renderer_activate (info->cell,
+ event,
+ tree_column->tree_view,
+ path_string,
+ &rtl_background_area,
+ &rtl_cell_area,
+ flags))
+ {
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
+ return TRUE;
+ }
}
- }
- else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
- {
- *editable_widget =
- gtk_cell_renderer_start_editing (info->cell,
- event,
- tree_column->tree_view,
- path_string,
- &rtl_background_area,
- &rtl_cell_area,
- flags);
-
- if (*editable_widget != NULL)
+ else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
{
- g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
- info->in_editing_mode = TRUE;
- gtk_tree_view_column_focus_cell (tree_column, info->cell);
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
- return TRUE;
+ *editable_widget =
+ gtk_cell_renderer_start_editing (info->cell,
+ event,
+ tree_column->tree_view,
+ path_string,
+ &rtl_background_area,
+ &rtl_cell_area,
+ flags);
+
+ if (*editable_widget != NULL)
+ {
+ g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
+ info->in_editing_mode = TRUE;
+ gtk_tree_view_column_focus_cell (tree_column, info->cell);
+
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
+
+ return TRUE;
+ }
}
}
}
- }
-
- flags &= ~GTK_CELL_RENDERER_FOCUSED;
-
- real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
- real_background_area.x += (real_background_area.width + tree_column->spacing);
- /* Only needed for first cell */
- depth = 0;
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
+
+ real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
+ real_background_area.x += real_background_area.width + tree_column->spacing;
+
+ /* Only needed for first cell */
+ depth = 0;
+ }
}
/* fill focus_rectangle when required */
@@ -3587,19 +3446,28 @@ gtk_tree_view_column_focus_cell (GtkTreeViewColumn *tree_column,
void
_gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
+ gboolean recalculate_width,
gboolean install_handler)
{
GList *list;
+ GtkTreeViewColumnPrivate *priv;
- for (list = tree_column->cell_list; list; list = list->next)
- {
- GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
+ priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (tree_column);
- info->requested_width = 0;
- }
tree_column->dirty = TRUE;
- tree_column->requested_width = -1;
- tree_column->width = 0;
+
+ if (recalculate_width)
+ {
+ for (list = tree_column->cell_list; list; list = list->next)
+ {
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
+
+ info->requested_width = 0;
+ info->natural_width = 0;
+ }
+ tree_column->requested_width = -1;
+ priv->natural_width = -1;
+ }
if (tree_column->tree_view &&
gtk_widget_get_realized (tree_column->tree_view))
@@ -3612,6 +3480,7 @@ _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
}
}
+
void
_gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column,
GtkCellEditable *cell_editable)
@@ -3744,7 +3613,7 @@ gtk_tree_view_column_queue_resize (GtkTreeViewColumn *tree_column)
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
if (tree_column->tree_view)
- _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
+ _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE, TRUE);
}
/**
@@ -3768,5 +3637,288 @@ gtk_tree_view_column_get_tree_view (GtkTreeViewColumn *tree_column)
return tree_column->tree_view;
}
+/**
+ * gtk_tree_view_column_get_natural_width:
+ * @tree_column: A #GtkTreeViewColumn
+ * @minimum_width: location for storing the minimum width, or %NULL
+ * @natural_width: location for storing the natural width, or %NULL
+ *
+ * Retreives @tree_column's minimum and natural width.
+ *
+ * Since: 3.0
+ */
+void
+gtk_tree_view_column_get_natural_width (GtkTreeViewColumn *column,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ GList *list;
+ gboolean first_cell = TRUE;
+ gint focus_line_width;
+ gint min = 0, nat = 0;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
+
+ gtk_widget_style_get (column->tree_view, "focus-line-width", &focus_line_width, NULL);
+
+ for (list = column->cell_list; list; list = list->next)
+ {
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
+ gint cell_min, cell_nat;
+ gboolean visible;
+
+ g_object_get (info->cell, "visible", &visible, NULL);
+
+ if (visible == FALSE)
+ continue;
+
+ if (first_cell == FALSE)
+ {
+ min += column->spacing;
+ nat += column->spacing;
+ }
+
+ gtk_cell_size_request_get_width (GTK_CELL_SIZE_REQUEST (info->cell),
+ column->tree_view, &cell_min, &cell_nat);
+
+ cell_min += focus_line_width * 2;
+ cell_nat += focus_line_width * 2;
+
+ /* Store 'requested_width' and 'natural_width' to cache all the requests
+ * for every row in the column; natural space distribution is only calculated
+ * once for the whole column for now. */
+ info->requested_width = MAX (info->requested_width, cell_min);
+ info->natural_width = MAX (info->natural_width, cell_nat);
+
+ /* Return the collective minimum/natural width of all
+ * cached sizes */
+ min += info->requested_width;
+ nat += info->natural_width;
+
+ first_cell = FALSE;
+ }
+
+ if (minimum_width)
+ *minimum_width = min;
+
+ if (natural_width)
+ *natural_width = nat;
+}
+
+/**
+ * gtk_tree_view_column_get_height_for_width:
+ * @tree_column: A #GtkTreeViewColumn
+ * @width: the width available for allocation
+ * @minimum_height: location for storing the minimum height, or %NULL
+ * @natural_height: location for storing the natural height, or %NULL
+ *
+ * Retreives @tree_column's minimum and natural height if it were rendered to
+ * @widget with the specified @height.
+ *
+ * Since: 3.0
+ */
+void
+gtk_tree_view_column_get_height_for_width (GtkTreeViewColumn *column,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ GList *list;
+ GArray *array;
+ gint size = width;
+ gint focus_line_width;
+ gint expand_cell_count = 0, i;
+ gboolean first_cell = TRUE;
+ gint min_height = 0, nat_height = 0;
+ GtkRequestedSize *sizes;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
+
+ gtk_widget_style_get (column->tree_view, "focus-line-width", &focus_line_width, NULL);
+
+ array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
+
+
+ /* First get the overall expand space and collect the cell requests */
+ for (list = column->cell_list; list; list = list->next)
+ {
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
+ gboolean visible;
+ GtkRequestedSize requested;
+
+ g_object_get (info->cell, "visible", &visible, NULL);
+
+ if (visible == FALSE)
+ continue;
+
+ if (info->expand == TRUE)
+ expand_cell_count++;
+
+ if (first_cell == FALSE)
+ size -= column->spacing;
+
+ size -= focus_line_width * 2;
+ size -= info->requested_width;
+
+ /* Here the collective minimum/natural width for all rows
+ * has necessarily been cached by gtk_tree_view_column_get_natural_width().
+ *
+ * As the allocated width is based on the collective widths of all rows,
+ * the allocated width for a cell will be the same in each row.
+ *
+ * However the height-for-width must also be calculated for each
+ * row based on the aligned width in order to determine the row height.
+ *
+ * OPTIMIZE ME: It would be better to calculate the allocations of the cells once
+ * and caching an extra info->allocated_width in order to avoid this
+ * calculation for every row.
+ *
+ * Note we would use the real minimums/naturals as reported
+ * by the cells for each row here if we were to display
+ * the cells unaligned (which is more expensive to calculate
+ * but would allow cells to flow more naturally inside columns).
+ */
+ requested.data = info;
+ requested.minimum_size = info->requested_width;
+ requested.natural_size = info->natural_width;
+ g_array_append_val (array, requested);
+
+ first_cell = FALSE;
+ }
+
+
+ /* Distribute as much of remaining 'size' as possible before sharing expand space */
+ sizes = (GtkRequestedSize *)array->data;
+ size = gtk_distribute_natural_allocation (size, array->len, sizes);
+
+ /* The rest gets split up evenly among expanding cells */
+ if (expand_cell_count)
+ size /= expand_cell_count;
+
+ /* Collect the minimum and natural height for the allocations of cells */
+ for (i = 0, list = column->cell_list; list; list = list->next)
+ {
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
+ gint cell_min, cell_nat;
+ gboolean visible;
+
+ g_object_get (info->cell, "visible", &visible, NULL);
+
+ if (visible == FALSE)
+ continue;
+
+ gtk_cell_size_request_get_height_for_width (GTK_CELL_SIZE_REQUEST (info->cell),
+ column->tree_view,
+ sizes[i].minimum_size + (info->expand ? size : 0),
+ &cell_min, &cell_nat);
+
+ min_height = MAX (min_height, cell_min);
+ nat_height = MAX (nat_height, cell_nat);
+
+ i++;
+ }
+ g_array_free (array, TRUE);
+
+ if (minimum_height)
+ *minimum_height = min_height;
+
+ if (natural_height)
+ *natural_height = nat_height;
+}
+
+/**
+ * gtk_tree_view_column_allocate_width:
+ * @tree_column: A #GtkTreeViewColumn
+ * @width: the overall width of the column
+ *
+ * This allocates a good size for each cell in the column
+ * based on the overall minimum and natural widths of the
+ * cells after having been tested for each column.
+ *
+ * A width must be allocated after the request phase
+ * and before handling events
+ *
+ * Since: 3.0
+ */
+void
+gtk_tree_view_column_allocate_width (GtkTreeViewColumn *column,
+ gint width)
+{
+ GList *list;
+ GArray *array;
+ gint size = width;
+ gint focus_line_width;
+ gint expand_cell_count = 0, i;
+ gboolean first_cell = TRUE;
+ GtkRequestedSize *sizes;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
+
+ column->width = width;
+
+ gtk_widget_style_get (column->tree_view, "focus-line-width", &focus_line_width, NULL);
+
+ array = g_array_new (0, TRUE, sizeof (GtkRequestedSize));
+
+ /* First get the overall expand space and collect the cell requests */
+ for (list = column->cell_list; list; list = list->next)
+ {
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
+ gboolean visible;
+ GtkRequestedSize requested;
+
+ g_object_get (info->cell, "visible", &visible, NULL);
+
+ if (visible == FALSE)
+ continue;
+
+ if (info->expand == TRUE)
+ expand_cell_count++;
+
+ if (first_cell == FALSE)
+ size -= column->spacing;
+
+ size -= focus_line_width * 2;
+ size -= info->requested_width;
+
+ requested.data = info;
+ requested.minimum_size = info->requested_width;
+ requested.natural_size = info->natural_width;
+ g_array_append_val (array, requested);
+
+ first_cell = FALSE;
+ }
+
+ /* Distribute as much of remaining 'size' as possible before sharing expand space */
+ sizes = (GtkRequestedSize *)array->data;
+ size = gtk_distribute_natural_allocation (size, array->len, sizes);
+
+ /* The rest gets split up evenly among expanding cells */
+ if (expand_cell_count > 0)
+ size /= expand_cell_count;
+
+ /* Allocate/assign info->real_width based in minimum/natural size + expand space */
+ for (i = 0, list = column->cell_list; list; list = list->next)
+ {
+ GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
+ gboolean visible;
+
+ g_object_get (info->cell, "visible", &visible, NULL);
+
+ if (visible == FALSE)
+ continue;
+
+ info->real_width = sizes[i].minimum_size + (info->expand ? size : 0);
+
+ i++;
+ }
+ g_array_free (array, TRUE);
+
+ g_object_notify (G_OBJECT (column), "width");
+}
+
+
+
+
#define __GTK_TREE_VIEW_COLUMN_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtktreeviewcolumn.h b/gtk/gtktreeviewcolumn.h
index 4e72235..9b047eb 100644
--- a/gtk/gtktreeviewcolumn.h
+++ b/gtk/gtktreeviewcolumn.h
@@ -51,6 +51,7 @@ typedef enum
typedef struct _GtkTreeViewColumn GtkTreeViewColumn;
typedef struct _GtkTreeViewColumnClass GtkTreeViewColumnClass;
+typedef struct _GtkTreeViewColumnPrivate GtkTreeViewColumnPrivate;
typedef void (* GtkTreeCellDataFunc) (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
@@ -225,6 +226,17 @@ void gtk_tree_view_column_cell_get_size (GtkTreeViewCol
gint *y_offset,
gint *width,
gint *height);
+
+void gtk_tree_view_column_get_natural_width (GtkTreeViewColumn *column,
+ gint *minimum_width,
+ gint *natural_width);
+void gtk_tree_view_column_get_height_for_width(GtkTreeViewColumn *column,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+void gtk_tree_view_column_allocate_width (GtkTreeViewColumn *column,
+ gint width);
+
gboolean gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column);
void gtk_tree_view_column_focus_cell (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]