From 06d5b3438f682307db06074ce9709b949a9aa846 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 11 Apr 2013 08:53:29 +0200 Subject: Move binaries to bin and make ring buffer a lib --- CMakeLists.txt | 6 +- bin/CMakeLists.txt | 10 + bin/common/ring-buffer.c | 70 ++++ bin/common/ring-buffer.h | 29 ++ bin/gui/CMakeLists.txt | 41 +++ bin/gui/config.h.in | 1 + bin/gui/control.c | 662 +++++++++++++++++++++++++++++++++++ bin/gui/control.glade | 635 +++++++++++++++++++++++++++++++++ bin/gui/egg-histogram-view.c | 524 +++++++++++++++++++++++++++ bin/gui/egg-histogram-view.h | 66 ++++ bin/gui/egg-property-cell-renderer.c | 594 +++++++++++++++++++++++++++++++ bin/gui/egg-property-cell-renderer.h | 55 +++ bin/gui/egg-property-tree-view.c | 113 ++++++ bin/gui/egg-property-tree-view.h | 54 +++ bin/tools/CMakeLists.txt | 40 +++ bin/tools/benchmark.c | 272 ++++++++++++++ bin/tools/config.h.in | 1 + bin/tools/gen-doc.c | 224 ++++++++++++ bin/tools/grab.c | 292 +++++++++++++++ gui/CMakeLists.txt | 50 --- gui/config.h.in | 1 - gui/control.c | 662 ----------------------------------- gui/control.glade | 635 --------------------------------- gui/egg-histogram-view.c | 524 --------------------------- gui/egg-histogram-view.h | 66 ---- gui/egg-property-cell-renderer.c | 594 ------------------------------- gui/egg-property-cell-renderer.h | 55 --- gui/egg-property-tree-view.c | 113 ------ gui/egg-property-tree-view.h | 54 --- tools/CMakeLists.txt | 42 --- tools/benchmark.c | 272 -------------- tools/config.h.in | 1 - tools/gen-doc.c | 224 ------------ tools/grab.c | 292 --------------- tools/ring-buffer.c | 70 ---- tools/ring-buffer.h | 29 -- 36 files changed, 3685 insertions(+), 3688 deletions(-) create mode 100644 bin/CMakeLists.txt create mode 100644 bin/common/ring-buffer.c create mode 100644 bin/common/ring-buffer.h create mode 100644 bin/gui/CMakeLists.txt create mode 100644 bin/gui/config.h.in create mode 100644 bin/gui/control.c create mode 100644 bin/gui/control.glade create mode 100644 bin/gui/egg-histogram-view.c create mode 100644 bin/gui/egg-histogram-view.h create mode 100644 bin/gui/egg-property-cell-renderer.c create mode 100644 bin/gui/egg-property-cell-renderer.h create mode 100644 bin/gui/egg-property-tree-view.c create mode 100644 bin/gui/egg-property-tree-view.h create mode 100644 bin/tools/CMakeLists.txt create mode 100644 bin/tools/benchmark.c create mode 100644 bin/tools/config.h.in create mode 100644 bin/tools/gen-doc.c create mode 100644 bin/tools/grab.c delete mode 100644 gui/CMakeLists.txt delete mode 100644 gui/config.h.in delete mode 100644 gui/control.c delete mode 100644 gui/control.glade delete mode 100644 gui/egg-histogram-view.c delete mode 100644 gui/egg-histogram-view.h delete mode 100644 gui/egg-property-cell-renderer.c delete mode 100644 gui/egg-property-cell-renderer.h delete mode 100644 gui/egg-property-tree-view.c delete mode 100644 gui/egg-property-tree-view.h delete mode 100644 tools/CMakeLists.txt delete mode 100644 tools/benchmark.c delete mode 100644 tools/config.h.in delete mode 100644 tools/gen-doc.c delete mode 100644 tools/grab.c delete mode 100644 tools/ring-buffer.c delete mode 100644 tools/ring-buffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e8aae64..95afb55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,8 +58,7 @@ pkg_check_modules(GMODULE2 gmodule-2.0>=2.24 REQUIRED) pkg_check_modules(GIO2 gio-2.0>=2.24 REQUIRED) include_directories( - # ${CMAKE_CURRENT_BINARY_DIR}/src - #${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src ${GLIB2_INCLUDE_DIRS} ${GOBJECT2_INCLUDE_DIRS} ${GMODULE2_INCLUDE_DIRS} @@ -74,8 +73,7 @@ set(UCA_DEPS add_subdirectory(src) add_subdirectory(plugins) add_subdirectory(test) -add_subdirectory(tools) -add_subdirectory(gui) +add_subdirectory(bin) include(CPack) diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt new file mode 100644 index 0000000..b8d065b --- /dev/null +++ b/bin/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.8) + +add_library(ringbuffer + ${CMAKE_CURRENT_SOURCE_DIR}/common/ring-buffer.c) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common) + +add_subdirectory(gui) +add_subdirectory(tools) + diff --git a/bin/common/ring-buffer.c b/bin/common/ring-buffer.c new file mode 100644 index 0000000..039024f --- /dev/null +++ b/bin/common/ring-buffer.c @@ -0,0 +1,70 @@ + +#include +#include "ring-buffer.h" + +RingBuffer * +ring_buffer_new (gsize block_size, + gsize n_blocks) +{ + RingBuffer *buffer; + + buffer = g_new0 (RingBuffer, 1); + buffer->block_size = block_size; + buffer->n_blocks_total = n_blocks; + buffer->n_blocks_used = 0; + buffer->current_index = 0; + buffer->data = g_malloc0_n (n_blocks, block_size); + + return buffer; +} + +void +ring_buffer_free (RingBuffer *buffer) +{ + g_free (buffer->data); + g_free (buffer); +} + +void +ring_buffer_reset (RingBuffer *buffer) +{ + buffer->n_blocks_used = 0; + buffer->current_index = 0; +} + +gsize +ring_buffer_get_block_size (RingBuffer *buffer) +{ + return buffer->block_size; +} + +gpointer +ring_buffer_get_current_pointer (RingBuffer *buffer) +{ + return buffer->data + (buffer->current_index % buffer->n_blocks_total) * buffer->block_size; +} + +gpointer +ring_buffer_get_pointer (RingBuffer *buffer, + guint index) +{ + g_assert (index < buffer->n_blocks_total); + return buffer->data + ((buffer->current_index - buffer->n_blocks_used + index) % buffer->n_blocks_total) * buffer->block_size; +} + +guint +ring_buffer_get_num_blocks (RingBuffer *buffer) +{ + return buffer->n_blocks_used; +} + +void +ring_buffer_proceed (RingBuffer *buffer) +{ + buffer->current_index++; + + if (buffer->n_blocks_used < buffer->n_blocks_total) + buffer->n_blocks_used++; + else + buffer->current_index = buffer->current_index % buffer->n_blocks_total; +} diff --git a/bin/common/ring-buffer.h b/bin/common/ring-buffer.h new file mode 100644 index 0000000..a3758cb --- /dev/null +++ b/bin/common/ring-buffer.h @@ -0,0 +1,29 @@ +#ifndef RING_BUFFER_H +#define RING_BUFFER_H + +#include + +G_BEGIN_DECLS + +typedef struct { + guchar *data; + gsize block_size; + guint n_blocks_total; + guint n_blocks_used; + guint current_index; +} RingBuffer; + +RingBuffer * ring_buffer_new (gsize block_size, + gsize n_blocks); +void ring_buffer_free (RingBuffer *buffer); +void ring_buffer_reset (RingBuffer *buffer); +gsize ring_buffer_get_block_size (RingBuffer *buffer); +gpointer ring_buffer_get_current_pointer (RingBuffer *buffer); +gpointer ring_buffer_get_pointer (RingBuffer *buffer, + guint index); +guint ring_buffer_get_num_blocks (RingBuffer *buffer); +void ring_buffer_proceed (RingBuffer *buffer); + +G_END_DECLS + +#endif diff --git a/bin/gui/CMakeLists.txt b/bin/gui/CMakeLists.txt new file mode 100644 index 0000000..f64bd02 --- /dev/null +++ b/bin/gui/CMakeLists.txt @@ -0,0 +1,41 @@ +cmake_minimum_required(VERSION 2.8) + +add_definitions("--std=c99 -Wall") + +# --- Find packages and libraries --------------------------------------------- +find_package(PkgConfig) + +pkg_check_modules(GTK2 gtk+-2.0>=2.22) +pkg_check_modules(GTHREAD2 gthread-2.0) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.glade + ${CMAKE_CURRENT_BINARY_DIR}) + +# --- Build targets ----------------------------------------------------------- +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +if (GTK2_FOUND) + include_directories(${GTK2_INCLUDE_DIRS}) + + add_executable(control + control.c + egg-property-cell-renderer.c + egg-property-tree-view.c + egg-histogram-view.c) + + target_link_libraries(control + m + uca + ringbuffer + ${GTK2_LIBRARIES} + ${GTHREAD2_LIBRARIES}) + + install(TARGETS control + RUNTIME DESTINATION bin) + + install(FILES control.glade + DESTINATION share/libuca) +endif() diff --git a/bin/gui/config.h.in b/bin/gui/config.h.in new file mode 100644 index 0000000..e7de9c6 --- /dev/null +++ b/bin/gui/config.h.in @@ -0,0 +1 @@ +#define CONTROL_GLADE_PATH "${CMAKE_INSTALL_PREFIX}/share/libuca/control.glade" diff --git a/bin/gui/control.c b/bin/gui/control.c new file mode 100644 index 0000000..c177f07 --- /dev/null +++ b/bin/gui/control.c @@ -0,0 +1,662 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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 +#include +#include +#include +#include + +#include "config.h" +#include "ring-buffer.h" +#include "uca-camera.h" +#include "uca-plugin-manager.h" +#include "egg-property-tree-view.h" +#include "egg-histogram-view.h" + +typedef enum { + IDLE, + RUNNING, + RECORDING +} State; + +typedef struct { + UcaCamera *camera; + GtkWidget *main_window; + GdkPixbuf *pixbuf; + GtkWidget *image; + GtkWidget *start_button; + GtkWidget *stop_button; + GtkWidget *record_button; + GtkWidget *download_button; + GtkComboBox *zoom_box; + + GtkDialog *download_dialog; + GtkProgressBar *download_progressbar; + GtkWidget *download_close_button; + GtkAdjustment *download_adjustment; + + GtkWidget *histogram_view; + GtkToggleButton *histogram_button; + GtkAdjustment *frame_slider; + + RingBuffer *buffer; + guchar *pixels; + gint display_width, display_height; + gdouble zoom_factor; + State state; + gboolean data_in_camram; + + gint timestamp; + gint width, height; + gint pixel_size; +} ThreadData; + +static UcaPluginManager *plugin_manager; +static gsize mem_size = 2048; + +static void +convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) +{ + gdouble min; + gdouble max; + gdouble factor; + guint8 *output; + gint i = 0; + gint stride; + + egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min, &max); + factor = 255.0 / (max - min); + output = data->pixels; + stride = (gint) 1 / data->zoom_factor; + + if (data->pixel_size == 1) { + guint8 *input = (guint8 *) buffer; + + for (gint y = 0; y < data->display_height; y++) { + gint offset = y * stride * data->width; + + for (gint x = 0; x < data->display_width; x++, offset += stride) { + gdouble dval = (input[offset] - min) * factor; + guchar val = (guchar) CLAMP(dval, 0.0, 255.0); + + output[i++] = val; + output[i++] = val; + output[i++] = val; + } + } + } + else if (data->pixel_size == 2) { + guint16 *input = (guint16 *) buffer; + + for (gint y = 0; y < data->display_height; y++) { + gint offset = y * stride * data->width; + + for (gint x = 0; x < data->display_width; x++, offset += stride) { + gdouble dval = (input[offset] - min) * factor; + guchar val = (guchar) CLAMP(dval, 0.0, 255.0); + + output[i++] = val; + output[i++] = val; + output[i++] = val; + } + } + } +} + +static void +update_pixbuf (ThreadData *data) +{ + gdk_flush (); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); + gtk_widget_queue_draw_area (data->image, 0, 0, data->display_width, data->display_height); + + if (gtk_toggle_button_get_active (data->histogram_button)) + gtk_widget_queue_draw (data->histogram_view); +} + +static void +update_pixbuf_dimensions (ThreadData *data) +{ + if (data->pixbuf != NULL) + g_object_unref (data->pixbuf); + + data->display_width = (gint) data->width * data->zoom_factor; + data->display_height = (gint) data->height * data->zoom_factor; + data->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, data->display_width, data->display_height); + data->pixels = gdk_pixbuf_get_pixels (data->pixbuf); + gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); +} + +static void +print_and_free_error (GError **error) +{ + g_printerr ("%s\n", (*error)->message); + g_error_free (*error); + *error = NULL; +} + +static gpointer +preview_frames (void *args) +{ + ThreadData *data = (ThreadData *) args; + gint counter = 0; + GError *error = NULL;; + + while (data->state == RUNNING) { + gpointer buffer; + + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_trigger (data->camera, &error); + uca_camera_grab (data->camera, buffer, &error); + + if (error == NULL) { + convert_grayscale_to_rgb (data, buffer); + + gdk_threads_enter (); + update_pixbuf (data); + gdk_threads_leave (); + + counter++; + } + else + print_and_free_error (&error); + } + return NULL; +} + +static gpointer +record_frames (gpointer args) +{ + ThreadData *data; + gpointer buffer; + guint n_frames = 0; + GError *error = NULL; + + data = (ThreadData *) args; + ring_buffer_reset (data->buffer); + + while (data->state == RECORDING) { + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, buffer, NULL); + + if (error == NULL) { + ring_buffer_proceed (data->buffer); + n_frames++; + } + else + print_and_free_error (&error); + } + + n_frames = ring_buffer_get_num_blocks (data->buffer); + + gdk_threads_enter (); + gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); + gtk_adjustment_set_value (data->frame_slider, n_frames - 1); + gdk_threads_leave (); + + return NULL; +} + +gboolean +on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) +{ + return FALSE; +} + +void +on_destroy (GtkWidget *widget, ThreadData *data) +{ + data->state = IDLE; + g_object_unref (data->camera); + ring_buffer_free (data->buffer); + + gtk_main_quit (); +} + +static void +set_tool_button_state (ThreadData *data) +{ + gtk_widget_set_sensitive (data->start_button, + data->state == IDLE); + gtk_widget_set_sensitive (data->stop_button, + data->state == RUNNING || data->state == RECORDING); + gtk_widget_set_sensitive (data->record_button, + data->state == IDLE); + gtk_widget_set_sensitive (data->download_button, + data->data_in_camram); + gtk_widget_set_sensitive (GTK_WIDGET (data->zoom_box), + data->state == IDLE); +} + +static void +update_current_frame (ThreadData *data) +{ + gpointer buffer; + gint index; + + index = (gint) gtk_adjustment_get_value (data->frame_slider); + buffer = ring_buffer_get_pointer (data->buffer, index); + convert_grayscale_to_rgb (data, buffer); + update_pixbuf (data); +} + +static void +on_frame_slider_changed (GtkAdjustment *adjustment, ThreadData *data) +{ + if (data->state == IDLE) + update_current_frame (data); +} + +static void +on_start_button_clicked (GtkWidget *widget, ThreadData *data) +{ + GError *error = NULL; + + uca_camera_start_recording (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start recording: %s\n", error->message); + return; + } + + data->state = RUNNING; + set_tool_button_state (data); + + if (!g_thread_create (preview_frames, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + data->state = IDLE; + set_tool_button_state (data); + } +} + +static void +on_stop_button_clicked (GtkWidget *widget, ThreadData *data) +{ + GError *error = NULL; + + g_object_get (data->camera, "has-camram-recording", &data->data_in_camram, NULL); + data->state = IDLE; + set_tool_button_state (data); + uca_camera_stop_recording (data->camera, &error); + + if (error != NULL) + g_printerr ("Failed to stop: %s\n", error->message); + +} + +static void +on_record_button_clicked (GtkWidget *widget, ThreadData *data) +{ + GError *error = NULL; + + uca_camera_start_recording (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start recording: %s\n", error->message); + } + + data->timestamp = (int) time (0); + data->state = RECORDING; + set_tool_button_state (data); + + if (!g_thread_create (record_frames, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + data->state = IDLE; + set_tool_button_state (data); + } +} + +static gpointer +download_frames (ThreadData *data) +{ + gpointer buffer; + guint n_frames; + guint current_frame = 1; + GError *error = NULL; + + g_object_get (data->camera, "recorded-frames", &n_frames, NULL); + gdk_threads_enter (); + gtk_widget_set_sensitive (data->download_close_button, FALSE); + gtk_adjustment_set_upper (data->download_adjustment, n_frames); + gdk_threads_leave (); + + uca_camera_start_readout (data->camera, &error); + + if (error != NULL) { + g_printerr ("Failed to start read out of camera memory: %s\n", error->message); + return NULL; + } + + ring_buffer_reset (data->buffer); + + while (error == NULL) { + buffer = ring_buffer_get_current_pointer (data->buffer); + uca_camera_grab (data->camera, buffer, &error); + ring_buffer_proceed (data->buffer); + gdk_threads_enter (); + gtk_adjustment_set_value (data->download_adjustment, current_frame++); + gdk_threads_leave (); + } + + if (error->code == UCA_CAMERA_ERROR_END_OF_STREAM) { + guint n_frames = ring_buffer_get_num_blocks (data->buffer); + + gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); + gtk_adjustment_set_value (data->frame_slider, n_frames - 1); + } + else + g_printerr ("Error while reading out frames: %s\n", error->message); + + g_error_free (error); + error = NULL; + + uca_camera_stop_readout (data->camera, &error); + + if (error != NULL) + g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); + + gdk_threads_enter (); + gtk_widget_set_sensitive (data->download_close_button, TRUE); + gdk_threads_leave (); + + return NULL; +} + +static void +on_download_button_clicked (GtkWidget *widget, ThreadData *data) +{ + GError *error = NULL; + + if (!g_thread_create ((GThreadFunc) download_frames, data, FALSE, &error)) { + g_printerr ("Failed to create thread: %s\n", error->message); + } + + gtk_widget_set_sensitive (data->main_window, FALSE); + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); + gtk_dialog_run (data->download_dialog); + gtk_widget_hide (GTK_WIDGET (data->download_dialog)); + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), FALSE); + gtk_widget_set_sensitive (data->main_window, TRUE); + gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); +} + +static void +on_histogram_changed (EggHistogramView *view, ThreadData *data) +{ + if (data->state == IDLE) + update_current_frame (data); +} + +static void +on_zoom_changed (GtkComboBox *widget, ThreadData *data) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gdouble factor; + + enum { + DISPLAY_COLUMN, + FACTOR_COLUMN + }; + + model = gtk_combo_box_get_model (widget); + gtk_combo_box_get_active_iter (widget, &iter); + gtk_tree_model_get (model, &iter, FACTOR_COLUMN, &factor, -1); + + data->zoom_factor = factor; + update_pixbuf_dimensions (data); +} + +static void +on_roi_width_changed (GObject *object, GParamSpec *pspec, ThreadData *data) +{ + g_object_get (object, "roi-width", &data->width, NULL); + update_pixbuf_dimensions (data); +} + +static void +on_roi_height_changed (GObject *object, GParamSpec *pspec, ThreadData *data) +{ + g_object_get (object, "roi-height", &data->height, NULL); + update_pixbuf_dimensions (data); +} + +static void +create_main_window (GtkBuilder *builder, const gchar* camera_name) +{ + static ThreadData td; + UcaCamera *camera; + GtkWidget *window; + GtkWidget *image; + GtkWidget *histogram_view; + GtkWidget *property_tree_view; + GdkPixbuf *pixbuf; + GtkBox *histogram_box; + GtkContainer *property_window; + GtkAdjustment *max_bin_adjustment; + RingBuffer *ring_buffer; + gsize image_size; + guint n_frames; + guint bits_per_sample; + guint pixel_size; + guint width, height; + GError *error = NULL; + + camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error, NULL); + + if ((camera == NULL) || (error != NULL)) { + g_error ("%s\n", error->message); + gtk_main_quit (); + } + + g_object_get (camera, + "roi-width", &width, + "roi-height", &height, + "sensor-bitdepth", &bits_per_sample, + NULL); + + g_signal_connect (camera, "notify::roi-width", (GCallback) on_roi_width_changed, &td); + g_signal_connect (camera, "notify::roi-height", (GCallback) on_roi_height_changed, &td); + + histogram_view = egg_histogram_view_new (); + property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "property-window")); + image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); + + td.zoom_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "zoom-box")); + td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); + td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); + td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); + td.download_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-button")); + td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); + + td.download_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "download-dialog")); + td.download_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "download-adjustment")); + td.download_close_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-close-button")); + + /* Set initial data */ + pixel_size = bits_per_sample > 8 ? 2 : 1; + image_size = pixel_size * width * height; + n_frames = mem_size * 1024 * 1024 / image_size; + ring_buffer = ring_buffer_new (image_size, n_frames); + + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (histogram_view), + ring_buffer_get_current_pointer (ring_buffer), + width * height, bits_per_sample, 256); + + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + + gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); + + g_message ("Allocated memory for %d frames", n_frames); + + td.pixel_size = pixel_size; + td.image = image; + td.pixbuf = NULL; + td.pixels = NULL; + td.buffer = ring_buffer; + td.state = IDLE; + td.camera = camera; + td.width = td.display_width = width; + td.height = td.display_height = height; + td.zoom_factor = 1.0; + td.histogram_view = histogram_view; + td.data_in_camram = FALSE; + td.main_window = window; + + update_pixbuf_dimensions (&td); + set_tool_button_state (&td); + + /* Hook up signals */ + g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", + td.histogram_view, "minimum-bin-value", + G_BINDING_DEFAULT); + + g_object_bind_property (max_bin_adjustment, "value", + td.histogram_view, "maximum-bin-value", + G_BINDING_DEFAULT); + + g_signal_connect (td.frame_slider, "value-changed", G_CALLBACK (on_frame_slider_changed), &td); + g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); + g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); + g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); + g_signal_connect (td.download_button, "clicked", G_CALLBACK (on_download_button_clicked), &td); + g_signal_connect (td.zoom_box, "changed", G_CALLBACK (on_zoom_changed), &td); + g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); + g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); + + /* Layout */ + gtk_container_add (property_window, property_tree_view); + gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); + + gtk_widget_show_all (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, "proceed-button")); + 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[]) +{ + GtkBuilder *builder; + GOptionContext *context; + GError *error = NULL; + + static GOptionEntry entries[] = + { + { "mem-size", 'm', 0, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, + { NULL } + }; + + context = g_option_context_new ("- control libuca cameras"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_print ("Option parsing failed: %s\n", error->message); + return 1; + } + + g_thread_init (NULL); + gdk_threads_init (); + gtk_init (&argc, &argv); + + builder = gtk_builder_new (); + + if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { + g_print ("Could not load UI file: %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/bin/gui/control.glade b/bin/gui/control.glade new file mode 100644 index 0000000..eec9dde --- /dev/null +++ b/bin/gui/control.glade @@ -0,0 +1,635 @@ + + + + + + + + + + + + + + + + + + + + + + Camera Control + 1024 + 768 + + + + True + + + True + + + True + _File + True + + + True + + + gtk-new + True + True + True + + + + + gtk-open + True + True + True + + + + + gtk-save + True + True + True + + + + + gtk-save-as + True + True + True + + + + + True + + + + + gtk-quit + True + True + True + + + + + + + + + + True + _Help + True + + + True + + + gtk-about + True + True + True + + + + + + + + + False + 0 + + + + + True + + + True + Run + True + gtk-media-play + + + False + True + + + + + True + Record + True + gtk-media-record + + + False + True + + + + + True + Stop + True + gtk-media-stop + + + False + True + + + + + True + Download + True + network-receive + + + False + True + + + + + False + 1 + + + + + True + True + 6 + + + True + True + + + 640 + 480 + True + True + automatic + automatic + + + True + queue + + + True + gtk-missing-image + + + + + + + True + True + + + + + True + True + + + True + 10 + + + + + + True + 6 + 3 + 2 + 6 + 6 + + + True + 1 + Minimum Value: + + + GTK_FILL + + 6 + 6 + + + + + 100 + True + True + + min-bin-value-adjustment + + + 1 + 2 + GTK_EXPAND + + + + + + True + 1 + Maximum Value: + + + 1 + 2 + GTK_FILL + + 6 + 6 + + + + + 100 + True + True + + max-bin-value-adjustment + + + 1 + 2 + 1 + 2 + GTK_EXPAND + + + + + + Live Update + True + True + False + 6 + True + True + + + 2 + 3 + + + + + + + + + + False + False + 1 + + + + + + + True + Histogram + + + False + + + + + True + 10 + 2 + 2 + 6 + 6 + + + True + True + frames-adjustment + 0 + + + 1 + 2 + 1 + 2 + GTK_FILL + + + + + True + 1 + Frame: + + + 1 + 2 + GTK_FILL + + + + + + True + 1 + Zoom: + + + GTK_FILL + + + + + + True + zoom-values + + + + 0 + + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + 1 + + + + + True + Preview + + + 1 + False + + + + + True + True + + + + + False + True + + + + + True + True + automatic + automatic + + + + + + True + True + + + + + 2 + + + + + + + + + + + + + + + 100 % + 1 + + + 50 % + 0.5 + + + 25 % + 0.25 + + + + + 6 + + + True + 2 + + + True + True + automatic + automatic + + + True + True + camera-types + False + 0 + + + Choose camera + + + + 0 + + + + + + + + + 0 + + + + + True + 6 + end + + + gtk-quit + True + True + True + True + + + + False + False + 0 + + + + + gtk-ok + True + True + True + True + + + False + False + 1 + + + + + False + 6 + 1 + + + + + + + 65535 + 1 + 10 + + + 256 + 65535 + 1 + 10 + + + 1 + 10 + + + 5 + normal + + + True + 2 + + + True + 10 + 6 + + + True + 0 + Downloading Frames … + + + False + False + 0 + + + + + True + download-adjustment + + + False + 1 + + + + + 1 + + + + + True + end + + + gtk-close + True + True + True + True + + + False + False + 0 + + + + + False + False + end + 0 + + + + + + download-close-button + + + + 100 + 1 + 10 + 10 + + diff --git a/bin/gui/egg-histogram-view.c b/bin/gui/egg-histogram-view.c new file mode 100644 index 0000000..812af7a --- /dev/null +++ b/bin/gui/egg-histogram-view.c @@ -0,0 +1,524 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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 +#include "egg-histogram-view.h" + +G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_DRAWING_AREA) + +#define EGG_HISTOGRAM_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewPrivate)) + +#define MIN_WIDTH 128 +#define MIN_HEIGHT 128 +#define BORDER 2 + +struct _EggHistogramViewPrivate +{ + GdkCursorType cursor_type; + gboolean grabbing; + + /* This could be moved into a real histogram class */ + guint n_bins; + gint *bins; + gint *grabbed; + gint min_border; /* threshold set in screen units */ + gint max_border; + + gdouble min_value; /* lowest value of the first bin */ + gdouble max_value; /* highest value of the last bin */ + gdouble range; + + gpointer data; + gint n_elements; + gint n_bits; +}; + +enum +{ + PROP_0, + PROP_MINIMUM_BIN_VALUE, + PROP_MAXIMUM_BIN_VALUE, + N_PROPERTIES +}; + +enum +{ + CHANGED, + LAST_SIGNAL +}; + +static GParamSpec *egg_histogram_view_properties[N_PROPERTIES] = { NULL, }; + +static guint egg_histogram_view_signals[LAST_SIGNAL] = { 0 }; + + +GtkWidget * +egg_histogram_view_new (void) +{ + EggHistogramView *view; + + view = EGG_HISTOGRAM_VIEW (g_object_new (EGG_TYPE_HISTOGRAM_VIEW, NULL)); + return GTK_WIDGET (view); +} + +void +egg_histogram_view_set_data (EggHistogramView *view, + gpointer data, + guint n_elements, + guint n_bits, + guint n_bins) +{ + EggHistogramViewPrivate *priv; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); + priv = view->priv; + + if (priv->bins != NULL) + g_free (priv->bins); + + priv->data = data; + priv->bins = g_malloc0 (n_bins * sizeof (guint)); + priv->n_bins = n_bins; + priv->n_bits = n_bits; + priv->n_elements = n_elements; + + priv->min_value = 0.0; + priv->max_value = (gint) pow(2, n_bits) - 1; + + priv->min_border = 0; + priv->max_border = 256; + priv->range = priv->max_value - priv->min_value; +} + +void +egg_histogram_get_visible_range (EggHistogramView *view, gdouble *min, gdouble *max) +{ + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + gdouble width; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); + + gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + width = (gdouble) allocation.width - 2 * BORDER; + priv = view->priv; + + *min = (priv->min_border - 2) / width * priv->range; + *max = (priv->max_border - 2) / width * priv->range; +} + +static void +set_max_border (EggHistogramView *view) +{ + GtkAllocation allocation; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); + gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); + view->priv->max_border = allocation.width - 2 * BORDER; +} + +static void +compute_histogram (EggHistogramViewPrivate *priv) +{ + guint n_bins = priv->n_bins - 1; + + for (guint i = 0; i < priv->n_bins; i++) + priv->bins[i] = 0; + + if (priv->n_bits == 8) { + guint8 *data = (guint8 *) priv->data; + + for (guint i = 0; i < priv->n_elements; i++) { + guint8 v = data[i]; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) round (((gdouble) v) / priv->max_value * n_bins); + priv->bins[index]++; + } + } + } + else { + guint16 *data = (guint16 *) priv->data; + + for (guint i = 0; i < priv->n_elements; i++) { + guint16 v = data[i]; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) floor (((gdouble ) v) / priv->max_value * n_bins); + priv->bins[index]++; + } + } + } +} + +static void +set_cursor_type (EggHistogramView *view, GdkCursorType cursor_type) +{ + if (cursor_type != view->priv->cursor_type) { + GdkCursor *cursor = gdk_cursor_new (cursor_type); + + gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(view)), cursor); + gdk_cursor_unref (cursor); + view->priv->cursor_type = cursor_type; + } +} + +static void +egg_histogram_view_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + requisition->width = MIN_WIDTH; + requisition->height = MIN_HEIGHT; +} + +static void +draw_bins (EggHistogramViewPrivate *priv, + cairo_t *cr, + gint width, + gint height) +{ + gdouble skip = ((gdouble) width) / priv->n_bins; + gdouble x = BORDER; + gdouble ys = height + BORDER - 1; + gint max_value = 0; + + for (guint i = 0; i < priv->n_bins; i++) { + if (priv->bins[i] > max_value) + max_value = priv->bins[i]; + } + + if (max_value == 0) + return; + + for (guint i = 0; i < priv->n_bins && x < (width - BORDER); i++, x += skip) { + if (priv->bins[i] == 0) + continue; + + gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; + cairo_move_to (cr, round (x), ys); + cairo_line_to (cr, round (x), ys - y); + cairo_stroke (cr); + } +} + +static gboolean +egg_histogram_view_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + GtkStyle *style; + cairo_t *cr; + gint width, height; + + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (widget); + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + + gdk_cairo_region (cr, event->region); + cairo_clip (cr); + + style = gtk_widget_get_style (widget); + gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); + cairo_paint (cr); + + /* Draw the background */ + gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); + cairo_paint (cr); + + gtk_widget_get_allocation (widget, &allocation); + width = allocation.width - 2 * BORDER; + height = allocation.height - 2 * BORDER; + + gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); + cairo_set_line_width (cr, 1.0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_translate (cr, 0.5, 0.5); + cairo_rectangle (cr, BORDER, BORDER, width - 1, height - 1); + cairo_stroke (cr); + + if (priv->bins == NULL) + goto cleanup; + + compute_histogram (priv); + + /* Draw border areas */ + gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); + + cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); + cairo_fill (cr); + + cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->max_border + 0.5, height - 1); + cairo_fill (cr); + + /* Draw spikes */ + gdk_cairo_set_source_color (cr, &style->black); + draw_bins (priv, cr, width, height); + +cleanup: + cairo_destroy (cr); + return FALSE; +} + +static void +egg_histogram_view_finalize (GObject *object) +{ + EggHistogramViewPrivate *priv; + + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); + + if (priv->bins) + g_free (priv->bins); + + G_OBJECT_CLASS (egg_histogram_view_parent_class)->finalize (object); +} + +static void +egg_histogram_view_dispose (GObject *object) +{ + G_OBJECT_CLASS (egg_histogram_view_parent_class)->dispose (object); +} + +static void +egg_histogram_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EggHistogramViewPrivate *priv; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); + + switch (property_id) { + case PROP_MINIMUM_BIN_VALUE: + { + gdouble v = g_value_get_double (value); + + if (v > priv->max_value) + g_warning ("Minimum value `%f' larger than maximum value `%f'", + v, priv->max_value); + else { + priv->min_value = v; + priv->range = priv->max_value - v; + priv->min_border = 0; + } + } + break; + + case PROP_MAXIMUM_BIN_VALUE: + { + gdouble v = g_value_get_double (value); + + if (v < priv->min_value) + g_warning ("Maximum value `%f' larger than minimum value `%f'", + v, priv->min_value); + else { + priv->max_value = v; + priv->range = v - priv->min_value; + set_max_border (EGG_HISTOGRAM_VIEW (object)); + } + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } +} + +static void +egg_histogram_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EggHistogramViewPrivate *priv; + + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); + + switch (property_id) { + case PROP_MINIMUM_BIN_VALUE: + g_value_set_double (value, priv->min_value); + break; + + case PROP_MAXIMUM_BIN_VALUE: + g_value_set_double (value, priv->max_value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } +} + +static gboolean +is_on_border (EggHistogramViewPrivate *priv, + gint x) +{ + gint d1 = (priv->min_border + BORDER) - x; + gint d2 = (priv->max_border + BORDER) - x; + return ABS (d1) < 6 || ABS (d2) < 6; +} + +static gint * +get_grabbed_border (EggHistogramViewPrivate *priv, + gint x) +{ + gint d1 = (priv->min_border + BORDER) - x; + gint d2 = (priv->max_border + BORDER) - x; + + if (ABS (d1) < 6) + return &priv->min_border; + else if (ABS (d2) < 6) + return &priv->max_border; + + return NULL; +} + +static gboolean +egg_histogram_view_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + + if (priv->grabbing) { + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); + + if ((event->x + BORDER > 0) && (event->x + BORDER < allocation.width)) { + *priv->grabbed = event->x; + gtk_widget_queue_draw (widget); + } + } + else { + if (is_on_border (priv, event->x)) + set_cursor_type (view, GDK_FLEUR); + else + set_cursor_type (view, GDK_ARROW); + } + + return TRUE; +} + +static gboolean +egg_histogram_view_button_release (GtkWidget *widget, + GdkEventButton *event) +{ + EggHistogramView *view; + + view = EGG_HISTOGRAM_VIEW (widget); + set_cursor_type (view, GDK_ARROW); + view->priv->grabbing = FALSE; + g_signal_emit (widget, egg_histogram_view_signals[CHANGED], 0); + + return TRUE; +} + +static gboolean +egg_histogram_view_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + + if (is_on_border (priv, event->x)) { + priv->grabbing = TRUE; + priv->grabbed = get_grabbed_border (priv, event->x); + set_cursor_type (view, GDK_FLEUR); + } + + return TRUE; +} + +static void +egg_histogram_view_class_init (EggHistogramViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->set_property = egg_histogram_view_set_property; + object_class->get_property = egg_histogram_view_get_property; + object_class->dispose = egg_histogram_view_dispose; + object_class->finalize = egg_histogram_view_finalize; + + widget_class->size_request = egg_histogram_view_size_request; + widget_class->expose_event = egg_histogram_view_expose; + widget_class->button_press_event = egg_histogram_view_button_press; + widget_class->button_release_event = egg_histogram_view_button_release; + widget_class->motion_notify_event = egg_histogram_view_motion_notify; + + egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE] = + g_param_spec_double ("minimum-bin-value", + "Smallest possible bin value", + "Smallest possible bin value, everything below is discarded.", + 0.0, G_MAXDOUBLE, 0.0, + G_PARAM_READWRITE); + + egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE] = + g_param_spec_double ("maximum-bin-value", + "Largest possible bin value", + "Largest possible bin value, everything above is discarded.", + 0.0, G_MAXDOUBLE, 256.0, + G_PARAM_READWRITE); + + g_object_class_install_property (object_class, PROP_MINIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE]); + g_object_class_install_property (object_class, PROP_MAXIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE]); + + egg_histogram_view_signals[CHANGED] = + g_signal_new ("changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EggHistogramViewClass, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); +} + +static void +egg_histogram_view_init (EggHistogramView *view) +{ + EggHistogramViewPrivate *priv; + + view->priv = priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (view); + + priv->bins = NULL; + priv->data = NULL; + priv->n_bins = 0; + priv->n_elements = 0; + priv->min_value = priv->min_border = 0; + priv->max_value = priv->max_border = 256; + + priv->cursor_type = GDK_ARROW; + priv->grabbing = FALSE; + + gtk_widget_add_events (GTK_WIDGET (view), + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK | + GDK_POINTER_MOTION_MASK); +} diff --git a/bin/gui/egg-histogram-view.h b/bin/gui/egg-histogram-view.h new file mode 100644 index 0000000..7a62fca --- /dev/null +++ b/bin/gui/egg-histogram-view.h @@ -0,0 +1,66 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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_HISTOGRAM_VIEW_H +#define EGG_HISTOGRAM_VIEW_H + +#include + +G_BEGIN_DECLS + +#define EGG_TYPE_HISTOGRAM_VIEW (egg_histogram_view_get_type()) +#define EGG_HISTOGRAM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramView)) +#define EGG_IS_HISTOGRAM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_HISTOGRAM_VIEW)) +#define EGG_HISTOGRAM_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewClass)) +#define EGG_IS_HISTOGRAM_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_HISTOGRAM_VIEW)) +#define EGG_HISTOGRAM_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewClass)) + +typedef struct _EggHistogramView EggHistogramView; +typedef struct _EggHistogramViewClass EggHistogramViewClass; +typedef struct _EggHistogramViewPrivate EggHistogramViewPrivate; + +struct _EggHistogramView +{ + GtkDrawingArea parent_instance; + + /*< private >*/ + EggHistogramViewPrivate *priv; +}; + +struct _EggHistogramViewClass +{ + GtkDrawingAreaClass parent_class; + + /* signals */ + void (* changed) (EggHistogramView *view); +}; + +GType egg_histogram_view_get_type (void); +GtkWidget * egg_histogram_view_new (void); +void egg_histogram_view_set_data (EggHistogramView *view, + gpointer data, + guint n_elements, + guint n_bits, + guint n_bins); +void egg_histogram_get_visible_range + (EggHistogramView *view, + gdouble *min, + gdouble *max); + +G_END_DECLS + +#endif diff --git a/bin/gui/egg-property-cell-renderer.c b/bin/gui/egg-property-cell-renderer.c new file mode 100644 index 0000000..9df5cc3 --- /dev/null +++ b/bin/gui/egg-property-cell-renderer.c @@ -0,0 +1,594 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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 +#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/bin/gui/egg-property-cell-renderer.h b/bin/gui/egg-property-cell-renderer.h new file mode 100644 index 0000000..d4dbe02 --- /dev/null +++ b/bin/gui/egg-property-cell-renderer.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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 + +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/bin/gui/egg-property-tree-view.c b/bin/gui/egg-property-tree-view.c new file mode 100644 index 0000000..52d1e10 --- /dev/null +++ b/bin/gui/egg-property-tree-view.c @@ -0,0 +1,113 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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/bin/gui/egg-property-tree-view.h b/bin/gui/egg-property-tree-view.h new file mode 100644 index 0000000..e8fd0fe --- /dev/null +++ b/bin/gui/egg-property-tree-view.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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 + +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 diff --git a/bin/tools/CMakeLists.txt b/bin/tools/CMakeLists.txt new file mode 100644 index 0000000..a52bb97 --- /dev/null +++ b/bin/tools/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 2.8) + +add_definitions("--std=c99 -Wall") + +# --- Find packages and libraries --------------------------------------------- +find_package(TIFF) + +# --- Build targets ----------------------------------------------------------- +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ) + +set(libs uca) + +if (TIFF_FOUND) + set(HAVE_LIBTIFF "1") + list(APPEND libs ${TIFF_LIBRARIES}) + include_directories(${TIFF_INCLUDE_DIRS}) +endif () + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h) + +# --- gen-doc +add_executable(gen-doc gen-doc.c) +target_link_libraries(gen-doc ${libs}) + +# --- uca-grab +add_executable(uca-grab grab.c) +target_link_libraries(uca-grab + ringbuffer + ${libs}) + +# --- uca-benchmark +add_executable(benchmark benchmark.c) +target_link_libraries(benchmark ${libs}) + +install(TARGETS uca-grab + RUNTIME DESTINATION bin) diff --git a/bin/tools/benchmark.c b/bin/tools/benchmark.c new file mode 100644 index 0000000..0939d78 --- /dev/null +++ b/bin/tools/benchmark.c @@ -0,0 +1,272 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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 +#include +#include +#include +#include "uca-camera.h" +#include "uca-plugin-manager.h" + +typedef void (*GrabFrameFunc) (UcaCamera *camera, gpointer buffer, guint n_frames); + +static UcaCamera *camera = NULL; + +static void +sigint_handler(int signal) +{ + g_print ("Closing down libuca\n"); + uca_camera_stop_recording (camera, NULL); + g_object_unref (camera); + exit (signal); +} + +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: benchmark [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +static void +log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user) +{ + gsize n_written; + GError *error = NULL; + GIOChannel *channel = user; + +#if GLIB_CHECK_VERSION(2, 26, 0) + GTimeZone *tz; + GDateTime *date_time; + gchar *new_message; + + tz = g_time_zone_new_local (); + date_time = g_date_time_new_now (tz); + + new_message = g_strdup_printf ("[%s] %s\n", + g_date_time_format (date_time, "%FT%H:%M:%S%z"), message); + + g_time_zone_unref (tz); + g_date_time_unref (date_time); + + g_io_channel_write_chars (channel, new_message, strlen (new_message), &n_written, &error); + g_assert_no_error (error); + g_free (new_message); +#else + g_io_channel_write_chars (channel, message, strlen (message), &n_written, &error); + g_assert_no_error (error); +#endif + + g_io_channel_flush (channel, &error); + g_assert_no_error (error); +} + +static void +grab_frames_sync (UcaCamera *camera, gpointer buffer, guint n_frames) +{ + GError *error = NULL; + + uca_camera_start_recording (camera, &error); + + for (guint i = 0; i < n_frames; i++) { + if (!uca_camera_grab (camera, buffer, &error)) + g_warning ("Data stream ended"); + + if (error != NULL) { + g_warning ("Error grabbing frame %02i/%i: `%s'", i, n_frames, error->message); + g_error_free (error); + error = NULL; + } + } + + uca_camera_stop_recording (camera, &error); +} + +static void +grab_callback (gpointer data, gpointer user_data) +{ + static GStaticMutex mutex = G_STATIC_MUTEX_INIT; + guint *n_acquired_frames = user_data; + + g_static_mutex_lock (&mutex); + *n_acquired_frames += 1; + g_static_mutex_unlock (&mutex); +} + +static void +grab_frames_async (UcaCamera *camera, gpointer buffer, guint n_frames) +{ + GError *error = NULL; + guint n_acquired_frames = 0; + + uca_camera_set_grab_func (camera, grab_callback, &n_acquired_frames); + uca_camera_start_recording (camera, &error); + + /* + * Behold! Spinlooping is probably a bad idea but nowadays single core + * machines are relatively rare. + */ + while (n_acquired_frames < n_frames) + ; + + uca_camera_stop_recording (camera, &error); +} + +static void +benchmark_method (UcaCamera *camera, gpointer buffer, GrabFrameFunc func, guint n_runs, guint n_frames, guint n_bytes) +{ + GTimer *timer; + gdouble fps; + gdouble bandwidth; + gdouble total_time = 0.0; + GError *error = NULL; + + g_print ("%-10i%-10i", n_frames, n_runs); + timer = g_timer_new (); + g_assert_no_error (error); + + for (guint run = 0; run < n_runs; run++) { + g_message ("Start run %i of %i", run, n_runs); + g_timer_start (timer); + + func (camera, buffer, n_frames); + + g_timer_stop (timer); + total_time += g_timer_elapsed (timer, NULL); + } + + g_assert_no_error (error); + + fps = n_runs * n_frames / total_time; + bandwidth = n_bytes * fps / 1024 / 1024; + g_print ("%-16.2f%-16.2f\n", fps, bandwidth); + + g_timer_destroy (timer); +} + +static void +benchmark (UcaCamera *camera) +{ + const guint n_runs = 3; + const guint n_frames = 100; + + guint sensor_width; + guint sensor_height; + guint roi_width; + guint roi_height; + guint bits; + guint n_bytes_per_pixel; + guint n_bytes; + gdouble exposure = 0.00001; + gpointer buffer; + + g_object_set (G_OBJECT (camera), + "exposure-time", exposure, + NULL); + + g_object_get (G_OBJECT (camera), + "sensor-width", &sensor_width, + "sensor-height", &sensor_height, + "sensor-bitdepth", &bits, + "roi-width", &roi_width, + "roi-height", &roi_height, + "exposure-time", &exposure, + NULL); + + g_print ("# --- General information ---\n"); + g_print ("# Sensor size: %ix%i\n", sensor_width, sensor_height); + g_print ("# ROI size: %ix%i\n", roi_width, roi_height); + g_print ("# Exposure time: %fs\n", exposure); + g_print ("# Bits: %i\n", bits); + + /* Synchronous frame acquisition */ + g_print ("# %-10s%-10s%-10s%-16s%-16s\n", "type", "n_frames", "n_runs", "frames/s", "MiB/s"); + g_print (" %-10s", "sync"); + + g_message ("Start synchronous benchmark"); + + n_bytes_per_pixel = bits > 8 ? 2 : 1; + n_bytes = roi_width * roi_height * n_bytes_per_pixel; + buffer = g_malloc0(n_bytes); + + benchmark_method (camera, buffer, grab_frames_sync, n_runs, n_frames, n_bytes); + + /* Asynchronous frame acquisition */ + g_object_set (G_OBJECT(camera), + "transfer-asynchronously", TRUE, + NULL); + + g_message ("Start asynchronous benchmark"); + g_print (" %-10s", "async"); + + benchmark_method (camera, buffer, grab_frames_async, n_runs, n_frames, n_bytes); + + g_free (buffer); +} + +int +main (int argc, char *argv[]) +{ + UcaPluginManager *manager; + GIOChannel *log_channel; + GError *error = NULL; + + (void) signal (SIGINT, sigint_handler); + g_type_init(); + + if (argc < 2) { + print_usage(); + return 1; + } + + log_channel = g_io_channel_new_file ("error.log", "a+", &error); + g_assert_no_error (error); + g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, log_channel); + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error, NULL); + + if (camera == NULL) { + g_error ("Initialization: %s", error->message); + return 1; + } + + benchmark (camera); + + g_object_unref (camera); + g_io_channel_shutdown (log_channel, TRUE, &error); + g_assert_no_error (error); + + return 0; +} diff --git a/bin/tools/config.h.in b/bin/tools/config.h.in new file mode 100644 index 0000000..aea5237 --- /dev/null +++ b/bin/tools/config.h.in @@ -0,0 +1 @@ +#cmakedefine HAVE_LIBTIFF diff --git a/bin/tools/gen-doc.c b/bin/tools/gen-doc.c new file mode 100644 index 0000000..d27bdd8 --- /dev/null +++ b/bin/tools/gen-doc.c @@ -0,0 +1,224 @@ +/* Copyright (C) 2012 Matthias Vogelgesang + (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 +#include "uca-plugin-manager.h" +#include "uca-camera.h" + + +static void +print_usage (void) +{ + GList *types; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + g_print ("Usage: gen-doc [ "); + types = uca_plugin_manager_get_available_cameras (manager); + + if (types == NULL) { + g_print ("] -- no camera plugin found\n"); + return; + } + + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + if (g_list_next (it) == NULL) + g_print ("%s ]\n", name); + else + g_print ("%s, ", name); + } +} + +static const gchar * +get_flags_description (GParamSpec *pspec) +{ + static const gchar *descriptions[] = { + "", + "Read-only", + "Write-only", + "Read / Write", + "" + }; + + if (pspec->flags >= 3) + return descriptions[3]; + + return descriptions[pspec->flags]; +} + +static void +print_property_toc (GParamSpec **pspecs, guint n_props) +{ + g_print ("

Properties

    "); + + for (guint i = 0; i < n_props; i++) { + GParamSpec *pspec = pspecs[i]; + const gchar *name = g_param_spec_get_name (pspec); + + g_print ("
  • \"%s\"
  • ", name, name); + } + + g_print ("
"); +} + +static void +print_value_info (GParamSpec *pspec) +{ + gchar *default_value = NULL; + GString *range = g_string_new(""); + +#define MAKE_RANGE(spec_type, fmt) \ + { \ + spec_type *spec = (spec_type *) pspec; \ + g_string_printf (range, \ + fmt" ≤ %s ≤ "fmt, \ + spec->minimum, \ + g_param_spec_get_name (pspec), \ + spec->maximum); \ + default_value = g_strdup_printf (fmt, spec->default_value); \ + } + + switch (pspec->value_type) { + case G_TYPE_BOOLEAN: + { + GParamSpecBoolean *spec = (GParamSpecBoolean *) pspec; + default_value = spec->default_value ? g_strdup ("TRUE") : g_strdup ("FALSE"); + } + break; + + case G_TYPE_UINT: + MAKE_RANGE (GParamSpecUInt, "%i"); + break; + + case G_TYPE_FLOAT: + MAKE_RANGE (GParamSpecFloat, "%.1e"); + break; + + case G_TYPE_DOUBLE: + MAKE_RANGE (GParamSpecDouble, "%.1e"); + break; + } + +#undef MAKE_RANGE + + if (g_type_is_a (pspec->value_type, G_TYPE_ENUM)) { + GParamSpecEnum *spec = (GParamSpecEnum *) pspec; + + if (spec->enum_class->n_values > 0) { + g_string_printf (range, ""); + + for (guint i = 0; i < spec->enum_class->n_values; i++) { + GEnumValue *v = &spec->enum_class->values[i]; + g_string_append_printf (range, + "", + v->value_name, v->value); + } + + g_string_append_printf (range, "
Enum nameValue
%s%i
"); + } + } + + if (range->len > 0) + g_print ("

Possible values: %s

", range->str); + + if (default_value != NULL) { + g_print ("

Default value: %s

", default_value); + g_free (default_value); + } + + g_string_free (range, TRUE); +} + +static void +print_property_descriptions (GParamSpec **pspecs, guint n_props) +{ + g_print ("

Details

"); + + for (guint i = 0; i < n_props; i++) { + GParamSpec *pspec = pspecs[i]; + const gchar *name = g_param_spec_get_name (pspec); + + g_print ("
%s
\n", name, name); + g_print ("
"); + g_print ("
\"%s\" : %s : %s
\n", + name, + g_type_name (pspec->value_type), + get_flags_description (pspec)); + g_print ("

%s

\n", g_param_spec_get_blurb (pspec)); + print_value_info (pspec); + g_print ("
"); + } + + g_print ("
"); +} + +static void +print_properties (UcaCamera *camera) +{ + GObjectClass *oclass; + GParamSpec **pspecs; + guint n_props; + + oclass = G_OBJECT_GET_CLASS (camera); + pspecs = g_object_class_list_properties (oclass, &n_props); + + print_property_toc (pspecs, n_props); + print_property_descriptions (pspecs, n_props); + + g_free (pspecs); +} + +static const gchar *html_header = "\ +\ +\ +%s — properties"; +static const gchar *html_footer = ""; + +int main(int argc, char *argv[]) +{ + UcaPluginManager *manager; + UcaCamera *camera; + gchar *name; + GError *error = NULL; + + g_type_init(); + manager = uca_plugin_manager_new (); + + if (argc < 2) { + name = g_strdup ("Basic camera"); + camera = g_object_new (UCA_TYPE_CAMERA, NULL); + } + else { + name = argv[1]; + camera = uca_plugin_manager_get_camera (manager, name, &error, NULL); + } + + if (camera == NULL) { + g_print("Error during initialization: %s\n", error->message); + print_usage(); + return 1; + } + + g_print (html_header, name); + g_print ("

Property documentation of %s

", name); + print_properties (camera); + g_print ("%s\n", html_footer); + + g_object_unref (camera); + g_object_unref (manager); +} diff --git a/bin/tools/grab.c b/bin/tools/grab.c new file mode 100644 index 0000000..972f000 --- /dev/null +++ b/bin/tools/grab.c @@ -0,0 +1,292 @@ +/* Copyright (C) 2011, 2012 Matthias Vogelgesang + (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 "config.h" + +#include +#include +#include +#include "uca-plugin-manager.h" +#include "uca-camera.h" +#include "ring-buffer.h" + +#ifdef HAVE_LIBTIFF +#include +#endif + + +typedef struct { + gint n_frames; + gdouble duration; + gchar *filename; +} Options; + + +static gchar * +get_camera_list (void) +{ + GList *types; + GString *str; + UcaPluginManager *manager; + + manager = uca_plugin_manager_new (); + types = uca_plugin_manager_get_available_cameras (manager); + str = g_string_new ("[ "); + + if (types != NULL) { + for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { + gchar *name = (gchar *) it->data; + + if (g_list_next (it) == NULL) + g_string_append_printf (str, "%s ]", name); + else + g_string_append_printf (str, "%s, ", name); + } + } + else { + g_string_append (str, "]"); + } + + g_object_unref (manager); + return g_string_free (str, FALSE); +} + +static guint +get_bytes_per_pixel (guint bits_per_pixel) +{ + return bits_per_pixel > 8 ? 2 : 1; +} + +#ifdef HAVE_LIBTIFF +static void +write_tiff (RingBuffer *buffer, + Options *opts, + guint width, + guint height, + guint bits_per_pixel) +{ + TIFF *tif; + guint32 rows_per_strip; + guint n_frames; + guint bits_per_sample; + gsize bytes_per_pixel; + + if (opts->filename) + tif = TIFFOpen (opts->filename, "w"); + else + tif = TIFFOpen ("frames.tif", "w"); + + n_frames = ring_buffer_get_num_blocks (buffer); + rows_per_strip = TIFFDefaultStripSize (tif, (guint32) - 1); + bytes_per_pixel = get_bytes_per_pixel (bits_per_pixel); + bits_per_sample = bits_per_pixel > 8 ? 16 : 8; + + /* Write multi page TIFF file */ + TIFFSetField (tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + + for (guint i = 0; i < n_frames; i++) { + gpointer data; + gsize offset = 0; + + data = ring_buffer_get_pointer (buffer, i); + + TIFFSetField (tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField (tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, bits_per_sample); + TIFFSetField (tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField (tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip); + TIFFSetField (tif, TIFFTAG_PAGENUMBER, i, n_frames); + + for (guint y = 0; y < height; y++, offset += width * bytes_per_pixel) + TIFFWriteScanline (tif, data + offset, y, 0); + + TIFFWriteDirectory (tif); + } + + TIFFClose (tif); +} +#else +static void +write_raw (RingBuffer *buffer, + Options *opts) +{ + guint n_frames; + gsize size; + + size = ring_buffer_get_block_size (buffer); + n_frames = ring_buffer_get_num_blocks (buffer); + + for (gint i = 0; i < n_frames; i++) { + FILE *fp; + gchar *filename; + gpointer data; + + if (opts->filename) + filename = g_strdup_printf ("%s-%08i.raw", opts->filename, i); + else + filename = g_strdup_printf ("frame-%08i.raw", i); + + fp = fopen(filename, "wb"); + data = ring_buffer_get_pointer (buffer, i); + + fwrite (data, size, 1, fp); + fclose (fp); + g_free (filename); + } +} +#endif + +static GError * +record_frames (UcaCamera *camera, Options *opts) +{ + guint roi_width; + guint roi_height; + guint bits; + guint pixel_size; + gsize size; + gint n_frames; + guint n_allocated; + GTimer *timer; + RingBuffer *buffer; + GError *error = NULL; + gdouble last_printed; + + g_object_get (G_OBJECT (camera), + "roi-width", &roi_width, + "roi-height", &roi_height, + "sensor-bitdepth", &bits, + NULL); + + pixel_size = get_bytes_per_pixel (bits); + size = roi_width * roi_height * pixel_size; + n_allocated = opts->n_frames > 0 ? opts->n_frames : 256; + buffer = ring_buffer_new (size, n_allocated); + timer = g_timer_new(); + + g_print("Start recording: %ix%i at %i bits/pixel\n", + roi_width, roi_height, bits); + + uca_camera_start_recording(camera, &error); + + if (error != NULL) + return error; + + n_frames = 0; + g_timer_start(timer); + last_printed = 0.0; + + while (1) { + gdouble elapsed; + + uca_camera_grab (camera, ring_buffer_get_current_pointer (buffer), &error); + ring_buffer_proceed (buffer); + + if (error != NULL) + return error; + + n_frames++; + elapsed = g_timer_elapsed (timer, NULL); + + if (n_frames == opts->n_frames || (opts->duration > 0.0 && elapsed >= opts->duration)) + break; + + if (elapsed - last_printed >= 1.0) { + g_print ("Recorded %i frames at %.2f frames/s\n", + n_frames, n_frames / elapsed); + last_printed = elapsed; + } + } + + g_print ("Stop recording: %3.2f frames/s\n", + n_frames / g_timer_elapsed (timer, NULL)); + + uca_camera_stop_recording (camera, &error); + +#ifdef HAVE_LIBTIFF + write_tiff (buffer, opts, roi_width, roi_height, bits); +#else + write_raw (buffer, opts); +#endif + + ring_buffer_free (buffer); + g_timer_destroy (timer); + + return error; +} + +int +main (int argc, char *argv[]) +{ + GOptionContext *context; + UcaPluginManager *manager; + UcaCamera *camera; + gchar *cam_list; + GError *error = NULL; + + static Options opts = { + .n_frames = -1, + .duration = -1.0, + .filename = NULL + }; + + static GOptionEntry entries[] = { + { "num-frames", 'n', 0, G_OPTION_ARG_INT, &opts.n_frames, "Number of frames to acquire", "N" }, + { "duration", 'd', 0, G_OPTION_ARG_DOUBLE, &opts.duration, "Duration in seconds", NULL }, + { "output", 'o', 0, G_OPTION_ARG_STRING, &opts.filename, "Output file name", "FILE" }, + { NULL } + }; + + g_type_init(); + + cam_list = get_camera_list (); + context = g_option_context_new (cam_list); + g_option_context_add_main_entries (context, entries, NULL); + g_free (cam_list); + + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_print ("Failed parsing arguments: %s\n", error->message); + exit (1); + } + + if (argc < 2) { + g_print ("%s\n", g_option_context_get_help (context, TRUE, NULL)); + exit (0); + } + + if (opts.n_frames < 0 && opts.duration < 0.0) { + g_print ("You must specify at least one of --num-frames and --output.\n"); + exit (1); + } + + manager = uca_plugin_manager_new (); + camera = uca_plugin_manager_get_camera (manager, argv[1], &error, NULL); + + if (camera == NULL) { + g_print ("Error during initialization: %s\n", error->message); + exit (1); + } + + error = record_frames (camera, &opts); + + if (error != NULL) + g_print ("Error: %s\n", error->message); + + g_object_unref (camera); + return error != NULL ? 1 : 0; +} diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt deleted file mode 100644 index f0d90c3..0000000 --- a/gui/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -add_definitions("--std=c99 -Wall") - -# --- Find packages and libraries --------------------------------------------- -find_package(PkgConfig) - -pkg_check_modules(GTK2 gtk+-2.0>=2.22) -pkg_check_modules(GTHREAD2 gthread-2.0) -pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) -pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/control.glade - ${CMAKE_CURRENT_BINARY_DIR}) - -# --- Build targets ----------------------------------------------------------- -include_directories( - ${GLIB2_INCLUDE_DIRS} - ${GOBJECT2_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/../src - ${CMAKE_CURRENT_SOURCE_DIR}/../tools - ) - -message("include: ${CMAKE_CURRENT_BINARY_DIR}") - -if (GTK2_FOUND) - include_directories(${GTK2_INCLUDE_DIRS}) - - add_executable(control - control.c - ../tools/ring-buffer.c # yes this sucks and should be fixed - egg-property-cell-renderer.c - egg-property-tree-view.c - egg-histogram-view.c) - - target_link_libraries(control uca - ${GTK2_LIBRARIES} - ${GTHREAD2_LIBRARIES} - m) - - install(TARGETS control - RUNTIME DESTINATION bin) - - install(FILES control.glade - DESTINATION share/libuca) -endif() diff --git a/gui/config.h.in b/gui/config.h.in deleted file mode 100644 index e7de9c6..0000000 --- a/gui/config.h.in +++ /dev/null @@ -1 +0,0 @@ -#define CONTROL_GLADE_PATH "${CMAKE_INSTALL_PREFIX}/share/libuca/control.glade" diff --git a/gui/control.c b/gui/control.c deleted file mode 100644 index c177f07..0000000 --- a/gui/control.c +++ /dev/null @@ -1,662 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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 -#include -#include -#include -#include - -#include "config.h" -#include "ring-buffer.h" -#include "uca-camera.h" -#include "uca-plugin-manager.h" -#include "egg-property-tree-view.h" -#include "egg-histogram-view.h" - -typedef enum { - IDLE, - RUNNING, - RECORDING -} State; - -typedef struct { - UcaCamera *camera; - GtkWidget *main_window; - GdkPixbuf *pixbuf; - GtkWidget *image; - GtkWidget *start_button; - GtkWidget *stop_button; - GtkWidget *record_button; - GtkWidget *download_button; - GtkComboBox *zoom_box; - - GtkDialog *download_dialog; - GtkProgressBar *download_progressbar; - GtkWidget *download_close_button; - GtkAdjustment *download_adjustment; - - GtkWidget *histogram_view; - GtkToggleButton *histogram_button; - GtkAdjustment *frame_slider; - - RingBuffer *buffer; - guchar *pixels; - gint display_width, display_height; - gdouble zoom_factor; - State state; - gboolean data_in_camram; - - gint timestamp; - gint width, height; - gint pixel_size; -} ThreadData; - -static UcaPluginManager *plugin_manager; -static gsize mem_size = 2048; - -static void -convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) -{ - gdouble min; - gdouble max; - gdouble factor; - guint8 *output; - gint i = 0; - gint stride; - - egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min, &max); - factor = 255.0 / (max - min); - output = data->pixels; - stride = (gint) 1 / data->zoom_factor; - - if (data->pixel_size == 1) { - guint8 *input = (guint8 *) buffer; - - for (gint y = 0; y < data->display_height; y++) { - gint offset = y * stride * data->width; - - for (gint x = 0; x < data->display_width; x++, offset += stride) { - gdouble dval = (input[offset] - min) * factor; - guchar val = (guchar) CLAMP(dval, 0.0, 255.0); - - output[i++] = val; - output[i++] = val; - output[i++] = val; - } - } - } - else if (data->pixel_size == 2) { - guint16 *input = (guint16 *) buffer; - - for (gint y = 0; y < data->display_height; y++) { - gint offset = y * stride * data->width; - - for (gint x = 0; x < data->display_width; x++, offset += stride) { - gdouble dval = (input[offset] - min) * factor; - guchar val = (guchar) CLAMP(dval, 0.0, 255.0); - - output[i++] = val; - output[i++] = val; - output[i++] = val; - } - } - } -} - -static void -update_pixbuf (ThreadData *data) -{ - gdk_flush (); - gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); - gtk_widget_queue_draw_area (data->image, 0, 0, data->display_width, data->display_height); - - if (gtk_toggle_button_get_active (data->histogram_button)) - gtk_widget_queue_draw (data->histogram_view); -} - -static void -update_pixbuf_dimensions (ThreadData *data) -{ - if (data->pixbuf != NULL) - g_object_unref (data->pixbuf); - - data->display_width = (gint) data->width * data->zoom_factor; - data->display_height = (gint) data->height * data->zoom_factor; - data->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, data->display_width, data->display_height); - data->pixels = gdk_pixbuf_get_pixels (data->pixbuf); - gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); -} - -static void -print_and_free_error (GError **error) -{ - g_printerr ("%s\n", (*error)->message); - g_error_free (*error); - *error = NULL; -} - -static gpointer -preview_frames (void *args) -{ - ThreadData *data = (ThreadData *) args; - gint counter = 0; - GError *error = NULL;; - - while (data->state == RUNNING) { - gpointer buffer; - - buffer = ring_buffer_get_current_pointer (data->buffer); - uca_camera_trigger (data->camera, &error); - uca_camera_grab (data->camera, buffer, &error); - - if (error == NULL) { - convert_grayscale_to_rgb (data, buffer); - - gdk_threads_enter (); - update_pixbuf (data); - gdk_threads_leave (); - - counter++; - } - else - print_and_free_error (&error); - } - return NULL; -} - -static gpointer -record_frames (gpointer args) -{ - ThreadData *data; - gpointer buffer; - guint n_frames = 0; - GError *error = NULL; - - data = (ThreadData *) args; - ring_buffer_reset (data->buffer); - - while (data->state == RECORDING) { - buffer = ring_buffer_get_current_pointer (data->buffer); - uca_camera_grab (data->camera, buffer, NULL); - - if (error == NULL) { - ring_buffer_proceed (data->buffer); - n_frames++; - } - else - print_and_free_error (&error); - } - - n_frames = ring_buffer_get_num_blocks (data->buffer); - - gdk_threads_enter (); - gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); - gtk_adjustment_set_value (data->frame_slider, n_frames - 1); - gdk_threads_leave (); - - return NULL; -} - -gboolean -on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - return FALSE; -} - -void -on_destroy (GtkWidget *widget, ThreadData *data) -{ - data->state = IDLE; - g_object_unref (data->camera); - ring_buffer_free (data->buffer); - - gtk_main_quit (); -} - -static void -set_tool_button_state (ThreadData *data) -{ - gtk_widget_set_sensitive (data->start_button, - data->state == IDLE); - gtk_widget_set_sensitive (data->stop_button, - data->state == RUNNING || data->state == RECORDING); - gtk_widget_set_sensitive (data->record_button, - data->state == IDLE); - gtk_widget_set_sensitive (data->download_button, - data->data_in_camram); - gtk_widget_set_sensitive (GTK_WIDGET (data->zoom_box), - data->state == IDLE); -} - -static void -update_current_frame (ThreadData *data) -{ - gpointer buffer; - gint index; - - index = (gint) gtk_adjustment_get_value (data->frame_slider); - buffer = ring_buffer_get_pointer (data->buffer, index); - convert_grayscale_to_rgb (data, buffer); - update_pixbuf (data); -} - -static void -on_frame_slider_changed (GtkAdjustment *adjustment, ThreadData *data) -{ - if (data->state == IDLE) - update_current_frame (data); -} - -static void -on_start_button_clicked (GtkWidget *widget, ThreadData *data) -{ - GError *error = NULL; - - uca_camera_start_recording (data->camera, &error); - - if (error != NULL) { - g_printerr ("Failed to start recording: %s\n", error->message); - return; - } - - data->state = RUNNING; - set_tool_button_state (data); - - if (!g_thread_create (preview_frames, data, FALSE, &error)) { - g_printerr ("Failed to create thread: %s\n", error->message); - data->state = IDLE; - set_tool_button_state (data); - } -} - -static void -on_stop_button_clicked (GtkWidget *widget, ThreadData *data) -{ - GError *error = NULL; - - g_object_get (data->camera, "has-camram-recording", &data->data_in_camram, NULL); - data->state = IDLE; - set_tool_button_state (data); - uca_camera_stop_recording (data->camera, &error); - - if (error != NULL) - g_printerr ("Failed to stop: %s\n", error->message); - -} - -static void -on_record_button_clicked (GtkWidget *widget, ThreadData *data) -{ - GError *error = NULL; - - uca_camera_start_recording (data->camera, &error); - - if (error != NULL) { - g_printerr ("Failed to start recording: %s\n", error->message); - } - - data->timestamp = (int) time (0); - data->state = RECORDING; - set_tool_button_state (data); - - if (!g_thread_create (record_frames, data, FALSE, &error)) { - g_printerr ("Failed to create thread: %s\n", error->message); - data->state = IDLE; - set_tool_button_state (data); - } -} - -static gpointer -download_frames (ThreadData *data) -{ - gpointer buffer; - guint n_frames; - guint current_frame = 1; - GError *error = NULL; - - g_object_get (data->camera, "recorded-frames", &n_frames, NULL); - gdk_threads_enter (); - gtk_widget_set_sensitive (data->download_close_button, FALSE); - gtk_adjustment_set_upper (data->download_adjustment, n_frames); - gdk_threads_leave (); - - uca_camera_start_readout (data->camera, &error); - - if (error != NULL) { - g_printerr ("Failed to start read out of camera memory: %s\n", error->message); - return NULL; - } - - ring_buffer_reset (data->buffer); - - while (error == NULL) { - buffer = ring_buffer_get_current_pointer (data->buffer); - uca_camera_grab (data->camera, buffer, &error); - ring_buffer_proceed (data->buffer); - gdk_threads_enter (); - gtk_adjustment_set_value (data->download_adjustment, current_frame++); - gdk_threads_leave (); - } - - if (error->code == UCA_CAMERA_ERROR_END_OF_STREAM) { - guint n_frames = ring_buffer_get_num_blocks (data->buffer); - - gtk_adjustment_set_upper (data->frame_slider, n_frames - 1); - gtk_adjustment_set_value (data->frame_slider, n_frames - 1); - } - else - g_printerr ("Error while reading out frames: %s\n", error->message); - - g_error_free (error); - error = NULL; - - uca_camera_stop_readout (data->camera, &error); - - if (error != NULL) - g_printerr ("Failed to stop reading out of camera memory: %s\n", error->message); - - gdk_threads_enter (); - gtk_widget_set_sensitive (data->download_close_button, TRUE); - gdk_threads_leave (); - - return NULL; -} - -static void -on_download_button_clicked (GtkWidget *widget, ThreadData *data) -{ - GError *error = NULL; - - if (!g_thread_create ((GThreadFunc) download_frames, data, FALSE, &error)) { - g_printerr ("Failed to create thread: %s\n", error->message); - } - - gtk_widget_set_sensitive (data->main_window, FALSE); - gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); - gtk_dialog_run (data->download_dialog); - gtk_widget_hide (GTK_WIDGET (data->download_dialog)); - gtk_window_set_modal (GTK_WINDOW (data->download_dialog), FALSE); - gtk_widget_set_sensitive (data->main_window, TRUE); - gtk_window_set_modal (GTK_WINDOW (data->download_dialog), TRUE); -} - -static void -on_histogram_changed (EggHistogramView *view, ThreadData *data) -{ - if (data->state == IDLE) - update_current_frame (data); -} - -static void -on_zoom_changed (GtkComboBox *widget, ThreadData *data) -{ - GtkTreeModel *model; - GtkTreeIter iter; - gdouble factor; - - enum { - DISPLAY_COLUMN, - FACTOR_COLUMN - }; - - model = gtk_combo_box_get_model (widget); - gtk_combo_box_get_active_iter (widget, &iter); - gtk_tree_model_get (model, &iter, FACTOR_COLUMN, &factor, -1); - - data->zoom_factor = factor; - update_pixbuf_dimensions (data); -} - -static void -on_roi_width_changed (GObject *object, GParamSpec *pspec, ThreadData *data) -{ - g_object_get (object, "roi-width", &data->width, NULL); - update_pixbuf_dimensions (data); -} - -static void -on_roi_height_changed (GObject *object, GParamSpec *pspec, ThreadData *data) -{ - g_object_get (object, "roi-height", &data->height, NULL); - update_pixbuf_dimensions (data); -} - -static void -create_main_window (GtkBuilder *builder, const gchar* camera_name) -{ - static ThreadData td; - UcaCamera *camera; - GtkWidget *window; - GtkWidget *image; - GtkWidget *histogram_view; - GtkWidget *property_tree_view; - GdkPixbuf *pixbuf; - GtkBox *histogram_box; - GtkContainer *property_window; - GtkAdjustment *max_bin_adjustment; - RingBuffer *ring_buffer; - gsize image_size; - guint n_frames; - guint bits_per_sample; - guint pixel_size; - guint width, height; - GError *error = NULL; - - camera = uca_plugin_manager_get_camera (plugin_manager, camera_name, &error, NULL); - - if ((camera == NULL) || (error != NULL)) { - g_error ("%s\n", error->message); - gtk_main_quit (); - } - - g_object_get (camera, - "roi-width", &width, - "roi-height", &height, - "sensor-bitdepth", &bits_per_sample, - NULL); - - g_signal_connect (camera, "notify::roi-width", (GCallback) on_roi_width_changed, &td); - g_signal_connect (camera, "notify::roi-height", (GCallback) on_roi_height_changed, &td); - - histogram_view = egg_histogram_view_new (); - property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); - property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "property-window")); - image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); - histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); - window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); - max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max-bin-value-adjustment")); - - td.zoom_box = GTK_COMBO_BOX (gtk_builder_get_object (builder, "zoom-box")); - td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); - td.stop_button = GTK_WIDGET (gtk_builder_get_object (builder, "stop-button")); - td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); - td.download_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-button")); - td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); - td.frame_slider = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "frames-adjustment")); - - td.download_dialog = GTK_DIALOG (gtk_builder_get_object (builder, "download-dialog")); - td.download_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "download-adjustment")); - td.download_close_button = GTK_WIDGET (gtk_builder_get_object (builder, "download-close-button")); - - /* Set initial data */ - pixel_size = bits_per_sample > 8 ? 2 : 1; - image_size = pixel_size * width * height; - n_frames = mem_size * 1024 * 1024 / image_size; - ring_buffer = ring_buffer_new (image_size, n_frames); - - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (histogram_view), - ring_buffer_get_current_pointer (ring_buffer), - width * height, bits_per_sample, 256); - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height); - gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); - - gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); - - g_message ("Allocated memory for %d frames", n_frames); - - td.pixel_size = pixel_size; - td.image = image; - td.pixbuf = NULL; - td.pixels = NULL; - td.buffer = ring_buffer; - td.state = IDLE; - td.camera = camera; - td.width = td.display_width = width; - td.height = td.display_height = height; - td.zoom_factor = 1.0; - td.histogram_view = histogram_view; - td.data_in_camram = FALSE; - td.main_window = window; - - update_pixbuf_dimensions (&td); - set_tool_button_state (&td); - - /* Hook up signals */ - g_object_bind_property (gtk_builder_get_object (builder, "min-bin-value-adjustment"), "value", - td.histogram_view, "minimum-bin-value", - G_BINDING_DEFAULT); - - g_object_bind_property (max_bin_adjustment, "value", - td.histogram_view, "maximum-bin-value", - G_BINDING_DEFAULT); - - g_signal_connect (td.frame_slider, "value-changed", G_CALLBACK (on_frame_slider_changed), &td); - g_signal_connect (td.start_button, "clicked", G_CALLBACK (on_start_button_clicked), &td); - g_signal_connect (td.stop_button, "clicked", G_CALLBACK (on_stop_button_clicked), &td); - g_signal_connect (td.record_button, "clicked", G_CALLBACK (on_record_button_clicked), &td); - g_signal_connect (td.download_button, "clicked", G_CALLBACK (on_download_button_clicked), &td); - g_signal_connect (td.zoom_box, "changed", G_CALLBACK (on_zoom_changed), &td); - g_signal_connect (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); - g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); - - /* Layout */ - gtk_container_add (property_window, property_tree_view); - gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); - - gtk_widget_show_all (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, "proceed-button")); - 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[]) -{ - GtkBuilder *builder; - GOptionContext *context; - GError *error = NULL; - - static GOptionEntry entries[] = - { - { "mem-size", 'm', 0, G_OPTION_ARG_INT, &mem_size, "Memory in megabytes to allocate for frame storage", "M" }, - { NULL } - }; - - context = g_option_context_new ("- control libuca cameras"); - g_option_context_add_main_entries (context, entries, NULL); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("Option parsing failed: %s\n", error->message); - return 1; - } - - g_thread_init (NULL); - gdk_threads_init (); - gtk_init (&argc, &argv); - - builder = gtk_builder_new (); - - if (!gtk_builder_add_from_file (builder, CONTROL_GLADE_PATH, &error)) { - g_print ("Could not load UI file: %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/gui/control.glade b/gui/control.glade deleted file mode 100644 index eec9dde..0000000 --- a/gui/control.glade +++ /dev/null @@ -1,635 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - Camera Control - 1024 - 768 - - - - True - - - True - - - True - _File - True - - - True - - - gtk-new - True - True - True - - - - - gtk-open - True - True - True - - - - - gtk-save - True - True - True - - - - - gtk-save-as - True - True - True - - - - - True - - - - - gtk-quit - True - True - True - - - - - - - - - - True - _Help - True - - - True - - - gtk-about - True - True - True - - - - - - - - - False - 0 - - - - - True - - - True - Run - True - gtk-media-play - - - False - True - - - - - True - Record - True - gtk-media-record - - - False - True - - - - - True - Stop - True - gtk-media-stop - - - False - True - - - - - True - Download - True - network-receive - - - False - True - - - - - False - 1 - - - - - True - True - 6 - - - True - True - - - 640 - 480 - True - True - automatic - automatic - - - True - queue - - - True - gtk-missing-image - - - - - - - True - True - - - - - True - True - - - True - 10 - - - - - - True - 6 - 3 - 2 - 6 - 6 - - - True - 1 - Minimum Value: - - - GTK_FILL - - 6 - 6 - - - - - 100 - True - True - - min-bin-value-adjustment - - - 1 - 2 - GTK_EXPAND - - - - - - True - 1 - Maximum Value: - - - 1 - 2 - GTK_FILL - - 6 - 6 - - - - - 100 - True - True - - max-bin-value-adjustment - - - 1 - 2 - 1 - 2 - GTK_EXPAND - - - - - - Live Update - True - True - False - 6 - True - True - - - 2 - 3 - - - - - - - - - - False - False - 1 - - - - - - - True - Histogram - - - False - - - - - True - 10 - 2 - 2 - 6 - 6 - - - True - True - frames-adjustment - 0 - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - 1 - Frame: - - - 1 - 2 - GTK_FILL - - - - - - True - 1 - Zoom: - - - GTK_FILL - - - - - - True - zoom-values - - - - 0 - - - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - 1 - - - - - True - Preview - - - 1 - False - - - - - True - True - - - - - False - True - - - - - True - True - automatic - automatic - - - - - - True - True - - - - - 2 - - - - - - - - - - - - - - - 100 % - 1 - - - 50 % - 0.5 - - - 25 % - 0.25 - - - - - 6 - - - True - 2 - - - True - True - automatic - automatic - - - True - True - camera-types - False - 0 - - - Choose camera - - - - 0 - - - - - - - - - 0 - - - - - True - 6 - end - - - gtk-quit - True - True - True - True - - - - False - False - 0 - - - - - gtk-ok - True - True - True - True - - - False - False - 1 - - - - - False - 6 - 1 - - - - - - - 65535 - 1 - 10 - - - 256 - 65535 - 1 - 10 - - - 1 - 10 - - - 5 - normal - - - True - 2 - - - True - 10 - 6 - - - True - 0 - Downloading Frames … - - - False - False - 0 - - - - - True - download-adjustment - - - False - 1 - - - - - 1 - - - - - True - end - - - gtk-close - True - True - True - True - - - False - False - 0 - - - - - False - False - end - 0 - - - - - - download-close-button - - - - 100 - 1 - 10 - 10 - - diff --git a/gui/egg-histogram-view.c b/gui/egg-histogram-view.c deleted file mode 100644 index 812af7a..0000000 --- a/gui/egg-histogram-view.c +++ /dev/null @@ -1,524 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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 -#include "egg-histogram-view.h" - -G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_DRAWING_AREA) - -#define EGG_HISTOGRAM_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewPrivate)) - -#define MIN_WIDTH 128 -#define MIN_HEIGHT 128 -#define BORDER 2 - -struct _EggHistogramViewPrivate -{ - GdkCursorType cursor_type; - gboolean grabbing; - - /* This could be moved into a real histogram class */ - guint n_bins; - gint *bins; - gint *grabbed; - gint min_border; /* threshold set in screen units */ - gint max_border; - - gdouble min_value; /* lowest value of the first bin */ - gdouble max_value; /* highest value of the last bin */ - gdouble range; - - gpointer data; - gint n_elements; - gint n_bits; -}; - -enum -{ - PROP_0, - PROP_MINIMUM_BIN_VALUE, - PROP_MAXIMUM_BIN_VALUE, - N_PROPERTIES -}; - -enum -{ - CHANGED, - LAST_SIGNAL -}; - -static GParamSpec *egg_histogram_view_properties[N_PROPERTIES] = { NULL, }; - -static guint egg_histogram_view_signals[LAST_SIGNAL] = { 0 }; - - -GtkWidget * -egg_histogram_view_new (void) -{ - EggHistogramView *view; - - view = EGG_HISTOGRAM_VIEW (g_object_new (EGG_TYPE_HISTOGRAM_VIEW, NULL)); - return GTK_WIDGET (view); -} - -void -egg_histogram_view_set_data (EggHistogramView *view, - gpointer data, - guint n_elements, - guint n_bits, - guint n_bins) -{ - EggHistogramViewPrivate *priv; - - g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); - priv = view->priv; - - if (priv->bins != NULL) - g_free (priv->bins); - - priv->data = data; - priv->bins = g_malloc0 (n_bins * sizeof (guint)); - priv->n_bins = n_bins; - priv->n_bits = n_bits; - priv->n_elements = n_elements; - - priv->min_value = 0.0; - priv->max_value = (gint) pow(2, n_bits) - 1; - - priv->min_border = 0; - priv->max_border = 256; - priv->range = priv->max_value - priv->min_value; -} - -void -egg_histogram_get_visible_range (EggHistogramView *view, gdouble *min, gdouble *max) -{ - EggHistogramViewPrivate *priv; - GtkAllocation allocation; - gdouble width; - - g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); - - gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); - width = (gdouble) allocation.width - 2 * BORDER; - priv = view->priv; - - *min = (priv->min_border - 2) / width * priv->range; - *max = (priv->max_border - 2) / width * priv->range; -} - -static void -set_max_border (EggHistogramView *view) -{ - GtkAllocation allocation; - - g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); - gtk_widget_get_allocation (GTK_WIDGET (view), &allocation); - view->priv->max_border = allocation.width - 2 * BORDER; -} - -static void -compute_histogram (EggHistogramViewPrivate *priv) -{ - guint n_bins = priv->n_bins - 1; - - for (guint i = 0; i < priv->n_bins; i++) - priv->bins[i] = 0; - - if (priv->n_bits == 8) { - guint8 *data = (guint8 *) priv->data; - - for (guint i = 0; i < priv->n_elements; i++) { - guint8 v = data[i]; - - if (v >= priv->min_value && v <= priv->max_value) { - guint index = (guint) round (((gdouble) v) / priv->max_value * n_bins); - priv->bins[index]++; - } - } - } - else { - guint16 *data = (guint16 *) priv->data; - - for (guint i = 0; i < priv->n_elements; i++) { - guint16 v = data[i]; - - if (v >= priv->min_value && v <= priv->max_value) { - guint index = (guint) floor (((gdouble ) v) / priv->max_value * n_bins); - priv->bins[index]++; - } - } - } -} - -static void -set_cursor_type (EggHistogramView *view, GdkCursorType cursor_type) -{ - if (cursor_type != view->priv->cursor_type) { - GdkCursor *cursor = gdk_cursor_new (cursor_type); - - gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET(view)), cursor); - gdk_cursor_unref (cursor); - view->priv->cursor_type = cursor_type; - } -} - -static void -egg_histogram_view_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - requisition->width = MIN_WIDTH; - requisition->height = MIN_HEIGHT; -} - -static void -draw_bins (EggHistogramViewPrivate *priv, - cairo_t *cr, - gint width, - gint height) -{ - gdouble skip = ((gdouble) width) / priv->n_bins; - gdouble x = BORDER; - gdouble ys = height + BORDER - 1; - gint max_value = 0; - - for (guint i = 0; i < priv->n_bins; i++) { - if (priv->bins[i] > max_value) - max_value = priv->bins[i]; - } - - if (max_value == 0) - return; - - for (guint i = 0; i < priv->n_bins && x < (width - BORDER); i++, x += skip) { - if (priv->bins[i] == 0) - continue; - - gint y = (gint) ((height - 2) * priv->bins[i]) / max_value; - cairo_move_to (cr, round (x), ys); - cairo_line_to (cr, round (x), ys - y); - cairo_stroke (cr); - } -} - -static gboolean -egg_histogram_view_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - EggHistogramViewPrivate *priv; - GtkAllocation allocation; - GtkStyle *style; - cairo_t *cr; - gint width, height; - - priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (widget); - cr = gdk_cairo_create (gtk_widget_get_window (widget)); - - gdk_cairo_region (cr, event->region); - cairo_clip (cr); - - style = gtk_widget_get_style (widget); - gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); - cairo_paint (cr); - - /* Draw the background */ - gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]); - cairo_paint (cr); - - gtk_widget_get_allocation (widget, &allocation); - width = allocation.width - 2 * BORDER; - height = allocation.height - 2 * BORDER; - - gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); - cairo_set_line_width (cr, 1.0); - cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); - cairo_translate (cr, 0.5, 0.5); - cairo_rectangle (cr, BORDER, BORDER, width - 1, height - 1); - cairo_stroke (cr); - - if (priv->bins == NULL) - goto cleanup; - - compute_histogram (priv); - - /* Draw border areas */ - gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); - - cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); - cairo_fill (cr); - - cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->max_border + 0.5, height - 1); - cairo_fill (cr); - - /* Draw spikes */ - gdk_cairo_set_source_color (cr, &style->black); - draw_bins (priv, cr, width, height); - -cleanup: - cairo_destroy (cr); - return FALSE; -} - -static void -egg_histogram_view_finalize (GObject *object) -{ - EggHistogramViewPrivate *priv; - - priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); - - if (priv->bins) - g_free (priv->bins); - - G_OBJECT_CLASS (egg_histogram_view_parent_class)->finalize (object); -} - -static void -egg_histogram_view_dispose (GObject *object) -{ - G_OBJECT_CLASS (egg_histogram_view_parent_class)->dispose (object); -} - -static void -egg_histogram_view_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - EggHistogramViewPrivate *priv; - - g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); - priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); - - switch (property_id) { - case PROP_MINIMUM_BIN_VALUE: - { - gdouble v = g_value_get_double (value); - - if (v > priv->max_value) - g_warning ("Minimum value `%f' larger than maximum value `%f'", - v, priv->max_value); - else { - priv->min_value = v; - priv->range = priv->max_value - v; - priv->min_border = 0; - } - } - break; - - case PROP_MAXIMUM_BIN_VALUE: - { - gdouble v = g_value_get_double (value); - - if (v < priv->min_value) - g_warning ("Maximum value `%f' larger than minimum value `%f'", - v, priv->min_value); - else { - priv->max_value = v; - priv->range = v - priv->min_value; - set_max_border (EGG_HISTOGRAM_VIEW (object)); - } - } - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - return; - } -} - -static void -egg_histogram_view_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - EggHistogramViewPrivate *priv; - - g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); - priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (object); - - switch (property_id) { - case PROP_MINIMUM_BIN_VALUE: - g_value_set_double (value, priv->min_value); - break; - - case PROP_MAXIMUM_BIN_VALUE: - g_value_set_double (value, priv->max_value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - return; - } -} - -static gboolean -is_on_border (EggHistogramViewPrivate *priv, - gint x) -{ - gint d1 = (priv->min_border + BORDER) - x; - gint d2 = (priv->max_border + BORDER) - x; - return ABS (d1) < 6 || ABS (d2) < 6; -} - -static gint * -get_grabbed_border (EggHistogramViewPrivate *priv, - gint x) -{ - gint d1 = (priv->min_border + BORDER) - x; - gint d2 = (priv->max_border + BORDER) - x; - - if (ABS (d1) < 6) - return &priv->min_border; - else if (ABS (d2) < 6) - return &priv->max_border; - - return NULL; -} - -static gboolean -egg_histogram_view_motion_notify (GtkWidget *widget, - GdkEventMotion *event) -{ - EggHistogramView *view; - EggHistogramViewPrivate *priv; - - view = EGG_HISTOGRAM_VIEW (widget); - priv = view->priv; - - if (priv->grabbing) { - GtkAllocation allocation; - - gtk_widget_get_allocation (widget, &allocation); - - if ((event->x + BORDER > 0) && (event->x + BORDER < allocation.width)) { - *priv->grabbed = event->x; - gtk_widget_queue_draw (widget); - } - } - else { - if (is_on_border (priv, event->x)) - set_cursor_type (view, GDK_FLEUR); - else - set_cursor_type (view, GDK_ARROW); - } - - return TRUE; -} - -static gboolean -egg_histogram_view_button_release (GtkWidget *widget, - GdkEventButton *event) -{ - EggHistogramView *view; - - view = EGG_HISTOGRAM_VIEW (widget); - set_cursor_type (view, GDK_ARROW); - view->priv->grabbing = FALSE; - g_signal_emit (widget, egg_histogram_view_signals[CHANGED], 0); - - return TRUE; -} - -static gboolean -egg_histogram_view_button_press (GtkWidget *widget, - GdkEventButton *event) -{ - EggHistogramView *view; - EggHistogramViewPrivate *priv; - - view = EGG_HISTOGRAM_VIEW (widget); - priv = view->priv; - - if (is_on_border (priv, event->x)) { - priv->grabbing = TRUE; - priv->grabbed = get_grabbed_border (priv, event->x); - set_cursor_type (view, GDK_FLEUR); - } - - return TRUE; -} - -static void -egg_histogram_view_class_init (EggHistogramViewClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - object_class->set_property = egg_histogram_view_set_property; - object_class->get_property = egg_histogram_view_get_property; - object_class->dispose = egg_histogram_view_dispose; - object_class->finalize = egg_histogram_view_finalize; - - widget_class->size_request = egg_histogram_view_size_request; - widget_class->expose_event = egg_histogram_view_expose; - widget_class->button_press_event = egg_histogram_view_button_press; - widget_class->button_release_event = egg_histogram_view_button_release; - widget_class->motion_notify_event = egg_histogram_view_motion_notify; - - egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE] = - g_param_spec_double ("minimum-bin-value", - "Smallest possible bin value", - "Smallest possible bin value, everything below is discarded.", - 0.0, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE); - - egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE] = - g_param_spec_double ("maximum-bin-value", - "Largest possible bin value", - "Largest possible bin value, everything above is discarded.", - 0.0, G_MAXDOUBLE, 256.0, - G_PARAM_READWRITE); - - g_object_class_install_property (object_class, PROP_MINIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MINIMUM_BIN_VALUE]); - g_object_class_install_property (object_class, PROP_MAXIMUM_BIN_VALUE, egg_histogram_view_properties[PROP_MAXIMUM_BIN_VALUE]); - - egg_histogram_view_signals[CHANGED] = - g_signal_new ("changed", - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, - G_STRUCT_OFFSET (EggHistogramViewClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); -} - -static void -egg_histogram_view_init (EggHistogramView *view) -{ - EggHistogramViewPrivate *priv; - - view->priv = priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (view); - - priv->bins = NULL; - priv->data = NULL; - priv->n_bins = 0; - priv->n_elements = 0; - priv->min_value = priv->min_border = 0; - priv->max_value = priv->max_border = 256; - - priv->cursor_type = GDK_ARROW; - priv->grabbing = FALSE; - - gtk_widget_add_events (GTK_WIDGET (view), - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_POINTER_MOTION_MASK); -} diff --git a/gui/egg-histogram-view.h b/gui/egg-histogram-view.h deleted file mode 100644 index 7a62fca..0000000 --- a/gui/egg-histogram-view.h +++ /dev/null @@ -1,66 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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_HISTOGRAM_VIEW_H -#define EGG_HISTOGRAM_VIEW_H - -#include - -G_BEGIN_DECLS - -#define EGG_TYPE_HISTOGRAM_VIEW (egg_histogram_view_get_type()) -#define EGG_HISTOGRAM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramView)) -#define EGG_IS_HISTOGRAM_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), EGG_TYPE_HISTOGRAM_VIEW)) -#define EGG_HISTOGRAM_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewClass)) -#define EGG_IS_HISTOGRAM_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EGG_TYPE_HISTOGRAM_VIEW)) -#define EGG_HISTOGRAM_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewClass)) - -typedef struct _EggHistogramView EggHistogramView; -typedef struct _EggHistogramViewClass EggHistogramViewClass; -typedef struct _EggHistogramViewPrivate EggHistogramViewPrivate; - -struct _EggHistogramView -{ - GtkDrawingArea parent_instance; - - /*< private >*/ - EggHistogramViewPrivate *priv; -}; - -struct _EggHistogramViewClass -{ - GtkDrawingAreaClass parent_class; - - /* signals */ - void (* changed) (EggHistogramView *view); -}; - -GType egg_histogram_view_get_type (void); -GtkWidget * egg_histogram_view_new (void); -void egg_histogram_view_set_data (EggHistogramView *view, - gpointer data, - guint n_elements, - guint n_bits, - guint n_bins); -void egg_histogram_get_visible_range - (EggHistogramView *view, - gdouble *min, - gdouble *max); - -G_END_DECLS - -#endif diff --git a/gui/egg-property-cell-renderer.c b/gui/egg-property-cell-renderer.c deleted file mode 100644 index 9df5cc3..0000000 --- a/gui/egg-property-cell-renderer.c +++ /dev/null @@ -1,594 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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 -#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/gui/egg-property-cell-renderer.h b/gui/egg-property-cell-renderer.h deleted file mode 100644 index d4dbe02..0000000 --- a/gui/egg-property-cell-renderer.h +++ /dev/null @@ -1,55 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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 - -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/gui/egg-property-tree-view.c b/gui/egg-property-tree-view.c deleted file mode 100644 index 52d1e10..0000000 --- a/gui/egg-property-tree-view.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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/gui/egg-property-tree-view.h b/gui/egg-property-tree-view.h deleted file mode 100644 index e8fd0fe..0000000 --- a/gui/egg-property-tree-view.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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 - -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 diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt deleted file mode 100644 index b16f018..0000000 --- a/tools/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -add_definitions("--std=c99 -Wall") - -# --- Find packages and libraries --------------------------------------------- -find_package(PkgConfig) -find_package(TIFF) - -pkg_check_modules(GLIB2 glib-2.0>=2.24 REQUIRED) -pkg_check_modules(GOBJECT2 gobject-2.0>=2.24 REQUIRED) - -# --- Build targets ----------------------------------------------------------- -include_directories( - ${GLIB2_INCLUDE_DIRS} - ${GOBJECT2_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/../src - ) - -set(libs uca ${GLIB2_LIBRARIES} ${GOBJECT2_LIBRARIES}) - -if (TIFF_FOUND) - set(HAVE_LIBTIFF "1") - list(APPEND libs ${TIFF_LIBRARIES}) - include_directories(${TIFF_INCLUDE_DIRS}) -endif () - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h) - -add_executable(gen-doc gen-doc.c) -target_link_libraries(gen-doc ${libs}) - -add_executable(uca-grab grab.c ring-buffer.c) -target_link_libraries(uca-grab ${libs}) - -add_executable(benchmark benchmark.c) -target_link_libraries(benchmark ${libs}) - -install(TARGETS uca-grab - RUNTIME DESTINATION bin) diff --git a/tools/benchmark.c b/tools/benchmark.c deleted file mode 100644 index 0939d78..0000000 --- a/tools/benchmark.c +++ /dev/null @@ -1,272 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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 -#include -#include -#include -#include "uca-camera.h" -#include "uca-plugin-manager.h" - -typedef void (*GrabFrameFunc) (UcaCamera *camera, gpointer buffer, guint n_frames); - -static UcaCamera *camera = NULL; - -static void -sigint_handler(int signal) -{ - g_print ("Closing down libuca\n"); - uca_camera_stop_recording (camera, NULL); - g_object_unref (camera); - exit (signal); -} - -static void -print_usage (void) -{ - GList *types; - UcaPluginManager *manager; - - manager = uca_plugin_manager_new (); - g_print ("Usage: benchmark [ "); - types = uca_plugin_manager_get_available_cameras (manager); - - if (types == NULL) { - g_print ("] -- no camera plugin found\n"); - return; - } - - for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { - gchar *name = (gchar *) it->data; - if (g_list_next (it) == NULL) - g_print ("%s ]\n", name); - else - g_print ("%s, ", name); - } -} - -static void -log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user) -{ - gsize n_written; - GError *error = NULL; - GIOChannel *channel = user; - -#if GLIB_CHECK_VERSION(2, 26, 0) - GTimeZone *tz; - GDateTime *date_time; - gchar *new_message; - - tz = g_time_zone_new_local (); - date_time = g_date_time_new_now (tz); - - new_message = g_strdup_printf ("[%s] %s\n", - g_date_time_format (date_time, "%FT%H:%M:%S%z"), message); - - g_time_zone_unref (tz); - g_date_time_unref (date_time); - - g_io_channel_write_chars (channel, new_message, strlen (new_message), &n_written, &error); - g_assert_no_error (error); - g_free (new_message); -#else - g_io_channel_write_chars (channel, message, strlen (message), &n_written, &error); - g_assert_no_error (error); -#endif - - g_io_channel_flush (channel, &error); - g_assert_no_error (error); -} - -static void -grab_frames_sync (UcaCamera *camera, gpointer buffer, guint n_frames) -{ - GError *error = NULL; - - uca_camera_start_recording (camera, &error); - - for (guint i = 0; i < n_frames; i++) { - if (!uca_camera_grab (camera, buffer, &error)) - g_warning ("Data stream ended"); - - if (error != NULL) { - g_warning ("Error grabbing frame %02i/%i: `%s'", i, n_frames, error->message); - g_error_free (error); - error = NULL; - } - } - - uca_camera_stop_recording (camera, &error); -} - -static void -grab_callback (gpointer data, gpointer user_data) -{ - static GStaticMutex mutex = G_STATIC_MUTEX_INIT; - guint *n_acquired_frames = user_data; - - g_static_mutex_lock (&mutex); - *n_acquired_frames += 1; - g_static_mutex_unlock (&mutex); -} - -static void -grab_frames_async (UcaCamera *camera, gpointer buffer, guint n_frames) -{ - GError *error = NULL; - guint n_acquired_frames = 0; - - uca_camera_set_grab_func (camera, grab_callback, &n_acquired_frames); - uca_camera_start_recording (camera, &error); - - /* - * Behold! Spinlooping is probably a bad idea but nowadays single core - * machines are relatively rare. - */ - while (n_acquired_frames < n_frames) - ; - - uca_camera_stop_recording (camera, &error); -} - -static void -benchmark_method (UcaCamera *camera, gpointer buffer, GrabFrameFunc func, guint n_runs, guint n_frames, guint n_bytes) -{ - GTimer *timer; - gdouble fps; - gdouble bandwidth; - gdouble total_time = 0.0; - GError *error = NULL; - - g_print ("%-10i%-10i", n_frames, n_runs); - timer = g_timer_new (); - g_assert_no_error (error); - - for (guint run = 0; run < n_runs; run++) { - g_message ("Start run %i of %i", run, n_runs); - g_timer_start (timer); - - func (camera, buffer, n_frames); - - g_timer_stop (timer); - total_time += g_timer_elapsed (timer, NULL); - } - - g_assert_no_error (error); - - fps = n_runs * n_frames / total_time; - bandwidth = n_bytes * fps / 1024 / 1024; - g_print ("%-16.2f%-16.2f\n", fps, bandwidth); - - g_timer_destroy (timer); -} - -static void -benchmark (UcaCamera *camera) -{ - const guint n_runs = 3; - const guint n_frames = 100; - - guint sensor_width; - guint sensor_height; - guint roi_width; - guint roi_height; - guint bits; - guint n_bytes_per_pixel; - guint n_bytes; - gdouble exposure = 0.00001; - gpointer buffer; - - g_object_set (G_OBJECT (camera), - "exposure-time", exposure, - NULL); - - g_object_get (G_OBJECT (camera), - "sensor-width", &sensor_width, - "sensor-height", &sensor_height, - "sensor-bitdepth", &bits, - "roi-width", &roi_width, - "roi-height", &roi_height, - "exposure-time", &exposure, - NULL); - - g_print ("# --- General information ---\n"); - g_print ("# Sensor size: %ix%i\n", sensor_width, sensor_height); - g_print ("# ROI size: %ix%i\n", roi_width, roi_height); - g_print ("# Exposure time: %fs\n", exposure); - g_print ("# Bits: %i\n", bits); - - /* Synchronous frame acquisition */ - g_print ("# %-10s%-10s%-10s%-16s%-16s\n", "type", "n_frames", "n_runs", "frames/s", "MiB/s"); - g_print (" %-10s", "sync"); - - g_message ("Start synchronous benchmark"); - - n_bytes_per_pixel = bits > 8 ? 2 : 1; - n_bytes = roi_width * roi_height * n_bytes_per_pixel; - buffer = g_malloc0(n_bytes); - - benchmark_method (camera, buffer, grab_frames_sync, n_runs, n_frames, n_bytes); - - /* Asynchronous frame acquisition */ - g_object_set (G_OBJECT(camera), - "transfer-asynchronously", TRUE, - NULL); - - g_message ("Start asynchronous benchmark"); - g_print (" %-10s", "async"); - - benchmark_method (camera, buffer, grab_frames_async, n_runs, n_frames, n_bytes); - - g_free (buffer); -} - -int -main (int argc, char *argv[]) -{ - UcaPluginManager *manager; - GIOChannel *log_channel; - GError *error = NULL; - - (void) signal (SIGINT, sigint_handler); - g_type_init(); - - if (argc < 2) { - print_usage(); - return 1; - } - - log_channel = g_io_channel_new_file ("error.log", "a+", &error); - g_assert_no_error (error); - g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, log_channel); - - manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_get_camera (manager, argv[1], &error, NULL); - - if (camera == NULL) { - g_error ("Initialization: %s", error->message); - return 1; - } - - benchmark (camera); - - g_object_unref (camera); - g_io_channel_shutdown (log_channel, TRUE, &error); - g_assert_no_error (error); - - return 0; -} diff --git a/tools/config.h.in b/tools/config.h.in deleted file mode 100644 index aea5237..0000000 --- a/tools/config.h.in +++ /dev/null @@ -1 +0,0 @@ -#cmakedefine HAVE_LIBTIFF diff --git a/tools/gen-doc.c b/tools/gen-doc.c deleted file mode 100644 index d27bdd8..0000000 --- a/tools/gen-doc.c +++ /dev/null @@ -1,224 +0,0 @@ -/* Copyright (C) 2012 Matthias Vogelgesang - (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 -#include "uca-plugin-manager.h" -#include "uca-camera.h" - - -static void -print_usage (void) -{ - GList *types; - UcaPluginManager *manager; - - manager = uca_plugin_manager_new (); - g_print ("Usage: gen-doc [ "); - types = uca_plugin_manager_get_available_cameras (manager); - - if (types == NULL) { - g_print ("] -- no camera plugin found\n"); - return; - } - - for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { - gchar *name = (gchar *) it->data; - if (g_list_next (it) == NULL) - g_print ("%s ]\n", name); - else - g_print ("%s, ", name); - } -} - -static const gchar * -get_flags_description (GParamSpec *pspec) -{ - static const gchar *descriptions[] = { - "", - "Read-only", - "Write-only", - "Read / Write", - "" - }; - - if (pspec->flags >= 3) - return descriptions[3]; - - return descriptions[pspec->flags]; -} - -static void -print_property_toc (GParamSpec **pspecs, guint n_props) -{ - g_print ("

