summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Vogelgesang <matthias.vogelgesang@gmail.com>2012-07-04 10:49:26 +0200
committerMatthias Vogelgesang <matthias.vogelgesang@gmail.com>2012-07-04 10:49:26 +0200
commit39c6bb082696283e74ee72a2097749a4de1a418b (patch)
treec3b7e2cf8e9710d6eac6b330ff58adf4b28d1ee8
parentb67947751a24366137844cd1a3b41bed7095bf76 (diff)
downloaduca-39c6bb082696283e74ee72a2097749a4de1a418b.tar.gz
uca-39c6bb082696283e74ee72a2097749a4de1a418b.tar.bz2
uca-39c6bb082696283e74ee72a2097749a4de1a418b.tar.xz
uca-39c6bb082696283e74ee72a2097749a4de1a418b.zip
Add property tree view
The standard tree view widget is not capable of setting individual cell renderers per row. Thus I made one with a custom cell renderer that uses an appropriate cell renderer depending of the property type. I developed this independently and put it up on Github at https://github.com/matze/EggPropertyTreeView.
-rw-r--r--test/CMakeLists.txt5
-rw-r--r--test/control.c46
-rw-r--r--test/control.glade30
-rw-r--r--test/egg-property-cell-renderer.c502
-rw-r--r--test/egg-property-cell-renderer.h55
-rw-r--r--test/egg-property-tree-view.c114
-rw-r--r--test/egg-property-tree-view.h54
7 files changed, 740 insertions, 66 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 428a56a..224bd46 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -36,7 +36,10 @@ target_link_libraries(grab-async uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES})
if (GTK2_FOUND)
include_directories(${GTK2_INCLUDE_DIRS})
- add_executable(control control.c)
+ add_executable(control
+ control.c
+ egg-property-cell-renderer.c
+ egg-property-tree-view.c)
target_link_libraries(control uca
${GTK2_LIBRARIES} ${GTHREAD2_LIBRARIES})
endif()
diff --git a/test/control.c b/test/control.c
index d408d90..eb3cce5 100644
--- a/test/control.c
+++ b/test/control.c
@@ -23,7 +23,9 @@
#include <time.h>
#include <unistd.h>
#include <errno.h>
+
#include "uca-camera.h"
+#include "egg-property-tree-view.h"
typedef struct {
@@ -54,6 +56,7 @@ typedef struct {
enum {
COLUMN_NAME = 0,
COLUMN_VALUE,
+ COLUMN_EDITABLE,
NUM_COLUMNS
};
@@ -230,7 +233,7 @@ static void on_valuecell_edited(GtkCellRendererText *renderer, gchar *path, gcha
static void value_cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
gboolean editable;
- gtk_tree_model_get(model, iter, 2, &editable, -1);
+ gtk_tree_model_get(model, iter, COLUMN_EDITABLE, &editable, -1);
if (editable) {
g_object_set(cell,
@@ -249,40 +252,6 @@ static void value_cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *cel
}
}
-static void populate_property_list(GtkBuilder *builder, UcaCamera *camera)
-{
- GtkTreeViewColumn *value_column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "valuecolumn"));
- GtkCellRendererText *value_renderer = GTK_CELL_RENDERER_TEXT(gtk_builder_get_object(builder, "valuecell"));
- GtkListStore *list_store = GTK_LIST_STORE(gtk_builder_get_object(builder, "camera-properties"));
- GtkTreeIter iter;
-
- gtk_tree_view_column_set_cell_data_func(value_column, GTK_CELL_RENDERER(value_renderer), value_cell_data_func, NULL, NULL);
-
- GObjectClass *oclass = G_OBJECT_GET_CLASS(camera);
- guint num_specs = 0;
- GParamSpec **specs = g_object_class_list_properties(oclass, &num_specs);
- GValue dest_value = {0}, src_value = {0};
- g_value_init(&dest_value, G_TYPE_STRING);
-
- for (guint i = 0; i < num_specs; i++) {
- gtk_list_store_append(list_store, &iter);
- gtk_list_store_set(list_store, &iter, 0, specs[i]->name, -1);
-
- if (specs[i]->flags & G_PARAM_READABLE) {
- g_value_init(&src_value, specs[i]->value_type);
- g_object_get_property(G_OBJECT(camera), specs[i]->name, &src_value);
- if (g_value_transform(&src_value, &dest_value))
- gtk_list_store_set(list_store, &iter,
- 1, g_value_get_string(&dest_value),
- 2, specs[i]->flags & G_PARAM_WRITABLE,
- -1);
- g_value_unset(&src_value);
- }
- }
-
- g_free(specs);
-}
-
static void transform_string_to_boolean(const GValue *src_value, GValue *dest_value)
{
const gchar *str = g_value_get_string(src_value);
@@ -355,11 +324,16 @@ static void create_main_window(GtkBuilder *builder, const gchar* camera_name)
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
GtkWidget *image = GTK_WIDGET(gtk_builder_get_object(builder, "image"));
+ GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera));
+ GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2"));
+
+ gtk_container_add (scrolled_property_window, property_tree_view);
+ gtk_widget_show_all (GTK_WIDGET (scrolled_property_window));
+
GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height);
gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
register_transform_funcs();
- populate_property_list(builder, camera);
td.pixel_size = bits_per_sample == 16 ? 2 : 1;
td.image = image;
diff --git a/test/control.glade b/test/control.glade
index 36ed0ce..d70a343 100644
--- a/test/control.glade
+++ b/test/control.glade
@@ -196,35 +196,7 @@
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkTreeView" id="treeview-properties">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="model">camera-properties</property>
- <property name="headers_clickable">False</property>
- <property name="search_column">0</property>
- <child>
- <object class="GtkTreeViewColumn" id="namecolumn">
- <property name="title">Name</property>
- <child>
- <object class="GtkCellRendererText" id="namecell"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="valuecolumn">
- <property name="title">Value</property>
- <child>
- <object class="GtkCellRendererText" id="valuecell"/>
- <attributes>
- <attribute name="text">1</attribute>
- </attributes>
- </child>
- </object>
- </child>
- </object>
+ <placeholder/>
</child>
</object>
<packing>
diff --git a/test/egg-property-cell-renderer.c b/test/egg-property-cell-renderer.c
new file mode 100644
index 0000000..d6cc5d5
--- /dev/null
+++ b/test/egg-property-cell-renderer.c
@@ -0,0 +1,502 @@
+/* Copyright (C) 2011, 2012 Matthias Vogelgesang <matthias.vogelgesang@kit.edu>
+ (Karlsruhe Institute of Technology)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 51
+ Franklin St, Fifth Floor, Boston, MA 02110, USA */
+
+#include <stdlib.h>
+#include "egg-property-cell-renderer.h"
+
+G_DEFINE_TYPE (EggPropertyCellRenderer, egg_property_cell_renderer, GTK_TYPE_CELL_RENDERER)
+
+#define EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererPrivate))
+
+
+struct _EggPropertyCellRendererPrivate
+{
+ GObject *object;
+ GtkListStore *list_store;
+ GtkCellRenderer *renderer;
+ GtkCellRenderer *text_renderer;
+ GtkCellRenderer *spin_renderer;
+ GtkCellRenderer *toggle_renderer;
+};
+
+enum
+{
+ PROP_0,
+ PROP_PROP_NAME,
+ N_PROPERTIES
+};
+
+static GParamSpec *egg_property_cell_renderer_properties[N_PROPERTIES] = { NULL, };
+
+GtkCellRenderer *
+egg_property_cell_renderer_new (GObject *object,
+ GtkListStore *list_store)
+{
+ EggPropertyCellRenderer *renderer;
+
+ renderer = EGG_PROPERTY_CELL_RENDERER (g_object_new (EGG_TYPE_PROPERTY_CELL_RENDERER, NULL));
+ renderer->priv->object = object;
+ renderer->priv->list_store = list_store;
+ return GTK_CELL_RENDERER (renderer);
+}
+
+static GParamSpec *
+get_pspec_from_object (GObject *object, const gchar *prop_name)
+{
+ GObjectClass *oclass = G_OBJECT_GET_CLASS (object);
+ return g_object_class_find_property (oclass, prop_name);
+}
+
+static void
+get_string_double_repr (GObject *object, const gchar *prop_name, gchar **text, gdouble *number)
+{
+ GParamSpec *pspec;
+ GValue from = { 0 };
+ GValue to_string = { 0 };
+ GValue to_double = { 0 };
+
+ pspec = get_pspec_from_object (object, prop_name);
+ g_value_init (&from, pspec->value_type);
+ g_value_init (&to_string, G_TYPE_STRING);
+ g_value_init (&to_double, G_TYPE_DOUBLE);
+ g_object_get_property (object, prop_name, &from);
+
+ if (g_value_transform (&from, &to_string))
+ *text = g_strdup (g_value_get_string (&to_string));
+ else
+ g_warning ("Could not convert from %s gchar*\n", g_type_name (pspec->value_type));
+
+ if (g_value_transform (&from, &to_double))
+ *number = g_value_get_double (&to_double);
+ else
+ g_warning ("Could not convert from %s to gdouble\n", g_type_name (pspec->value_type));
+}
+
+static void
+clear_adjustment (GObject *object)
+{
+ GtkAdjustment *adjustment;
+
+ g_object_get (object,
+ "adjustment", &adjustment,
+ NULL);
+
+ if (adjustment)
+ g_object_unref (adjustment);
+
+ g_object_set (object,
+ "adjustment", NULL,
+ NULL);
+}
+
+static void
+egg_property_cell_renderer_set_renderer (EggPropertyCellRenderer *renderer,
+ const gchar *prop_name)
+{
+ EggPropertyCellRendererPrivate *priv;
+ GParamSpec *pspec;
+ gchar *text = NULL;
+ gdouble number;
+ gboolean change_adjustment = FALSE;
+
+ priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (renderer);
+ pspec = get_pspec_from_object (priv->object, prop_name);
+
+ /*
+ * Set this renderers mode, so that any actions can be forwarded to our
+ * child renderers.
+ */
+ switch (pspec->value_type) {
+ /* toggle renderers */
+ case G_TYPE_BOOLEAN:
+ priv->renderer = priv->toggle_renderer;
+ g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
+ break;
+
+ /* spin renderers */
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE:
+ priv->renderer = priv->spin_renderer;
+ g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL);
+ g_object_set (priv->renderer, "digits", 5, NULL);
+ change_adjustment = TRUE;
+ break;
+
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ case G_TYPE_LONG:
+ case G_TYPE_ULONG:
+ case G_TYPE_INT64:
+ case G_TYPE_UINT64:
+ priv->renderer = priv->spin_renderer;
+ g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL);
+ g_object_set (priv->renderer, "digits", 0, NULL);
+ change_adjustment = TRUE;
+ break;
+
+ /* text renderers */
+ case G_TYPE_POINTER:
+ case G_TYPE_STRING:
+ priv->renderer = priv->text_renderer;
+ g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL);
+ break;
+
+ /* combo renderers */
+ default:
+ /* g_print ("no idea how to handle %s -> %s\n", prop_name, g_type_name (pspec->value_type)); */
+ break;
+ }
+
+ /*
+ * Set the content from the objects property.
+ */
+ switch (pspec->value_type) {
+ case G_TYPE_BOOLEAN:
+ {
+ gboolean val;
+
+ g_object_get (priv->object, prop_name, &val, NULL);
+ g_object_set (priv->renderer,
+ "active", val,
+ "activatable", pspec->flags & G_PARAM_WRITABLE ? TRUE : FALSE,
+ NULL);
+ break;
+ }
+
+ case G_TYPE_INT:
+ case G_TYPE_UINT:
+ case G_TYPE_LONG:
+ case G_TYPE_ULONG:
+ case G_TYPE_INT64:
+ case G_TYPE_UINT64:
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE:
+ get_string_double_repr (priv->object, prop_name, &text, &number);
+ break;
+
+ case G_TYPE_STRING:
+ g_object_get (priv->object, prop_name, &text, NULL);
+ break;
+
+ case G_TYPE_POINTER:
+ {
+ gpointer val;
+
+ g_object_get (priv->object, prop_name, &val, NULL);
+ text = g_strdup_printf ("0x%x", GPOINTER_TO_INT (val));
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (pspec->flags & G_PARAM_WRITABLE) {
+ if (GTK_IS_CELL_RENDERER_TOGGLE (priv->renderer))
+ g_object_set (priv->renderer, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
+ else
+ g_object_set (priv->renderer, "foreground", "#000000", NULL);
+
+ if (GTK_IS_CELL_RENDERER_TEXT (priv->renderer)) {
+ g_object_set (priv->renderer,
+ "editable", TRUE,
+ "mode", GTK_CELL_RENDERER_MODE_EDITABLE,
+ NULL);
+ }
+
+ if (GTK_IS_CELL_RENDERER_SPIN (priv->renderer)) {
+ GtkObject *adjustment = NULL;
+
+#define gtk_typed_adjustment_new(type, pspec, val, step_inc, page_inc) \
+ gtk_adjustment_new (val, ((type *) pspec)->minimum, ((type *) pspec)->maximum, step_inc, page_inc, 0)
+
+ switch (pspec->value_type) {
+ case G_TYPE_INT:
+ adjustment = gtk_typed_adjustment_new (GParamSpecInt, pspec, number, 1, 10);
+ break;
+ case G_TYPE_UINT:
+ adjustment = gtk_typed_adjustment_new (GParamSpecUInt, pspec, number, 1, 10);
+ break;
+ case G_TYPE_LONG:
+ adjustment = gtk_typed_adjustment_new (GParamSpecLong, pspec, number, 1, 10);
+ break;
+ case G_TYPE_ULONG:
+ adjustment = gtk_typed_adjustment_new (GParamSpecULong, pspec, number, 1, 10);
+ break;
+ case G_TYPE_INT64:
+ adjustment = gtk_typed_adjustment_new (GParamSpecInt64, pspec, number, 1, 10);
+ break;
+ case G_TYPE_UINT64:
+ adjustment = gtk_typed_adjustment_new (GParamSpecUInt64, pspec, number, 1, 10);
+ break;
+ case G_TYPE_FLOAT:
+ adjustment = gtk_typed_adjustment_new (GParamSpecFloat, pspec, number, 0.05, 10);
+ break;
+ case G_TYPE_DOUBLE:
+ adjustment = gtk_typed_adjustment_new (GParamSpecDouble, pspec, number, 0.05, 10);
+ break;
+ }
+
+ clear_adjustment (G_OBJECT (priv->renderer));
+ g_object_set (priv->renderer, "adjustment", adjustment, NULL);
+ }
+ }
+ else {
+ g_object_set (priv->renderer, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
+
+ if (!GTK_IS_CELL_RENDERER_TOGGLE (priv->renderer))
+ g_object_set (priv->renderer, "foreground", "#aaaaaa", NULL);
+ }
+
+ if (text != NULL) {
+ g_object_set (priv->renderer, "text", text, NULL);
+ g_free (text);
+ }
+}
+
+static gchar *
+get_prop_name_from_tree_model (GtkTreeModel *model, const gchar *path)
+{
+ GtkTreeIter iter;
+ gchar *prop_name = NULL;
+
+ /* TODO: don't assume column 0 to contain the prop name */
+ if (gtk_tree_model_get_iter_from_string (model, &iter, path))
+ gtk_tree_model_get (model, &iter, 0, &prop_name, -1);
+
+ return prop_name;
+}
+
+static void
+egg_property_cell_renderer_toggle_cb (GtkCellRendererToggle *renderer,
+ gchar *path,
+ gpointer user_data)
+{
+ EggPropertyCellRendererPrivate *priv;
+ gchar *prop_name;
+
+ priv = (EggPropertyCellRendererPrivate *) user_data;
+ prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path);
+
+ if (prop_name != NULL) {
+ gboolean activated;
+
+ g_object_get (priv->object, prop_name, &activated, NULL);
+ g_object_set (priv->object, prop_name, !activated, NULL);
+ g_free (prop_name);
+ }
+}
+
+static void
+egg_property_cell_renderer_text_edited_cb (GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ gpointer user_data)
+{
+ EggPropertyCellRendererPrivate *priv;
+ gchar *prop_name;
+
+ priv = (EggPropertyCellRendererPrivate *) user_data;
+ prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path);
+
+ if (prop_name != NULL) {
+ g_object_set (priv->object, prop_name, new_text, NULL);
+ g_free (prop_name);
+ }
+}
+
+static void
+egg_property_cell_renderer_spin_edited_cb (GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ gpointer user_data)
+{
+ EggPropertyCellRendererPrivate *priv;
+ gchar *prop_name;
+
+ priv = (EggPropertyCellRendererPrivate *) user_data;
+ prop_name = get_prop_name_from_tree_model (GTK_TREE_MODEL (priv->list_store), path);
+
+ if (prop_name != NULL) {
+ GParamSpec *pspec;
+ GValue from = { 0 };
+ GValue to = { 0 };
+
+ pspec = get_pspec_from_object (priv->object, prop_name);
+
+ g_value_init (&from, G_TYPE_DOUBLE);
+ g_value_init (&to, pspec->value_type);
+ g_value_set_double (&from, strtod (new_text, NULL));
+
+ if (g_value_transform (&from, &to))
+ g_object_set_property (priv->object, prop_name, &to);
+ else
+ g_warning ("Could not transform %s to %s\n",
+ g_value_get_string (&from), g_type_name (pspec->value_type));
+
+ g_free (prop_name);
+ }
+}
+
+static void
+egg_property_cell_renderer_get_size (GtkCellRenderer *cell,
+ GtkWidget *widget,
+ GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+
+ EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell);
+
+ gtk_cell_renderer_get_size (priv->renderer, widget, cell_area, x_offset, y_offset, width, height);
+}
+
+static void
+egg_property_cell_renderer_render (GtkCellRenderer *cell,
+ GdkDrawable *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+{
+ EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell);
+ gtk_cell_renderer_render (priv->renderer, window, widget, background_area, cell_area, expose_area, flags);
+}
+
+static gboolean
+egg_property_cell_renderer_activate (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags)
+{
+ EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell);
+ return gtk_cell_renderer_activate (priv->renderer, event, widget, path, background_area, cell_area, flags);
+}
+
+static GtkCellEditable *
+egg_property_cell_renderer_start_editing (GtkCellRenderer *cell,
+ GdkEvent *event,
+ GtkWidget *widget,
+ const gchar *path,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GtkCellRendererState flags)
+{
+ EggPropertyCellRendererPrivate *priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (cell);
+ return gtk_cell_renderer_start_editing (priv->renderer, event, widget, path, background_area, cell_area, flags);
+}
+
+static void
+egg_property_cell_renderer_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ g_return_if_fail (EGG_IS_PROPERTY_CELL_RENDERER (object));
+ EggPropertyCellRenderer *renderer = EGG_PROPERTY_CELL_RENDERER (object);
+
+ switch (property_id) {
+ case PROP_PROP_NAME:
+ egg_property_cell_renderer_set_renderer (renderer, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ return;
+ }
+}
+
+static void
+egg_property_cell_renderer_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ g_return_if_fail (EGG_IS_PROPERTY_CELL_RENDERER (object));
+
+ switch (property_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ return;
+ }
+}
+
+static void
+egg_property_cell_renderer_class_init (EggPropertyCellRendererClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GtkCellRendererClass *cellrenderer_class = GTK_CELL_RENDERER_CLASS (klass);
+
+ gobject_class->set_property = egg_property_cell_renderer_set_property;
+ gobject_class->get_property = egg_property_cell_renderer_get_property;
+
+ cellrenderer_class->render = egg_property_cell_renderer_render;
+ cellrenderer_class->get_size = egg_property_cell_renderer_get_size;
+ cellrenderer_class->activate = egg_property_cell_renderer_activate;
+ cellrenderer_class->start_editing = egg_property_cell_renderer_start_editing;
+
+ egg_property_cell_renderer_properties[PROP_PROP_NAME] =
+ g_param_spec_string("prop-name",
+ "Property name", "Property name", "",
+ G_PARAM_READWRITE);
+
+ g_object_class_install_property(gobject_class, PROP_PROP_NAME, egg_property_cell_renderer_properties[PROP_PROP_NAME]);
+
+ g_type_class_add_private (klass, sizeof (EggPropertyCellRendererPrivate));
+}
+
+static void
+egg_property_cell_renderer_init (EggPropertyCellRenderer *renderer)
+{
+ EggPropertyCellRendererPrivate *priv;
+
+ renderer->priv = priv = EGG_PROPERTY_CELL_RENDERER_GET_PRIVATE (renderer);
+
+ priv->text_renderer = gtk_cell_renderer_text_new ();
+ priv->spin_renderer = gtk_cell_renderer_spin_new ();
+ priv->toggle_renderer = gtk_cell_renderer_toggle_new ();
+ priv->renderer = priv->text_renderer;
+
+ g_object_set (priv->text_renderer,
+ "editable", TRUE,
+ NULL);
+
+ g_object_set (priv->spin_renderer,
+ "editable", TRUE,
+ NULL);
+
+ g_object_set (priv->toggle_renderer,
+ "xalign", 0.0f,
+ "activatable", TRUE,
+ "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
+ NULL);
+
+ g_signal_connect (priv->spin_renderer, "edited",
+ G_CALLBACK (egg_property_cell_renderer_spin_edited_cb), priv);
+
+ g_signal_connect (priv->text_renderer, "edited",
+ G_CALLBACK (egg_property_cell_renderer_text_edited_cb), NULL);
+
+ g_signal_connect (priv->toggle_renderer, "toggled",
+ G_CALLBACK (egg_property_cell_renderer_toggle_cb), priv);
+}
diff --git a/test/egg-property-cell-renderer.h b/test/egg-property-cell-renderer.h
new file mode 100644
index 0000000..d4dbe02
--- /dev/null
+++ b/test/egg-property-cell-renderer.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2011, 2012 Matthias Vogelgesang <matthias.vogelgesang@kit.edu>
+ (Karlsruhe Institute of Technology)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 51
+ Franklin St, Fifth Floor, Boston, MA 02110, USA */
+
+#ifndef EGG_PROPERTY_CELL_RENDERER_H
+#define EGG_PROPERTY_CELL_RENDERER_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_PROPERTY_CELL_RENDERER (egg_property_cell_renderer_get_type())
+#define EGG_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRenderer))
+#define EGG_IS_PROPERTY_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_PROPERTY_CELL_RENDERER))
+#define EGG_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererClass))
+#define EGG_IS_PROPERTY_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_PROPERTY_CELL_RENDERER))
+#define EGG_PROPERTY_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_PROPERTY_CELL_RENDERER, EggPropertyCellRendererClass))
+
+typedef struct _EggPropertyCellRenderer EggPropertyCellRenderer;
+typedef struct _EggPropertyCellRendererClass EggPropertyCellRendererClass;
+typedef struct _EggPropertyCellRendererPrivate EggPropertyCellRendererPrivate;
+
+struct _EggPropertyCellRenderer
+{
+ GtkCellRenderer parent_instance;
+
+ /*< private >*/
+ EggPropertyCellRendererPrivate *priv;
+};
+
+struct _EggPropertyCellRendererClass
+{
+ GtkCellRendererClass parent_class;
+};
+
+GType egg_property_cell_renderer_get_type (void);
+GtkCellRenderer* egg_property_cell_renderer_new (GObject *object,
+ GtkListStore *list_store);
+
+G_END_DECLS
+
+#endif
diff --git a/test/egg-property-tree-view.c b/test/egg-property-tree-view.c
new file mode 100644
index 0000000..f4ed2fb
--- /dev/null
+++ b/test/egg-property-tree-view.c
@@ -0,0 +1,114 @@
+/* Copyright (C) 2011, 2012 Matthias Vogelgesang <matthias.vogelgesang@kit.edu>
+ (Karlsruhe Institute of Technology)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 51
+ Franklin St, Fifth Floor, Boston, MA 02110, USA */
+
+
+#include "egg-property-tree-view.h"
+#include "egg-property-cell-renderer.h"
+
+G_DEFINE_TYPE (EggPropertyTreeView, egg_property_tree_view, GTK_TYPE_TREE_VIEW)
+
+#define EGG_PROPERTY_TREE_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewPrivate))
+
+struct _EggPropertyTreeViewPrivate
+{
+ GtkListStore *list_store;
+};
+
+enum
+{
+ COLUMN_PROP_NAME,
+ COLUMN_PROP_ROW,
+ COLUMN_PROP_ADJUSTMENT,
+ N_COLUMNS
+};
+
+static void
+egg_property_tree_view_populate_model_with_properties (GtkListStore *model, GObject *object)
+{
+ GParamSpec **pspecs;
+ GObjectClass *oclass;
+ guint n_properties;
+ GtkTreeIter iter;
+
+ oclass = G_OBJECT_GET_CLASS (object);
+ pspecs = g_object_class_list_properties (oclass, &n_properties);
+
+ for (guint i = 0; i < n_properties; i++) {
+ if (pspecs[i]->flags & G_PARAM_READABLE) {
+ GtkObject *adjustment;
+
+ adjustment = gtk_adjustment_new (5, 0, 1000, 1, 10, 0);
+
+ gtk_list_store_append (model, &iter);
+ gtk_list_store_set (model, &iter,
+ COLUMN_PROP_NAME, pspecs[i]->name,
+ COLUMN_PROP_ROW, FALSE,
+ COLUMN_PROP_ADJUSTMENT, adjustment,
+ -1);
+ }
+ }
+
+ g_free (pspecs);
+}
+
+GtkWidget *
+egg_property_tree_view_new (GObject *object)
+{
+ EggPropertyTreeView *property_tree_view;
+ GtkTreeView *tree_view;
+ GtkTreeViewColumn *prop_column, *value_column;
+ GtkCellRenderer *prop_renderer, *value_renderer;
+ GtkListStore *list_store;
+
+ property_tree_view = EGG_PROPERTY_TREE_VIEW (g_object_new (EGG_TYPE_PROPERTY_TREE_VIEW, NULL));
+ list_store = property_tree_view->priv->list_store;
+ tree_view = GTK_TREE_VIEW (property_tree_view);
+
+ egg_property_tree_view_populate_model_with_properties (list_store, object);
+ gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store));
+
+ prop_renderer = gtk_cell_renderer_text_new ();
+ prop_column = gtk_tree_view_column_new_with_attributes ("Property", prop_renderer,
+ "text", COLUMN_PROP_NAME,
+ NULL);
+
+ value_renderer = egg_property_cell_renderer_new (object, list_store);
+ value_column = gtk_tree_view_column_new_with_attributes ("Value", value_renderer,
+ "prop-name", COLUMN_PROP_NAME,
+ NULL);
+
+ gtk_tree_view_append_column (tree_view, prop_column);
+ gtk_tree_view_append_column (tree_view, value_column);
+
+ return GTK_WIDGET (tree_view);
+}
+
+static void
+egg_property_tree_view_class_init (EggPropertyTreeViewClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (EggPropertyTreeViewPrivate));
+}
+
+static void
+egg_property_tree_view_init (EggPropertyTreeView *tree_view)
+{
+ EggPropertyTreeViewPrivate *priv = EGG_PROPERTY_TREE_VIEW_GET_PRIVATE (tree_view);
+
+ tree_view->priv = priv = EGG_PROPERTY_TREE_VIEW_GET_PRIVATE (tree_view);
+ priv->list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, GTK_TYPE_ADJUSTMENT);
+}
+
diff --git a/test/egg-property-tree-view.h b/test/egg-property-tree-view.h
new file mode 100644
index 0000000..e8fd0fe
--- /dev/null
+++ b/test/egg-property-tree-view.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2011, 2012 Matthias Vogelgesang <matthias.vogelgesang@kit.edu>
+ (Karlsruhe Institute of Technology)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by the
+ Free Software Foundation; either version 2.1 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along
+ with this library; if not, write to the Free Software Foundation, Inc., 51
+ Franklin St, Fifth Floor, Boston, MA 02110, USA */
+
+#ifndef EGG_PROPERTY_TREE_VIEW_H
+#define EGG_PROPERTY_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_PROPERTY_TREE_VIEW (egg_property_tree_view_get_type())
+#define EGG_PROPERTY_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeView))
+#define EGG_IS_PROPERTY_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_PROPERTY_TREE_VIEW))
+#define EGG_PROPERTY_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewClass))
+#define EGG_IS_PROPERTY_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_PROPERTY_TREE_VIEW))
+#define EGG_PROPERTY_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_PROPERTY_TREE_VIEW, EggPropertyTreeViewClass))
+
+typedef struct _EggPropertyTreeView EggPropertyTreeView;
+typedef struct _EggPropertyTreeViewClass EggPropertyTreeViewClass;
+typedef struct _EggPropertyTreeViewPrivate EggPropertyTreeViewPrivate;
+
+struct _EggPropertyTreeView
+{
+ GtkTreeView parent_instance;
+
+ /*< private >*/
+ EggPropertyTreeViewPrivate *priv;
+};
+
+struct _EggPropertyTreeViewClass
+{
+ GtkTreeViewClass parent_class;
+};
+
+GType egg_property_tree_view_get_type (void) G_GNUC_CONST;
+GtkWidget* egg_property_tree_view_new (GObject *object);
+
+G_END_DECLS
+
+#endif