diff options
author | Benjamin Otte <otte@redhat.com> | 2022-02-14 03:18:36 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2023-04-11 13:37:32 +0200 |
commit | 74c55de53df2af26bd3dd97ec4ee5dbbf68476a4 (patch) | |
tree | 6443cf34f4e99f912e8037985b412381067bab92 | |
parent | 65a631a56165621cd6df6375337e2c079c71b1f2 (diff) | |
download | gtk+-74c55de53df2af26bd3dd97ec4ee5dbbf68476a4.tar.gz |
Add GtkSectionModel
Prototyping the interface to be used for sections in listview, so people
can review and play with it.
-rw-r--r-- | gtk/gtk.h | 1 | ||||
-rw-r--r-- | gtk/gtksectionmodel.c | 182 | ||||
-rw-r--r-- | gtk/gtksectionmodel.h | 72 | ||||
-rw-r--r-- | gtk/meson.build | 2 |
4 files changed, 257 insertions, 0 deletions
@@ -225,6 +225,7 @@ #include <gtk/gtkscrolledwindow.h> #include <gtk/gtksearchbar.h> #include <gtk/gtksearchentry.h> +#include <gtk/gtksectionmodel.h> #include <gtk/gtkselectionfiltermodel.h> #include <gtk/gtkselectionmodel.h> #include <gtk/gtkseparator.h> 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 <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#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); +} diff --git a/gtk/gtksectionmodel.h b/gtk/gtksectionmodel.h new file mode 100644 index 0000000000..a242b42c20 --- /dev/null +++ b/gtk/gtksectionmodel.h @@ -0,0 +1,72 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + * + * Authors: Benjamin Otte <otte@gnome.org> + */ + +#pragma once + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk.h> can be included directly." +#endif + +#include <gtk/gtktypes.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_SECTION_MODEL (gtk_section_model_get_type ()) + +GDK_AVAILABLE_IN_4_12 +G_DECLARE_INTERFACE (GtkSectionModel, gtk_section_model, GTK, SECTION_MODEL, GListModel) + +/** + * GtkSectionModelInterface: + * @get_section: Return the section that covers the given position. If + * the position is outside the number of items, returns a single range from + * n_items to G_MAXUINT + * + * The list of virtual functions for the `GtkSectionModel` interface. + * No function must be implemented, but unless `GtkSectionModel::get_section()` + * is implemented, the whole model will just be a single section. + * + * Since: 4.12 + */ +struct _GtkSectionModelInterface +{ + /*< private >*/ + GTypeInterface g_iface; + + /*< public >*/ + void (* get_section) (GtkSectionModel *self, + guint position, + guint *out_start, + guint *out_end); +}; + +GDK_AVAILABLE_IN_4_12 +void gtk_section_model_get_section (GtkSectionModel *self, + guint position, + guint *out_start, + guint *out_end); + +/* for implementations only */ +GDK_AVAILABLE_IN_4_12 +void gtk_section_model_sections_changed (GtkSectionModel *self, + guint position, + guint n_items); + +G_END_DECLS + diff --git a/gtk/meson.build b/gtk/meson.build index b3975fb3fc..1ea9b37e25 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -333,6 +333,7 @@ gtk_public_sources = files([ 'gtkscrolledwindow.c', 'gtksearchbar.c', 'gtksearchentry.c', + 'gtksectionmodel.c', 'gtkselectionfiltermodel.c', 'gtkselectionmodel.c', 'gtkseparator.c', @@ -565,6 +566,7 @@ gtk_public_headers = files([ 'gtkscrolledwindow.h', 'gtksearchbar.h', 'gtksearchentry.h', + 'gtksectionmodel.h', 'gtkselectionfiltermodel.h', 'gtkselectionmodel.h', 'gtkseparator.h', |