? docs/reference/gtk/tmpl/gtkaccelmap.sgml ? docs/reference/gtk/tmpl/gtkaccessible.sgml ? docs/reference/gtk/tmpl/gtkpacker.sgml ? gtk/foo.ps ? gtk/out ? tests/festival_server ? tests/festival_server.scm ? tests/festival_sleep_pid ? tests/festival_wrapper_pid Index: demos/gtk-demo/main.c =================================================================== RCS file: /cvs/gnome/gtk+/demos/gtk-demo/main.c,v retrieving revision 1.36 diff -u -r1.36 main.c --- demos/gtk-demo/main.c 2001/11/25 23:36:29 1.36 +++ demos/gtk-demo/main.c 2001/11/30 21:53:09 @@ -673,7 +673,8 @@ Demo *d = testgtk_demos; model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN); - tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); + tree_view = gtk_tree_view_new (); + gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model)); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection), @@ -739,7 +740,6 @@ g_signal_connect (tree_view, "row_activated", G_CALLBACK (row_activated_cb), model); gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view)); - return tree_view; } Index: docs/tree-column-sizing.txt =================================================================== RCS file: /cvs/gnome/gtk+/docs/tree-column-sizing.txt,v retrieving revision 1.2 diff -u -r1.2 tree-column-sizing.txt --- docs/tree-column-sizing.txt 2001/09/25 16:44:37 1.2 +++ docs/tree-column-sizing.txt 2001/11/30 21:53:09 @@ -1,67 +1,67 @@ The way that the GtkTreeView calculates sizing is pretty confusing. This is written down to help keep track of it in my head, and thus help anyone who hopes to work with the code in the future. +-jrb HOW THE GTKTREEVIEW CALCULATES SIZE: ==================================== -When the view is given a new model, the first thing it does is walk + When the view is given a new model, the first thing it does is walk through the model at the top level, creating an GtkRBNode for each element of the model. Each node has a height of 0. The RBTree is kept updated as the models structure changes. Additionally, the user can expand, collapse, and select rows at this stage. The RBTree is accurate --- it just doesn't have a height for any row. +-- it just has a height of zero for every row. -When the TreeView is realized, it calculates the actual height of each -row by walking the tree and measuring them. While doing so, it gets the -size of each column. +When the widget is realized, it calls install_presize_handler, to setup +the first-run function. This is run before the expose event. - - -Columns are initially marked as 'dirty'. When sized, -gtk_tree_view_check_dirty_and_clean () is called on each column. This -function walks through all visible columns, and sees if they're dirty or -not. If any are dirty, it then walks the tree, calling -gtk_tree_view_calc_size on each row. gtk_tree_view_calc_size requests -the size of every dirty column in the tree. Finally, it updates the -size of the widget (including adjustments). - - HOW THE GTKTREEVIEWCOLUMN STORES SIZE: ====================================== There are a number of size related fields in the GtkTreeViewColumn structure. These are all valid after realization: - sizing The sizing method to use when calculating the size - of the column. Can be grow_only, resizable, auto, and fixed. + column_type The sizing method to use when calculating the size + of the column. Can be GROW_ONLY, AUTO, and FIXED. - requested_width The width of the column as requested by the column + requested_width The width of the column as requested by the column. + It is the max requested width of the bcells in the + column. If the column_type is AUTO, then it is + recalculated when a column changes. Otherwise, it + only grows. - width The actual width. This is requested width for all - columns but possibly the last one. + width The actual width of the column as displayed. fixed_width The requested fixed width for the column iff it's sizing type is set to GTK_TREE_VIEW_COLUMN_FIXED. + Used instead of requested_width in that case. - min_width The minimum width the column can be + min_width The minimum width the column can be. If set to -1, + this field is considered unset. max_width The maximum width the column can be. This can be overridden for the last column, if the tree_view is actually wider than the sum of all of the columns - requested_widths. + requested_widths. If set to -1, this field is + considered unset. +-- +tree_view->priv->width = the width the widget wants to be, including headers. +tree_view->priv->height = the height the widget requests. It's the sum + of the width of all visible columns. + +Both of these are calculated in _gtk_tree_view_update_size +-- + The following invariants are true: min_width is less than or equal to width max_width is greater than or equal to width -(sizing == GTK_TREE_VIEW_COLUMN_FIXED) => (requested_width == fixed_width) +min_width <= max_width -(column != last visible column) => width == requested_width +(sizing == GTK_TREE_VIEW_COLUMN_FIXED) => (requested_width == fixed_width) +(column != last visible column) => width == CLAMP (requested_width, min_width, max_width) -/* Functions needed by gtktreeview for gtktreeviewcolumn */ -size_request_button -set_width (for resizing resizable columns) -calculate_width Index: gtk/gtkrbtree.c =================================================================== RCS file: /cvs/gnome/gtk+/gtk/gtkrbtree.c,v retrieving revision 1.15 diff -u -r1.15 gtkrbtree.c --- gtk/gtkrbtree.c 2001/11/02 21:47:27 1.15 +++ gtk/gtkrbtree.c 2001/11/30 21:53:09 @@ -571,9 +571,10 @@ GtkRBNode * -_gtk_rbtree_insert_after (GtkRBTree *tree, - GtkRBNode *current, - gint height) +_gtk_rbtree_insert_after (GtkRBTree *tree, + GtkRBNode *current, + gint height, + gboolean valid) { GtkRBNode *node; gboolean right = TRUE; @@ -632,14 +633,20 @@ if (gtk_debug_flags & GTK_DEBUG_TREE) _gtk_rbtree_test (G_STRLOC, tree); - + + if (valid) + _gtk_rbtree_node_mark_valid (tree, node); + else + _gtk_rbtree_node_mark_invalid (tree, node); + return node; } GtkRBNode * -_gtk_rbtree_insert_before (GtkRBTree *tree, - GtkRBNode *current, - gint height) +_gtk_rbtree_insert_before (GtkRBTree *tree, + GtkRBNode *current, + gint height, + gboolean valid) { GtkRBNode *node; gboolean left = TRUE; @@ -698,7 +705,12 @@ if (gtk_debug_flags & GTK_DEBUG_TREE) _gtk_rbtree_test (G_STRLOC, tree); - + + if (valid) + _gtk_rbtree_node_mark_valid (tree, node); + else + _gtk_rbtree_node_mark_invalid (tree, node); + return node; } @@ -775,18 +787,22 @@ _gtk_rbtree_node_mark_valid (GtkRBTree *tree, GtkRBNode *node) { - if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)) + if ((!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)) && + (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))) return; GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_INVALID); + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_COLUMN_INVALID); + do { - if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) || + if ((GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)) || + (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)) || (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)) || - (node->left && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) || - (node->right && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))) + (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) || + (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))) return; - + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID); node = node->parent; if (node == NULL) @@ -798,6 +814,32 @@ while (node); } + +/* Assume tree is the root node as it doesn't set DESCENDANTS_INVALID above. + */ +void +_gtk_rbtree_column_invalid (GtkRBTree *tree) +{ + GtkRBNode *node; + + node = tree->root; + g_assert (node); + + while (node->left != tree->nil) + node = node->left; + + do + { + if (! (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))) + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_COLUMN_INVALID); + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID); + + if (node->children) + _gtk_rbtree_column_invalid (node->children); + } + while ((node = _gtk_rbtree_next (tree, node)) != NULL); +} + typedef struct _GtkRBReorder { GtkRBTree *children; @@ -849,6 +891,14 @@ node->offset += node->children->root->offset; node->parity += node->children->root->parity; } + + if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) || + (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) || + (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) || + (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID))) + GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID); + else + GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID); } /* It basically pulls everything out of the tree, rearranges it, and puts it @@ -990,19 +1040,23 @@ } gint -_gtk_rbtree_find_offset (GtkRBTree *tree, - gint height, - GtkRBTree **new_tree, - GtkRBNode **new_node) +_gtk_rbtree_real_find_offset (GtkRBTree *tree, + gint height, + GtkRBTree **new_tree, + GtkRBNode **new_node) { GtkRBNode *tmp_node; + g_assert (tree); + if (height < 0) { *new_tree = NULL; *new_node = NULL; + return 0; } + tmp_node = tree->root; while (tmp_node != tree->nil && @@ -1033,20 +1087,40 @@ *new_node = tmp_node; return (height - tmp_node->left->offset); } - return _gtk_rbtree_find_offset (tmp_node->children, - height - tmp_node->left->offset - - (tmp_node->offset - - tmp_node->left->offset - - tmp_node->right->offset - - tmp_node->children->root->offset), - new_tree, - new_node); + return _gtk_rbtree_real_find_offset (tmp_node->children, + height - tmp_node->left->offset - + (tmp_node->offset - + tmp_node->left->offset - + tmp_node->right->offset - + tmp_node->children->root->offset), + new_tree, + new_node); } *new_tree = tree; *new_node = tmp_node; return (height - tmp_node->left->offset); } +gint +_gtk_rbtree_find_offset (GtkRBTree *tree, + gint height, + GtkRBTree **new_tree, + GtkRBNode **new_node) +{ + GtkRBNode *tmp_node; + + g_assert (tree); + + if ((height < 0) || + (height >= tree->root->offset)) + { + *new_tree = NULL; + *new_node = NULL; + + return 0; + } + _gtk_rbtree_real_find_offset (tree, height, new_tree, new_node); +} void _gtk_rbtree_remove_node (GtkRBTree *tree, @@ -1068,7 +1142,6 @@ if (gtk_debug_flags & GTK_DEBUG_TREE) _gtk_rbtree_test (G_STRLOC, tree); - if (node->left == tree->nil || node->right == tree->nil) { Index: gtk/gtkrbtree.h =================================================================== RCS file: /cvs/gnome/gtk+/gtk/gtkrbtree.h,v retrieving revision 1.10 diff -u -r1.10 gtkrbtree.h --- gtk/gtkrbtree.h 2001/10/25 20:32:40 1.10 +++ gtk/gtkrbtree.h 2001/11/30 21:53:09 @@ -37,8 +37,16 @@ GTK_RBNODE_IS_SEMI_COLLAPSED = 1 << 5, GTK_RBNODE_IS_SEMI_EXPANDED = 1 << 6, GTK_RBNODE_INVALID = 1 << 7, - GTK_RBNODE_DESCENDANTS_INVALID = 1 << 8, - GTK_RBNODE_NON_COLORS = GTK_RBNODE_IS_PARENT | GTK_RBNODE_IS_SELECTED | GTK_RBNODE_IS_PRELIT | GTK_RBNODE_IS_SEMI_COLLAPSED | GTK_RBNODE_IS_SEMI_EXPANDED | GTK_RBNODE_INVALID | GTK_RBNODE_DESCENDANTS_INVALID + GTK_RBNODE_COLUMN_INVALID = 1 << 8, + GTK_RBNODE_DESCENDANTS_INVALID = 1 << 9, + GTK_RBNODE_NON_COLORS = GTK_RBNODE_IS_PARENT | + GTK_RBNODE_IS_SELECTED | + GTK_RBNODE_IS_PRELIT | + GTK_RBNODE_IS_SEMI_COLLAPSED | + GTK_RBNODE_IS_SEMI_EXPANDED | + GTK_RBNODE_INVALID | + GTK_RBNODE_COLUMN_INVALID | + GTK_RBNODE_DESCENDANTS_INVALID } GtkRBNodeColor; typedef struct _GtkRBTree GtkRBTree; @@ -93,6 +101,7 @@ GtkRBTree *children; }; + #define GTK_RBNODE_GET_COLOR(node) (node?(((node->flags>K_RBNODE_RED)==GTK_RBNODE_RED)?GTK_RBNODE_RED:GTK_RBNODE_BLACK):GTK_RBNODE_BLACK) #define GTK_RBNODE_SET_COLOR(node,color) if((node->flags&color)!=color)node->flags=node->flags^(GTK_RBNODE_RED|GTK_RBNODE_BLACK) #define GTK_RBNODE_GET_HEIGHT(node) (node->offset-(node->left->offset+node->right->offset+(node->children?node->children->root->offset:0))) @@ -109,10 +118,12 @@ void _gtk_rbtree_destroy (GtkRBTree *tree); GtkRBNode *_gtk_rbtree_insert_before (GtkRBTree *tree, GtkRBNode *node, - gint height); + gint height, + gboolean valid); GtkRBNode *_gtk_rbtree_insert_after (GtkRBTree *tree, GtkRBNode *node, - gint height); + gint height, + gboolean valid); void _gtk_rbtree_remove_node (GtkRBTree *tree, GtkRBNode *node); void _gtk_rbtree_reorder (GtkRBTree *tree, @@ -127,6 +138,7 @@ GtkRBNode *node); void _gtk_rbtree_node_mark_valid (GtkRBTree *tree, GtkRBNode *node); +void _gtk_rbtree_column_invalid (GtkRBTree *tree); gint _gtk_rbtree_node_find_offset (GtkRBTree *tree, GtkRBNode *node); gint _gtk_rbtree_node_find_parity (GtkRBTree *tree, Index: gtk/gtktreemodel.c =================================================================== RCS file: /cvs/gnome/gtk+/gtk/gtktreemodel.c,v retrieving revision 1.68 diff -u -r1.68 gtktreemodel.c --- gtk/gtktreemodel.c 2001/11/24 17:32:27 1.68 +++ gtk/gtktreemodel.c 2001/11/30 21:53:09 @@ -1093,6 +1093,16 @@ g_signal_emit_by_name (tree_model, "row_has_child_toggled", path, iter); } +/** + * gtk_tree_model_row_deleted: + * @tree_model: A #GtkTreeModel + * @path: A #GtkTreePath pointing to the previous location of the deleted row. + * + * Emits the "row_deleted" signal on @tree_model. This should be called by + * models after a row has been removed. The location pointed to by @path should + * be the location that the row previously was at. It may not be a valid + * location anymore. + **/ void gtk_tree_model_row_deleted (GtkTreeModel *tree_model, GtkTreePath *path) Index: gtk/gtktreeprivate.h =================================================================== RCS file: /cvs/gnome/gtk+/gtk/gtktreeprivate.h,v retrieving revision 1.35 diff -u -r1.35 gtktreeprivate.h --- gtk/gtktreeprivate.h 2001/11/21 22:08:09 1.35 +++ gtk/gtktreeprivate.h 2001/11/30 21:53:09 @@ -28,8 +28,6 @@ #include #include #include - - #define TREE_VIEW_DRAG_WIDTH 6 @@ -53,11 +51,12 @@ DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3, DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4 }; + #define GTK_TREE_VIEW_SET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags|=flag); }G_STMT_END #define GTK_TREE_VIEW_UNSET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags&=~(flag)); }G_STMT_END #define GTK_TREE_VIEW_FLAG_SET(tree_view, flag) ((tree_view->priv->flags&flag)==flag) #define TREE_VIEW_HEADER_HEIGHT(tree_view) (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE)?tree_view->priv->header_height:0) -#define TREE_VIEW_COLUMN_WIDTH(column) (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width)) +#define TREE_VIEW_COLUMN_REQUESTED_WIDTH(column) (CLAMP (column->requested_width, (column->min_width!=-1)?column->min_width:column->requested_width, (column->max_width!=-1)?column->max_width:column->requested_width)) #define TREE_VIEW_DRAW_EXPANDERS(tree_view) (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST)&>K_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS)) /* This lovely little value is used to determine how far away from the title bar @@ -108,6 +107,8 @@ GtkTreeViewColumn *expander_column; GtkTreeViewColumn *edited_column; + guint presize_handler_timer; + guint validate_rows_timer; /* Focus code */ GtkTreeViewColumn *focus_column; @@ -118,7 +119,6 @@ /* Column Resizing */ GdkCursor *cursor_drag; - GdkGC *xor_gc; gint drag_pos; gint x_drag; @@ -184,8 +184,6 @@ GtkDestroyNotify search_destroy; }; -#ifdef __GNUC__ - #define TREE_VIEW_INTERNAL_ASSERT(expr, ret) G_STMT_START{ \ if (!(expr)) \ { \ @@ -203,7 +201,7 @@ return ret; \ }; }G_STMT_END -#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr) G_STMT_START{ \ +#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr) G_STMT_START{ \ if (!(expr)) \ { \ g_log (G_LOG_DOMAIN, \ @@ -220,41 +218,6 @@ return; \ }; }G_STMT_END -#else - -#define TREE_VIEW_INTERNAL_ASSERT(expr, ret) G_STMT_START{ \ - if (!(expr)) \ - { \ - g_log (G_LOG_DOMAIN, \ - G_LOG_LEVEL_CRITICAL, \ - "file %s: line %d: assertion `%s' failed.\n" \ - "There is a disparity between the internal view of the GtkTreeView,\n" \ - "and the GtkTreeModel. This generally means that the model has changed\n"\ - "without letting the view know. Any display from now on is likely to\n" \ - "be incorrect.\n", \ - __FILE__, \ - __LINE__, \ - #expr); \ - return ret; \ - }; }G_STMT_END - -#define TREE_VIEW_INTERNAL_ASSERT_VOID(expr) G_STMT_START{ \ - if (!(expr)) \ - { \ - g_log (G_LOG_DOMAIN, \ - G_LOG_LEVEL_CRITICAL, \ - "file %s: line %d: assertion '%s' failed.\n" \ - "There is a disparity between the internal view of the GtkTreeView,\n" \ - "and the GtkTreeModel. This generally means that the model has changed\n"\ - "without letting the view know. Any display from now on is likely to\n" \ - "be incorrect.\n", \ - __FILE__, \ - __LINE__, \ - #expr); \ - return; \ - }; }G_STMT_END -#endif - /* functions that shouldn't be exported */ void _gtk_tree_selection_internal_select_node (GtkTreeSelection *selection, @@ -269,7 +232,6 @@ GtkTreePath *_gtk_tree_view_find_path (GtkTreeView *tree_view, GtkRBTree *tree, GtkRBNode *node); -void _gtk_tree_view_update_size (GtkTreeView *tree_view); void _gtk_tree_view_child_move_resize (GtkTreeView *tree_view, GtkWidget *widget, gint x, Index: gtk/gtktreeview.c =================================================================== RCS file: /cvs/gnome/gtk+/gtk/gtktreeview.c,v retrieving revision 1.175 diff -u -r1.175 gtktreeview.c --- gtk/gtktreeview.c 2001/11/19 21:18:21 1.175 +++ gtk/gtktreeview.c 2001/11/30 21:53:09 @@ -40,7 +40,8 @@ #include #define GTK_TREE_VIEW_SEARCH_DIALOG_KEY "gtk-tree-view-search-dialog" - +#define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5) +#define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 50 #define SCROLL_EDGE_SIZE 15 #define EXPANDER_EXTRA_PADDING 4 @@ -249,6 +250,16 @@ gint *new_order, gpointer data); +/* Incremental reflow */ +static gboolean validate_row (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node, + GtkTreeIter *iter, + GtkTreePath *path); +static void validate_visible_area (GtkTreeView *tree_view); +static gboolean validate_rows_handler (GtkTreeView *tree_view); +static gboolean presize_handler_callback (gpointer data); +static void install_presize_handler (GtkTreeView *tree_view); /* Internal functions */ @@ -286,20 +297,11 @@ gint *x); static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment, GtkTreeView *tree_view); -static gint gtk_tree_view_insert_iter_height (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth); static void gtk_tree_view_build_tree (GtkTreeView *tree_view, GtkRBTree *tree, GtkTreeIter *iter, gint depth, - gboolean recurse, - gboolean calc_bounds); -static void gtk_tree_view_calc_size (GtkTreeView *priv, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth); + gboolean recurse); static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view, GtkTreeIter *iter, gint depth, @@ -309,7 +311,6 @@ GtkRBTree *tree, GtkTreeIter *iter, gint depth); -static void gtk_tree_view_check_dirty_and_clean (GtkTreeView *tree_view); static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view, GtkRBTree *tree, GtkRBNode *node); @@ -317,7 +318,6 @@ GtkTreeViewColumn *column); static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view, GdkEventMotion *event); -static void _gtk_tree_view_update_col_width (GtkTreeView *tree_view); static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view); static void gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view, gint count); @@ -908,9 +908,9 @@ tree_view->priv->press_start_x = -1; tree_view->priv->press_start_y = -1; tree_view->priv->reorderable = FALSE; + tree_view->priv->presize_handler_timer = 0; gtk_tree_view_set_adjustments (tree_view, NULL, NULL); tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view); - _gtk_tree_view_update_size (tree_view); tree_view->priv->enable_search = TRUE; tree_view->priv->search_column = -1; tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func; @@ -969,10 +969,10 @@ } static void -gtk_tree_view_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +gtk_tree_view_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { GtkTreeView *tree_view; @@ -1207,7 +1207,6 @@ tree_view = GTK_TREE_VIEW (widget); - gtk_tree_view_check_dirty_and_clean (GTK_TREE_VIEW (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); /* Make the main, clipping window */ @@ -1267,11 +1266,7 @@ widget->style->black:widget->style->white); values.function = GDK_XOR; values.subwindow_mode = GDK_INCLUDE_INFERIORS; - tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window, - &values, - GDK_GC_FOREGROUND | - GDK_GC_FUNCTION | - GDK_GC_SUBWINDOW); + /* Add them all up. */ widget->style = gtk_style_attach (widget->style, widget->window); gdk_window_set_background (widget->window, &widget->style->base[widget->state]); @@ -1290,9 +1285,9 @@ for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next) _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)); - _gtk_tree_view_update_size (GTK_TREE_VIEW (widget)); + install_presize_handler (tree_view); -if (GTK_WIDGET_CLASS (parent_class)->map) + if (GTK_WIDGET_CLASS (parent_class)->map) (* GTK_WIDGET_CLASS (parent_class)->map) (widget); } @@ -1323,6 +1318,12 @@ gtk_timeout_remove (tree_view->priv->expand_collapse_timeout); tree_view->priv->expand_collapse_timeout = 0; } + + if (tree_view->priv->presize_handler_timer != 0) + { + gtk_timeout_remove (tree_view->priv->presize_handler_timer); + tree_view->priv->presize_handler_timer = 0; + } for (list = tree_view->priv->columns; list; list = list->next) _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data)); @@ -1355,12 +1356,6 @@ tree_view->priv->cursor_drag = NULL; } - if (tree_view->priv->xor_gc) - { - gdk_gc_destroy (tree_view->priv->xor_gc); - tree_view->priv->xor_gc = NULL; - } - /* GtkWidget::unrealize destroys children and widget->window */ if (GTK_WIDGET_CLASS (parent_class)->unrealize) (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); @@ -1368,11 +1363,11 @@ /* GtkWidget::size_request helper */ static void -gtk_tree_view_size_request_buttons (GtkTreeView *tree_view) +gtk_tree_view_size_request_columns (GtkTreeView *tree_view) { GList *list; - tree_view->priv->header_height = 1; + tree_view->priv->header_height = 0; if (tree_view->priv->model) { @@ -1385,15 +1380,66 @@ continue; column = list->data; - + gtk_widget_size_request (column->button, &requisition); - - _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width)); + column->button_request = requisition.width; tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height); } } } + +static void +gtk_tree_view_update_size (GtkTreeView *tree_view) +{ + GList *list; + GtkTreeViewColumn *column; + gint i; + + if (tree_view->priv->model == NULL) + { + tree_view->priv->width = 0; + tree_view->priv->height = 0; + return; + } + + tree_view->priv->width = 0; + /* keep this in sync with size_allocate below */ + for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++) + { + gint real_requested_width = 0; + column = list->data; + if (!column->visible) + continue; + + if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED) + { + real_requested_width = column->fixed_width; + } + else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE)) + { + real_requested_width = MAX (column->requested_width, column->button_request); + } + else + { + real_requested_width = column->requested_width; + } + + if (column->min_width != -1) + real_requested_width = MAX (real_requested_width, column->min_width); + if (column->max_width != -1) + real_requested_width = MIN (real_requested_width, column->max_width); + + tree_view->priv->width += real_requested_width; + } + + if (tree_view->priv->tree == NULL) + tree_view->priv->height = 0; + else + tree_view->priv->height = tree_view->priv->tree->root->offset; + +} + static void gtk_tree_view_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -1405,7 +1451,8 @@ tree_view = GTK_TREE_VIEW (widget); - gtk_tree_view_size_request_buttons (tree_view); + 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->priv->header_height; @@ -1426,31 +1473,62 @@ /* GtkWidget::size_allocate helper */ static void -gtk_tree_view_size_allocate_buttons (GtkWidget *widget) +gtk_tree_view_size_allocate_columns (GtkWidget *widget) { GtkTreeView *tree_view; - GList *list; + GList *list, *last_column; GtkTreeViewColumn *column; GtkAllocation allocation; gint width = 0; tree_view = GTK_TREE_VIEW (widget); + 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) + ; + if (last_column == NULL) + return; + allocation.y = 0; allocation.height = tree_view->priv->header_height; - for (list = tree_view->priv->columns; list != NULL; list = list->next) + for (list = tree_view->priv->columns; list != last_column->next; list = list->next) { + gint real_requested_width = 0; column = list->data; - if (!column->visible) continue; + if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED) + { + real_requested_width = column->fixed_width; + } + else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE)) + { + real_requested_width = MAX (column->requested_width, column->button_request); + } + else + { + real_requested_width = column->requested_width; + } + + if (column->min_width != -1) + real_requested_width = MAX (real_requested_width, column->min_width); + if (column->max_width != -1) + real_requested_width = MIN (real_requested_width, column->max_width); + allocation.x = width; + column->width = real_requested_width; + if (list == last_column && + width + real_requested_width < widget->allocation.width) + { + column->width += (widget->allocation.width - column->width - width); + } + g_object_notify (G_OBJECT (column), "width"); allocation.width = column->width; width += column->width; gtk_widget_size_allocate (column->button, &allocation); - if (column->window) gdk_window_move_resize (column->window, allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2, @@ -1472,8 +1550,6 @@ tree_view = GTK_TREE_VIEW (widget); - gtk_tree_view_check_dirty_and_clean (tree_view); - tmp_list = tree_view->priv->children; while (tmp_list) @@ -1500,12 +1576,11 @@ MAX (tree_view->priv->width, allocation->width), tree_view->priv->header_height); gdk_window_resize (tree_view->priv->bin_window, - tree_view->priv->width, + MAX (tree_view->priv->width, allocation->width), allocation->height); - _gtk_tree_view_update_col_width (tree_view); } - gtk_tree_view_size_allocate_buttons (widget); + gtk_tree_view_size_allocate_columns (widget); tree_view->priv->hadjustment->page_size = allocation->width; tree_view->priv->hadjustment->page_increment = allocation->width; @@ -1544,7 +1619,6 @@ } tree_view->priv->scroll_to_column = NULL; } - } static gboolean @@ -2280,8 +2354,7 @@ if (x != GTK_TREE_VIEW (widget)->priv->x_drag) _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width); - /* FIXME: Do we need to scroll */ - _gtk_tree_view_update_size (GTK_TREE_VIEW (widget)); + gtk_widget_queue_resize (widget); return FALSE; } @@ -2518,10 +2591,10 @@ if (event->area.height < 0) return TRUE; } - - gtk_tree_view_check_dirty_and_clean (GTK_TREE_VIEW (widget)); - new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->area.y); + validate_visible_area (tree_view); + + new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y); if (new_y < 0) new_y = 0; y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node); @@ -3027,40 +3100,306 @@ gtk_tree_view_search_dialog_destroy (search_dialog, GTK_TREE_VIEW (widget)); return FALSE; } + + +/* Incremental Reflow + */ + +/* Returns TRUE if it updated the size + */ +static gboolean +validate_row (GtkTreeView *tree_view, + GtkRBTree *tree, + GtkRBNode *node, + GtkTreeIter *iter, + GtkTreePath *path) +{ + GtkTreeViewColumn *column; + GList *list; + gint height = 0; + gint horizontal_separator; + gint depth = gtk_tree_path_get_depth (path); + gboolean retval = FALSE; + + + /* double check the row needs validating */ + if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) && + ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)) + return FALSE; + + gtk_widget_style_get (GTK_WIDGET (tree_view), + "horizontal_separator", &horizontal_separator, + NULL); + + for (list = tree_view->priv->columns; list; list = list->next) + { + gint tmp_width; + gint tmp_height; + + column = list->data; + + if (! column->visible) + continue; + + if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty) + continue; + + if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED) + continue; + + 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); + height = MAX (height, tmp_height); + + if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view)) + tmp_width = tmp_width + horizontal_separator + depth * tree_view->priv->tab_offset; + else + tmp_width = tmp_width + horizontal_separator; + + if (tmp_width > column->requested_width) + { + retval = TRUE; + column->requested_width = tmp_width; + } + } + + if (height != GTK_RBNODE_GET_HEIGHT (node)) + { + retval = TRUE; + _gtk_rbtree_node_set_height (tree, node, height); + } + _gtk_rbtree_node_mark_valid (tree, node); + + return retval; +} -/* Incremental Reflow */ static void validate_visible_area (GtkTreeView *tree_view) { + GtkTreePath *path; + GtkTreeIter iter; + GtkRBTree *tree; + GtkRBNode *node; + gint y, height, offset; + gboolean validated_area = FALSE; + + + if (tree_view->priv->tree == NULL) + return; + + if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID)) + return; + + + height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view); + + y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, TREE_VIEW_HEADER_HEIGHT (tree_view)); + + offset = _gtk_rbtree_find_offset (tree_view->priv->tree, y, + &tree, &node); + if (node == NULL) + { + path = gtk_tree_path_new_root (); + _gtk_tree_view_find_node (tree_view, path, &tree, &node); + } + else + { + path = _gtk_tree_view_find_path (tree_view, tree, node); + height += offset; + } + + gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); + do + { + validated_area = validate_row (tree_view, tree, node, &iter, path) || validated_area; + height -= GTK_RBNODE_GET_HEIGHT (node); + if (node->children) + { + GtkTreeIter parent = iter; + gboolean has_child; + + tree = node->children; + node = tree->root; + + g_assert (node != tree->nil); + + while (node->left != tree->nil) + node = node->left; + has_child = gtk_tree_model_iter_children (tree_view->priv->model, + &iter, + &parent); + TREE_VIEW_INTERNAL_ASSERT_VOID (has_child); + gtk_tree_path_append_index (path, 0); + } + else + { + gboolean done = FALSE; + do + { + node = _gtk_rbtree_next (tree, node); + if (node != NULL) + { + gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter); + done = TRUE; + + /* Sanity Check! */ + TREE_VIEW_INTERNAL_ASSERT_VOID (has_next); + } + else + { + GtkTreeIter parent_iter = iter; + gboolean has_parent; + + node = tree->parent_node; + tree = tree->parent_tree; + if (tree == NULL) + break; + has_parent = gtk_tree_model_iter_parent (tree_view->priv->model, + &iter, + &parent_iter); + /* Sanity check */ + TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent); + } + } + while (!done); + } + } + while (node && height > 0); + + if (validated_area) + gtk_widget_queue_resize (GTK_WIDGET (tree_view)); } +/* Our strategy for finding nodes to validate is a little convoluted. We find + * the left-most uninvalidated node. We then try walking right, validating + * nodes. Once we find a valid node, we repeat the previous process of finding + * the first invalid node. + */ + static gboolean validate_rows_handler (GtkTreeView *tree_view) { + GtkRBTree *tree = NULL; + GtkRBNode *node = NULL; + gboolean validated_area = FALSE; + gint retval = TRUE; + GtkTreePath *path = NULL; + GtkTreeIter iter; + gint i = 0; g_assert (tree_view); + g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE); - g_return_val_if_fail (tree_view->priv->tree != NULL, TRUE); + GDK_THREADS_ENTER (); - if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID)) - return TRUE; + do + { + if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID)) + { + retval = FALSE; + goto done; + } - return TRUE; + if (path != NULL) + { + node = _gtk_rbtree_next (tree, node); + if (node != NULL) + { + TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE); + gtk_tree_path_next (path); + } + else + { + gtk_tree_path_free (path); + path = NULL; + } + } + + if (path == NULL) + { + tree = tree_view->priv->tree; + node = tree_view->priv->tree->root; + + g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID)); + + do + { + if (node->left != tree->nil && + GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) + { + node = node->left; + } + else if (node->right != tree->nil && + GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) + { + node = node->right; + } + else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) || + GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)) + { + break; + } + else + { + tree = node->children; + node = tree->root; + } + } + while (TRUE); + path = _gtk_tree_view_find_path (tree_view, tree, node); + gtk_tree_model_get_iter (tree_view->priv->model, &iter, path); + } + validated_area = validate_row (tree_view, tree, node, &iter, path) | validated_area; + i++; + } + while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE); + + done: + if (path) gtk_tree_path_free (path); + if (validated_area) + gtk_widget_queue_resize (GTK_WIDGET (tree_view)); + if (! retval) + tree_view->priv->validate_rows_timer = 0; + + GDK_THREADS_LEAVE (); + + return retval; } static gboolean presize_handler_callback (gpointer data) { + GtkTreeView *tree_view = GTK_TREE_VIEW (data); - return TRUE; + GDK_THREADS_ENTER (); + + validate_visible_area (tree_view); + tree_view->priv->presize_handler_timer = 0; + + GDK_THREADS_LEAVE (); + + return FALSE; } static void install_presize_handler (GtkTreeView *tree_view) { - + if (! tree_view->priv->presize_handler_timer) + { + tree_view->priv->presize_handler_timer = + g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL); + } + if (! tree_view->priv->validate_rows_timer) + { + tree_view->priv->validate_rows_timer = + g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL); + } } /* Drag-and-drop */ @@ -4437,7 +4776,6 @@ { _gtk_rbtree_node_set_height (tree, node, height + vertical_separator); gtk_widget_queue_resize (GTK_WIDGET (data)); - _gtk_tree_view_update_size (tree_view); goto done; } if (dirty_marked) @@ -4464,15 +4802,10 @@ gint *indices; GtkRBTree *tmptree, *tree; GtkRBNode *tmpnode = NULL; - gint max_height; gint depth; gint i = 0; gboolean free_path = FALSE; - if (tree_view->priv->tree == NULL) - tree_view->priv->tree = _gtk_rbtree_new (); - - tmptree = tree = tree_view->priv->tree; g_return_if_fail (path != NULL || iter != NULL); if (path == NULL) @@ -4483,6 +4816,11 @@ else if (iter == NULL) gtk_tree_model_get_iter (model, iter, path); + if (tree_view->priv->tree == NULL) + tree_view->priv->tree = _gtk_rbtree_new (); + + tmptree = tree = tree_view->priv->tree; + /* Update all row-references */ gtk_tree_row_reference_inserted (G_OBJECT (data), path); depth = gtk_tree_path_get_depth (path); @@ -4529,27 +4867,23 @@ /* ref the node */ gtk_tree_model_ref_node (tree_view->priv->model, iter); - max_height = gtk_tree_view_insert_iter_height (tree_view, - tree, - iter, - depth); if (indices[depth - 1] == 0) { tmpnode = _gtk_rbtree_find_count (tree, 1); - _gtk_rbtree_insert_before (tree, tmpnode, max_height); + _gtk_rbtree_insert_before (tree, tmpnode, 0, FALSE); } else { tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]); - _gtk_rbtree_insert_after (tree, tmpnode, max_height); + _gtk_rbtree_insert_after (tree, tmpnode, 0, FALSE); } - - _gtk_tree_view_update_size (tree_view); + install_presize_handler (tree_view); done: if (free_path) gtk_tree_path_free (path); } + #include "gtktreemodelsort.h" static void gtk_tree_view_row_has_child_toggled (GtkTreeModel *model, @@ -4700,7 +5034,7 @@ _gtk_rbtree_remove_node (tree, node); } - _gtk_tree_view_update_size (GTK_TREE_VIEW (data)); + gtk_widget_queue_resize (GTK_WIDGET (tree_view)); if (selection_changed) g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed"); @@ -4852,71 +5186,19 @@ } } -static gint -gtk_tree_view_insert_iter_height (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth) -{ - GtkTreeViewColumn *column; - GList *list; - gint max_height = 0; - gint vertical_separator; - - gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL); - - /* do stuff with node */ - for (list = tree_view->priv->columns; list; list = list->next) - { - gint height = 0, width = 0; - column = list->data; - - if (!column->visible) - continue; - - if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED) - continue; - - gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter, - gtk_tree_model_iter_has_child (tree_view->priv->model, iter), - FALSE); - - gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height); - max_height = MAX (max_height, vertical_separator + height); - - if (gtk_tree_view_is_expander_column (tree_view, column) && - TREE_VIEW_DRAW_EXPANDERS (tree_view)) - _gtk_tree_view_column_set_width (column, - MAX (column->width, depth * tree_view->priv->tab_offset + width)); - else - _gtk_tree_view_column_set_width (column, - MAX (column->width, width)); - } - return max_height; -} - static void gtk_tree_view_build_tree (GtkTreeView *tree_view, GtkRBTree *tree, GtkTreeIter *iter, gint depth, - gboolean recurse, - gboolean calc_bounds) + gboolean recurse) { GtkRBNode *temp = NULL; - gint max_height; do { - max_height = 0; - if (calc_bounds) - max_height = gtk_tree_view_insert_iter_height (tree_view, - tree, - iter, - depth); - gtk_tree_model_ref_node (tree_view->priv->model, iter); - temp = _gtk_rbtree_insert_after (tree, temp, max_height); + temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE); if (recurse) { GtkTreeIter child; @@ -4926,7 +5208,7 @@ temp->children = _gtk_rbtree_new (); temp->children->parent_tree = tree; temp->children->parent_node = temp; - gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds); + gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse); } } if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)) @@ -4939,74 +5221,6 @@ while (gtk_tree_model_iter_next (tree_view->priv->model, iter)); } -static void -gtk_tree_view_calc_size (GtkTreeView *tree_view, - GtkRBTree *tree, - GtkTreeIter *iter, - gint depth) -{ - GtkRBNode *temp; - GtkTreeIter child; - GList *list; - GtkTreeViewColumn *column; - gint max_height; - gint vertical_separator; - gint horizontal_separator; - TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL); - - gtk_widget_style_get (GTK_WIDGET (tree_view), - "vertical_separator", &vertical_separator, - "horizontal_separator", &horizontal_separator, - NULL); - - temp = tree->root; - while (temp->left != tree->nil) - temp = temp->left; - - do - { - max_height = 0; - /* Do stuff with node */ - for (list = tree_view->priv->columns; list; list = list->next) - { - gint height = 0, width = 0; - column = list->data; - - if (!column->visible) - continue; - - gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter, - GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_IS_PARENT), - temp->children?TRUE:FALSE); - gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height); - max_height = MAX (max_height, vertical_separator + height); - - /* FIXME: I'm getting the width of all nodes here. )-: */ - if (column->dirty == FALSE) - continue; - - if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED) - { - continue; - } - if (gtk_tree_view_is_expander_column (tree_view, column) && - TREE_VIEW_DRAW_EXPANDERS (tree_view)) - _gtk_tree_view_column_set_width (column, - MAX (column->width, depth * tree_view->priv->tab_offset + width + horizontal_separator)); - else - _gtk_tree_view_column_set_width (column, MAX (column->width, width + horizontal_separator)); - } - - _gtk_rbtree_node_set_height (tree, temp, max_height); - - if (temp->children != NULL && - gtk_tree_model_iter_children (tree_view->priv->model, &child, iter)) - gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1); - temp = _gtk_rbtree_next (tree, temp); - } - while (gtk_tree_model_iter_next (tree_view->priv->model, iter)); -} - /* If height is non-NULL, then we set it to be the new height. if it's all * dirty, then height is -1. We know we'll remeasure dirty rows, anyways. */ @@ -5130,61 +5344,6 @@ } -/** - * gtk_tree_view_check_dirty_and_clean: - * @tree_view: A #GtkTreeView - * - * Does all the actual sizing for - **/ -static void -gtk_tree_view_check_dirty_and_clean (GtkTreeView *tree_view) -{ - GtkTreePath *path; - gboolean dirty = FALSE; - GList *list; - GtkTreeViewColumn *column; - GtkTreeIter iter; - - for (list = tree_view->priv->columns; list; list = list->next) - { - column = list->data; - if (column->dirty) - { - dirty = TRUE; - if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) - { - gint w = 1; - - if (column->button) - w = MAX (w, column->button->requisition.width); - - _gtk_tree_view_column_set_width (column, w); - } - } - } - - if (dirty == FALSE) - return; - - if (tree_view->priv->model == NULL) - return; - - path = gtk_tree_path_new_root (); - if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path)) - { - gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1); - _gtk_tree_view_update_size (tree_view); - } - - gtk_tree_path_free (path); - - for (list = tree_view->priv->columns; list; list = list->next) - { - column = list->data; - column->dirty = FALSE; - } -} - /* Make sure the node is visible vertically */ static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view, @@ -5326,6 +5485,9 @@ { GList *list; + if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST)) + return FALSE; + if (tree_view->priv->expander_column != NULL) { if (tree_view->priv->expander_column == column) @@ -5678,6 +5840,7 @@ rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node); rect.height = BACKGROUND_HEIGHT (node); + // g_print ("gtk_tree_view_queue_draw_node: (%d %d) (%d %d)\n", rect.x, rect.y, rect.width, rect.height); if (clip_rect) { @@ -5778,37 +5941,6 @@ expander_style); } - -static void -_gtk_tree_view_update_col_width (GtkTreeView *tree_view) -{ - GList *list, *last_column; - GtkTreeViewColumn *column; - gint width = 0; - - for (last_column = g_list_last (tree_view->priv->columns); - last_column && - !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) && - GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button); - last_column = last_column->prev) - ; - - if (last_column == NULL) - return; - - for (list = tree_view->priv->columns; list != last_column; list = list->next) - { - column = GTK_TREE_VIEW_COLUMN (list->data); - if (! column->visible) - continue; - - width += column->width; - column->width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width)); - } - column = GTK_TREE_VIEW_COLUMN (last_column->data); - column->width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width; -} - static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view) @@ -6282,64 +6414,6 @@ gtk_tree_view_search_init (entry, tree_view); } -void -_gtk_tree_view_update_size (GtkTreeView *tree_view) -{ - gint width, height; - GList *list; - GtkTreeViewColumn *column; - gint vertical_separator; - gint i; - - gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL); - - if (tree_view->priv->model == NULL) - { - tree_view->priv->width = 0; - tree_view->priv->height = 0; - gtk_widget_queue_draw (GTK_WIDGET (tree_view)); - return; - } - - width = 0; - for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++) - { - column = list->data; - if (!column->visible) - continue; - width += TREE_VIEW_COLUMN_WIDTH (column); - } - - if (tree_view->priv->tree == NULL) - height = 0; - else - height = tree_view->priv->tree->root->offset + vertical_separator; - - if (tree_view->priv->width != width) - { - tree_view->priv->width = width; - tree_view->priv->hadjustment->upper = width; - gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed"); - } - - if (tree_view->priv->height != height) - { - tree_view->priv->height = height; - tree_view->priv->vadjustment->upper = tree_view->priv->height; - gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed"); - } - - if (GTK_WIDGET_REALIZED (tree_view)) - { - gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view)); - gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height); - - _gtk_tree_view_update_col_width (tree_view); - } - - gtk_widget_queue_resize (GTK_WIDGET (tree_view)); -} - /* this function returns the new width of the column being resized given * the column and x position of the cursor; the x cursor position is passed * in as a pointer and automagicly corrected if it's beyond min/max limits @@ -6553,16 +6627,17 @@ if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path)) { tree_view->priv->tree = _gtk_rbtree_new (); - gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view)); + gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE); } gtk_tree_path_free (path); /* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */ } - if (GTK_WIDGET_REALIZED (tree_view)) - _gtk_tree_view_update_size (tree_view); g_object_notify (G_OBJECT (tree_view), "model"); + + if (GTK_WIDGET_REALIZED (tree_view)) + gtk_widget_queue_resize (GTK_WIDGET (tree_view)); } /** @@ -7160,9 +7235,8 @@ if (GTK_WIDGET_REALIZED (tree_view)) { - /*gtk_widget_queue_resize (GTK_WIDGET (tree_view)); */ - _gtk_tree_view_update_size (tree_view); - gtk_tree_view_size_allocate_buttons (GTK_WIDGET (tree_view)); + gtk_widget_queue_resize (GTK_WIDGET (tree_view)); + gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view)); } g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0); @@ -7433,8 +7507,7 @@ node->children, &child, gtk_tree_path_get_depth (path) + 1, - TRUE, - GTK_WIDGET_REALIZED (tree_view)); + TRUE); gtk_tree_path_free (path); } } @@ -7456,8 +7529,6 @@ G_PRE_ORDER, gtk_tree_view_expand_all_helper, tree_view); - - _gtk_tree_view_update_size (tree_view); } /* Timeout to animate the expander during expands and collapses */ @@ -7610,8 +7681,7 @@ node->children, &temp, gtk_tree_path_get_depth (path) + 1, - open_all, - GTK_WIDGET_REALIZED (tree_view)); + open_all); if (tree_view->priv->expand_collapse_timeout) { @@ -7637,10 +7707,7 @@ } if (GTK_WIDGET_MAPPED (tree_view)) - { - gtk_widget_queue_draw (GTK_WIDGET (tree_view)); - _gtk_tree_view_update_size (tree_view); - } + install_presize_handler (tree_view); g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path); return TRUE; @@ -7779,8 +7846,7 @@ if (GTK_WIDGET_MAPPED (tree_view)) { - gtk_widget_queue_draw (GTK_WIDGET (tree_view)); - _gtk_tree_view_update_size (tree_view); + gtk_widget_queue_resize (GTK_WIDGET (tree_view)); } if (gtk_tree_row_reference_valid (tree_view->priv->cursor)) @@ -9456,4 +9522,3 @@ gtk_cell_editable_editing_done (tree_view->priv->edited_column->editable_widget); gtk_cell_editable_remove_widget (tree_view->priv->edited_column->editable_widget); } - Index: gtk/gtktreeviewcolumn.c =================================================================== RCS file: /cvs/gnome/gtk+/gtk/gtktreeviewcolumn.c,v retrieving revision 1.81 diff -u -r1.81 gtktreeviewcolumn.c --- gtk/gtktreeviewcolumn.c 2001/11/19 21:18:21 1.81 +++ gtk/gtktreeviewcolumn.c 2001/11/30 21:53:09 @@ -302,6 +302,7 @@ tree_column->requested_width = -1; tree_column->min_width = -1; tree_column->max_width = -1; + tree_column->resized_width = 0; tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY; tree_column->visible = TRUE; tree_column->resizable = FALSE; @@ -315,6 +316,7 @@ tree_column->sort_column_id = -1; tree_column->reorderable = FALSE; tree_column->maybe_reordered = FALSE; + tree_column->use_resized_width = FALSE; } static void @@ -355,6 +357,11 @@ g_value_get_boolean (value)); break; + case PROP_RESIZABLE: + gtk_tree_view_column_set_resizable (tree_column, + g_value_get_boolean (value)); + break; + case PROP_SIZING: gtk_tree_view_column_set_sizing (tree_column, g_value_get_enum (value)); @@ -433,6 +440,11 @@ gtk_tree_view_column_get_visible (tree_column)); break; + case PROP_RESIZABLE: + g_value_set_boolean (value, + gtk_tree_view_column_get_resizable (tree_column)); + break; + case PROP_WIDTH: g_value_set_int (value, gtk_tree_view_column_get_width (tree_column)); @@ -1429,6 +1441,8 @@ if (tree_column->resizable == resizable) return; + + tree_column->resizable = resizable; if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE) gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY); Index: gtk/gtktreeviewcolumn.h =================================================================== RCS file: /cvs/gnome/gtk+/gtk/gtktreeviewcolumn.h,v retrieving revision 1.44 diff -u -r1.44 gtktreeviewcolumn.h --- gtk/gtktreeviewcolumn.h 2001/11/19 21:18:21 1.44 +++ gtk/gtktreeviewcolumn.h 2001/11/30 21:53:09 @@ -66,13 +66,18 @@ GtkCellEditable *editable_widget; gfloat xalign; guint property_changed_signal; - gint spacing; + + /* Sizing fields */ + /* see gtk+/doc/tree-column-sizing.txt for more information on them */ + GtkTreeViewColumnSizing column_type; + gint button_request; gint fixed_width; gint width; gint requested_width; gint min_width; gint max_width; + gint resized_width; /* dragging columns */ gint drag_x; @@ -80,7 +85,6 @@ gchar *title; GList *cell_list; - GtkTreeViewColumnSizing column_type; /* Sorting */ guint sort_clicked_signal; @@ -96,6 +100,7 @@ guint show_sort_indicator : 1; guint maybe_reordered : 1; guint reorderable : 1; + guint use_resized_width : 1; }; struct _GtkTreeViewColumnClass Index: tests/testtreefocus.c =================================================================== RCS file: /cvs/gnome/gtk+/tests/testtreefocus.c,v retrieving revision 1.14 diff -u -r1.14 testtreefocus.c --- tests/testtreefocus.c 2001/09/25 16:44:39 1.14 +++ tests/testtreefocus.c 2001/11/30 21:53:09 @@ -337,6 +337,7 @@ "text", HOLIDAY_COLUMN, NULL); column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), col_offset - 1); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); + gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column), GTK_TREE_VIEW_COLUMN_AUTOSIZE); /* Alex Column */ renderer = gtk_cell_renderer_toggle_new (); Index: tests/testtreesort.c =================================================================== RCS file: /cvs/gnome/gtk+/tests/testtreesort.c,v retrieving revision 1.20 diff -u -r1.20 testtreesort.c --- tests/testtreesort.c 2001/10/31 22:57:51 1.20 +++ tests/testtreesort.c 2001/11/30 21:53:09 @@ -88,10 +88,9 @@ model = gtk_tree_store_new (NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); -/* smodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model)); ssmodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (smodel)); -*/ + tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model)); /* 12 iters now, 12 later... */ @@ -128,8 +127,8 @@ } } - smodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model)); - ssmodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (smodel)); + // smodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model)); + // ssmodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (smodel)); g_object_unref (G_OBJECT (model)); gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);