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.
This commit is contained in:
Benjamin Otte
2019-10-24 06:49:38 +02:00
parent 96d333f649
commit c835bb30d1
4 changed files with 364 additions and 337 deletions

View File

@@ -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
@@ -1276,81 +1262,6 @@ gtk_grid_view_activate_item (GtkWidget *widget,
g_signal_emit (widget, signals[ACTIVATE], 0, pos);
}
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,
@@ -1469,32 +1380,6 @@ gtk_grid_view_add_custom_move_binding (GtkBindingSet *binding_set,
NULL, NULL);
}
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)
{
@@ -1508,8 +1393,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;
@@ -1621,32 +1507,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

View File

@@ -22,6 +22,7 @@
#include "gtklistbaseprivate.h"
#include "gtkadjustment.h"
#include "gtkbindings.h"
#include "gtkintl.h"
#include "gtkorientableprivate.h"
#include "gtkscrollable.h"
@@ -93,6 +94,68 @@ gtk_list_base_clear_adjustment (GtkListBase *self,
g_clear_object (&priv->adjustment[orientation]);
}
/*
* 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
@@ -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)
{
@@ -378,13 +543,126 @@ gtk_list_base_unselect_all (GtkWidget *widget,
gtk_selection_model_unselect_all (selection_model);
}
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

View File

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

View File

@@ -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)
{
@@ -962,76 +932,6 @@ gtk_list_view_activate_item (GtkWidget *widget,
g_signal_emit (widget, signals[ACTIVATE], 0, pos);
}
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,
@@ -1144,32 +1044,6 @@ gtk_list_view_add_custom_move_binding (GtkBindingSet *binding_set,
NULL, NULL);
}
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)
{
@@ -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"));
}