summaryrefslogtreecommitdiff
path: root/gtk/gtksectionmodel.c
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2022-02-14 03:18:36 +0100
committerBenjamin Otte <otte@redhat.com>2023-05-09 17:00:39 +0200
commit45c9e7aff4715208a77feaa4e9bd20a0c376c3cc (patch)
treed86a029a9bc0316e46db9b039a74595499717843 /gtk/gtksectionmodel.c
parentd24291db98b659440073beb928bd5b5f7d0b654d (diff)
downloadgtk+-45c9e7aff4715208a77feaa4e9bd20a0c376c3cc.tar.gz
Add GtkSectionModel
Prototyping the interface to be used for sections in listview, so people can review and play with it.
Diffstat (limited to 'gtk/gtksectionmodel.c')
-rw-r--r--gtk/gtksectionmodel.c182
1 files changed, 182 insertions, 0 deletions
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);
+}