# HG changeset patch
# Node ID e99e8e6ae90a
# Parent  a6c4cbd31856
diff --git a/gplugin-gtk4/gplugin-gtk-plugin-settings-list.c b/gplugin-gtk4/gplugin-gtk-plugin-settings-list.c
--- a/gplugin-gtk4/gplugin-gtk-plugin-settings-list.c
+++ b/gplugin-gtk4/gplugin-gtk-plugin-settings-list.c
@@ -15,6 +15,8 @@
  * License along with this library; if not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <glib/gi18n-lib.h>
+
 #include <gplugin.h>
 
 #include <gplugin-gtk-plugin-settings-list.h>
@@ -51,38 +53,275 @@ static GParamSpec *properties[N_PROPERTI
 };
 
 /******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static gboolean
+gplugin_gtk_plugin_settings_row_byte_to_double(
+	GValue *value,
+	GVariant *variant,
+	G_GNUC_UNUSED gpointer data)
+{
+	g_value_set_double(value, (gdouble)g_variant_get_byte(variant));
+	return TRUE;
+}
+
+static GVariant *
+gplugin_gtk_plugin_settings_row_double_to_byte(
+	const GValue *value,
+	G_GNUC_UNUSED const GVariantType *expected_type,
+	G_GNUC_UNUSED gpointer data)
+{
+	return g_variant_new_byte((char)g_value_get_double(value));
+}
+
+static gboolean
+gplugin_gtk_plugin_settings_row_enum_to_selected(
+	GValue *value,
+	GVariant *variant,
+	gpointer data)
+{
+	GListModel *model = data;
+	const char *string = NULL;
+	guint n_items;
+
+	string = g_variant_get_string(variant, NULL);
+	n_items = g_list_model_get_n_items(model);
+	for(guint index = 0; index < n_items; index++) {
+		GtkStringObject *obj = g_list_model_get_item(model, index);
+
+		if(g_str_equal(string, gtk_string_object_get_string(obj))) {
+			g_value_set_uint(value, index);
+			g_object_unref(obj);
+			return TRUE;
+		}
+
+		g_object_unref(obj);
+	}
+
+	return FALSE;
+}
+
+static GVariant *
+gplugin_gtk_plugin_settings_row_selected_to_enum(
+	const GValue *value,
+	G_GNUC_UNUSED const GVariantType *expected_type,
+	gpointer data)
+{
+	GListModel *model = data;
+	GtkStringObject *obj = NULL;
+	GVariant *result = NULL;
+
+	obj = g_list_model_get_item(model, g_value_get_uint(value));
+	result = g_variant_new_string(gtk_string_object_get_string(obj));
+	g_object_unref(obj);
+
+	return result;
+}
+
+/******************************************************************************
  * Helpers
  *****************************************************************************/
 static GtkWidget *
 gplugin_gtk_plugin_settings_row_new_for_key(
 	GSettings *settings,
 	const gchar *name,
-	GSettingsSchemaKey *key)
+	GSettingsSchemaKey *key,
+	GtkSizeGroup *sg)
 {
-	/* TODO: Make real widgets. */
 	GtkWidget *widget = NULL;
 	GtkWidget *label = NULL;
 	GtkWidget *entry = NULL;
-	GVariant *value = NULL;
-	char *value_str = NULL;
+	const char *summary = NULL;
+	const GVariantType *type = NULL;
+	GVariant *range = NULL;
+	gchar *range_type = NULL;
+	GVariant *range_value = NULL;
 
 	widget = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
 
-	label = gtk_label_new(g_settings_schema_key_get_name(key));
+	summary = g_settings_schema_key_get_summary(key);
+	label = gtk_label_new((summary != NULL) ? summary : name);
 	gtk_label_set_xalign(GTK_LABEL(label), 0);
 	gtk_box_append(GTK_BOX(widget), label);
+	gtk_size_group_add_widget(sg, label);
 
-	value = g_settings_get_value(settings, name);
-	value_str = g_variant_print(value, TRUE);
-	g_variant_unref(value);
+	gtk_widget_set_tooltip_text(
+		widget,
+		g_settings_schema_key_get_description(key));
+
+	type = g_settings_schema_key_get_value_type(key);
+	range = g_settings_schema_key_get_range(key);
+	g_variant_get_child(range, 0, "s", &range_type);
+	g_variant_get_child(range, 1, "v", &range_value);
+
+	if(g_str_equal(range_type, "enum")) {
+		const gchar **allowed_values = NULL;
+		GListModel *model = NULL;
+
+		allowed_values = g_variant_get_strv(range_value, NULL);
+		entry = gtk_drop_down_new_from_strings(allowed_values);
+		g_free(allowed_values);
+
+		model = gtk_drop_down_get_model(GTK_DROP_DOWN(entry));
+		g_settings_bind_with_mapping(
+			settings,
+			name,
+			entry,
+			"selected",
+			G_SETTINGS_BIND_DEFAULT,
+			gplugin_gtk_plugin_settings_row_enum_to_selected,
+			gplugin_gtk_plugin_settings_row_selected_to_enum,
+			g_object_ref(model),
+			g_object_unref);
+
+	} else if(g_str_equal(range_type, "range")) {
+		gdouble min, max, step;
+		if(g_variant_type_peek_string(type)[0] == 'd') {
+			g_variant_get_child(range_value, 0, "d", &min);
+			g_variant_get_child(range_value, 1, "d", &max);
+			step = (max - min) / 100;
+		} else {
+			gint mini, maxi;
+			g_variant_get_child(range_value, 0, "i", &mini);
+			g_variant_get_child(range_value, 1, "i", &maxi);
+			min = (gdouble)mini;
+			max = (gdouble)maxi;
+			step = 1;
+		}
+		entry = gtk_spin_button_new_with_range(min, max, step);
+
+		g_settings_bind(
+			settings,
+			name,
+			entry,
+			"value",
+			G_SETTINGS_BIND_DEFAULT);
+
+	} else if(g_str_equal(range_type, "type")) {
+		char main_type;
+		gdouble min, max;
+
+		main_type = g_variant_type_peek_string(type)[0];
+		switch(main_type) {
+			/* Boolean */
+			case 'b':
+				entry = gtk_switch_new();
+				gtk_widget_set_halign(entry, GTK_ALIGN_END);
+				gtk_widget_set_valign(entry, GTK_ALIGN_CENTER);
+
+				g_settings_bind(
+					settings,
+					name,
+					entry,
+					"active",
+					G_SETTINGS_BIND_DEFAULT);
+				break;
 
-	entry = gtk_entry_new();
-	gtk_editable_set_text(GTK_EDITABLE(entry), value_str);
-	gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
-	gtk_widget_set_hexpand(entry, TRUE);
-	gtk_box_append(GTK_BOX(widget), entry);
+			/* Numbers */
+			case 'y':
+			case 'n':
+			case 'q':
+			case 'i':
+			case 'u':
+			case 'x':
+			case 't':
+				switch(main_type) {
+					case 'y':
+						min = 0.0;
+						max = G_MAXUINT8;
+						break;
+					case 'n':
+						min = G_MININT16;
+						max = G_MAXINT16;
+						break;
+					case 'q':
+						min = 0.0;
+						max = G_MAXUINT16;
+						break;
+					case 'i':
+						min = G_MININT32;
+						max = G_MAXINT32;
+						break;
+					case 'u':
+						min = 0.0;
+						max = G_MAXUINT32;
+						break;
+					case 'x':
+						min = G_MININT64;
+						max = (gdouble)G_MAXINT64;
+						break;
+					case 't':
+						min = 0.0;
+						max = (gdouble)G_MAXUINT64;
+						break;
+				}
 
-	g_free(value_str);
+				entry = gtk_spin_button_new_with_range(min, max, 1.0);
+				if(main_type != 'y') {
+					g_settings_bind(
+						settings,
+						name,
+						entry,
+						"value",
+						G_SETTINGS_BIND_DEFAULT);
+				} else {
+					/* For some reason, Gio's default bindings understand
+					 * double-to-int conversions for any bit size other than
+					 * bytes. */
+					g_settings_bind_with_mapping(
+						settings,
+						name,
+						entry,
+						"value",
+						G_SETTINGS_BIND_DEFAULT,
+						gplugin_gtk_plugin_settings_row_byte_to_double,
+						gplugin_gtk_plugin_settings_row_double_to_byte,
+						NULL,
+						NULL);
+				}
+
+				break;
+
+			case 'd':
+				entry = gtk_spin_button_new(NULL, 1.0, 5);
+				g_settings_bind(
+					settings,
+					name,
+					entry,
+					"value",
+					G_SETTINGS_BIND_DEFAULT);
+
+				break;
+
+			/* Strings */
+			case 's':
+				entry = gtk_entry_new();
+				g_settings_bind(
+					settings,
+					name,
+					gtk_entry_get_buffer(GTK_ENTRY(entry)),
+					"text",
+					G_SETTINGS_BIND_DEFAULT);
+				break;
+
+			default:
+				entry = gtk_label_new(_("Unknown setting type"));
+				break;
+		}
+	} else {
+		/* No other types are documented. */
+		g_warn_if_reached();
+		entry = gtk_label_new(_("Unknown setting type"));
+	}
+
+	g_variant_unref(range_value);
+	g_free(range_type);
+	g_variant_unref(range);
+
+	if(GTK_IS_WIDGET(entry)) {
+		gtk_widget_set_hexpand(entry, TRUE);
+		gtk_box_append(GTK_BOX(widget), entry);
+	}
 
 	return widget;
 }
@@ -94,6 +333,7 @@ gplugin_gtk_plugin_settings_list_refresh
 {
 	GSettingsSchema *schema = NULL;
 	gchar **names = NULL;
+	GtkSizeGroup *sg = NULL;
 
 	while(list->rows) {
 		gtk_list_box_remove(list->list_box, list->rows->data);
@@ -106,6 +346,7 @@ gplugin_gtk_plugin_settings_list_refresh
 
 	g_object_get(G_OBJECT(settings), "settings-schema", &schema, NULL);
 	names = g_settings_schema_list_keys(schema);
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 
 	for(gint i = 0; names[i] != NULL; i++) {
 		GSettingsSchemaKey *key = NULL;
@@ -116,7 +357,8 @@ gplugin_gtk_plugin_settings_list_refresh
 		widget = gplugin_gtk_plugin_settings_row_new_for_key(
 			settings,
 			names[i],
-			key);
+			key,
+			sg);
 
 		row = gtk_list_box_row_new();
 		gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), widget);