Properties

    "); - - for (guint i = 0; i < n_props; i++) { - GParamSpec *pspec = pspecs[i]; - const gchar *name = g_param_spec_get_name (pspec); - - g_print ("
  • \"%s\"
  • ", name, name); - } - - g_print ("
"); -} - -static void -print_value_info (GParamSpec *pspec) -{ - gchar *default_value = NULL; - GString *range = g_string_new(""); - -#define MAKE_RANGE(spec_type, fmt) \ - { \ - spec_type *spec = (spec_type *) pspec; \ - g_string_printf (range, \ - fmt" ≤ %s ≤ "fmt, \ - spec->minimum, \ - g_param_spec_get_name (pspec), \ - spec->maximum); \ - default_value = g_strdup_printf (fmt, spec->default_value); \ - } - - switch (pspec->value_type) { - case G_TYPE_BOOLEAN: - { - GParamSpecBoolean *spec = (GParamSpecBoolean *) pspec; - default_value = spec->default_value ? g_strdup ("TRUE") : g_strdup ("FALSE"); - } - break; - - case G_TYPE_UINT: - MAKE_RANGE (GParamSpecUInt, "%i"); - break; - - case G_TYPE_FLOAT: - MAKE_RANGE (GParamSpecFloat, "%.1e"); - break; - - case G_TYPE_DOUBLE: - MAKE_RANGE (GParamSpecDouble, "%.1e"); - break; - } - -#undef MAKE_RANGE - - if (g_type_is_a (pspec->value_type, G_TYPE_ENUM)) { - GParamSpecEnum *spec = (GParamSpecEnum *) pspec; - - if (spec->enum_class->n_values > 0) { - g_string_printf (range, ""); - - for (guint i = 0; i < spec->enum_class->n_values; i++) { - GEnumValue *v = &spec->enum_class->values[i]; - g_string_append_printf (range, - "", - v->value_name, v->value); - } - - g_string_append_printf (range, "
Enum nameValue
%s%i
"); - } - } - - if (range->len > 0) - g_print ("

