From 33c6b428f739b2717fcf14c7331b3c3665ae29dc Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 25 Oct 2019 07:39:57 +0200 Subject: [PATCH] listbase: Add vfuncs to convert positions to/from coordinates ... and use that to implement PageUp/PageDown. With that, all keyboard handling has been moved to GtkListBase. --- gtk/gtkgridview.c | 372 ++++++++++++++++----------------------- gtk/gtklistbase.c | 170 +++++++++++++++++- gtk/gtklistbaseprivate.h | 17 ++ gtk/gtklistview.c | 236 +++++++++---------------- 4 files changed, 422 insertions(+), 373 deletions(-) diff --git a/gtk/gtkgridview.c b/gtk/gtkgridview.c index 423e2e38fd..cb3dea3a84 100644 --- a/gtk/gtkgridview.c +++ b/gtk/gtkgridview.c @@ -275,103 +275,6 @@ gtk_grid_view_get_cell_at_y (GtkGridView *self, return cell; } -/* - * gtk_grid_view_get_size_at_position: - * @self: a #GtkGridView - * @position: position of the item - * @offset: (out caller-allocates) (optional): stores the y coordinate - * of the cell (x coordinate for horizontal grids) - * @size: (out caller-allocates) (optional): stores the height - * of the cell (width for horizontal grids) - * - * Computes where the cell at @position is allocated. - * - * If position is larger than the number of items, %FALSE will be returned. - * In particular that means that for an emtpy grid, %FALSE is returned - * for any value. - * - * Returns: (nullable): %TRUE if the cell existed, %FALSE otherwise - **/ -static gboolean -gtk_grid_view_get_size_at_position (GtkGridView *self, - guint position, - int *offset, - int *size) -{ - Cell *cell, *tmp; - int y; - - cell = gtk_list_item_manager_get_root (self->item_manager); - y = 0; - position -= position % self->n_columns; - - while (cell) - { - tmp = gtk_rb_tree_node_get_left (cell); - if (tmp) - { - CellAugment *aug = gtk_list_item_manager_get_item_augment (self->item_manager, tmp); - if (position < aug->parent.n_items) - { - cell = tmp; - continue; - } - position -= aug->parent.n_items; - y += aug->size; - } - - if (position < cell->parent.n_items) - break; - y += cell->size; - position -= cell->parent.n_items; - - cell = gtk_rb_tree_node_get_right (cell); - } - - if (cell == NULL) - { - if (offset) - *offset = 0; - if (size) - *size = 0; - return FALSE; - } - - /* We know have the (range of) cell(s) that contains this offset. - * Now for the hard part of computing which index this actually is. - */ - if (offset || size) - { - guint n_items = cell->parent.n_items; - guint skip; - - /* skip remaining items at end of row */ - if (position % self->n_columns) - { - skip = position % self->n_columns; - n_items -= skip; - position -= skip; - } - - /* Skip all the rows this index doesn't go into */ - skip = position / self->n_columns; - n_items -= skip * self->n_columns; - y += skip * self->unknown_row_height; - - if (offset) - *offset = y; - if (size) - { - if (n_items > self->n_columns) - *size = self->unknown_row_height; - else - *size = cell->size - skip * self->unknown_row_height; - } - } - - return TRUE; -} - static void gtk_grid_view_set_anchor (GtkGridView *self, guint position, @@ -399,6 +302,151 @@ gtk_grid_view_set_anchor (GtkGridView *self, } } +static gboolean +gtk_grid_view_get_allocation_along (GtkListBase *base, + guint pos, + int *offset, + int *size) +{ + GtkGridView *self = GTK_GRID_VIEW (base); + Cell *cell, *tmp; + int y; + + cell = gtk_list_item_manager_get_root (self->item_manager); + y = 0; + pos -= pos % self->n_columns; + + while (cell) + { + tmp = gtk_rb_tree_node_get_left (cell); + if (tmp) + { + CellAugment *aug = gtk_list_item_manager_get_item_augment (self->item_manager, tmp); + if (pos < aug->parent.n_items) + { + cell = tmp; + continue; + } + pos -= aug->parent.n_items; + y += aug->size; + } + + if (pos < cell->parent.n_items) + break; + y += cell->size; + pos -= cell->parent.n_items; + + cell = gtk_rb_tree_node_get_right (cell); + } + + if (cell == NULL) + { + if (offset) + *offset = 0; + if (size) + *size = 0; + return FALSE; + } + + /* We know have the (range of) cell(s) that contains this offset. + * Now for the hard part of computing which index this actually is. + */ + if (offset || size) + { + guint n_items = cell->parent.n_items; + guint skip; + + /* skip remaining items at end of row */ + if (pos % self->n_columns) + { + skip = pos % self->n_columns; + n_items -= skip; + pos -= skip; + } + + /* Skip all the rows this index doesn't go into */ + skip = pos / self->n_columns; + n_items -= skip * self->n_columns; + y += skip * self->unknown_row_height; + + if (offset) + *offset = y; + if (size) + { + if (n_items > self->n_columns) + *size = self->unknown_row_height; + else + *size = cell->size - skip * self->unknown_row_height; + } + } + + return TRUE; +} + +static gboolean +gtk_grid_view_get_allocation_across (GtkListBase *base, + guint pos, + int *offset, + int *size) +{ + GtkGridView *self = GTK_GRID_VIEW (base); + guint start; + + pos %= self->n_columns; + start = ceil (self->column_width * pos); + + if (offset) + *offset = start; + if (size) + *size = ceil (self->column_width * (pos + 1)) - start; + + return TRUE; +} + +static gboolean +gtk_grid_view_get_position_from_allocation (GtkListBase *base, + int across, + int along, + guint *position, + cairo_rectangle_int_t *area) +{ + GtkGridView *self = GTK_GRID_VIEW (base); + int offset, size; + guint pos, n_items; + + if (across >= self->column_width * self->n_columns) + return FALSE; + + n_items = self->model ? g_list_model_get_n_items (self->model) : 0; + if (!gtk_grid_view_get_cell_at_y (self, + along, + &pos, + &offset, + &size)) + return FALSE; + + pos += floor (across / self->column_width); + + if (pos >= n_items) + { + /* Ugh, we're in the last row and don't have enough items + * to fill the row. + * Do it the hard way then... */ + pos = n_items - 1; + } + + *position = pos; + if (area) + { + area->x = ceil (self->column_width * (pos % self->n_columns)); + area->width = ceil (self->column_width * (1 + pos % self->n_columns)) - area->x; + area->y = along - offset; + area->height = size; + } + + return TRUE; +} + static guint gtk_grid_view_move_focus_along (GtkListBase *base, guint pos, @@ -588,7 +636,7 @@ gtk_grid_view_update_adjustment (GtkGridView *self, cell = gtk_list_item_manager_get_root (self->item_manager); g_assert (cell); aug = gtk_list_item_manager_get_item_augment (self->item_manager, cell); - if (!gtk_grid_view_get_size_at_position (self, + if (!gtk_list_base_get_allocation_along (GTK_LIST_BASE (self), anchor_pos, &value, &cell_size)) @@ -1213,7 +1261,7 @@ gtk_grid_view_scroll_to_item (GtkWidget *widget, g_variant_get (parameter, "u", &pos); /* figure out primary orientation and if position is valid */ - if (!gtk_grid_view_get_size_at_position (self, pos, &start, &end)) + if (!gtk_list_base_get_allocation_along (GTK_LIST_BASE (self), pos, &start, &end)) return; end += start; @@ -1261,124 +1309,6 @@ gtk_grid_view_activate_item (GtkWidget *widget, g_signal_emit (widget, signals[ACTIVATE], 0, pos); } -static gboolean -gtk_grid_view_move_cursor_page_up (GtkWidget *widget, - GVariant *args, - gpointer unused) -{ - GtkGridView *self = GTK_GRID_VIEW (widget); - gboolean select, modify, extend; - int offset, start, size, page_size; - guint pos, new_pos; - - pos = gtk_list_item_tracker_get_position (self->item_manager, self->anchor); - if (pos < self->n_columns) /* already on first row */ - return TRUE; - if (!gtk_grid_view_get_size_at_position (self, pos, &start, &size)) - return TRUE; - gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self), - gtk_list_base_get_orientation (GTK_LIST_BASE (self)), - NULL, NULL, &page_size); - if (!gtk_grid_view_get_cell_at_y (self, - MAX (0, start + size - page_size), - &new_pos, - &offset, - NULL)) - return TRUE; - /* gtk_grid_view_get_cell_at_y() returns first column positions, we want to keep columns */ - new_pos += pos % self->n_columns; - if (offset > 0) - new_pos += self->n_columns; - if (new_pos >= pos) - new_pos = pos - self->n_columns; - - g_variant_get (args, "(bbb)", &select, &modify, &extend); - - gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), new_pos, select, modify, extend); - - return TRUE; -} - -static gboolean -gtk_grid_view_move_cursor_page_down (GtkWidget *widget, - GVariant *args, - gpointer unused) -{ - GtkGridView *self = GTK_GRID_VIEW (widget); - gboolean select, modify, extend; - int start, page_size; - guint pos, new_pos, n_items; - - pos = gtk_list_item_tracker_get_position (self->item_manager, self->anchor); - n_items = g_list_model_get_n_items (self->model); - if (n_items == 0 || pos / self->n_columns >= (n_items - 1) / self->n_columns) - return TRUE; - if (!gtk_grid_view_get_size_at_position (self, pos, &start, NULL)) - return TRUE; - gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self), - gtk_list_base_get_orientation (GTK_LIST_BASE (self)), - NULL, NULL, &page_size); - if (gtk_grid_view_get_cell_at_y (self, - start + page_size, - &new_pos, - NULL, NULL)) - { - /* We want a fully visible row and we just checked for the row that covers the - * pixels more than a page down */ - if (new_pos >= self->n_columns) - new_pos -= self->n_columns; - } - else - { - /* scroll to last row if there's nothing in the place we checked */ - new_pos = (n_items - 1); - new_pos -= new_pos % self->n_columns; - } - - /* gtk_grid_view_get_cell_at_y() returns first column positions, we want to keep columns */ - new_pos += pos % self->n_columns; - /* We want to scroll at least one row */ - if (new_pos <= pos) - new_pos = pos + self->n_columns; - /* And finally, we need to check we've not scrolled to a cell in the last row that isn't - * covered because n_items is not a multiple of n_columns */ - if (new_pos >= n_items) - new_pos = n_items - 1; - - g_variant_get (args, "(bbb)", &select, &modify, &extend); - - gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), new_pos, select, modify, extend); - - return TRUE; -} - -static void -gtk_grid_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_grid_view_class_init (GtkGridViewClass *klass) { @@ -1391,6 +1321,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->get_allocation_along = gtk_grid_view_get_allocation_along; + list_base_class->get_allocation_across = gtk_grid_view_get_allocation_across; + list_base_class->get_position_from_allocation = gtk_grid_view_get_position_from_allocation; list_base_class->move_focus_along = gtk_grid_view_move_focus_along; list_base_class->move_focus_across = gtk_grid_view_move_focus_across; @@ -1503,11 +1436,6 @@ gtk_grid_view_class_init (GtkGridViewClass *klass) "u", gtk_grid_view_scroll_to_item); - gtk_grid_view_add_custom_move_binding (widget_class, GDK_KEY_Page_Up, gtk_grid_view_move_cursor_page_up); - gtk_grid_view_add_custom_move_binding (widget_class, GDK_KEY_KP_Page_Up, gtk_grid_view_move_cursor_page_up); - gtk_grid_view_add_custom_move_binding (widget_class, GDK_KEY_Page_Down, gtk_grid_view_move_cursor_page_down); - gtk_grid_view_add_custom_move_binding (widget_class, GDK_KEY_KP_Page_Down, gtk_grid_view_move_cursor_page_down); - gtk_widget_class_set_css_name (widget_class, I_("flowbox")); } diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c index 2c70e8dca1..c42d9732c2 100644 --- a/gtk/gtklistbase.c +++ b/gtk/gtklistbase.c @@ -155,9 +155,84 @@ gtk_list_base_move_focus (GtkListBase *self, return gtk_list_base_move_focus_across (self, pos, steps); } +/* + * gtk_list_base_get_allocation_along: + * @self: a #GtkListBase + * @pos: item to get the size of + * @offset: (out caller-allocates) (allow-none) set to the offset + * of the top/left of the item + * @size: (out caller-allocates) (allow-none) set to the size of + * the item in the direction + * + * Computes the allocation of the item in the direction along the sizing + * axis. + * + * Returns: %TRUE if the item exists and has an allocation, %FALSE otherwise + **/ +gboolean +gtk_list_base_get_allocation_along (GtkListBase *self, + guint pos, + int *offset, + int *size) +{ + return GTK_LIST_BASE_GET_CLASS (self)->get_allocation_along (self, pos, offset, size); +} + +/* + * gtk_list_base_get_allocation_across: + * @self: a #GtkListBase + * @pos: item to get the size of + * @offset: (out caller-allocates) (allow-none) set to the offset + * of the top/left of the item + * @size: (out caller-allocates) (allow-none) set to the size of + * the item in the direction + * + * Computes the allocation of the item in the direction across to the sizing + * axis. + * + * Returns: %TRUE if the item exists and has an allocation, %FALSE otherwise + **/ +static gboolean +gtk_list_base_get_allocation_across (GtkListBase *self, + guint pos, + int *offset, + int *size) +{ + return GTK_LIST_BASE_GET_CLASS (self)->get_allocation_across (self, pos, offset, size); +} + +/* + * gtk_list_base_get_position_from_allocation: + * @self: a #GtkListBase + * @across: position in pixels in the direction cross to the list + * @along: position in pixels in the direction of the list + * @pos: (out caller-allocates): set to the looked up position + * @area: (out caller-allocates) (allow-none): set to the area occupied + * by the returned position. + * + * Given a coordinate in list coordinates, determine the position of the + * item that occupies that position. + * + * It is possible for @area to not include the point given by (across, along). + * This will happen for example in the last row of a gridview, where the + * last item will be returned for the whole width, even if there are empty + * cells. + * + * Returns: %TRUE on success or %FALSE if no position occupies the given offset. + **/ +static guint +gtk_list_base_get_position_from_allocation (GtkListBase *self, + int across, + int along, + guint *pos, + cairo_rectangle_int_t *area) +{ + return GTK_LIST_BASE_GET_CLASS (self)->get_position_from_allocation (self, across, along, pos, area); +} + /* * gtk_list_base_select_item: - * @self: a %GtkListBase + * @self: a #GtkListBase * @pos: item to select * @modify: %TRUE if the selection should be modified, %FALSE * if a new selection should be done. This is usually set @@ -560,6 +635,95 @@ gtk_list_base_move_cursor_to_start (GtkWidget *widget, return TRUE; } +static gboolean +gtk_list_base_move_cursor_page_up (GtkWidget *widget, + GVariant *args, + gpointer unused) +{ + GtkListBase *self = GTK_LIST_BASE (widget); + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + gboolean select, modify, extend; + cairo_rectangle_int_t area, new_area; + int page_size; + guint pos, new_pos; + + pos = gtk_list_base_get_focus_position (self); + page_size = gtk_adjustment_get_page_size (priv->adjustment[priv->orientation]); + if (!gtk_list_base_get_allocation_along (self, pos, &area.y, &area.height) || + !gtk_list_base_get_allocation_across (self, pos, &area.x, &area.width)) + return TRUE; + if (!gtk_list_base_get_position_from_allocation (self, + area.x + area.width / 2, + MAX (0, area.y + area.height - page_size), + &new_pos, + &new_area)) + return TRUE; + + /* We want the whole row to be visible */ + if (new_area.y < MAX (0, area.y + area.height - page_size)) + new_pos = gtk_list_base_move_focus_along (self, new_pos, 1); + /* But we definitely want to move if we can */ + if (new_pos >= pos) + { + new_pos = gtk_list_base_move_focus_along (self, new_pos, -1); + if (new_pos == pos) + return TRUE; + } + + g_variant_get (args, "(bbb)", &select, &modify, &extend); + + gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), new_pos, select, modify, extend); + + return TRUE; +} + +static gboolean +gtk_list_base_move_cursor_page_down (GtkWidget *widget, + GVariant *args, + gpointer unused) +{ + GtkListBase *self = GTK_LIST_BASE (widget); + GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self); + gboolean select, modify, extend; + cairo_rectangle_int_t area, new_area; + int page_size, end; + guint pos, new_pos; + + pos = gtk_list_base_get_focus_position (self); + page_size = gtk_adjustment_get_page_size (priv->adjustment[priv->orientation]); + end = gtk_adjustment_get_upper (priv->adjustment[priv->orientation]); + if (end == 0) + return TRUE; + + if (!gtk_list_base_get_allocation_along (self, pos, &area.y, &area.height) || + !gtk_list_base_get_allocation_across (self, pos, &area.x, &area.width)) + return TRUE; + + if (!gtk_list_base_get_position_from_allocation (self, + area.x + area.width / 2, + MIN (end, area.y + page_size) - 1, + &new_pos, + &new_area)) + return TRUE; + + /* We want the whole row to be visible */ + if (new_area.y + new_area.height > MIN (end, area.y + page_size)) + new_pos = gtk_list_base_move_focus_along (self, new_pos, -1); + /* But we definitely want to move if we can */ + if (new_pos <= pos) + { + new_pos = gtk_list_base_move_focus_along (self, new_pos, 1); + if (new_pos == pos) + return TRUE; + } + + g_variant_get (args, "(bbb)", &select, &modify, &extend); + + gtk_list_base_grab_focus_on_item (GTK_LIST_BASE (self), new_pos, select, modify, extend); + + return TRUE; +} + static gboolean gtk_list_base_move_cursor_to_end (GtkWidget *widget, GVariant *args, @@ -753,6 +917,10 @@ gtk_list_base_class_init (GtkListBaseClass *klass) gtk_list_base_add_custom_move_binding (widget_class, GDK_KEY_KP_Home, gtk_list_base_move_cursor_to_start); gtk_list_base_add_custom_move_binding (widget_class, GDK_KEY_End, gtk_list_base_move_cursor_to_end); gtk_list_base_add_custom_move_binding (widget_class, GDK_KEY_KP_End, gtk_list_base_move_cursor_to_end); + gtk_list_base_add_custom_move_binding (widget_class, GDK_KEY_Page_Up, gtk_list_base_move_cursor_page_up); + gtk_list_base_add_custom_move_binding (widget_class, GDK_KEY_KP_Page_Up, gtk_list_base_move_cursor_page_up); + gtk_list_base_add_custom_move_binding (widget_class, GDK_KEY_Page_Down, gtk_list_base_move_cursor_page_down); + gtk_list_base_add_custom_move_binding (widget_class, GDK_KEY_KP_Page_Down, gtk_list_base_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); diff --git a/gtk/gtklistbaseprivate.h b/gtk/gtklistbaseprivate.h index 189538a700..8f3054acaa 100644 --- a/gtk/gtklistbaseprivate.h +++ b/gtk/gtklistbaseprivate.h @@ -41,6 +41,19 @@ struct _GtkListBaseClass void (* adjustment_value_changed) (GtkListBase *self, GtkOrientation orientation); + gboolean (* get_allocation_along) (GtkListBase *self, + guint pos, + int *offset, + int *size); + gboolean (* get_allocation_across) (GtkListBase *self, + guint pos, + int *offset, + int *size); + gboolean (* get_position_from_allocation) (GtkListBase *self, + int across, + int along, + guint *pos, + cairo_rectangle_int_t *area); guint (* move_focus_along) (GtkListBase *self, guint pos, int steps); @@ -55,6 +68,10 @@ guint gtk_list_base_get_focus_position (GtkListBase GtkListItemManager * gtk_list_base_get_manager (GtkListBase *self); GtkScrollablePolicy gtk_list_base_get_scroll_policy (GtkListBase *self, GtkOrientation orientation); +gboolean gtk_list_base_get_allocation_along (GtkListBase *base, + guint pos, + int *offset, + int *size); void gtk_list_base_get_adjustment_values (GtkListBase *self, GtkOrientation orientation, int *value, diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c index dbb24f25a8..69e81afbe7 100644 --- a/gtk/gtklistview.c +++ b/gtk/gtklistview.c @@ -263,37 +263,6 @@ list_row_get_y (GtkListView *self, return y ; } -static gboolean -gtk_list_view_get_size_at_position (GtkListView *self, - guint pos, - int *offset, - int *height) -{ - ListRow *row; - guint skip; - int y; - - row = gtk_list_item_manager_get_nth (self->item_manager, pos, &skip); - if (row == NULL) - { - if (offset) - *offset = 0; - if (height) - *height = 0; - return FALSE; - } - - y = list_row_get_y (self, row); - y += skip * row->height; - - if (offset) - *offset = y; - if (height) - *height = row->height; - - return TRUE; -} - static int gtk_list_view_get_list_height (GtkListView *self) { @@ -392,6 +361,54 @@ gtk_list_view_adjustment_value_changed (GtkListBase *base, gtk_widget_queue_allocate (GTK_WIDGET (self)); } +static gboolean +gtk_list_view_get_allocation_along (GtkListBase *base, + guint pos, + int *offset, + int *size) +{ + GtkListView *self = GTK_LIST_VIEW (base); + ListRow *row; + guint skip; + int y; + + row = gtk_list_item_manager_get_nth (self->item_manager, pos, &skip); + if (row == NULL) + { + if (offset) + *offset = 0; + if (size) + *size = 0; + return FALSE; + } + + y = list_row_get_y (self, row); + y += skip * row->height; + + if (offset) + *offset = y; + if (size) + *size = row->height; + + return TRUE; +} + +static gboolean +gtk_list_view_get_allocation_across (GtkListBase *base, + guint pos, + int *offset, + int *size) +{ + GtkListView *self = GTK_LIST_VIEW (base); + + if (offset) + *offset = 0; + if (size) + *size = self->list_width; + + return TRUE; +} + static guint gtk_list_view_move_focus_along (GtkListBase *base, guint pos, @@ -410,6 +427,39 @@ gtk_list_view_move_focus_along (GtkListBase *base, return pos; } +static gboolean +gtk_list_view_get_position_from_allocation (GtkListBase *base, + int across, + int along, + guint *pos, + cairo_rectangle_int_t *area) +{ + GtkListView *self = GTK_LIST_VIEW (base); + ListRow *row; + int remaining; + + if (across >= self->list_width) + return FALSE; + + row = gtk_list_view_get_row_at_y (self, along, &remaining); + if (row == NULL) + return FALSE; + + *pos = gtk_list_item_manager_get_item_position (self->item_manager, row); + g_assert (remaining < row->height * row->parent.n_items); + *pos += remaining / row->height; + + if (area) + { + area->x = 0; + area->width = self->list_width; + area->y = along - remaining % row->height; + area->height = row->height; + } + + return TRUE; +} + static guint gtk_list_view_move_focus_across (GtkListBase *base, guint pos, @@ -434,7 +484,7 @@ gtk_list_view_update_adjustments (GtkListView *self, upper = gtk_list_view_get_list_height (self); anchor_pos = gtk_list_item_tracker_get_position (self->item_manager, self->anchor); - if (!gtk_list_view_get_size_at_position (self, + if (!gtk_list_base_get_allocation_along (GTK_LIST_BASE (self), anchor_pos, &offset, &size)) @@ -892,7 +942,7 @@ gtk_list_view_scroll_to_item (GtkWidget *widget, g_variant_get (parameter, "u", &pos); /* figure out primary orientation and if position is valid */ - if (!gtk_list_view_get_size_at_position (self, pos, &start, &end)) + if (!gtk_list_base_get_allocation_along (GTK_LIST_BASE (self), pos, &start, &end)) return; end += start; @@ -931,118 +981,6 @@ gtk_list_view_activate_item (GtkWidget *widget, g_signal_emit (widget, signals[ACTIVATE], 0, pos); } -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; - - pixels = gtk_widget_get_size (widget, gtk_list_base_get_orientation (GTK_LIST_BASE (self))); - 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_base_grab_focus_on_item (GTK_LIST_BASE (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; - - pixels = gtk_widget_get_size (widget, gtk_list_base_get_orientation (GTK_LIST_BASE (self))); - - 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_base_grab_focus_on_item (GTK_LIST_BASE (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_class_init (GtkListViewClass *klass) { @@ -1055,6 +993,9 @@ 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->get_allocation_along = gtk_list_view_get_allocation_along; + list_base_class->get_allocation_across = gtk_list_view_get_allocation_across; + list_base_class->get_position_from_allocation = gtk_list_view_get_position_from_allocation; list_base_class->move_focus_along = gtk_list_view_move_focus_along; list_base_class->move_focus_across = gtk_list_view_move_focus_across; @@ -1151,11 +1092,6 @@ gtk_list_view_class_init (GtkListViewClass *klass) "u", gtk_list_view_scroll_to_item); - 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_set_css_name (widget_class, I_("list")); }