[Rawstudio-commit] r2053 - trunk/src

Anders Brander anders at brander.dk
Tue Sep 30 20:46:19 CEST 2008


Author: abrander
Date: 2008-09-30 20:46:18 +0200 (Tue, 30 Sep 2008)
New Revision: 2053

Modified:
   trunk/src/Makefile.am
   trunk/src/rawstudio.c
   trunk/src/rawstudio.h
   trunk/src/rs-actions.c
   trunk/src/rs-cache.c
   trunk/src/rs-cache.h
   trunk/src/rs-color-transform.c
   trunk/src/rs-color-transform.h
   trunk/src/rs-curve.c
   trunk/src/rs-curve.h
   trunk/src/rs-photo.c
   trunk/src/rs-photo.h
   trunk/src/rs-preview-widget.c
   trunk/src/toolbox.c
Log:
Merged RS_SETTINGS and RS_SETTINGS_DOUBLE into RSSettings (and broke white balance in an interesting way).

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/Makefile.am	2008-09-30 18:46:18 UTC (rev 2053)
@@ -26,6 +26,7 @@
 rawstudio_SOURCES = \
 	rawstudio.c rawstudio.h \
 	rs-filetypes.c rs-filetypes.h \
+	rs-settings.c rs-settings.h \
 	rs-utils.c rs-utils.h \
 	rs-job.c rs-job.h \
 	rs-actions.c rs-actions.h \

Modified: trunk/src/rawstudio.c
===================================================================
--- trunk/src/rawstudio.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rawstudio.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -54,9 +54,8 @@
 #include "rs-filetypes.h"
 #include "rs-utils.h"
 
-static void photo_settings_changed(RS_PHOTO *photo, gint mask, RS_BLOB *rs);
+static void photo_settings_changed(RS_PHOTO *photo, RSSettingsMask mask, RS_BLOB *rs);
 static void photo_spatial_changed(RS_PHOTO *photo, RS_BLOB *rs);
-static RS_SETTINGS *rs_settings_new();
 static void rs_gdk_load_meta(const gchar *src, RSMetadata *metadata);
 
 RS_FILETYPE *filetypes;
@@ -147,7 +146,7 @@
 }
 
 static void
-photo_settings_changed(RS_PHOTO *photo, gint mask, RS_BLOB *rs)
+photo_settings_changed(RS_PHOTO *photo, RSSettingsMask mask, RS_BLOB *rs)
 {
 	const gint snapshot = mask>>24;
 	mask &= 0x00ffffff;
@@ -163,17 +162,9 @@
 		rs_histogram_set_color_transform(RS_HISTOGRAM_WIDGET(rs->histogram), rs->histogram_transform);
 
 		/* Update histogram in curve */
-		rs_curve_draw_histogram(RS_CURVE_WIDGET(rs->settings[rs->current_setting]->curve),
+		rs_curve_draw_histogram(RS_CURVE_WIDGET(rs->curve[rs->current_setting]),
 			rs->histogram_dataset,
 			rs->photo->settings[rs->current_setting]);
-
-		/* Update local settings according to photo */
-		rs->mute_signals_to_photo = TRUE;
-		/* FIXME: This 'if' is just a workaround for a bug in rs_photo_apply_settings() */
-		if (mask)
-			rs_settings_double_to_rs_settings(rs->photo->settings[rs->current_setting],
-				rs->settings[rs->current_setting], mask);
-		rs->mute_signals_to_photo = FALSE;
 	}
 }
 
@@ -192,6 +183,7 @@
 
 		rs_histogram_set_image(RS_HISTOGRAM_WIDGET(rs->histogram), rs->histogram_dataset);
 
+		/* Force update of histograms */
 		photo_settings_changed(photo, MASK_ALL, rs);
 	}
 }
@@ -199,7 +191,6 @@
 void
 rs_set_photo(RS_BLOB *rs, RS_PHOTO *photo)
 {
-	gint c;
 	g_assert(rs != NULL);
 
 	/* Unref old photo if any */
@@ -207,14 +198,16 @@
 		g_object_unref(rs->photo);
 	rs->photo = NULL;
 
-	for(c=0;c<3;c++)
-		rs_settings_reset(rs->settings[c], MASK_ALL);
-
 	/* Apply settings from photo */
-	rs_settings_double_to_rs_settings(photo->settings[0], rs->settings[0], MASK_ALL);
-	rs_settings_double_to_rs_settings(photo->settings[1], rs->settings[1], MASK_ALL);
-	rs_settings_double_to_rs_settings(photo->settings[2], rs->settings[2], MASK_ALL);
+	rs_settings_copy(photo->settings[0], MASK_ALL, rs->settings[0]);
+	rs_settings_copy(photo->settings[1], MASK_ALL, rs->settings[1]);
+	rs_settings_copy(photo->settings[2], MASK_ALL, rs->settings[2]);
 
+	/* make sure we're synchronized */
+	rs_settings_link(rs->settings[0], photo->settings[0]);
+	rs_settings_link(rs->settings[1], photo->settings[1]);
+	rs_settings_link(rs->settings[2], photo->settings[2]);
+
 	/* Set photo in preview-widget */
 	rs_preview_widget_set_photo(RS_PREVIEW_WIDGET(rs->preview), photo);
 
@@ -247,180 +240,6 @@
 		photo_settings_changed(rs->photo, MASK_ALL|(snapshot<<24), rs);
 }
 
