[gtk+/cellarea-style-transitions: 9/10] treeview: use GtkCellArea animation APIs



commit f1bf62c1b0f2c5d9e3db5556dc1b54edfc15aafc
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed May 11 13:49:30 2011 +0200

    treeview: use GtkCellArea animation APIs
    
    GtkTreeViewColumn has been added some helper API to interface
    with GtkTreeView. The tree view handles (recursive) cancellation
    of animations if:
    
      - A row is deleted
      - A row is collapsed
      - A row is scrolled outside of the visible range
      - The model is removed

 gtk/gtktreeprivate.h    |   14 ++-
 gtk/gtktreeview.c       |  261 ++++++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtktreeviewcolumn.c |   28 ++++-
 3 files changed, 290 insertions(+), 13 deletions(-)
---
diff --git a/gtk/gtktreeprivate.h b/gtk/gtktreeprivate.h
index 2c54a04..cf38ae4 100644
--- a/gtk/gtktreeprivate.h
+++ b/gtk/gtktreeprivate.h
@@ -133,11 +133,15 @@ gboolean          _gtk_tree_view_column_is_blank_at_pos  (GtkTreeViewColumn  *co
                                                           gint                y);
 
 void		  _gtk_tree_view_column_cell_render      (GtkTreeViewColumn  *tree_column,
-							  cairo_t            *cr,
-							  const GdkRectangle *background_area,
-							  const GdkRectangle *cell_area,
-							  guint               flags,
-                                                          gboolean            draw_focus);
+                                                          cairo_t            *cr,
+                                                          const GdkRectangle *background_area,
+                                                          const GdkRectangle *cell_area,
+                                                          guint               flags,
+                                                          gboolean            draw_focus,
+                                                          gpointer            anim_id);
+void              _gtk_tree_view_column_cancel_animations (GtkTreeViewColumn *tree_column,
+                                                           gpointer           anim_id);
+
 void		  _gtk_tree_view_column_cell_set_dirty	 (GtkTreeViewColumn  *tree_column,
 							  gboolean            install_handler);
 gboolean          _gtk_tree_view_column_cell_get_dirty   (GtkTreeViewColumn  *tree_column);
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 232e8d5..04f4b47 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -298,6 +298,7 @@ struct _GtkTreeViewPrivate
 
   /* Scroll position state keeping */
   GtkTreeRowReference *top_row;
+  GtkTreeRowReference *bottom_row;
   gint top_row_dy;
   /* dy == y pos of top_row + top_row_dy */
   /* we cache it for simplicity of the code */
@@ -721,6 +722,9 @@ static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
 					     gint         offset);
 static void	gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
+static GtkTreePath * gtk_tree_view_get_bottom_row (GtkTreeView *tree_view,
+                                                   GtkTreePath *top_row);
+
 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
 
 /* Internal functions */
@@ -883,6 +887,10 @@ static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree
 							 GtkTreeViewColumn *column,
 							 gint               drop_position);
 
+static void gtk_tree_view_cancel_row_animations         (GtkTreeView       *tree_view,
+                                                         GtkTreePath       *top_row,
+                                                         GtkTreePath       *bottom_row);
+
 /* GtkBuildable */
 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
 							    GtkBuilder        *builder,
@@ -2815,6 +2823,26 @@ gtk_tree_view_size_allocate (GtkWidget     *widget,
           tree_view->priv->prev_width_before_expander = width_before_expander;
         }
     }
+
+  if (tree_view->priv->top_row &&
+      tree_view->priv->bottom_row)
+    {
+      GtkTreePath *top_path, *bottom_path;
+
+
+      top_path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
+      bottom_path = gtk_tree_view_get_bottom_row (tree_view, top_path);
+
+      gtk_tree_view_cancel_row_animations (tree_view, top_path, bottom_path);
+
+      gtk_tree_path_free (top_path);
+
+      /* Update bottom row */
+      gtk_tree_row_reference_free (tree_view->priv->bottom_row);
+      tree_view->priv->bottom_row = gtk_tree_row_reference_new (tree_view->priv->model,
+                                                                bottom_path);
+      gtk_tree_path_free (bottom_path);
+    }
 }
 
 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
