Implement property proxy widget creation.
The functions katze_property_proxy and katze_propery_label can intelligently create widgets that represent properties of a particular object. This allows for building up a configuration interface with few to no code dealing with specific settings.
This commit is contained in:
parent
f11b76b6ef
commit
a9eb81a016
2 changed files with 246 additions and 3 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
|
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -10,3 +10,237 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "katze-utils.h"
|
#include "katze-utils.h"
|
||||||
|
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_toggle_button_toggled_cb (GtkToggleButton* button, GObject* object)
|
||||||
|
{
|
||||||
|
gboolean toggled = gtk_toggle_button_get_active (button);
|
||||||
|
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
|
||||||
|
g_object_set (object, property, toggled, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_file_file_set_cb (GtkFileChooser* button,
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
const gchar* file = gtk_file_chooser_get_filename (button);
|
||||||
|
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
|
||||||
|
g_object_set (object, property, file, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_folder_file_set_cb (GtkFileChooser* button,
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
const gchar* file = gtk_file_chooser_get_current_folder (button);
|
||||||
|
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
|
||||||
|
g_object_set (object, property, file, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_uri_file_set_cb (GtkFileChooser* button,
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
const gchar* file = gtk_file_chooser_get_uri (button);
|
||||||
|
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
|
||||||
|
g_object_set (object, property, file, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
proxy_entry_focus_out_event_cb (GtkEntry* entry,
|
||||||
|
GdkEventFocus* event,
|
||||||
|
GObject* object)
|
||||||
|
{
|
||||||
|
const gchar* text = gtk_entry_get_text (entry);
|
||||||
|
const gchar* property = g_object_get_data (G_OBJECT (entry), "property");
|
||||||
|
g_object_set (object, property, text, NULL);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
proxy_spin_button_changed_cb (GtkSpinButton* button, GObject* object)
|
||||||
|
{
|
||||||
|
gdouble value = gtk_spin_button_get_value (button);
|
||||||
|
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
|
||||||
|
g_object_set (object, property, value, NULL);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
proxy_combo_box_changed_cb (GtkComboBox* button, GObject* object)
|
||||||
|
{
|
||||||
|
gint value = gtk_combo_box_get_active (button);
|
||||||
|
const gchar* property = g_object_get_data (G_OBJECT (button), "property");
|
||||||
|
g_object_set (object, property, value, NULL);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* katze_property_proxy:
|
||||||
|
* @object: a #GObject
|
||||||
|
* @property: the name of a property
|
||||||
|
* @hint: a special hint
|
||||||
|
*
|
||||||
|
* Create a widget of an appropriate type to represent the specified
|
||||||
|
* object's property. If the property is writable changes of the value
|
||||||
|
* through the widget will be reflected in the value of the property.
|
||||||
|
*
|
||||||
|
* Supported values for @hint are as follows:
|
||||||
|
* "blurb": the blurb of the property will be used to provide a kind
|
||||||
|
* of label, instead of the name.
|
||||||
|
* "file": the widget created will be particularly suitable for
|
||||||
|
* choosing an existing filename.
|
||||||
|
* "folder": the widget created will be particularly suitable for
|
||||||
|
* choosing an existing folder.
|
||||||
|
* "uri": the widget created will be particularly suitable for
|
||||||
|
* choosing an existing filename, encoded as an URI.
|
||||||
|
*
|
||||||
|
* Any other values for @hint are silently ignored.
|
||||||
|
*
|
||||||
|
* Return value: a new widget
|
||||||
|
**/
|
||||||
|
GtkWidget*
|
||||||
|
katze_property_proxy (gpointer object,
|
||||||
|
const gchar* property,
|
||||||
|
const gchar* hint)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
|
||||||
|
GObjectClass* class = G_OBJECT_GET_CLASS (object);
|
||||||
|
GParamSpec* pspec = g_object_class_find_property (class, property);
|
||||||
|
if (!pspec)
|
||||||
|
{
|
||||||
|
g_warning ("Property '%s' is invalid for %s",
|
||||||
|
property, G_OBJECT_CLASS_NAME (class));
|
||||||
|
return gtk_label_new (property);
|
||||||
|
}
|
||||||
|
GType type = G_PARAM_SPEC_TYPE (pspec);
|
||||||
|
const gchar* nick = g_param_spec_get_nick (pspec);
|
||||||
|
const gchar* _hint = g_intern_string (hint);
|
||||||
|
if (_hint == g_intern_string ("blurb"))
|
||||||
|
nick = g_param_spec_get_blurb (pspec);
|
||||||
|
GtkWidget* widget;
|
||||||
|
const gchar* string;
|
||||||
|
if (type == G_TYPE_PARAM_BOOLEAN)
|
||||||
|
{
|
||||||
|
widget = gtk_check_button_new_with_label (nick);
|
||||||
|
gboolean toggled;
|
||||||
|
g_object_get (object, property, &toggled, NULL);
|
||||||
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), toggled);
|
||||||
|
g_signal_connect (widget, "toggled",
|
||||||
|
G_CALLBACK (proxy_toggle_button_toggled_cb), object);
|
||||||
|
}
|
||||||
|
else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("file"))
|
||||||
|
{
|
||||||
|
widget = gtk_file_chooser_button_new (_("Choose file"),
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN);
|
||||||
|
g_object_get (object, property, &string, NULL);
|
||||||
|
if (!string)
|
||||||
|
string = G_PARAM_SPEC_STRING (pspec)->default_value;
|
||||||
|
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget),
|
||||||
|
string ? string : "");
|
||||||
|
g_signal_connect (widget, "file-set",
|
||||||
|
G_CALLBACK (proxy_file_file_set_cb), object);
|
||||||
|
}
|
||||||
|
else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("folder"))
|
||||||
|
{
|
||||||
|
widget = gtk_file_chooser_button_new (_("Choose folder"),
|
||||||
|
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
|
||||||
|
g_object_get (object, property, &string, NULL);
|
||||||
|
if (!string)
|
||||||
|
string = G_PARAM_SPEC_STRING (pspec)->default_value;
|
||||||
|
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (widget),
|
||||||
|
string ? string : "");
|
||||||
|
g_signal_connect (widget, "file-set",
|
||||||
|
G_CALLBACK (proxy_folder_file_set_cb), object);
|
||||||
|
}
|
||||||
|
else if (type == G_TYPE_PARAM_STRING && _hint == g_intern_string ("uri"))
|
||||||
|
{
|
||||||
|
widget = gtk_file_chooser_button_new (_("Choose file"),
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN);
|
||||||
|
g_object_get (object, property, &string, NULL);
|
||||||
|
if (!string)
|
||||||
|
string = G_PARAM_SPEC_STRING (pspec)->default_value;
|
||||||
|
gtk_file_chooser_set_uri (GTK_FILE_CHOOSER (widget),
|
||||||
|
string ? string : "");
|
||||||
|
g_signal_connect (widget, "file-set",
|
||||||
|
G_CALLBACK (proxy_uri_file_set_cb), object);
|
||||||
|
}
|
||||||
|
else if (type == G_TYPE_PARAM_STRING)
|
||||||
|
{
|
||||||
|
widget = gtk_entry_new ();
|
||||||
|
g_object_get (object, property, &string, NULL);
|
||||||
|
if (!string)
|
||||||
|
string = G_PARAM_SPEC_STRING (pspec)->default_value;
|
||||||
|
gtk_entry_set_text (GTK_ENTRY (widget), string ? string : "");
|
||||||
|
g_signal_connect (widget, "focus-out-event",
|
||||||
|
G_CALLBACK (proxy_entry_focus_out_event_cb), object);
|
||||||
|
}
|
||||||
|
else if (type == G_TYPE_PARAM_INT)
|
||||||
|
{
|
||||||
|
widget = gtk_spin_button_new_with_range (
|
||||||
|
G_PARAM_SPEC_INT (pspec)->minimum,
|
||||||
|
G_PARAM_SPEC_INT (pspec)->maximum, 1);
|
||||||
|
gdouble value;
|
||||||
|
g_object_get (object, property, &value, NULL);
|
||||||
|
gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
|
||||||
|
g_signal_connect (widget, "changed",
|
||||||
|
G_CALLBACK (proxy_spin_button_changed_cb), object);
|
||||||
|
}
|
||||||
|
else if (type == G_TYPE_PARAM_ENUM)
|
||||||
|
{
|
||||||
|
GEnumClass* enum_class = G_ENUM_CLASS (
|
||||||
|
g_type_class_ref (pspec->value_type));
|
||||||
|
widget = gtk_combo_box_new_text ();
|
||||||
|
gint i = 0;
|
||||||
|
while (i < enum_class->n_values)
|
||||||
|
{
|
||||||
|
const gchar* label = enum_class->values[i].value_nick;
|
||||||
|
gtk_combo_box_append_text (GTK_COMBO_BOX (widget), label);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
gint value;
|
||||||
|
g_object_get (object, property, &value, NULL);
|
||||||
|
gtk_combo_box_set_active (GTK_COMBO_BOX (widget), value);
|
||||||
|
g_signal_connect (widget, "changed",
|
||||||
|
G_CALLBACK (proxy_combo_box_changed_cb), object);
|
||||||
|
g_type_class_unref (enum_class);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
widget = gtk_label_new (nick);
|
||||||
|
|
||||||
|
gtk_widget_set_sensitive (widget, pspec->flags & G_PARAM_WRITABLE);
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (widget), "property", (gchar*)property);
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* katze_property_label:
|
||||||
|
* @object: a #GObject
|
||||||
|
* @property: the name of a property
|
||||||
|
*
|
||||||
|
* Create a label widget displaying the name of the specified object's property.
|
||||||
|
*
|
||||||
|
* Return value: a new label widget
|
||||||
|
**/
|
||||||
|
GtkWidget*
|
||||||
|
katze_property_label (gpointer object,
|
||||||
|
const gchar* property)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
|
||||||
|
GObjectClass* class = G_OBJECT_GET_CLASS (object);
|
||||||
|
GParamSpec* pspec = g_object_class_find_property (class, property);
|
||||||
|
if (!pspec)
|
||||||
|
{
|
||||||
|
g_warning ("Property '%s' is invalid for %s",
|
||||||
|
property, G_OBJECT_CLASS_NAME (class));
|
||||||
|
return gtk_label_new (property);
|
||||||
|
}
|
||||||
|
const gchar* nick = g_param_spec_get_nick (pspec);
|
||||||
|
GtkWidget* widget = gtk_label_new (nick);
|
||||||
|
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
|
Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
#ifndef __KATZE_UTILS_H__
|
#ifndef __KATZE_UTILS_H__
|
||||||
#define __KATZE_UTILS_H__
|
#define __KATZE_UTILS_H__
|
||||||
|
|
||||||
#include <glib-object.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -45,6 +45,15 @@ G_BEGIN_DECLS
|
||||||
lvalue = rvalue; \
|
lvalue = rvalue; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GtkWidget*
|
||||||
|
katze_property_proxy (gpointer object,
|
||||||
|
const gchar* property,
|
||||||
|
const gchar* hint);
|
||||||
|
|
||||||
|
GtkWidget*
|
||||||
|
katze_property_label (gpointer object,
|
||||||
|
const gchar* property);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __KATZE_UTILS_H__ */
|
#endif /* __KATZE_UTILS_H__ */
|
||||||
|
|
Loading…
Reference in a new issue