summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2019-10-24 06:49:38 +0200
committerBenjamin Otte <otte@redhat.com>2019-12-12 07:47:44 +0100
commitdf4a5944ce7ff9ecde1e0f4ad54437bc72eaa514 (patch)
tree37013173fceaeee523d35d31cece8389ad75baf6
parent10ea8705b6b8eb6fd5fc898346e13e81a662b11f (diff)
downloadgtk+-df4a5944ce7ff9ecde1e0f4ad54437bc72eaa514.tar.gz
listbase: Move focus moving keybindings here
The focus tracker is not yet moved because that depends on scroll_to() support and we don't have that yet. Whoops. So we use a hack.
-rw-r--r--gtk/gtkgridview.c196
-rw-r--r--gtk/gtklistbase.c298
-rw-r--r--gtk/gtklistbaseprivate.h7
-rw-r--r--gtk/gtklistview.c200
4 files changed, 364 insertions, 337 deletions
diff --git a/gtk/gtkgridview.c b/gtk/gtkgridview.c
index 8d28701bfd..4633a4972c 100644
--- a/gtk/gtkgridview.c
+++ b/gtk/gtkgridview.c
@@ -400,60 +400,46 @@ gtk_grid_view_set_anchor (GtkGridView *self,
}
}
-static gboolean
-gtk_grid_view_focus (GtkWidget *widget,
- GtkDirectionType direction)
+static guint
+gtk_grid_view_move_focus_along (GtkListBase *base,
+ guint pos,
+ int steps)
{
- GtkGridView *self = GTK_GRID_VIEW (widget);
- GtkWidget *old_focus_child, *new_focus_child;
+ GtkGridView *self = GTK_GRID_VIEW (base);
- old_focus_child = gtk_widget_get_focus_child (widget);
+ steps *= self->n_columns;
- if (old_focus_child == NULL &&
- (direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD))
+ if (steps < 0)
{
- Cell *cell;
- guint pos;
-
- /* When tabbing into the listview, don't focus the first/last item,
- * but keep the previously focused item
- */
- pos = gtk_list_item_tracker_get_position (self->item_manager, self->focus);
- cell = gtk_list_item_manager_get_nth (self->item_manager, pos, NULL);
- if (cell && gtk_widget_grab_focus (cell->parent.widget))
- goto moved_focus;
+ if (pos >= self->n_columns)
+ pos -= MIN (pos, -steps);
+ }
+ else
+ {
+ guint n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
+ if (n_items / self->n_columns > pos / self->n_columns)
+ pos += MIN (n_items - pos - 1, steps);
}
- if (!GTK_WIDGET_CLASS (gtk_grid_view_parent_class)->focus (widget, direction))
- return FALSE;
+ return pos;
+}
-moved_focus:
- new_focus_child = gtk_widget_get_focus_child (widget);
+static guint
+gtk_grid_view_move_focus_across (GtkListBase *base,
+ guint pos,
+ int steps)
+{
+ GtkGridView *self = GTK_GRID_VIEW (base);
- if (old_focus_child != new_focus_child &&
- GTK_IS_LIST_ITEM (new_focus_child))
+ if (steps < 0)
+ return pos - MIN (pos, -steps);
+ else
{
- GdkModifierType state;
- GdkModifierType mask;
- gboolean extend = FALSE, modify = FALSE;
-
- if (old_focus_child && 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_base_select_item (GTK_LIST_BASE (self),
- gtk_list_item_get_position (GTK_LIST_ITEM (new_focus_child)),
- modify,
- extend);
+ guint n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
+ pos += MIN (n_items - pos - 1, steps);
}
- return TRUE;
+ return pos;
}
static void
@@ -1254,81 +1240,6 @@ gtk_grid_view_activate_item (GtkWidget *widget,
}
static void
-gtk_grid_view_move_cursor (GtkWidget *widget,
- GVariant *args,
- gpointer unused)
-{
- GtkGridView *self = GTK_GRID_VIEW (widget);
- int amount;
- guint orientation;
- guint pos, n_items;
- gboolean select, modify, extend;
-
- g_variant_get (args, "(ubbbi)", &orientation, &select, &modify, &extend, &amount);
-
- if (gtk_list_base_get_orientation (GTK_LIST_BASE (self)) == orientation)
- amount *= self->n_columns;
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL &&
- gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- amount = -amount;
-
- pos = gtk_list_item_tracker_get_position (self->item_manager, self->focus);
- n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
- if (pos >= n_items || /* no focused item */
- (amount < 0 && pos < -amount))
- return;
- if (amount > 0 && amount > n_items - pos)
- {
- /* pressing down with no item below the current item is more complicated
- * because we want to move to the last row if we're not there yet */
- if (pos / self->n_columns < (n_items - 1) / self->n_columns)
- amount = n_items - pos - 1;
- else
- return;
- }
-
- gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), pos + amount, select, modify, extend);
-}
-
-static void
-gtk_grid_view_move_cursor_to_start (GtkWidget *widget,
- GVariant *args,
- gpointer unused)
-{
- GtkGridView *self = GTK_GRID_VIEW (widget);
- gboolean select, modify, extend;
-
- if (self->model == NULL || g_list_model_get_n_items (self->model) == 0)
- return;
-
- g_variant_get (args, "(bbb)", &select, &modify, &extend);
-
- gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), 0, select, modify, extend);
-}
-
-static void
-gtk_grid_view_move_cursor_to_end (GtkWidget *widget,
- GVariant *args,
- gpointer unused)
-{
- GtkGridView *self = GTK_GRID_VIEW (widget);
- gboolean select, modify, extend;
- guint n_items;
-
- if (self->model == NULL)
- return;
-
- n_items = g_list_model_get_n_items (self->model);
- if (n_items == 0)
- return;
-
- g_variant_get (args, "(bbb)", &select, &modify, &extend);
-
- gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), n_items - 1, select, modify, extend);
-}
-
-static void
gtk_grid_view_move_cursor_page_up (GtkWidget *widget,
GVariant *args,
gpointer unused)
@@ -1447,32 +1358,6 @@ gtk_grid_view_add_custom_move_binding (GtkBindingSet *binding_set,
}
static void
-gtk_grid_view_add_move_binding (GtkBindingSet *binding_set,
- guint keyval,
- GtkOrientation orientation,
- int amount)
-{
- gtk_binding_entry_add_callback (binding_set,
- keyval,
- GDK_CONTROL_MASK,
- gtk_grid_view_move_cursor,
- g_variant_new ("(ubbbi)", orientation, FALSE, FALSE, FALSE, amount),
- NULL, NULL);
- gtk_binding_entry_add_callback (binding_set,
- keyval,
- GDK_SHIFT_MASK,
- gtk_grid_view_move_cursor,
- g_variant_new ("(ubbbi)", orientation, TRUE, FALSE, TRUE, amount),
- NULL, NULL);
- gtk_binding_entry_add_callback (binding_set,
- keyval,
- GDK_CONTROL_MASK | GDK_SHIFT_MASK,
- gtk_grid_view_move_cursor,
- g_variant_new ("(ubbbi)", orientation, TRUE, TRUE, TRUE, amount),
- NULL, NULL);
-}
-
-static void
gtk_grid_view_class_init (GtkGridViewClass *klass)
{
GtkListBaseClass *list_base_class = GTK_LIST_BASE_CLASS (klass);
@@ -1485,8 +1370,9 @@ gtk_grid_view_class_init (GtkGridViewClass *klass)
list_base_class->list_item_augment_size = sizeof (CellAugment);
list_base_class->list_item_augment_func = cell_augment;
list_base_class->adjustment_value_changed = gtk_grid_view_adjustment_value_changed;
+ list_base_class->move_focus_along = gtk_grid_view_move_focus_along;
+ list_base_class->move_focus_across = gtk_grid_view_move_focus_across;
- widget_class->focus = gtk_grid_view_focus;
widget_class->measure = gtk_grid_view_measure;
widget_class->size_allocate = gtk_grid_view_size_allocate;
@@ -1598,32 +1484,12 @@ gtk_grid_view_class_init (GtkGridViewClass *klass)
binding_set = gtk_binding_set_by_class (klass);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_Up, GTK_ORIENTATION_VERTICAL, -1);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_KP_Up, GTK_ORIENTATION_VERTICAL, -1);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_Down, GTK_ORIENTATION_VERTICAL, 1);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_KP_Down, GTK_ORIENTATION_VERTICAL, 1);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_Left, GTK_ORIENTATION_HORIZONTAL, -1);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_KP_Left, GTK_ORIENTATION_HORIZONTAL, -1);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_Right, GTK_ORIENTATION_HORIZONTAL, 1);
- gtk_grid_view_add_move_binding (binding_set, GDK_KEY_KP_Right, GTK_ORIENTATION_HORIZONTAL, 1);
-
- gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_Home, gtk_grid_view_move_cursor_to_start);
- gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_KP_Home, gtk_grid_view_move_cursor_to_start);
- gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_End, gtk_grid_view_move_cursor_to_end);
- gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_KP_End, gtk_grid_view_move_cursor_to_end);
gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_Page_Up, gtk_grid_view_move_cursor_page_up);
gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_KP_Page_Up, gtk_grid_view_move_cursor_page_up);
gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_Page_Down, gtk_grid_view_move_cursor_page_down);
gtk_grid_view_add_custom_move_binding (binding_set, GDK_KEY_KP_Page_Down, gtk_grid_view_move_cursor_page_down);
- gtk_binding_entry_add_action (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "list.select-all", NULL);
- gtk_binding_entry_add_action (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "list.select-all", NULL);
-
- gtk_binding_entry_add_action (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "list.unselect-all", NULL);
- gtk_binding_entry_add_action (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
-
gtk_widget_class_set_css_name (widget_class, I_("flowbox"));
-
}
static void
diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c
index 38fad7320a..9ab59fc783 100644
--- a/gtk/gtklistbase.c
+++ b/gtk/gtklistbase.c
@@ -22,6 +22,7 @@
#include "gtklistbaseprivate.h"
#include "gtkadjustment.h"
+#include "gtkbindings.h"
#include "gtkintl.h"
#include "gtkorientableprivate.h"
#include "gtkscrollable.h"
@@ -94,6 +95,68 @@ gtk_list_base_clear_adjustment (GtkListBase *self,
}
/*
+ * gtk_list_base_move_focus_along:
+ * @self: a #GtkListBase
+ * @pos: position from which to move focus
+ * @steps: steps to move focus - negative numbers
+ * move focus backwards
+ *
+ * Moves focus @steps in the direction of the list.
+ * If focus cannot be moved, @pos is returned.
+ * If focus should be moved out of the widget, %GTK_INVALID_LIST_POSITION
+ * is returned.
+ *
+ * Returns: new focus position
+ **/
+static guint
+gtk_list_base_move_focus_along (GtkListBase *self,
+ guint pos,
+ int steps)
+{
+ return GTK_LIST_BASE_GET_CLASS (self)->move_focus_along (self, pos, steps);
+}
+
+/*
+ * gtk_list_base_move_focus_across:
+ * @self: a #GtkListBase
+ * @pos: position from which to move focus
+ * @steps: steps to move focus - negative numbers
+ * move focus backwards
+ *
+ * Moves focus @steps in the direction across the list.
+ * If focus cannot be moved, @pos is returned.
+ * If focus should be moved out of the widget, %GTK_INVALID_LIST_POSITION
+ * is returned.
+ *
+ * Returns: new focus position
+ **/
+static guint
+gtk_list_base_move_focus_across (GtkListBase *self,
+ guint pos,
+ int steps)
+{
+ return GTK_LIST_BASE_GET_CLASS (self)->move_focus_across (self, pos, steps);
+}
+
+static guint
+gtk_list_base_move_focus (GtkListBase *self,
+ guint pos,
+ GtkOrientation orientation,
+ int steps)
+{
+ GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL &&
+ gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL)
+ steps = -steps;
+
+ if (orientation == priv->orientation)
+ return gtk_list_base_move_focus_along (self, pos, steps);
+ else
+ return gtk_list_base_move_focus_across (self, pos, steps);
+}
+
+/*
* gtk_list_base_select_item:
* @self: a %GtkListBase
* @pos: item to select
@@ -185,6 +248,108 @@ gtk_list_base_select_item (GtkListBase *self,
0, 0);
}
+static guint
+gtk_list_base_get_n_items (GtkListBase *self)
+{
+ GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+ GtkSelectionModel *model;
+
+ model = gtk_list_item_manager_get_model (priv->item_manager);
+ if (model == NULL)
+ return 0;
+
+ return g_list_model_get_n_items (G_LIST_MODEL (model));
+}
+
+guint
+gtk_list_base_get_focus_position (GtkListBase *self)
+{
+#if 0
+ GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+
+ return gtk_list_item_tracker_get_position (priv->item_manager, priv->focus);
+#else
+ GtkWidget *focus_child = gtk_widget_get_focus_child (GTK_WIDGET (self));
+ if (focus_child)
+ return gtk_list_item_get_position (GTK_LIST_ITEM (focus_child));
+ else
+ return GTK_INVALID_LIST_POSITION;
+#endif
+}
+
+static gboolean
+gtk_list_base_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ GtkListBase *self = GTK_LIST_BASE (widget);
+ guint old, pos, n_items;
+
+ pos = gtk_list_base_get_focus_position (self);
+ n_items = gtk_list_base_get_n_items (self);
+ old = pos;
+
+ if (pos >= n_items)
+ {
+ if (n_items == 0)
+ return FALSE;
+
+ pos = 0;
+ }
+ else if (gtk_widget_get_focus_child (widget) == NULL)
+ {
+ /* Focus was outside the list, just grab the old focus item
+ * while keeping the selection intact.
+ */
+ return gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), pos, FALSE, FALSE, FALSE);
+ }
+ else
+ {
+ switch (direction)
+ {
+ case GTK_DIR_TAB_FORWARD:
+ pos++;
+ if (pos >= n_items)
+ return FALSE;
+ break;
+
+ case GTK_DIR_TAB_BACKWARD:
+ if (pos == 0)
+ return FALSE;
+ pos--;
+ break;
+
+ case GTK_DIR_UP:
+ pos = gtk_list_base_move_focus (self, pos, GTK_ORIENTATION_VERTICAL, -1);
+ break;
+
+ case GTK_DIR_DOWN:
+ pos = gtk_list_base_move_focus (self, pos, GTK_ORIENTATION_VERTICAL, 1);
+ break;
+
+ case GTK_DIR_LEFT:
+ pos = gtk_list_base_move_focus (self, pos, GTK_ORIENTATION_HORIZONTAL, -1);
+ break;
+
+ case GTK_DIR_RIGHT:
+ pos = gtk_list_base_move_focus (self, pos, GTK_ORIENTATION_HORIZONTAL, 1);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ return TRUE;
+ }
+ }
+
+ if (old != pos)
+ {
+ return gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), pos, TRUE, FALSE, FALSE);
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
static void
gtk_list_base_dispose (GObject *object)
{
@@ -379,12 +544,125 @@ gtk_list_base_unselect_all (GtkWidget *widget,
}
static void
+gtk_list_base_move_cursor_to_start (GtkWidget *widget,
+ GVariant *args,
+ gpointer unused)
+{
+ GtkListBase *self = GTK_LIST_BASE (widget);
+ gboolean select, modify, extend;
+
+ if (gtk_list_base_get_n_items (self) == 0)
+ return;
+
+ g_variant_get (args, "(bbb)", &select, &modify, &extend);
+
+ gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), 0, select, modify, extend);
+}
+
+static void
+gtk_list_base_move_cursor_to_end (GtkWidget *widget,
+ GVariant *args,
+ gpointer unused)
+{
+ GtkListBase *self = GTK_LIST_BASE (widget);
+ gboolean select, modify, extend;
+ guint n_items;
+
+ n_items = gtk_list_base_get_n_items (self);
+ if (n_items == 0)
+ return;
+
+ g_variant_get (args, "(bbb)", &select, &modify, &extend);
+
+ gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), n_items - 1, select, modify, extend);
+}
+
+static void
+gtk_list_base_move_cursor (GtkWidget *widget,
+ GVariant *args,
+ gpointer unused)
+{
+ GtkListBase *self = GTK_LIST_BASE (widget);
+ int amount;
+ guint orientation;
+ guint pos;
+ gboolean select, modify, extend;
+
+ g_variant_get (args, "(ubbbi)", &orientation, &select, &modify, &extend, &amount);
+
+ pos = gtk_list_base_get_focus_position (self);
+ pos = gtk_list_base_move_focus (self, pos, orientation, amount);
+
+ gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), pos, select, modify, extend);
+}
+
+static void
+gtk_list_base_add_move_binding (GtkBindingSet *binding_set,
+ guint keyval,
+ GtkOrientation orientation,
+ int amount)
+{
+ gtk_binding_entry_add_callback (binding_set,
+ keyval,
+ GDK_CONTROL_MASK,
+ gtk_list_base_move_cursor,
+ g_variant_new ("(ubbbi)", orientation, FALSE, FALSE, FALSE, amount),
+ NULL, NULL);
+ gtk_binding_entry_add_callback (binding_set,
+ keyval,
+ GDK_SHIFT_MASK,
+ gtk_list_base_move_cursor,
+ g_variant_new ("(ubbbi)", orientation, TRUE, FALSE, TRUE, amount),
+ NULL, NULL);
+ gtk_binding_entry_add_callback (binding_set,
+ keyval,
+ GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+ gtk_list_base_move_cursor,
+ g_variant_new ("(ubbbi)", orientation, TRUE, TRUE, TRUE, amount),
+ NULL, NULL);
+}
+
+static void
+gtk_list_base_add_custom_move_binding (GtkBindingSet *binding_set,
+ guint keyval,
+ GtkBindingCallback callback)
+{
+ gtk_binding_entry_add_callback (binding_set,
+ keyval,
+ 0,
+ callback,
+ g_variant_new ("(bbb)", TRUE, FALSE, FALSE),
+ NULL, NULL);
+ gtk_binding_entry_add_callback (binding_set,
+ keyval,
+ GDK_CONTROL_MASK,
+ callback,
+ g_variant_new ("(bbb)", FALSE, FALSE, FALSE),
+ NULL, NULL);
+ gtk_binding_entry_add_callback (binding_set,
+ keyval,
+ GDK_SHIFT_MASK,
+ callback,
+ g_variant_new ("(bbb)", TRUE, FALSE, TRUE),
+ NULL, NULL);
+ gtk_binding_entry_add_callback (binding_set,
+ keyval,
+ GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+ callback,
+ g_variant_new ("(bbb)", TRUE, TRUE, TRUE),
+ NULL, NULL);
+}
+
+static void
gtk_list_base_class_init (GtkListBaseClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkBindingSet *binding_set;
gpointer iface;
+ widget_class->focus = gtk_list_base_focus;
+
gobject_class->dispose = gtk_list_base_dispose;
gobject_class->get_property = gtk_list_base_get_property;
gobject_class->set_property = gtk_list_base_set_property;
@@ -465,6 +743,26 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
NULL,
gtk_list_base_unselect_all);
+ binding_set = gtk_binding_set_by_class (klass);
+
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_Up, GTK_ORIENTATION_VERTICAL, -1);
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_KP_Up, GTK_ORIENTATION_VERTICAL, -1);
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_Down, GTK_ORIENTATION_VERTICAL, 1);
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_KP_Down, GTK_ORIENTATION_VERTICAL, 1);
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_Left, GTK_ORIENTATION_HORIZONTAL, -1);
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_KP_Left, GTK_ORIENTATION_HORIZONTAL, -1);
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_Right, GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_list_base_add_move_binding (binding_set, GDK_KEY_KP_Right, GTK_ORIENTATION_HORIZONTAL, 1);
+
+ gtk_list_base_add_custom_move_binding (binding_set, GDK_KEY_Home, gtk_list_base_move_cursor_to_start);
+ gtk_list_base_add_custom_move_binding (binding_set, GDK_KEY_KP_Home, gtk_list_base_move_cursor_to_start);
+ gtk_list_base_add_custom_move_binding (binding_set, GDK_KEY_End, gtk_list_base_move_cursor_to_end);
+ gtk_list_base_add_custom_move_binding (binding_set, GDK_KEY_KP_End, gtk_list_base_move_cursor_to_end);
+
+ gtk_binding_entry_add_action (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "list.select-all", NULL);
+ gtk_binding_entry_add_action (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "list.select-all", NULL);
+ gtk_binding_entry_add_action (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "list.unselect-all", NULL);
+ gtk_binding_entry_add_action (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
}
static void
diff --git a/gtk/gtklistbaseprivate.h b/gtk/gtklistbaseprivate.h
index e6b070c508..189538a700 100644
--- a/gtk/gtklistbaseprivate.h
+++ b/gtk/gtklistbaseprivate.h
@@ -41,10 +41,17 @@ struct _GtkListBaseClass
void (* adjustment_value_changed) (GtkListBase *self,
GtkOrientation orientation);
+ guint (* move_focus_along) (GtkListBase *self,
+ guint pos,
+ int steps);
+ guint (* move_focus_across) (GtkListBase *self,
+ guint pos,
+ int steps);
};
GtkOrientation gtk_list_base_get_orientation (GtkListBase *self);
#define gtk_list_base_get_opposite_orientation(self) OPPOSITE_ORIENTATION(gtk_list_base_get_orientation(self))
+guint gtk_list_base_get_focus_position (GtkListBase *self);
GtkListItemManager * gtk_list_base_get_manager (GtkListBase *self);
GtkScrollablePolicy gtk_list_base_get_scroll_policy (GtkListBase *self,
GtkOrientation orientation);
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index a57a647b22..033f4eab8f 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -393,6 +393,32 @@ gtk_list_view_adjustment_value_changed (GtkListBase *base,
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
+static guint
+gtk_list_view_move_focus_along (GtkListBase *base,
+ guint pos,
+ int steps)
+{
+ GtkListView *self = GTK_LIST_VIEW (base);
+
+ if (steps < 0)
+ return pos - MIN (pos, -steps);
+ else
+ {
+ guint n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
+ pos += MIN (n_items - pos - 1, steps);
+ }
+
+ return pos;
+}
+
+static guint
+gtk_list_view_move_focus_across (GtkListBase *base,
+ guint pos,
+ int steps)
+{
+ return pos;
+}
+
static int
gtk_list_view_update_adjustments (GtkListView *self,
GtkOrientation orientation)
@@ -689,62 +715,6 @@ gtk_list_view_size_allocate (GtkWidget *widget,
}
}
-static gboolean
-gtk_list_view_focus (GtkWidget *widget,
- GtkDirectionType direction)
-{
- GtkListView *self = GTK_LIST_VIEW (widget);
- GtkWidget *old_focus_child, *new_focus_child;
-
- old_focus_child = gtk_widget_get_focus_child (widget);
-
- if (old_focus_child == NULL &&
- (direction == GTK_DIR_TAB_FORWARD || direction == GTK_DIR_TAB_BACKWARD))
- {
- ListRow *row;
- guint pos;
-
- /* When tabbing into the listview, don't focus the first/last item,
- * but keep the previously focused item
- */
- pos = gtk_list_item_tracker_get_position (self->item_manager, self->focus);
- row = gtk_list_item_manager_get_nth (self->item_manager, pos, NULL);
- if (row && gtk_widget_grab_focus (row->parent.widget))
- goto moved_focus;
- }
-
- if (!GTK_WIDGET_CLASS (gtk_list_view_parent_class)->focus (widget, direction))
- return FALSE;
-
-moved_focus:
- new_focus_child = gtk_widget_get_focus_child (widget);
-
- if (old_focus_child != new_focus_child &&
- GTK_IS_LIST_ITEM (new_focus_child))
- {
- GdkModifierType state;
- GdkModifierType mask;
- gboolean extend = FALSE, modify = FALSE;
-
- if (old_focus_child && 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_base_select_item (GTK_LIST_BASE (self),
- gtk_list_item_get_position (GTK_LIST_ITEM (new_focus_child)),
- modify,
- extend);
- }
-
- return TRUE;
-}
-
static void
gtk_list_view_dispose (GObject *object)
{
@@ -963,76 +933,6 @@ gtk_list_view_activate_item (GtkWidget *widget,
}
static void
-gtk_list_view_move_cursor (GtkWidget *widget,
- GVariant *args,
- gpointer unused)
-{
- GtkListView *self = GTK_LIST_VIEW (widget);
- int amount;
- guint orientation;
- guint pos, new_pos, n_items;
- gboolean select, modify, extend;
-
- g_variant_get (args, "(ubbbi)", &orientation, &select, &modify, &extend, &amount);
-
- if (gtk_list_base_get_orientation (GTK_LIST_BASE (self)) != orientation)
- return;
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL &&
- gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
- amount = -amount;
-
- pos = gtk_list_item_tracker_get_position (self->item_manager, self->focus);
- n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
- if (pos >= n_items)
- return;
-
- new_pos = pos + amount;
- /* This overflow check only works reliably for amount == 1 */
- if (new_pos >= n_items)
- return;
-
- gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), new_pos, select, modify, extend);
-}
-
-static void
-gtk_list_view_move_cursor_to_start (GtkWidget *widget,
- GVariant *args,
- gpointer unused)
-{
- GtkListView *self = GTK_LIST_VIEW (widget);
- gboolean select, modify, extend;
-
- if (self->model == NULL || g_list_model_get_n_items (self->model) == 0)
- return;
-
- g_variant_get (args, "(bbb)", &select, &modify, &extend);
-
- gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), 0, select, modify, extend);
-}
-
-static void
-gtk_list_view_move_cursor_to_end (GtkWidget *widget,
- GVariant *args,
- gpointer unused)
-{
- GtkListView *self = GTK_LIST_VIEW (widget);
- gboolean select, modify, extend;
- guint n_items;
-
- if (self->model == NULL)
- return;
-
- n_items = g_list_model_get_n_items (self->model);
- if (n_items == 0)
- return;
-
- g_variant_get (args, "(bbb)", &select, &modify, &extend);
-
- gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), n_items - 1, select, modify, extend);
-}
-
-static void
gtk_list_view_move_cursor_page_up (GtkWidget *widget,
GVariant *args,
gpointer unused)
@@ -1145,32 +1045,6 @@ gtk_list_view_add_custom_move_binding (GtkBindingSet *binding_set,
}
static void
-gtk_list_view_add_move_binding (GtkBindingSet *binding_set,
- guint keyval,
- GtkOrientation orientation,
- int amount)
-{
- gtk_binding_entry_add_callback (binding_set,
- keyval,
- GDK_CONTROL_MASK,
- gtk_list_view_move_cursor,
- g_variant_new ("(ubbbi)", orientation, FALSE, FALSE, FALSE, amount),
- NULL, NULL);
- gtk_binding_entry_add_callback (binding_set,
- keyval,
- GDK_SHIFT_MASK,
- gtk_list_view_move_cursor,
- g_variant_new ("(ubbbi)", orientation, TRUE, FALSE, TRUE, amount),
- NULL, NULL);
- gtk_binding_entry_add_callback (binding_set,
- keyval,
- GDK_CONTROL_MASK | GDK_SHIFT_MASK,
- gtk_list_view_move_cursor,
- g_variant_new ("(ubbbi)", orientation, TRUE, TRUE, TRUE, amount),
- NULL, NULL);
-}
-
-static void
gtk_list_view_class_init (GtkListViewClass *klass)
{
GtkListBaseClass *list_base_class = GTK_LIST_BASE_CLASS (klass);
@@ -1183,10 +1057,11 @@ gtk_list_view_class_init (GtkListViewClass *klass)
list_base_class->list_item_augment_size = sizeof (ListRowAugment);
list_base_class->list_item_augment_func = list_row_augment;
list_base_class->adjustment_value_changed = gtk_list_view_adjustment_value_changed;
+ list_base_class->move_focus_along = gtk_list_view_move_focus_along;
+ list_base_class->move_focus_across = gtk_list_view_move_focus_across;
widget_class->measure = gtk_list_view_measure;
widget_class->size_allocate = gtk_list_view_size_allocate;
- widget_class->focus = gtk_list_view_focus;
gobject_class->dispose = gtk_list_view_dispose;
gobject_class->get_property = gtk_list_view_get_property;
@@ -1280,30 +1155,11 @@ gtk_list_view_class_init (GtkListViewClass *klass)
binding_set = gtk_binding_set_by_class (klass);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_Up, GTK_ORIENTATION_VERTICAL, -1);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_KP_Up, GTK_ORIENTATION_VERTICAL, -1);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_Down, GTK_ORIENTATION_VERTICAL, 1);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_KP_Down, GTK_ORIENTATION_VERTICAL, 1);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_Left, GTK_ORIENTATION_HORIZONTAL, -1);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_KP_Left, GTK_ORIENTATION_HORIZONTAL, -1);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_Right, GTK_ORIENTATION_HORIZONTAL, 1);
- gtk_list_view_add_move_binding (binding_set, GDK_KEY_KP_Right, GTK_ORIENTATION_HORIZONTAL, 1);
-
- gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_Home, gtk_list_view_move_cursor_to_start);
- gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_KP_Home, gtk_list_view_move_cursor_to_start);
- gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_End, gtk_list_view_move_cursor_to_end);
- gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_KP_End, gtk_list_view_move_cursor_to_end);
gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_Page_Up, gtk_list_view_move_cursor_page_up);
gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_KP_Page_Up, gtk_list_view_move_cursor_page_up);
gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_Page_Down, gtk_list_view_move_cursor_page_down);
gtk_list_view_add_custom_move_binding (binding_set, GDK_KEY_KP_Page_Down, gtk_list_view_move_cursor_page_down);
- gtk_binding_entry_add_action (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "list.select-all", NULL);
- gtk_binding_entry_add_action (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "list.select-all", NULL);
-
- gtk_binding_entry_add_action (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "list.unselect-all", NULL);
- gtk_binding_entry_add_action (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
-
gtk_widget_class_set_css_name (widget_class, I_("list"));
}