[gthumb] histogram view: added widgets to change current channel and scale type
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] histogram view: added widgets to change current channel and scale type
- Date: Thu, 20 Jan 2011 20:20:07 +0000 (UTC)
commit 03eb2d3a450b203e3ca7f01f613be746cad76342
Author: Paolo Bacchilega <paobac src gnome org>
Date: Mon Jan 17 21:43:36 2011 +0100
histogram view: added widgets to change current channel and scale type
gthumb/gth-histogram-view.c | 699 ++++++++++++++++++++++++++++++++++---------
gthumb/gth-histogram-view.h | 36 ++--
2 files changed, 583 insertions(+), 152 deletions(-)
---
diff --git a/gthumb/gth-histogram-view.c b/gthumb/gth-histogram-view.c
index 9605eb0..dff53cd 100644
--- a/gthumb/gth-histogram-view.c
+++ b/gthumb/gth-histogram-view.c
@@ -3,7 +3,7 @@
/*
* GThumb
*
- * Copyright (C) 2001-2009 The Free Software Foundation, Inc.
+ * Copyright (C) 2001-2010 The Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,30 +20,49 @@
*/
#include <config.h>
+#include <stdlib.h>
#include <math.h>
#include <cairo/cairo.h>
+#include <glib/gi18n.h>
#include "glib-utils.h"
#include "gth-histogram-view.h"
+#include "gth-enum-types.h"
+
+
+#define GRID_STEP 50.0
/* Properties */
enum {
PROP_0,
- PROP_HISTOGRAM
+ PROP_HISTOGRAM,
+ PROP_CURRENT_CHANNEL,
+ PROP_DISPLAY_MODE,
+ PROP_SCALE_TYPE
};
+enum {
+ CHANNEL_COLUMN_ICON,
+ CHANNEL_COLUMN_NAME,
+ CHANNEL_COLUMN_SENSITIVE
+};
static gpointer gth_histogram_view_parent_class = NULL;
struct _GthHistogramViewPrivate {
- GthHistogram *histogram;
- gulong histogram_changed_event;
- GthHistogramMode display_mode;
- GthHistogramScale scale_type;
- int current_channel;
- guchar selection_start;
- guchar selection_end;
+ GthHistogram *histogram;
+ gulong histogram_changed_event;
+ GthHistogramMode display_mode;
+ GthHistogramScale scale_type;
+ GthHistogramChannel current_channel;
+ guchar selection_start;
+ guchar selection_end;
+ GtkWidget *histogram_view;
+ GtkWidget *linear_histogram_button;
+ GtkWidget *logarithmic_histogram_button;
+ GtkWidget *channel_combo_box;
+
};
@@ -61,6 +80,15 @@ gth_histogram_set_property (GObject *object,
case PROP_HISTOGRAM:
gth_histogram_view_set_histogram (self, g_value_get_object (value));
break;
+ case PROP_CURRENT_CHANNEL:
+ gth_histogram_view_set_current_channel (self, g_value_get_enum (value));
+ break;
+ case PROP_DISPLAY_MODE:
+ gth_histogram_view_set_histogram (self, g_value_get_object (value));
+ break;
+ case PROP_SCALE_TYPE:
+ gth_histogram_view_set_scale_type (self, g_value_get_enum (value));
+ break;
default:
break;
}
@@ -81,6 +109,15 @@ gth_histogram_get_property (GObject *object,
case PROP_HISTOGRAM:
g_value_set_object (value, self->priv->histogram);
break;
+ case PROP_CURRENT_CHANNEL:
+ g_value_set_int (value, self->priv->current_channel);
+ break;
+ case PROP_DISPLAY_MODE:
+ g_value_set_enum (value, self->priv->display_mode);
+ break;
+ case PROP_SCALE_TYPE:
+ g_value_set_enum (value, self->priv->scale_type);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -101,6 +138,56 @@ gth_histogram_view_finalize (GObject *obj)
}
+static void
+gth_histogram_view_class_init (GthHistogramViewClass *klass)
+{
+ GObjectClass *object_class;
+
+ gth_histogram_view_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GthHistogramViewPrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->set_property = gth_histogram_set_property;
+ object_class->get_property = gth_histogram_get_property;
+ object_class->finalize = gth_histogram_view_finalize;
+
+ /* properties */
+
+ g_object_class_install_property (object_class,
+ PROP_HISTOGRAM,
+ g_param_spec_object ("histogram",
+ "Histogram",
+ "The histogram to display",
+ GTH_TYPE_HISTOGRAM,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_CURRENT_CHANNEL,
+ g_param_spec_enum ("current-channel",
+ "Channel",
+ "The channel to display",
+ GTH_TYPE_HISTOGRAM_CHANNEL,
+ GTH_HISTOGRAM_CHANNEL_VALUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_MODE,
+ g_param_spec_enum ("display-mode",
+ "Display mode",
+ "Whether to display a single channel or all the channels at the same time",
+ GTH_TYPE_HISTOGRAM_MODE,
+ GTH_HISTOGRAM_MODE_ONE_CHANNEL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SCALE_TYPE,
+ g_param_spec_enum ("scale-type",
+ "Scale",
+ "The scale type",
+ GTH_TYPE_HISTOGRAM_SCALE,
+ GTH_HISTOGRAM_SCALE_LOGARITHMIC,
+ G_PARAM_READWRITE));
+}
+
+
+
static double
convert_to_scale (GthHistogramScale scale_type,
double value)
@@ -117,48 +204,46 @@ convert_to_scale (GthHistogramScale scale_type,
static void
-gth_histogram_paint_channel (GthHistogramView *self,
- cairo_t *cr,
- int channel,
- gboolean black_mask)
+_cairo_set_source_color_from_channel (cairo_t *cr,
+ int channel)
{
- GtkWidget *widget = GTK_WIDGET (self);
- GtkAllocation allocation;
- double max;
- double step;
- int i;
-
- if (channel > 3)
- return;
- if ((self->priv->display_mode == GTH_HISTOGRAM_MODE_ALL_CHANNELS) && (channel == 0))
- return;
-
- gtk_widget_get_allocation (widget, &allocation);
-
switch (channel) {
- case 0:
+ case GTH_HISTOGRAM_CHANNEL_VALUE:
default:
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
break;
- case 1:
+ case GTH_HISTOGRAM_CHANNEL_RED:
cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 1.0);
break;
- case 2:
+ case GTH_HISTOGRAM_CHANNEL_GREEN:
cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 1.0);
break;
- case 3:
+ case GTH_HISTOGRAM_CHANNEL_BLUE:
cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 1.0);
break;
- case 4:
+ case GTH_HISTOGRAM_CHANNEL_ALPHA:
cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 1.0);
break;
}
+}
- if (black_mask) {
- cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
- }
- else if (self->priv->display_mode == GTH_HISTOGRAM_MODE_ALL_CHANNELS)
+
+static void
+gth_histogram_paint_channel (GthHistogramView *self,
+ cairo_t *cr,
+ int channel,
+ GtkAllocation *allocation)
+{
+ double max;
+ double step;
+ int i;
+
+ if (channel > gth_histogram_get_nchannels (self->priv->histogram))
+ return;
+
+ _cairo_set_source_color_from_channel (cr, channel);
+
+ if (self->priv->display_mode == GTH_HISTOGRAM_MODE_ALL_CHANNELS)
cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
else
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
@@ -169,197 +254,508 @@ gth_histogram_paint_channel (GthHistogramView *self,
else
max = 1.0;
- step = allocation.width / 256.0;
+ step = (double) allocation->width / 255.0;
cairo_set_line_width (cr, 0.5);
- for (i = 0; i < 256; i++) {
+ for (i = 0; i < 255; i++) {
double value;
int y;
value = gth_histogram_get_value (self->priv->histogram, channel, i);
- y = (int) (allocation.height * convert_to_scale (self->priv->scale_type, value)) / max;
-
- /*cairo_new_path (cr);
- cairo_move_to (cr, i * step + (step / 2) + 0.5, h - y);
- cairo_line_to (cr, i * step + (step / 2) + 0.5, h);
- cairo_close_path (cr);
- cairo_stroke (cr);*/
+ y = (int) (allocation->height * convert_to_scale (self->priv->scale_type, value)) / max;
- cairo_rectangle (cr, (i * step) + 0.5, allocation.height - y, 1 + step, allocation.height);
+ cairo_rectangle (cr, (i * step) + 0.5, allocation->height - y, step, allocation->height);
}
cairo_fill (cr);
}
static void
+gth_histogram_paint_rgb (GthHistogramView *self,
+ cairo_t *cr,
+ GtkAllocation *allocation)
+{
+ double max;
+ double step;
+ int i;
+
+ max = gth_histogram_get_max (self->priv->histogram);
+ if (max > 0.0)
+ max = convert_to_scale (self->priv->scale_type, max);
+ else
+ max = 1.0;
+
+ step = (double) allocation->width / 255.0;
+ cairo_set_line_width (cr, 0.5);
+ for (i = 0; i < 255; i++) {
+ double value_r;
+ double value_g;
+ double value_b;
+ int min_c;
+ int mid_c;
+ int max_c;
+ int y;
+ double value;
+
+ value_r = gth_histogram_get_value (self->priv->histogram, 1, i);
+ value_g = gth_histogram_get_value (self->priv->histogram, 2, i);
+ value_b = gth_histogram_get_value (self->priv->histogram, 3, i);
+
+ /* find the channel with minimum value */
+
+ if ((value_r <= value_g) && (value_r <= value_b))
+ min_c = 1;
+ else if ((value_g <= value_r) && (value_g <= value_b))
+ min_c = 2;
+ else
+ min_c = 3;
+
+ /* find the channel with maximum value */
+
+ if ((value_r >= value_g) && (value_r >= value_b))
+ max_c = 1;
+ else if ((value_g >= value_r) && (value_g >= value_b))
+ max_c = 2;
+ else
+ max_c = 3;
+
+ /* find the channel with middle value */
+
+ if (abs (max_c - min_c) == 1) {
+ if ((max_c == 1) || (min_c == 1))
+ mid_c = 3;
+ else
+ mid_c = 1;
+ }
+ else
+ mid_c = 2;
+
+ /* use the OVER operator for the maximum value */
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ _cairo_set_source_color_from_channel (cr, max_c);
+ value = gth_histogram_get_value (self->priv->histogram, max_c, i);
+ y = (int) (allocation->height * convert_to_scale (self->priv->scale_type, value)) / max;
+ cairo_rectangle (cr, (i * step) + 0.5, allocation->height - y, step, allocation->height);
+ cairo_fill (cr);
+
+ /* use the ADD operator for the middle value */
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
+ _cairo_set_source_color_from_channel (cr, mid_c);
+ value = gth_histogram_get_value (self->priv->histogram, mid_c, i);
+ y = (int) (allocation->height * convert_to_scale (self->priv->scale_type, value)) / max;
+ cairo_rectangle (cr, (i * step) + 0.5, allocation->height - y, step, allocation->height);
+ cairo_fill (cr);
+
+ /* the minimum value is shared by all the channels and is
+ * painted in black. */
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ value = gth_histogram_get_value (self->priv->histogram, min_c, i);
+ y = (int) (allocation->height * convert_to_scale (self->priv->scale_type, value)) / max;
+ cairo_rectangle (cr, (i * step) + 0.5, allocation->height - y, step, allocation->height);
+ cairo_fill (cr);
+ }
+}
+
+
+static void
gth_histogram_paint_grid (GthHistogramView *self,
- cairo_t *cr)
+ cairo_t *cr,
+ GtkAllocation *allocation)
{
- GtkWidget *widget = GTK_WIDGET (self);
- GtkAllocation allocation;
- GtkStyle *style;
- int i;
+ GtkStyle *style;
+ int i;
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
- style = gtk_widget_get_style (widget);
- gdk_cairo_set_source_color (cr, &style->dark[gtk_widget_get_state (widget)]);
+ style = gtk_widget_get_style (GTK_WIDGET (self));
+ gdk_cairo_set_source_color (cr, &style->dark[gtk_widget_get_state (GTK_WIDGET (self))]);
- gtk_widget_get_allocation (widget, &allocation);
- cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+ cairo_rectangle (cr, 0, 0, allocation->width, allocation->height);
cairo_stroke (cr);
cairo_set_line_width (cr, 0.5);
for (i = 1; i <= 4; i++) {
int x;
- x = (i * 64) * ((float) allocation.width / 256);
+ x = (i * GRID_STEP) * ((double) allocation->width / 255.0);
- /*cairo_new_path (cr);*/
cairo_move_to (cr, x + 0.5, 0);
- cairo_line_to (cr, x + 0.5, allocation.height);
- /*cairo_close_path (cr);*/
+ cairo_line_to (cr, x + 0.5, allocation->height);
}
cairo_stroke (cr);
}
+static void
+gth_histogram_paint_selection (GthHistogramView *self,
+ cairo_t *cr,
+ GtkAllocation *allocation)
+{
+ double step;
+
+ step = (double) allocation->width / 255.0;
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_line_width (cr, 0.5);
+ cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5);
+ cairo_rectangle (cr,
+ self->priv->selection_start * step,
+ 0,
+ self->priv->selection_end * step,
+ allocation->height);
+ cairo_fill (cr);
+}
+
+
static gboolean
-gth_histogram_view_expose_event (GtkWidget *widget,
- GdkEventExpose *event)
+histogram_view_expose_event_cb (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer user_data)
{
- GthHistogramView *self;
+ GthHistogramView *self = user_data;
GtkAllocation allocation;
GtkStyle *style;
cairo_t *cr;
- self = GTH_HISTOGRAM_VIEW (widget);
-
gtk_widget_get_allocation (widget, &allocation);
+ allocation.width--;
+ allocation.height--;
+
style = gtk_widget_get_style (widget);
cr = gdk_cairo_create (gtk_widget_get_window (widget));
+
gdk_cairo_set_source_color (cr, &style->base[gtk_widget_get_state (widget)]);
cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
cairo_fill (cr);
- cairo_set_line_width (cr, 2.0);
+ if ((self->priv->selection_start > 0) || (self->priv->selection_end < 255))
+ gth_histogram_paint_selection (self, cr, &allocation);
if ((self->priv->histogram == NULL)
- || (self->priv->current_channel > gth_histogram_get_nchannels (self->priv->histogram)))
+ || ((self->priv->display_mode == GTH_HISTOGRAM_MODE_ONE_CHANNEL)
+ && (self->priv->current_channel > gth_histogram_get_nchannels (self->priv->histogram))))
{
- /* draw an x if no histogram is set */
- cairo_new_path (cr);
+ /* draw an x if the current channel is not available */
+
+ cairo_set_line_width (cr, 2.0);
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, allocation.width, allocation.height);
- cairo_close_path (cr);
- cairo_stroke (cr);
-
- cairo_new_path (cr);
cairo_move_to (cr, allocation.width, 0);
cairo_line_to (cr, 0, allocation.height);
cairo_close_path (cr);
cairo_stroke (cr);
}
else {
- gth_histogram_paint_grid (self, cr);
- if (self->priv->display_mode == GTH_HISTOGRAM_MODE_ALL_CHANNELS) {
- int i;
-
- for (i = 0; i <= gth_histogram_get_nchannels (self->priv->histogram); i++)
- gth_histogram_paint_channel (self, cr, i, TRUE);
-
- for (i = 0; i <= gth_histogram_get_nchannels (self->priv->histogram); i++)
- if (i != self->priv->current_channel)
- gth_histogram_paint_channel (self, cr, i, FALSE);
- gth_histogram_paint_channel (self, cr, self->priv->current_channel, FALSE);
- }
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+ gth_histogram_paint_grid (self, cr, &allocation);
+ if (self->priv->display_mode == GTH_HISTOGRAM_MODE_ALL_CHANNELS)
+ gth_histogram_paint_rgb (self, cr, &allocation);
else
- gth_histogram_paint_channel (self, cr, self->priv->current_channel, FALSE);
+ gth_histogram_paint_channel (self, cr, self->priv->current_channel, &allocation);
}
cairo_destroy (cr);
- if (GTK_WIDGET_CLASS (gth_histogram_view_parent_class)->expose_event != NULL)
- GTK_WIDGET_CLASS (gth_histogram_view_parent_class)->expose_event (widget, event);
+ return TRUE;
+}
+
- return FALSE;
+static gboolean
+histogram_view_scroll_event_cb (GtkWidget *widget,
+ GdkEventScroll *event,
+ gpointer user_data)
+{
+ GthHistogramView *self = user_data;
+ int channel;
+
+ if (self->priv->histogram == NULL)
+ return FALSE;
+
+ if (event->direction == GDK_SCROLL_UP) {
+ if (gth_histogram_view_get_display_mode (self) == GTH_HISTOGRAM_MODE_ALL_CHANNELS)
+ channel = gth_histogram_get_nchannels (self->priv->histogram);
+ else
+ channel = self->priv->current_channel - 1;
+ }
+ else if (event->direction == GDK_SCROLL_DOWN) {
+ if (gth_histogram_view_get_display_mode (self) == GTH_HISTOGRAM_MODE_ALL_CHANNELS)
+ return TRUE;
+ else
+ channel = self->priv->current_channel + 1;
+ }
+
+ if (channel <= gth_histogram_get_nchannels (self->priv->histogram)) {
+ gth_histogram_view_set_current_channel (self, CLAMP (channel, 0, GTH_HISTOGRAM_N_CHANNELS - 1));
+ gth_histogram_view_set_display_mode (self, GTH_HISTOGRAM_MODE_ONE_CHANNEL);
+ }
+ else
+ gth_histogram_view_set_display_mode (self, GTH_HISTOGRAM_MODE_ALL_CHANNELS);
+
+ return TRUE;
}
static void
-gth_histogram_view_map (GtkWidget *widget)
+linear_histogram_button_toggled_cb (GtkToggleButton *button,
+ gpointer user_data)
{
- GdkWindow *window;
-
- if (GTK_WIDGET_CLASS (gth_histogram_view_parent_class)->map != NULL)
- GTK_WIDGET_CLASS (gth_histogram_view_parent_class)->map (widget);
+ GthHistogramView *self = user_data;
- window = gtk_widget_get_window (widget);
- gdk_window_set_events (window, GDK_BUTTON_PRESS_MASK | gdk_window_get_events (window));
+ if (gtk_toggle_button_get_active (button))
+ gth_histogram_view_set_scale_type (GTH_HISTOGRAM_VIEW (self), GTH_HISTOGRAM_SCALE_LINEAR);
}
-static gboolean
-gth_histogram_view_scroll_event (GtkWidget *widget,
- GdkEventScroll *event)
+static void
+logarithmic_histogram_button_toggled_cb (GtkToggleButton *button,
+ gpointer user_data)
{
- GthHistogramView *self;
+ GthHistogramView *self = user_data;
- self = GTH_HISTOGRAM_VIEW (widget);
+ if (gtk_toggle_button_get_active (button))
+ gth_histogram_view_set_scale_type (GTH_HISTOGRAM_VIEW (self), GTH_HISTOGRAM_SCALE_LOGARITHMIC);
+}
- if (self->priv->histogram == NULL)
- return FALSE;
- if (event->direction == GDK_SCROLL_UP)
- self->priv->current_channel--;
- else if (event->direction == GDK_SCROLL_DOWN)
- self->priv->current_channel++;
- self->priv->current_channel = CLAMP (self->priv->current_channel, 0, 3);
- gtk_widget_queue_draw (widget);
+static void
+channel_combo_box_changed_cb (GtkComboBox *combo_box,
+ gpointer user_data)
+{
+ GthHistogramView *self = user_data;
+ int n_channel;
- return TRUE;
+ n_channel = gtk_combo_box_get_active (combo_box);
+ if (n_channel < GTH_HISTOGRAM_N_CHANNELS) {
+ gth_histogram_view_set_current_channel (GTH_HISTOGRAM_VIEW (self), n_channel);
+ gth_histogram_view_set_display_mode (GTH_HISTOGRAM_VIEW (self), GTH_HISTOGRAM_MODE_ONE_CHANNEL);
+ }
+ else
+ gth_histogram_view_set_display_mode (GTH_HISTOGRAM_VIEW (self), GTH_HISTOGRAM_MODE_ALL_CHANNELS);
}
static void
-gth_histogram_view_class_init (GthHistogramViewClass *klass)
+self_notify_current_channel_cb (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
{
- GObjectClass *object_class;
- GtkWidgetClass *widget_class;
+ GthHistogramView *self = user_data;
- gth_histogram_view_parent_class = g_type_class_peek_parent (klass);
- g_type_class_add_private (klass, sizeof (GthHistogramViewPrivate));
+ gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->channel_combo_box), self->priv->current_channel);
+}
- object_class = (GObjectClass*) klass;
- object_class->set_property = gth_histogram_set_property;
- object_class->get_property = gth_histogram_get_property;
- object_class->finalize = gth_histogram_view_finalize;
- widget_class = (GtkWidgetClass*) klass;
- widget_class->expose_event = gth_histogram_view_expose_event;
- widget_class->map = gth_histogram_view_map;
- widget_class->scroll_event = gth_histogram_view_scroll_event;
+static void
+self_notify_display_mode_cb (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GthHistogramView *self = user_data;
- /* properties */
+ if (self->priv->display_mode == GTH_HISTOGRAM_MODE_ALL_CHANNELS)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->channel_combo_box), GTH_HISTOGRAM_N_CHANNELS);
+ else
+ gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->channel_combo_box), self->priv->current_channel);
+}
- g_object_class_install_property (object_class,
- PROP_HISTOGRAM,
- g_param_spec_object ("histogram",
- "Histogram",
- "The histogram to display",
- GTH_TYPE_HISTOGRAM,
- G_PARAM_READWRITE));
+
+static void
+self_notify_scale_type_cb (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GthHistogramView *self = user_data;
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->linear_histogram_button), self->priv->scale_type == GTH_HISTOGRAM_SCALE_LINEAR);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->logarithmic_histogram_button), self->priv->scale_type == GTH_HISTOGRAM_SCALE_LOGARITHMIC);
}
static void
gth_histogram_view_instance_init (GthHistogramView *self)
{
+ GtkWidget *box;
+ GtkWidget *sub_box;
+ PangoAttrList *attr_list;
+ GtkWidget *label;
+ GtkWidget *view_frame;
+ GtkListStore *channel_model;
+ GtkCellRenderer *renderer;
+ GtkTreeIter iter;
+
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_HISTOGRAM_VIEW, GthHistogramViewPrivate);
self->priv->histogram = NULL;
- self->priv->current_channel = 0;
- self->priv->display_mode = GTH_HISTOGRAM_MODE_ONE_CHANNEL /*GTH_HISTOGRAM_MODE_ALL_CHANNELS*/;
+ self->priv->current_channel = GTH_HISTOGRAM_CHANNEL_VALUE;
+ self->priv->display_mode = GTH_HISTOGRAM_MODE_ONE_CHANNEL;
self->priv->scale_type = GTH_HISTOGRAM_SCALE_LINEAR;
+
+ gtk_box_set_spacing (GTK_BOX (self), 6);
+
+ /* topbar */
+
+ box = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (box);
+ gtk_box_pack_start (GTK_BOX (self), box, FALSE, FALSE, 0);
+
+ /* linear / logarithmic buttons */
+
+ sub_box = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (sub_box);
+ gtk_box_pack_end (GTK_BOX (box), sub_box, FALSE, FALSE, 0);
+
+ self->priv->linear_histogram_button = gtk_toggle_button_new ();
+ gtk_widget_set_tooltip_text (self->priv->linear_histogram_button, _("Linear scale"));
+ gtk_button_set_relief (GTK_BUTTON (self->priv->linear_histogram_button), GTK_RELIEF_NONE);
+ gtk_container_add (GTK_CONTAINER (self->priv->linear_histogram_button), gtk_image_new_from_icon_name ("histogram-linear", GTK_ICON_SIZE_MENU));
+ gtk_widget_show_all (self->priv->linear_histogram_button);
+ gtk_box_pack_start (GTK_BOX (sub_box), self->priv->linear_histogram_button, FALSE, FALSE, 0);
+
+ g_signal_connect (self->priv->linear_histogram_button,
+ "toggled",
+ G_CALLBACK (linear_histogram_button_toggled_cb),
+ self);
+
+ self->priv->logarithmic_histogram_button = gtk_toggle_button_new ();
+ gtk_widget_set_tooltip_text (self->priv->logarithmic_histogram_button, _("Logarithmic scale"));
+ gtk_button_set_relief (GTK_BUTTON (self->priv->logarithmic_histogram_button), GTK_RELIEF_NONE);
+ gtk_container_add (GTK_CONTAINER (self->priv->logarithmic_histogram_button), gtk_image_new_from_icon_name ("histogram-logarithmic", GTK_ICON_SIZE_MENU));
+ gtk_widget_show_all (self->priv->logarithmic_histogram_button);
+ gtk_box_pack_start (GTK_BOX (sub_box), self->priv->logarithmic_histogram_button, FALSE, FALSE, 0);
+
+ g_signal_connect (self->priv->logarithmic_histogram_button,
+ "toggled",
+ G_CALLBACK (logarithmic_histogram_button_toggled_cb),
+ self);
+
+ /* channel selector */
+
+ sub_box = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (sub_box);
+ gtk_box_pack_start (GTK_BOX (box), sub_box, FALSE, FALSE, 0);
+
+ attr_list = pango_attr_list_new ();
+ pango_attr_list_insert (attr_list, pango_attr_size_new (PANGO_SCALE * 8));
+
+ label = gtk_label_new (_("Channel:"));
+ gtk_label_set_attributes (GTK_LABEL (label), attr_list);
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (sub_box), label, FALSE, FALSE, 0);
+ channel_model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ self->priv->channel_combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (channel_model));
+ g_object_unref (channel_model);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->priv->channel_combo_box),
+ renderer,
+ FALSE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->priv->channel_combo_box),
+ renderer,
+ "icon-name", CHANNEL_COLUMN_ICON,
+ "sensitive", CHANNEL_COLUMN_SENSITIVE,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "attributes", attr_list, NULL);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->priv->channel_combo_box),
+ renderer,
+ TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->priv->channel_combo_box),
+ renderer,
+ "text", CHANNEL_COLUMN_NAME,
+ "sensitive", CHANNEL_COLUMN_SENSITIVE,
+ NULL);
+
+ gtk_list_store_append (channel_model, &iter);
+ gtk_list_store_set (channel_model, &iter,
+ CHANNEL_COLUMN_ICON, "channel-value",
+ CHANNEL_COLUMN_NAME, _("Value"),
+ CHANNEL_COLUMN_SENSITIVE, TRUE,
+ -1);
+ gtk_list_store_append (channel_model, &iter);
+ gtk_list_store_set (channel_model, &iter,
+ CHANNEL_COLUMN_ICON, "channel-red",
+ CHANNEL_COLUMN_NAME, _("Red"),
+ CHANNEL_COLUMN_SENSITIVE, TRUE,
+ -1);
+ gtk_list_store_append (channel_model, &iter);
+ gtk_list_store_set (channel_model, &iter,
+ CHANNEL_COLUMN_ICON, "channel-green",
+ CHANNEL_COLUMN_NAME, _("Green"),
+ CHANNEL_COLUMN_SENSITIVE, TRUE,
+ -1);
+ gtk_list_store_append (channel_model, &iter);
+ gtk_list_store_set (channel_model, &iter,
+ CHANNEL_COLUMN_ICON, "channel-blue",
+ CHANNEL_COLUMN_NAME, _("Blue"),
+ CHANNEL_COLUMN_SENSITIVE, TRUE,
+ -1);
+ gtk_list_store_append (channel_model, &iter);
+ gtk_list_store_set (channel_model, &iter,
+ CHANNEL_COLUMN_ICON, "channel-alpha",
+ CHANNEL_COLUMN_NAME, _("Alpha"),
+ CHANNEL_COLUMN_SENSITIVE, FALSE,
+ -1);
+ gtk_list_store_append (channel_model, &iter);
+ gtk_list_store_set (channel_model, &iter,
+ CHANNEL_COLUMN_ICON, "channel-rgb",
+ CHANNEL_COLUMN_NAME, _("RGB"),
+ CHANNEL_COLUMN_SENSITIVE, TRUE,
+ -1);
+
+ gtk_widget_show (self->priv->channel_combo_box);
+ gtk_box_pack_start (GTK_BOX (sub_box), self->priv->channel_combo_box, FALSE, FALSE, 0);
+
+ g_signal_connect (self->priv->channel_combo_box,
+ "changed",
+ G_CALLBACK (channel_combo_box_changed_cb),
+ self);
+
+ pango_attr_list_unref (attr_list);
+
+ /* histogram view */
+
+ view_frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (view_frame), GTK_SHADOW_IN);
+ gtk_widget_show (view_frame);
+ gtk_box_pack_start (GTK_BOX (self), view_frame, TRUE, TRUE, 0);
+
+ self->priv->histogram_view = gtk_drawing_area_new ();
+ gtk_widget_add_events (self->priv->histogram_view, GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK);
+ gtk_widget_show (self->priv->histogram_view);
+ gtk_container_add (GTK_CONTAINER (view_frame), self->priv->histogram_view);
+
+ g_signal_connect (self->priv->histogram_view,
+ "expose-event",
+ G_CALLBACK (histogram_view_expose_event_cb),
+ self);
+ g_signal_connect (self->priv->histogram_view,
+ "scroll-event",
+ G_CALLBACK (histogram_view_scroll_event_cb),
+ self);
+
+ /* update widgets when a property changes */
+
+ g_signal_connect (self,
+ "notify::current-channel",
+ G_CALLBACK (self_notify_current_channel_cb),
+ self);
+ g_signal_connect (self,
+ "notify::display-mode",
+ G_CALLBACK (self_notify_display_mode_cb),
+ self);
+ g_signal_connect (self,
+ "notify::scale-type",
+ G_CALLBACK (self_notify_scale_type_cb),
+ self);
+
+ /* default values */
+
+ gth_histogram_view_set_display_mode (self, GTH_HISTOGRAM_MODE_ALL_CHANNELS);
+ gth_histogram_view_set_scale_type (self, GTH_HISTOGRAM_SCALE_LINEAR);
}
@@ -379,7 +775,7 @@ gth_histogram_view_get_type (void) {
(GInstanceInitFunc) gth_histogram_view_instance_init,
NULL
};
- gth_histogram_view_type_id = g_type_register_static (GTK_TYPE_DRAWING_AREA, "GthHistogramView", &g_define_type_info, 0);
+ gth_histogram_view_type_id = g_type_register_static (GTK_TYPE_VBOX, "GthHistogramView", &g_define_type_info, 0);
}
return gth_histogram_view_type_id;
}
@@ -393,11 +789,35 @@ gth_histogram_view_new (GthHistogram *histogram)
static void
+update_channel_combo_box_sensitivity (GthHistogramView *self)
+{
+ gboolean has_alpha;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ has_alpha = gth_histogram_get_nchannels (self->priv->histogram) > 3;
+ path = gtk_tree_path_new_from_indices (GTH_HISTOGRAM_CHANNEL_ALPHA, -1);
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->channel_combo_box))),
+ &iter,
+ path))
+ {
+ gtk_list_store_set (GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (self->priv->channel_combo_box))),
+ &iter,
+ CHANNEL_COLUMN_SENSITIVE, has_alpha,
+ -1);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+
+static void
histogram_changed_cb (GthHistogram *histogram,
gpointer user_data)
{
GthHistogramView *self = user_data;
+ update_channel_combo_box_sensitivity (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
@@ -423,6 +843,8 @@ gth_histogram_view_set_histogram (GthHistogramView *self,
self->priv->histogram = g_object_ref (histogram);
self->priv->histogram_changed_event = g_signal_connect (self->priv->histogram, "changed", G_CALLBACK (histogram_changed_cb), self);
+
+ g_object_notify (G_OBJECT (self), "histogram");
}
@@ -439,7 +861,10 @@ gth_histogram_view_set_current_channel (GthHistogramView *self,
int n_channel)
{
g_return_if_fail (GTH_IS_HISTOGRAM_VIEW (self));
- self->priv->current_channel = n_channel;
+
+ self->priv->current_channel = CLAMP (n_channel, 0, GTH_HISTOGRAM_N_CHANNELS);
+ g_object_notify (G_OBJECT (self), "current-channel");
+
gtk_widget_queue_draw (GTK_WIDGET (self));
}
@@ -457,7 +882,10 @@ gth_histogram_view_set_display_mode (GthHistogramView *self,
GthHistogramMode mode)
{
g_return_if_fail (GTH_IS_HISTOGRAM_VIEW (self));
+
self->priv->display_mode = mode;
+ g_object_notify (G_OBJECT (self), "display-mode");
+
gtk_widget_queue_draw (GTK_WIDGET (self));
}
@@ -475,7 +903,10 @@ gth_histogram_view_set_scale_type (GthHistogramView *self,
GthHistogramScale scale_type)
{
g_return_if_fail (GTH_IS_HISTOGRAM_VIEW (self));
+
self->priv->scale_type = scale_type;
+ g_object_notify (G_OBJECT (self), "scale-type");
+
gtk_widget_queue_draw (GTK_WIDGET (self));
}
diff --git a/gthumb/gth-histogram-view.h b/gthumb/gth-histogram-view.h
index 02ae9cb..4c1c720 100644
--- a/gthumb/gth-histogram-view.h
+++ b/gthumb/gth-histogram-view.h
@@ -50,31 +50,31 @@ typedef enum {
} GthHistogramScale;
struct _GthHistogramView {
- GtkDrawingArea parent_instance;
+ GtkVBox parent_instance;
GthHistogramViewPrivate *priv;
};
struct _GthHistogramViewClass {
- GtkDrawingAreaClass parent_class;
+ GtkVBoxClass parent_class;
};
GType gth_histogram_view_get_type (void);
-GtkWidget * gth_histogram_view_new (GthHistogram *histogram);
-void gth_histogram_view_set_histogram (GthHistogramView *self,
- GthHistogram *histogram);
-GthHistogram * gth_histogram_view_get_histogram (GthHistogramView *self);
-void gth_histogram_view_set_current_channel (GthHistogramView *self,
- int n_channel);
-int gth_histogram_view_get_current_channel (GthHistogramView *self);
-void gth_histogram_view_set_display_mode (GthHistogramView *self,
- GthHistogramMode mode);
-GthHistogramMode gth_histogram_view_get_display_mode (GthHistogramView *self);
-void gth_histogram_view_set_scale_type (GthHistogramView *self,
- GthHistogramScale scale);
-GthHistogramScale gth_histogram_view_get_scale_type (GthHistogramView *self);
-void gth_histogram_view_set_selection (GthHistogramView *self,
- guchar start,
- guchar end);
+GtkWidget * gth_histogram_view_new (GthHistogram *histogram);
+void gth_histogram_view_set_histogram (GthHistogramView *self,
+ GthHistogram *histogram);
+GthHistogram * gth_histogram_view_get_histogram (GthHistogramView *self);
+void gth_histogram_view_set_current_channel (GthHistogramView *self,
+ int n_channel);
+int gth_histogram_view_get_current_channel (GthHistogramView *self);
+void gth_histogram_view_set_display_mode (GthHistogramView *self,
+ GthHistogramMode mode);
+GthHistogramMode gth_histogram_view_get_display_mode (GthHistogramView *self);
+void gth_histogram_view_set_scale_type (GthHistogramView *self,
+ GthHistogramScale scale);
+GthHistogramScale gth_histogram_view_get_scale_type (GthHistogramView *self);
+void gth_histogram_view_set_selection (GthHistogramView *self,
+ guchar start,
+ guchar end);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]