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:
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user