[gtk/wip/otte/listview: 34/133] listitem: Add a press gesture to select the item
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 34/133] listitem: Add a press gesture to select the item
- Date: Wed, 11 Dec 2019 03:43:59 +0000 (UTC)
commit 325e94b2aa466ebb4a370b435bdede8bcf837b49
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 is implemented by using actions, which are a neat trick to get to
allow the ListItem to call functions on the ListView without actually
needing to be aware of it.
gtk/gtklistitem.c | 91 +++++++++++++++++++++++++++++++++++++++--
gtk/gtklistitemfactory.c | 15 +++----
gtk/gtklistitemfactoryprivate.h | 3 +-
gtk/gtklistitemmanager.c | 4 +-
gtk/gtklistitemprivate.h | 4 +-
gtk/gtklistview.c | 51 +++++++++++++++++++++++
6 files changed, 151 insertions(+), 17 deletions(-)
---
diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c
index b1461dd386..cc51953835 100644
--- a/gtk/gtklistitem.c
+++ b/gtk/gtklistitem.c
@@ -23,7 +23,9 @@
#include "gtkbinlayout.h"
#include "gtkcssnodeprivate.h"
+#include "gtkgestureclick.h"
#include "gtkintl.h"
+#include "gtkmain.h"
#include "gtkselectionmodel.h" /* for GTK_INVALID_LIST_POSITION */
#include "gtkwidget.h"
#include "gtkwidgetprivate.h"
@@ -233,20 +235,99 @@ gtk_list_item_class_init (GtkListItemClass *klass)
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
}
+static void
+gtk_list_item_click_gesture_pressed (GtkGestureClick *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_widget_activate_action (GTK_WIDGET (self),
+ "list.select-item",
+ "(ubb)",
+ self->position, 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_click_gesture_released (GtkGestureClick *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_click_gesture_canceled (GtkGestureClick *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;
+
self->selectable = TRUE;
+ gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
+
+ gesture = gtk_gesture_click_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_click_gesture_pressed), self);
+ g_signal_connect (gesture, "released",
+ G_CALLBACK (gtk_list_item_click_gesture_released), 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));
}
-GtkWidget *
+GtkListItem *
gtk_list_item_new (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);
+
+ return result;
}
/**
@@ -449,5 +530,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 6b7c2b3550..9115b1c3f8 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..00bce1a10b 100644
--- a/gtk/gtklistitemmanager.c
+++ b/gtk/gtklistitemmanager.c
@@ -21,6 +21,7 @@
#include "gtklistitemmanagerprivate.h"
+#include "gtklistitemprivate.h"
#include "gtkwidgetprivate.h"
struct _GtkListItemManager
@@ -260,7 +261,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 ("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/gtklistitemprivate.h b/gtk/gtklistitemprivate.h
index 08ed82f162..3a2ac463d1 100644
--- a/gtk/gtklistitemprivate.h
+++ b/gtk/gtklistitemprivate.h
@@ -22,9 +22,11 @@
#include "gtklistitem.h"
+#include "gtklistitemmanagerprivate.h"
+
G_BEGIN_DECLS
-GtkWidget * gtk_list_item_new (const char *css_name);
+GtkListItem * gtk_list_item_new (const char *css_name);
void gtk_list_item_set_item (GtkListItem *self,
gpointer item);
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index 494a2a591b..36c18d698b 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -1201,6 +1201,34 @@ gtk_list_view_set_property (GObject *object,
}
}
+static void
+gtk_list_view_select_item (GtkWidget *widget,
+ const char *action_name,
+ GVariant *parameter)
+{
+ GtkListView *self = GTK_LIST_VIEW (widget);
+ GtkSelectionModel *selection_model;
+ guint pos;
+ gboolean modify, extend;
+
+ selection_model = gtk_list_item_manager_get_model (self->item_manager);
+ g_variant_get (parameter, "(ubb)", &pos, &modify, &extend);
+
+ /* XXX: handle extend by tracking the item to extend from */
+
+ if (modify)
+ {
+ if (gtk_selection_model_is_selected (selection_model, pos))
+ gtk_selection_model_unselect_item (selection_model, pos);
+ else
+ gtk_selection_model_select_item (selection_model, pos, FALSE);
+ }
+ else
+ {
+ gtk_selection_model_select_item (selection_model, pos, TRUE);
+ }
+}
+
static void
gtk_list_view_class_init (GtkListViewClass *klass)
{
@@ -1245,6 +1273,29 @@ gtk_list_view_class_init (GtkListViewClass *klass)
g_object_class_install_properties (gobject_class, N_PROPS, properties);
+ /**
+ * GtkListView|list.select-item:
+ * @position: position of item to select
+ * @modify: %TRUE to toggle the existing selection, %FALSE to select
+ * @extend: %TRUE to extend the selection
+ *
+ * Changes selection.
+ *
+ * If @extend is %TRUE and the model supports selecting ranges, the
+ * affected items are all items from the last selected item to the item
+ * in @position.
+ * If @extend is %FALSE or selecting ranges is not supported, only the
+ * item in @position is affected.
+ *
+ * If @modify is %TRUE, the affected items will be set to the same state.
+ * If @modify is %FALSE, the affected items will be selected and
+ * all other items will be deselected.
+ */
+ gtk_widget_class_install_action (widget_class,
+ "list.select-item",
+ "(ubb)",
+ gtk_list_view_select_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]