-void
-rs_settings_to_rs_settings_double(RS_SETTINGS *rs_settings, RS_SETTINGS_DOUBLE *rs_settings_double)
-{
-	if (rs_settings==NULL)
-		return;
-	if (rs_settings_double==NULL)
-		return;
-	rs_settings_double->exposure = GETVAL(rs_settings->exposure);
-	rs_settings_double->saturation = GETVAL(rs_settings->saturation);
-	rs_settings_double->hue = GETVAL(rs_settings->hue);
-	rs_settings_double->contrast = GETVAL(rs_settings->contrast);
-	rs_settings_double->warmth = GETVAL(rs_settings->warmth);
-	rs_settings_double->tint = GETVAL(rs_settings->tint);
-	rs_settings_double->sharpen = GETVAL(rs_settings->sharpen);
-	rs_curve_widget_get_knots(RS_CURVE_WIDGET(rs_settings->curve), &rs_settings_double->curve_knots, &rs_settings_double->curve_nknots);
-	return;
-}
-
-void
-rs_settings_double_to_rs_settings(RS_SETTINGS_DOUBLE *rs_settings_double, RS_SETTINGS *rs_settings, gint mask)
-{
-	if (rs_settings_double==NULL)
-		return;
-	if (rs_settings==NULL)
-		return;
-
-	if (mask == 0)
-		return;
-	if (mask & MASK_EXPOSURE)
-		SETVAL(rs_settings->exposure, rs_settings_double->exposure);
-	if (mask & MASK_SATURATION)
-	SETVAL(rs_settings->saturation, rs_settings_double->saturation);
-	if (mask & MASK_HUE)
-		SETVAL(rs_settings->hue, rs_settings_double->hue);
-	if (mask & MASK_CONTRAST)
-		SETVAL(rs_settings->contrast, rs_settings_double->contrast);
-	if (mask & MASK_WARMTH)
-		SETVAL(rs_settings->warmth, rs_settings_double->warmth);
-	if (mask & MASK_TINT)
-		SETVAL(rs_settings->tint, rs_settings_double->tint);
-	if (mask & MASK_SHARPEN)
-		SETVAL(rs_settings->sharpen, rs_settings_double->sharpen);
-	if (mask & MASK_CURVE)
-	{
-		gulong handler = g_signal_handler_find(rs_settings->curve, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, update_preview_callback, NULL);
-		g_signal_handler_block(rs_settings->curve, handler);
-		rs_curve_widget_reset(RS_CURVE_WIDGET(rs_settings->curve));
-		if (rs_settings_double->curve_nknots>0)
-		{
-			gint i;
-			for(i=0;i<rs_settings_double->curve_nknots;i++)
-				rs_curve_widget_add_knot(RS_CURVE_WIDGET(rs_settings->curve), rs_settings_double->curve_knots[i*2+0],
-					rs_settings_double->curve_knots[i*2+1]);
-		}
-		else
-		{
-			rs_curve_widget_add_knot(RS_CURVE_WIDGET(rs_settings->curve), 0.0f, 0.0f);
-			rs_curve_widget_add_knot(RS_CURVE_WIDGET(rs_settings->curve), 1.0f, 1.0f);
-		}
-		g_signal_handler_unblock(rs_settings->curve, handler);
-	}
-	return;
-}
-
-void
-rs_settings_reset(RS_SETTINGS *rss, guint mask)
-{
-	if (mask & MASK_EXPOSURE)
-		gtk_adjustment_set_value((GtkAdjustment *) rss->exposure, 0.0);
-	if (mask & MASK_SATURATION)
-		gtk_adjustment_set_value((GtkAdjustment *) rss->saturation, 1.0);
-	if (mask & MASK_HUE)
-		gtk_adjustment_set_value((GtkAdjustment *) rss->hue, 0.0);
-	if (mask & MASK_CONTRAST)
-		gtk_adjustment_set_value((GtkAdjustment *) rss->contrast, 1.0);
-	if (mask & MASK_WARMTH)
-		gtk_adjustment_set_value((GtkAdjustment *) rss->warmth, 0.0);
-	if (mask & MASK_TINT)
-		gtk_adjustment_set_value((GtkAdjustment *) rss->tint, 0.0);
-	if (mask & MASK_SHARPEN)
-		gtk_adjustment_set_value((GtkAdjustment *) rss->sharpen, 0.0);
-	if (mask & MASK_CURVE)
-	{
-		rs_curve_widget_reset(RS_CURVE_WIDGET(rss->curve));
-		rs_curve_widget_add_knot(RS_CURVE_WIDGET(rss->curve), 0.0f, 0.0f);
-		rs_curve_widget_add_knot(RS_CURVE_WIDGET(rss->curve), 1.0f, 1.0f);
-	}
-	return;
-}
-
-static RS_SETTINGS *
-rs_settings_new(void)
-{
-	RS_SETTINGS *rss;
-	rss = g_malloc(sizeof(RS_SETTINGS));
-	rss->exposure = gtk_adjustment_new(0.0, -3.0, 3.0, 0.1, 0.5, 0.0);
-	rss->saturation = gtk_adjustment_new(1.0, 0.0, 3.0, 0.1, 0.5, 0.0);
-	rss->hue = gtk_adjustment_new(0.0, -180.0, 180.0, 0.1, 30.0, 0.0);
-	rss->contrast = gtk_adjustment_new(1.0, 0.0, 3.0, 0.1, 0.5, 0.0);
-	rss->warmth = gtk_adjustment_new(0.0, -2.0, 2.0, 0.1, 0.5, 0.0);
-	rss->tint = gtk_adjustment_new(0.0, -2.0, 2.0, 0.1, 0.5, 0.0);
-	rss->sharpen = gtk_adjustment_new(0.0, 0.0, 10.0, 0.1, 0.5, 0.0);
-	rss->curve = rs_curve_widget_new();
-	return(rss);
-}
-
-RS_SETTINGS_DOUBLE *
-rs_settings_double_new(void)
-{
-	RS_SETTINGS_DOUBLE *rssd;
-	rssd = g_malloc(sizeof(RS_SETTINGS_DOUBLE));
-	rssd->exposure = 0.0;
-	rssd->saturation = 1.0;
-	rssd->hue = 0.0;
-	rssd->contrast = 1.0;
-	rssd->warmth = 0.0;
-	rssd->tint = 0.0;
-	rssd->sharpen = 0.0;
-
-	/* Initialize curve with some sane values */
-	rssd->curve_nknots = 2;
-	rssd->curve_knots = g_new(gfloat, 4);
-	rssd->curve_knots[0] = 0.0;
-	rssd->curve_knots[1] = 0.0;
-	rssd->curve_knots[2] = 1.0;
-	rssd->curve_knots[3] = 1.0;
-	return rssd;
-}
-
-void
-rs_settings_double_copy(const RS_SETTINGS_DOUBLE *in, RS_SETTINGS_DOUBLE *out, gint mask)
-{
-	g_assert(in);
-	g_assert(out);
-	if (mask & MASK_EXPOSURE)
-		out->exposure = in->exposure;
-	if (mask & MASK_SATURATION)
-		out->saturation = in->saturation;
-	if (mask & MASK_HUE)
-		out->hue = in->hue;
-	if (mask & MASK_CONTRAST)
-		out->contrast = in->contrast;
-	if (mask & MASK_WARMTH)
-		out->warmth = in->warmth;
-	if (mask & MASK_TINT)
-		out->tint = in->tint;
-	if (mask & MASK_SHARPEN)
-		out->sharpen = in->sharpen;
-	if (mask & MASK_CURVE)
-	{
-
-		if (in->curve_nknots>1)
-		{
-			gint i;
-
-			out->curve_nknots = in->curve_nknots;
-			if (out->curve_knots)
-				g_free(out->curve_knots);
-			out->curve_knots = g_new(gfloat, out->curve_nknots*2);
-			
-			for(i=0;i<in->curve_nknots*2;i++)
-				out->curve_knots[i] = in->curve_knots[i];
-		}
-	}
-	return;
-}
-
-void
-rs_settings_double_free(RS_SETTINGS_DOUBLE *rssd)
-{
-	g_free(rssd);
-	return;
-}
-
 gboolean
 rs_photo_save(RS_PHOTO *photo, const gchar *filename, gint filetype, gint width, gint height, gboolean keep_aspect, gdouble scale, gint snapshot, RS_CMS *cms)
 {
@@ -534,7 +353,6 @@
 	rs->histogram_dataset = NULL;
 	rs->histogram_transform = rs_color_transform_new();
 	rs->settings_buffer = NULL;
-	rs->mute_signals_to_photo = FALSE;
 	rs->photo = NULL;
 	rs->queue = rs_batch_new_queue();
 	rs->current_setting = 0;
@@ -587,47 +405,11 @@
 		}
 		whitepoint = (gdouble) i / (gdouble) 255;
 
-		rs_curve_widget_move_knot(RS_CURVE_WIDGET(rs->settings[rs->current_setting]->curve),0,blackpoint,0.0);
-		rs_curve_widget_move_knot(RS_CURVE_WIDGET(rs->settings[rs->current_setting]->curve),-1,whitepoint,1.0);
+		rs_curve_widget_move_knot(RS_CURVE_WIDGET(rs->curve[rs->current_setting]),0,blackpoint,0.0);
+		rs_curve_widget_move_knot(RS_CURVE_WIDGET(rs->curve[rs->current_setting]),-1,whitepoint,1.0);
 	}
 }
 