@@ -5036,7 +5064,8 @@ gtk_tree_view_bin_draw (GtkWidget      *widget,
 						   &background_area,
 						   &cell_area,
 						   flags,
-                                                   draw_focus);
+                                                   draw_focus,
+                                                   node);
 	      if (gtk_tree_view_draw_expanders (tree_view)
 		  && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
 		{
@@ -5075,7 +5104,8 @@ gtk_tree_view_bin_draw (GtkWidget      *widget,
 						   &background_area,
 						   &cell_area,
 						   flags,
-                                                   draw_focus);
+                                                   draw_focus,
+                                                   node);
 	    }
 
 	  if (draw_hgrid_lines)
@@ -6856,13 +6886,195 @@ install_scroll_sync_handler (GtkTreeView *tree_view)
     }
 }
 
+/* Gets the bottom row for a given top_row, taking
+ * into account current treeview allocation.
+ */
+static GtkTreePath *
+gtk_tree_view_get_bottom_row (GtkTreeView *tree_view,
+                              GtkTreePath *top_row)
+{
+  GtkRBTree *tree, *bottom_row_tree;
+  GtkRBNode *node, *bottom_row_node;
+  gint y;
+
+  if (!top_row)
+    return NULL;
+
+  _gtk_tree_view_find_node (tree_view, top_row, &tree, &node);
+
+  if (!tree)
+    return NULL;
+
+  y = _gtk_rbtree_node_find_offset (tree, node);
+  y += gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
+  y = CLAMP (y,
+             (gint) gtk_adjustment_get_lower (tree_view->priv->vadjustment),
+             (gint) gtk_adjustment_get_upper (tree_view->priv->vadjustment));
+
+  if (y >= tree_view->priv->height)
+    y = tree_view->priv->height - 1;
+
+  _gtk_rbtree_find_offset (tree_view->priv->tree, y,
+			   &bottom_row_tree,
+			   &bottom_row_node);
+
+  if (!bottom_row_tree)
+    return NULL;
+
+  return _gtk_tree_view_find_path (tree_view,
+                                   bottom_row_tree,
+                                   bottom_row_node);
+}
+
+static void
+gtk_tree_view_cancel_row_range (GtkTreeView *tree_view,
+                                GtkTreePath *from,
+                                GtkTreePath *to)
+{
+  GtkRBNode *from_node, *to_node;
+  GtkRBTree *tree;
+
+  if (gtk_tree_path_compare (from, to) > 0)
+    {
+      GtkTreePath *tmp;
+
+      tmp = from;
+      from = to;
+      to = tmp;
+    }
+
+  _gtk_tree_view_find_node (tree_view, to, &tree, &to_node);
+  _gtk_tree_view_find_node (tree_view, from, &tree, &from_node);
+
+  if (!from_node || !to_node)
+    return;
+
+  while (from_node)
+    {
+      GList *columns;
+
+      for (columns = tree_view->priv->columns; columns; columns = columns->next)
+        {
+          GtkTreeViewColumn *column;
+
+          column = columns->data;
+          _gtk_tree_view_column_cancel_animations (column, from_node);
+        }
+
+      if (from_node != to_node)
+        _gtk_rbtree_next_full (tree, from_node, &tree, &from_node);
+      else
+        from_node = NULL;
+    }
+}
+
+static void
+gtk_tree_view_cancel_row_animations (GtkTreeView *tree_view,
+                                     GtkTreePath *top_row,
+                                     GtkTreePath *bottom_row)
+{
+  GtkTreePath *old_top_row, *old_bottom_row;
+  GtkTreePath *start_path = NULL;
+  GtkRBNode *node;
+  GtkRBTree *tree;
+
+  if (!tree_view->priv->top_row &&
+      !tree_view->priv->bottom_row)
+    return;
+
+  old_top_row = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
+  old_bottom_row = gtk_tree_row_reference_get_path (tree_view->priv->bottom_row);
+
+  if (gtk_tree_path_compare (old_top_row, top_row) < 0)
+    {
+      /* If the top row moved downwards, cancel all running animations
+       * from the new top row upwards, or optionally cancel all previous
+       * view contents if it's been scrolled to a completely disconnected
+       * place.
+       */
+      if (gtk_tree_path_compare (top_row, old_bottom_row) < 0)
+	{
+	  /* Top row is in the viewable range,
+	   * start from the one right above it
+	   */
+	  _gtk_tree_view_find_node (tree_view, top_row, &tree, &node);
+
+	  if (tree)
+	    {
+	      _gtk_rbtree_prev_full (tree, node, &tree, &node);
+
+	      if (tree)
+		start_path = _gtk_tree_view_find_path (tree_view, tree, node);
+	    }
+	}
+      else
+        start_path = gtk_tree_path_copy (old_bottom_row);
+
+      if (start_path)
+	{
+	  gtk_tree_view_cancel_row_range (tree_view, start_path, old_top_row);
+	  gtk_tree_path_free (start_path);
+	  start_path = NULL;
+	}
+    }
+
+  if (gtk_tree_path_compare (old_bottom_row, bottom_row) > 0)
+    {
+      /* If the bottom row moved upwards, cancel all running
+       * animations from the bottom row downwards, handling
+       * also jumps through the view.
+       */
+      if (gtk_tree_path_compare (bottom_row, old_top_row) > 0)
+	{
+	  /* Bottom row is in the viewable range,
+	   * start from the one right above it
+	   */
+	  _gtk_tree_view_find_node (tree_view, bottom_row, &tree, &node);
+
+	  if (tree)
+	    {
+	      _gtk_rbtree_next_full (tree, node, &tree, &node);
+
+	      if (tree)
+		start_path = _gtk_tree_view_find_path (tree_view, tree, node);
+	    }
+	}
+      else
+        start_path = gtk_tree_path_copy (old_top_row);
+
+      if (start_path)
+	{
+	  gtk_tree_view_cancel_row_range (tree_view, start_path, old_bottom_row);
+	  gtk_tree_path_free (start_path);
+	}
+    }
+
+  gtk_tree_path_free (old_top_row);
+  gtk_tree_path_free (old_bottom_row);
+}
+
 static void
 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
 			   GtkTreePath *path,
 			   gint         offset)
 {
+  GtkTreePath *bottom_path = NULL;
+
+  if (path)
+    bottom_path = gtk_tree_view_get_bottom_row (tree_view, path);
+
+  if (tree_view->priv->top_row &&
+      tree_view->priv->bottom_row)
+    gtk_tree_view_cancel_row_animations (tree_view, path, bottom_path);
+
   gtk_tree_row_reference_free (tree_view->priv->top_row);
 
+  if (tree_view->priv->bottom_row)
+    {
+      gtk_tree_row_reference_free (tree_view->priv->bottom_row);
+      tree_view->priv->bottom_row = NULL;
+    }
+
   if (!path)
     {
       tree_view->priv->top_row = NULL;
@@ -6872,6 +7084,9 @@ gtk_tree_view_set_top_row (GtkTreeView *tree_view,
     {
       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
       tree_view->priv->top_row_dy = offset;
+
+      if (bottom_path)
+        tree_view->priv->bottom_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, bottom_path);
     }
 }
 
@@ -8973,6 +9188,29 @@ check_selection_helper (GtkRBTree *tree,
 }
 
 static void
+cancel_row_animation_helper (GtkRBTree *tree,
+                             GtkRBNode *node,
+                             gpointer   user_data)
+{
+  GtkTreeView *tree_view = user_data;
+  GList *columns;
+
+  for (columns = tree_view->priv->columns;
+       columns;
+       columns = columns->next)
+    {
+      GtkTreeViewColumn *column;
+
+      column = columns->data;
+      _gtk_tree_view_column_cancel_animations (column, node);
+    }
+
+  if (node->children)
+    _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER,
+                          cancel_row_animation_helper, user_data);
+}
+
+static void
 gtk_tree_view_row_deleted (GtkTreeModel *model,
 			   GtkTreePath  *path,
 			   gpointer      data)
