GtkTreeView scroll_to patch



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]