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.
This commit is contained in:
Benjamin Otte
2018-10-05 23:24:18 +02:00
parent 21f240e99a
commit 25e896ec40
6 changed files with 153 additions and 19 deletions

View File

@@ -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"
@@ -234,19 +236,98 @@ gtk_list_item_class_init (GtkListItemClass *klass)
}
static void
gtk_list_item_init (GtkListItem *self)
gtk_list_item_click_gesture_pressed (GtkGestureClick *gesture,
int n_press,
double x,
double y,
GtkListItem *self)
{
self->selectable = TRUE;
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);
}
GtkWidget *
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));
}
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]);
}

View File

@@ -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

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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"));
}