GtkTreeView scroll_to patch
- From: Jonathan Blandford <jrb redhat com>
- To: gtk-devel-list gnome org
- Subject: GtkTreeView scroll_to patch
- Date: 20 Feb 2002 16:50:48 -0500
Here's a patch to make gtk_tree_view_scroll_to_cell work when we're not
realized yet. I haven't tested it as well as I'd like, so if anyone has
time to play with it, I'd appreciate it.
Thanks,
-Jonathan
? autom4te.cache
? gdk--2.0.pc
? gtk+--2.0.pc
? tests/.xvpics
? tests/out
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.3056
diff -u -r1.3056 ChangeLog
--- ChangeLog 2002/02/20 21:22:21 1.3056
+++ ChangeLog 2002/02/20 21:49:27
@@ -1,3 +1,11 @@
+Wed Feb 20 16:44:05 2002 Jonathan Blandford <jrb redhat com>
+
+ * gtk/gtktreeview.c (gtk_tree_view_scroll_to_cell): delay
+ scrolling until we try to draw the window.
+
+ * gtk/gtktreeview.c (validate_visible_area): Implement
+ scroll_to_cell.
+
Wed Feb 20 16:19:49 2002 Owen Taylor <otaylor redhat com>
* gdk/x11/gdkevents-x11.c: Add a XSETTING mapping for
Index: gtk/gtktreeprivate.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktreeprivate.h,v
retrieving revision 1.43
diff -u -r1.43 gtktreeprivate.h
--- gtk/gtktreeprivate.h 2002/02/19 18:21:50 1.43
+++ gtk/gtktreeprivate.h 2002/02/20 21:49:27
@@ -166,7 +166,7 @@
gint press_start_y;
/* Scroll-to functionality when unrealized */
- GtkTreePath *scroll_to_path;
+ GtkTreeRowReference *scroll_to_path;
GtkTreeViewColumn *scroll_to_column;
gfloat scroll_to_row_align;
gfloat scroll_to_col_align;
Index: gtk/gtktreeview.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtktreeview.c,v
retrieving revision 1.229
diff -u -r1.229 gtktreeview.c
--- gtk/gtktreeview.c 2002/02/19 21:16:49 1.229
+++ gtk/gtktreeview.c 2002/02/20 21:49:27
@@ -1061,7 +1061,7 @@
if (tree_view->priv->scroll_to_path != NULL)
{
- gtk_tree_path_free (tree_view->priv->scroll_to_path);
+ gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
tree_view->priv->scroll_to_path = NULL;
}
@@ -1624,23 +1624,6 @@
}
gtk_tree_view_size_allocate_columns (widget);
-
- if (tree_view->priv->scroll_to_path != NULL ||
- tree_view->priv->scroll_to_column != NULL)
- {
- gtk_tree_view_scroll_to_cell (tree_view,
- tree_view->priv->scroll_to_path,
- tree_view->priv->scroll_to_column,
- tree_view->priv->scroll_to_use_align,
- tree_view->priv->scroll_to_row_align,
- tree_view->priv->scroll_to_col_align);
- if (tree_view->priv->scroll_to_path)
- {
- gtk_tree_path_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
- }
- tree_view->priv->scroll_to_column = NULL;
- }
}
static gboolean
@@ -3258,40 +3241,84 @@
static void
validate_visible_area (GtkTreeView *tree_view)
{
- GtkTreePath *path;
+ GtkTreePath *path = NULL;
+ GtkTreePath *above_path = NULL;
GtkTreeIter iter;
- GtkRBTree *tree;
- GtkRBNode *node;
- gint y, height, offset;
+ GtkRBTree *tree = NULL;
+ GtkRBNode *node = NULL;
gboolean validated_area = FALSE;
gboolean size_changed = FALSE;
-
+ gboolean modify_dy = FALSE;
+ gint total_height;
+ gint area_above = 0;
+ gint area_below = 0;
+
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, 0);
+ total_height = GTK_WIDGET (tree_view)->allocation.height - 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
+ /* First, we check to see if we need to scroll anywhere
+ */
+ if (tree_view->priv->scroll_to_path)
{
- path = _gtk_tree_view_find_path (tree_view, tree, node);
- height += offset;
+ path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
+ if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node))
+ {
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+ {
+ validated_area = TRUE;
+ if (validate_row (tree_view, tree, node, &iter, path))
+ size_changed = TRUE;
+ }
+ if (tree_view->priv->scroll_to_use_align)
+ {
+ area_above = (total_height - MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size)) *
+ tree_view->priv->scroll_to_row_align;
+ area_below = total_height - MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size) - area_above;
+ area_above = MAX (area_above, 0);
+ area_below = MAX (area_below, 0);
+ }
+ else
+ {
+ g_warning ("non use_align not implemented yet");
+ gtk_tree_path_free (path);
+ path = NULL;
+ }
+ }
+ else
+ /* the scroll to isn't valid; ignore it.
+ */
+ {
+ gtk_tree_path_free (path);
+ path = NULL;
+ }
}
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
- do
+ /* We didn't have a scroll_to set, so we just handle things normally
+ */
+ if (path == NULL)
{
+ gint offset;
+
+ offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
+ TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
+ &tree, &node);
+ if (node == NULL)
+ {
+ /* In this case, nothing has been validated */
+ path = gtk_tree_path_new_root ();
+ }
+ else
+ {
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+ total_height += offset;
+ }
+
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
{
@@ -3299,8 +3326,19 @@
if (validate_row (tree_view, tree, node, &iter, path))
size_changed = TRUE;
}
- height -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ area_above = 0;
+ area_below = total_height - MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ }
+
+ above_path = gtk_tree_path_copy (path);
+ /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
+ * backwards is much slower then forward, as there is no iter_prev function.
+ * We go forwards first in case we run out of tree. Then we go backwards to
+ * fill out the top.
+ */
+ while (node && area_below > 0)
+ {
if (node->children)
{
GtkTreeIter parent = iter;
@@ -3352,17 +3390,83 @@
}
while (!done);
}
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+ {
+ validated_area = TRUE;
+ if (validate_row (tree_view, tree, node, &iter, path))
+ size_changed = TRUE;
+ }
+ if (node)
+ area_below -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ }
+ gtk_tree_path_free (path);
+
+ /* If we ran out of tree, and have extra area_below left, we need to remove it from the area_above */
+ if (area_below > 0)
+ area_above += area_below;
+
+ _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
+ _gtk_rbtree_prev_full (tree, node, &tree, &node);
+ if (! gtk_tree_path_prev (above_path) && node != NULL)
+ {
+ gtk_tree_path_free (above_path);
+ above_path = _gtk_tree_view_find_path (tree_view, tree, node);
+ }
+
+ while (node != NULL && area_above > 0)
+ {
+ /* We walk ever so slowly backwards... */
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+ {
+ validated_area = TRUE;
+ if (validate_row (tree_view, tree, node, &iter, above_path))
+ size_changed = TRUE;
+ }
+ area_above -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+
+ _gtk_rbtree_prev_full (tree, node, &tree, &node);
+ if (! gtk_tree_path_prev (above_path))
+ {
+ gtk_tree_path_free (above_path);
+ above_path = _gtk_tree_view_find_path (tree_view, tree, node);
+ }
+ modify_dy = TRUE;
+ }
+
+ /* if we walk backwards at all, then we need to reset our dy. */
+ if (modify_dy && node != NULL)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->top_row);
+ tree_view->priv->top_row =
+ gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, above_path);
+ tree_view->priv->top_row_dy = - area_above;
+ }
+ else
+ {
+ /* hrm. */
+ }
+
+ if (tree_view->priv->scroll_to_path)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
+ tree_view->priv->scroll_to_path = NULL;
}
- while (node && height > 0);
+ if (tree_view->priv->scroll_to_column)
+ {
+ tree_view->priv->scroll_to_column = NULL;
+ }
if (size_changed)
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
if (validated_area)
gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- if (path)
- gtk_tree_path_free (path);
}
+
/* 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
@@ -7665,12 +7769,16 @@
*
* Moves the alignments of @tree_view to the position specified by @column and
* @path. If @column is %NULL, then no horizontal scrolling occurs. Likewise,
- * if @path is %NULL no vertical scrolling occurs. @row_align determines where
- * the row is placed, and @col_align determines where @column is placed. Both
- * are expected to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0
- * means right/bottom alignment, 0.5 means center. If @use_align is %FALSE,
- * then the alignment arguments are ignored, and the tree does the minimum
- * amount of work to scroll the cell onto the screen.
+ * if @path is %NULL no vertical scrolling occurs. At a minimum, one of @column
+ * or @path need to be non-%NULL. @row_align determines where the row is
+ * placed, and @col_align determines where @column is placed. Both are expected
+ * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
+ * right/bottom alignment, 0.5 means center.
+ *
+ * If @use_align is %FALSE, then the alignment arguments are ignored, and the
+ * tree does the minimum amount of work to scroll the cell onto the screen.
+ * This means that the cell will be scrolled to the edge closest to it's current
+ * position. If the cell is currently visible on the screen, nothing is done.
**/
void
gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
@@ -7680,15 +7788,6 @@
gfloat row_align,
gfloat col_align)
{
- GdkRectangle cell_rect;
- GdkRectangle vis_rect;
- gint dest_x, dest_y;
- gfloat within_margin = 0;
-
- /* FIXME work on unmapped/unrealized trees? maybe implement when
- * we do incremental reflow for trees
- */
-
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
@@ -7697,19 +7796,23 @@
row_align = CLAMP (row_align, 0.0, 1.0);
col_align = CLAMP (col_align, 0.0, 1.0);
- if (! GTK_WIDGET_REALIZED (tree_view))
- {
- if (path)
- tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
- if (column)
- tree_view->priv->scroll_to_column = column;
- tree_view->priv->scroll_to_use_align = use_align;
- tree_view->priv->scroll_to_row_align = row_align;
- tree_view->priv->scroll_to_col_align = col_align;
+ if (tree_view->priv->scroll_to_path)
+ gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- return;
- }
+ tree_view->priv->scroll_to_path = NULL;
+ tree_view->priv->scroll_to_column = NULL;
+
+ if (path)
+ tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
+ if (column)
+ tree_view->priv->scroll_to_column = column;
+ tree_view->priv->scroll_to_use_align = use_align;
+ tree_view->priv->scroll_to_row_align = row_align;
+ tree_view->priv->scroll_to_col_align = col_align;
+ install_presize_handler (tree_view);
+}
+#if 0
gtk_tree_view_get_cell_area (tree_view, path, column, &cell_rect);
gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
@@ -7747,7 +7850,7 @@
}
gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
-}
+#endif
/**
@@ -7997,8 +8100,7 @@
GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
}
- if (GTK_WIDGET_MAPPED (tree_view))
- install_presize_handler (tree_view);
+ install_presize_handler (tree_view);
g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
return TRUE;
Index: tests/testtreeflow.c
===================================================================
RCS file: /cvs/gnome/gtk+/tests/testtreeflow.c,v
retrieving revision 1.4
diff -u -r1.4 testtreeflow.c
--- tests/testtreeflow.c 2001/12/08 01:10:52 1.4
+++ tests/testtreeflow.c 2002/02/20 21:49:27
@@ -2,7 +2,7 @@
GtkTreeModel *model = NULL;
GRand *rand = NULL;
-
+GtkTreeSelection *selection = NULL;
enum
{
TEXT_COLUMN,
@@ -56,6 +56,8 @@
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_path_free (path);
+ if (gtk_tree_selection_iter_is_selected (selection, &iter))
+ return;
switch (g_rand_int_range (rand, 0, 3))
{
case 0:
@@ -74,6 +76,7 @@
break;
case 2:
/* modify */
+ return;
if (gtk_tree_model_iter_n_children (model, NULL) == 0)
return;
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
@@ -103,9 +106,11 @@
GtkWidget *tree_view;
GtkWidget *hbox;
GtkWidget *button;
+ GtkTreePath *path;
gtk_init (&argc, &argv);
+ path = gtk_tree_path_new_from_string ("80");
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Reflow test");
gtk_signal_connect (GTK_OBJECT (window), "destroy", gtk_main_quit, NULL);
@@ -121,6 +126,8 @@
initialize_model ();
tree_view = gtk_tree_view_new_with_model (model);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tree_view), path, NULL, TRUE, 0.5, 0.0);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]