-void
-rs_apply_settings_from_double(RS_SETTINGS *rss, RS_SETTINGS_DOUBLE *rsd, gint mask)
-{
-	if (mask & MASK_EXPOSURE)
-		SETVAL(rss->exposure,rsd->exposure);
-	if (mask & MASK_SATURATION)
-		SETVAL(rss->saturation,rsd->saturation);
-	if (mask & MASK_HUE)
-		SETVAL(rss->hue,rsd->hue);
-	if (mask & MASK_CONTRAST)
-		SETVAL(rss->contrast,rsd->contrast);
-	if (mask & MASK_WARMTH)
-		SETVAL(rss->warmth,rsd->warmth);
-	if (mask & MASK_TINT)
-		SETVAL(rss->tint,rsd->tint);
-	if (mask & MASK_CURVE) {
-		rs_curve_widget_reset(RS_CURVE_WIDGET(rss->curve));
-
-		if (rsd->curve_nknots>1)
-		{
-			gint i;
-			for(i=0;i<rsd->curve_nknots;i++)
-				rs_curve_widget_add_knot(RS_CURVE_WIDGET(rss->curve), 
-										rsd->curve_knots[i*2+0],
-										rsd->curve_knots[i*2+1]
-										);
-		}
-		else
-		{
-			rs_curve_widget_add_knot(RS_CURVE_WIDGET(rss->curve), 0.0f, 0.0f);
-			rs_curve_widget_add_knot(RS_CURVE_WIDGET(rss->curve), 1.0f, 1.0f);
-		}
-	}
-	return;
-}
-
 /**
  * This is a very simple regression test for Rawstudio. Filenames will be read
  * from "testimages" in the current directory, one filename per line, and a

Modified: trunk/src/rawstudio.h
===================================================================
--- trunk/src/rawstudio.h	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rawstudio.h	2008-09-30 18:46:18 UTC (rev 2053)
@@ -39,20 +39,6 @@
 #define ORIENTATION_FLIP(orientation) orientation = (orientation^4)
 #define ORIENTATION_MIRROR(orientation) orientation = ((orientation&4)^4) | ((orientation+2)&3)
 
-enum {
-	MASK_EXPOSURE = 1,
-	MASK_SATURATION = 2,
-	MASK_HUE = 4,
-	MASK_CONTRAST = 8,
-	MASK_WARMTH = 16,
-	MASK_TINT = 32,
-	MASK_CURVE = 64,
-	MASK_SHARPEN = 128,
-	MASK_ALL = 0x00ffffff,
-};
-
-#define MASK_WB (MASK_WARMTH|MASK_TINT)
-
 #if __GNUC__ >= 3
 #define likely(x) __builtin_expect (!!(x), 1)
 #define unlikely(x) __builtin_expect (!!(x), 0)
@@ -87,6 +73,8 @@
 /* Defined in rs-image.h */
 typedef struct _rs_image16 RS_IMAGE16;
 
+#include "rs-settings.h" /* FIXME: This is getting pathetic */
+
 typedef struct {double coeff[3][3]; } RS_MATRIX3;
 typedef struct {int coeff[3][3]; } RS_MATRIX3Int;
 typedef struct {double coeff[4][4]; } RS_MATRIX4;
@@ -99,34 +87,11 @@
 	gint y2;
 } RS_RECT;
 
-typedef struct {
-	GtkObject *exposure;
-	GtkObject *saturation;
-	GtkObject *hue;
-	GtkObject *contrast;
-	GtkObject *warmth;
-	GtkObject *tint;
-	GtkObject *sharpen;
-	GtkWidget *curve;
-} RS_SETTINGS;
-
-typedef struct {
-	gdouble exposure;
-	gdouble saturation;
-	gdouble hue;
-	gdouble contrast;
-	gdouble warmth;
-	gdouble tint;
-	gdouble sharpen;
-	guint curve_nknots;
-	gfloat *curve_knots;
-} RS_SETTINGS_DOUBLE;
-
 typedef struct _photo {
 	GObject parent;
 	gchar *filename;
 	RS_IMAGE16 *input;
-	RS_SETTINGS_DOUBLE *settings[3];
+	RSSettings *settings[3];
 	gint priority;
 	guint orientation;
 	RSMetadata *metadata;
@@ -137,10 +102,10 @@
 } RS_PHOTO;
 
 typedef struct {
-	gboolean mute_signals_to_photo;
 	RS_PHOTO *photo;
-	RS_SETTINGS_DOUBLE *settings_buffer;
-	RS_SETTINGS *settings[3];
+	RSSettings *settings_buffer;
+	RSSettings *settings[3];
+	GtkWidget *curve[3];
 	gint current_setting;
 	RS_IMAGE16 *histogram_dataset;
 	GtkWidget *histogram;
@@ -173,20 +138,13 @@
 	struct _rs_filetype *next;
 } RS_FILETYPE;
 
-void rs_settings_to_rs_settings_double(RS_SETTINGS *rs_settings, RS_SETTINGS_DOUBLE *rs_settings_double);
-void rs_settings_double_to_rs_settings(RS_SETTINGS_DOUBLE *rs_settings_double, RS_SETTINGS *rs_settings, gint mask);
-void rs_settings_reset(RS_SETTINGS *rss, guint mask);
 gboolean rs_photo_save(RS_PHOTO *photo, const gchar *filename, gint filetype,
 	gint width, gint height, gboolean keep_aspect, gdouble scale, gint snapshot, RS_CMS *cms);
-RS_SETTINGS_DOUBLE *rs_settings_double_new(void);
-void rs_settings_double_copy(const RS_SETTINGS_DOUBLE *in, RS_SETTINGS_DOUBLE *out, gint mask);
-void rs_settings_double_free(RS_SETTINGS_DOUBLE *rssd);
 RS_BLOB *rs_new();
 void rs_free(RS_BLOB *rs);
 void rs_set_photo(RS_BLOB *rs, RS_PHOTO *photo);
 void rs_set_snapshot(RS_BLOB *rs, gint snapshot);
 void rs_white_black_point(RS_BLOB *rs);
-void rs_apply_settings_from_double(RS_SETTINGS *rss, RS_SETTINGS_DOUBLE *rsd, gint mask);
 
 /* Contains a list of supported filetypes */
 extern RS_FILETYPE *filetypes;

Modified: trunk/src/rs-actions.c
===================================================================
--- trunk/src/rs-actions.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-actions.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -333,15 +333,15 @@
 ACTION(copy_settings)
 {
 	if (!rs->settings_buffer)
-		rs->settings_buffer = g_new(RS_SETTINGS_DOUBLE, 1);
-	rs_settings_to_rs_settings_double(rs->settings[rs->current_setting], rs->settings_buffer);
+		rs->settings_buffer = rs_settings_new();
+	rs_settings_copy(rs->settings[rs->current_setting], MASK_ALL, rs->settings_buffer);
 	gui_status_notify(_("Copied settings"));
 }
 
 ACTION(paste_settings)
 {
-	gint mask = 0xffffff;
-	
+	gint mask = 0xffffff; /* Should be RSSettingsMask, is gint to satisfy rs_conf_get_integer() */
+
 	GtkWidget *dialog, *cb_box;
 	GtkWidget *cb_exposure, *cb_saturation, *cb_hue, *cb_contrast, *cb_whitebalance, *cb_curve, *cb_sharpen;
 
@@ -429,14 +429,14 @@
 				photo = rs_photo_new();
 				photo->filename = g_strdup(g_list_nth_data(selected, cur));
 				new_mask = rs_cache_load(photo);
-				rs_settings_double_copy(rs->settings_buffer, photo->settings[rs->current_setting], mask);
+				rs_settings_copy(rs->settings_buffer, mask, photo->settings[rs->current_setting]);
 				rs_cache_save(photo, new_mask | mask);
 				g_object_unref(photo);
 			}
 			g_list_free(selected);
 
 			/* Apply to current photo */
-			rs_photo_apply_settings_double(rs->photo, rs->current_setting, rs->settings_buffer, mask);
+			rs_settings_copy(rs->settings_buffer, mask, rs->settings[rs->current_setting]); 
 
 			gui_status_notify(_("Pasted settings"));
 		}
@@ -459,6 +459,7 @@
 {
 	gui_make_preference_window(rs);
 }
+
 ACTION(flag_for_deletion)
 {
 	gui_setprio(rs, PRIO_D);

Modified: trunk/src/rs-cache.c
===================================================================
--- trunk/src/rs-cache.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-cache.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -28,7 +28,7 @@
 /* This will be written to XML files for making backward compatibility easier to implement */
 #define CACHEVERSION 2
 
-static guint rs_cache_load_setting(RS_SETTINGS_DOUBLE *rss, xmlDocPtr doc, xmlNodePtr cur);
+static guint rs_cache_load_setting(RSSettings *rss, xmlDocPtr doc, xmlNodePtr cur);
 
 gchar *
 rs_cache_get_name(const gchar *src)
@@ -53,7 +53,7 @@
 }
 
 void
-rs_cache_save(RS_PHOTO *photo, guint mask)
+rs_cache_save(RS_PHOTO *photo, const RSSettingsMask mask)
 {
 	gint id, i;
 	xmlTextWriterPtr writer;
@@ -126,11 +126,11 @@
 }
 
 static guint
