diff options
author | Benjamin Otte <otte@redhat.com> | 2023-05-08 20:47:39 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2023-05-09 17:03:35 +0200 |
commit | ddefbfa8b588e65cd4b2f614b0310c6909f12a3d (patch) | |
tree | e2c567cb762bb04227793271145e8508deb930ab /demos | |
parent | 435a405c553941e54a5b0ccf3556ab96a900fdfb (diff) | |
download | gtk+-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.
Diffstat (limited to 'demos')
-rw-r--r-- | demos/gtk-demo/demo.gresource.xml | 4 | ||||
-rw-r--r-- | demos/gtk-demo/listview_settings2.c | 230 | ||||
-rw-r--r-- | demos/gtk-demo/listview_settings2.ui | 130 | ||||
-rw-r--r-- | demos/gtk-demo/meson.build | 1 |
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', |