[gtk/wip/otte/listview: 43/155] listview: Try to keep the list items in order when scrolling



commit 77eb0d979b07a7d07bfbbb3e5e3c61efad4f1eda
Author: Benjamin Otte <otte redhat com>
Date:   Fri Sep 28 03:33:16 2018 +0200

    listview: Try to keep the list items in order when scrolling
    
    Instead of just destroying all items and then recreating them (or even
    hide()ing and then show()ing them again (or even even repositioning
    them in the widget tree)), just try to reust them in the order they are.
    
    This works surprisingly well when scrolling and most/all widgets
    just moved.

 gtk/gtklistitemmanager.c        | 29 +++++++++++++++++++++++++++++
 gtk/gtklistitemmanagerprivate.h |  4 ++++
 gtk/gtklistview.c               | 34 +++++++++++++++++++++++++---------
 3 files changed, 58 insertions(+), 9 deletions(-)
---
diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c
index 32687440b26..62888f366ae 100644
--- a/gtk/gtklistitemmanager.c
+++ b/gtk/gtklistitemmanager.c
@@ -21,6 +21,8 @@
 
 #include "gtklistitemmanagerprivate.h"
 
+#include "gtkwidgetprivate.h"
+
 struct _GtkListItemManager
 {
   GObject parent_instance;
@@ -312,6 +314,33 @@ gtk_list_item_manager_try_reacquire_list_item (GtkListItemManager       *self,
   return GTK_WIDGET (result);
 }
 
+/**
+ * gtk_list_item_manager_move_list_item:
+ * @self: a #GtkListItemManager
+ * @list_item: an acquired #GtkListItem that should be moved to represent
+ *     a different row
+ * @position: the new position of that list item
+ * @prev_sibling: the new previous sibling
+ *
+ * Moves the widget to represent a new position in the listmodel without
+ * releasing the item.
+ *
+ * This is most useful when scrolling.
+ **/
+void
+gtk_list_item_manager_move_list_item (GtkListItemManager     *self,
+                                      GtkWidget              *list_item,
+                                      guint                   position,
+                                      GtkWidget              *prev_sibling)
+{
+  gpointer item;
+
+  item = g_list_model_get_item (self->model, position);
+  gtk_list_item_factory_bind (self->factory, GTK_LIST_ITEM (list_item), position, item);
+  gtk_widget_insert_after (list_item, _gtk_widget_get_parent (list_item), prev_sibling);
+  g_object_unref (item);
+}
+
 /**
  * gtk_list_item_manager_update_list_item:
  * @self: a #GtkListItemManager
diff --git a/gtk/gtklistitemmanagerprivate.h b/gtk/gtklistitemmanagerprivate.h
index 0f1d1bddd11..d34e346a21e 100644
--- a/gtk/gtklistitemmanagerprivate.h
+++ b/gtk/gtklistitemmanagerprivate.h
@@ -69,6 +69,10 @@ GtkWidget *             gtk_list_item_manager_try_reacquire_list_item
 void                    gtk_list_item_manager_update_list_item  (GtkListItemManager     *self,
                                                                  GtkWidget              *item,
                                                                  guint                   position);
+void                    gtk_list_item_manager_move_list_item    (GtkListItemManager     *self,
+                                                                 GtkWidget              *list_item,
+                                                                 guint                   position,
+                                                                 GtkWidget              *prev_sibling);
 void                    gtk_list_item_manager_release_list_item (GtkListItemManager     *self,
                                                                  GtkListItemManagerChange *change,
                                                                  GtkWidget              *widget);
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index c9cfc7c840d..35cf3b6da3e 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -336,7 +336,8 @@ gtk_list_view_merge_list_rows (GtkListView *self,
 }
 
 static void
-gtk_list_view_release_rows (GtkListView *self)
+gtk_list_view_release_rows (GtkListView *self,
+                            GQueue      *released)
 {
   ListRow *row, *prev, *next;
   guint i;
@@ -347,7 +348,7 @@ gtk_list_view_release_rows (GtkListView *self)
     {
       if (row->widget)
         {
-          gtk_list_item_manager_release_list_item (self->item_manager, NULL, row->widget);
+          g_queue_push_tail (released, row->widget);
           row->widget = NULL;
           i++;
           prev = gtk_rb_tree_node_get_previous (row);
@@ -379,7 +380,7 @@ gtk_list_view_release_rows (GtkListView *self)
   
   if (row->widget)
     {
-      gtk_list_item_manager_release_list_item (self->item_manager, NULL, row->widget);
+      g_queue_push_tail (released, row->widget);
       row->widget = NULL;
       prev = gtk_rb_tree_node_get_previous (row);
       if (prev && gtk_list_view_merge_list_rows (self, prev, row))
@@ -390,7 +391,7 @@ gtk_list_view_release_rows (GtkListView *self)
     {
       if (next->widget)
         {
-          gtk_list_item_manager_release_list_item (self->item_manager, NULL, next->widget);
+          g_queue_push_tail (released, next->widget);
           next->widget = NULL;
         }
       gtk_list_view_merge_list_rows (self, row, next);
@@ -404,9 +405,10 @@ gtk_list_view_ensure_rows (GtkListView              *self,
 {
   ListRow *row, *new_row;
   guint i, offset;
-  GtkWidget *insert_after;
+  GtkWidget *widget, *insert_after;
+  GQueue released = G_QUEUE_INIT;
 
-  gtk_list_view_release_rows (self);
+  gtk_list_view_release_rows (self, &released);
 
   row = gtk_list_view_get_row (self, self->anchor_start, &offset);
   if (offset > 0)
@@ -444,9 +446,20 @@ gtk_list_view_ensure_rows (GtkListView              *self,
             }
           if (new_row->widget == NULL)
             {
-              new_row->widget = gtk_list_item_manager_acquire_list_item (self->item_manager,
-                                                                         i,
-                                                                         insert_after);
+              new_row->widget = g_queue_pop_head (&released);
+              if (new_row->widget)
+                {
+                  gtk_list_item_manager_move_list_item (self->item_manager,
+                                                        new_row->widget,
+                                                        i,
+                                                        insert_after);
+                }
+              else
+                {
+                  new_row->widget = gtk_list_item_manager_acquire_list_item (self->item_manager,
+                                                                             i,
+                                                                             insert_after);
+                }
             }
         }
       else
@@ -456,6 +469,9 @@ gtk_list_view_ensure_rows (GtkListView              *self,
         }
       insert_after = new_row->widget;
     }
+
+  while ((widget = g_queue_pop_head (&released)))
+    gtk_list_item_manager_release_list_item (self->item_manager, NULL, widget);
 }
 
 static void


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