[gtk/wip/otte/listview: 121/128] listitem: Add a press gesture to select the item



commit a75de1cd44af8e07c2975cc3b7054707d88f6ae2
Author: Benjamin Otte <otte redhat com>
Date:   Fri Oct 5 23:24:18 2018 +0200

    listitem: Add a press gesture to select the item
    
    This requires a bunch of refactoring because so far the ListItem had no
    knowledge of the manager, but it needs the manager so it can access the
    selection to trigger the select/unselect operation.

 gtk/gtklistitem.c               | 95 ++++++++++++++++++++++++++++++++++++++---
 gtk/gtklistitemfactory.c        | 15 +++----
 gtk/gtklistitemfactoryprivate.h |  3 +-
 gtk/gtklistitemmanager.c        | 25 ++++++++++-
 gtk/gtklistitemmanagerprivate.h |  5 +++
 gtk/gtklistitemprivate.h        |  5 ++-
 6 files changed, 130 insertions(+), 18 deletions(-)
---
diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c
index 4084cf2f6f..817304172d 100644
--- a/gtk/gtklistitem.c
+++ b/gtk/gtklistitem.c
@@ -22,7 +22,9 @@
 #include "gtklistitemprivate.h"
 
 #include "gtkcssnodeprivate.h"
+#include "gtkgesturemultipress.h"
 #include "gtkintl.h"
+#include "gtkmain.h"
 #include "gtkwidgetprivate.h"
 
 /**
@@ -53,6 +55,8 @@ struct _GtkListItem
 {
   GtkBin parent_instance;
 
+  GtkListItemManager *manager; /* no ref, the manager refs us */
+
   GObject *item;
   guint position;
 
@@ -201,22 +205,101 @@ gtk_list_item_class_init (GtkListItemClass *klass)
   gtk_widget_class_set_css_name (widget_class, I_("row"));
 }
 
+static void
+gtk_list_item_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                          int                   n_press,
+                                          double                x,
+                                          double                y,
+                                          GtkListItem          *self)
+{
+  GtkWidget *widget = GTK_WIDGET (self);
+  GdkModifierType state;
+  GdkModifierType mask;
+  gboolean extend = FALSE, modify = FALSE;
+
+  if (!self->selectable)
+    {
+      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+      return;
+    }
+
+  if (gtk_get_current_event_state (&state))
+    {
+      mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
+      if ((state & mask) == mask)
+        modify = TRUE;
+      mask = gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
+      if ((state & mask) == mask)
+        extend = TRUE;
+    }
+
+  gtk_list_item_manager_select (self->manager, self, modify, extend);
+
+  gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_ACTIVE, FALSE);
+
+  if (gtk_widget_get_focus_on_click (widget))
+    gtk_widget_grab_focus (widget);
+}
+
+static void
+gtk_list_item_multipress_gesture_released (GtkGestureMultiPress *gesture,
+                                           int                   n_press,
+                                           double                x,
+                                           double                y,
+                                           GtkListItem          *self)
+{
+  gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE);
+}
+
+static void
+gtk_list_item_multipress_gesture_canceled (GtkGestureMultiPress *gesture,
+                                           GdkEventSequence     *sequence,
+                                           GtkListItem          *self)
+{
+  gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_ACTIVE);
+}
+
 static void
 gtk_list_item_init (GtkListItem *self)
 {
+  GtkGesture *gesture;
+
   gtk_widget_set_has_surface (GTK_WIDGET (self), FALSE);
 
   self->selectable = TRUE;
+  gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
+
+  gesture = gtk_gesture_multi_press_new ();
+  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
+                                              GTK_PHASE_BUBBLE);
+  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture),
+                                     FALSE);
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture),
+                                 GDK_BUTTON_PRIMARY);
+  g_signal_connect (gesture, "pressed",
+                    G_CALLBACK (gtk_list_item_multipress_gesture_pressed), self);
+  g_signal_connect (gesture, "released",
+                    G_CALLBACK (gtk_list_item_multipress_gesture_released), self);
+  g_signal_connect (gesture, "cancel",
+                    G_CALLBACK (gtk_list_item_multipress_gesture_canceled), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
 }
 
