diff options
Diffstat (limited to 'tools/gui')
-rw-r--r-- | tools/gui/control.c | 350 | ||||
-rw-r--r-- | tools/gui/control.glade | 302 | ||||
-rw-r--r-- | tools/gui/egg-property-cell-renderer.c | 594 | ||||
-rw-r--r-- | tools/gui/egg-property-cell-renderer.h | 55 | ||||
-rw-r--r-- | tools/gui/egg-property-tree-view.c | 113 | ||||
-rw-r--r-- | tools/gui/egg-property-tree-view.h | 54 |
6 files changed, 1468 insertions, 0 deletions
diff --git a/tools/gui/control.c b/tools/gui/control.c new file mode 100644 index 0000000..75b3cde --- /dev/null +++ b/tools/gui/control.c @@ -0,0 +1,350 @@ +/* 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 <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 "config.h" +#include "uca-camera.h" +#include "uca-plugin-manager.h" +#include "egg-property-tree-view.h" + + +typedef struct { + gboolean running; + gboolean store; + + guchar *buffer, *pixels; + GdkPixbuf *pixbuf; + GtkWidget *image; + GtkTreeModel *property_model; + UcaCamera *camera; + + GtkStatusbar *statusbar; + guint statusbar_context_id; + + int timestamp; + int width; + int height; + int pixel_size; +} ThreadData; + +enum { + COLUMN_NAME = 0, + COLUMN_VALUE, + COLUMN_EDITABLE, + NUM_COLUMNS +}; + +static UcaPluginManager *plugin_manager; + +static void +convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) +{ + for (int i = 0, j = 0; i < width*height; i++) { + output[j++] = input[i]; + output[j++] = input[i]; + output[j++] = input[i]; + } +} + +static void +convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) +{ + guint16 *in = (guint16 *) input; + guint16 min = G_MAXUINT16, max = 0; + gfloat spread = 0.0f; + + for (int i = 0; i < width * height; i++) { + guint16 v = in[i]; + if (v < min) + min = v; + if (v > max) + max = v; + } + + spread = (gfloat) max - min; + + if (spread > 0.0f) { + for (int i = 0, j = 0; i < width*height; i++) { + guchar val = (guint8) (((in[i] - min) / spread) * 255.0f); + output[j++] = val; + output[j++] = val; + output[j++] = val; + } + } +} + +static void * +grab_thread (void *args) +{ + ThreadData *data = (ThreadData *) args; + gchar filename[FILENAME_MAX] = {0,}; + gint counter = 0; + + while (data->running) { + uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); + + if (data->store) { + snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); + FILE *fp = fopen (filename, "wb"); + fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); + fclose (fp); + } + + /* FIXME: We should actually check if this is really a new frame and + * just do nothing if it is an already displayed one. */ + if (data->pixel_size == 1) + convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); + else if (data->pixel_size == 2) { + convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); + } + + gdk_threads_enter (); + gdk_flush (); + gtk_image_clear (GTK_IMAGE (data->image)); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); + gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + gdk_threads_leave (); + } + return NULL; +} + +gboolean +on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + return FALSE; +} + +void +on_destroy (GtkWidget *widget, gpointer data) +{ + ThreadData *td = (ThreadData *) data; + td->running = FALSE; + g_object_unref (td->camera); + gtk_main_quit (); +} + +static void +on_toolbutton_run_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + + if (data->running) + return; + + GError *error = NULL; + data->running = TRUE; + + uca_camera_start_recording (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start recording: %s\n", error->message); + return; + } + + if (!g_thread_create (grab_thread, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + return; + } +} + +static void +on_toolbutton_stop_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + data->running = FALSE; + data->store = FALSE; + GError *error = NULL; + uca_camera_stop_recording (data->camera, &error); + + if (error != NULL) + g_printerr ("Failed to stop: %s\n", error->message); +} + +static void +on_toolbutton_record_clicked (GtkWidget *widget, gpointer args) +{ + ThreadData *data = (ThreadData *) args; + data->timestamp = (int) time (0); + data->store = TRUE; + GError *error = NULL; + + gtk_statusbar_push (data->statusbar, data->statusbar_context_id, "Recording..."); + + if (data->running != TRUE) { + data->running = TRUE; + 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); + } +} + +static void +create_main_window (GtkBuilder *builder, const gchar* camera_name) +{ + static ThreadData td; + + GError *error = NULL; + UcaCamera *camera = uca_plugin_manager_new_camera (plugin_manager, camera_name, &error); + + if ((camera == NULL) || (error != NULL)) { + g_error ("%s\n", error->message); + gtk_main_quit (); + } + + guint bits_per_sample; + g_object_get (camera, + "roi-width", &td.width, + "roi-height", &td.height, + "sensor-bitdepth", &bits_per_sample, + NULL); + + 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); + + td.pixel_size = bits_per_sample > 8 ? 2 : 1; + td.image = image; + td.pixbuf = pixbuf; + td.buffer = (guchar *) g_malloc (td.pixel_size * td.width * td.height); + td.pixels = gdk_pixbuf_get_pixels (pixbuf); + td.running = FALSE; + td.statusbar = GTK_STATUSBAR (gtk_builder_get_object (builder, "statusbar")); + 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"), + "clicked", G_CALLBACK (on_toolbutton_run_clicked), &td); + g_signal_connect (gtk_builder_get_object (builder, "toolbutton_stop"), + "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); + + gtk_widget_show (image); + gtk_widget_show (window); +} + +static void +on_button_proceed_clicked (GtkWidget *widget, gpointer data) +{ + GtkBuilder *builder = GTK_BUILDER (data); + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); + + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + GList *selected_rows = gtk_tree_selection_get_selected_rows (selection, NULL); + GtkTreeIter iter; + + gtk_widget_destroy (choice_window); + gboolean valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store), &iter, selected_rows->data); + + if (valid) { + gchar *data; + gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter, 0, &data, -1); + create_main_window (builder, data); + g_free (data); + } + + g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL); + 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) +{ + GList *camera_types = uca_plugin_manager_get_available_cameras (plugin_manager); + + GtkWidget *choice_window = GTK_WIDGET (gtk_builder_get_object (builder, "choice-window")); + GtkTreeView *treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "treeview-cameras")); + GtkListStore *list_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "camera-types")); + GtkButton *proceed_button = GTK_BUTTON (gtk_builder_get_object (builder, "button-proceed")); + GtkTreeIter iter; + + for (GList *it = g_list_first (camera_types); it != NULL; it = g_list_next (it)) { + gtk_list_store_append (list_store, &iter); + gtk_list_store_set (list_store, &iter, 0, g_strdup ((gchar *) it->data), -1); + } + + gboolean valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter); + + if (valid) { + GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview); + gtk_tree_selection_unselect_all (selection); + gtk_tree_selection_select_path (selection, gtk_tree_model_get_path (GTK_TREE_MODEL (list_store), &iter)); + } + + 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)); + + g_list_foreach (camera_types, (GFunc) g_free, NULL); + g_list_free (camera_types); +} + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + + g_thread_init (NULL); + gdk_threads_init (); + gtk_init (&argc, &argv); + + GtkBuilder *builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { + g_print ("Error: %s\n", error->message); + return 1; + } + + plugin_manager = uca_plugin_manager_new (); + create_choice_window (builder); + gtk_builder_connect_signals (builder, NULL); + + gdk_threads_enter (); + gtk_main (); + gdk_threads_leave (); + + g_object_unref (plugin_manager); + return 0; +} diff --git a/tools/gui/control.glade b/tools/gui/control.glade new file mode 100644 index 0000000..d7ba2fc --- /dev/null +++ b/tools/gui/control.glade @@ -0,0 +1,302 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <requires lib="gtk+" version="2.20"/> + <!-- interface-naming-policy project-wide --> + <object class="GtkListStore" id="camera-types"> + <columns> + <!-- column-name name --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkListStore" id="camera-properties"> + <columns> + <!-- column-name PropertyName --> + <column type="gchararray"/> + <!-- column-name PropertyValue --> + <column type="gchararray"/> + <!-- column-name writeable --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkWindow" id="window"> + <property name="title" translatable="yes">Camera Control</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"> + <property name="visible">True</property> + <child> + <object class="GtkMenuBar" id="menubar1"> + <property name="visible">True</property> + <child> + <object class="GtkMenuItem" id="menuitem1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu_file"> + <property name="visible">True</property> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem1"> + <property name="label">gtk-new</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem2"> + <property name="label">gtk-open</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem3"> + <property name="label">gtk-save</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem4"> + <property name="label">gtk-save-as</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem" id="separatormenuitem1"> + <property name="visible">True</property> + </object> + </child> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_quit"> + <property name="label">gtk-quit</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + <signal name="activate" handler="gtk_main_quit"/> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="GtkMenuItem" id="menuitem4"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="menu_help"> + <property name="visible">True</property> + <child> + <object class="GtkImageMenuItem" id="imagemenuitem_about"> + <property name="label">gtk-about</property> + <property name="visible">True</property> + <property name="use_underline">True</property> + <property name="use_stock">True</property> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToolbar" id="toolbar"> + <property name="visible">True</property> + <child> + <object class="GtkToolButton" id="toolbutton_run"> + <property name="visible">True</property> + <property name="label" translatable="yes">Run</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-media-play</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="toolbutton_record"> + <property name="visible">True</property> + <property name="label" translatable="yes">Record</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-media-record</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + <child> + <object class="GtkToolButton" id="toolbutton_stop"> + <property name="visible">True</property> + <property name="label" translatable="yes">Stop</property> + <property name="use_underline">True</property> + <property name="stock_id">gtk-media-stop</property> + </object> + <packing> + <property name="expand">False</property> + <property name="homogeneous">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkHPaned" id="hpaned1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">6</property> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="width_request">300</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <object class="GtkViewport" id="viewport1"> + <property name="visible">True</property> + <property name="resize_mode">queue</property> + <child> + <object class="GtkImage" id="image"> + <property name="visible">True</property> + <property name="stock">gtk-missing-image</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">False</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">automatic</property> + <property name="vscrollbar_policy">automatic</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkStatusbar" id="statusbar"> + <property name="visible">True</property> + <property name="spacing">2</property> + </object> + <packing> + <property name="expand">False</property> + <property name="position">3</property> + </packing> + </child> + </object> + </child> + </object> + <object class="GtkAdjustment" id="adjustment_scale"> + <property name="value">65535</property> + <property name="lower">1</property> + <property name="upper">65535</property> + <property name="step_increment">1</property> + <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> + <property name="spacing">2</property> + <child> + <object class="GtkTreeView" id="treeview-cameras"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">camera-types</property> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <property name="title">Choose camera</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + <packing> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="spacing">6</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="button-cancel"> + <property name="label">gtk-quit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="gtk_main_quit"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="button-proceed"> + <property name="label">gtk-ok</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="padding">6</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/tools/gui/egg-property-cell-renderer.c b/tools/gui/egg-property-cell-renderer.c new file mode 100644 index 0000000..9df5cc3 --- /dev/null +++ b/tools/gui/egg-property-cell-renderer.c @@ -0,0 +1,594 @@ +/* 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; + GtkCellRenderer *combo_renderer; + GHashTable *combo_models; +}; + +enum +{ + PROP_0, + PROP_PROP_NAME, + N_PROPERTIES +}; + +enum +{ + COMBO_COLUMN_VALUE_NAME, + COMBO_COLUMN_VALUE, + N_COMBO_COLUMNS +}; + +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; + + 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); + 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); + 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: + if (G_TYPE_IS_ENUM (pspec->value_type)) { + priv->renderer = priv->combo_renderer; + g_object_set (renderer, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); + } + 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: + if (G_TYPE_IS_ENUM (pspec->value_type)) { + GParamSpecEnum *pspec_enum; + GEnumClass *enum_class; + GtkTreeModel *combo_model; + GtkTreeIter iter; + gint value; + + g_object_get (priv->object, prop_name, &value, NULL); + + pspec_enum = G_PARAM_SPEC_ENUM (pspec); + enum_class = pspec_enum->enum_class; + combo_model = g_hash_table_lookup (priv->combo_models, prop_name); + + if (combo_model == NULL) { + combo_model = GTK_TREE_MODEL (gtk_list_store_new (N_COMBO_COLUMNS, G_TYPE_STRING, G_TYPE_INT)); + g_hash_table_insert (priv->combo_models, g_strdup (prop_name), combo_model); + + for (guint i = 0; i < enum_class->n_values; i++) { + gtk_list_store_append (GTK_LIST_STORE (combo_model), &iter); + gtk_list_store_set (GTK_LIST_STORE (combo_model), &iter, + COMBO_COLUMN_VALUE_NAME, enum_class->values[i].value_name, + COMBO_COLUMN_VALUE, enum_class->values[i].value, + -1); + } + } + + + for (guint i = 0; i < enum_class->n_values; i++) { + if (enum_class->values[i].value == value) + text = g_strdup (enum_class->values[i].value_name); + } + + g_object_set (priv->renderer, + "model", combo_model, + "text-column", 0, + NULL); + } + 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_changed_cb (GtkCellRendererCombo *combo, + gchar *path, + GtkTreeIter *new_iter, + 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) { + GtkTreeModel *combo_model; + gchar *value_name; + gint value; + + combo_model = g_hash_table_lookup (priv->combo_models, prop_name); + + gtk_tree_model_get (combo_model, new_iter, + COMBO_COLUMN_VALUE_NAME, &value_name, + COMBO_COLUMN_VALUE, &value, + -1); + + g_object_set (priv->object, prop_name, value, NULL); + g_free (value_name); + 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_dispose (GObject *object) +{ + EggPropertyCellRenderer *renderer = EGG_PROPERTY_CELL_RENDERER (object); + g_hash_table_destroy (renderer->priv->combo_models); +} + +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; + gobject_class->dispose = egg_property_cell_renderer_dispose; + + 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->combo_renderer = gtk_cell_renderer_combo_new (); + priv->renderer = priv->text_renderer; + priv->combo_models = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + 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_object_set (priv->combo_renderer, + "has-entry", FALSE, + 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); + + g_signal_connect (priv->combo_renderer, "changed", + G_CALLBACK (egg_property_cell_renderer_changed_cb), priv); +} diff --git a/tools/gui/egg-property-cell-renderer.h b/tools/gui/egg-property-cell-renderer.h new file mode 100644 index 0000000..d4dbe02 --- /dev/null +++ b/tools/gui/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/tools/gui/egg-property-tree-view.c b/tools/gui/egg-property-tree-view.c new file mode 100644 index 0000000..52d1e10 --- /dev/null +++ b/tools/gui/egg-property-tree-view.c @@ -0,0 +1,113 @@ +/* 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/tools/gui/egg-property-tree-view.h b/tools/gui/egg-property-tree-view.h new file mode 100644 index 0000000..e8fd0fe --- /dev/null +++ b/tools/gui/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 |