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:
Christian Dywan 2008-04-13 21:21:39 +02:00
parent f11b76b6ef
commit a9eb81a016
2 changed files with 246 additions and 3 deletions

View File

@ -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
modify it under the terms of the GNU Lesser General Public
@ -10,3 +10,237 @@
*/
#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;
}

View File

@ -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
modify it under the terms of the GNU Lesser General Public
@ -12,7 +12,7 @@
#ifndef __KATZE_UTILS_H__
#define __KATZE_UTILS_H__
#include <glib-object.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
@ -45,6 +45,15 @@ G_BEGIN_DECLS
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
#endif /* __KATZE_UTILS_H__ */