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