-rs_cache_load_setting(RS_SETTINGS_DOUBLE *rss, xmlDocPtr doc, xmlNodePtr cur)
+rs_cache_load_setting(RSSettings *rss, xmlDocPtr doc, xmlNodePtr cur)
 {
-	guint mask = 0;
+	RSSettingsMask mask = 0;
 	xmlChar *val;
-	gdouble *target=NULL;
+	gfloat *target=NULL;
 	xmlNodePtr curve = NULL;
 	while(cur)
 	{
@@ -223,14 +223,14 @@
 guint
 rs_cache_load(RS_PHOTO *photo)
 {
-	guint mask = 0;
+	RSSettingsMask mask = 0;
 	xmlDocPtr doc;
 	xmlNodePtr cur;
 	xmlChar *val;
 	gchar *cachename;
 	gint id;
 	gint version = 0;
-	RS_SETTINGS_DOUBLE *settings;
+	RSSettings *settings;
 
 	cachename = rs_cache_get_name(photo->filename);
 	if (!cachename) return mask;
@@ -261,10 +261,10 @@
 			xmlFree(val);
 			if (id>2) id=0;
 			if (id<0) id=0;
-			settings = rs_settings_double_new();
+			settings = rs_settings_new();
 			mask |= rs_cache_load_setting(settings, doc, cur->xmlChildrenNode);
-			rs_photo_apply_settings_double(photo, id, settings, MASK_ALL);
-			rs_settings_double_free(settings);
+			rs_photo_apply_settings(photo, id, settings, MASK_ALL);
+			g_object_unref(settings);
 		}
 		else if ((!xmlStrcmp(cur->name, BAD_CAST "priority")))
 		{
@@ -395,7 +395,7 @@
 rs_cache_save_flags(const gchar *filename, const guint *priority, const gboolean *exported)
 {
 	RS_PHOTO *photo;
-	guint mask;
+	RSSettingsMask mask;
 
 	g_assert(filename != NULL);
 

Modified: trunk/src/rs-cache.h
===================================================================
--- trunk/src/rs-cache.h	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-cache.h	2008-09-30 18:46:18 UTC (rev 2053)
@@ -21,7 +21,7 @@
 #define RS_CACHE_H
 
 extern gchar *rs_cache_get_name(const gchar *src);
-extern void rs_cache_save(RS_PHOTO *photo, guint mask);
+extern void rs_cache_save(RS_PHOTO *photo, const RSSettingsMask mask);
 extern guint rs_cache_load(RS_PHOTO *photo);
 extern void rs_cache_load_quick(const gchar *filename, gint *priority, gboolean *exported);
 extern void rs_cache_save_flags(const gchar *filename, const guint *priority, const gboolean *exported);

Modified: trunk/src/rs-color-transform.c
===================================================================
--- trunk/src/rs-color-transform.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-color-transform.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -53,9 +53,7 @@
 	RS_MATRIX4 adobe_matrix;
 	guchar *table8;
 	gushort *table16;
-	rs_spline_t *spline;
 	gint nknots;
-	gfloat *knots;
 	gfloat *curve_samples;
 	void *cms_transform;
 };
@@ -96,9 +94,7 @@
 	rct->bits_per_color = 8;
 	matrix4_identity(&rct->color_matrix);
 	matrix4_identity(&rct->adobe_matrix);
-	rct->spline = NULL;
 	rct->nknots = 0;
-	rct->knots = NULL;
 	rct->curve_samples = g_new(gfloat, 65536);
 	for(i=0;i<65536;i++)
 		rct->curve_samples[i] = ((gfloat)i)/65536.0;
@@ -204,7 +200,7 @@
 }
 
 void
-rs_color_transform_set_from_settings(RSColorTransform *rct, RS_SETTINGS_DOUBLE *settings, guint mask)
+rs_color_transform_set_from_settings(RSColorTransform *rct, RSSettings *settings, const RSSettingsMask mask)
 {
 	gboolean update_tables = FALSE;
 
@@ -218,62 +214,53 @@
 		else
 			rct->color_matrix = rct->adobe_matrix;
 
-		matrix4_color_exposure(&rct->color_matrix, settings->exposure);
-		matrix4_color_saturate(&rct->color_matrix, settings->saturation);
-		matrix4_color_hue(&rct->color_matrix, settings->hue);
+		matrix4_color_exposure(&rct->color_matrix, rs_settings_get_exposure(settings));
+		matrix4_color_saturate(&rct->color_matrix, rs_settings_get_saturation(settings));
+		matrix4_color_hue(&rct->color_matrix, rs_settings_get_hue(settings));
 	}
 
 	if (mask & MASK_WB)
 	{
-		rct->pre_mul[R] = (1.0+settings->warmth)*(2.0-settings->tint);
+		const gfloat warmth = rs_settings_get_warmth(settings);
+		const gfloat tint = rs_settings_get_tint(settings);
+		rct->pre_mul[R] = (1.0+warmth)*(2.0-tint);
 		rct->pre_mul[G] = 1.0;
-		rct->pre_mul[B] = (1.0-settings->warmth)*(2.0-settings->tint);
+		rct->pre_mul[B] = (1.0-warmth)*(2.0-tint);
 		rct->pre_mul[G2] = 1.0;
 	}
 
 	if (mask & MASK_CONTRAST)
 	{
-		if (rct->contrast != settings->contrast)
+		if (rct->contrast != rs_settings_get_contrast(settings))
 		{
 			update_tables = TRUE;
-			rct->contrast = settings->contrast;
+			rct->contrast = rs_settings_get_contrast(settings);
 		}
 	}
 
 	if (mask & MASK_CURVE)
 	{
-		if (settings->curve_nknots < 2)
+		const gint nknots = rs_settings_get_curve_nknots(settings);
+
+		if (nknots > 1)
 		{
-			if (rct->knots)
+			gfloat *knots = rs_settings_get_curve_knots(settings);
+			if (knots)
 			{
-				g_free(rct->knots);
-				rct->knots = NULL;
-				rct->nknots = 0;
+				rct->nknots = nknots;
+				rs_spline_t *spline = rs_spline_new(knots, rct->nknots, NATURAL);
+				rs_spline_sample(spline, rct->curve_samples, 65536);
+				rs_spline_destroy(spline);
+				g_free(knots);
 				update_tables = TRUE;
 			}
 		}
-		if ((settings->curve_nknots > 1) && (rct->nknots != settings->curve_nknots))
+		else
 		{
-			rct->nknots = settings->curve_nknots;
-			if (rct->knots)
-			{
-				g_free(rct->knots);
-				rct->knots = NULL;
-			}
-			rct->knots = g_new0(gfloat, rct->nknots*2);
+			gint i;
+			for(i=0;i<65536;i++)
+				rct->curve_samples[i] = ((gfloat)i)/65536.0;
 		}
-		if ((settings->curve_nknots > 1) && (rct->nknots == settings->curve_nknots))
-		{
-			if (memcmp(rct->knots, settings->curve_knots, rct->nknots*sizeof(gfloat)*2) != 0)
-			{
-				memcpy(rct->knots, settings->curve_knots, rct->nknots*sizeof(gfloat)*2);
-				if (rct->spline)
-					rs_spline_destroy(rct->spline);
-				rct->spline = rs_spline_new(rct->knots, rct->nknots, NATURAL);
-				rs_spline_sample(rct->spline, rct->curve_samples, 65536);
-				update_tables = TRUE;
-			}
-		}
 	}
 
 	if (update_tables)

Modified: trunk/src/rs-color-transform.h
===================================================================
--- trunk/src/rs-color-transform.h	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-color-transform.h	2008-09-30 18:46:18 UTC (rev 2053)
@@ -23,6 +23,7 @@
 #include <glib-object.h>
 #include "rawstudio.h"
 #include "rs-math.h"
+#include "rs-settings.h"
 
 #define RS_TYPE_COLOR_TRANSFORM rs_color_transform_get_type()
 #define RS_COLOR_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), RS_TYPE_COLOR_TRANSFORM, RSColorTransform))
@@ -51,7 +52,7 @@
 extern gboolean rs_color_transform_set_contrast(RSColorTransform *rct, gdouble contrast);
 extern gboolean rs_color_transform_set_premul(RSColorTransform *rct, gfloat *premul);
 extern gboolean rs_color_transform_set_matrix(RSColorTransform *rct, RS_MATRIX4 *matrix);
-void rs_color_transform_set_from_settings(RSColorTransform *rct, RS_SETTINGS_DOUBLE *settings, guint mask);
+void rs_color_transform_set_from_settings(RSColorTransform *rct, RSSettings *settings, const RSSettingsMask mask);
 extern gboolean rs_color_transform_set_curve(RSColorTransform *rct, gfloat *curve);
 extern void rs_color_transform_set_all(RSColorTransform *rct, gdouble gamma,
 	gdouble contrast, gfloat *premul, RS_MATRIX4 *matrix, gfloat *curve);

Modified: trunk/src/rs-curve.c
===================================================================
--- trunk/src/rs-curve.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-curve.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -44,7 +44,7 @@
 	guint histogram_data[4][256];
 	guchar *bg_buffer;
 	RSColorTransform *rct;
-	RS_SETTINGS_DOUBLE *settings;
+	RSSettings *settings;
 };
 
 struct _RSCurveWidgetClass
@@ -122,7 +122,7 @@
 	curve->spline = rs_spline_new(NULL, 0, NATURAL);
 	curve->marker = -1.0;
 	curve->bg_buffer = NULL;
-	curve->settings = rs_settings_double_new();
+	curve->settings = rs_settings_new();
 	curve->settings->saturation = 0.0f; /* We want the histogram to be desaturated */
 	curve->rct = rs_color_transform_new();
 	rs_color_transform_set_gamma(curve->rct, GAMMA);
@@ -198,9 +198,9 @@
  * @param setting Settings to use, curve and saturation will be ignored
  */
 void
-rs_curve_draw_histogram(RSCurveWidget *curve, RS_IMAGE16 *image, RS_SETTINGS_DOUBLE *settings)
+rs_curve_draw_histogram(RSCurveWidget *curve, RS_IMAGE16 *image, RSSettings *settings)
 {
-	rs_settings_double_copy(settings, curve->settings, MASK_ALL-MASK_CURVE);
+	rs_settings_copy(settings, MASK_ALL-MASK_CURVE-MASK_SATURATION, curve->settings);
 	rs_color_transform_set_from_settings(curve->rct, curve->settings, MASK_ALL);
 	rs_color_transform_make_histogram(curve->rct, image, curve->histogram_data);
 
@@ -305,6 +305,36 @@
 }
 
 /**
+ * Set knots of a RSCurveWidget
+ * @param curve A RSCurveWidget
+ * @param knots An array of knots (two values/knot)
+ * @param nknots Number of knots
+ */
+void
+rs_curve_widget_set_knots(RSCurveWidget *curve, gfloat *knots, guint nknots)
+{
+	gint i;
+
+	g_assert(RS_IS_CURVE_WIDGET(curve));
+
+	/* Free thew current spline */
+	rs_spline_destroy(curve->spline);
+
+	/* Allocate new spline */
+	curve->spline = rs_spline_new(NULL, 0, NATURAL);
+
+	/* Add the knot */
+	for(i=0;i<nknots;i++)
+		rs_spline_add(curve->spline, knots[i*2], knots[i*2+1]);
+
+	/* Redraw the widget */
+	rs_curve_draw(curve);
+
+	/* Propagate the change */
+	rs_curve_changed(curve);
+}
+
+/**
  * Get knots from a RSCurveWidget
  * @param curve A RSCurveWidget
  * @param knots An array of knots (two values/knot) (out)

Modified: trunk/src/rs-curve.h
===================================================================
--- trunk/src/rs-curve.h	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-curve.h	2008-09-30 18:46:18 UTC (rev 2053)
@@ -62,7 +62,7 @@
  * @param setting Settings to use, curve and saturation will be ignored
  */
 extern void
-rs_curve_draw_histogram(RSCurveWidget *curve, RS_IMAGE16 *image, RS_SETTINGS_DOUBLE *settings);
+rs_curve_draw_histogram(RSCurveWidget *curve, RS_IMAGE16 *image, RSSettings *settings);
 
 /**
  * Add a knot to a curve widget
@@ -94,6 +94,15 @@
 rs_curve_widget_sample(RSCurveWidget *curve, gfloat *samples, guint nbsamples);
 
 /**
+ * Set knots of a RSCurveWidget
+ * @param curve A RSCurveWidget
+ * @param knots An array of knots (two values/knot)
+ * @param nknots Number of knots
+ */
+extern void
+rs_curve_widget_set_knots(RSCurveWidget *curve, gfloat *knots, guint nknots);
+
+/**
  * Get knots from a RSCurveWidget
  * @param curve A RSCurveWidget
  * @param knots An array of knots (two values/knot) (out)

Modified: trunk/src/rs-photo.c
===================================================================
--- trunk/src/rs-photo.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-photo.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -41,6 +41,7 @@
 
 static GObjectClass *parent_class = NULL;
 
+static void photo_settings_changed_cb(RSSettings *settings, RSSettingsMask mask, gpointer user_data);
 static void
 rs_photo_dispose (GObject *obj)
 {
@@ -69,7 +70,7 @@
 		g_object_unref(photo->input);
 
 	for(c=0;c<3;c++)
-		rs_settings_double_free(photo->settings[c]);
+		g_object_unref(photo->settings[c]);
 	if (photo->crop)
 		g_free(photo->crop);
 
@@ -116,12 +117,31 @@
 	photo->priority = PRIO_U;
 	photo->metadata = rs_metadata_new();
 	for(c=0;c<3;c++)
-		photo->settings[c] = rs_settings_double_new();
+	{
+		photo->settings[c] = rs_settings_new();
+		g_signal_connect(photo->settings[c], "settings-changed", G_CALLBACK(photo_settings_changed_cb), photo);
+	}
 	photo->crop = NULL;
 	photo->angle = 0.0;
 	photo->exported = FALSE;
 }
 
+static void
+photo_settings_changed_cb(RSSettings *settings, RSSettingsMask mask, gpointer user_data)
+{
+	gint i;
+	RS_PHOTO *photo = RS_PHOTO(user_data);
+
+	if (mask)
+		/* Find changed snapshot */
+		for(i=0;i<3;i++)
+			if (settings == photo->settings[i])
+			{
+				g_signal_emit(photo, signals[SETTINGS_CHANGED], 0, mask|(i<<24));
+				break;
+			}
+}
+
 /**
  * Allocates a new RS_PHOTO
  * @return A new RS_PHOTO
@@ -252,121 +272,26 @@
 #undef RS_PHOTO_SET_GDOUBLE_VALUE
 
 /**
- * Apply settings to a RS_PHOTO from a RS_SETTINGS
+ * Apply settings to a RS_PHOTO from a RSSettings
  * @param photo A RS_PHOTO
  * @param snapshot Which snapshot to affect
  * @param rs_settings The settings to apply
  * @param mask A mask for defining which settings to apply
  */
 void
