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.
This commit is contained in:
Benjamin Otte 2023-05-08 20:47:39 +02:00
parent 435a405c55
commit ddefbfa8b5
4 changed files with 365 additions and 0 deletions

View File

@ -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>

View File

@ -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;
}

View File

@ -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>

View File

@ -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',