[gtk/wip/otte/listview: 72/157] listview: Add list.scroll_to_item action



commit d50a534fd3f6ac3294fb1adda4d4b2bc16de6bdc
Author: Benjamin Otte <otte redhat com>
Date:   Fri Oct 4 06:50:47 2019 +0200

    listview: Add list.scroll_to_item action
    
    The action scrolls the given item into view.
    
    Listitems activate this action when they gain focus.

 gtk/gtklistitem.c | 22 ++++++++++++++++++++++
 gtk/gtklistview.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)
---
diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c
index 356759592c..b01e7d4cfb 100644
--- a/gtk/gtklistitem.c
+++ b/gtk/gtklistitem.c
@@ -23,6 +23,7 @@
 
 #include "gtkbinlayout.h"
 #include "gtkcssnodeprivate.h"
+#include "gtkeventcontrollerkey.h"
 #include "gtkgestureclick.h"
 #include "gtkintl.h"
 #include "gtkmain.h"
@@ -272,6 +273,22 @@ gtk_list_item_click_gesture_pressed (GtkGestureClick *gesture,
     gtk_widget_grab_focus (widget);
 }
 
+static void
+gtk_list_item_focus_changed_cb (GtkEventControllerKey *controller,
+                                GParamSpec            *psepc,
+                                GtkListItem           *self)
+{
+  GtkWidget *widget = GTK_WIDGET (self);
+
+  if (gtk_event_controller_key_contains_focus (controller))
+    {
+      gtk_widget_activate_action (widget,
+                                  "list.scroll-to-item",
+                                  "u",
+                                  self->position);
+    }
+}
+
 static void
 gtk_list_item_click_gesture_released (GtkGestureClick *gesture,
                                       int              n_press,
@@ -293,6 +310,7 @@ gtk_list_item_click_gesture_canceled (GtkGestureClick  *gesture,
 static void
 gtk_list_item_init (GtkListItem *self)
 {
+  GtkEventController *controller;
   GtkGesture *gesture;
 
   self->selectable = TRUE;
@@ -312,6 +330,10 @@ gtk_list_item_init (GtkListItem *self)
   g_signal_connect (gesture, "cancel",
                     G_CALLBACK (gtk_list_item_click_gesture_canceled), self);
   gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
+
+  controller = gtk_event_controller_key_new ();
+  g_signal_connect (controller, "notify::contains-focus", G_CALLBACK (gtk_list_item_focus_changed_cb), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), controller);
 }
 
 GtkListItem *
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index 63f34f455a..6d0283139d 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -731,6 +731,48 @@ gtk_list_view_select_item (GtkWidget  *widget,
     }
 }
 
+static void
+gtk_list_view_scroll_to_item (GtkWidget  *widget,
+                              const char *action_name,
+                              GVariant   *parameter)
+{
+  GtkListView *self = GTK_LIST_VIEW (widget);
+  ListRow *row;
+  guint pos;
+
+  if (!g_variant_check_format_string (parameter, "u", FALSE))
+    return;
+
+  g_variant_get (parameter, "u", &pos);
+  row = gtk_list_item_manager_get_nth (self->item_manager, pos, NULL);
+  if (row == NULL)
+    return;
+
+  if (row->parent.widget)
+    {
+      int y = list_row_get_y (self, row);
+      int start = gtk_adjustment_get_value (self->adjustment[GTK_ORIENTATION_VERTICAL]);
+      int height = gtk_widget_get_height (GTK_WIDGET (self));
+      double align;
+
+      if (y < start)
+        align = 0.0;
+      else if (y + row->height > start + height)
+        align = 1.0;
+      else
+        align = (double) (y - start) / (height - row->height);
+
+      gtk_list_view_set_anchor (self, pos, align);
+    }
+  else
+    {
+      if (pos < gtk_list_item_tracker_get_position (self->item_manager, self->anchor))
+        gtk_list_view_set_anchor (self, pos, 0.0);
+      else
+        gtk_list_view_set_anchor (self, pos, 1.0);
+    }
+}
+
 static void
 gtk_list_view_class_init (GtkListViewClass *klass)
 {
@@ -810,6 +852,18 @@ gtk_list_view_class_init (GtkListViewClass *klass)
                                    "(ubb)",
                                    gtk_list_view_select_item);
 
+  /**
+   * GtkListView|list.scroll-to-item:
+   * @position: position of item to scroll to
+   *
+   * Scrolls to the item given in @position with the minimum amount
+   * of scrolling required. If the item is already visible, nothing happens.
+   */
+  gtk_widget_class_install_action (widget_class,
+                                   "list.scroll-to-item",
+                                   "u",
+                                   gtk_list_view_scroll_to_item);
+
   gtk_widget_class_set_css_name (widget_class, I_("list"));
 }
 


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