diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index be3cdfca7d..3028576cd4 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -352,6 +352,8 @@ gtk_selection_model_select_all gtk_selection_model_unselect_all gtk_selection_model_query_range +gtk_selection_model_user_select_item + gtk_selection_model_selection_changed GTK_SELECTION_MODEL diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c index e2eb610597..e9fd7b7eb5 100644 --- a/gtk/gtklistview.c +++ b/gtk/gtklistview.c @@ -616,61 +616,11 @@ gtk_list_view_select_item (GtkListView *self, gboolean modify, gboolean extend) { - GtkSelectionModel *selection_model; - gboolean success = FALSE; - - selection_model = gtk_list_item_manager_get_model (self->item_manager); - - if (extend) - { - guint start_pos = gtk_list_item_tracker_get_position (self->item_manager, self->selected); - if (start_pos != GTK_INVALID_LIST_POSITION) - { - guint max = MAX (start_pos, pos); - guint min = MIN (start_pos, pos); - if (modify) - { - if (gtk_selection_model_is_selected (selection_model, start_pos)) - { - success = gtk_selection_model_select_range (selection_model, - min, - max - min + 1, - FALSE); - } - else - { - success = gtk_selection_model_unselect_range (selection_model, - min, - max - min + 1); - } - } - else - { - success = gtk_selection_model_select_range (selection_model, - min, - max - min + 1, - TRUE); - } - } - /* If there's no range to select or selecting ranges isn't supported - * by the model, fall through to normal setting. - */ - } - if (success) - return; - - if (modify) - { - if (gtk_selection_model_is_selected (selection_model, pos)) - success = gtk_selection_model_unselect_item (selection_model, pos); - else - success = gtk_selection_model_select_item (selection_model, pos, FALSE); - } - else - { - success = gtk_selection_model_select_item (selection_model, pos, TRUE); - } - if (success) + if (gtk_selection_model_user_select_item (gtk_list_item_manager_get_model (self->item_manager), + pos, + modify, + extend ? gtk_list_item_tracker_get_position (self->item_manager, self->selected) + : GTK_INVALID_LIST_POSITION)) { gtk_list_item_tracker_set_position (self->item_manager, self->selected, diff --git a/gtk/gtkselectionmodel.c b/gtk/gtkselectionmodel.c index 7be454fd74..c5853e87a7 100644 --- a/gtk/gtkselectionmodel.c +++ b/gtk/gtkselectionmodel.c @@ -382,3 +382,90 @@ gtk_selection_model_selection_changed (GtkSelectionModel *model, g_signal_emit (model, signals[SELECTION_CHANGED], 0, position, n_items); } +/** + * gtk_selection_model_user_select_item: + * @self: a #GtkSelectionModel + * @pos: position selected by the user. If this position is invalid + * no selection will be done. + * @modify: %TRUE if the selection should be modified, %FALSE + * if a new selection should be done. This is usually set + * to %TRUE if the user keeps the key pressed. + * @extend_pos: the position to extend the selection from or + * an invalid position like #GTK_INVALID_LIST_POSITION to not + * extend the selection. Selections are usually extended + * from the last selected position if the user presses the + * key. The last selected position is stored by the + * widget + * + * Does a selection according to how GTK list widgets modify + * selections, both when clicking rows with the mouse or when using + * the keyboard. + * + * Returns: %TRUE if the last selected position for further calls + * to this function should be updated to @pos, %FALSE if the + * last selected position should not change. + **/ +gboolean +gtk_selection_model_user_select_item (GtkSelectionModel *self, + guint pos, + gboolean modify, + guint extend_pos) +{ + gboolean success = FALSE; + guint n_items; + + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (self), FALSE); + + n_items = g_list_model_get_n_items (G_LIST_MODEL (self)); + if (pos >= n_items) + return FALSE; + + if (extend_pos < n_items) + { + guint max = MAX (extend_pos, pos); + guint min = MIN (extend_pos, pos); + if (modify) + { + if (gtk_selection_model_is_selected (self, extend_pos)) + { + success = gtk_selection_model_select_range (self, + min, + max - min + 1, + FALSE); + } + else + { + success = gtk_selection_model_unselect_range (self, + min, + max - min + 1); + } + } + else + { + success = gtk_selection_model_select_range (self, + min, + max - min + 1, + TRUE); + } + /* If there's no range to select or selecting ranges isn't supported + * by the model, fall through to normal setting. + */ + } + if (success) + return FALSE; + + if (modify) + { + if (gtk_selection_model_is_selected (self, pos)) + success = gtk_selection_model_unselect_item (self, pos); + else + success = gtk_selection_model_select_item (self, pos, FALSE); + } + else + { + success = gtk_selection_model_select_item (self, pos, TRUE); + } + + return success; +} + diff --git a/gtk/gtkselectionmodel.h b/gtk/gtkselectionmodel.h index 9e8de6a66b..ef5fd1e598 100644 --- a/gtk/gtkselectionmodel.h +++ b/gtk/gtkselectionmodel.h @@ -118,6 +118,11 @@ void gtk_selection_model_query_range (GtkSelectionMod guint *n_items, gboolean *selected); +GDK_AVAILABLE_IN_ALL +gboolean gtk_selection_model_user_select_item (GtkSelectionModel *self, + guint pos, + gboolean modify, + guint extend_pos); /* for implementations only */ GDK_AVAILABLE_IN_ALL void gtk_selection_model_selection_changed (GtkSelectionModel *model,