forked from AuroraMiddleware/gtk
listview: Add move keybindings
My god, these are a lot. And my god, these are complicated to get right.
This commit is contained in:
parent
2b9481ecdc
commit
042e13a932
@ -1071,6 +1071,264 @@ gtk_list_view_activate_item (GtkWidget *widget,
|
||||
g_signal_emit (widget, signals[ACTIVATE], 0, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_view_move_to (GtkListView *self,
|
||||
guint pos,
|
||||
gboolean select,
|
||||
gboolean modify,
|
||||
gboolean extend)
|
||||
{
|
||||
ListRow *row;
|
||||
|
||||
row = gtk_list_item_manager_get_nth (self->item_manager, pos, NULL);
|
||||
if (row == NULL)
|
||||
return;
|
||||
|
||||
if (!row->parent.widget)
|
||||
{
|
||||
GtkListItemTracker *tracker = gtk_list_item_tracker_new (self->item_manager);
|
||||
|
||||
/* We need a tracker here to create the widget.
|
||||
* That needs to have happened or we can't grab it.
|
||||
* And we can't use a different tracker, because they manage important rows,
|
||||
* so we create a temporary one. */
|
||||
gtk_list_item_tracker_set_position (self->item_manager, tracker, pos, 0, 0);
|
||||
|
||||
row = gtk_list_item_manager_get_nth (self->item_manager, pos, NULL);
|
||||
g_assert (row->parent.widget);
|
||||
|
||||
if (!gtk_widget_grab_focus (row->parent.widget))
|
||||
return; /* FIXME: What now? Can this even happen? */
|
||||
|
||||
gtk_list_item_tracker_free (self->item_manager, tracker);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gtk_widget_grab_focus (row->parent.widget))
|
||||
return; /* FIXME: What now? Can this even happen? */
|
||||
}
|
||||
|
||||
if (select)
|
||||
gtk_list_view_select_item (self, pos, modify, extend);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
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 (self->orientation != orientation)
|
||||
return TRUE;
|
||||
|
||||
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 TRUE;
|
||||
|
||||
new_pos = pos + amount;
|
||||
/* This overflow check only works reliably for amount == 1 */
|
||||
if (new_pos >= n_items)
|
||||
return TRUE;
|
||||
|
||||
gtk_list_view_move_to (self, new_pos, select, modify, extend);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
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 TRUE;
|
||||
|
||||
g_variant_get (args, "(bbb)", &select, &modify, &extend);
|
||||
|
||||
gtk_list_view_move_to (self, 0, select, modify, extend);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
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 TRUE;
|
||||
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
if (n_items == 0)
|
||||
return TRUE;
|
||||
|
||||
g_variant_get (args, "(bbb)", &select, &modify, &extend);
|
||||
|
||||
gtk_list_view_move_to (self, n_items - 1, select, modify, extend);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_view_move_cursor_page_up (GtkWidget *widget,
|
||||
GVariant *args,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkListView *self = GTK_LIST_VIEW (widget);
|
||||
gboolean select, modify, extend;
|
||||
guint start, pos, n_items;
|
||||
ListRow *row;
|
||||
int pixels, offset;
|
||||
|
||||
start = gtk_list_item_tracker_get_position (self->item_manager, self->focus);
|
||||
row = gtk_list_item_manager_get_nth (self->item_manager, start, NULL);
|
||||
if (row == NULL)
|
||||
return TRUE;
|
||||
n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
|
||||
/* check that we can go at least one row up */
|
||||
if (n_items == 0 || start == 0)
|
||||
return TRUE;
|
||||
|
||||
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
pixels = gtk_widget_get_width (widget);
|
||||
else
|
||||
pixels = gtk_widget_get_height (widget);
|
||||
pixels -= row->height;
|
||||
|
||||
pos = gtk_list_view_get_position_at_y (self,
|
||||
MAX (0, list_row_get_y (self, row) - pixels),
|
||||
&offset,
|
||||
NULL);
|
||||
/* there'll always be rows between 0 and this row */
|
||||
g_assert (pos < n_items);
|
||||
/* if row is too high, go one row less */
|
||||
if (offset > 0)
|
||||
pos++;
|
||||
/* but go at least 1 row */
|
||||
if (pos >= start)
|
||||
pos = start - 1;
|
||||
|
||||
g_variant_get (args, "(bbb)", &select, &modify, &extend);
|
||||
|
||||
gtk_list_view_move_to (self, pos, select, modify, extend);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_view_move_cursor_page_down (GtkWidget *widget,
|
||||
GVariant *args,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkListView *self = GTK_LIST_VIEW (widget);
|
||||
gboolean select, modify, extend;
|
||||
guint start, pos, n_items;
|
||||
ListRow *row;
|
||||
int pixels, offset;
|
||||
|
||||
start = gtk_list_item_tracker_get_position (self->item_manager, self->focus);
|
||||
row = gtk_list_item_manager_get_nth (self->item_manager, start, NULL);
|
||||
if (row == NULL)
|
||||
return TRUE;
|
||||
n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
|
||||
/* check that we can go at least one row down */
|
||||
if (n_items == 0 || start >= n_items - 1)
|
||||
return TRUE;
|
||||
|
||||
if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
pixels = gtk_widget_get_width (widget);
|
||||
else
|
||||
pixels = gtk_widget_get_height (widget);
|
||||
|
||||
pos = gtk_list_view_get_position_at_y (self,
|
||||
list_row_get_y (self, row) + pixels,
|
||||
&offset,
|
||||
NULL);
|
||||
if (pos >= n_items)
|
||||
pos = n_items - 1;
|
||||
/* if row is too high, go one row less */
|
||||
else if (pos > 0 && offset > 0)
|
||||
pos--;
|
||||
/* but go at least 1 row */
|
||||
if (pos <= start)
|
||||
pos = start + 1;
|
||||
|
||||
g_variant_get (args, "(bbb)", &select, &modify, &extend);
|
||||
|
||||
gtk_list_view_move_to (self, pos, select, modify, extend);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_view_add_custom_move_binding (GtkWidgetClass *widget_class,
|
||||
guint keyval,
|
||||
GtkShortcutFunc callback)
|
||||
{
|
||||
gtk_widget_class_add_binding (widget_class,
|
||||
keyval,
|
||||
0,
|
||||
callback,
|
||||
"(bbb)", TRUE, FALSE, FALSE);
|
||||
gtk_widget_class_add_binding (widget_class,
|
||||
keyval,
|
||||
GDK_CONTROL_MASK,
|
||||
callback,
|
||||
"(bbb)", FALSE, FALSE, FALSE);
|
||||
gtk_widget_class_add_binding (widget_class,
|
||||
keyval,
|
||||
GDK_SHIFT_MASK,
|
||||
callback,
|
||||
"(bbb)", TRUE, FALSE, TRUE);
|
||||
gtk_widget_class_add_binding (widget_class,
|
||||
keyval,
|
||||
GDK_CONTROL_MASK | GDK_SHIFT_MASK,
|
||||
callback,
|
||||
"(bbb)", TRUE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_view_add_move_binding (GtkWidgetClass *widget_class,
|
||||
guint keyval,
|
||||
GtkOrientation orientation,
|
||||
int amount)
|
||||
{
|
||||
gtk_widget_class_add_binding (widget_class,
|
||||
keyval,
|
||||
GDK_CONTROL_MASK,
|
||||
gtk_list_view_move_cursor,
|
||||
"(ubbbi)", orientation, FALSE, FALSE, FALSE, amount);
|
||||
gtk_widget_class_add_binding (widget_class,
|
||||
keyval,
|
||||
GDK_SHIFT_MASK,
|
||||
gtk_list_view_move_cursor,
|
||||
"(ubbbi)", orientation, TRUE, FALSE, TRUE, amount);
|
||||
gtk_widget_class_add_binding (widget_class,
|
||||
keyval,
|
||||
GDK_CONTROL_MASK | GDK_SHIFT_MASK,
|
||||
gtk_list_view_move_cursor,
|
||||
"(ubbbi)", orientation, TRUE, TRUE, TRUE, amount);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_view_class_init (GtkListViewClass *klass)
|
||||
{
|
||||
@ -1247,6 +1505,24 @@ gtk_list_view_class_init (GtkListViewClass *klass)
|
||||
"u",
|
||||
gtk_list_view_scroll_to_item);
|
||||
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_Up, GTK_ORIENTATION_VERTICAL, -1);
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_KP_Up, GTK_ORIENTATION_VERTICAL, -1);
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_Down, GTK_ORIENTATION_VERTICAL, 1);
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_KP_Down, GTK_ORIENTATION_VERTICAL, 1);
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_Left, GTK_ORIENTATION_HORIZONTAL, -1);
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_KP_Left, GTK_ORIENTATION_HORIZONTAL, -1);
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_Right, GTK_ORIENTATION_HORIZONTAL, 1);
|
||||
gtk_list_view_add_move_binding (widget_class, GDK_KEY_KP_Right, GTK_ORIENTATION_HORIZONTAL, 1);
|
||||
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_Home, gtk_list_view_move_cursor_to_start);
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_KP_Home, gtk_list_view_move_cursor_to_start);
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_End, gtk_list_view_move_cursor_to_end);
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_KP_End, gtk_list_view_move_cursor_to_end);
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_Page_Up, gtk_list_view_move_cursor_page_up);
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_KP_Page_Up, gtk_list_view_move_cursor_page_up);
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_Page_Down, gtk_list_view_move_cursor_page_down);
|
||||
gtk_list_view_add_custom_move_binding (widget_class, GDK_KEY_KP_Page_Down, gtk_list_view_move_cursor_page_down);
|
||||
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_a, GDK_CONTROL_MASK, "list.select-all", NULL);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_slash, GDK_CONTROL_MASK, "list.select-all", NULL);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user