From 08a794b59a02a36028da90f31e165e7f44ef28e5 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Wed, 10 Oct 2012 09:15:21 +0200 Subject: Add histogram view skeleton --- tools/gui/egg-histogram-view.c | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 tools/gui/egg-histogram-view.c (limited to 'tools/gui/egg-histogram-view.c') diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c new file mode 100644 index 0000000..809a2d9 --- /dev/null +++ b/tools/gui/egg-histogram-view.c @@ -0,0 +1,100 @@ +/* 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_CELL_RENDERER) + +#define EGG_HISTOGRAM_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), EGG_TYPE_HISTOGRAM_VIEW, EggHistogramViewPrivate)) + + +struct _EggHistogramViewPrivate +{ + guint foo; +}; + +enum +{ + PROP_0, + N_PROPERTIES +}; + +static GParamSpec *egg_histogram_view_properties[N_PROPERTIES] = { NULL, }; + + +GtkWidget * +egg_histogram_view_new (void) +{ + EggHistogramView *view; + + view = EGG_HISTOGRAM_VIEW (g_object_new (EGG_TYPE_HISTOGRAM_VIEW, NULL)); + return GTK_WIDGET (view); +} + +static void +egg_histogram_view_dispose (GObject *object) +{ +} + +static void +egg_histogram_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + + switch (property_id) { + 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) +{ + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (object)); + + switch (property_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + return; + } +} + +static void +egg_histogram_view_class_init (EggHistogramViewClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = egg_histogram_view_set_property; + gobject_class->get_property = egg_histogram_view_get_property; + gobject_class->dispose = egg_histogram_view_dispose; + + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); +} + +static void +egg_histogram_view_init (EggHistogramView *renderer) +{ + renderer->priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (renderer); +} -- cgit v1.2.3 From 95a22bf2f02ad11c2602df5ac5ffd04fee93588c Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Wed, 10 Oct 2012 17:44:34 +0200 Subject: Implement experimental histogram view --- plugins/mock/uca-mock-camera.c | 4 - plugins/pf/uca-pf-camera.c | 1 + src/uca-camera.c | 10 +- tools/gui/control.c | 47 ++++--- tools/gui/control.glade | 75 ++++++++-- tools/gui/egg-histogram-view.c | 301 +++++++++++++++++++++++++++++++++++++++-- tools/gui/egg-histogram-view.h | 5 + 7 files changed, 400 insertions(+), 43 deletions(-) (limited to 'tools/gui/egg-histogram-view.c') diff --git a/plugins/mock/uca-mock-camera.c b/plugins/mock/uca-mock-camera.c index 7ab1d4a..65c4240 100644 --- a/plugins/mock/uca-mock-camera.c +++ b/plugins/mock/uca-mock-camera.c @@ -37,7 +37,6 @@ static const gint mock_overrideables[] = { PROP_SENSOR_HORIZONTAL_BINNINGS, PROP_SENSOR_VERTICAL_BINNING, PROP_SENSOR_VERTICAL_BINNINGS, - PROP_TRIGGER_MODE, PROP_EXPOSURE_TIME, PROP_ROI_X, PROP_ROI_Y, @@ -301,9 +300,6 @@ static void uca_mock_camera_get_property(GObject *object, guint property_id, GVa case PROP_EXPOSURE_TIME: g_value_set_double(value, priv->exposure_time); break; - case PROP_TRIGGER_MODE: - g_value_set_enum(value, UCA_CAMERA_TRIGGER_AUTO); - break; case PROP_ROI_X: g_value_set_uint(value, priv->roi_x); break; diff --git a/plugins/pf/uca-pf-camera.c b/plugins/pf/uca-pf-camera.c index 35b5edd..473ffd3 100644 --- a/plugins/pf/uca-pf-camera.c +++ b/plugins/pf/uca-pf-camera.c @@ -234,6 +234,7 @@ static void uca_pf_camera_get_property(GObject *object, guint property_id, GValu g_value_set_boolean(value, FALSE); break; case PROP_EXPOSURE_TIME: + g_value_set_double(value, 1. / 488.0); break; case PROP_ROI_X: g_value_set_uint(value, 0); diff --git a/src/uca-camera.c b/src/uca-camera.c index 6d92e6a..5684888 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -132,15 +132,19 @@ uca_camera_get_property(GObject *object, guint property_id, GValue *value, GPara switch (property_id) { case PROP_IS_RECORDING: - g_value_set_boolean(value, priv->is_recording); + g_value_set_boolean (value, priv->is_recording); break; case PROP_IS_READOUT: - g_value_set_boolean(value, priv->is_readout); + g_value_set_boolean (value, priv->is_readout); break; case PROP_TRANSFER_ASYNCHRONOUSLY: - g_value_set_boolean(value, priv->transfer_async); + g_value_set_boolean (value, priv->transfer_async); + break; + + case PROP_TRIGGER_MODE: + g_value_set_enum (value, UCA_CAMERA_TRIGGER_AUTO); break; case PROP_FRAMES_PER_SECOND: diff --git a/tools/gui/control.c b/tools/gui/control.c index f7d3618..b36d188 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -28,6 +28,7 @@ #include "uca-camera.h" #include "uca-plugin-manager.h" #include "egg-property-tree-view.h" +#include "egg-histogram-view.h" typedef struct { @@ -37,6 +38,8 @@ typedef struct { GtkWidget *start_button; GtkWidget *stop_button; GtkWidget *record_button; + GtkWidget *histogram_view; + GtkToggleButton *histogram_button; guchar *buffer; guchar *pixels; @@ -49,15 +52,9 @@ typedef struct { int pixel_size; } ThreadData; -enum { - COLUMN_NAME = 0, - COLUMN_VALUE, - COLUMN_EDITABLE, - NUM_COLUMNS -}; - static UcaPluginManager *plugin_manager; + static void convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) { @@ -106,7 +103,7 @@ grab_thread (void *args) uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); if (data->store) { - snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter++); + snprintf (filename, FILENAME_MAX, "frame-%i-%08i.raw", data->timestamp, counter); FILE *fp = fopen (filename, "wb"); fwrite (data->buffer, data->width*data->height, data->pixel_size, fp); fclose (fp); @@ -121,11 +118,18 @@ grab_thread (void *args) } gdk_threads_enter (); + gdk_flush (); gtk_image_clear (GTK_IMAGE (data->image)); gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), data->pixbuf); gtk_widget_queue_draw_area (data->image, 0, 0, data->width, data->height); + + if (gtk_toggle_button_get_active (data->histogram_button)) + gtk_widget_queue_draw (data->histogram_view); + gdk_threads_leave (); + + counter++; } return NULL; } @@ -211,6 +215,12 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { + GtkWidget *window; + GtkWidget *image; + GtkWidget *property_tree_view; + GdkPixbuf *pixbuf; + GtkBox *histogram_box; + GtkContainer *scrolled_property_window; static ThreadData td; GError *error = NULL; @@ -228,15 +238,12 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) "sensor-bitdepth", &bits_per_sample, NULL); - GtkWidget *window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); - GtkWidget *image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); - GtkWidget *property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); - GtkContainer *scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); - + property_tree_view = egg_property_tree_view_new (G_OBJECT (camera)); + scrolled_property_window = GTK_CONTAINER (gtk_builder_get_object (builder, "scrolledwindow2")); gtk_container_add (scrolled_property_window, property_tree_view); - gtk_widget_show_all (GTK_WIDGET (scrolled_property_window)); - GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); + image = GTK_WIDGET (gtk_builder_get_object (builder, "image")); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, td.width, td.height); gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); td.pixel_size = bits_per_sample > 8 ? 2 : 1; @@ -247,7 +254,14 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.running = FALSE; td.store = FALSE; td.camera = camera; + td.histogram_view = egg_histogram_view_new (); + td.histogram_button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder, "histogram-checkbutton")); + + histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); + gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), td.buffer, td.width * td.height, bits_per_sample, 256); + window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); td.start_button = GTK_WIDGET (gtk_builder_get_object (builder, "start-button")); @@ -259,8 +273,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) 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); - gtk_widget_show (image); - gtk_widget_show (window); + gtk_widget_show_all (window); } static void diff --git a/tools/gui/control.glade b/tools/gui/control.glade index ee888e8..6d6d791 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -164,28 +164,83 @@ True 6 - - 300 + True True - automatic - automatic - + + 640 + 480 True - queue + True + automatic + automatic - + True - gtk-missing-image + queue + + + 640 + 480 + True + gtk-missing-image + + + + True + True + + + + + True + True + + + True + + + + + + Enable Live Update + True + True + False + 6 + True + True + + + end + 1 + + + + + + + True + Histogram + + + False + + + + + True + True + - True - False + False + True diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 809a2d9..d3cb18b 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -15,17 +15,33 @@ with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA */ -#include +#include #include "egg-histogram-view.h" -G_DEFINE_TYPE (EggHistogramView, egg_histogram_view, GTK_TYPE_CELL_RENDERER) +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 { - guint foo; + GdkCursorType cursor_type; + gboolean grabbing; + + /* This could be moved into a real histogram class */ + guint n_bins; + gint *bins; + gint min_value; + gint max_value; + gint min_border; + gint max_border; + + gpointer data; + gint n_elements; + gint n_bits; }; enum @@ -46,9 +62,178 @@ egg_histogram_view_new (void) 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; + + 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; + priv->max_value = (gint) pow(2, n_bits) - 1; + + priv->min_border = 20; + priv->max_border = priv->max_value - 20; +} + +static void +compute_histogram (EggHistogramViewPrivate *priv) +{ + 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]; + guint index = (guint) round (((gdouble) v) / priv->max_value * (priv->n_bins - 1)); + priv->bins[index]++; + } + } + else if (priv->n_bits == 16) { + guint16 *data = (guint16 *) priv->data; + + for (guint i = 0; i < priv->n_elements; i++) { + guint16 v = data[i]; + guint index = (guint) floor (((gdouble ) v) / priv->max_value * (priv->n_bins - 1)); + priv->bins[index]++; + } + } + else + g_warning ("%i number of bits unsupported", priv->n_bits); +} + +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 gboolean +egg_histogram_view_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + GtkStyle *style; + cairo_t *cr; + gint width, height; + gint max_value = 0; + + 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]); + + if (priv->min_border > 0) { + cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); + cairo_fill (cr); + } + + /* Draw spikes */ + for (guint i = 0; i < priv->n_bins; i++) { + if (priv->bins[i] > max_value) + max_value = priv->bins[i]; + } + + if (max_value == 0) + goto cleanup; + + gdk_cairo_set_source_color (cr, &style->black); + + if (width > priv->n_bins) { + gdouble skip = ((gdouble) width) / priv->n_bins; + gdouble x = 1; + + for (guint i = 0; i < priv->n_bins; 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 + BORDER), height + BORDER - 1); + cairo_line_to (cr, round (x + BORDER), height + BORDER - 1 - y); + cairo_stroke (cr); + } + } + +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 @@ -81,20 +266,118 @@ egg_histogram_view_get_property (GObject *object, } } +static gint +get_mouse_distance (EggHistogramViewPrivate *priv, + gint x) +{ + return (priv->min_border + BORDER) - x; +} + +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) { + priv->min_border = event->x + BORDER; + gtk_widget_queue_draw (widget); + } + else { + gint distance = get_mouse_distance (priv, event->x); + + if (ABS(distance) < 6) + 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; + EggHistogramViewPrivate *priv; + GtkAllocation allocation; + gint width; + + gtk_widget_get_allocation (widget, &allocation); + width = allocation.width - 2 * BORDER; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + + set_cursor_type (view, GDK_ARROW); + priv->grabbing = FALSE; + + return TRUE; +} + +static gboolean +egg_histogram_view_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + EggHistogramView *view; + EggHistogramViewPrivate *priv; + gint distance; + + view = EGG_HISTOGRAM_VIEW (widget); + priv = view->priv; + distance = get_mouse_distance (priv, event->x); + + if (ABS (distance) < 6) { + priv->grabbing = TRUE; + set_cursor_type (view, GDK_FLEUR); + } + + return TRUE; +} + static void egg_histogram_view_class_init (EggHistogramViewClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - gobject_class->set_property = egg_histogram_view_set_property; - gobject_class->get_property = egg_histogram_view_get_property; - gobject_class->dispose = egg_histogram_view_dispose; + 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; g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } static void -egg_histogram_view_init (EggHistogramView *renderer) +egg_histogram_view_init (EggHistogramView *view) { - renderer->priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (renderer); + 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->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/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index 23581dc..a1df0ba 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -48,6 +48,11 @@ struct _EggHistogramViewClass 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); G_END_DECLS -- cgit v1.2.3 From 195ccad179d96766165b1dc846dbe066fffc43ac Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Wed, 10 Oct 2012 17:47:00 +0200 Subject: Disable unused variables --- tools/gui/egg-histogram-view.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/gui/egg-histogram-view.c') diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index d3cb18b..7abc2be 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -305,11 +305,11 @@ egg_histogram_view_button_release (GtkWidget *widget, { EggHistogramView *view; EggHistogramViewPrivate *priv; - GtkAllocation allocation; - gint width; + /* GtkAllocation allocation; */ + /* gint width; */ - gtk_widget_get_allocation (widget, &allocation); - width = allocation.width - 2 * BORDER; + /* gtk_widget_get_allocation (widget, &allocation); */ + /* width = allocation.width - 2 * BORDER; */ view = EGG_HISTOGRAM_VIEW (widget); priv = view->priv; -- cgit v1.2.3 From 13b2833ea9c16750efb923a981ea04d37aaa6789 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Thu, 11 Oct 2012 16:38:26 +0200 Subject: Implement adjustable histogram --- src/uca-camera.c | 2 +- tools/gui/control.c | 70 ++++++------ tools/gui/control.glade | 112 +++++++++++++++++--- tools/gui/egg-histogram-view.c | 234 +++++++++++++++++++++++++++++++---------- tools/gui/egg-histogram-view.h | 4 + 5 files changed, 316 insertions(+), 106 deletions(-) (limited to 'tools/gui/egg-histogram-view.c') diff --git a/src/uca-camera.c b/src/uca-camera.c index 5684888..091ef54 100644 --- a/src/uca-camera.c +++ b/src/uca-camera.c @@ -128,7 +128,7 @@ uca_camera_set_property (GObject *object, guint property_id, const GValue *value static void uca_camera_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { - UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE(object); + UcaCameraPrivate *priv = UCA_CAMERA_GET_PRIVATE (object); switch (property_id) { case PROP_IS_RECORDING: diff --git a/tools/gui/control.c b/tools/gui/control.c index b36d188..214e4da 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -19,10 +19,7 @@ #include #include #include -#include -#include -#include -#include +#include #include "config.h" #include "uca-camera.h" @@ -56,39 +53,28 @@ static UcaPluginManager *plugin_manager; static void -convert_8bit_to_rgb (guchar *output, guchar *input, int width, int height) +convert_8bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) { + gdouble factor = 255.0 / (max - min); + for (int i = 0, j = 0; i < width*height; i++) { - output[j++] = input[i]; - output[j++] = input[i]; - output[j++] = input[i]; + guchar val = (guchar) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; } } static void -convert_16bit_to_rgb (guchar *output, guchar *input, int width, int height) +convert_16bit_to_rgb (guchar *output, guchar *input, gint width, gint height, gdouble min, gdouble max) { - guint16 *in = (guint16 *) input; - guint16 min = G_MAXUINT16, max = 0; - gfloat spread = 0.0f; - - for (int i = 0; i < width * height; i++) { - guint16 v = in[i]; - if (v < min) - min = v; - if (v > max) - max = v; - } - - spread = (gfloat) max - min; + gdouble factor = 255.0 / (max - min); - if (spread > 0.0f) { - for (int i = 0, j = 0; i < width*height; i++) { - guchar val = (guint8) (((in[i] - min) / spread) * 255.0f); - output[j++] = val; - output[j++] = val; - output[j++] = val; - } + for (int i = 0, j = 0; i < width*height; i++) { + guchar val = (guint8) ((input[i] - min) * factor); + output[j++] = val; + output[j++] = val; + output[j++] = val; } } @@ -100,6 +86,9 @@ grab_thread (void *args) gint counter = 0; while (data->running) { + gdouble min_value; + gdouble max_value; + uca_camera_grab (data->camera, (gpointer) &data->buffer, NULL); if (data->store) { @@ -111,11 +100,12 @@ grab_thread (void *args) /* FIXME: We should actually check if this is really a new frame and * just do nothing if it is an already displayed one. */ + egg_histogram_get_visible_range (EGG_HISTOGRAM_VIEW (data->histogram_view), &min_value, &max_value); + if (data->pixel_size == 1) - convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - else if (data->pixel_size == 2) { - convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height); - } + convert_8bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); + else if (data->pixel_size == 2) + convert_16bit_to_rgb (data->pixels, data->buffer, data->width, data->height, min_value, max_value); gdk_threads_enter (); @@ -221,6 +211,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) GdkPixbuf *pixbuf; GtkBox *histogram_box; GtkContainer *scrolled_property_window; + GtkAdjustment *max_bin_adjustment; static ThreadData td; GError *error = NULL; @@ -259,7 +250,8 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) histogram_box = GTK_BOX (gtk_builder_get_object (builder, "histogram-box")); gtk_box_pack_start (histogram_box, td.histogram_view, TRUE, TRUE, 6); - egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), td.buffer, td.width * td.height, bits_per_sample, 256); + egg_histogram_view_set_data (EGG_HISTOGRAM_VIEW (td.histogram_view), + td.buffer, td.width * td.height, bits_per_sample, 256); window = GTK_WIDGET (gtk_builder_get_object (builder, "window")); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); @@ -269,6 +261,16 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) td.record_button = GTK_WIDGET (gtk_builder_get_object (builder, "record-button")); set_tool_button_state (&td); + g_object_bind_property (gtk_builder_get_object (builder, "min_bin_value_adjustment"), "value", + td.histogram_view, "minimum-bin-value", + G_BINDING_DEFAULT); + + max_bin_adjustment = GTK_ADJUSTMENT (gtk_builder_get_object (builder, "max_bin_value_adjustment")); + gtk_adjustment_set_value (max_bin_adjustment, pow (2, bits_per_sample) - 1); + g_object_bind_property (max_bin_adjustment, "value", + td.histogram_view, "maximum-bin-value", + G_BINDING_DEFAULT); + 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); diff --git a/tools/gui/control.glade b/tools/gui/control.glade index 7ef712d..ebe2cc8 100644 --- a/tools/gui/control.glade +++ b/tools/gui/control.glade @@ -204,17 +204,97 @@ - - Enable Live Update + True - True - False 6 - True - True + 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 + + + + + + + - end + False + False 1 @@ -264,13 +344,6 @@ - - 65535 - 1 - 65535 - 1 - 10 - 6 @@ -352,4 +425,15 @@ + + 65535 + 1 + 10 + + + 256 + 65535 + 1 + 10 + diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 7abc2be..91e61e8 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -34,11 +34,14 @@ struct _EggHistogramViewPrivate /* This could be moved into a real histogram class */ guint n_bins; gint *bins; - gint min_value; - gint max_value; - gint min_border; + 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; @@ -47,6 +50,8 @@ struct _EggHistogramViewPrivate enum { PROP_0, + PROP_MINIMUM_BIN_VALUE, + PROP_MAXIMUM_BIN_VALUE, N_PROPERTIES }; @@ -71,6 +76,7 @@ egg_histogram_view_set_data (EggHistogramView *view, { EggHistogramViewPrivate *priv; + g_return_if_fail (EGG_IS_HISTOGRAM_VIEW (view)); priv = view->priv; if (priv->bins != NULL) @@ -82,16 +88,46 @@ egg_histogram_view_set_data (EggHistogramView *view, priv->n_bits = n_bits; priv->n_elements = n_elements; - priv->min_value = 0; + priv->min_value = 0.0; priv->max_value = (gint) pow(2, n_bits) - 1; - priv->min_border = 20; - priv->max_border = priv->max_value - 20; + 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; @@ -100,8 +136,11 @@ compute_histogram (EggHistogramViewPrivate *priv) for (guint i = 0; i < priv->n_elements; i++) { guint8 v = data[i]; - guint index = (guint) round (((gdouble) v) / priv->max_value * (priv->n_bins - 1)); - priv->bins[index]++; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) round (((gdouble) v) / priv->max_value * n_bins); + priv->bins[index]++; + } } } else if (priv->n_bits == 16) { @@ -109,8 +148,11 @@ compute_histogram (EggHistogramViewPrivate *priv) for (guint i = 0; i < priv->n_elements; i++) { guint16 v = data[i]; - guint index = (guint) floor (((gdouble ) v) / priv->max_value * (priv->n_bins - 1)); - priv->bins[index]++; + + if (v >= priv->min_value && v <= priv->max_value) { + guint index = (guint) floor (((gdouble ) v) / priv->max_value * n_bins); + priv->bins[index]++; + } } } else @@ -137,6 +179,36 @@ egg_histogram_view_size_request (GtkWidget *widget, 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) @@ -146,7 +218,6 @@ egg_histogram_view_expose (GtkWidget *widget, GtkStyle *style; cairo_t *cr; gint width, height; - gint max_value = 0; priv = EGG_HISTOGRAM_VIEW_GET_PRIVATE (widget); cr = gdk_cairo_create (gtk_widget_get_window (widget)); @@ -181,36 +252,15 @@ egg_histogram_view_expose (GtkWidget *widget, /* Draw border areas */ gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]); - if (priv->min_border > 0) { - cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); - cairo_fill (cr); - } - - /* Draw spikes */ - for (guint i = 0; i < priv->n_bins; i++) { - if (priv->bins[i] > max_value) - max_value = priv->bins[i]; - } + cairo_rectangle (cr, BORDER, BORDER, priv->min_border + 0.5, height - 1); + cairo_fill (cr); - if (max_value == 0) - goto cleanup; + cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->min_border - 0.5, height - 1); + cairo_fill (cr); + /* Draw spikes */ gdk_cairo_set_source_color (cr, &style->black); - - if (width > priv->n_bins) { - gdouble skip = ((gdouble) width) / priv->n_bins; - gdouble x = 1; - - for (guint i = 0; i < priv->n_bins; 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 + BORDER), height + BORDER - 1); - cairo_line_to (cr, round (x + BORDER), height + BORDER - 1 - y); - cairo_stroke (cr); - } - } + draw_bins (priv, cr, width, height); cleanup: cairo_destroy (cr); @@ -242,9 +292,42 @@ egg_histogram_view_set_property (GObject *object, 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; @@ -257,20 +340,48 @@ egg_histogram_view_get_property (GObject *object, 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 gint -get_mouse_distance (EggHistogramViewPrivate *priv, +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) { - return (priv->min_border + BORDER) - 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 @@ -284,13 +395,12 @@ egg_histogram_view_motion_notify (GtkWidget *widget, priv = view->priv; if (priv->grabbing) { - priv->min_border = event->x + BORDER; + *priv->grabbed = event->x; + gtk_widget_queue_draw (widget); } else { - gint distance = get_mouse_distance (priv, event->x); - - if (ABS(distance) < 6) + if (is_on_border (priv, event->x)) set_cursor_type (view, GDK_FLEUR); else set_cursor_type (view, GDK_ARROW); @@ -304,18 +414,10 @@ egg_histogram_view_button_release (GtkWidget *widget, GdkEventButton *event) { EggHistogramView *view; - EggHistogramViewPrivate *priv; - /* GtkAllocation allocation; */ - /* gint width; */ - - /* gtk_widget_get_allocation (widget, &allocation); */ - /* width = allocation.width - 2 * BORDER; */ view = EGG_HISTOGRAM_VIEW (widget); - priv = view->priv; - set_cursor_type (view, GDK_ARROW); - priv->grabbing = FALSE; + view->priv->grabbing = FALSE; return TRUE; } @@ -326,14 +428,13 @@ egg_histogram_view_button_press (GtkWidget *widget, { EggHistogramView *view; EggHistogramViewPrivate *priv; - gint distance; view = EGG_HISTOGRAM_VIEW (widget); priv = view->priv; - distance = get_mouse_distance (priv, event->x); - if (ABS (distance) < 6) { + if (is_on_border (priv, event->x)) { priv->grabbing = TRUE; + priv->grabbed = get_grabbed_border (priv, event->x); set_cursor_type (view, GDK_FLEUR); } @@ -357,6 +458,23 @@ egg_histogram_view_class_init (EggHistogramViewClass *klass) 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]); + g_type_class_add_private (klass, sizeof (EggHistogramViewPrivate)); } @@ -371,6 +489,8 @@ egg_histogram_view_init (EggHistogramView *view) 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; diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index a1df0ba..61a1c8c 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -53,6 +53,10 @@ void egg_histogram_view_set_data (EggHistogramView *view, guint n_elements, guint n_bits, guint n_bins); +void egg_histogram_get_visible_range + (EggHistogramView *view, + gdouble *min, + gdouble *max); G_END_DECLS -- cgit v1.2.3 From 63a030a0d65f4ab77a2cbc138eaf5782e276e290 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Fri, 12 Oct 2012 16:29:21 +0200 Subject: Accept anything else than 8 bit as 16 bits For now, there is no other possible format. --- tools/gui/egg-histogram-view.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'tools/gui/egg-histogram-view.c') diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 91e61e8..5041ba2 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -143,7 +143,7 @@ compute_histogram (EggHistogramViewPrivate *priv) } } } - else if (priv->n_bits == 16) { + else { guint16 *data = (guint16 *) priv->data; for (guint i = 0; i < priv->n_elements; i++) { @@ -155,8 +155,6 @@ compute_histogram (EggHistogramViewPrivate *priv) } } } - else - g_warning ("%i number of bits unsupported", priv->n_bits); } static void -- cgit v1.2.3 From 33a90d8dc20a513722f5fdf66a99cff91be422d5 Mon Sep 17 00:00:00 2001 From: Matthias Vogelgesang Date: Mon, 15 Oct 2012 10:33:14 +0200 Subject: Fix replay feature --- tools/gui/control.c | 54 ++++++++++++++++++++++++------------------ tools/gui/egg-histogram-view.c | 29 ++++++++++++++++++++--- tools/gui/egg-histogram-view.h | 3 +++ tools/gui/ring-buffer.c | 12 +++++----- tools/gui/ring-buffer.h | 2 +- 5 files changed, 67 insertions(+), 33 deletions(-) (limited to 'tools/gui/egg-histogram-view.c') diff --git a/tools/gui/control.c b/tools/gui/control.c index e01bc7d..f26cafc 100644 --- a/tools/gui/control.c +++ b/tools/gui/control.c @@ -79,6 +79,9 @@ convert_grayscale_to_rgb (ThreadData *data, gpointer buffer) output[j++] = val; output[j++] = val; output[j++] = val; + /* if (i < 10) { */ + /* g_print ("%i->%i ", input[i], val); */ + /* } */ } } else if (data->pixel_size == 2) { @@ -161,13 +164,11 @@ on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) } void -on_destroy (GtkWidget *widget, gpointer data) +on_destroy (GtkWidget *widget, ThreadData *data) { - ThreadData *td = (ThreadData *) data; - - td->state = IDLE; - g_object_unref (td->camera); - ring_buffer_free (td->buffer); + data->state = IDLE; + g_object_unref (data->camera); + ring_buffer_free (data->buffer); gtk_main_quit (); } @@ -184,25 +185,27 @@ set_tool_button_state (ThreadData *data) } static void -on_frame_slider_changed (GtkAdjustment *adjustment, gpointer user_data) +update_current_frame (ThreadData *data) { - ThreadData *data = (ThreadData *) user_data; + gpointer buffer; + gint index; - if (data->state == IDLE) { - 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); +} - index = (gint) gtk_adjustment_get_value (adjustment); - 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, gpointer args) +on_start_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; uca_camera_start_recording (data->camera, &error); @@ -223,13 +226,11 @@ on_start_button_clicked (GtkWidget *widget, gpointer args) } static void -on_stop_button_clicked (GtkWidget *widget, gpointer args) +on_stop_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; data->state = IDLE; - set_tool_button_state (data); uca_camera_stop_recording (data->camera, &error); @@ -238,9 +239,8 @@ on_stop_button_clicked (GtkWidget *widget, gpointer args) } static void -on_record_button_clicked (GtkWidget *widget, gpointer args) +on_record_button_clicked (GtkWidget *widget, ThreadData *data) { - ThreadData *data = (ThreadData *) args; GError *error = NULL; uca_camera_start_recording (data->camera, &error); @@ -260,6 +260,13 @@ on_record_button_clicked (GtkWidget *widget, gpointer args) } } +static void +on_histogram_changed (EggHistogramView *view, ThreadData *data) +{ + if (data->state == IDLE) + update_current_frame (data); +} + static void create_main_window (GtkBuilder *builder, const gchar* camera_name) { @@ -351,6 +358,7 @@ create_main_window (GtkBuilder *builder, const gchar* camera_name) 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 (histogram_view, "changed", G_CALLBACK (on_histogram_changed), &td); g_signal_connect (window, "destroy", G_CALLBACK (on_destroy), &td); /* Layout */ diff --git a/tools/gui/egg-histogram-view.c b/tools/gui/egg-histogram-view.c index 5041ba2..812af7a 100644 --- a/tools/gui/egg-histogram-view.c +++ b/tools/gui/egg-histogram-view.c @@ -55,8 +55,16 @@ enum 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) @@ -253,7 +261,7 @@ egg_histogram_view_expose (GtkWidget *widget, 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->min_border - 0.5, height - 1); + cairo_rectangle (cr, priv->max_border + 0.5, BORDER, width - priv->max_border + 0.5, height - 1); cairo_fill (cr); /* Draw spikes */ @@ -393,9 +401,14 @@ egg_histogram_view_motion_notify (GtkWidget *widget, priv = view->priv; if (priv->grabbing) { - *priv->grabbed = event->x; + GtkAllocation allocation; + + gtk_widget_get_allocation (widget, &allocation); - gtk_widget_queue_draw (widget); + 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)) @@ -416,6 +429,7 @@ egg_histogram_view_button_release (GtkWidget *widget, 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; } @@ -473,6 +487,15 @@ egg_histogram_view_class_init (EggHistogramViewClass *klass) 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)); } diff --git a/tools/gui/egg-histogram-view.h b/tools/gui/egg-histogram-view.h index 61a1c8c..7a62fca 100644 --- a/tools/gui/egg-histogram-view.h +++ b/tools/gui/egg-histogram-view.h @@ -44,6 +44,9 @@ struct _EggHistogramView struct _EggHistogramViewClass { GtkDrawingAreaClass parent_class; + + /* signals */ + void (* changed) (EggHistogramView *view); }; GType egg_histogram_view_get_type (void); diff --git a/tools/gui/ring-buffer.c b/tools/gui/ring-buffer.c index 5915d2a..ec2638c 100644 --- a/tools/gui/ring-buffer.c +++ b/tools/gui/ring-buffer.c @@ -12,7 +12,7 @@ ring_buffer_new (gsize block_size, buffer->block_size = block_size; buffer->n_blocks_total = n_blocks; buffer->n_blocks_used = 0; - buffer->start_index = 0; + buffer->current_index = 0; buffer->data = g_malloc0_n (n_blocks, block_size); return buffer; @@ -29,13 +29,13 @@ void ring_buffer_reset (RingBuffer *buffer) { buffer->n_blocks_used = 0; - buffer->start_index = 0; + buffer->current_index = 0; } gpointer ring_buffer_get_current_pointer (RingBuffer *buffer) { - return ring_buffer_get_pointer (buffer, 0); + return buffer->data + (buffer->current_index % buffer->n_blocks_total) * buffer->block_size; } gpointer @@ -43,7 +43,7 @@ ring_buffer_get_pointer (RingBuffer *buffer, guint index) { g_assert (index < buffer->n_blocks_total); - return buffer->data + ((buffer->start_index + index) % buffer->n_blocks_total) * buffer->block_size; + return buffer->data + ((buffer->current_index - buffer->n_blocks_used + index) % buffer->n_blocks_total) * buffer->block_size; } guint @@ -55,10 +55,10 @@ ring_buffer_get_num_blocks (RingBuffer *buffer) void ring_buffer_proceed (RingBuffer *buffer) { - buffer->start_index++; + buffer->current_index++; if (buffer->n_blocks_used < buffer->n_blocks_total) buffer->n_blocks_used++; else - buffer->start_index = buffer->start_index % buffer->n_blocks_total; + buffer->current_index = buffer->current_index % buffer->n_blocks_total; } diff --git a/tools/gui/ring-buffer.h b/tools/gui/ring-buffer.h index 22cbde7..9966eb7 100644 --- a/tools/gui/ring-buffer.h +++ b/tools/gui/ring-buffer.h @@ -10,7 +10,7 @@ typedef struct { gsize block_size; guint n_blocks_total; guint n_blocks_used; - guint start_index; + guint current_index; } RingBuffer; RingBuffer * ring_buffer_new (gsize block_size, -- cgit v1.2.3