-rs_photo_apply_settings(RS_PHOTO *photo, const gint snapshot, const RS_SETTINGS *rs_settings, const gint mask)
+rs_photo_apply_settings(RS_PHOTO *photo, const gint snapshot, RSSettings *settings, RSSettingsMask mask)
 {
-	gint changed_mask = 0;
+	g_assert(RS_IS_PHOTO(photo));
+	g_assert(RS_IS_SETTINGS(settings));
+	g_assert((snapshot>=0) && (snapshot<=2));
 
-	if (!photo) return;
-	if (!rs_settings) return;
-	g_return_if_fail ((snapshot>=0) && (snapshot<=2));
-
 	if (mask == 0)
 		return;
 
-	if (mask & MASK_EXPOSURE)
-		if (photo->settings[snapshot]->exposure != GETVAL(rs_settings->exposure))
-		{
-			photo->settings[snapshot]->exposure = GETVAL(rs_settings->exposure);
-			changed_mask |= MASK_EXPOSURE;
-		}
-
-	if (mask & MASK_SATURATION)
-		if (photo->settings[snapshot]->saturation != GETVAL(rs_settings->saturation))
-		{
-			photo->settings[snapshot]->saturation = GETVAL(rs_settings->saturation);
-			changed_mask |= MASK_SATURATION;
-		}
-
-	if (mask & MASK_HUE)
-		if (photo->settings[snapshot]->hue != GETVAL(rs_settings->hue))
-		{
-			photo->settings[snapshot]->hue = GETVAL(rs_settings->hue);
-			changed_mask |= MASK_HUE;
-		}
-
-	if (mask & MASK_CONTRAST)
-		if (photo->settings[snapshot]->contrast != GETVAL(rs_settings->contrast))
-		{
-			photo->settings[snapshot]->contrast = GETVAL(rs_settings->contrast);
-			changed_mask |= MASK_CONTRAST;
-		}
-
-	if (mask & MASK_WARMTH)
-		if (photo->settings[snapshot]->warmth != GETVAL(rs_settings->warmth))
-		{
-			photo->settings[snapshot]->warmth = GETVAL(rs_settings->warmth);
-			changed_mask |= MASK_WARMTH;
-		}
-
-	if (mask & MASK_TINT)
-		if (photo->settings[snapshot]->tint != GETVAL(rs_settings->tint))
-		{
-			photo->settings[snapshot]->tint = GETVAL(rs_settings->tint);
-			changed_mask |= MASK_TINT;
-		}
-
-	if (mask & MASK_SHARPEN)
-		if (photo->settings[snapshot]->sharpen != GETVAL(rs_settings->sharpen))
-		{
-			photo->settings[snapshot]->sharpen = GETVAL(rs_settings->sharpen);
-			changed_mask |= MASK_SHARPEN;
-		}
-
-	if (mask & MASK_CURVE)
-	{
-		gfloat *knots;
-		guint nknots;
-		gint i;
-
-		rs_curve_widget_get_knots(RS_CURVE_WIDGET(rs_settings->curve), &knots, &nknots);
-		if (nknots != photo->settings[snapshot]->curve_nknots)
-		{
-			rs_curve_widget_get_knots(RS_CURVE_WIDGET(rs_settings->curve), &photo->settings[snapshot]->curve_knots, &photo->settings[snapshot]->curve_nknots);
-			changed_mask |= MASK_CURVE;
-		}
-		else
-			for(i=0;i<(nknots*2);i++)
-			{
-				if (knots[i] != photo->settings[snapshot]->curve_knots[i])
-				{
-					rs_curve_widget_get_knots(RS_CURVE_WIDGET(rs_settings->curve), &photo->settings[snapshot]->curve_knots, &photo->settings[snapshot]->curve_nknots);
-					changed_mask |= MASK_CURVE;
-					break;
-				}
-			}
-	}
-
-	if (changed_mask)
-		g_signal_emit(photo, signals[SETTINGS_CHANGED], 0, changed_mask|(snapshot<<24));
+	rs_settings_copy(settings, mask, photo->settings[snapshot]);
 }
 
 /**
- * Apply settings to a RS_PHOTO from a RS_SETTINGS_DOUBLE
- * @param photo A RS_PHOTO
- * @param snapshot Which snapshot to affect
- * @param rs_settings_double The settings to apply
- * @param mask A mask for defining which settings to apply
- */
-void
-rs_photo_apply_settings_double(RS_PHOTO *photo, const gint snapshot, const RS_SETTINGS_DOUBLE *rs_settings_double, const gint mask)
-{
-	if (!photo) return;
-	if (!rs_settings_double) return;
-	g_return_if_fail ((snapshot>=0) && (snapshot<=2));
-
-	rs_settings_double_copy(rs_settings_double, photo->settings[snapshot], mask);
-
-	g_signal_emit(photo, signals[SETTINGS_CHANGED], 0, mask|(snapshot<<24));
-}
-
-/**
  * Flips a RS_PHOTO
  * @param photo A RS_PHOTO
  */
