summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2023-05-08 20:47:39 +0200
committerBenjamin Otte <otte@redhat.com>2023-05-09 17:03:35 +0200
commitddefbfa8b588e65cd4b2f614b0310c6909f12a3d (patch)
treee2c567cb762bb04227793271145e8508deb930ab
parent435a405c553941e54a5b0ccf3556ab96a900fdfb (diff)
downloadgtk+-ddefbfa8b588e65cd4b2f614b0310c6909f12a3d.tar.gz
gtk-demo: Add alternative settings demo
This one displays a long list of all settings with sections and allows filtering the list to quickly search for keys.
-rw-r--r--demos/gtk-demo/demo.gresource.xml4
-rw-r--r--demos/gtk-demo/listview_settings2.c230
-rw-r--r--demos/gtk-demo/listview_settings2.ui130
-rw-r--r--demos/gtk-demo/meson.build1
4 files changed, 365 insertions, 0 deletions
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 615d782bfe..ba87e860ce 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -195,6 +195,9 @@
<gresource prefix="/listview_settings">
<file>listview_settings.ui</file>
</gresource>
+ <gresource prefix="/listview_settings2">
+ <file>listview_settings2.ui</file>
+ </gresource>
<gresource prefix="/listview_ucd_data/">
<file>ucdnames.data</file>
</gresource>
@@ -312,6 +315,7 @@
<file>listview_minesweeper.c</file>
<file>listview_selections.c</file>
<file>listview_settings.c</file>
+ <file>listview_settings2.c</file>
<file>listview_ucd.c</file>
<file>listview_weather.c</file>
<file>listview_words.c</file>
diff --git a/demos/gtk-demo/listview_settings2.c b/demos/gtk-demo/listview_settings2.c
new file mode 100644
index 0000000000..4f3e87fb68
--- /dev/null
+++ b/demos/gtk-demo/listview_settings2.c
@@ -0,0 +1,230 @@
+/* Lists/Settings v2
+ * #Keywords: GtkListHeaderFactory, GtkSectionModel
+ *
+ * This demo shows a settings viewer for GSettings.
+ *
+ * It demonstrates how to implement support for sections with GtkListView.
+ *
+ * It also shows how to quickly flatten a large tree of items into a list
+ * that can be filtered to find the itmes one is looking for.
+ */
+
+#include <gtk/gtk.h>
+
+#include "settings-key.h"
+
+static void
+item_value_changed (GtkEditableLabel *label,
+ GParamSpec *pspec,
+ GtkColumnViewCell *cell)
+{
+ SettingsKey *self;
+ GSettingsSchemaKey *key;
+ const char *text;
+ const GVariantType *type;
+ GVariant *variant;
+ GError *error = NULL;
+ const char *name;
+ char *value;
+
+ text = gtk_editable_get_text (GTK_EDITABLE (label));
+
+ self = gtk_column_view_cell_get_item (cell);
+ key = settings_key_get_key (self);
+
+ type = g_settings_schema_key_get_value_type (key);
+ name = g_settings_schema_key_get_name (key);
+
+ variant = g_variant_parse (type, text, NULL, NULL, &error);
+ if (!variant)
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ goto revert;
+ }
+
+ if (!g_settings_schema_key_range_check (key, variant))
+ {
+ g_warning ("Not a valid value for %s", name);
+ goto revert;
+ }
+
+ g_settings_set_value (settings_key_get_settings (self), name, variant);
+ g_variant_unref (variant);
+ return;
+
+revert:
+ gtk_widget_error_bell (GTK_WIDGET (label));
+
+ g_object_get (self, "value", &value, NULL);
+ gtk_editable_set_text (GTK_EDITABLE (label), value);
+ g_free (value);
+}
+
+static int
+strvcmp (gconstpointer p1,
+ gconstpointer p2)
+{
+ const char * const *s1 = p1;
+ const char * const *s2 = p2;
+
+ return strcmp (*s1, *s2);
+}
+
+static gpointer
+map_settings_to_keys (gpointer item,
+ gpointer unused)
+{
+ GSettings *settings = item;
+ GSettingsSchema *schema;
+ GListStore *store;
+ char **keys;
+ guint i;
+
+ g_object_get (settings, "settings-schema", &schema, NULL);
+
+ store = g_list_store_new (SETTINGS_TYPE_KEY);
+
+ keys = g_settings_schema_list_keys (schema);
+
+ for (i = 0; keys[i] != NULL; i++)
+ {
+ GSettingsSchemaKey *almost_there = g_settings_schema_get_key (schema, keys[i]);
+ SettingsKey *finally = settings_key_new (settings, almost_there);
+ g_list_store_append (store, finally);
+ g_object_unref (finally);
+ g_settings_schema_key_unref (almost_there);
+ }
+
+ g_strfreev (keys);
+ g_settings_schema_unref (schema);
+ g_object_unref (settings);
+
+ return store;
+}
+
+static GListModel *
+create_settings_model (gpointer item,
+ gpointer unused)
+{
+ GSettings *settings = item;
+ char **schemas;
+ GListStore *result;
+ guint i;
+
+ if (settings == NULL)
+ {
+ g_settings_schema_source_list_schemas (g_settings_schema_source_get_default (),
+ TRUE,
+ &schemas,
+ NULL);
+ }
+ else
+ {
+ schemas = g_settings_list_children (settings);
+ }
+
+ if (schemas == NULL || schemas[0] == NULL)
+ {
+ g_free (schemas);
+ return NULL;
+ }
+
+ qsort (schemas, g_strv_length (schemas), sizeof (char *), strvcmp);
+
+ result = g_list_store_new (G_TYPE_SETTINGS);
+ for (i = 0; schemas[i] != NULL; i++)
+ {
+ GSettings *child;
+
+ if (settings == NULL)
+ child = g_settings_new (schemas[i]);
+ else
+ child = g_settings_get_child (settings, schemas[i]);
+
+ g_list_store_append (result, child);
+ g_object_unref (child);
+ }
+
+ g_strfreev (schemas);
+
+ return G_LIST_MODEL (result);
+}
+
+static void
+search_enabled (GtkSearchEntry *entry)
+{
+ gtk_editable_set_text (GTK_EDITABLE (entry), "");
+}
+
+static void
+stop_search (GtkSearchEntry *entry,
+ gpointer data)
+{
+ gtk_editable_set_text (GTK_EDITABLE (entry), "");
+}
+
+static GtkWidget *window = NULL;
+
+GtkWidget *
+do_listview_settings2 (GtkWidget *do_widget)
+{
+ if (window == NULL)
+ {
+ GtkListView *listview;
+ GListModel *model;
+ GtkTreeListModel *treemodel;
+ GtkNoSelection *selection;
+ GtkBuilderScope *scope;
+ GtkBuilder *builder;
+ GError *error = NULL;
+ GtkFilter *filter;
+
+ g_type_ensure (SETTINGS_TYPE_KEY);
+
+ scope = gtk_builder_cscope_new ();
+ gtk_builder_cscope_add_callback (scope, search_enabled);
+ gtk_builder_cscope_add_callback (scope, stop_search);
+ gtk_builder_cscope_add_callback (scope, settings_key_get_search_string);
+ gtk_builder_cscope_add_callback (scope, item_value_changed);
+
+ builder = gtk_builder_new ();
+ gtk_builder_set_scope (builder, scope);
+ g_object_unref (scope);
+
+ gtk_builder_add_from_resource (builder, "/listview_settings2/listview_settings2.ui", &error);
+ g_assert_no_error (error);
+
+ window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
+ gtk_window_set_display (GTK_WINDOW (window),
+ gtk_widget_get_display (do_widget));
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
+
+ listview = GTK_LIST_VIEW (gtk_builder_get_object (builder, "listview"));
+ filter = GTK_FILTER (gtk_builder_get_object (builder, "filter"));
+
+ model = create_settings_model (NULL, NULL);
+ treemodel = gtk_tree_list_model_new (model,
+ TRUE,
+ TRUE,
+ create_settings_model,
+ NULL,
+ NULL);
+ model = G_LIST_MODEL (gtk_map_list_model_new (G_LIST_MODEL (treemodel), map_settings_to_keys, NULL, NULL));
+ model = G_LIST_MODEL (gtk_flatten_list_model_new (model));
+ model = G_LIST_MODEL (gtk_filter_list_model_new (model, g_object_ref (filter)));
+ selection = gtk_no_selection_new (model);
+
+ gtk_list_view_set_model (GTK_LIST_VIEW (listview), GTK_SELECTION_MODEL (selection));
+ g_object_unref (selection);
+
+ g_object_unref (builder);
+ }
+
+ if (!gtk_widget_get_visible (window))
+ gtk_widget_set_visible (window, TRUE);
+ else
+ gtk_window_destroy (GTK_WINDOW (window));
+
+ return window;
+}
diff --git a/demos/gtk-demo/listview_settings2.ui b/demos/gtk-demo/listview_settings2.ui
new file mode 100644
index 0000000000..0600f63582
--- /dev/null
+++ b/demos/gtk-demo/listview_settings2.ui
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <object class="GtkStringFilter" id="filter">
+ <property name="expression">
+ <closure type="gchararray" function="settings_key_get_search_string" />
+ </property>
+ <property name="search" bind-source="entry" bind-property="text" />
+ </object>
+ <object class="GtkWindow" id="window">
+ <property name="title" translatable="yes">Settings</property>
+ <property name="default-width">640</property>
+ <property name="default-height">480</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar">
+ <child type="end">
+ <object class="GtkToggleButton" id="search_button">
+ <property name="icon-name">system-search-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSearchBar">
+ <property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional"/>
+ <signal name="notify::search-mode-enabled" handler="search_enabled" object="entry"/>
+ <child>
+ <object class="GtkSearchEntry" id="entry">
+ <signal name="stop-search" handler="stop_search"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <child>
+ <object class="GtkListView" id="listview">
+ <property name="vexpand">1</property>
+ <style>
+ <class name="rich-list"/>
+ </style>
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="bytes"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkListItem">
+ <property name="child">
+ <object class="GtkBox">
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="xalign">0</property>
+ <binding name="label">
+ <lookup name="name" type="SettingsKey">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <style>
+ <class name="dim-label"/>
+ </style>
+ <property name="xalign">0</property>
+ <property name="ellipsize">end</property>
+ <binding name="label">
+ <lookup name="summary" type="SettingsKey">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkEntry">
+ <property name="hexpand">1</property>
+ <property name="halign">end</property>
+ <binding name="text">
+ <lookup name="value" type="SettingsKey">
+ <lookup name="item">GtkListItem</lookup>
+ </lookup>
+ </binding>
+ <signal name="notify::label" handler="item_value_changed"/>
+ </object>
+ </child>
+ </object>
+ </property>
+ </template>
+</interface>
+ ]]></property>
+ </object>
+ </property>
+ <property name="header-factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="bytes"><![CDATA[
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkListHeader">
+ <property name="child">
+ <object class="GtkLabel">
+ <property name="xalign">0</property>
+ <binding name="label">
+ <lookup name="schema" type="GSettings">
+ <lookup name="settings" type="SettingsKey">
+ <lookup name="item">GtkListHeader</lookup>
+ </lookup>
+ </lookup>
+ </binding>
+ </object>
+ </property>
+ </template>
+</interface>
+ ]]></property>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index f1ce4ffc6b..976c3ec997 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -57,6 +57,7 @@ demos = files([
'listview_minesweeper.c',
'listview_selections.c',
'listview_settings.c',
+ 'listview_settings2.c',
'listview_ucd.c',
'listview_weather.c',
'listview_words.c',