Possible values: %s

", range->str); - - if (default_value != NULL) { - g_print ("

Default value: %s

", default_value); - g_free (default_value); - } - - g_string_free (range, TRUE); -} - -static void -print_property_descriptions (GParamSpec **pspecs, guint n_props) -{ - g_print ("

Details

"); - - for (guint i = 0; i < n_props; i++) { - GParamSpec *pspec = pspecs[i]; - const gchar *name = g_param_spec_get_name (pspec); - - g_print ("
%s
\n", name, name); - g_print ("
"); - g_print ("
\"%s\" : %s : %s
\n", - name, - g_type_name (pspec->value_type), - get_flags_description (pspec)); - g_print ("

%s

\n", g_param_spec_get_blurb (pspec)); - print_value_info (pspec); - g_print ("
"); - } - - g_print ("
"); -} - -static void -print_properties (UcaCamera *camera) -{ - GObjectClass *oclass; - GParamSpec **pspecs; - guint n_props; - - oclass = G_OBJECT_GET_CLASS (camera); - pspecs = g_object_class_list_properties (oclass, &n_props); - - print_property_toc (pspecs, n_props); - print_property_descriptions (pspecs, n_props); - - g_free (pspecs); -} - -static const gchar *html_header = "\ -\ -\ -%s — properties"; -static const gchar *html_footer = ""; - -int main(int argc, char *argv[]) -{ - UcaPluginManager *manager; - UcaCamera *camera; - gchar *name; - GError *error = NULL; - - g_type_init(); - manager = uca_plugin_manager_new (); - - if (argc < 2) { - name = g_strdup ("Basic camera"); - camera = g_object_new (UCA_TYPE_CAMERA, NULL); - } - else { - name = argv[1]; - camera = uca_plugin_manager_get_camera (manager, name, &error, NULL); - } - - if (camera == NULL) { - g_print("Error during initialization: %s\n", error->message); - print_usage(); - return 1; - } - - g_print (html_header, name); - g_print ("

