From: Benjamin Otte Date: Fri, 24 Mar 2023 02:00:02 +0000 (+0100) Subject: listview: Add GtkListView::tab-behavior X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~1^2~497^2~2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=c0ca71e9f4d0821139233333c06032eea872bfed;p=gtk4.git listview: Add GtkListView::tab-behavior The implementation lives (as always) in GtkListBase. This is a feature request from the Nautilus developers, who currently do some hacks to emulate that behavior and it apparently only breaks sometimes. --- diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h index af2f3689ca..eb460ea997 100644 --- a/gtk/gtkenums.h +++ b/gtk/gtkenums.h @@ -265,6 +265,31 @@ typedef enum GTK_JUSTIFY_FILL } GtkJustification; +/** + * GtkListTabBehavior: + * @GTK_LIST_TAB_ALL: Cycle through all focusable items of the list + * @GTK_LIST_TAB_ITEM: Cycle through a single list element, then move + * focus out of the list. Moving focus between items needs to be + * done with the arrow keys. + * @GTK_LIST_TAB_CELL: Cycle only through a single cell, then + * move focus out of the list. Moving focus between cells needs to + * be done with the arrow keys. This is only relevant for + * cell-based widgets like #GtkColumnView, otherwise it behaves + * like `GTK_LIST_TAB_ITEM`. + * + * Used to configure the focus behavior in the `GTK_DIR_TAB_FORWARD` + * and `GTK_DIR_TAB_BACKWARD` direction, like the Tab key + * in a [class@Gtk.ListView]. + * + * Since: 4.12 + */ +typedef enum +{ + GTK_LIST_TAB_ALL, + GTK_LIST_TAB_ITEM, + GTK_LIST_TAB_CELL +} GtkListTabBehavior; + /** * GtkMessageType: * @GTK_MESSAGE_INFO: Informational message diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c index 4f0d575777..3316145484 100644 --- a/gtk/gtklistbase.c +++ b/gtk/gtklistbase.c @@ -68,6 +68,7 @@ struct _GtkListBasePrivate GtkOrientation orientation; GtkAdjustment *adjustment[2]; GtkScrollablePolicy scroll_policy[2]; + GtkListTabBehavior tab_behavior; GtkListItemTracker *anchor; double anchor_align_along; @@ -554,21 +555,42 @@ gtk_list_base_focus (GtkWidget *widget, * while keeping the selection intact. */ old = GTK_INVALID_LIST_POSITION; + if (priv->tab_behavior == GTK_LIST_TAB_ALL) + { + if (direction == GTK_DIR_TAB_FORWARD) + pos = 0; + else if (direction == GTK_DIR_TAB_BACKWARD) + pos = n_items - 1; + } } else { switch (direction) { case GTK_DIR_TAB_FORWARD: - pos++; - if (pos >= n_items) - return FALSE; + if (priv->tab_behavior == GTK_LIST_TAB_ALL) + { + pos++; + if (pos >= n_items) + return FALSE; + } + else + { + return FALSE; + } break; case GTK_DIR_TAB_BACKWARD: - if (pos == 0) - return FALSE; - pos--; + if (priv->tab_behavior == GTK_LIST_TAB_ALL) + { + if (pos == 0) + return FALSE; + pos--; + } + else + { + return FALSE; + } break; case GTK_DIR_UP: @@ -1948,6 +1970,7 @@ gtk_list_base_init_real (GtkListBase *self, priv->adjustment[GTK_ORIENTATION_VERTICAL] = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); g_object_ref_sink (priv->adjustment[GTK_ORIENTATION_VERTICAL]); + priv->tab_behavior = GTK_LIST_TAB_ALL; priv->orientation = GTK_ORIENTATION_VERTICAL; gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN); @@ -2248,3 +2271,21 @@ gtk_list_base_set_model (GtkListBase *self, return TRUE; } + +void +gtk_list_base_set_tab_behavior (GtkListBase *self, + GtkListTabBehavior behavior) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + priv->tab_behavior = behavior; +} + +GtkListTabBehavior +gtk_list_base_get_tab_behavior (GtkListBase *self) +{ + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + + return priv->tab_behavior; +} + diff --git a/gtk/gtklistbaseprivate.h b/gtk/gtklistbaseprivate.h index 9ee30b79b4..cd66e58ecc 100644 --- a/gtk/gtklistbaseprivate.h +++ b/gtk/gtklistbaseprivate.h @@ -85,6 +85,10 @@ void gtk_list_base_set_anchor_max_widgets (GtkListBase void gtk_list_base_set_enable_rubberband (GtkListBase *self, gboolean enable); gboolean gtk_list_base_get_enable_rubberband (GtkListBase *self); +void gtk_list_base_set_tab_behavior (GtkListBase *self, + GtkListTabBehavior behavior); +GtkListTabBehavior gtk_list_base_get_tab_behavior (GtkListBase *self); + void gtk_list_base_allocate (GtkListBase *self); diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c index 3e0f277b60..c7977119a8 100644 --- a/gtk/gtklistview.c +++ b/gtk/gtklistview.c @@ -25,11 +25,9 @@ #include "gtklistbaseprivate.h" #include "gtklistitemmanagerprivate.h" #include "gtklistitemwidgetprivate.h" -#include "gtkmain.h" -#include "gtkprivate.h" -#include "gtkrbtreeprivate.h" -#include "gtkwidgetprivate.h" #include "gtkmultiselection.h" +#include "gtktypebuiltins.h" +#include "gtkwidgetprivate.h" /* Maximum number of list items created by the listview. * For debugging, you can set this to G_MAXUINT to ensure @@ -145,11 +143,12 @@ enum { PROP_0, + PROP_ENABLE_RUBBERBAND, PROP_FACTORY, PROP_MODEL, PROP_SHOW_SEPARATORS, PROP_SINGLE_CLICK_ACTIVATE, - PROP_ENABLE_RUBBERBAND, + PROP_TAB_BEHAVIOR, N_PROPS }; @@ -627,6 +626,10 @@ gtk_list_view_get_property (GObject *object, switch (property_id) { + case PROP_ENABLE_RUBBERBAND: + g_value_set_boolean (value, gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self))); + break; + case PROP_FACTORY: g_value_set_object (value, self->factory); break; @@ -643,8 +646,8 @@ gtk_list_view_get_property (GObject *object, g_value_set_boolean (value, self->single_click_activate); break; - case PROP_ENABLE_RUBBERBAND: - g_value_set_boolean (value, gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self))); + case PROP_TAB_BEHAVIOR: + g_value_set_enum (value, gtk_list_base_get_tab_behavior (GTK_LIST_BASE (self))); break; default: @@ -663,6 +666,10 @@ gtk_list_view_set_property (GObject *object, switch (property_id) { + case PROP_ENABLE_RUBBERBAND: + gtk_list_view_set_enable_rubberband (self, g_value_get_boolean (value)); + break; + case PROP_FACTORY: gtk_list_view_set_factory (self, g_value_get_object (value)); break; @@ -679,8 +686,8 @@ gtk_list_view_set_property (GObject *object, gtk_list_view_set_single_click_activate (self, g_value_get_boolean (value)); break; - case PROP_ENABLE_RUBBERBAND: - gtk_list_view_set_enable_rubberband (self, g_value_get_boolean (value)); + case PROP_TAB_BEHAVIOR: + gtk_list_view_set_tab_behavior (self, g_value_get_enum (value)); break; default: @@ -729,6 +736,16 @@ gtk_list_view_class_init (GtkListViewClass *klass) gobject_class->get_property = gtk_list_view_get_property; gobject_class->set_property = gtk_list_view_set_property; + /** + * GtkListView:enable-rubberband: (attributes org.gtk.Property.get=gtk_list_view_get_enable_rubberband org.gtk.Property.set=gtk_list_view_set_enable_rubberband) + * + * Allow rubberband selection. + */ + properties[PROP_ENABLE_RUBBERBAND] = + g_param_spec_boolean ("enable-rubberband", NULL, NULL, + FALSE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + /** * GtkListView:factory: (attributes org.gtk.Property.get=gtk_list_view_get_factory org.gtk.Property.set=gtk_list_view_set_factory) * @@ -770,14 +787,17 @@ gtk_list_view_class_init (GtkListViewClass *klass) G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); /** - * GtkListView:enable-rubberband: (attributes org.gtk.Property.get=gtk_list_view_get_enable_rubberband org.gtk.Property.set=gtk_list_view_set_enable_rubberband) + * GtkListView:tab-behavior: (attributes org.gtk.Property.get=gtk_list_view_get_tab_behavior org.gtk.Property.set=gtk_list_view_set_tab_behavior) * - * Allow rubberband selection. + * Behavior of the Tab key + * + * Since: 4.12 */ - properties[PROP_ENABLE_RUBBERBAND] = - g_param_spec_boolean ("enable-rubberband", NULL, NULL, - FALSE, - G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + properties[PROP_TAB_BEHAVIOR] = + g_param_spec_enum ("tab-behavior", NULL, NULL, + GTK_TYPE_LIST_TAB_BEHAVIOR, + GTK_LIST_TAB_ALL, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (gobject_class, N_PROPS, properties); @@ -1089,3 +1109,45 @@ gtk_list_view_get_enable_rubberband (GtkListView *self) return gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self)); } + +/** + * gtk_list_view_set_tab_behavior: (attributes org.gtk.Method.set_property=tab-behavior) + * @self: a `GtkListView` + * @tab_behavior: The desired tab behavior + * + * Sets the behavior of the Tab and Shift+Tab keys. + * + * Since: 4.12 + */ +void +gtk_list_view_set_tab_behavior (GtkListView *self, + GtkListTabBehavior tab_behavior) +{ + g_return_if_fail (GTK_IS_LIST_VIEW (self)); + + if (tab_behavior == gtk_list_base_get_tab_behavior (GTK_LIST_BASE (self))) + return; + + gtk_list_base_set_tab_behavior (GTK_LIST_BASE (self), tab_behavior); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TAB_BEHAVIOR]); +} + +/** + * gtk_list_view_get_tab_behavior: (attributes org.gtk.Method.get_property=tab-behavior) + * @self: a `GtkListView` + * + * Gets the behavior set for the Tab key. + * + * Returns: The behavior of the Tab key + * + * Since: 4.12 + */ +gboolean +gtk_list_view_get_tab_behavior (GtkListView *self) +{ + g_return_val_if_fail (GTK_IS_LIST_VIEW (self), FALSE); + + return gtk_list_base_get_tab_behavior (GTK_LIST_BASE (self)); +} + diff --git a/gtk/gtklistview.h b/gtk/gtklistview.h index 2664b07afb..e2ee0b8c4d 100644 --- a/gtk/gtklistview.h +++ b/gtk/gtklistview.h @@ -76,6 +76,13 @@ void gtk_list_view_set_enable_rubberband (GtkListView GDK_AVAILABLE_IN_ALL gboolean gtk_list_view_get_enable_rubberband (GtkListView *self); +GDK_AVAILABLE_IN_4_12 +void gtk_list_view_set_tab_behavior (GtkListView *self, + GtkListTabBehavior tab_behavior); +GDK_AVAILABLE_IN_4_12 +gboolean gtk_list_view_get_tab_behavior (GtkListView *self); + + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkListView, g_object_unref) G_END_DECLS