[gtk/rubberband-again: 1/2] listbase: Redo rubberbanding



commit eeb2d2cc38b2306505e1d61340cbb716cb5c2f14
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Jun 4 22:30:47 2020 -0400

    listbase: Redo rubberbanding
    
    Make it so that the selection is only updated in the end.

 gtk/gtklistbase.c | 95 ++++++++++++++++++++++++++++++-------------------------
 1 file changed, 52 insertions(+), 43 deletions(-)
---
diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c
index 7f8bf34ba5..373ba704e3 100644
--- a/gtk/gtklistbase.c
+++ b/gtk/gtklistbase.c
@@ -34,13 +34,13 @@
 #include "gtksnapshot.h"
 #include "gtkmultiselection.h"
 #include "gtkgizmoprivate.h"
+#include "gtkset.h"
 
 typedef struct _RubberbandData RubberbandData;
 
 struct _RubberbandData
 {
   GtkWidget *widget;
-  GtkSelectionModel *selection;
   double x1, y1;
   double x2, y2;
   gboolean modify;
@@ -53,7 +53,6 @@ rubberband_data_free (gpointer data)
   RubberbandData *rdata = data;
 
   g_clear_pointer (&rdata->widget, gtk_widget_unparent);
-  g_clear_object (&rdata->selection);
   g_free (rdata);
 }
 
@@ -1324,7 +1323,6 @@ gtk_list_base_start_rubberband (GtkListBase *self,
 {
   GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
   double value_x, value_y;
-  GtkSelectionModel *selection;
 
   if (priv->rubberband)
     return;
@@ -1343,24 +1341,66 @@ gtk_list_base_start_rubberband (GtkListBase *self,
   priv->rubberband->widget = gtk_gizmo_new ("rubberband",
                                             NULL, NULL, NULL, NULL, NULL, NULL);
   gtk_widget_set_parent (priv->rubberband->widget, GTK_WIDGET (self));
+}
 
-  selection = gtk_list_item_manager_get_model (priv->item_manager);
-  if ((modify || extend) &&
-      GTK_IS_MULTI_SELECTION (selection))
-    priv->rubberband->selection = GTK_SELECTION_MODEL (gtk_multi_selection_copy (selection));
+static void
+range_cb (guint     position,
+          guint    *start,
+          guint    *n_items,
+          gboolean *selected,
+          gpointer  data)
+{
+  GtkSet *set = data;
 
-  if (!modify && !extend)
-    gtk_selection_model_unselect_all (selection);
+  gtk_set_find_range (set, position, gtk_set_get_max (set), start, n_items, selected);
 }
 
 static void
 gtk_list_base_stop_rubberband (GtkListBase *self)
 {
   GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+  GtkListItemManagerItem *item;
+  GtkSelectionModel *model;
+  GtkSet *active;
 
   if (!priv->rubberband)
     return;
 
+  active = gtk_set_new ();
+
+  for (item = gtk_list_item_manager_get_first (priv->item_manager);
+       item != NULL;
+       item = gtk_rb_tree_node_get_next (item))
+    {
+      if (!item->widget)
+        continue;
+
+      if (gtk_widget_get_state_flags (item->widget) & GTK_STATE_FLAG_ACTIVE)
+        {
+          guint pos;
+
+          pos = gtk_list_item_manager_get_item_position (priv->item_manager, item);
+          gtk_set_add_item (active, pos);
+          gtk_widget_unset_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE);
+        }
+    }
+
+  model = gtk_list_item_manager_get_model (priv->item_manager);
+
+  if (priv->rubberband->modify)
+    {
+      gtk_selection_model_unselect_callback (model, range_cb, active);
+    }
+  else
+    {
+      if (!priv->rubberband->extend)
+        gtk_selection_model_unselect_all (model);
+
+      gtk_selection_model_select_callback (model, range_cb, active);
+    }
+
+  gtk_set_free (active);
+
   g_clear_pointer (&priv->rubberband, rubberband_data_free);
   remove_autoscroll (self);
 
@@ -1423,55 +1463,24 @@ gtk_list_base_update_rubberband_selection (GtkListBase *self)
   GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
   GdkRectangle rect;
   GdkRectangle alloc;
-  GtkSelectionModel *model;
   GtkListItemManagerItem *item;
 
   gtk_list_base_allocate_rubberband (self);
   gtk_widget_get_allocation (priv->rubberband->widget, &rect);
 
-  model = gtk_list_item_manager_get_model (priv->item_manager);
-
   for (item = gtk_list_item_manager_get_first (priv->item_manager);
        item != NULL;
        item = gtk_rb_tree_node_get_next (item))
     {
-      guint pos;
-      gboolean selected;
-      gboolean was_selected;
-
       if (!item->widget)
         continue;
 
-      pos = gtk_list_item_manager_get_item_position (priv->item_manager, item);
-
       gtk_widget_get_allocation (item->widget, &alloc);
 
-      if (priv->rubberband->selection)
-        was_selected = gtk_selection_model_is_selected (priv->rubberband->selection, pos);
-      else
-        was_selected = FALSE;
-
-      selected = gdk_rectangle_intersect (&rect, &alloc, &alloc);
-
-      if (priv->rubberband->modify)
-        {
-          if (was_selected)
-            {
-              if (selected)
-                gtk_selection_model_unselect_item (model, pos);
-              else
-                gtk_selection_model_select_item (model, pos, FALSE);
-            }
-          else
-            gtk_selection_model_unselect_item (model, pos);
-        }
+      if (gdk_rectangle_intersect (&rect, &alloc, &alloc))
+        gtk_widget_set_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE, FALSE);
       else
-        {
-          if (selected || was_selected)
-            gtk_selection_model_select_item (model, pos, FALSE);
-          else
-            gtk_selection_model_unselect_item (model, pos);
-        }
+        gtk_widget_unset_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE);
     }
 }
 


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