-GtkWidget *
-gtk_list_item_new (const char *css_name)
+GtkListItem *
+gtk_list_item_new (GtkListItemManager *manager,
+                   const char         *css_name)
 {
+  GtkListItem *result;
+
   g_return_val_if_fail (css_name != NULL, NULL);
 
-  return g_object_new (GTK_TYPE_LIST_ITEM,
-                       "css-name", css_name,
-                       NULL);
+  result = g_object_new (GTK_TYPE_LIST_ITEM,
+                         "css-name", css_name,
+                         NULL);
+
+  result->manager = manager;
+
+  return result;
 }
 
 /**
@@ -370,5 +453,7 @@ gtk_list_item_set_selectable (GtkListItem *self,
 
   self->selectable = selectable;
 
+  gtk_widget_set_can_focus (GTK_WIDGET (self), self->selectable);
+
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTABLE]);
 }
diff --git a/gtk/gtklistitemfactory.c b/gtk/gtklistitemfactory.c
index 454344ae9b..d701918ea1 100644
--- a/gtk/gtklistitemfactory.c
+++ b/gtk/gtklistitemfactory.c
@@ -85,19 +85,14 @@ gtk_list_item_factory_new (GtkListItemSetupFunc setup_func,
   return self;
 }
 
-GtkListItem *
-gtk_list_item_factory_create (GtkListItemFactory *self)
+void
+gtk_list_item_factory_setup (GtkListItemFactory *self,
+                             GtkListItem         *list_item)
 {
-  GtkWidget *result;
-
-  g_return_val_if_fail (GTK_IS_LIST_ITEM_FACTORY (self), NULL);
-
-  result = gtk_list_item_new ("row");
+  g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (self));
 
   if (self->setup_func)
-    self->setup_func (GTK_LIST_ITEM (result), self->user_data);
-
-  return GTK_LIST_ITEM (result);
+    self->setup_func (list_item, self->user_data);
 }
 
 void
diff --git a/gtk/gtklistitemfactoryprivate.h b/gtk/gtklistitemfactoryprivate.h
index 3e815fa131..dc538f09fa 100644
--- a/gtk/gtklistitemfactoryprivate.h
+++ b/gtk/gtklistitemfactoryprivate.h
@@ -43,7 +43,8 @@ GtkListItemFactory *    gtk_list_item_factory_new               (GtkListItemSetu
                                                                  gpointer                user_data,
                                                                  GDestroyNotify          user_destroy);
 
-GtkListItem *           gtk_list_item_factory_create            (GtkListItemFactory     *self);
+void                    gtk_list_item_factory_setup             (GtkListItemFactory     *self,
+                                                                 GtkListItem            *list_item);
 
 void                    gtk_list_item_factory_bind              (GtkListItemFactory     *self,
                                                                  GtkListItem            *list_item,
diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c
index e7c11f483f..9d8fbbc85a 100644
--- a/gtk/gtklistitemmanager.c
+++ b/gtk/gtklistitemmanager.c
@@ -21,6 +21,7 @@
 
 #include "gtklistitemmanagerprivate.h"
 
+#include "gtklistitemprivate.h"
 #include "gtkwidgetprivate.h"
 
 struct _GtkListItemManager
@@ -129,6 +130,27 @@ gtk_list_item_manager_get_model (GtkListItemManager *self)
   return self->model;
 }
 
+void
+gtk_list_item_manager_select (GtkListItemManager *self,
+                              GtkListItem        *item,
+                              gboolean            modify,
+                              gboolean            extend)
+{
+  guint pos = gtk_list_item_get_position (item);
+
+  if (modify)
+    {
+      if (gtk_list_item_get_selected (item))
+        gtk_selection_model_unselect_item (self->model, pos);
+      else
+        gtk_selection_model_select_item (self->model, pos, FALSE);
+    }
+  else
+    {
+      gtk_selection_model_select_item (self->model, pos, TRUE);
+    }
+}
+
 #if 0 
 /*
  * gtk_list_item_manager_get_size:
@@ -260,7 +282,8 @@ gtk_list_item_manager_acquire_list_item (GtkListItemManager *self,
   g_return_val_if_fail (GTK_IS_LIST_ITEM_MANAGER (self), NULL);
   g_return_val_if_fail (prev_sibling == NULL || GTK_IS_WIDGET (prev_sibling), NULL);
 
-  result = gtk_list_item_factory_create (self->factory);
+  result = gtk_list_item_new (self, "row");
+  gtk_list_item_factory_setup (self->factory, result);
 
   item = g_list_model_get_item (G_LIST_MODEL (self->model), position);
   selected = gtk_selection_model_is_selected (self->model, position);
diff --git a/gtk/gtklistitemmanagerprivate.h b/gtk/gtklistitemmanagerprivate.h
index 47a4434d7d..bd189539d6 100644
--- a/gtk/gtklistitemmanagerprivate.h
+++ b/gtk/gtklistitemmanagerprivate.h
@@ -52,6 +52,11 @@ GtkSelectionModel *     gtk_list_item_manager_get_model         (GtkListItemMana
 
 guint                   gtk_list_item_manager_get_size          (GtkListItemManager     *self);
 
+void                    gtk_list_item_manager_select            (GtkListItemManager     *self,
+                                                                 GtkListItem            *item,
+                                                                 gboolean                modify,
+                                                                 gboolean                extend);
+
 GtkListItemManagerChange *
                         gtk_list_item_manager_begin_change      (GtkListItemManager     *self);
 void                    gtk_list_item_manager_end_change        (GtkListItemManager     *self,
diff --git a/gtk/gtklistitemprivate.h b/gtk/gtklistitemprivate.h
index 08ed82f162..141471ecd7 100644
--- a/gtk/gtklistitemprivate.h
+++ b/gtk/gtklistitemprivate.h
@@ -22,9 +22,12 @@
 
 #include "gtklistitem.h"
 
+#include "gtklistitemmanagerprivate.h"
+
 G_BEGIN_DECLS
 
-GtkWidget *     gtk_list_item_new                               (const char             *css_name);
+GtkListItem *   gtk_list_item_new                               (GtkListItemManager     *manager,
+                                                                 const char             *css_name);
 
 void            gtk_list_item_set_item                          (GtkListItem            *self,
                                                                  gpointer                item);


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