@@ -564,7 +489,7 @@
 {
 	RS_PHOTO *photo = NULL;
 	RS_IMAGE16 *image;
-	guint mask;
+	RSSettingsMask mask;
 	gint i;
 
 	/* Try preloaded first! */

Modified: trunk/src/rs-photo.h
===================================================================
--- trunk/src/rs-photo.h	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-photo.h	2008-09-30 18:46:18 UTC (rev 2053)
@@ -148,24 +148,15 @@
 extern void rs_photo_set_sharpen(RS_PHOTO *photo, const gint snapshot, const gdouble value);
 
 /**
- * Apply settings to a RS_PHOTO from a RS_SETTINGS
+ * Apply settings to a RS_PHOTO from a RSSettings
  * @param photo A RS_PHOTO
  * @param snapshot Which snapshot to affect
  * @param rs_settings The settings to apply
  * @param mask A mask for defining which settings to apply
  */
-extern void rs_photo_apply_settings(RS_PHOTO *photo, const gint snapshot, const RS_SETTINGS *rs_settings, const gint mask);
+extern void rs_photo_apply_settings(RS_PHOTO *photo, const gint snapshot, RSSettings *settings, RSSettingsMask mask);
 
 /**
- * Apply settings to a RS_PHOTO from a RS_SETTINGS_DOUBLE
- * @param photo A RS_PHOTO
- * @param snapshot Which snapshot to affect
- * @param rs_settings_double The settings to apply
- * @param mask A mask for defining which settings to apply
- */
-extern void rs_photo_apply_settings_double(RS_PHOTO *photo, const gint snapshot, const RS_SETTINGS_DOUBLE *rs_settings_double, const gint mask);
-
-/**
  * Flips a RS_PHOTO
  * @param photo A RS_PHOTO
  */

Modified: trunk/src/rs-preview-widget.c
===================================================================
--- trunk/src/rs-preview-widget.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/rs-preview-widget.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -183,7 +183,7 @@
 static void adjustment_changed(GtkAdjustment *adjustment, gpointer user_data);
 static gboolean button(GtkWidget *widget, GdkEventButton *event, RSPreviewWidget *preview);
 static gboolean motion(GtkWidget *widget, GdkEventMotion *event, gpointer user_data);
-static void settings_changed(RS_PHOTO *photo, gint mask, RSPreviewWidget *preview);
+static void settings_changed(RS_PHOTO *photo, RSSettingsMask mask, RSPreviewWidget *preview);
 static void spatial_changed(RS_PHOTO *photo, RSPreviewWidget *preview);
 static void input_changed(RS_IMAGE16 *image, RSPreviewWidget *preview);
 static void sharpened_changed(RS_IMAGE16 *image, RSPreviewWidget *preview);
@@ -1869,7 +1869,7 @@
 }
 
 static void
-settings_changed(RS_PHOTO *photo, gint mask, RSPreviewWidget *preview)
+settings_changed(RS_PHOTO *photo, RSSettingsMask mask, RSPreviewWidget *preview)
 {
 	gboolean update = FALSE;
 	gint view;

Modified: trunk/src/toolbox.c
===================================================================
--- trunk/src/toolbox.c	2008-09-29 00:55:31 UTC (rev 2052)
+++ trunk/src/toolbox.c	2008-09-30 18:46:18 UTC (rev 2053)
@@ -34,10 +34,13 @@
 #include "rs-photo.h"
 #include "rs-utils.h"
 
-/* used for gui_adj_reset_callback() */
+/* used for gui_adj_reset_callback() and others */
 struct cb_carrier {
-	RS_BLOB *rs;
-	gint mask;
+	RSSettings *settings;
+	RSSettingsMask mask;
+	gulong settings_signal_id;
+	GObject *obj;
+	gulong obj_signal_id; /* For signals FROM adj */
 };
 
 GtkLabel *infolabel;
@@ -50,10 +53,10 @@
 static void gui_transform_mirror_clicked(GtkWidget *w, RS_BLOB *rs);
 static void gui_transform_flip_clicked(GtkWidget *w, RS_BLOB *rs);
 static GtkWidget *gui_transform(RS_BLOB *rs, gboolean show);
-static GtkWidget *gui_tool_warmth(RS_BLOB *rs, gint n, gboolean show);
 static gboolean gui_adj_reset_callback(GtkWidget *widget, GdkEventButton *event, struct cb_carrier *rc);
-static void gui_adj_value_callback(GtkRange *range, gpointer user_data);
-static GtkWidget *gui_make_scale_from_adj(RS_BLOB *rs, GCallback cb, GtkObject *adj, gint mask);
+static void gui_adj_value_callback(GtkAdjustment *adj, gpointer user_data);
+static void curve_changed(GtkWidget *widget, gpointer user_data);
+static GtkWidget *gui_make_scale_from_adj(RSSettings *settings, gulong settings_signal_id, GCallback cb, GtkAdjustment *adj, RSSettingsMask mask);
 static void curve_context_callback_save(GtkMenuItem *menuitem, gpointer user_data);
 static void curve_context_callback_open(GtkMenuItem *menuitem, gpointer user_data);
 static void curve_context_callback_reset(GtkMenuItem *menuitem, gpointer user_data);
@@ -159,52 +162,63 @@
 	return(gui_box(_("Transforms"), hbox, show));
 }
 