Property documentation of %s

", name); - print_properties (camera); - g_print ("%s\n", html_footer); - - g_object_unref (camera); - g_object_unref (manager); -} diff --git a/tools/grab.c b/tools/grab.c deleted file mode 100644 index 972f000..0000000 --- a/tools/grab.c +++ /dev/null @@ -1,292 +0,0 @@ -/* Copyright (C) 2011, 2012 Matthias Vogelgesang - (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 "config.h" - -#include -#include -#include -#include "uca-plugin-manager.h" -#include "uca-camera.h" -#include "ring-buffer.h" - -#ifdef HAVE_LIBTIFF -#include -#endif - - -typedef struct { - gint n_frames; - gdouble duration; - gchar *filename; -} Options; - - -static gchar * -get_camera_list (void) -{ - GList *types; - GString *str; - UcaPluginManager *manager; - - manager = uca_plugin_manager_new (); - types = uca_plugin_manager_get_available_cameras (manager); - str = g_string_new ("[ "); - - if (types != NULL) { - for (GList *it = g_list_first (types); it != NULL; it = g_list_next (it)) { - gchar *name = (gchar *) it->data; - - if (g_list_next (it) == NULL) - g_string_append_printf (str, "%s ]", name); - else - g_string_append_printf (str, "%s, ", name); - } - } - else { - g_string_append (str, "]"); - } - - g_object_unref (manager); - return g_string_free (str, FALSE); -} - -static guint -get_bytes_per_pixel (guint bits_per_pixel) -{ - return bits_per_pixel > 8 ? 2 : 1; -} - -#ifdef HAVE_LIBTIFF -static void -write_tiff (RingBuffer *buffer, - Options *opts, - guint width, - guint height, - guint bits_per_pixel) -{ - TIFF *tif; - guint32 rows_per_strip; - guint n_frames; - guint bits_per_sample; - gsize bytes_per_pixel; - - if (opts->filename) - tif = TIFFOpen (opts->filename, "w"); - else - tif = TIFFOpen ("frames.tif", "w"); - - n_frames = ring_buffer_get_num_blocks (buffer); - rows_per_strip = TIFFDefaultStripSize (tif, (guint32) - 1); - bytes_per_pixel = get_bytes_per_pixel (bits_per_pixel); - bits_per_sample = bits_per_pixel > 8 ? 16 : 8; - - /* Write multi page TIFF file */ - TIFFSetField (tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); - - for (guint i = 0; i < n_frames; i++) { - gpointer data; - gsize offset = 0; - - data = ring_buffer_get_pointer (buffer, i); - - TIFFSetField (tif, TIFFTAG_IMAGEWIDTH, width); - TIFFSetField (tif, TIFFTAG_IMAGELENGTH, height); - TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, bits_per_sample); - TIFFSetField (tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); - TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, 1); - TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField (tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip); - TIFFSetField (tif, TIFFTAG_PAGENUMBER, i, n_frames); - - for (guint y = 0; y < height; y++, offset += width * bytes_per_pixel) - TIFFWriteScanline (tif, data + offset, y, 0); - - TIFFWriteDirectory (tif); - } - - TIFFClose (tif); -} -#else -static void -write_raw (RingBuffer *buffer, - Options *opts) -{ - guint n_frames; - gsize size; - - size = ring_buffer_get_block_size (buffer); - n_frames = ring_buffer_get_num_blocks (buffer); - - for (gint i = 0; i < n_frames; i++) { - FILE *fp; - gchar *filename; - gpointer data; - - if (opts->filename) - filename = g_strdup_printf ("%s-%08i.raw", opts->filename, i); - else - filename = g_strdup_printf ("frame-%08i.raw", i); - - fp = fopen(filename, "wb"); - data = ring_buffer_get_pointer (buffer, i); - - fwrite (data, size, 1, fp); - fclose (fp); - g_free (filename); - } -} -#endif - -static GError * -record_frames (UcaCamera *camera, Options *opts) -{ - guint roi_width; - guint roi_height; - guint bits; - guint pixel_size; - gsize size; - gint n_frames; - guint n_allocated; - GTimer *timer; - RingBuffer *buffer; - GError *error = NULL; - gdouble last_printed; - - g_object_get (G_OBJECT (camera), - "roi-width", &roi_width, - "roi-height", &roi_height, - "sensor-bitdepth", &bits, - NULL); - - pixel_size = get_bytes_per_pixel (bits); - size = roi_width * roi_height * pixel_size; - n_allocated = opts->n_frames > 0 ? opts->n_frames : 256; - buffer = ring_buffer_new (size, n_allocated); - timer = g_timer_new(); - - g_print("Start recording: %ix%i at %i bits/pixel\n", - roi_width, roi_height, bits); - - uca_camera_start_recording(camera, &error); - - if (error != NULL) - return error; - - n_frames = 0; - g_timer_start(timer); - last_printed = 0.0; - - while (1) { - gdouble elapsed; - - uca_camera_grab (camera, ring_buffer_get_current_pointer (buffer), &error); - ring_buffer_proceed (buffer); - - if (error != NULL) - return error; - - n_frames++; - elapsed = g_timer_elapsed (timer, NULL); - - if (n_frames == opts->n_frames || (opts->duration > 0.0 && elapsed >= opts->duration)) - break; - - if (elapsed - last_printed >= 1.0) { - g_print ("Recorded %i frames at %.2f frames/s\n", - n_frames, n_frames / elapsed); - last_printed = elapsed; - } - } - - g_print ("Stop recording: %3.2f frames/s\n", - n_frames / g_timer_elapsed (timer, NULL)); - - uca_camera_stop_recording (camera, &error); - -#ifdef HAVE_LIBTIFF - write_tiff (buffer, opts, roi_width, roi_height, bits); -#else - write_raw (buffer, opts); -#endif - - ring_buffer_free (buffer); - g_timer_destroy (timer); - - return error; -} - -int -main (int argc, char *argv[]) -{ - GOptionContext *context; - UcaPluginManager *manager; - UcaCamera *camera; - gchar *cam_list; - GError *error = NULL; - - static Options opts = { - .n_frames = -1, - .duration = -1.0, - .filename = NULL - }; - - static GOptionEntry entries[] = { - { "num-frames", 'n', 0, G_OPTION_ARG_INT, &opts.n_frames, "Number of frames to acquire", "N" }, - { "duration", 'd', 0, G_OPTION_ARG_DOUBLE, &opts.duration, "Duration in seconds", NULL }, - { "output", 'o', 0, G_OPTION_ARG_STRING, &opts.filename, "Output file name", "FILE" }, - { NULL } - }; - - g_type_init(); - - cam_list = get_camera_list (); - context = g_option_context_new (cam_list); - g_option_context_add_main_entries (context, entries, NULL); - g_free (cam_list); - - if (!g_option_context_parse (context, &argc, &argv, &error)) { - g_print ("Failed parsing arguments: %s\n", error->message); - exit (1); - } - - if (argc < 2) { - g_print ("%s\n", g_option_context_get_help (context, TRUE, NULL)); - exit (0); - } - - if (opts.n_frames < 0 && opts.duration < 0.0) { - g_print ("You must specify at least one of --num-frames and --output.\n"); - exit (1); - } - - manager = uca_plugin_manager_new (); - camera = uca_plugin_manager_get_camera (manager, argv[1], &error, NULL); - - if (camera == NULL) { - g_print ("Error during initialization: %s\n", error->message); - exit (1); - } - - error = record_frames (camera, &opts); - - if (error != NULL) - g_print ("Error: %s\n", error->message); - - g_object_unref (camera); - return error != NULL ? 1 : 0; -} diff --git a/tools/ring-buffer.c b/tools/ring-buffer.c deleted file mode 100644 index 039024f..0000000 --- a/tools/ring-buffer.c +++ /dev/null @@ -1,70 +0,0 @@ - -#include -#include "ring-buffer.h" - -RingBuffer * -ring_buffer_new (gsize block_size, - gsize n_blocks) -{ - RingBuffer *buffer; - - buffer = g_new0 (RingBuffer, 1); - buffer->block_size = block_size; - buffer->n_blocks_total = n_blocks; - buffer->n_blocks_used = 0; - buffer->current_index = 0; - buffer->data = g_malloc0_n (n_blocks, block_size); - - return buffer; -} - -void -ring_buffer_free (RingBuffer *buffer) -{ - g_free (buffer->data); - g_free (buffer); -} - -void -ring_buffer_reset (RingBuffer *buffer) -{ - buffer->n_blocks_used = 0; - buffer->current_index = 0; -} - -gsize -ring_buffer_get_block_size (RingBuffer *buffer) -{ - return buffer->block_size; -} - -gpointer -ring_buffer_get_current_pointer (RingBuffer *buffer) -{ - return buffer->data + (buffer->current_index % buffer->n_blocks_total) * buffer->block_size; -} - -gpointer -ring_buffer_get_pointer (RingBuffer *buffer, - guint index) -{ - g_assert (index < buffer->n_blocks_total); - return buffer->data + ((buffer->current_index - buffer->n_blocks_used + index) % buffer->n_blocks_total) * buffer->block_size; -} - -guint -ring_buffer_get_num_blocks (RingBuffer *buffer) -{ - return buffer->n_blocks_used; -} - -void -ring_buffer_proceed (RingBuffer *buffer) -{ - buffer->current_index++; - - if (buffer->n_blocks_used < buffer->n_blocks_total) - buffer->n_blocks_used++; - else - buffer->current_index = buffer->current_index % buffer->n_blocks_total; -} diff --git a/tools/ring-buffer.h b/tools/ring-buffer.h deleted file mode 100644 index a3758cb..0000000 --- a/tools/ring-buffer.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef RING_BUFFER_H -#define RING_BUFFER_H - -#include - -G_BEGIN_DECLS - -typedef struct { - guchar *data; - gsize block_size; - guint n_blocks_total; - guint n_blocks_used; - guint current_index; -} RingBuffer; - -RingBuffer * ring_buffer_new (gsize block_size, - gsize n_blocks); -void ring_buffer_free (RingBuffer *buffer); -void ring_buffer_reset (RingBuffer *buffer); -gsize ring_buffer_get_block_size (RingBuffer *buffer); -gpointer ring_buffer_get_current_pointer (RingBuffer *buffer); -gpointer ring_buffer_get_pointer (RingBuffer *buffer, - guint index); -guint ring_buffer_get_num_blocks (RingBuffer *buffer); -void ring_buffer_proceed (RingBuffer *buffer); - -G_END_DECLS - -#endif -- cgit v1.2.3