[gtk/listview-for-merge: 68/150] listview: Track focus movements and update selection



commit b9eb818b57c66145c9c6e59cd98cca42a5ae12b7
Author: Benjamin Otte <otte redhat com>
Date:   Tue Oct 15 23:45:33 2019 +0200

    listview: Track focus movements and update selection
    
    When focus moves via tab/arrow, we need to select the new item.

 gtk/gtklistview.c | 183 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 120 insertions(+), 63 deletions(-)
---
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index 85a4a5744f..7650918db3 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -24,6 +24,7 @@
 #include "gtkadjustment.h"
 #include "gtkintl.h"
 #include "gtklistitemmanagerprivate.h"
+#include "gtkmain.h"
 #include "gtkorientableprivate.h"
 #include "gtkprivate.h"
 #include "gtkrbtreeprivate.h"
@@ -583,6 +584,119 @@ gtk_list_view_size_allocate (GtkWidget *widget,
     }
 }
 
+static void
+gtk_list_view_select_item (GtkListView *self,
+                           guint        pos,
+                           gboolean     modify,
+                           gboolean     extend)
+{
+  GtkSelectionModel *selection_model;
+  gboolean success = FALSE;
+
+  selection_model = gtk_list_item_manager_get_model (self->item_manager);
+
+  if (extend)
+    {
+      guint start_pos = gtk_list_item_tracker_get_position (self->item_manager, self->selected);
+      if (start_pos != GTK_INVALID_LIST_POSITION)
+        {
+          guint max = MAX (start_pos, pos);
+          guint min = MIN (start_pos, pos);
+          if (modify)
+            {
+              if (gtk_selection_model_is_selected (selection_model, start_pos))
+                {
+                  success = gtk_selection_model_select_range (selection_model,
+                                                              min,
+                                                              max - min + 1,
+                                                              FALSE);
+                }
+              else
+                {
+                  success = gtk_selection_model_unselect_range (selection_model,
+                                                                min,
+                                                                max - min + 1);
+                }
+            }
+          else
+            {
+              success = gtk_selection_model_select_range (selection_model,
+                                                          min,
+                                                          max - min + 1,
+                                                          TRUE);
+            }
+        }
+      /* If there's no range to select or selecting ranges isn't supported
+       * by the model, fall through to normal setting.
+       */
+    }
+  if (success)
+    return;
+
+  if (modify)
+    {
+      if (gtk_selection_model_is_selected (selection_model, pos))
+        success = gtk_selection_model_unselect_item (selection_model, pos);
+      else
+        success = gtk_selection_model_select_item (selection_model, pos, FALSE);
+    }
+  else
+    {
+      success = gtk_selection_model_select_item (selection_model, pos, TRUE);
+    }
+  if (success)
+    {
+      gtk_list_item_tracker_set_position (self->item_manager,
+                                          self->selected,
+                                          pos,
+                                          0, 0);
+    }
+}
+
+static gboolean
+gtk_list_view_focus (GtkWidget        *widget,
+                     GtkDirectionType  direction)
+{
+  GtkListView *self = GTK_LIST_VIEW (widget);
+  GtkWidget *old_focus_child, *new_focus_child;
+
+  old_focus_child = gtk_widget_get_focus_child (widget);
+
+  if (!GTK_WIDGET_CLASS (gtk_list_view_parent_class)->focus (widget, direction))
+    return FALSE;
+
+  new_focus_child = gtk_widget_get_focus_child (widget);
+
+  if (old_focus_child != new_focus_child &&
+      GTK_IS_LIST_ITEM (new_focus_child))
+    {
+      gboolean extend = FALSE, modify = FALSE;
+
+      if (old_focus_child)
+        {
+          GdkSeat *seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
+          if (seat)
+            {
+              GdkDevice *keyboard = gdk_seat_get_keyboard (seat);
+              if (keyboard)
+                {
+                  GdkModifierType state = gdk_device_get_modifier_state (keyboard);
+
+                  extend = (state & GDK_SHIFT_MASK) != 0;
+                  modify = (state & GDK_CONTROL_MASK) != 0;
+                }
+            }
+        }
+
+      gtk_list_view_select_item (self,
+                                 gtk_list_item_get_position (GTK_LIST_ITEM (new_focus_child)),
+                                 modify,
+                                 extend);
+    }
+
+  return TRUE;
+}
+
 static void
 gtk_list_view_clear_adjustment (GtkListView    *self,
                                 GtkOrientation  orientation)
@@ -778,75 +892,17 @@ gtk_list_view_set_property (GObject      *object,
 }
 
 static void
-gtk_list_view_select_item (GtkWidget  *widget,
-                           const char *action_name,
-                           GVariant   *parameter)
+gtk_list_view_select_item_action (GtkWidget  *widget,
+                                  const char *action_name,
+                                  GVariant   *parameter)
 {
   GtkListView *self = GTK_LIST_VIEW (widget);
-  GtkSelectionModel *selection_model;
   guint pos;
   gboolean modify, extend;
-  gboolean success = FALSE;
 
-  selection_model = gtk_list_item_manager_get_model (self->item_manager);
   g_variant_get (parameter, "(ubb)", &pos, &modify, &extend);
 
-  if (extend)
-    {
-      guint start_pos = gtk_list_item_tracker_get_position (self->item_manager, self->selected);
-      if (start_pos != GTK_INVALID_LIST_POSITION)
-        {
-          guint max = MAX (start_pos, pos);
-          guint min = MIN (start_pos, pos);
-          if (modify)
-            {
-              if (gtk_selection_model_is_selected (selection_model, start_pos))
-                {
-                  success = gtk_selection_model_select_range (selection_model,
-                                                              min,
-                                                              max - min + 1,
-                                                              FALSE);
-                }
-              else
-                {
-                  success = gtk_selection_model_unselect_range (selection_model,
-                                                                min,
-                                                                max - min + 1);
-                }
-            }
-          else
-            {
-              success = gtk_selection_model_select_range (selection_model,
-                                                          min,
-                                                          max - min + 1,
-                                                          TRUE);
-            }
-        }
-      /* If there's no range to select or selecting ranges isn't supported
-       * by the model, fall through to normal setting.
-       */
-    }
-  if (success)
-    return;
-
-  if (modify)
-    {
-      if (gtk_selection_model_is_selected (selection_model, pos))
-        success = gtk_selection_model_unselect_item (selection_model, pos);
-      else
-        success = gtk_selection_model_select_item (selection_model, pos, FALSE);
-    }
-  else
-    {
-      success = gtk_selection_model_select_item (selection_model, pos, TRUE);
-    }
-  if (success)
-    {
-      gtk_list_item_tracker_set_position (self->item_manager,
-                                          self->selected,
-                                          pos,
-                                          0, 0);
-    }
+  gtk_list_view_select_item (self, pos, modify, extend);
 }
 
 static void
@@ -922,6 +978,7 @@ gtk_list_view_class_init (GtkListViewClass *klass)
 
   widget_class->measure = gtk_list_view_measure;
   widget_class->size_allocate = gtk_list_view_size_allocate;
+  widget_class->focus = gtk_list_view_focus;
 
   gobject_class->dispose = gtk_list_view_dispose;
   gobject_class->finalize = gtk_list_view_finalize;
@@ -1052,7 +1109,7 @@ gtk_list_view_class_init (GtkListViewClass *klass)
   gtk_widget_class_install_action (widget_class,
                                    "list.select-item",
                                    "(ubb)",
-                                   gtk_list_view_select_item);
+                                   gtk_list_view_select_item_action);
 
   /**
    * GtkListView|list.scroll-to-item:


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