From 45c9e7aff4715208a77feaa4e9bd20a0c376c3cc Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 14 Feb 2022 03:18:36 +0100 Subject: Add GtkSectionModel Prototyping the interface to be used for sections in listview, so people can review and play with it. --- gtk/gtksectionmodel.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 gtk/gtksectionmodel.c (limited to 'gtk/gtksectionmodel.c') diff --git a/gtk/gtksectionmodel.c b/gtk/gtksectionmodel.c new file mode 100644 index 0000000000..a3763a1c64 --- /dev/null +++ b/gtk/gtksectionmodel.c @@ -0,0 +1,182 @@ +/* + * Copyright © 2022 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gtksectionmodel.h" + +#include "gtkmarshalers.h" + +/** + * GtkSectionModel: + * + * `GtkSectionModel` is an interface that adds support for section to list models. + * + * This support is then used by widgets using list models to be able to group their + * items into sections. + * + * Many GTK list models support sections inherently, or they pass through the sections + * of a model they are wrapping. + * + * A `GtkSectionModel` groups successive items into so-called sections. List widgets + * like `GtkListView` then allow displaying section headers for these sections. + * + * When the section groupings of a model changes, the model will emit the + * [signal@Gtk.SectionModel::sections-changed] signal by calling the + * [method@Gtk.SectionModel.sections_changed] function. All sections in the given range + * now need to be queried again. + * The [signal@Gio.ListModel::items-changed] signal has the same effect, all sections in + * that range are invalidated, too. + * + * Since: 4.12 + */ + +G_DEFINE_INTERFACE (GtkSectionModel, gtk_section_model, G_TYPE_LIST_MODEL) + +enum { + SECTIONS_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +gtk_section_model_default_get_section (GtkSectionModel *self, + guint position, + guint *out_start, + guint *out_end) +{ + guint n_items = g_list_model_get_n_items (G_LIST_MODEL (self)); + + if (position >= n_items) + { + *out_start = n_items; + *out_end = G_MAXUINT; + } + + *out_start = 0; + *out_end = n_items; +} + +static void +gtk_section_model_default_init (GtkSectionModelInterface *iface) +{ + iface->get_section = gtk_section_model_default_get_section; + + /** + * GtkSectionModel::sections-changed + * @model: a `GtkSectionModel` + * @position: The first item that may have changed + * @n_items: number of items with changes + * + * Emitted when the start-of-section state of some of the items in @model changes. + * + * Note that this signal does not specify the new section state of the + * items, they need to be queried manually. It is also not necessary for + * a model to change the section state of any of the items in the section + * model, though it would be rather useless to emit such a signal. + * + * The [signal@Gio.ListModel::items-changed] implies the effect of the + * [signal@Gtk.SectionModel::section-changed] signal for all the items + * it covers. + * + * Since: 4.12 + */ + signals[SECTIONS_CHANGED] = + g_signal_new ("sections-changed", + GTK_TYPE_SECTION_MODEL, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _gtk_marshal_VOID__UINT_UINT, + G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + g_signal_set_va_marshaller (signals[SECTIONS_CHANGED], + GTK_TYPE_SECTION_MODEL, + _gtk_marshal_VOID__UINT_UINTv); +} + +/** + * gtk_section_model_get_section: + * @self: a `GtkSectionModel` + * @position: the position of the item to query + * @out_start: (out caller-allocates): the position of the first + * item in the section + * @out_end: (out caller-allocates): the position of the first + * item not part of the section anymore. + * + * Query the section that covers the given position. The number of + * items in the section can be computed by `out_end - out_start`. + * + * If the position is larger than the number of items, a single + * range from n_items to G_MAXUINT will be returned. + * + * Since: 4.12 + */ +void +gtk_section_model_get_section (GtkSectionModel *self, + guint position, + guint *out_start, + guint *out_end) +{ + GtkSectionModelInterface *iface; + + g_return_if_fail (GTK_IS_SECTION_MODEL (self)); + g_return_if_fail (out_start != NULL); + g_return_if_fail (out_end != NULL); + + iface = GTK_SECTION_MODEL_GET_IFACE (self); + iface->get_section (self, position, out_start, out_end); + + g_warn_if_fail (*out_start < *out_end); +} + +/** + * gtk_section_model_section_changed: + * @self: a `GtkSectionModel` + * @position: the first changed item + * @n_items: the number of changed items + * + * This function emits the [signal@Gtk.SectionModel::section-changed] + * signal to notify about changes to sections. It must cover all + * positions that used to be a section start or that are now a section + * start. It does not have to cover all positions for which the section + * has changed. + * + * The [signal@Gio.ListModel::items-changed] implies the effect of the + * [signal@Gtk.SectionModel::section-changed] signal for all the items + * it covers. + * + * It is recommended that when changes to the items cause section changes + * in a larger range, that the larger range is included in the emission + * of the [signal@Gio.ListModel::items-changed] instead of emitting + * two signals. + * + * Since: 4.12 + */ +void +gtk_section_model_sections_changed (GtkSectionModel *self, + guint position, + guint n_items) +{ + g_return_if_fail (GTK_IS_SECTION_MODEL (self)); + g_return_if_fail (n_items > 0); + g_return_if_fail (position + n_items <= g_list_model_get_n_items (G_LIST_MODEL (self))); + + g_signal_emit (self, signals[SECTIONS_CHANGED], 0, position, n_items); +} -- cgit v1.2.1