-static GtkWidget *
-gui_tool_warmth(RS_BLOB *rs, gint n, gboolean show)
-{
-	GtkWidget *box;
-	GtkWidget *wscale;
-	GtkWidget *tscale;
-
-	wscale = gui_make_scale_from_adj(rs, G_CALLBACK(gui_adj_value_callback), rs->settings[n]->warmth, MASK_WARMTH);
-	tscale = gui_make_scale_from_adj(rs, G_CALLBACK(gui_adj_value_callback), rs->settings[n]->tint, MASK_TINT);
-
-	box = gtk_vbox_new (FALSE, 0);
-	gtk_box_pack_start (GTK_BOX (box), wscale, FALSE, FALSE, 0);
-	gtk_box_pack_start (GTK_BOX (box), tscale, FALSE, FALSE, 0);
-	return(gui_box(_("Warmth/tint"), box, show));
-}
-
 static gboolean
 gui_adj_reset_callback(GtkWidget *widget, GdkEventButton *event, struct cb_carrier *rc)
 {
-	rs_settings_reset(rc->rs->settings[rc->rs->current_setting], rc->mask);
+	rs_settings_reset(rc->settings, rc->mask);
 	return(TRUE);
 }
 
 static void
-gui_adj_value_callback(GtkRange *range, gpointer user_data)
+gui_adj_value_callback(GtkAdjustment *adj, gpointer user_data)
 {
 	struct cb_carrier *rc = (struct cb_carrier *) user_data;
 
-	if (!rc->rs->mute_signals_to_photo)
-		rs_photo_apply_settings(rc->rs->photo,
-			rc->rs->current_setting,
-			rc->rs->settings[rc->rs->current_setting], rc->mask);
+	g_signal_handler_block(rc->settings, rc->settings_signal_id);
+#define APPLY(lower, upper) \
+do { \
+	if (rc->mask & MASK_##upper) \
+		rs_settings_set_##lower(rc->settings, gtk_adjustment_get_value(adj)); \
+} while(0)
+	APPLY(exposure, EXPOSURE);
+	APPLY(saturation, SATURATION);
+	APPLY(hue, HUE);
+	APPLY(contrast, CONTRAST);
+	APPLY(warmth, WARMTH);
+	APPLY(tint, TINT);
+	APPLY(sharpen, SHARPEN);
+#undef APPLY
+	g_signal_handler_unblock(rc->settings, rc->settings_signal_id);
 }
 
+static void
+curve_changed(GtkWidget *widget, gpointer user_data)
+{
+	gfloat *knots;
+	guint nknots;
+	RSSettings *settings = RS_SETTINGS(user_data);
+
+	rs_curve_widget_get_knots(RS_CURVE_WIDGET(widget), &knots, &nknots);
+
+	rs_settings_set_curve_knots(settings, knots, nknots);
+
+	g_free(knots);
+}
+
 static GtkWidget *
-gui_make_scale_from_adj(RS_BLOB *rs, GCallback cb, GtkObject *adj, gint mask)
+gui_make_scale_from_adj(RSSettings *settings, gulong settings_signal_id, GCallback cb, GtkAdjustment *adj, RSSettingsMask mask)
 {
 	GtkWidget *hscale, *box, *rimage, *revent;
 	struct cb_carrier *rc = g_malloc(sizeof(struct cb_carrier));
-	rc->rs = rs;
+	rc->obj = G_OBJECT(adj);
 	rc->mask = mask;
+	rc->settings = settings;
+	rc->settings_signal_id = settings_signal_id;
 
 	box = gtk_hbox_new(FALSE, 0);
 
 	hscale = gtk_hscale_new((GtkAdjustment *) adj);
-	g_signal_connect(adj, "value_changed", cb, rc);
+	rc->obj_signal_id = g_signal_connect(adj, "value_changed", cb, rc);
 	gtk_scale_set_value_pos( GTK_SCALE(hscale), GTK_POS_LEFT);
 	gtk_scale_set_digits(GTK_SCALE(hscale), 2);
 
@@ -305,7 +319,7 @@
 {
 	RSCurveWidget *curve = RS_CURVE_WIDGET(user_data);
 
-	gulong handler = g_signal_handler_find(curve, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, update_preview_callback, NULL);
+	gulong handler = g_signal_handler_find(curve, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, curve_changed, NULL);
 	g_signal_handler_block(curve, handler);
 
 	rs_curve_widget_reset(curve);
@@ -392,6 +406,54 @@
 	rs_conf_set_boolean(name, expanded);
 }
 
+typedef struct {
+	GtkAdjustment *exposure;
+	GtkAdjustment *saturation;
+	GtkAdjustment *hue;
+	GtkAdjustment *contrast;
+	GtkAdjustment *warmth;
+	GtkAdjustment *tint;
+	GtkAdjustment *sharpen;
+	RSCurveWidget *curve;
+} ToolboxAdjusters;
+
+static void
+toolbox_settings_changed_cb(RSSettings *settings, RSSettingsMask mask, gpointer user_data)
+{
+	ToolboxAdjusters *adjusters = (ToolboxAdjusters *) user_data;
+
+/* Programmers are lazy */
+#define APPLY(lower, upper) do { \
+	if (mask & MASK_##upper) \
+	{\
+		g_signal_handlers_block_matched(adjusters->lower, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, gui_adj_value_callback, NULL); \
+		gtk_adjustment_set_value(adjusters->lower, rs_settings_get_##lower(settings)); \
+		g_signal_handlers_unblock_matched(adjusters->lower, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, gui_adj_value_callback, NULL); \
+	} \
+} while(0)
+	APPLY(exposure, EXPOSURE);
+	APPLY(saturation, SATURATION);
+	APPLY(hue, HUE);
+	APPLY(contrast, CONTRAST);
+	APPLY(warmth, WARMTH);
+	APPLY(tint, TINT);
+	APPLY(sharpen, SHARPEN);
+#undef APPLY
+
+	if (mask & MASK_CURVE)
+	{
+		gfloat *knots = rs_settings_get_curve_knots(settings);
+		const gint nknots = rs_settings_get_curve_nknots(settings);
+
+		/* Block handlers during update */
+		g_signal_handlers_block_matched(adjusters->curve, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, curve_changed, NULL); \
+		rs_curve_widget_set_knots(adjusters->curve, knots, nknots);
+		g_signal_handlers_unblock_matched(adjusters->curve, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, curve_changed, NULL); \
+
+		g_free(knots);
+	}
+}
+
 GtkWidget *
 make_toolbox(RS_BLOB *rs)
 {
@@ -419,59 +481,74 @@
 	notebook = gtk_notebook_new();
 
 	for(n = 0; n < 3; n++) {
+		GtkWidget *embed;
+		gulong settings_signal_id;
 		tbox[n] = gtk_vbox_new (FALSE, 0);
 		gtk_widget_show (tbox[n]);
 
-		rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_EXPOSURE, &show, DEFAULT_CONF_SHOW_TOOLBOX_EXPOSURE);
-		toolbox_exposure[n] = gui_box(_("Exposure"), gui_make_scale_from_adj(rs, 
-			G_CALLBACK(gui_adj_value_callback), rs->settings[n]->exposure, MASK_EXPOSURE), show);
-		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_exposure[n], FALSE, FALSE, 0);
-		g_signal_connect_after(toolbox_exposure[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_exposure);
-		g_signal_connect_after(toolbox_exposure[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_EXPOSURE);
+		ToolboxAdjusters *adjusters = g_new0(ToolboxAdjusters, 1);
 
-		rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_SATURATION, &show, DEFAULT_CONF_SHOW_TOOLBOX_SATURATION);
-		toolbox_saturation[n] = gui_box(_("Saturation"), gui_make_scale_from_adj(rs, 
-			G_CALLBACK(gui_adj_value_callback), rs->settings[n]->saturation, MASK_SATURATION), show);
-		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_saturation[n], FALSE, FALSE, 0);
-		g_signal_connect_after(toolbox_saturation[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_saturation);
-		g_signal_connect_after(toolbox_saturation[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_SATURATION);
+		settings_signal_id = g_signal_connect(rs->settings[n], "settings-changed", G_CALLBACK(toolbox_settings_changed_cb), adjusters);
 
-		rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_HUE, &show, DEFAULT_CONF_SHOW_TOOLBOX_HUE);
-		toolbox_hue[n] = gui_box(_("Hue"), gui_make_scale_from_adj(rs, 
-			G_CALLBACK(gui_adj_value_callback), rs->settings[n]->hue, MASK_HUE), show);
-		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_hue[n], FALSE, FALSE, 0);
-		g_signal_connect_after(toolbox_hue[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_hue);
-		g_signal_connect_after(toolbox_hue[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_HUE);
+#define SLIDER(lower, upper, label, floor, ceiling, step, page) \
+	adjusters->lower = GTK_ADJUSTMENT(gtk_adjustment_new(rs_settings_get_##lower(rs->settings[n]), floor, ceiling, step, page, 0.0)); \
+	rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_##upper, &show, DEFAULT_CONF_SHOW_TOOLBOX_##upper); \
+	embed = gui_make_scale_from_adj(rs->settings[n], settings_signal_id, G_CALLBACK(gui_adj_value_callback), adjusters->lower, MASK_##upper); \
+	toolbox_##lower[n] = gui_box(label, embed, show); \
+	gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_##lower[n], FALSE, FALSE, 0); \
+	g_signal_connect_after(toolbox_##lower[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_##lower); \
+	g_signal_connect_after(toolbox_##lower[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_##upper) \
 
-		rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_CONTRAST, &show, DEFAULT_CONF_SHOW_TOOLBOX_CONTRAST);
-		toolbox_contrast[n] = gui_box(_("Contrast"), gui_make_scale_from_adj(rs,
-			G_CALLBACK(gui_adj_value_callback), rs->settings[n]->contrast, MASK_CONTRAST), show);
-		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_contrast[n], FALSE, FALSE, 0);
-		g_signal_connect_after(toolbox_contrast[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_contrast);
-		g_signal_connect_after(toolbox_contrast[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_CONTRAST);
+		SLIDER(exposure, EXPOSURE, _("Exposure"), -3.0, 3.0, 0.1, 0.5);
+		SLIDER(saturation, SATURATION, _("Saturation"), 0.0, 3.0, 0.1, 0.5);
+		SLIDER(hue, HUE, _("Hue"), -180.0, 180.0, 0.1, 30.0);
+		SLIDER(contrast, CONTRAST, _("Contrast"), 0.0, 3.0, 0.1, 0.5);
 
+		/* White balance */
+		GtkWidget *box = gtk_vbox_new (FALSE, 0);
 		rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_WARMTH, &show, DEFAULT_CONF_SHOW_TOOLBOX_WARMTH);
-		toolbox_warmth[n] = gui_tool_warmth(rs, n, show);
-		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_warmth[n], FALSE, FALSE, 0);
+
+		/* Warmth slider */
+		adjusters->warmth = GTK_ADJUSTMENT(gtk_adjustment_new(rs_settings_get_warmth(rs->settings[n]), -2.0, 2.0, 0.1, 0.5, 0.0));
+		embed = gui_make_scale_from_adj(rs->settings[n], settings_signal_id, G_CALLBACK(gui_adj_value_callback), adjusters->warmth, MASK_WARMTH); \
+		gtk_box_pack_start (GTK_BOX (box), embed, FALSE, FALSE, 0);
+
+		/* Tint slider */
+		adjusters->tint = GTK_ADJUSTMENT(gtk_adjustment_new(rs_settings_get_tint(rs->settings[n]), -2.0, 2.0, 0.1, 0.5, 0.0));
+		embed = gui_make_scale_from_adj(rs->settings[n], settings_signal_id, G_CALLBACK(gui_adj_value_callback), adjusters->tint, MASK_TINT);
+		gtk_box_pack_start (GTK_BOX (box), embed, FALSE, FALSE, 0);
+
+		/* Box it! */
+		toolbox_warmth[n] = gui_box(_("Warmth/tint"), box, show);
+
+		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_warmth[n], FALSE, FALSE, 0); \
 		g_signal_connect_after(toolbox_warmth[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_warmth);
 		g_signal_connect_after(toolbox_warmth[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_WARMTH);
 
-		rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_SHARPEN, &show, DEFAULT_CONF_SHOW_TOOLBOX_SHARPEN);
-		toolbox_sharpen[n] = gui_box(_("Sharpen"), gui_make_scale_from_adj(rs,
-			G_CALLBACK(gui_adj_value_callback), rs->settings[n]->sharpen, MASK_SHARPEN), show);
-		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_sharpen[n], FALSE, FALSE, 0);
-		g_signal_connect_after(toolbox_sharpen[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_sharpen);
-		g_signal_connect_after(toolbox_sharpen[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_SHARPEN);
+		SLIDER(sharpen, SHARPEN, _("Sharpen"), 0.0, 10.0, 0.1, 0.5);
 
+		/* Curve */
+		gfloat *knots;
+		gint nknots;
+		rs->curve[n] = rs_curve_widget_new();
+		adjusters->curve = RS_CURVE_WIDGET(rs->curve[n]);
+
+		/* Initialize curve with knots from RSSettings */
+		nknots = rs_settings_get_curve_nknots(rs->settings[n]);
+		knots = rs_settings_get_curve_knots(rs->settings[n]);
+		rs_curve_widget_set_knots(RS_CURVE_WIDGET(rs->curve[n]), knots, nknots);
+		g_free(knots);
+
 		rs_conf_get_boolean_with_default(CONF_SHOW_TOOLBOX_CURVE, &show, DEFAULT_CONF_SHOW_TOOLBOX_CURVE);
-		gtk_widget_set_size_request(rs->settings[n]->curve, 64, 64);
-		g_signal_connect(rs->settings[n]->curve, "changed", G_CALLBACK(update_preview_callback), rs);
-		g_signal_connect(rs->settings[n]->curve, "right-click", G_CALLBACK(curve_context_callback), rs);
-		toolbox_curve[n] = gui_box(_("Curve"), rs->settings[n]->curve, show);
+		gtk_widget_set_size_request(rs->curve[n], 64, 64);
+		g_signal_connect(rs->curve[n], "changed", G_CALLBACK(curve_changed), rs->settings[n]);
+		g_signal_connect(rs->curve[n], "right-click", G_CALLBACK(curve_context_callback), rs);
+		toolbox_curve[n] = gui_box(_("Curve"), rs->curve[n], show);
 		gtk_box_pack_start (GTK_BOX (tbox[n]), toolbox_curve[n], TRUE, FALSE, 0);
 		g_signal_connect_after(toolbox_curve[n], "activate", G_CALLBACK(gui_expander_toggle_callback), toolbox_curve);
 		g_signal_connect_after(toolbox_curve[n], "activate", G_CALLBACK(gui_expander_save_status_callback), CONF_SHOW_TOOLBOX_CURVE);
 
+		/* Append tab */
 		gtk_notebook_append_page(GTK_NOTEBOOK(notebook), tbox[n], toolbox_label[n]);
 	}
 	g_signal_connect(notebook, "switch-page", G_CALLBACK(gui_notebook_callback), rs);




More information about the Rawstudio-commit mailing list