@@ -8994,6 +9232,10 @@ gtk_tree_view_row_deleted (GtkTreeModel *model,
   if (tree == NULL)
     return;
 
+  _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
+                        cancel_row_animation_helper,
+                        tree_view);
+
   /* check if the selection has been changed */
   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
                         check_selection_helper, &selection_changed);
@@ -11315,6 +11557,8 @@ void
 gtk_tree_view_set_model (GtkTreeView  *tree_view,
 			 GtkTreeModel *model)
 {
+  GList *columns;
+
   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
 
@@ -11327,6 +11571,15 @@ gtk_tree_view_set_model (GtkTreeView  *tree_view,
       tree_view->priv->scroll_to_path = NULL;
     }
 
+  /* Have all columns cancel every animation */
+  for (columns = tree_view->priv->columns; columns; columns = columns->next)
+    {
+      GtkTreeViewColumn *column;
+
+      column = columns->data;
+      _gtk_tree_view_column_cancel_animations (column, NULL);
+    }
+
   if (tree_view->priv->model)
     {
       GList *tmplist = tree_view->priv->columns;
@@ -12852,6 +13105,8 @@ gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
   tree_view->priv->last_button_x = -1;
   tree_view->priv->last_button_y = -1;
 
+  _gtk_rbtree_traverse (node->children, node->children->root, G_PRE_ORDER, cancel_row_animation_helper, tree_view);
+
   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
     {
       _gtk_rbtree_remove (node->children);
@@ -14591,7 +14846,7 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
                                                cr,
 					       &background_area,
 					       &cell_area,
-					       0, FALSE);
+					       0, FALSE, NULL);
 	}
       cell_offset += gtk_tree_view_column_get_width (column);
     }
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index cb04b1b..f63a3a6 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -2891,11 +2891,12 @@ gtk_tree_view_column_cell_get_size (GtkTreeViewColumn  *tree_column,
  **/
 void
 _gtk_tree_view_column_cell_render (GtkTreeViewColumn  *tree_column,
-				   cairo_t            *cr,
-				   const GdkRectangle *background_area,
-				   const GdkRectangle *cell_area,
-				   guint               flags,
-                                   gboolean            draw_focus)
+                                   cairo_t            *cr,
+                                   const GdkRectangle *background_area,
+                                   const GdkRectangle *cell_area,
+                                   guint               flags,
+                                   gboolean            draw_focus,
+                                   gpointer            anim_id)
 {
   GtkTreeViewColumnPrivate *priv;
 
@@ -2907,15 +2908,32 @@ _gtk_tree_view_column_cell_render (GtkTreeViewColumn  *tree_column,
   priv = tree_column->priv;
 
   cairo_save (cr);
+  gtk_cell_area_set_animation_id (priv->cell_area, anim_id);
 
   gtk_cell_area_render (priv->cell_area, priv->cell_area_context,
                         priv->tree_view, cr,
                         background_area, cell_area, flags,
                         draw_focus);
 
+  gtk_cell_area_set_animation_id (priv->cell_area, NULL);
   cairo_restore (cr);
 }
 
+void
+_gtk_tree_view_column_cancel_animations (GtkTreeViewColumn *tree_column,
+                                         gpointer           anim_id)
+{
+  GtkTreeViewColumnPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
+
+  priv = tree_column->priv;
+
+  gtk_cell_area_forget_animation_id (priv->cell_area,
+                                     priv->tree_view,
+                                     anim_id);
+}
+
 gboolean
 _gtk_tree_view_column_cell_event (GtkTreeViewColumn  *tree_column,
 				  GdkEvent           *event,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]