diff options
author | Benjamin Otte <otte@redhat.com> | 2019-10-24 06:49:38 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2019-12-12 07:47:44 +0100 |
commit | df4a5944ce7ff9ecde1e0f4ad54437bc72eaa514 (patch) | |
tree | 37013173fceaeee523d35d31cece8389ad75baf6 | |
parent | 10ea8705b6b8eb6fd5fc898346e13e81a662b11f (diff) | |
download | gtk+-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.c | 196 | ||||
-rw-r--r-- | gtk/gtklistbase.c | 298 | ||||
-rw-r--r-- | gtk/gtklistbaseprivate.h | 7 | ||||
-rw-r--r-- | gtk/gtklistview.c | 200 |
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")); } |