summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Vogelgesang <matthias.vogelgesang@gmail.com>2012-04-16 17:00:00 +0200
committerMatthias Vogelgesang <matthias.vogelgesang@gmail.com>2012-04-16 17:00:00 +0200
commit0b5838e40bed5b175f7703b788eae361e2ca8177 (patch)
treeac3ad5e3c143de0c1c2d7148eba80b5d3eb6d1ab
parent3ffc19bbe6a399654e642ed7941cb81ed23f6920 (diff)
downloadlibuca-0b5838e40bed5b175f7703b788eae361e2ca8177.tar.gz
libuca-0b5838e40bed5b175f7703b788eae361e2ca8177.tar.bz2
libuca-0b5838e40bed5b175f7703b788eae361e2ca8177.tar.xz
libuca-0b5838e40bed5b175f7703b788eae361e2ca8177.zip
Implement property editing
-rw-r--r--test/control.c162
-rw-r--r--test/control.glade68
2 files changed, 168 insertions, 62 deletions
diff --git a/test/control.c b/test/control.c
index 0614071..a5a4e22 100644
--- a/test/control.c
+++ b/test/control.c
@@ -18,9 +18,11 @@
#include <glib/gprintf.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <errno.h>
#include "uca-camera.h"
@@ -31,6 +33,7 @@ typedef struct {
guchar *buffer, *pixels;
GdkPixbuf *pixbuf;
GtkWidget *image;
+ GtkTreeModel *property_model;
UcaCamera *camera;
GtkStatusbar *statusbar;
@@ -51,8 +54,6 @@ typedef struct {
enum {
COLUMN_NAME = 0,
COLUMN_VALUE,
- COLUMN_UNIT,
- COLUMN_UCA_ID,
NUM_COLUMNS
};
@@ -145,7 +146,7 @@ void on_adjustment_scale_value_changed(GtkAdjustment* adjustment, gpointer user_
data->scale = gtk_adjustment_get_value(adjustment);
}
-void on_toolbutton_run_clicked(GtkWidget *widget, gpointer args)
+static void on_toolbutton_run_clicked(GtkWidget *widget, gpointer args)
{
ThreadData *data = (ThreadData *) args;
@@ -168,7 +169,7 @@ void on_toolbutton_run_clicked(GtkWidget *widget, gpointer args)
}
}
-void on_toolbutton_stop_clicked(GtkWidget *widget, gpointer args)
+static void on_toolbutton_stop_clicked(GtkWidget *widget, gpointer args)
{
ThreadData *data = (ThreadData *) args;
data->running = FALSE;
@@ -176,7 +177,7 @@ void on_toolbutton_stop_clicked(GtkWidget *widget, gpointer args)
uca_camera_stop_recording(data->camera, NULL);
}
-void on_toolbutton_record_clicked(GtkWidget *widget, gpointer args)
+static void on_toolbutton_record_clicked(GtkWidget *widget, gpointer args)
{
ThreadData *data = (ThreadData *) args;
data->timestamp = (int) time(0);
@@ -187,7 +188,7 @@ void on_toolbutton_record_clicked(GtkWidget *widget, gpointer args)
if (data->running != TRUE) {
data->running = TRUE;
- uca_camera_start_recording(data->cam, &error);
+ uca_camera_start_recording(data->camera, &error);
if (!g_thread_create(grab_thread, data, FALSE, &error)) {
g_printerr("Failed to create thread: %s\n", error->message);
@@ -195,6 +196,142 @@ void on_toolbutton_record_clicked(GtkWidget *widget, gpointer args)
}
}
+static void on_valuecell_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data)
+{
+ ThreadData *td = (ThreadData *) data;
+ GtkTreePath *tree_path = gtk_tree_path_new_from_string(path);
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter(td->property_model, &iter, tree_path)) {
+ gchar *propname;
+ GValue dest_value = {0}, src_value = {0};
+ g_value_init(&src_value, G_TYPE_STRING);
+ g_value_set_string(&src_value, new_text);
+
+ gtk_tree_model_get(td->property_model, &iter, COLUMN_NAME, &propname, -1);
+
+ GParamSpec *spec = g_object_class_find_property(G_OBJECT_GET_CLASS(td->camera), propname);
+ g_value_init(&dest_value, spec->value_type);
+ errno = 0;
+
+ if (g_value_transform(&src_value, &dest_value) && (errno != EINVAL)) {
+ g_object_set_property(G_OBJECT(td->camera), propname, &dest_value);
+ g_object_get_property(G_OBJECT(td->camera), propname, &src_value);
+ gtk_list_store_set(GTK_LIST_STORE(td->property_model), &iter, COLUMN_VALUE, g_value_get_string(&src_value), -1);
+ }
+ else
+ g_print("Couldn't transform %s\n", g_value_get_string(&src_value));
+ }
+}
+
+static void value_cell_data_func(GtkTreeViewColumn *column, GtkCellRenderer *cell, GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+ UcaCamera *camera = UCA_CAMERA(data);
+ gchar *propname;
+ gtk_tree_model_get(model, iter, COLUMN_NAME, &propname, -1);
+ GParamSpec *spec = g_object_class_find_property(G_OBJECT_GET_CLASS(camera), propname);
+
+ if (spec->flags & G_PARAM_WRITABLE) {
+ g_object_set(cell,
+ "mode", GTK_CELL_RENDERER_MODE_EDITABLE,
+ "editable", TRUE,
+ "style", PANGO_STYLE_NORMAL,
+ "foreground", "#000000",
+ NULL);
+ }
+ else {
+ g_object_set(cell,
+ "mode", GTK_CELL_RENDERER_MODE_INERT,
+ "editable", FALSE,
+ "foreground", "#aaaaaa",
+ NULL);
+ }
+
+ g_free(propname);
+}
+
+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, camera, 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), -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);
+
+ if (g_ascii_strncasecmp(str, "TRUE", 4) == 0)
+ g_value_set_boolean(dest_value, TRUE);
+ else if (g_ascii_strncasecmp(str, "FALSE", 4) == 0)
+ g_value_set_boolean(dest_value, FALSE);
+}
+
+static void transform_string_to_uint(const GValue *src_value, GValue *dest_value)
+{
+ const gchar *str = g_value_get_string(src_value);
+ gchar *endptr = NULL;
+ guint64 result = g_ascii_strtoull(str, &endptr, 10);
+ if (endptr != str)
+ g_value_set_uint(dest_value, result);
+ else
+ errno = EINVAL;
+}
+
+static void transform_string_to_double(const GValue *src_value, GValue *dest_value)
+{
+ const gchar *str = g_value_get_string(src_value);
+ gchar *endptr = NULL;
+ gdouble result = g_ascii_strtod(str, &endptr);
+ if (endptr != str)
+ g_value_set_double(dest_value, result);
+ else
+ errno = EINVAL;
+}
+
+static void transform_string_to_float(const GValue *src_value, GValue *dest_value)
+{
+ const gchar *str = g_value_get_string(src_value);
+ gchar *endptr = NULL;
+ gdouble result = g_ascii_strtod(str, &endptr);
+ if (endptr != str)
+ g_value_set_float(dest_value, (gfloat) result);
+ else
+ errno = EINVAL;
+}
+
+static void register_transform_funcs(void)
+{
+ g_value_register_transform_func(G_TYPE_STRING, G_TYPE_BOOLEAN, &transform_string_to_boolean);
+ g_value_register_transform_func(G_TYPE_STRING, G_TYPE_UINT, &transform_string_to_uint);
+ g_value_register_transform_func(G_TYPE_STRING, G_TYPE_DOUBLE, &transform_string_to_double);
+ g_value_register_transform_func(G_TYPE_STRING, G_TYPE_FLOAT, &transform_string_to_float);
+}
+
static void create_main_window(GtkBuilder *builder, const gchar* camera_name)
{
static ThreadData td;
@@ -219,6 +356,9 @@ static void create_main_window(GtkBuilder *builder, const gchar* camera_name)
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;
td.pixbuf = pixbuf;
@@ -230,6 +370,7 @@ static void create_main_window(GtkBuilder *builder, const gchar* camera_name)
td.statusbar_context_id = gtk_statusbar_get_context_id(td.statusbar, "Recording Information");
td.store = FALSE;
td.camera = camera;
+ td.property_model = GTK_TREE_MODEL(gtk_builder_get_object(builder, "camera-properties"));
g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), &td);
g_signal_connect(gtk_builder_get_object(builder, "toolbutton_run"),
@@ -238,6 +379,8 @@ static void create_main_window(GtkBuilder *builder, const gchar* camera_name)
"clicked", G_CALLBACK(on_toolbutton_stop_clicked), &td);
g_signal_connect(gtk_builder_get_object(builder, "toolbutton_record"),
"clicked", G_CALLBACK(on_toolbutton_record_clicked), &td);
+ g_signal_connect(gtk_builder_get_object(builder, "valuecell"),
+ "edited", G_CALLBACK(on_valuecell_edited), &td);
gtk_widget_show(image);
gtk_widget_show(window);
@@ -268,6 +411,12 @@ static void on_button_proceed_clicked(GtkWidget *widget, gpointer data)
g_list_free(selected_rows);
}
+static void on_treeview_keypress(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+ if (event->keyval == GDK_KEY_Return)
+ gtk_widget_grab_focus(GTK_WIDGET(data));
+}
+
static void create_choice_window(GtkBuilder *builder)
{
gchar **camera_types = uca_camera_get_types();
@@ -293,6 +442,7 @@ static void create_choice_window(GtkBuilder *builder)
g_strfreev(camera_types);
g_signal_connect(proceed_button, "clicked", G_CALLBACK(on_button_proceed_clicked), builder);
+ g_signal_connect(treeview, "key-press-event", G_CALLBACK(on_treeview_keypress), proceed_button);
gtk_widget_show_all(GTK_WIDGET(choice_window));
}
diff --git a/test/control.glade b/test/control.glade
index eeeeaaf..bee9323 100644
--- a/test/control.glade
+++ b/test/control.glade
@@ -2,28 +2,24 @@
<interface>
<requires lib="gtk+" version="2.20"/>
<!-- interface-naming-policy project-wide -->
- <object class="GtkTreeStore" id="cameraproperties">
+ <object class="GtkListStore" id="camera-types">
<columns>
- <!-- column-name PropertyName -->
- <column type="gchararray"/>
- <!-- column-name PropertyValue -->
- <column type="gchararray"/>
- <!-- column-name PropertyUnit -->
+ <!-- column-name name -->
<column type="gchararray"/>
- <!-- column-name PropertyUCA -->
- <column type="guint"/>
</columns>
</object>
- <object class="GtkListStore" id="camera-types">
+ <object class="GtkListStore" id="camera-properties">
<columns>
- <!-- column-name name -->
+ <!-- column-name PropertyName -->
+ <column type="gchararray"/>
+ <!-- column-name PropertyValue -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkWindow" id="window">
<property name="title" translatable="yes">Camera Control</property>
- <property name="default_width">800</property>
- <property name="default_height">600</property>
+ <property name="default_width">1024</property>
+ <property name="default_height">768</property>
<signal name="delete_event" handler="on_delete_event"/>
<child>
<object class="GtkVBox" id="vbox1">
@@ -198,10 +194,10 @@
<property name="hscrollbar_policy">automatic</property>
<property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkTreeView" id="treeview">
+ <object class="GtkTreeView" id="treeview-properties">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="model">cameraproperties</property>
+ <property name="model">camera-properties</property>
<property name="headers_clickable">False</property>
<property name="search_column">0</property>
<child>
@@ -226,17 +222,6 @@
</child>
</object>
</child>
- <child>
- <object class="GtkTreeViewColumn" id="unitcolumn">
- <property name="title">Unit</property>
- <child>
- <object class="GtkCellRendererText" id="unitcell"/>
- <attributes>
- <attribute name="text">2</attribute>
- </attributes>
- </child>
- </object>
- </child>
</object>
</child>
</object>
@@ -314,6 +299,7 @@
<property name="page_increment">10</property>
</object>
<object class="GtkWindow" id="choice-window">
+ <property name="border_width">6</property>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
@@ -325,7 +311,7 @@
<property name="model">camera-types</property>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
- <property name="title">column</property>
+ <property name="title">Choose camera</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
@@ -383,34 +369,4 @@
</object>
</child>
</object>
- <object class="GtkDialog" id="dialog1">
- <property name="border_width">5</property>
- <property name="type_hint">normal</property>
- <child internal-child="vbox">
- <object class="GtkVBox" id="dialog-vbox2">
- <property name="visible">True</property>
- <property name="spacing">2</property>
- <child>
- <placeholder/>
- </child>
- <child internal-child="action_area">
- <object class="GtkHButtonBox" id="dialog-action_area2">
- <property name="visible">True</property>
- <property name="layout_style">end</property>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="pack_type">end</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
</interface>