diff options
Diffstat (limited to 'gtk/gtktreeview.c')
-rw-r--r-- | gtk/gtktreeview.c | 653 |
1 files changed, 439 insertions, 214 deletions
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index 464842ea09..0c43d366f7 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" #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5) @@ -164,8 +166,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, @@ -298,7 +298,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, @@ -464,6 +465,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, @@ -488,7 +498,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) @@ -518,7 +531,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; @@ -1865,7 +1877,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 @@ -2033,37 +2045,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) { @@ -2172,6 +2153,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, @@ -2182,15 +2185,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) @@ -2203,25 +2214,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 @@ -2234,21 +2276,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; @@ -2258,12 +2287,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; @@ -2284,56 +2313,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, @@ -2342,7 +2358,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)); } @@ -2356,6 +2372,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; @@ -2379,11 +2396,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; @@ -2425,6 +2480,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) @@ -2500,6 +2556,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 */ @@ -4460,11 +4542,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; @@ -4506,62 +4589,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, @@ -4684,59 +4773,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 (draw_hgrid_lines) @@ -4842,7 +4914,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget, flags); } - cell_offset += column->width; + cell_offset += background_area.width; } if (node == drag_highlight) @@ -4964,6 +5036,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) { @@ -5716,7 +5792,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) && @@ -5725,6 +5801,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, @@ -5752,12 +5831,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; @@ -5765,51 +5847,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; @@ -6443,8 +6558,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; @@ -6604,7 +6723,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); } /* @@ -6621,7 +6740,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)); @@ -7749,7 +7868,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 { @@ -7771,6 +7890,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"); @@ -8079,7 +8200,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; @@ -8362,7 +8483,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); } } } @@ -8370,9 +8491,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 @@ -8485,9 +8609,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 @@ -8547,8 +8673,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; } } @@ -8615,7 +8740,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); @@ -10883,7 +11008,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"); @@ -10893,6 +11018,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; } /** @@ -11091,7 +11218,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; } @@ -11274,7 +11401,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 && @@ -11344,7 +11471,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)); } @@ -11752,7 +11879,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 { @@ -12165,7 +12292,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) @@ -12276,7 +12403,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) @@ -15708,3 +15835,101 @@ 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); +} |