Flat curve editor widget, HSV tool modified to use it.

Usage :
 - click & drag a control point to move it in X&Y direction
 - click & drag a vertical line to move it in horizontal or vertical direction (the very first move will be used to determine the motion direction)
 - click & drag the yellow or blue square handle to modify the tangent of the same color
This commit is contained in:
Hombre
2011-03-24 00:39:48 +01:00
parent e57a56b40f
commit eb4b2d8781
44 changed files with 4778 additions and 2136 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

View File

@@ -18,6 +18,7 @@ CURVEEDITOR_HIGHLIGHTS;Hautes lumières
CURVEEDITOR_LIGHTS;Zones claires
CURVEEDITOR_LINEAR;Linéaire
CURVEEDITOR_LOADDLGLABEL;Charger la courbe...
CURVEEDITOR_MINMAXCPOINTS;Points de contrôle minima/maxima
CURVEEDITOR_NURBS;Cage de contrôle
CURVEEDITOR_PARAMETRIC;Paramétrique
CURVEEDITOR_SAVEDLGLABEL;Enregistrer la courbe...
@@ -499,8 +500,8 @@ PREFERENCES_INTENT_RELATIVE;Colorimétrie relative
PREFERENCES_INTENT_SATURATION;Saturation
PREFERENCES_LIVETHUMBNAILS;Vignettes "Live" (plus lent)
PREFERENCES_MONITORICC;Profil du moniteur
PREFERENCES_MULTITAB;Mode éditeurs multiple
PREFERENCES_MULTITABDUALMON;Mode éditeurs multiple, si possible sur un second moniteur
PREFERENCES_MULTITAB;Éditeurs multiple
PREFERENCES_MULTITABDUALMON;Éditeurs multiple, si possible sur un second moniteur
PREFERENCES_OUTDIR;Dossier de sortie
PREFERENCES_OUTDIRFOLDER;Dossier de sauvegarde
PREFERENCES_OUTDIRFOLDERHINT;Place les images traitées dans le dossier selectionné
@@ -531,8 +532,8 @@ PREFERENCES_SHOWBASICEXIF;Voir les infos EXIF basiques
PREFERENCES_SHOWDATETIME;Voir la date et l'heure
PREFERENCES_SHOWONLYRAW;Voir seulement les fichiers RAW
PREFERENCES_SHTHRESHOLD;Seuil pour le dépassement de domaine inférieur
PREFERENCES_SINGLETAB;Mode éditeur unique
PREFERENCES_SINGLETABVERTAB;Mode éditeur unique, onglets verticaux
PREFERENCES_SINGLETAB;Éditeur unique
PREFERENCES_SINGLETABVERTAB;Éditeur unique, onglets verticaux
PREFERENCES_STARTUPIMDIR;Répertoire Image au démarrage
PREFERENCES_TAB_BROWSER;Navigateur de fichiers
PREFERENCES_TAB_COLORMGR;Gestion des couleurs
@@ -691,11 +692,11 @@ TP_HSVEQUALIZER6;Bleu
TP_HSVEQUALIZER7;Violet
TP_HSVEQUALIZER8;Magenta
TP_HSVEQUALIZER_CHANNEL;Canal
TP_HSVEQUALIZER_HUE;Teinte
TP_HSVEQUALIZER_HUE;T
TP_HSVEQUALIZER_LABEL;Égaliseur TSV
TP_HSVEQUALIZER_NEUTRAL;Neutre
TP_HSVEQUALIZER_SAT;Saturation
TP_HSVEQUALIZER_VAL;Valeur
TP_HSVEQUALIZER_SAT;S
TP_HSVEQUALIZER_VAL;V
TP_ICM_FILEDLGFILTERANY;Tous les fichiers
TP_ICM_FILEDLGFILTERICM;Fichiers de profil ICC
TP_ICM_GAMMABEFOREINPUT;Appliquer le Gamma du profil

View File

@@ -17,6 +17,7 @@ CURVEEDITOR_HIGHLIGHTS;Highlights
CURVEEDITOR_LIGHTS;Lights
CURVEEDITOR_LINEAR;Linear
CURVEEDITOR_LOADDLGLABEL;Load Curve...
CURVEEDITOR_MINMAXCPOINTS;Minima/Maxima control points
CURVEEDITOR_NURBS;Control cage
CURVEEDITOR_PARAMETRIC;Parametric
CURVEEDITOR_SAVEDLGLABEL;Save Curve...
@@ -706,11 +707,11 @@ TP_HSVEQUALIZER6;Blue
TP_HSVEQUALIZER7;Purple
TP_HSVEQUALIZER8;Magenta
TP_HSVEQUALIZER_CHANNEL;HSV Channel
TP_HSVEQUALIZER_HUE;Hue
TP_HSVEQUALIZER_HUE;H
TP_HSVEQUALIZER_LABEL;HSV Equalizer
TP_HSVEQUALIZER_NEUTRAL;Neutral
TP_HSVEQUALIZER_SAT;Saturation
TP_HSVEQUALIZER_VAL;Value
TP_HSVEQUALIZER_SAT;S
TP_HSVEQUALIZER_VAL;V
TP_ICM_FILEDLGFILTERANY;Any files
TP_ICM_FILEDLGFILTERICM;ICC Profile Files
TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma

View File

@@ -7,8 +7,8 @@ link_directories (${CMAKE_CURRENT_SOURCE_DIR}/../rtexif ${EXTRA_LIBDIR} ${GTHREA
${GOBJECT_LIBRARY_DIRS} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS}
${IPTCDATA_LIBRARY_DIRS} ${LCMS_LIBRARY_DIRS})
set (RTENGINESOURCEFILES colortemp.cc curves.cc dcraw.cc iccstore.cc dfmanager.cc rawimage.cc
image8.cc image16.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc
set (RTENGINESOURCEFILES colortemp.cc curves.cc flatcurves.cc diagonalcurves.cc dcraw.cc iccstore.cc
dfmanager.cc rawimage.cc image8.cc image16.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc
loadinitial.cc procparams.cc rawimagesource.cc shmap.cc simpleprocess.cc refreshmap.cc
stdimagesource.cc myfile.cc iccjpeg.c hlmultipliers.cc improccoordinator.cc
processingjob.cc rtthumbnail.cc utils.cc labimage.cc slicer.cc

View File

@@ -30,275 +30,32 @@
namespace rtengine {
Curve::Curve (const std::vector<double>& p, int poly_pn) : x(NULL), y(NULL), ypp(NULL) {
ppn = poly_pn;
if (p.size()<3) {
kind = Empty;
}
else {
kind = (CurveType)p[0];
if (kind==Linear || kind==Spline || kind==NURBS) {
N = (p.size()-1)/2;
x = new double[N];
y = new double[N];
int ix = 1;
for (int i=0; i<N; i++) {
x[i] = p[ix++];
y[i] = p[ix++];
}
if (kind==Spline)
spline_cubic_set ();
else if (kind==NURBS && N > 2)
NURBS_set ();
else kind=Linear;
}
else if (kind==Parametric) {
if (p.size()!=8 && p.size()!=9)
kind = Empty;
else {
x = new double[9];
for (int i=0; i<4; i++)
x[i] = p[i];
for (int i=4; i<8; i++)
x[i] = (p[i]+100.0)/200.0;
if (p.size()<9)
x[8] = 1.0;
else
x[8] = p[8]/100.0;
}
}
}
Curve::Curve () {
x = 0;
y = 0;
ypp = 0;
}
Curve::~Curve () {
void Curve::AddPolygons ()
{
if (firstPointIncluded) {
poly_x.push_back(x1);
poly_y.push_back(y1);
}
for (int k=1; k<(nbr_points-1); k++) {
double t = k*increment;
double t2 = t*t;
double tr = 1.-t;
double tr2 = tr*tr;
double tr2t = tr*2*t;
delete [] x;
delete [] y;
delete [] ypp;
poly_x.clear();
poly_y.clear();
}
void Curve::spline_cubic_set () {
double* u = new double[N-1];
delete [] ypp;
ypp = new double [N];
ypp[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */
for (int i = 1; i < N - 1; ++i) {
double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
double p = sig * ypp[i - 1] + 2.0;
ypp[i] = (sig - 1.0) / p;
u[i] = ((y[i + 1] - y[i])
/ (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]));
u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
}
ypp[N - 1] = 0.0;
for (int k = N - 2; k >= 0; --k)
ypp[k] = ypp[k] * ypp[k + 1] + u[k];
delete [] u;
}
void Curve::NURBS_set () {
int nbSubCurvesPoints = N + (N-3)*2;
std::vector<double> sc_x(nbSubCurvesPoints); // X sub-curve points ( XP0,XP1,XP2, XP2,XP3,XP4, ...)
std::vector<double> sc_y(nbSubCurvesPoints); // Y sub-curve points ( YP0,YP1,YP2, YP2,YP3,YP4, ...)
std::vector<double> sc_length(N+2); // Length of the subcurves
double total_length=0.;
// Create the list of Bezier sub-curves
// NURBS_set is called if N > 2 only
int j = 0;
int k = 0;
for (int i = 0; i < N-1;) {
double length;
double dx;
double dy;
// first point (on the curve)
if (!i) {
sc_x[j] = x[i];
sc_y[j++] = y[i++];
}
else {
sc_x[j] = (x[i-1] + x[i]) / 2.;
sc_y[j++] = (y[i-1] + y[i]) / 2.;
}
// second point (control point)
sc_x[j] = x[i];
sc_y[j] = y[i++];
length = sqrt(pow(sc_x[j] - sc_x[j-1],2) + pow(sc_y[j] - sc_y[j-1],2));
j++;
// third point (on the curve)
if (i==N-1) {
sc_x[j] = x[i];
sc_y[j] = y[i];
}
else {
sc_x[j] = (x[i-1] + x[i]) / 2.;
sc_y[j] = (y[i-1] + y[i]) / 2.;
}
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length += sqrt(dx*dx + dy*dy);
j++;
// Storing the length of all sub-curves and the total length (to have a better distribution
// of the points along the curve)
sc_length[k++] = length;
total_length += length;
}
poly_x.clear();
poly_y.clear();
unsigned int sc_xsize=j-1;
j = 0;
// create the polyline with the number of points adapted to the X range of the sub-curve
for (unsigned int i=0; i < sc_xsize /*sc_x.size()*/; i+=3) {
// TODO: Speeding-up the interface by caching the polyline, instead of rebuilding it at each action on sliders !!!
int nbr_points = (int)(((double)(ppn+N-2) * sc_length[i/3] )/ total_length);
if (nbr_points<0){
for(int it=0;it < sc_x.size(); it+=3) printf("sc_length[%d/3]=%f \n",it,sc_length[it/3]);
printf("NURBS: error detected!\n i=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f",i,nbr_points,ppn,N,sc_length[i/3],total_length);
exit(0);
}
// increment along the curve, not along the X axis
double increment = 1.0 / (double)(nbr_points-1);
if (!i) {
poly_x.push_back( sc_x[i]);
poly_y.push_back(sc_y[i]);
}
for (k=1; k<(nbr_points-1); k++) {
double t = k*increment;
double t2 = t*t;
double tr = 1.-t;
double tr2 = tr*tr;
double tr2t = tr*2*t;
// adding a point to the polyline
poly_x.push_back( tr2*sc_x[i] + tr2t*sc_x[i+1] + t2*sc_x[i+2]);
poly_y.push_back( tr2*sc_y[i] + tr2t*sc_y[i+1] + t2*sc_y[i+2]);
}
// adding the last point of the sub-curve
poly_x.push_back( sc_x[i+2]);
poly_y.push_back(sc_y[i+2]);
}
}
double Curve::getVal (double t) {
switch (kind) {
case Empty :
return t;
break;
case Parametric : {
if (t<=1e-14)
return 0.0;
double c = -log(2.0)/log(x[2]);
double tv = exp(c*log(t));
double base = pfull (tv, x[8], x[6], x[5]);
double stretched = base<=1e-14 ? 0.0 : exp(log(base)/c);
base = pfull (0.5, x[8], x[6], x[5]);
double fc = base<=1e-14 ? 0.0 : exp(log(base)/c); // value of the curve at the center point
if (t<x[2]) {
// add shadows effect:
double sc = -log(2.0)/log(x[1]/x[2]);
double stv = exp(sc*log(stretched/fc));
double sbase = pfull (stv, x[8], x[7], 0.5);
double sstretched = fc*(sbase<=1e-14 ? 0.0 : exp(log(sbase)/sc));
return sstretched;
}
else {
// add highlights effect:
double hc = -log(2.0)/log((x[3]-x[2])/(1-x[2]));
double htv = exp(hc*log((stretched-fc)/(1-fc)));
double hbase = pfull (htv, x[8], 0.5, x[4]);
double hstretched = fc + (1-fc)*(hbase<=1e-14 ? 0.0 : exp(log(hbase)/hc));
return hstretched;
}
break;
}
case Linear :
case Spline : {
// values under and over the first and last point
if (t>x[N-1])
return y[N-1];
else if (t<x[0])
return y[0];
// do a binary search for the right interval:
int k_lo = 0, k_hi = N - 1;
while (k_hi - k_lo > 1){
int k = (k_hi + k_lo) / 2;
if (x[k] > t)
k_hi = k;
else
k_lo = k;
}
double h = x[k_hi] - x[k_lo];
// linear
if (kind==Linear)
return y[k_lo] + (t - x[k_lo]) * ( y[k_hi] - y[k_lo] ) / h;
// spline curve
else { // if (kind==Spline) {
double a = (x[k_hi] - t) / h;
double b = (t - x[k_lo]) / h;
double r = a*y[k_lo] + b*y[k_hi] + ((a*a*a - a)*ypp[k_lo] + (b*b*b - b)*ypp[k_hi]) * (h*h)/6.0;
return CLIPD(r);
}
break;
}
case NURBS : {
// values under and over the first and last point
if (t>x[N-1])
return y[N-1];
else if (t<x[0])
return y[0];
else if (N == 2)
return y[0] + (t - x[0]) * ( y[1] - y[0] ) / (x[1] - x[0]);
// do a binary search for the right interval:
int k_lo = 0, k_hi = poly_x.size() - 1;
while (k_hi - k_lo > 1){
int k = (k_hi + k_lo) / 2;
if (poly_x[k] > t)
k_hi = k;
else
k_lo = k;
}
double h = poly_x[k_hi] - poly_x[k_lo];
return poly_y[k_lo] + (t - poly_x[k_lo]) * ( poly_y[k_hi] - poly_y[k_lo] ) / h;
break;
}
default:
// all other (unknown) kind
return t;
}
}
void Curve::getVal (const std::vector<double>& t, std::vector<double>& res) {
// TODO!!!! can be made much faster!!! Binary search of getVal(double) at each point can be avoided
res.resize (t.size());
for (unsigned int i=0; i<t.size(); i++)
res[i] = getVal(t[i]);
// adding a point to the polyline
poly_x.push_back( tr2*x1 + tr2t*x2 + t2*x3);
poly_y.push_back( tr2*y1 + tr2t*y2 + t2*y3);
}
// adding the last point of the sub-curve
poly_x.push_back(x3);
poly_y.push_back(y3);
}
@@ -314,7 +71,7 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
std::vector<double> satcurvePoints;
satcurvePoints.push_back((double)((CurveType)NURBS));
satcurvePoints.push_back((double)DCT_NURBS);
if (saturation>0) {
double satslope = (0.5+2*saturation/500.0)/(0.5-2*saturation/500.0);
double scale = (satlimthresh/100.1);
@@ -352,14 +109,14 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat
satcurvePoints.push_back(1);
satcurvePoints.push_back(1+saturation/200.0);
}
Curve* satcurve = NULL;
satcurve = new Curve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
DiagonalCurve* satcurve = NULL;
satcurve = new DiagonalCurve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// create a curve if needed
Curve* tcurve = NULL;
DiagonalCurve* tcurve = NULL;
if (curvePoints.size()>0 && curvePoints[0]!=0)
tcurve = new Curve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) {
@@ -432,9 +189,9 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat
bool needigamma = igamma_ && gamma_>0;
// create a curve if needed
Curve* tcurve = NULL;
DiagonalCurve* tcurve = NULL;
if (curvePoints.size()>0 && curvePoints[0]!=0)
tcurve = new Curve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS/skip);
// clear array that stores histogram valid before applying the custom curve
if (outBeforeCCurveHistogram)
@@ -445,7 +202,7 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
std::vector<double> brightcurvePoints;
brightcurvePoints.push_back((double)((CurveType)NURBS));
brightcurvePoints.push_back((double)DCT_NURBS);
brightcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
brightcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
@@ -466,8 +223,8 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat
brightcurvePoints.push_back(1); // white point
brightcurvePoints.push_back(1); // value at white point
Curve* brightcurve = NULL;
brightcurve = new Curve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
DiagonalCurve* brightcurve = NULL;
brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
float exp_scale = a*def_mul ;
@@ -545,7 +302,7 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
std::vector<double> contrastcurvePoints;
contrastcurvePoints.push_back((double)((CurveType)NURBS));
contrastcurvePoints.push_back((double)DCT_NURBS);
contrastcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
contrastcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
@@ -559,8 +316,8 @@ void CurveFactory::complexsgnCurve (double saturation, bool satlimit, double sat
contrastcurvePoints.push_back(1); // white point
contrastcurvePoints.push_back(1); // value at white point
Curve* contrastcurve = NULL;
contrastcurve = new Curve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
DiagonalCurve* contrastcurve = NULL;
contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// apply contrast enhancement

View File

@@ -24,6 +24,8 @@
#include <string>
#include <math.h>
#include <mycurve.h>
#include <myflatcurve.h>
#include <mydiagonalcurve.h>
#define CURVES_MIN_POLY_POINTS 1000
@@ -175,11 +177,13 @@ class Curve {
std::vector<double> poly_x; // X points of the faceted curve
std::vector<double> poly_y; // Y points of the faceted curve
double* ypp;
CurveType kind;
protected:
void spline_cubic_set ();
void NURBS_set ();
// Fields for the elementary curve polygonisation
double x1, y1, x2, y2, x3, y3;
bool firstPointIncluded;
double increment;
int nbr_points;
static inline double p00 (double x, double prot) { return CurveFactory::clower (x, 2.0, prot); }
static inline double p11 (double x, double prot) { return CurveFactory::cupper (x, 2.0, prot); }
static inline double p01 (double x, double prot) { return x<=0.5 ? CurveFactory::clower (x*2, 2.0, prot)/2.0 : 0.5 + CurveFactory::cupper ((x-0.5)*2, 2.0, prot)/2.0; }
@@ -187,11 +191,44 @@ class Curve {
static inline double pfull (double x, double prot, double sh, double hl) { return (1-sh)*(1-hl)*p00(x,prot) + sh*hl*p11(x,prot) + (1-sh)*hl*p01(x,prot) + sh*(1-hl)*p10(x,prot); }
public:
Curve ();
void AddPolygons ();
virtual double getVal (double t) = 0;
virtual void getVal (const std::vector<double>& t, std::vector<double>& res) = 0;
Curve (const std::vector<double>& points, int ppn=CURVES_MIN_POLY_POINTS);
~Curve ();
};
double getVal (double x);
class DiagonalCurve : public Curve {
protected:
DiagonalCurveType kind;
void spline_cubic_set ();
void NURBS_set ();
public:
DiagonalCurve (const std::vector<double>& points, int ppn=CURVES_MIN_POLY_POINTS);
~DiagonalCurve ();
double getVal (double t);
void getVal (const std::vector<double>& t, std::vector<double>& res);
};
class FlatCurve : public Curve {
protected:
FlatCurveType kind;
double* leftTangent;
double* rightTangent;
void CtrlPoints_set ();
public:
FlatCurve (const std::vector<double>& points, int ppn=CURVES_MIN_POLY_POINTS);
~FlatCurve ();
double getVal (double t);
void getVal (const std::vector<double>& t, std::vector<double>& res);
};
}

292
rtengine/diagonalcurves.cc Normal file
View File

@@ -0,0 +1,292 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
#include <glib/gstdio.h>
#include <curves.h>
#include <math.h>
#include <vector>
#include <mytime.h>
#include <string.h>
#define CLIPD(a) ((a)>0.0?((a)<1.0?(a):1.0):0.0)
namespace rtengine {
DiagonalCurve::DiagonalCurve (const std::vector<double>& p, int poly_pn) {
ppn = poly_pn;
if (p.size()<3) {
kind = DCT_Empty;
}
else {
kind = (DiagonalCurveType)p[0];
if (kind==DCT_Linear || kind==DCT_Spline || kind==DCT_NURBS) {
N = (p.size()-1)/2;
x = new double[N];
y = new double[N];
int ix = 1;
for (int i=0; i<N; i++) {
x[i] = p[ix++];
y[i] = p[ix++];
}
if (kind==DCT_Spline)
spline_cubic_set ();
else if (kind==DCT_NURBS && N > 2)
NURBS_set ();
else kind=DCT_Linear;
}
else if (kind==DCT_Parametric) {
if (p.size()!=8 && p.size()!=9)
kind = DCT_Empty;
else {
x = new double[9];
for (int i=0; i<4; i++)
x[i] = p[i];
for (int i=4; i<8; i++)
x[i] = (p[i]+100.0)/200.0;
if (p.size()<9)
x[8] = 1.0;
else
x[8] = p[8]/100.0;
}
}
}
}
DiagonalCurve::~DiagonalCurve () {
delete [] x;
delete [] y;
delete [] ypp;
poly_x.clear();
poly_y.clear();
}
void DiagonalCurve::spline_cubic_set () {
double* u = new double[N-1];
delete [] ypp;
ypp = new double [N];
ypp[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */
for (int i = 1; i < N - 1; ++i) {
double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);
double p = sig * ypp[i - 1] + 2.0;
ypp[i] = (sig - 1.0) / p;
u[i] = ((y[i + 1] - y[i])
/ (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]));
u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;
}
ypp[N - 1] = 0.0;
for (int k = N - 2; k >= 0; --k)
ypp[k] = ypp[k] * ypp[k + 1] + u[k];
delete [] u;
}
void DiagonalCurve::NURBS_set () {
int nbSubCurvesPoints = N + (N-3)*2;
std::vector<double> sc_x(nbSubCurvesPoints); // X sub-curve points ( XP0,XP1,XP2, XP2,XP3,XP4, ...)
std::vector<double> sc_y(nbSubCurvesPoints); // Y sub-curve points ( YP0,YP1,YP2, YP2,YP3,YP4, ...)
std::vector<double> sc_length(N+2); // Length of the subcurves
double total_length=0.;
// Create the list of Bezier sub-curves
// NURBS_set is called if N > 2 only
int j = 0;
int k = 0;
for (int i = 0; i < N-1;) {
double length;
double dx;
double dy;
// first point (on the curve)
if (!i) {
sc_x[j] = x[i];
sc_y[j++] = y[i++];
}
else {
sc_x[j] = (x[i-1] + x[i]) / 2.;
sc_y[j++] = (y[i-1] + y[i]) / 2.;
}
// second point (control point)
sc_x[j] = x[i];
sc_y[j] = y[i++];
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length = sqrt(dx*dx + dy*dy);
j++;
// third point (on the curve)
if (i==N-1) {
sc_x[j] = x[i];
sc_y[j] = y[i];
}
else {
sc_x[j] = (x[i-1] + x[i]) / 2.;
sc_y[j] = (y[i-1] + y[i]) / 2.;
}
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length += sqrt(dx*dx + dy*dy);
j++;
// Storing the length of all sub-curves and the total length (to have a better distribution
// of the points along the curve)
sc_length[k++] = length;
total_length += length;
}
poly_x.clear();
poly_y.clear();
unsigned int sc_xsize=j-1;
j = 0;
// create the polyline with the number of points adapted to the X range of the sub-curve
for (unsigned int i=0; i < sc_xsize /*sc_x.size()*/; i+=3) {
// TODO: Speeding-up the interface by caching the polyline, instead of rebuilding it at each action on sliders !!!
nbr_points = (int)(((double)(ppn+N-2) * sc_length[i/3] )/ total_length);
if (nbr_points<0){
for(int it=0;it < sc_x.size(); it+=3) printf("sc_length[%d/3]=%f \n",it,sc_length[it/3]);
printf("NURBS: error detected!\n i=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f",i,nbr_points,ppn,N,sc_length[i/3],total_length);
exit(0);
}
// increment along the curve, not along the X axis
increment = 1.0 / (double)(nbr_points-1);
x1 = sc_x[i]; y1 = sc_y[i];
x2 = sc_x[i+1]; y2 = sc_y[i+1];
x3 = sc_x[i+2]; y3 = sc_y[i+2];
firstPointIncluded = !i;
AddPolygons ();
}
}
double DiagonalCurve::getVal (double t) {
switch (kind) {
case DCT_Empty :
return t;
break;
case DCT_Parametric : {
if (t<=1e-14)
return 0.0;
double c = -log(2.0)/log(x[2]);
double tv = exp(c*log(t));
double base = pfull (tv, x[8], x[6], x[5]);
double stretched = base<=1e-14 ? 0.0 : exp(log(base)/c);
base = pfull (0.5, x[8], x[6], x[5]);
double fc = base<=1e-14 ? 0.0 : exp(log(base)/c); // value of the curve at the center point
if (t<x[2]) {
// add shadows effect:
double sc = -log(2.0)/log(x[1]/x[2]);
double stv = exp(sc*log(stretched/fc));
double sbase = pfull (stv, x[8], x[7], 0.5);
double sstretched = fc*(sbase<=1e-14 ? 0.0 : exp(log(sbase)/sc));
return sstretched;
}
else {
// add highlights effect:
double hc = -log(2.0)/log((x[3]-x[2])/(1-x[2]));
double htv = exp(hc*log((stretched-fc)/(1-fc)));
double hbase = pfull (htv, x[8], 0.5, x[4]);
double hstretched = fc + (1-fc)*(hbase<=1e-14 ? 0.0 : exp(log(hbase)/hc));
return hstretched;
}
break;
}
case DCT_Linear :
case DCT_Spline : {
// values under and over the first and last point
if (t>x[N-1])
return y[N-1];
else if (t<x[0])
return y[0];
// do a binary search for the right interval:
int k_lo = 0, k_hi = N - 1;
while (k_hi - k_lo > 1){
int k = (k_hi + k_lo) / 2;
if (x[k] > t)
k_hi = k;
else
k_lo = k;
}
double h = x[k_hi] - x[k_lo];
// linear
if (kind==DCT_Linear)
return y[k_lo] + (t - x[k_lo]) * ( y[k_hi] - y[k_lo] ) / h;
// spline curve
else { // if (kind==Spline) {
double a = (x[k_hi] - t) / h;
double b = (t - x[k_lo]) / h;
double r = a*y[k_lo] + b*y[k_hi] + ((a*a*a - a)*ypp[k_lo] + (b*b*b - b)*ypp[k_hi]) * (h*h)/6.0;
return CLIPD(r);
}
break;
}
case DCT_NURBS : {
// values under and over the first and last point
if (t>x[N-1])
return y[N-1];
else if (t<x[0])
return y[0];
else if (N == 2)
return y[0] + (t - x[0]) * ( y[1] - y[0] ) / (x[1] - x[0]);
// do a binary search for the right interval:
int k_lo = 0, k_hi = poly_x.size() - 1;
while (k_hi - k_lo > 1){
int k = (k_hi + k_lo) / 2;
if (poly_x[k] > t)
k_hi = k;
else
k_lo = k;
}
double h = poly_x[k_hi] - poly_x[k_lo];
return poly_y[k_lo] + (t - poly_x[k_lo]) * ( poly_y[k_hi] - poly_y[k_lo] ) / h;
break;
}
default:
// all other (unknown) kind
return t;
}
}
void DiagonalCurve::getVal (const std::vector<double>& t, std::vector<double>& res) {
// TODO!!!! can be made much faster!!! Binary search of getVal(double) at each point can be avoided
res.resize (t.size());
for (unsigned int i=0; i<t.size(); i++)
res[i] = getVal(t[i]);
}
}

336
rtengine/flatcurves.cc Normal file
View File

@@ -0,0 +1,336 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <glib.h>
#include <glib/gstdio.h>
#include <curves.h>
#include <math.h>
#include <vector>
#include <mytime.h>
#include <string.h>
#include <gtkmm.h>
#include <fstream>
namespace rtengine {
FlatCurve::FlatCurve (const std::vector<double>& p, int poly_pn) : leftTangent(NULL), rightTangent(NULL) {
ppn = poly_pn;
poly_x.clear();
poly_y.clear();
kind = FCT_Empty;
if (p.size()>4) {
kind = (FlatCurveType)p[0];
if (kind==FCT_MinMaxCPoints) {
N = (p.size()-1)/4;
x = new double[N+1];
y = new double[N+1];
leftTangent = new double[N+1];
rightTangent = new double[N+1];
int ix = 1;
for (int i=0; i<N; i++) {
x[i] = p[ix++];
y[i] = p[ix++];
leftTangent[i] = p[ix++];
rightTangent[i] = p[ix++];
}
// The first point is copied to the end of the point list, to handle the curve periodicity
x[N] = p[1]+1.0;
y[N] = p[2];
leftTangent[N] = p[3];
rightTangent[N] = p[4];
if (N > 1)
CtrlPoints_set ();
}
/*else if (kind==FCT_Parametric) {
}*/
}
}
FlatCurve::~FlatCurve () {
delete [] x;
delete [] y;
delete [] leftTangent;
delete [] rightTangent;
delete [] ypp;
poly_x.clear();
poly_y.clear();
}
void FlatCurve::CtrlPoints_set () {
int nbSubCurvesPoints = N*6;
std::vector<double> sc_x(nbSubCurvesPoints); // X sub-curve points ( XP0,XP1,XP2, XP2,XP3,XP4, ...)
std::vector<double> sc_y(nbSubCurvesPoints); // Y sub-curve points ( YP0,YP1,YP2, YP2,YP3,YP4, ...)
std::vector<double> sc_length(N*2); // Length of the subcurves
std::vector<bool> sc_isLinear(N*2); // true if the subcurve is linear
double total_length=0.;
// Create the list of Bezier sub-curves
// CtrlPoints_set is called if N > 1
unsigned int j = 0;
unsigned int k = 0;
for (int i = 0; i < N;) {
double length;
double dx;
double dy;
double xp1, xp2, yp2, xp3;
bool startLinear, endLinear;
startLinear = (rightTangent[i] == 0.) || (y[i] == y[i+1]);
endLinear = (leftTangent [i+1] == 0.) || (y[i] == y[i+1]);
if (startLinear && endLinear) {
// line shape
sc_x[j] = x[i];
sc_y[j++] = y[i];
sc_x[j] = x[i+1];
sc_y[j] = y[i+1];
sc_isLinear[k] = true;
i++;
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length = sqrt(dx*dx + dy*dy);
j++;
// Storing the length of all sub-curves and the total length (to have a better distribution
// of the points along the curve)
sc_length[k++] = length;
total_length += length;
}
else {
if (startLinear) {
xp1 = x[i];
}
else {
//xp1 = (xp4 - xp0) * rightTangent0 + xp0;
xp1 = (x[i+1] - x[i]) * rightTangent[i] + x[i];
}
if (endLinear) {
xp3 = x[i+1];
}
else {
//xp3 = (xp0 - xp4]) * leftTangent4 + xp4;
xp3 = (x[i] - x[i+1]) * leftTangent[i+1] + x[i+1];
}
xp2 = (xp1 + xp3) / 2.0;
yp2 = (y[i] + y[i+1]) / 2.0;
if (rightTangent[i]+leftTangent[i+1] > 1.0) { // also means that start and end are not linear
xp1 = xp3 = xp2;
}
if (startLinear) {
// Point 0, 2
sc_x[j] = x[i];
sc_y[j++] = y[i];
sc_x[j] = xp2;
sc_y[j] = yp2;
sc_isLinear[k] = true;
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length = sqrt(dx*dx + dy*dy);
j++;
// Storing the length of all sub-curves and the total length (to have a better distribution
// of the points along the curve)
sc_length[k++] = length;
total_length += length;
}
else {
// Point 0, 1, 2
sc_x[j] = x[i];
sc_y[j++] = y[i];
sc_x[j] = xp1;
sc_y[j] = y[i];
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length = sqrt(dx*dx + dy*dy);
j++;
sc_x[j] = xp2;
sc_y[j] = yp2;
sc_isLinear[k] = false;
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length += sqrt(dx*dx + dy*dy);
j++;
// Storing the length of all sub-curves and the total length (to have a better distribution
// of the points along the curve)
sc_length[k++] = length;
total_length += length;
}
if (endLinear) {
// Point 2, 4
sc_x[j] = xp2;
sc_y[j++] = yp2;
sc_x[j] = x[i+1];
sc_y[j] = y[i+1];
sc_isLinear[k] = true;
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length = sqrt(dx*dx + dy*dy);
j++;
// Storing the length of all sub-curves and the total length (to have a better distribution
// of the points along the curve)
sc_length[k++] = length;
total_length += length;
}
else {
// Point 2, 3, 4
sc_x[j] = xp2;
sc_y[j++] = yp2;
sc_x[j] = xp3;
sc_y[j] = y[i+1];
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length = sqrt(dx*dx + dy*dy);
j++;
sc_x[j] = x[i+1];
sc_y[j] = y[i+1];
sc_isLinear[k] = false;
dx = sc_x[j] - sc_x[j-1];
dy = sc_y[j] - sc_y[j-1];
length += sqrt(dx*dx + dy*dy);
j++;
// Storing the length of all sub-curves and the total length (to have a better distribution
// of the points along the curve)
sc_length[k++] = length;
total_length += length;
}
i++;
}
}
poly_x.clear();
poly_y.clear();
j = 0;
// very first point of the curve
poly_x.push_back(sc_x[j]);
poly_y.push_back(sc_y[j]);
firstPointIncluded = false;
// create the polyline with the number of points adapted to the X range of the sub-curve
for (unsigned int i=0; i < k; i++) {
if (sc_isLinear[i]) {
j++; // skip the first point
poly_x.push_back(sc_x[j]);
poly_y.push_back(sc_y[j++]);
}
else {
nbr_points = (int)(((double)(ppn) * sc_length[i] )/ total_length);
if (nbr_points<0){
for(unsigned int it=0;it < sc_x.size(); it+=3) printf("sc_length[%d/3]=%f \n",it,sc_length[it/3]);
printf("Flat curve: error detected!\n i=%d nbr_points=%d ppn=%d N=%d sc_length[i/3]=%f total_length=%f",i,nbr_points,ppn,N,sc_length[i/3],total_length);
exit(0);
}
// increment along the curve, not along the X axis
increment = 1.0 / (double)(nbr_points-1);
x1 = sc_x[j]; y1 = sc_y[j++];
x2 = sc_x[j]; y2 = sc_y[j++];
x3 = sc_x[j]; y3 = sc_y[j++];
AddPolygons ();
}
}
/*
// Checking the values
Glib::ustring fname = "Curve.xyz"; // TopSolid'Design "plot" file format
std::ofstream f (fname.c_str());
f << "$" << std::endl;;
for (unsigned int iter = 0; iter < poly_x.size(); iter++) {
f << poly_x[iter] << ", " << poly_y[iter] << ", 0." << std::endl;;
}
f << "$" << std::endl;;
f.close ();
*/
}
double FlatCurve::getVal (double t) {
switch (kind) {
case FCT_MinMaxCPoints : {
/* To be updated if we have to handle non periodic flat curves
// values under and over the first and last point
if (t>x[N-1])
return y[N-1];
else if (t<x[0])
return y[0];
else if (N == 2)
return y[0] + (t - x[0]) * ( y[1] - y[0] ) / (x[1] - x[0]);
*/
// magic to handle curve periodicity : we look above the 1.0 bound for the value
if (t < poly_x[0]) t += 1.0;
// do a binary search for the right interval:
int k_lo = 0, k_hi = poly_x.size() - 1;
while (k_hi - k_lo > 1){
int k = (k_hi + k_lo) / 2;
if (poly_x[k] > t)
k_hi = k;
else
k_lo = k;
}
double h = poly_x[k_hi] - poly_x[k_lo];
return poly_y[k_lo] + (t - poly_x[k_lo]) * ( poly_y[k_hi] - poly_y[k_lo] ) / h;
break;
}
/*case Parametric : {
break;
}*/
case FCT_Empty :
case FCT_Linear :
default:
return t;
}
}
void FlatCurve::getVal (const std::vector<double>& t, std::vector<double>& res) {
// TODO!!!! can be made much faster!!! Binary search of getVal(double) at each point can be avoided
res.resize (t.size());
for (unsigned int i=0; i<t.size(); i++)
res[i] = getVal(t[i]);
}
}

View File

@@ -28,6 +28,7 @@
#include <glibmm.h>
#include <iccstore.h>
#include <impulse_denoise.h>
#include <utils.h>
#ifdef _OPENMP
#include <omp.h>
@@ -294,16 +295,28 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, float* hltonecur
int tH = working->height;
int r, g, b;
float h, s, v;
float satparam,valparam;
int hue, hueband, hueres, nbrband;
double pi = M_PI;
FlatCurve* hCurve;
FlatCurve* sCurve;
FlatCurve* vCurve;
float* cossq = new float [8093];
for (int i=0; i<8093; i++)
cossq[i] = SQR(cos(pi*(float)i/16384));
#pragma omp parallel for private(r, g, b,factor,mapval,h,s,v,hue,hueband,hueres,nbrband,satparam,valparam) if (multiThread)
FlatCurveType hCurveType = (FlatCurveType)params->hsvequalizer.hcurve.at(0);
FlatCurveType sCurveType = (FlatCurveType)params->hsvequalizer.scurve.at(0);
FlatCurveType vCurveType = (FlatCurveType)params->hsvequalizer.vcurve.at(0);
bool hCurveEnabled = hCurveType > FCT_Linear;
bool sCurveEnabled = sCurveType > FCT_Linear;
bool vCurveEnabled = vCurveType > FCT_Linear;
// TODO: We should create a 'skip' value like for CurveFactory::complexsgnCurve (rtengine/curves.cc)
if (hCurveEnabled) hCurve = new FlatCurve(params->hsvequalizer.hcurve);
if (sCurveEnabled) sCurve = new FlatCurve(params->hsvequalizer.scurve);
if (vCurveEnabled) vCurve = new FlatCurve(params->hsvequalizer.vcurve);
#pragma omp parallel for private(r, g, b,factor,mapval,h,s,v) if (multiThread)
for (int i=0; i<tH; i++) {
for (int j=0; j<tW; j++) {
@@ -363,7 +376,7 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, float* hltonecur
g = tonecurve[CLIP(g)];
b = tonecurve[CLIP(b)];
if (abs(sat)>0.5 || params->hsvequalizer.enabled) {
if (abs(sat)>0.5 || hCurveEnabled || sCurveEnabled || vCurveEnabled) {
rgb2hsv(r,g,b,h,s,v);
if (sat > 0.5) {
s = (1-(float)sat/100)*s+(float)sat/100*(1-SQR(SQR(1-s)));
@@ -372,44 +385,51 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, float* hltonecur
s *= 1+(float)sat/100;
}
//HSV equalizer
if (params->hsvequalizer.enabled) {
hue = (int)(65535*h);
hueres = hue & 8091;//location of hue within a band
hueband = (hue-hueres) >> 13;//divides hue range into 8 bands
nbrband = (hueband+1)&7;
//shift hue
h = fmod(h + 0.0025*(params->hsvequalizer.hue[hueband] * cossq[hueres] + params->hsvequalizer.hue[nbrband] * (1-cossq[hueres])),1);
if (h<0) h +=1;
hue = (int)(65535*h);
hueres = hue & 8091;//location of hue within a band
hueband = (hue-hueres) >> 13;//divides hue range into 8 bands
nbrband = (hueband+1)&7;
//change saturation
satparam = 0.01*(params->hsvequalizer.sat[hueband] * cossq[hueres] + params->hsvequalizer.sat[nbrband] * (1-cossq[hueres]));
if (hCurveEnabled) {
h = (hCurve->getVal((double)h) - 0.5) * 2 + h;
if (h > 1.0)
h -= 1.0;
else if (h < 0.0)
h += 1.0;
}
if (sCurveEnabled) {
//shift saturation
float satparam = (sCurve->getVal((double)h)-0.5) * 2;
if (satparam > 0.00001) {
s = (1-satparam)*s+satparam*(1-SQR(1-s));
} else {
if (satparam < -0.00001)
s *= 1+satparam;
s *= 1+satparam;
}
//change value
valparam = 0.005*(params->hsvequalizer.val[hueband] * cossq[hueres] + params->hsvequalizer.val[nbrband] * (1-cossq[hueres]));
/*s = sCurve->getVal((double)s);
if (s > 1.0)
s -= 1.0;
else if (s < 0.0)
s += 1.0;*/
}
if (vCurveEnabled) {
//shift value
float valparam = vCurve->getVal((double)h)-0.5;
valparam *= (1-SQR(SQR(1-s)));
if (valparam > 0.00001) {
v = (1-valparam)*v+valparam*(1-SQR(1-v));
} else {
if (valparam < -0.00001)
v *= (1+valparam);
v *= (1+valparam);
}
/*v = vCurve->getVal((double)v);
if (v > 1.0)
v -= 1.0;
else if (v < 0.0)
v += 1.0;*/
}
hsv2rgb(h,s,v,r,g,b);
}
//hsv2rgb(h,s,v,r,g,b);
int x = (toxyz[0][0] * r + toxyz[1][0] * g + toxyz[2][0] * b) >> 15;
int y = (toxyz[0][1] * r + toxyz[1][1] * g + toxyz[2][1] * b) >> 15;
int z = (toxyz[0][2] * r + toxyz[1][2] * g + toxyz[2][2] * b) >> 15;
@@ -425,6 +445,9 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, float* hltonecur
}
}
if (hCurveEnabled) delete hCurve;
if (sCurveEnabled) delete sCurve;
if (vCurveEnabled) delete vCurve;
delete [] cossq;
//delete [] my_tonecurve;
}
@@ -677,60 +700,5 @@ void ImProcFunctions::getAutoExp (unsigned int* histogram, int histcompr, doubl
if (br>10) br=10;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void ImProcFunctions::rgb2hsv (int r, int g, int b, float &h, float &s, float &v) {
double var_R = r / 65535.0;
double var_G = g / 65535.0;
double var_B = b / 65535.0;
double var_Min = MIN(MIN(var_R,var_G),var_B);
double var_Max = MAX(MAX(var_R,var_G),var_B);
double del_Max = var_Max - var_Min;
v = var_Max;
if (fabs(del_Max)<0.00001) {
h = 0;
s = 0;
}
else {
s = del_Max/var_Max;
if ( var_R == var_Max ) h = (var_G - var_B)/del_Max;
else if ( var_G == var_Max ) h = 2.0 + (var_B - var_R)/del_Max;
else if ( var_B == var_Max ) h = 4.0 + (var_R - var_G)/del_Max;
h /= 6.0;
if ( h < 0 ) h += 1;
if ( h > 1 ) h -= 1;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void ImProcFunctions::hsv2rgb (float h, float s, float v, int &r, int &g, int &b) {
float h1 = h*6; // sector 0 to 5
int i = floor( h1 );
float f = h1 - i; // fractional part of h
float p = v * ( 1 - s );
float q = v * ( 1 - s * f );
float t = v * ( 1 - s * ( 1 - f ) );
float r1,g1,b1;
if (i==0) {r1 = v; g1 = t; b1 = p;}
if (i==1) {r1 = q; g1 = v; b1 = p;}
if (i==2) {r1 = p; g1 = v; b1 = t;}
if (i==3) {r1 = p; g1 = q; b1 = v;}
if (i==4) {r1 = t; g1 = p; b1 = v;}
if (i==5) {r1 = v; g1 = p; b1 = q;}
r = (int)((r1)*65535);
g = (int)((g1)*65535);
b = (int)((b1)*65535);
}
}

View File

@@ -121,9 +121,6 @@ class ImProcFunctions {
bool transCoord (int W, int H, std::vector<Coord2D> &src, std::vector<Coord2D> &red, std::vector<Coord2D> &green, std::vector<Coord2D> &blue, double ascaleDef = -1);
void getAutoExp (unsigned int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl);
double getTransformAutoFill (int oW, int oH);
void rgb2hsv (int r, int g, int b, float &h, float &s, float &v);
void hsv2rgb (float h, float s, float v, int &r, int &g, int &b);
};
}
#endif

View File

@@ -24,6 +24,7 @@
#include <string.h>
#include <version.h>
#include <ppversion.h>
#include <myflatcurve.h>
#include <safekeyfile.h>
@@ -200,13 +201,12 @@ void ProcParams::setDefaults () {
dirpyrequalizer.mult[i] = 1.0;
}
dirpyrequalizer.mult[4] = 0.0;
hsvequalizer.enabled = false;
for(int i = 0; i < 8; i ++)
{
hsvequalizer.sat[i] = 0;
hsvequalizer.val[i] = 0;
hsvequalizer.hue[i] = 0;
}
hsvequalizer.hcurve.clear ();
hsvequalizer.hcurve.push_back (FCT_Linear);
hsvequalizer.scurve.clear ();
hsvequalizer.scurve.push_back (FCT_Linear);
hsvequalizer.vcurve.clear ();
hsvequalizer.vcurve.push_back (FCT_Linear);
raw.df_autoselect = false;
raw.cared = 0;
raw.cablue = 0;
@@ -219,10 +219,10 @@ void ProcParams::setDefaults () {
raw.dcb_iterations=2;
raw.dcb_enhance=false;
//exposition
raw.expos=1.0;
raw.preser=0.0;
//raw.expos_correc=false;
// expos
raw.expos=1.0;
raw.preser=0.0;
//raw.expos_correc=false;
// expos
exif.clear ();
iptc.clear ();
@@ -417,27 +417,15 @@ int ProcParams::save (Glib::ustring fname) const {
keyFile.set_double("Directional Pyramid Equalizer", ss.str(), dirpyrequalizer.mult[i]);
}
// save hsv equalizer parameters
keyFile.set_boolean ("HSV Equalizer", "Enabled", hsvequalizer.enabled);
keyFile.set_string ("HSV Equalizer", "Channel", hsvequalizer.hsvchannel);
for(int i = 0; i < 8; i++)
{
std::stringstream ss;
ss << "Sat" << i;
keyFile.set_double("HSV Equalizer", ss.str(), hsvequalizer.sat[i]);
}
for(int i = 0; i < 8; i++)
{
std::stringstream ss;
ss << "Val" << i;
keyFile.set_double("HSV Equalizer", ss.str(), hsvequalizer.val[i]);
}
for(int i = 0; i < 8; i++)
{
std::stringstream ss;
ss << "Hue" << i;
keyFile.set_double("HSV Equalizer", ss.str(), hsvequalizer.hue[i]);
}
// save hsv equalizer parameters
//keyFile.set_boolean ("HSV Equalizer", "Enabled", hsvequalizer.enabled);
//keyFile.set_string ("HSV Equalizer", "Channel", hsvequalizer.hsvchannel);
Glib::ArrayHandle<double> hcurve = hsvequalizer.hcurve;
Glib::ArrayHandle<double> scurve = hsvequalizer.scurve;
Glib::ArrayHandle<double> vcurve = hsvequalizer.vcurve;
keyFile.set_double_list("HSV Equalizer", "HCurve", hcurve);
keyFile.set_double_list("HSV Equalizer", "SCurve", scurve);
keyFile.set_double_list("HSV Equalizer", "VCurve", vcurve);
// save RAW parameters
keyFile.set_string ("RAW", "DarkFrame", raw.dark_frame );
@@ -742,27 +730,13 @@ if (keyFile.has_group ("Directional Pyramid Equalizer")) {
if(keyFile.has_key ("Directional Pyramid Equalizer", ss.str())) dirpyrequalizer.mult[i] = keyFile.get_double ("Directional Pyramid Equalizer", ss.str());
}
}
// load wavelet equalizer parameters
// load HSV equalizer parameters
if (keyFile.has_group ("HSV Equalizer")) {
if (keyFile.has_key ("HSV Equalizer", "Enabled")) hsvequalizer.enabled = keyFile.get_boolean ("HSV Equalizer", "Enabled");
for(int i = 0; i < 8; i ++)
{
std::stringstream ss;
ss << "Sat" << i;
if(keyFile.has_key ("HSV Equalizer", ss.str())) hsvequalizer.sat[i] = keyFile.get_double ("HSV Equalizer", ss.str());
}
for(int i = 0; i < 8; i ++)
{
std::stringstream ss;
ss << "Val" << i;
if(keyFile.has_key ("HSV Equalizer", ss.str())) hsvequalizer.val[i] = keyFile.get_double ("HSV Equalizer", ss.str());
}
for(int i = 0; i < 8; i ++)
{
std::stringstream ss;
ss << "Hue" << i;
if(keyFile.has_key ("HSV Equalizer", ss.str())) hsvequalizer.hue[i] = keyFile.get_double ("HSV Equalizer", ss.str());
if (ppVersion>=300) {
if (keyFile.has_key ("HSV Equalizer", "HCurve")) hsvequalizer.hcurve = keyFile.get_double_list ("HSV Equalizer", "HCurve");
if (keyFile.has_key ("HSV Equalizer", "SCurve")) hsvequalizer.scurve = keyFile.get_double_list ("HSV Equalizer", "SCurve");
if (keyFile.has_key ("HSV Equalizer", "VCurve")) hsvequalizer.vcurve = keyFile.get_double_list ("HSV Equalizer", "VCurve");
}
}
@@ -841,17 +815,6 @@ bool operator==(const DirPyrEqualizerParams & a, const DirPyrEqualizerParams & b
return true;
}
bool operator==(const HSVEqualizerParams & a, const HSVEqualizerParams & b) {
if(a.enabled != b.enabled)
return false;
for(int i = 0; i < 8; i++) {
if(a.sat[i] != b.sat[i] && a.val[i] != b.val[i] && a.hue[i] != b.hue[i])
return false;
}
return true;
}
bool operator==(const ExifPair& a, const ExifPair& b) {
return a.field == b.field && a.value == b.value;
@@ -984,8 +947,10 @@ bool ProcParams::operator== (const ProcParams& other) {
&& icm.working == other.icm.working
&& icm.output == other.icm.output
&& equalizer == other.equalizer
&& dirpyrequalizer == other.dirpyrequalizer
&& hsvequalizer == other.hsvequalizer
&& dirpyrequalizer == other.dirpyrequalizer
&& hsvequalizer.hcurve == other.hsvequalizer.hcurve
&& hsvequalizer.scurve == other.hsvequalizer.scurve
&& hsvequalizer.vcurve == other.hsvequalizer.vcurve
&& exif==other.exif
&& iptc==other.iptc
&& raw.expos==other.raw.expos // exposi

View File

@@ -370,16 +370,16 @@ class DirPyrEqualizerParams {
};
/**
* Wavelet equalizer params
* HSV equalizer params
*/
class HSVEqualizerParams {
public:
bool enabled;
Glib::ustring hsvchannel;
int sat[8];
int val[8];
int hue[8];
//bool enabled;
//Glib::ustring hsvchannel;
std::vector<double> hcurve;
std::vector<double> scurve;
std::vector<double> vcurve;
};
/**

View File

@@ -17,9 +17,16 @@
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <utils.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#undef MAX
#undef MIN
#define MAX(a,b) ((a)<(b)?(b):(a))
#define MIN(a,b) ((a)>(b)?(b):(a))
namespace rtengine {
void bilinearInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh) {
@@ -139,6 +146,77 @@ void vflip (unsigned char* img, int w, int h) {
delete [] flipped;
}
void rgb2hsv (int r, int g, int b, float &h, float &s, float &v) {
double var_R = r / 65535.0;
double var_G = g / 65535.0;
double var_B = b / 65535.0;
double var_Min = MIN(MIN(var_R,var_G),var_B);
double var_Max = MAX(MAX(var_R,var_G),var_B);
double del_Max = var_Max - var_Min;
v = var_Max;
if (fabs(del_Max)<0.00001) {
h = 0;
s = 0;
}
else {
s = del_Max/var_Max;
if ( var_R == var_Max ) h = (var_G - var_B)/del_Max;
else if ( var_G == var_Max ) h = 2.0 + (var_B - var_R)/del_Max;
else if ( var_B == var_Max ) h = 4.0 + (var_R - var_G)/del_Max;
h /= 6.0;
if ( h < 0 ) h += 1;
if ( h > 1 ) h -= 1;
}
}
void hsv2rgb (float h, float s, float v, int &r, int &g, int &b) {
float h1 = h*6; // sector 0 to 5
int i = floor( h1 );
float f = h1 - i; // fractional part of h
float p = v * ( 1 - s );
float q = v * ( 1 - s * f );
float t = v * ( 1 - s * ( 1 - f ) );
float r1,g1,b1;
if (i==0) {r1 = v; g1 = t; b1 = p;}
if (i==1) {r1 = q; g1 = v; b1 = p;}
if (i==2) {r1 = p; g1 = v; b1 = t;}
if (i==3) {r1 = p; g1 = q; b1 = v;}
if (i==4) {r1 = t; g1 = p; b1 = v;}
if (i==5) {r1 = v; g1 = p; b1 = q;}
r = (int)((r1)*65535);
g = (int)((g1)*65535);
b = (int)((b1)*65535);
}
// The same function but set float values intead if int
// Function copied for speed concerns
void hsv2rgb (float h, float s, float v, float &r, float &g, float &b) {
float h1 = h*6; // sector 0 to 5
int i = floor( h1 );
float f = h1 - i; // fractional part of h
float p = v * ( 1 - s );
float q = v * ( 1 - s * f );
float t = v * ( 1 - s * ( 1 - f ) );
if (i==0) {r = v; g = t; b = p;}
if (i==1) {r = q; g = v; b = p;}
if (i==2) {r = p; g = v; b = t;}
if (i==3) {r = p; g = q; b = v;}
if (i==4) {r = t; g = p; b = v;}
if (i==5) {r = v; g = p; b = q;}
}
}

View File

@@ -26,6 +26,9 @@ void nearestInterp (const unsigned char* src, int sw, int sh, unsigned char* dst
void rotate (unsigned char* img, int& w, int& h, int deg);
void hflip (unsigned char* img, int w, int h);
void vflip (unsigned char* img, int w, int h);
void rgb2hsv (int r, int g, int b, float &h, float &s, float &v);
void hsv2rgb (float h, float s, float v, int &r, int &g, int &b);
void hsv2rgb (float h, float s, float v, float &r, float &g, float &b);
}
#endif

View File

@@ -12,12 +12,13 @@ set (BASESOURCEFILES
exifpanel.cc toolpanel.cc
sharpening.cc
whitebalance.cc vignetting.cc rotate.cc distortion.cc
crophandler.cc curveeditorgroup.cc curveeditor.cc dirbrowser.cc
crophandler.cc dirbrowser.cc
curveeditor.cc curveeditorgroup.cc diagonalcurveeditorsubgroup.cc flatcurveeditorsubgroup.cc
filecatalog.cc
previewloader.cc
histogrampanel.cc history.cc imagearea.cc
imageareapanel.cc iptcpanel.cc labcurve.cc lumadenoise.cc main.cc
multilangmgr.cc mycurve.cc options.cc
multilangmgr.cc mycurve.cc myflatcurve.cc mydiagonalcurve.cc options.cc
preferences.cc profilepanel.cc safegtk.cc saveasdlg.cc
saveformatpanel.cc splash.cc
thumbnail.cc tonecurve.cc toolbar.cc

33
rtgui/colorprovider.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _COLORPROVIDER_
#define _COLORPROVIDER_
class ColorProvider {
public:
double red;
double green;
double blue;
virtual void colorForValue (double valX, double valY) {}
};
#endif

View File

@@ -30,6 +30,8 @@ void CursorManager::init (Glib::RefPtr<Gdk::Window> mainWin) {
cCropMove = new Gdk::Cursor (Gdk::FLEUR);
cCropMoving = new Gdk::Cursor (Gdk::HAND2);
cCropSelection = new Gdk::Cursor (Gdk::CROSSHAIR);
cLeftTanMove = new Gdk::Cursor (Gdk::SB_LEFT_ARROW);
cRightTanMove = new Gdk::Cursor (Gdk::SB_RIGHT_ARROW);
cAdd = new Gdk::Cursor (Gdk::PLUS);
Glib::RefPtr<Gdk::Pixbuf> hand = safe_create_from_file(argv0+"/images/openhand22.png");
@@ -50,7 +52,7 @@ void CursorManager::setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape sha
if (shape==CSArrow)
// set_cursor without any arguments to select system default
window->set_cursor ();
window->set_cursor ();
else if (shape==CSOpenHand)
window->set_cursor (*cHand);
else if (shape==CSClosedHand)
@@ -67,6 +69,10 @@ void CursorManager::setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape sha
window->set_cursor (*cWB);
else if (shape==CSCropSelect)
window->set_cursor (*cCropSelection);
else if (shape==CSMoveLeft)
window->set_cursor (*cLeftTanMove);
else if (shape==CSMoveRight)
window->set_cursor (*cRightTanMove);
else if (shape==CSStraighten)
window->set_cursor (*cCropSelection);
else if (shape==CSPlus)

View File

@@ -21,7 +21,7 @@
#include <gtkmm.h>
enum CursorShape {CSArrow, CSOpenHand, CSClosedHand, CSMove, CSResizeWidth, CSResizeHeight, CSResizeDiagonal, CSSpotWB, CSCropSelect, CSStraighten, CSPlus, CSEmpty};
enum CursorShape {CSArrow, CSOpenHand, CSClosedHand, CSMove, CSMoveLeft, CSMoveRight, CSResizeWidth, CSResizeHeight, CSResizeDiagonal, CSSpotWB, CSCropSelect, CSStraighten, CSPlus, CSEmpty};
class CursorManager {
@@ -31,6 +31,8 @@ class CursorManager {
Gdk::Cursor* cResizeDiag;
Gdk::Cursor* cCropMove;
Gdk::Cursor* cCropMoving;
Gdk::Cursor* cLeftTanMove;
Gdk::Cursor* cRightTanMove;
Gdk::Cursor* cNormal;
Gdk::Cursor* cCropSelection;
Gdk::Cursor* cAdd;

View File

@@ -25,6 +25,58 @@
extern Glib::ustring argv0;
DiagonalCurveEditor::DiagonalCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup) : CurveEditor::CurveEditor(text, (CurveEditorGroup*) ceGroup, ceSubGroup) {
// Order set in the same order than "enum DiagonalCurveType". Shouldn't change, for compatibility reason
curveType->addEntry(argv0+"/images/curveType-linear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear
curveType->addEntry(argv0+"/images/curveType-spline.png", M("CURVEEDITOR_CUSTOM")); // 1 Spline
curveType->addEntry(argv0+"/images/curveType-parametric.png", M("CURVEEDITOR_PARAMETRIC")); // 2 Parametric
curveType->addEntry(argv0+"/images/curveType-NURBS.png", M("CURVEEDITOR_NURBS")); // 3 NURBS
curveType->setSelected(DCT_Linear);
curveType->show();
}
std::vector<double> DiagonalCurveEditor::getCurve () {
std::vector<double> curve;
switch (selected) {
case (DCT_Spline):
return curve = customCurveEd;
case (DCT_Parametric):
return curve = paramCurveEd;
case (DCT_NURBS):
return curve = NURBSCurveEd;
default:
// returning Linear or Unchanged
curve.push_back((double)(selected));
return curve;
}
}
FlatCurveEditor::FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup) : CurveEditor::CurveEditor(text, (CurveEditorGroup*) ceGroup, ceSubGroup) {
// Order set in the same order than "enum FlatCurveType". Shouldn't change, for compatibility reason
curveType->addEntry(argv0+"/images/curveType-flatLinear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear
curveType->addEntry(argv0+"/images/curveType-controlPoints.png", M("CURVEEDITOR_MINMAXCPOINTS")); // 1 Min/Max ControlPoints
curveType->setSelected(FCT_Linear);
curveType->show();
}
std::vector<double> FlatCurveEditor::getCurve () {
std::vector<double> curve;
switch (selected) {
//case (Parametric):
// return curve = paramCurveEd;
case (FCT_MinMaxCPoints):
return curve = controlPointsCurveEd;
default:
// returning Linear or Unchanged
curve.push_back((double)(selected));
return curve;
}
}
/*
* CurveEditor (CurveEditorGroup* ceGroup, Glib::ustring text)
*
@@ -32,32 +84,25 @@ extern Glib::ustring argv0;
* ceGroup = NULL or the address of the Widget that will receive the CurveTypeToggleButton
* text = (optional) label of the curve, displayed in the CurveTypeToggleButton, next to the image
*/
CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup) {
CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup) {
bgHistValid = false;
selected = Linear;
selected = DCT_Linear;
histogram = new unsigned int[256]; // histogram values
group = ceGroup;
subGroup = ceSubGroup;
if (group && text.size())
curveType = Gtk::manage (new PopUpToggleButton(text + ":"));
else
curveType = Gtk::manage (new PopUpToggleButton());
// Order set in the same order than "enum CurveType". Shouldn't change, for compatibility reason
curveType->addEntry(argv0+"/images/curveType-linear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear
curveType->addEntry(argv0+"/images/curveType-spline.png", M("CURVEEDITOR_CUSTOM")); // 1 Spline
curveType->addEntry(argv0+"/images/curveType-parametric.png", M("CURVEEDITOR_PARAMETRIC")); // 2 Parametric
curveType->addEntry(argv0+"/images/curveType-NURBS.png", M("CURVEEDITOR_NURBS")); // 3 NURBS
curveType->setSelected(Linear);
curveType->set_tooltip_text(M("CURVEEDITOR_TYPE"));
// TODO: Does this signal have to be blocked when on curve type change ?
curveType->signal_toggled().connect ( sigc::mem_fun(*this, &CurveEditor::curveTypeToggled) );
typeconn = curveType->signal_changed().connect (sigc::mem_fun(*this, &CurveEditor::typeSelectionChanged) );
curveType->show();
}
CurveEditor::~CurveEditor () {
@@ -65,29 +110,11 @@ CurveEditor::~CurveEditor () {
delete [] histogram;
}
void CurveEditor::setCurve (const std::vector<double>& p) {
tempCurve = p;
group->setCurveExternal(this, p);
}
std::vector<double> CurveEditor::getCurve () {
std::vector<double> curve;
switch (selected) {
case (Spline):
return curve = customCurveEd;
case (Parametric):
return curve = paramCurveEd;
case (NURBS):
return curve = NURBSCurveEd;
default:
// returning Linear or Unchanged
curve.push_back((double)(selected));
return curve;
}
}
void CurveEditor::typeSelectionChanged (int n) {
group->typeSelectionChanged(this, n);
}
@@ -97,7 +124,7 @@ void CurveEditor::curveTypeToggled() {
}
bool CurveEditor::isUnChanged () {
return curveType->getSelected()==Unchanged;
return curveType->getSelected()==subGroup->getValUnchanged();
}
void CurveEditor::setUnChanged (bool uc) {
@@ -117,5 +144,5 @@ void CurveEditor::updateBackgroundHistogram (unsigned int* hist) {
bgHistValid = false;
// Then call the curve editor group to eventually update the histogram
group->updateBackgroundHistogram (this);
subGroup->updateBackgroundHistogram (this);
}

View File

@@ -19,12 +19,16 @@
#ifndef _CURVEEDITOR_
#define _CURVEEDITOR_
#include <gtkmm.h>
#include <popuptogglebutton.h>
#include <curveeditorgroup.h>
#include <mycurve.h>
class CurveEditorGroup;
class CurveEditorSubGroup;
/*
*********************** Curve Editor ***********************
*/
/*
* This class is an interface between RT and the curve editor group ; it handles the methods
@@ -32,40 +36,83 @@ class CurveEditorGroup;
*/
class CurveEditor {
private:
/*
* The curve editor contains only one widget (the curve type button) to receive the signals
* but it's co-handled by the CurveEditorGroup too
*/
// reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value
CurveType selected;
PopUpToggleButton* curveType;
unsigned int* histogram; // histogram values
bool bgHistValid;
CurveEditorGroup* group;
std::vector<double> tempCurve;
std::vector<double> customCurveEd;
std::vector<double> paramCurveEd;
std::vector<double> NURBSCurveEd;
sigc::connection typeconn;
public:
friend class CurveEditorGroup;
CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup);
~CurveEditor ();
void typeSelectionChanged (int n);
void curveTypeToggled();
void setCurve (const std::vector<double>& p);
std::vector<double> getCurve ();
bool isUnChanged ();
void setUnChanged (bool uc);
void updateBackgroundHistogram (unsigned int* hist);
friend class CurveEditorSubGroup;
friend class DiagonalCurveEditorSubGroup;
friend class FlatCurveEditorSubGroup;
friend class DiagonalCurveEditor;
friend class FlatCurveEditor;
protected:
/*
* The curve editor contains only one widget (the curve type button) to receive the signals
* but it's co-handled by the CurveEditorGroup too
*/
PopUpToggleButton* curveType;
unsigned int* histogram; // histogram values
bool bgHistValid;
int selected;
CurveEditorGroup* group;
CurveEditorSubGroup* subGroup;
std::vector<double> tempCurve;
sigc::connection typeconn;
public:
CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup);
~CurveEditor ();
void typeSelectionChanged (int n);
void curveTypeToggled();
bool isUnChanged ();
void setUnChanged (bool uc);
void updateBackgroundHistogram (unsigned int* hist);
void setCurve (const std::vector<double>& p);
virtual std::vector<double> getCurve () = 0;
};
/*
******************** Diagonal Curve Editor ********************
*/
class DiagonalCurveEditor : public CurveEditor {
friend class DiagonalCurveEditorSubGroup;
protected:
// reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value
std::vector<double> customCurveEd;
std::vector<double> paramCurveEd;
std::vector<double> NURBSCurveEd;
public:
DiagonalCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup);
std::vector<double> getCurve ();
};
/*
********************** Flat Curve Editor **********************
*/
class FlatCurveEditor : public CurveEditor {
friend class FlatCurveEditorSubGroup;
protected:
// reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value
std::vector<double> controlPointsCurveEd;
public:
FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup);
std::vector<double> getCurve ();
};
#endif

View File

@@ -18,144 +18,24 @@
*
* Class created by Jean-Christophe FRISCH, aka 'Hombre'
*/
#include <curveeditor.h>
#include <curveeditorgroup.h>
#include <diagonalcurveeditorsubgroup.h>
#include <flatcurveeditorsubgroup.h>
#include <multilangmgr.h>
extern Glib::ustring argv0;
CurveEditorGroup::CurveEditorGroup (Glib::ustring groupLabel) : cl(NULL), activeParamControl(-1) {
CurveEditorGroup::CurveEditorGroup (Glib::ustring groupLabel) : cl(NULL), cp(NULL) {
curveEditors.clear();
displayedCurve = 0;
numberOfPackedCurve = 0;
flatSubGroup = 0;
diagonalSubGroup = 0;
// We set the label to the one provided as parameter, even if it's an empty string
curveGroupLabel = Gtk::manage (new Gtk::Label (groupLabel+":", Gtk::ALIGN_LEFT));
// custom curve
customCurveBox = new Gtk::HBox ();
Gtk::HBox* tmpa = Gtk::manage (new Gtk::HBox ());
customCurve = Gtk::manage (new MyCurve ());
//Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
//af->add (*customCurve);
customCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
customCurve->setType (Spline);
//customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED"));
tmpa->pack_start (*customCurve, true, false, 4);
customCurveBox->pack_start (*tmpa, true, true,4);
Gtk::VBox* custombbox = Gtk::manage (new Gtk::VBox ());
saveCustom = Gtk::manage (new Gtk::Button ());
saveCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)));
loadCustom = Gtk::manage (new Gtk::Button ());
loadCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON)));
custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 4);
custombbox->pack_end (*loadCustom, Gtk::PACK_SHRINK, 4);
customCurveBox->pack_end (*custombbox, Gtk::PACK_SHRINK, 0);
customCurveBox->show_all ();
saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::savePressed) );
loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::loadPressed) );
saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
loadCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD"));
// NURBS curve
NURBSCurveBox = new Gtk::HBox ();
Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ());
NURBSCurve = Gtk::manage (new MyCurve ());
//Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
//af->add (*customCurve);
NURBSCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
NURBSCurve->setType (NURBS);
//customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED"));
tmpb->pack_start (*NURBSCurve, true, false, 4);
NURBSCurveBox->pack_start (*tmpb, true, true,4);
Gtk::VBox* NURBSbbox = Gtk::manage (new Gtk::VBox ());
saveNURBS = Gtk::manage (new Gtk::Button ());
saveNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)));
loadNURBS = Gtk::manage (new Gtk::Button ());
loadNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON)));
NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 4);
NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_SHRINK, 4);
NURBSCurveBox->pack_end (*NURBSbbox, Gtk::PACK_SHRINK, 0);
NURBSCurveBox->show_all ();
saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::savePressed) );
loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::loadPressed) );
saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
loadNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD"));
// parametric curve
paramCurveBox = new Gtk::VBox ();
paramCurve = Gtk::manage (new MyCurve ());
Gtk::Table* paramctab = Gtk::manage (new Gtk::Table (2,1));
//Gtk::AspectFrame* afp = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
//afp->add (*paramCurve);
paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
paramCurve->setType (Parametric);
shcSelector = Gtk::manage (new SHCSelector ());
shcSelector->set_size_request (GRAPH_SIZE, 20);
paramctab->attach (*paramCurve, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 4, 4);
paramctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, RADIUS+4, 0);
Gtk::HBox* tmpc = Gtk::manage (new Gtk::HBox ());
tmpc->pack_start (*paramctab, true, false);
paramCurveBox->pack_start (*tmpc, true, true);
highlights = Gtk::manage (new Adjuster (M("CURVEEDITOR_HIGHLIGHTS"), -100, 100, 1, 0));
lights = Gtk::manage (new Adjuster (M("CURVEEDITOR_LIGHTS"), -100, 100, 1, 0));
darks = Gtk::manage (new Adjuster (M("CURVEEDITOR_DARKS"), -100, 100, 1, 0));
shadows = Gtk::manage (new Adjuster (M("CURVEEDITOR_SHADOWS"), -100, 100, 1, 0));
Gtk::EventBox* evhighlights = Gtk::manage (new Gtk::EventBox ());
Gtk::EventBox* evlights = Gtk::manage (new Gtk::EventBox ());
Gtk::EventBox* evdarks = Gtk::manage (new Gtk::EventBox ());
Gtk::EventBox* evshadows = Gtk::manage (new Gtk::EventBox ());
evhighlights->add (*highlights);
evlights->add (*lights);
evdarks->add (*darks);
evshadows->add (*shadows);
paramCurveBox->pack_start (*Gtk::manage (new Gtk::HSeparator ()));
paramCurveBox->pack_start (*evhighlights);
paramCurveBox->pack_start (*evlights);
paramCurveBox->pack_start (*evdarks);
paramCurveBox->pack_start (*evshadows);
paramCurveBox->show_all ();
customCurveBox->reference ();
paramCurveBox->reference ();
customCurve->setCurveListener (this);
NURBSCurve->setCurveListener (this);
paramCurve->setCurveListener (this);
shcSelector->setSHCListener (this);
highlights->setAdjusterListener (this);
lights->setAdjusterListener (this);
darks->setAdjusterListener (this);
shadows->setAdjusterListener (this);
evhighlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evdarks->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evshadows->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evhighlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 4));
evlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 5));
evdarks->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 6));
evshadows->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterEntered), 7));
evhighlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 4));
evlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 5));
evdarks->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 6));
evshadows->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditorGroup::adjusterLeft), 7));
}
CurveEditorGroup::~CurveEditorGroup() {
@@ -163,9 +43,8 @@ CurveEditorGroup::~CurveEditorGroup() {
{
delete *i;
}
delete customCurveBox;
delete paramCurveBox;
delete NURBSCurveBox;
delete flatSubGroup;
delete diagonalSubGroup;
}
void CurveEditorGroup::hideCurrentCurve() {
@@ -177,17 +56,22 @@ void CurveEditorGroup::hideCurrentCurve() {
/*
* Add a new curve to the curves list
*/
CurveEditor* CurveEditorGroup::addCurve(Glib::ustring curveLabel) {
CurveEditor* newCE = new CurveEditor(curveLabel, this);
// Initialization of the new curve
storeCurveValues(newCE, getCurveFromGUI(Spline));
storeCurveValues(newCE, getCurveFromGUI(Parametric));
storeCurveValues(newCE, getCurveFromGUI(NURBS));
// We add it to the curve editor list
curveEditors.push_back(newCE);
return newCE;
CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabel) {
switch (cType) {
case (CT_Diagonal):
if (!diagonalSubGroup) {
diagonalSubGroup = new DiagonalCurveEditorSubGroup(this);
}
return (CurveEditor*)diagonalSubGroup->addCurve(curveLabel);
case (CT_Flat):
if (!flatSubGroup) {
flatSubGroup = new FlatCurveEditorSubGroup(this);
}
return (CurveEditor*)flatSubGroup->addCurve(curveLabel);
default:
return (CurveEditor*)NULL;
break;
}
}
/*
@@ -233,6 +117,12 @@ void CurveEditorGroup::newLine() {
void CurveEditorGroup::curveListComplete() {
newLine();
// Set the color provider
if (cp) {
if (flatSubGroup) flatSubGroup->setColorProvider(cp);
if (diagonalSubGroup) diagonalSubGroup->setColorProvider(cp);
}
// We check the length of the label ; if it contains only one char (':'), we set it to the right default string
if (curveGroupLabel->get_label().size()==1)
curveGroupLabel->set_label(M(curveEditors.size() > 1 ? "CURVEEDITOR_CURVES" : "CURVEEDITOR_CURVE") + ":");
@@ -247,11 +137,11 @@ void CurveEditorGroup::curveListComplete() {
*/
void CurveEditorGroup::typeSelectionChanged (CurveEditor* ce, int n) {
// Same type : do nothing
if (ce==displayedCurve && (CurveType)n==ce->selected)
if (ce==displayedCurve && n==(int)ce->selected)
return;
if ((CurveType)(n)<Unchanged)
ce->selected = (CurveType)n;
if (n<ce->subGroup->valUnchanged)
ce->selected = n;
// The user selected a new type from a toggled off button
if (ce!=displayedCurve)
@@ -260,11 +150,11 @@ void CurveEditorGroup::typeSelectionChanged (CurveEditor* ce, int n) {
// If the button was not pressed before
if (!ce->curveType->get_active()) {
storeDisplayedCurve();
ce->subGroup->storeDisplayedCurve();
// We set it pressed : it will emit the toggle on signal and update the GUI
ce->curveType->set_active( n>Linear && n<Unchanged );
if (n==Linear || n==Unchanged) {
// Since we do not activate the curve when the user switch the a toggled off button to 'Linear', we have to
ce->curveType->set_active( n>ce->subGroup->valLinear && n<ce->subGroup->valUnchanged );
if (n==ce->subGroup->valLinear || n==ce->subGroup->valUnchanged) {
// Since we do not activate the curve when the user switch the toggled off button to 'Linear', we have to
// to call the curve listener manually, because 'curveChanged' uses displayedCurve...
if (cl) {
if (cl->isMulti())
@@ -278,7 +168,7 @@ void CurveEditorGroup::typeSelectionChanged (CurveEditor* ce, int n) {
}
else {
// The button is already pressed so we switch the GUI ourselves
switchGUI();
ce->subGroup->switchGUI();
curveChanged ();
}
}
@@ -297,21 +187,21 @@ void CurveEditorGroup::curveTypeToggled(CurveEditor* ce) {
displayedCurve = ce;
if (ce->curveType->getSelected()==Unchanged) {
if (ce->curveType->getSelected()==ce->subGroup->valUnchanged) {
curveRestored = true;
ce->curveType->setSelected(ce->selected);
}
// then show this CurveEditor
int ct = ce->curveType->getSelected();
if (ct < Unchanged)
restoreDisplayedHistogram();
if (ct < ce->subGroup->valUnchanged)
ce->subGroup->restoreDisplayedHistogram();
}
else {
// The button is now released, so we have to hide this CurveEditor
displayedCurve = 0;
}
switchGUI();
ce->subGroup->switchGUI();
if (curveRestored)
curveChanged ();
@@ -319,49 +209,88 @@ void CurveEditorGroup::curveTypeToggled(CurveEditor* ce) {
}
/*
* Switch the editor widgets to the currently edited curve
* Update the GUI if the given curveEditor is currently displayed
*/
void CurveEditorGroup::switchGUI() {
void CurveEditorGroup::updateGUI (CurveEditor* ce) {
if (!ce) {
return;
}
removeEditor();
// we update the curve type button to the corresponding curve type, only if it is not currently set to 'Unchanged'
if (ce->curveType->getSelected()<ce->subGroup->valUnchanged)
ce->curveType->setSelected(ce->selected);
// if not displayed or "unchanged" is selected, do not change gui
if (ce==displayedCurve && ce->curveType->getSelected()<ce->subGroup->valUnchanged) {
ce->subGroup->switchGUI();
}
}
/*
* Called from the outside to set the curve type & values
*/
void CurveEditorGroup::setCurveExternal (CurveEditor* ce, const std::vector<double>& c) {
if (c.size()) {
ce->subGroup->storeCurveValues(ce, c); // The new curve is saved in the CurveEditor
(ce)->selected = c[0]; // We set the selected curve type in the CurveEditor to the one of the specified curve
}
updateGUI((CurveEditor*)ce); // And we update the GUI if necessary
}
/*
* Listener called when the user has modified the curve
*/
void CurveEditorGroup::curveChanged () {
displayedCurve->subGroup->storeDisplayedCurve();
if (cl) {
if (cl->isMulti())
cl->curveChanged (displayedCurve);
else
cl->curveChanged ();
}
}
/*
* Call back method when the reset button is pressed :
* reset the currently toggled on curve editor
*/
void CurveEditorGroup::curveResetPressed () {
if (displayedCurve) {
// Initializing GUI values + repacking the appropriated widget
//displayedCurve->typeconn.block(true);
switch((CurveType)(displayedCurve->curveType->getSelected())) {
case (Spline):
customCurve->setPoints (displayedCurve->customCurveEd);
pack_start (*customCurveBox);
break;
case (Parametric):
paramCurve->setPoints (displayedCurve->paramCurveEd);
shcSelector->setPositions (
displayedCurve->paramCurveEd.at(1),
displayedCurve->paramCurveEd.at(2),
displayedCurve->paramCurveEd.at(3)
);
highlights->setValue (displayedCurve->paramCurveEd.at(4));
lights->setValue (displayedCurve->paramCurveEd.at(5));
darks->setValue (displayedCurve->paramCurveEd.at(6));
shadows->setValue (displayedCurve->paramCurveEd.at(7));
pack_start (*paramCurveBox);
break;
case (NURBS):
NURBSCurve->setPoints (displayedCurve->NURBSCurveEd);
pack_start (*NURBSCurveBox);
break;
default: // (Linear, Unchanged)
// ... do nothing
break;
if (displayedCurve->subGroup->curveReset(displayedCurve->selected)) {
curveChanged();
}
//displayedCurve->typeconn.block(false);
}
}
void CurveEditorGroup::savePressed () {
void CurveEditorGroup::setBatchMode (bool batchMode) {
for (std::vector<CurveEditor*>::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) {
(*i)->curveType->addEntry(argv0+"/images/curveType-unchanged.png", M("GENERAL_UNCHANGED"));
(*i)->curveType->show();
}
}
void CurveEditorGroup::setUnChanged (bool uc, CurveEditor* ce) {
if (uc) {
// the user selected several thumbnails, so we hide the editors and set the curveEditor selection to 'Unchanged'
//ce->typeconn.block(true);
// we hide the editor widgets
hideCurrentCurve();
// the curve type selected option is set to unchanged
ce->curveType->setSelected(ce->subGroup->valUnchanged);
//ce->typeconn.block(false);
}
else {
// we want it to use back the 'CurveEditor::setCurve' memorized in CurveEditor::tempCurve
//ce->typeconn.block(true);
// we switch back the curve type selected option to the one of the used curve
ce->curveType->setSelected(ce->selected);
updateGUI (ce);
//ce->typeconn.block(false);
}
}
Glib::ustring CurveEditorSubGroup::outputFile () {
Gtk::FileChooserDialog dialog(M("CURVEEDITOR_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE);
// if (options.multiUser)
@@ -384,52 +313,37 @@ void CurveEditorGroup::savePressed () {
dialog.set_do_overwrite_confirmation (true);
int result = dialog.run();
Glib::ustring fname;
do {
int result = dialog.run();
if (result==Gtk::RESPONSE_OK) {
fname = dialog.get_filename();
std::string fname = dialog.get_filename();
if (result==Gtk::RESPONSE_OK) {
if (getExtension (fname)!="rtc")
fname = fname + ".rtc";
if (getExtension (fname)!="rtc")
fname = fname + ".rtc";
if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) {
Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + "</b>";
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
int response = msgd.run ();
if (response==Gtk::RESPONSE_NO)
return;
}
if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) {
Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + "</b>";
Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
int response = msgd.run ();
if (response==Gtk::RESPONSE_YES)
break;
}
else
break;
}
else {
fname = "";
break;
}
} while (1);
std::ofstream f (fname.c_str());
std::vector<double> p = customCurve->getPoints ();
switch (displayedCurve->selected) {
case Spline: // custom
p = customCurve->getPoints ();
break;
case NURBS: // NURBS
p = NURBSCurve->getPoints ();
break;
default:
break;
}
int ix = 0;
if (p[ix]==(double)(Linear))
f << "Linear\n";
else if (p[ix]==(double)(Spline))
f << "Spline\n";
else if (p[ix]==(double)(NURBS))
f << "NURBS\n";
ix++;
for (unsigned int i=0; i<p.size()/2; i++, ix+=2)
f << p[ix] << ' ' << p[ix+1] << std::endl;
f.close ();
}
return fname;
}
void CurveEditorGroup::loadPressed () {
Glib::ustring CurveEditorSubGroup::inputFile () {
Gtk::FileChooserDialog dialog(M("CURVEEDITOR_LOADDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN);
@@ -448,284 +362,12 @@ void CurveEditorGroup::loadPressed () {
int result = dialog.run();
Glib::ustring fname;
if (result==Gtk::RESPONSE_OK) {
std::ifstream f (dialog.get_filename().c_str());
if (f) {
std::vector<double> p;
std::string s;
f >> s;
if (s=="Linear")
p.push_back ((double)(Linear));
else if (s=="Spline")
p.push_back ((double)(Spline));
else if (s=="NURBS")
p.push_back ((double)(NURBS));
else return;
double x;
while (f) {
f >> x;
if (f)
p.push_back (x);
}
if (p[0] == (double)(Spline)) {
customCurve->setPoints (p);
customCurve->queue_draw ();
customCurve->notifyListener ();
}
else if (p[0] == (double)(NURBS)) {
NURBSCurve->setPoints (p);
NURBSCurve->queue_draw ();
NURBSCurve->notifyListener ();
}
}
fname = dialog.get_filename();
if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS))
return fname;
}
}
/*
* Store the curves of the currently displayed type from the widgets to the CurveEditor object
*/
void CurveEditorGroup::storeDisplayedCurve() {
if (displayedCurve) {
switch (displayedCurve->selected) {
case (Spline):
storeCurveValues(displayedCurve, getCurveFromGUI(Spline));
break;
case (Parametric):
storeCurveValues(displayedCurve, getCurveFromGUI(Parametric));
break;
case (NURBS):
storeCurveValues(displayedCurve, getCurveFromGUI(NURBS));
break;
default:
break;
}
}
}
/*
* Restore the histogram to all types from the CurveEditor object to the widgets
*/
void CurveEditorGroup::restoreDisplayedHistogram() {
if (displayedCurve) {
paramCurve->updateBackgroundHistogram (displayedCurve->bgHistValid ? displayedCurve->histogram : NULL);
customCurve->updateBackgroundHistogram (displayedCurve->bgHistValid ? displayedCurve->histogram : NULL);
NURBSCurve->updateBackgroundHistogram (displayedCurve->bgHistValid ? displayedCurve->histogram : NULL);
}
}
void CurveEditorGroup::storeCurveValues (CurveEditor* ce, const std::vector<double>& p) {
if (p.size()) {
CurveType t = (CurveType)p[0];
for (int i=0; i<(int)p.size(); i++)
switch (t) {
case (Spline):
ce->customCurveEd = p;
break;
case (Parametric):
ce->paramCurveEd = p;
break;
case (NURBS):
ce->NURBSCurveEd = p;
break;
default:
break;
}
}
}
/*
* Update the GUI if the given curveEditor is currently displayed
*/
void CurveEditorGroup::updateGUI (CurveEditor* ce) {
if (!ce) {
return;
}
// we update the curve type button to the corresponding curve type, only if it is not currently set to 'Unchanged'
if (ce->curveType->getSelected()<Unchanged)
ce->curveType->setSelected(ce->selected);
// if not displayed or "unchanged" is selected, do not change gui
if (ce==displayedCurve && ce->curveType->getSelected()<Unchanged) {
switchGUI();
}
}
/*
* Called from the outside to set the curve type & values
*/
void CurveEditorGroup::setCurveExternal (CurveEditor* ce, const std::vector<double>& c) {
if (c.size()) {
storeCurveValues(ce, c); // The new curve is saved in the CurveEditor
ce->selected = (CurveType)(c[0]); // We set the selected curve type in the CurveEditor to the one of the specified curve
}
updateGUI(ce); // And we update the GUI if necessary
}
/*
* Called to update the parametric curve graph with new slider values
*/
const std::vector<double> CurveEditorGroup::getCurveFromGUI (CurveType type) {
switch (type) {
case (Parametric): {
std::vector<double> lcurve (8);
lcurve[0] = (double)(Parametric);
shcSelector->getPositions (lcurve[1], lcurve[2], lcurve[3]);
lcurve[4] = highlights->getValue ();
lcurve[5] = lights->getValue ();
lcurve[6] = darks->getValue ();
lcurve[7] = shadows->getValue ();
return lcurve;
}
case (Spline):
return customCurve->getPoints ();
case (NURBS):
return NURBSCurve->getPoints ();
default: {
// linear and other solutions
std::vector<double> lcurve (1);
lcurve[0] = (double)(Linear);
return lcurve;
}
}
}
/*
* Unlink the tree editor widgets from their parent box to hide them
*/
void CurveEditorGroup::removeEditor () {
removeIfThere (this, customCurveBox, false);
removeIfThere (this, paramCurveBox, false);
removeIfThere (this, NURBSCurveBox, false);
}
/*
* Listener called when the user has modified the curve
*/
void CurveEditorGroup::curveChanged () {
storeDisplayedCurve();
if (cl) {
if (cl->isMulti())
cl->curveChanged (displayedCurve);
else
cl->curveChanged ();
}
}
/*
* Listener
*/
void CurveEditorGroup::shcChanged () {
paramCurve->setPoints (getCurveFromGUI(Parametric));
storeDisplayedCurve();
if (cl->isMulti())
cl->curveChanged (displayedCurve);
else
cl->curveChanged ();
}
/*
* Listener
*/
void CurveEditorGroup::adjusterChanged (Adjuster* a, double newval) {
paramCurve->setPoints (getCurveFromGUI(Parametric));
storeDisplayedCurve();
if (cl->isMulti())
cl->curveChanged (displayedCurve);
else
cl->curveChanged ();
}
/*
* Listener called when the mouse is over a parametric curve's slider
*/
bool CurveEditorGroup::adjusterEntered (GdkEventCrossing* ev, int ac) {
if (ev->detail != GDK_NOTIFY_INFERIOR) {
activeParamControl = ac;
paramCurve->setActiveParam (activeParamControl);
}
return true;
}
/*
* Listener called when the mouse left the parametric curve's slider
*/
bool CurveEditorGroup::adjusterLeft (GdkEventCrossing* ev, int ac) {
if (ev->detail != GDK_NOTIFY_INFERIOR) {
activeParamControl = -1;
paramCurve->setActiveParam (activeParamControl);
}
return true;
}
/*
* Call back method when the reset button is pressed :
* reset the currently toggled on curve editor
*/
void CurveEditorGroup::curveResetPressed() {
if (displayedCurve) {
switch (displayedCurve->selected) {
case (NURBS) : // = Control cage
NURBSCurve->reset ();
curveChanged ();
break;
case (Spline) : // = Custom
customCurve->reset ();
curveChanged ();
break;
case (Parametric) :
highlights->resetPressed();
lights->resetPressed();
darks->resetPressed();
shadows->resetPressed();
shcSelector->reset();
paramCurve->reset ();
curveChanged ();
break;
default:
break;
}
}
}
void CurveEditorGroup::setBatchMode (bool batchMode) {
for (std::vector<CurveEditor*>::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) {
(*i)->curveType->addEntry(argv0+"/images/curveType-unchanged.png", M("GENERAL_UNCHANGED"));
(*i)->curveType->show();
}
}
void CurveEditorGroup::setUnChanged (bool uc, CurveEditor* ce) {
if (uc) {
// the user selected several thumbnails, so we hide the editors and set the curveEditor selection to 'Unchanged'
//ce->typeconn.block(true);
// we hide the editor widgets
hideCurrentCurve();
// the curve type selected option is set to unchanged
ce->curveType->setSelected(Unchanged);
//ce->typeconn.block(false);
}
else {
// we want it to use back the 'CurveEditor::setCurve' memorized in CurveEditor::tempCurve
//ce->typeconn.block(true);
// we switch back the curve type selected option to the one of the used curve
ce->curveType->setSelected(ce->selected);
updateGUI (ce);
//ce->typeconn.block(false);
}
}
void CurveEditorGroup::updateBackgroundHistogram (CurveEditor* ce) {
if (ce==displayedCurve) {
paramCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL);
customCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL);
NURBSCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL);
}
fname = "";
return fname;
}

View File

@@ -24,9 +24,14 @@
#include <string>
#include <guiutils.h>
#include <mycurve.h>
#include <myflatcurve.h>
#include <mydiagonalcurve.h>
#include <shcselector.h>
#include <adjuster.h>
#include <curveeditor.h>
class CurveEditor;
class DiagonalCurveEditorSubGroup;
class FlatCurveEditorSubGroup;
/*
* This class handle the curve widgets, shared between any number curve
@@ -34,75 +39,76 @@
* - to start a new line of curve button, use the 'newLine' method
* - if you add more than one curve, you must add a "CurveEditor* ce" parameter to your listener
*/
class CurveEditorGroup : public Gtk::VBox, public CurveListener, public SHCListener, public AdjusterListener {
class CurveEditorGroup : public Gtk::VBox, public CurveListener {
private:
friend class CurveEditor;
friend class CurveEditorSubGroup;
friend class DiagonalCurveEditorSubGroup;
friend class FlatCurveEditorSubGroup;
protected:
Gtk::Label* curveGroupLabel;
Gtk::Button* curve_reset;
Gtk::HBox* customCurveBox;
Gtk::VBox* paramCurveBox;
Gtk::HBox* NURBSCurveBox;
MyCurve* customCurve;
MyCurve* paramCurve;
MyCurve* NURBSCurve;
SHCSelector* shcSelector;
Adjuster* highlights;
Adjuster* lights;
Adjuster* darks;
Adjuster* shadows;
Gtk::Button* saveCustom;
Gtk::Button* loadCustom;
Gtk::Button* saveNURBS;
Gtk::Button* loadNURBS;
CurveListener* cl;
CurveType curveTypeIx;
unsigned int numberOfPackedCurve;
std::vector<CurveEditor*> curveEditors;
CurveEditor* displayedCurve;
FlatCurveEditorSubGroup* flatSubGroup;
DiagonalCurveEditorSubGroup* diagonalSubGroup;
int activeParamControl;
CurveListener* cl;
ColorProvider* cp;
void curveResetPressed ();
void curveTypeToggled ();
void typeSelectionChanged (CurveEditor* ce, int n);
void curveTypeToggled (CurveEditor* ce);
void savePressed ();
void loadPressed ();
void hideCurrentCurve ();
void setUnChanged (bool uc, CurveEditor* ce);
void storeDisplayedCurve ();
void restoreDisplayedHistogram();
void storeCurveValues (CurveEditor* ce, const std::vector<double>& p);
void typeSelectionChanged (int n);
void switchGUI();
void updateGUI (CurveEditor* ce);
void removeEditor ();
void curveChanged ();
void shcChanged ();
void adjusterChanged (Adjuster* a, double newval);
bool adjusterEntered (GdkEventCrossing* ev, int ac);
bool adjusterLeft (GdkEventCrossing* ev, int ac);
const std::vector<double> getCurveFromGUI (CurveType type);
void updateBackgroundHistogram (CurveEditor* ce);
unsigned int numberOfPackedCurve;
public:
friend class CurveEditor;
CurveEditorGroup(Glib::ustring groupLabel = "");
~CurveEditorGroup();
CurveEditor* addCurve(Glib::ustring curveLabel = "");
void newLine();
void curveListComplete();
void setBatchMode (bool batchMode);
void setCurveExternal (CurveEditor* ce, const std::vector<double>& c);
//void on_realize ();
void setCurveListener (CurveListener* l) { cl = l; }
void setColorProvider (ColorProvider* p) { cp = p; }
CurveEditor* getDisplayedCurve () { return displayedCurve; }
//void on_realize ();
CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel);
protected:
//void curveTypeToggled ();
void curveTypeToggled (CurveEditor* ce);
//void typeSelectionChanged (int n);
void typeSelectionChanged (CurveEditor* ce, int n);
void hideCurrentCurve ();
void updateGUI (CurveEditor* ce);
void curveResetPressed ();
void curveChanged ();
void setUnChanged (bool uc, CurveEditor* ce);
};
class CurveEditorSubGroup {
friend class CurveEditorGroup;
protected:
int valLinear;
int valUnchanged;
CurveEditorGroup *parent;
public:
int getValUnchanged() { return valUnchanged; }
virtual void updateBackgroundHistogram (CurveEditor* ce) {}
virtual void setColorProvider (ColorProvider* p) = 0;
protected:
Glib::ustring outputFile ();
Glib::ustring inputFile ();
virtual bool curveReset (int cType) = 0; // Reset a curve editor, return TRUE if successful (curve changed)
virtual void storeCurveValues (CurveEditor* ce, const std::vector<double>& p) = 0;
virtual void storeDisplayedCurve () = 0;
virtual void restoreDisplayedHistogram() {};
virtual void switchGUI() = 0;
virtual void removeEditor () = 0;
virtual const std::vector<double> getCurveFromGUI (int type) = 0;
};
#endif

View File

@@ -0,0 +1,474 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtkmm.h>
#include <fstream>
#include <string>
#include <guiutils.h>
#include <multilangmgr.h>
#include <guiutils.h>
#include <mycurve.h>
#include <shcselector.h>
#include <adjuster.h>
#include <mycurve.h>
#include <curveeditor.h>
#include <diagonalcurveeditorsubgroup.h>
DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt) {
valLinear = (int)DCT_Linear;
valUnchanged = (int)DCT_Unchanged;
parent = prt;
activeParamControl = -1;
// custom curve
customCurveBox = new Gtk::HBox ();
Gtk::HBox* tmpa = Gtk::manage (new Gtk::HBox ());
customCurve = Gtk::manage (new MyDiagonalCurve ());
//Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
customCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
customCurve->setType (DCT_Spline);
//customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED"));
tmpa->pack_start (*customCurve, true, false, 4);
customCurveBox->pack_start (*tmpa, true, true,4);
Gtk::VBox* custombbox = Gtk::manage (new Gtk::VBox ());
saveCustom = Gtk::manage (new Gtk::Button ());
saveCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)));
loadCustom = Gtk::manage (new Gtk::Button ());
loadCustom->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON)));
custombbox->pack_end (*saveCustom, Gtk::PACK_SHRINK, 4);
custombbox->pack_end (*loadCustom, Gtk::PACK_SHRINK, 4);
customCurveBox->pack_end (*custombbox, Gtk::PACK_SHRINK, 0);
customCurveBox->show_all ();
saveCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) );
loadCustom->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) );
saveCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
loadCustom->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD"));
// NURBS curve
NURBSCurveBox = new Gtk::HBox ();
Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ());
NURBSCurve = Gtk::manage (new MyDiagonalCurve ());
//Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
//af->add (*customCurve);
NURBSCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
NURBSCurve->setType (DCT_NURBS);
//customCurve->set_tooltip_text (M("CURVEEDITOR_TOOLTIPMOVESPEED"));
tmpb->pack_start (*NURBSCurve, true, false, 4);
NURBSCurveBox->pack_start (*tmpb, true, true,4);
Gtk::VBox* NURBSbbox = Gtk::manage (new Gtk::VBox ());
saveNURBS = Gtk::manage (new Gtk::Button ());
saveNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)));
loadNURBS = Gtk::manage (new Gtk::Button ());
loadNURBS->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON)));
NURBSbbox->pack_end (*saveNURBS, Gtk::PACK_SHRINK, 4);
NURBSbbox->pack_end (*loadNURBS, Gtk::PACK_SHRINK, 4);
NURBSCurveBox->pack_end (*NURBSbbox, Gtk::PACK_SHRINK, 0);
NURBSCurveBox->show_all ();
saveNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::savePressed) );
loadNURBS->signal_clicked().connect( sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::loadPressed) );
saveNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
loadNURBS->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD"));
// parametric curve
paramCurveBox = new Gtk::VBox ();
paramCurve = Gtk::manage (new MyDiagonalCurve ());
Gtk::Table* paramctab = Gtk::manage (new Gtk::Table (2,1));
//Gtk::AspectFrame* afp = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
paramCurve->set_size_request (GRAPH_SIZE+2*RADIUS, GRAPH_SIZE+2*RADIUS);
paramCurve->setType (DCT_Parametric);
shcSelector = Gtk::manage (new SHCSelector ());
shcSelector->set_size_request (GRAPH_SIZE, 20);
paramctab->attach (*paramCurve, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 4, 4);
paramctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, RADIUS+4, 0);
Gtk::HBox* tmpc = Gtk::manage (new Gtk::HBox ());
tmpc->pack_start (*paramctab, true, false);
paramCurveBox->pack_start (*tmpc, true, true);
highlights = Gtk::manage (new Adjuster (M("CURVEEDITOR_HIGHLIGHTS"), -100, 100, 1, 0));
lights = Gtk::manage (new Adjuster (M("CURVEEDITOR_LIGHTS"), -100, 100, 1, 0));
darks = Gtk::manage (new Adjuster (M("CURVEEDITOR_DARKS"), -100, 100, 1, 0));
shadows = Gtk::manage (new Adjuster (M("CURVEEDITOR_SHADOWS"), -100, 100, 1, 0));
Gtk::EventBox* evhighlights = Gtk::manage (new Gtk::EventBox ());
Gtk::EventBox* evlights = Gtk::manage (new Gtk::EventBox ());
Gtk::EventBox* evdarks = Gtk::manage (new Gtk::EventBox ());
Gtk::EventBox* evshadows = Gtk::manage (new Gtk::EventBox ());
evhighlights->add (*highlights);
evlights->add (*lights);
evdarks->add (*darks);
evshadows->add (*shadows);
paramCurveBox->pack_start (*Gtk::manage (new Gtk::HSeparator ()));
paramCurveBox->pack_start (*evhighlights);
paramCurveBox->pack_start (*evlights);
paramCurveBox->pack_start (*evdarks);
paramCurveBox->pack_start (*evshadows);
paramCurveBox->show_all ();
customCurveBox->reference ();
paramCurveBox->reference ();
customCurve->setCurveListener (parent); // Send the message directly to the parent
NURBSCurve->setCurveListener (parent);
paramCurve->setCurveListener (parent);
shcSelector->setSHCListener (this);
highlights->setAdjusterListener (this);
lights->setAdjusterListener (this);
darks->setAdjusterListener (this);
shadows->setAdjusterListener (this);
evhighlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evdarks->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evshadows->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK);
evhighlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 4));
evlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 5));
evdarks->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 6));
evshadows->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterEntered), 7));
evhighlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 4));
evlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 5));
evdarks->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 6));
evshadows->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &DiagonalCurveEditorSubGroup::adjusterLeft), 7));
}
DiagonalCurveEditorSubGroup::~DiagonalCurveEditorSubGroup() {
delete customCurveBox;
delete paramCurveBox;
delete NURBSCurveBox;
}
/*
* Add a new curve to the curves list
*/
DiagonalCurveEditor* DiagonalCurveEditorSubGroup::addCurve(Glib::ustring curveLabel) {
DiagonalCurveEditor* newCE = new DiagonalCurveEditor(curveLabel, parent, this);
// Initialization of the new curve
storeCurveValues(newCE, getCurveFromGUI(DCT_Spline));
storeCurveValues(newCE, getCurveFromGUI(DCT_Parametric));
storeCurveValues(newCE, getCurveFromGUI(DCT_NURBS));
// We add it to the curve editor list
parent->curveEditors.push_back(newCE);
return newCE;
}
/*
* Switch the editor widgets to the currently edited curve
*/
void DiagonalCurveEditorSubGroup::switchGUI() {
removeEditor();
DiagonalCurveEditor* dCurve = (DiagonalCurveEditor*)(parent->displayedCurve);
if (dCurve) {
// Initializing GUI values + repacking the appropriated widget
//dCurve->typeconn.block(true);
switch((DiagonalCurveType)(dCurve->curveType->getSelected())) {
case (DCT_Spline):
customCurve->setPoints (dCurve->customCurveEd);
parent->pack_start (*customCurveBox);
break;
case (DCT_Parametric):
paramCurve->setPoints (dCurve->paramCurveEd);
shcSelector->setPositions (
dCurve->paramCurveEd.at(1),
dCurve->paramCurveEd.at(2),
dCurve->paramCurveEd.at(3)
);
highlights->setValue (dCurve->paramCurveEd.at(4));
lights->setValue (dCurve->paramCurveEd.at(5));
darks->setValue (dCurve->paramCurveEd.at(6));
shadows->setValue (dCurve->paramCurveEd.at(7));
parent->pack_start (*paramCurveBox);
break;
case (DCT_NURBS):
NURBSCurve->setPoints (dCurve->NURBSCurveEd);
parent->pack_start (*NURBSCurveBox);
break;
default: // (DCT_Linear, DCT_Unchanged)
// ... do nothing
break;
}
//dCurve->typeconn.block(false);
}
}
void DiagonalCurveEditorSubGroup::savePressed () {
Glib::ustring fname = outputFile();
if (fname.size()) {
std::ofstream f (fname.c_str());
std::vector<double> p;
//std::vector<double> p = customCurve->getPoints ();
switch (parent->displayedCurve->selected) {
case DCT_Spline: // custom
p = customCurve->getPoints ();
break;
case DCT_NURBS: // NURBS
p = NURBSCurve->getPoints ();
break;
default:
break;
}
int ix = 0;
if (p[ix]==(double)(DCT_Linear))
f << "Linear\n";
else if (p[ix]==(double)(DCT_Spline))
f << "Spline\n";
else if (p[ix]==(double)(DCT_NURBS))
f << "NURBS\n";
ix++;
for (unsigned int i=0; i<p.size()/2; i++, ix+=2)
f << p[ix] << ' ' << p[ix+1] << std::endl;
f.close ();
}
}
void DiagonalCurveEditorSubGroup::loadPressed () {
Glib::ustring fname = inputFile();
if (fname.size()) {
std::ifstream f (fname.c_str());
if (f) {
std::vector<double> p;
std::string s;
f >> s;
if (s=="Linear")
p.push_back ((double)(DCT_Linear));
else if (s=="Spline")
p.push_back ((double)(DCT_Spline));
else if (s=="NURBS")
p.push_back ((double)(DCT_NURBS));
else return;
double x;
while (f) {
f >> x;
if (f)
p.push_back (x);
}
if (p[0] == (double)(DCT_Spline)) {
customCurve->setPoints (p);
customCurve->queue_draw ();
customCurve->notifyListener ();
}
else if (p[0] == (double)(DCT_NURBS)) {
NURBSCurve->setPoints (p);
NURBSCurve->queue_draw ();
NURBSCurve->notifyListener ();
}
}
}
}
/*
* Store the curves of the currently displayed type from the widgets to the CurveEditor object
*/
void DiagonalCurveEditorSubGroup::storeDisplayedCurve() {
if (parent->displayedCurve) {
switch (parent->displayedCurve->selected) {
case (DCT_Spline):
storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_Spline));
break;
case (DCT_Parametric):
storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_Parametric));
break;
case (DCT_NURBS):
storeCurveValues(parent->displayedCurve, getCurveFromGUI(DCT_NURBS));
break;
default:
break;
}
}
}
/*
* Restore the histogram to all types from the CurveEditor object to the widgets
*/
void DiagonalCurveEditorSubGroup::restoreDisplayedHistogram() {
if (parent->displayedCurve) {
paramCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL);
customCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL);
NURBSCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL);
}
}
void DiagonalCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector<double>& p) {
if (p.size()) {
DiagonalCurveType t = (DiagonalCurveType)p[0];
for (int i=0; i<(int)p.size(); i++)
switch (t) {
case (DCT_Spline):
((DiagonalCurveEditor*)ce)->customCurveEd = p;
break;
case (DCT_Parametric):
((DiagonalCurveEditor*)ce)->paramCurveEd = p;
break;
case (DCT_NURBS):
((DiagonalCurveEditor*)ce)->NURBSCurveEd = p;
break;
default:
break;
}
}
}
/*
* Called to update the parametric curve graph with new slider values
*/
const std::vector<double> DiagonalCurveEditorSubGroup::getCurveFromGUI (int type) {
switch ((DiagonalCurveType)type) {
case (DCT_Parametric): {
std::vector<double> lcurve (8);
lcurve[0] = (double)(DCT_Parametric);
shcSelector->getPositions (lcurve[1], lcurve[2], lcurve[3]);
lcurve[4] = highlights->getValue ();
lcurve[5] = lights->getValue ();
lcurve[6] = darks->getValue ();
lcurve[7] = shadows->getValue ();
return lcurve;
}
case (DCT_Spline):
return customCurve->getPoints ();
case (DCT_NURBS):
return NURBSCurve->getPoints ();
default: {
// linear and other solutions
std::vector<double> lcurve (1);
lcurve[0] = (double)(DCT_Linear);
return lcurve;
}
}
}
/*
* Unlink the tree editor widgets from their parent box to hide them
*/
void DiagonalCurveEditorSubGroup::removeEditor () {
removeIfThere (parent, customCurveBox, false);
removeIfThere (parent, paramCurveBox, false);
removeIfThere (parent, NURBSCurveBox, false);
}
bool DiagonalCurveEditorSubGroup::curveReset(int cType) {
switch ((DiagonalCurveType) cType) {
case (DCT_NURBS) : // = Control cage
NURBSCurve->reset ();
return true;
break;
case (DCT_Spline) : // = Custom
customCurve->reset ();
return true;
break;
case (DCT_Parametric) :
highlights->resetPressed();
lights->resetPressed();
darks->resetPressed();
shadows->resetPressed();
shcSelector->reset();
paramCurve->reset ();
return true;
break;
default:
return false;
break;
}
}
void DiagonalCurveEditorSubGroup::setColorProvider (ColorProvider* p) {
customCurve->setColorProvider(p);
paramCurve->setColorProvider(p);
NURBSCurve->setColorProvider(p);
}
/*
* Listener
*/
void DiagonalCurveEditorSubGroup::shcChanged () {
paramCurve->setPoints (getCurveFromGUI(DCT_Parametric));
storeDisplayedCurve();
parent->curveChanged ();
}
/*
* Listener
*/
void DiagonalCurveEditorSubGroup::adjusterChanged (Adjuster* a, double newval) {
paramCurve->setPoints (getCurveFromGUI(DCT_Parametric));
storeDisplayedCurve();
parent->curveChanged ();
}
/*
* Listener called when the mouse is over a parametric curve's slider
*/
bool DiagonalCurveEditorSubGroup::adjusterEntered (GdkEventCrossing* ev, int ac) {
if (ev->detail != GDK_NOTIFY_INFERIOR) {
activeParamControl = ac;
paramCurve->setActiveParam (activeParamControl);
}
return true;
}
/*
* Listener called when the mouse left the parametric curve's slider
*/
bool DiagonalCurveEditorSubGroup::adjusterLeft (GdkEventCrossing* ev, int ac) {
if (ev->detail != GDK_NOTIFY_INFERIOR) {
activeParamControl = -1;
paramCurve->setActiveParam (activeParamControl);
}
return true;
}
void DiagonalCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) {
if (ce==parent->displayedCurve) {
paramCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL);
customCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL);
NURBSCurve->updateBackgroundHistogram (ce->bgHistValid ? ce->histogram : NULL);
}
}

View File

@@ -0,0 +1,77 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DIAGONALCURVEEDITORSUBGROUP_
#define _DIAGONALCURVEEDITORSUBGROUP_
#include <gtkmm.h>
#include <curveeditorgroup.h>
class DiagonalCurveEditor;
class DiagonalCurveEditorSubGroup : public CurveEditorSubGroup, public SHCListener, public AdjusterListener {
friend class DiagonalCurveEditor;
private:
Gtk::HBox* customCurveBox;
Gtk::VBox* paramCurveBox;
Gtk::HBox* NURBSCurveBox;
MyDiagonalCurve* customCurve;
MyDiagonalCurve* paramCurve;
MyDiagonalCurve* NURBSCurve;
SHCSelector* shcSelector;
Adjuster* highlights;
Adjuster* lights;
Adjuster* darks;
Adjuster* shadows;
Gtk::Button* saveCustom;
Gtk::Button* loadCustom;
Gtk::Button* saveNURBS;
Gtk::Button* loadNURBS;
int activeParamControl;
public:
DiagonalCurveEditorSubGroup(CurveEditorGroup* prt);
~DiagonalCurveEditorSubGroup();
DiagonalCurveEditor* addCurve(Glib::ustring curveLabel = "");
virtual void updateBackgroundHistogram (CurveEditor* ce);
virtual void setColorProvider (ColorProvider* p);
private:
void storeCurveValues (CurveEditor* ce, const std::vector<double>& p);
void storeDisplayedCurve ();
void restoreDisplayedHistogram ();
void savePressed ();
void loadPressed ();
void switchGUI();
bool curveReset (int cType);
void removeEditor ();
const std::vector<double> getCurveFromGUI (int type);
void shcChanged ();
void adjusterChanged (Adjuster* a, double newval);
bool adjusterEntered (GdkEventCrossing* ev, int ac);
bool adjusterLeft (GdkEventCrossing* ev, int ac);
};
#endif

View File

@@ -0,0 +1,272 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtkmm.h>
#include <fstream>
#include <string>
#include <guiutils.h>
#include <multilangmgr.h>
#include <guiutils.h>
#include <mycurve.h>
#include <shcselector.h>
#include <adjuster.h>
#include <mycurve.h>
#include <curveeditor.h>
#include <flatcurveeditorsubgroup.h>
FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt) {
valLinear = (int)FCT_Linear;
valUnchanged = (int)FCT_Unchanged;
parent = prt;
// ControlPoints curve
CPointsCurveBox = new Gtk::HBox ();
//Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ());
CPointsCurve = Gtk::manage (new MyFlatCurve ());
//Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false));
//CPointsCurve->set_size_request (GRAPH_SIZE+2*RADIUS+1, GRAPH_SIZE+2*RADIUS+1);
CPointsCurve->setType (FCT_MinMaxCPoints);
//tmpb->pack_start (*CPointsCurve, Gtk::PACK_EXPAND_WIDGET, 4);
CPointsCurveBox->pack_start (*CPointsCurve, Gtk::PACK_EXPAND_WIDGET,4);
//CPointsCurveBox->pack_start (*tmpb, Gtk::PACK_EXPAND_WIDGET,4);
Gtk::VBox* CPointsbbox = Gtk::manage (new Gtk::VBox ());
saveCPoints = Gtk::manage (new Gtk::Button ());
saveCPoints->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)));
loadCPoints = Gtk::manage (new Gtk::Button ());
loadCPoints->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON)));
CPointsbbox->pack_end (*saveCPoints, Gtk::PACK_SHRINK, 4);
CPointsbbox->pack_end (*loadCPoints, Gtk::PACK_SHRINK, 4);
CPointsCurveBox->pack_end (*CPointsbbox, Gtk::PACK_SHRINK, 0);
CPointsCurveBox->show_all ();
saveCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::savePressed) );
loadCPoints->signal_clicked().connect( sigc::mem_fun(*this, &FlatCurveEditorSubGroup::loadPressed) );
saveCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE"));
loadCPoints->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD"));
CPointsCurve->setCurveListener (parent); // Send the message directly to the parent
}
FlatCurveEditorSubGroup::~FlatCurveEditorSubGroup() {
delete CPointsCurveBox;
}
/*
* Add a new curve to the curves list
*/
FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel) {
FlatCurveEditor* newCE = new FlatCurveEditor(curveLabel, parent, this);
// Initialization of the new curve
storeCurveValues(newCE, getCurveFromGUI(FCT_MinMaxCPoints));
// We add it to the curve editor list
parent->curveEditors.push_back(newCE);
return newCE;
}
/*
* Switch the editor widgets to the currently edited curve
*/
void FlatCurveEditorSubGroup::switchGUI() {
removeEditor();
FlatCurveEditor* dCurve = (FlatCurveEditor*)(parent->displayedCurve);
if (dCurve) {
// Initializing GUI values + repacking the appropriated widget
//dCurve->typeconn.block(true);
switch((FlatCurveType)(dCurve->curveType->getSelected())) {
case (FCT_MinMaxCPoints):
CPointsCurve->setPoints (dCurve->controlPointsCurveEd);
parent->pack_start (*CPointsCurveBox);
break;
default: // (DCT_Linear, DCT_Unchanged)
// ... do nothing
break;
}
//dCurve->typeconn.block(false);
}
}
void FlatCurveEditorSubGroup::savePressed () {
Glib::ustring fname = outputFile();
if (fname.size()) {
std::ofstream f (fname.c_str());
std::vector<double> p;
//std::vector<double> p = customCurve->getPoints ();
switch (parent->displayedCurve->selected) {
case FCT_MinMaxCPoints: // Control points
p = CPointsCurve->getPoints ();
break;
default:
break;
}
int ix = 0;
if (p[ix]==(double)(FCT_Linear))
f << "Linear\n";
else if (p[ix]==(double)(FCT_MinMaxCPoints))
f << "ControlPoints\n";
ix++;
for (unsigned int i=0; i<p.size()/2; i++, ix+=2)
f << p[ix] << ' ' << p[ix+1] << std::endl;
f.close ();
}
}
void FlatCurveEditorSubGroup::loadPressed () {
Glib::ustring fname = inputFile();
if (fname.size()) {
std::ifstream f (fname.c_str());
if (f) {
std::vector<double> p;
std::string s;
f >> s;
if (s=="Linear")
p.push_back ((double)(FCT_Linear));
else if (s=="ControlPoints")
p.push_back ((double)(FCT_MinMaxCPoints));
else return;
double x;
while (f) {
f >> x;
if (f)
p.push_back (x);
}
if (p[0] == (double)(FCT_MinMaxCPoints)) {
CPointsCurve->setPoints (p);
CPointsCurve->queue_draw ();
CPointsCurve->notifyListener ();
}
}
}
}
/*
* Store the curves of the currently displayed type from the widgets to the CurveEditor object
*/
void FlatCurveEditorSubGroup::storeDisplayedCurve() {
if (parent->displayedCurve) {
switch (parent->displayedCurve->selected) {
/*case (FCT_Parametric):
storeCurveValues(parent->displayedCurve, getCurveFromGUI(FCT_Parametric));
break;*/
case (FCT_MinMaxCPoints):
storeCurveValues(parent->displayedCurve, getCurveFromGUI(FCT_MinMaxCPoints));
break;
default:
break;
}
}
}
/*
* Restore the histogram to all types from the CurveEditor object to the widgets
*/
void FlatCurveEditorSubGroup::restoreDisplayedHistogram() {
if (parent->displayedCurve) {
//paramCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL);
CPointsCurve->updateBackgroundHistogram (parent->displayedCurve->bgHistValid ? parent->displayedCurve->histogram : NULL);
}
}
void FlatCurveEditorSubGroup::storeCurveValues (CurveEditor* ce, const std::vector<double>& p) {
if (p.size()) {
FlatCurveType t = (FlatCurveType)p[0];
for (int i=0; i<(int)p.size(); i++)
switch (t) {
case (FCT_MinMaxCPoints):
((FlatCurveEditor*)ce)->controlPointsCurveEd = p;
break;
default:
break;
}
}
}
/*
* Called to update the parametric curve graph with new slider values
*/
const std::vector<double> FlatCurveEditorSubGroup::getCurveFromGUI (int type) {
switch ((FlatCurveType)type) {
case (FCT_MinMaxCPoints):
return CPointsCurve->getPoints ();
default: {
// linear and other solutions
std::vector<double> lcurve (1);
lcurve[0] = (double)(FCT_Linear);
return lcurve;
}
}
}
/*
* Unlink the tree editor widgets from their parent box to hide them
*/
void FlatCurveEditorSubGroup::removeEditor () {
removeIfThere (parent, CPointsCurveBox, false);
}
bool FlatCurveEditorSubGroup::curveReset(int cType) {
switch ((FlatCurveType) cType) {
case (FCT_MinMaxCPoints) : // = Control cage
CPointsCurve->reset ();
return true;
break;
/*case (FCT_Parametric) :
highlights->resetPressed();
lights->resetPressed();
darks->resetPressed();
shadows->resetPressed();
shcSelector->reset();
paramCurve->reset ();
return true;
break;*/
default:
return false;
break;
}
}
void FlatCurveEditorSubGroup::setColorProvider (ColorProvider* p) {
CPointsCurve->setColorProvider(p);
}
/*void FlatCurveEditorSubGroup::updateBackgroundHistogram (CurveEditor* ce) {
CurveEditor* fce = (CurveEditor*)ce;
if (fce==displayedCurve) {
paramCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL);
customCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL);
NURBSCurve->updateBackgroundHistogram (fce->bgHistValid ? fce->histogram : NULL);
}
}*/

View File

@@ -0,0 +1,59 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _FLATCURVEEDITORSUBGROUP_
#define _FLATCURVEEDITORSUBGROUP_
#include <gtkmm.h>
#include <curveeditorgroup.h>
class FlatCurveEditor;
class FlatCurveEditorSubGroup: public CurveEditorSubGroup {
friend class FlatCurveEditor;
private:
Gtk::HBox* CPointsCurveBox;
MyFlatCurve* CPointsCurve;
Gtk::Button* saveCPoints;
Gtk::Button* loadCPoints;
public:
FlatCurveEditorSubGroup(CurveEditorGroup* prt);
~FlatCurveEditorSubGroup();
FlatCurveEditor* addCurve(Glib::ustring curveLabel = "");
//virtual void updateBackgroundHistogram (CurveEditor* ce);
virtual void setColorProvider (ColorProvider* p);
private:
void storeCurveValues (CurveEditor* ce, const std::vector<double>& p);
void storeDisplayedCurve ();
void restoreDisplayedHistogram ();
void savePressed ();
void loadPressed ();
void switchGUI();
bool curveReset (int cType);
void removeEditor ();
const std::vector<double> getCurveFromGUI (int type);
};
#endif

View File

@@ -18,6 +18,7 @@
*/
#include <hsvequalizer.h>
#include <utils.h>
using namespace rtengine;
using namespace rtengine::procparams;
@@ -26,196 +27,61 @@ using namespace rtengine::procparams;
HSVEqualizer::HSVEqualizer () : Gtk::VBox(), FoldableToolPanel(this) {
enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED")));
enabled->set_active (true);
pack_start(*enabled);
enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &HSVEqualizer::enabledToggled) );
Gtk::HSeparator *hsvsepa = Gtk::manage (new Gtk::HSeparator());
pack_start(*hsvsepa, Gtk::PACK_SHRINK, 2);
hsvsepa->show ();
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ());
hb->set_border_width (4);
hb->show ();
Gtk::Label* hsvselect = Gtk::manage (new Gtk::Label (M("TP_HSVEQUALIZER_CHANNEL")+":"));
hsvselect->show ();
hsvchannel = Gtk::manage (new Gtk::ComboBoxText ());
hsvchannel->append_text (M("TP_HSVEQUALIZER_SAT"));
hsvchannel->append_text (M("TP_HSVEQUALIZER_VAL"));
hsvchannel->append_text (M("TP_HSVEQUALIZER_HUE"));
hsvchannel->show ();
hb->pack_start(*hsvselect, Gtk::PACK_SHRINK, 4);
hb->pack_start(*hsvchannel);
Gtk::Button * neutralButton = Gtk::manage (new Gtk::Button(M("TP_HSVEQUALIZER_NEUTRAL")));
hb->pack_start(*neutralButton, Gtk::PACK_SHRINK, 2);
neutralPressedConn = neutralButton->signal_pressed().connect( sigc::mem_fun(*this, &HSVEqualizer::neutralPressed));
pack_start (*hb);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
Gtk::HBox * buttonBox17 = Gtk::manage (new Gtk::HBox());
pack_start(*buttonBox17, Gtk::PACK_SHRINK, 2);
Gtk::Button * neutralButton = Gtk::manage (new Gtk::Button(M("TP_HSVEQUALIZER_NEUTRAL")));
buttonBox17->pack_start(*neutralButton, Gtk::PACK_SHRINK, 2);
neutralPressedConn = neutralButton->signal_pressed().connect( sigc::mem_fun(*this, &HSVEqualizer::neutralPressed));
buttonBox17->show();
*/
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Gtk::HSeparator *hsvsepb = Gtk::manage (new Gtk::HSeparator());
pack_start(*hsvsepb, Gtk::PACK_SHRINK, 2);
hsvsepb->show ();
satbox = new Gtk::VBox ();
sat[0] = new Adjuster (M("TP_HSVEQUALIZER1"), -100, 100, 1, 0);
sat[1] = new Adjuster (M("TP_HSVEQUALIZER2"), -100, 100, 1, 0);
sat[2] = new Adjuster (M("TP_HSVEQUALIZER3"), -100, 100, 1, 0);
sat[3] = new Adjuster (M("TP_HSVEQUALIZER4"), -100, 100, 1, 0);
sat[4] = new Adjuster (M("TP_HSVEQUALIZER5"), -100, 100, 1, 0);
sat[5] = new Adjuster (M("TP_HSVEQUALIZER6"), -100, 100, 1, 0);
sat[6] = new Adjuster (M("TP_HSVEQUALIZER7"), -100, 100, 1, 0);
sat[7] = new Adjuster (M("TP_HSVEQUALIZER8"), -100, 100, 1, 0);
for(int i = 0; i < 8; i++)
{
sat[i]->setAdjusterListener(this);
satbox->pack_start(*sat[i]);
}
//show_all_children ();
satbox->show ();
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%
valbox = new Gtk::VBox ();
val[0] = new Adjuster (M("TP_HSVEQUALIZER1"), -100, 100, 1, 0);
val[1] = new Adjuster (M("TP_HSVEQUALIZER2"), -100, 100, 1, 0);
val[2] = new Adjuster (M("TP_HSVEQUALIZER3"), -100, 100, 1, 0);
val[3] = new Adjuster (M("TP_HSVEQUALIZER4"), -100, 100, 1, 0);
val[4] = new Adjuster (M("TP_HSVEQUALIZER5"), -100, 100, 1, 0);
val[5] = new Adjuster (M("TP_HSVEQUALIZER6"), -100, 100, 1, 0);
val[6] = new Adjuster (M("TP_HSVEQUALIZER7"), -100, 100, 1, 0);
val[7] = new Adjuster (M("TP_HSVEQUALIZER8"), -100, 100, 1, 0);
for(int i = 0; i < 8; i++)
{
val[i]->setAdjusterListener(this);
valbox->pack_start(*val[i]);
}
//show_all_children ();
valbox->show ();
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%
huebox = new Gtk::VBox ();
hue[0] = new Adjuster (M("TP_HSVEQUALIZER1"), -100, 100, 1, 0);
hue[1] = new Adjuster (M("TP_HSVEQUALIZER2"), -100, 100, 1, 0);
hue[2] = new Adjuster (M("TP_HSVEQUALIZER3"), -100, 100, 1, 0);
hue[3] = new Adjuster (M("TP_HSVEQUALIZER4"), -100, 100, 1, 0);
hue[4] = new Adjuster (M("TP_HSVEQUALIZER5"), -100, 100, 1, 0);
hue[5] = new Adjuster (M("TP_HSVEQUALIZER6"), -100, 100, 1, 0);
hue[6] = new Adjuster (M("TP_HSVEQUALIZER7"), -100, 100, 1, 0);
hue[7] = new Adjuster (M("TP_HSVEQUALIZER8"), -100, 100, 1, 0);
for(int i = 0; i < 8; i++)
{
hue[i]->setAdjusterListener(this);
huebox->pack_start(*hue[i]);
}
//huebox->show_all_children ();
huebox->show ();
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%
huebox->reference ();
valbox->reference ();
satbox->reference ();
//enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &HSVEqualizer::enabled_toggled) );
hsvchannel->signal_changed().connect( sigc::mem_fun(*this, &HSVEqualizer::hsvchannelChanged) );
curveEditorG = new CurveEditorGroup (M("TP_HSVEQUALIZER_CHANNEL"));
curveEditorG->setCurveListener (this);
curveEditorG->setColorProvider (this);
hshape = (FlatCurveEditor*)curveEditorG->addCurve(CT_Flat, M("TP_HSVEQUALIZER_HUE"));
sshape = (FlatCurveEditor*)curveEditorG->addCurve(CT_Flat, M("TP_HSVEQUALIZER_SAT"));
vshape = (FlatCurveEditor*)curveEditorG->addCurve(CT_Flat, M("TP_HSVEQUALIZER_VAL"));
// This will add the reset button at the end of the curveType buttons
curveEditorG->curveListComplete();
pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4);
//curveEditorG->show();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
HSVEqualizer::~HSVEqualizer () {
for (int i=0;i<8;i++)
{
delete hue[i];
delete val[i];
delete sat[i];
}
delete curveEditorG;
}
void HSVEqualizer::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
if (pedited) {
for (int i=0; i<8; i++) {
sat[i]->setEditedState (pedited->hsvequalizer.sat[i] ? Edited : UnEdited);
val[i]->setEditedState (pedited->hsvequalizer.val[i] ? Edited : UnEdited);
hue[i]->setEditedState (pedited->hsvequalizer.hue[i] ? Edited : UnEdited);
}
enabled->set_inconsistent (!pedited->hsvequalizer.enabled);
hshape->setUnChanged (!pedited->hsvequalizer.hcurve);
sshape->setUnChanged (!pedited->hsvequalizer.scurve);
vshape->setUnChanged (!pedited->hsvequalizer.vcurve);
}
enaConn.block (true);
enabled->set_active (pp->hsvequalizer.enabled);
enaConn.block (false);
lastEnabled = pp->hsvequalizer.enabled;
for (int i=0; i<8; i++) {
sat[i]->setValue (pp->hsvequalizer.sat[i]);
val[i]->setValue (pp->hsvequalizer.val[i]);
hue[i]->setValue (pp->hsvequalizer.hue[i]);
}
if (pedited && !pedited->hsvequalizer.hsvchannel)
hsvchannel->set_active (3);
else if (pp->hsvequalizer.hsvchannel=="sat")
hsvchannel->set_active (0);
else if (pp->hsvequalizer.hsvchannel=="val")
hsvchannel->set_active (1);
else if (pp->hsvequalizer.hsvchannel=="hue")
hsvchannel->set_active (2);
hshape->setCurve (pp->hsvequalizer.hcurve);
sshape->setCurve (pp->hsvequalizer.scurve);
vshape->setCurve (pp->hsvequalizer.vcurve);
enableListener ();
}
void HSVEqualizer::write (ProcParams* pp, ParamsEdited* pedited) {
pp->hsvequalizer.enabled = enabled->get_active ();
for (int i=0; i<8; i++) {
pp->hsvequalizer.sat[i] = sat[i]->getValue();
pp->hsvequalizer.val[i] = val[i]->getValue();
pp->hsvequalizer.hue[i] = hue[i]->getValue();
}
if (hsvchannel->get_active_row_number()==0)
pp->hsvequalizer.hsvchannel = "sat";
else if (hsvchannel->get_active_row_number()==1)
pp->hsvequalizer.hsvchannel = "val";
else if (hsvchannel->get_active_row_number()==2)
pp->hsvequalizer.hsvchannel = "hue";
pp->hsvequalizer.hcurve = hshape->getCurve ();
pp->hsvequalizer.scurve = sshape->getCurve ();
pp->hsvequalizer.vcurve = vshape->getCurve ();
if (pedited) {
pedited->hsvequalizer.enabled = !enabled->get_inconsistent();//from dirpyreq
for (int i=0; i<8; i++) {
pedited->hsvequalizer.sat[i] = sat[i]->getEditedState ();
pedited->hsvequalizer.val[i] = val[i]->getEditedState ();
pedited->hsvequalizer.hue[i] = hue[i]->getEditedState ();
}
pedited->hsvequalizer.hcurve = !hshape->isUnChanged ();
pedited->hsvequalizer.scurve = !sshape->isUnChanged ();
pedited->hsvequalizer.vcurve = !vshape->isUnChanged ();
}
}
/*
void HSVEqualizer::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
for (int i = 0; i < 8; i++) {
@@ -239,7 +105,27 @@ void HSVEqualizer::setDefaults (const ProcParams* defParams, const ParamsEdited*
}
}
}
*/
/*
* Curve listener
*
* If more than one curve has been added, the curve listener is automatically
* set to 'multi=true', and send a pointer of the modified curve in a parameter
*/
void HSVEqualizer::curveChanged (CurveEditor* ce) {
if (listener) {
if (ce == hshape)
listener->panelChanged (EvHSVEqualizerH, M("HISTORY_CUSTOMCURVE"));
if (ce == sshape)
listener->panelChanged (EvHSVEqualizerS, M("HISTORY_CUSTOMCURVE"));
if (ce == vshape)
listener->panelChanged (EvHSVEqualizerV, M("HISTORY_CUSTOMCURVE"));
}
}
/*
void HSVEqualizer::adjusterChanged (Adjuster* a, double newval) {
if (listener && enabled->get_active()) {
@@ -289,75 +175,47 @@ void HSVEqualizer::adjusterChanged (Adjuster* a, double newval) {
//listener->panelChanged (EvHSVEqualizer, ss.str());
}
}
*/
void HSVEqualizer::enabledToggled () {
if (batchMode) {
if (enabled->get_inconsistent()) {
enabled->set_inconsistent (false);
enaConn.block (true);
enabled->set_active (false);
enaConn.block (false);
}
else if (lastEnabled)
enabled->set_inconsistent (true);
lastEnabled = enabled->get_active ();
void HSVEqualizer::colorForValue (double valX, double valY) {
float r, g, b;
CurveEditor* ce = curveEditorG->getDisplayedCurve();
if (ce == hshape) { // Hue = f(Hue)
float h = (float)((valY - 0.5) * 2. + valX);
if (h > 1.0)
h -= 1.0;
else if (h < 0.0)
h += 1.0;
hsv2rgb(h, (float)0.5, (float)0.5, r, g, b);
red = (double)r;
green = (double)g;
blue = (double)b;
}
if (listener) {
if (enabled->get_active ())
listener->panelChanged (EvHSVEqEnabled, M("GENERAL_ENABLED"));
else
listener->panelChanged (EvHSVEqEnabled, M("GENERAL_DISABLED"));
else if (ce == sshape) { // Saturation = f(Hue)
hsv2rgb((float)valX, (float)valY, (float)0.5, r, g, b);
red = (double)r;
green = (double)g;
blue = (double)b;
}
else if (ce == vshape) { // Value = f(Hue)
hsv2rgb((float)valX, (float)0.5, (float)valY, r, g, b);
red = (double)r;
green = (double)g;
blue = (double)b;
}
else {
printf("Error: no curve displayed!\n");
}
}
void HSVEqualizer::hsvchannelChanged () {
removeIfThere (this, satbox, false);
removeIfThere (this, valbox, false);
removeIfThere (this, huebox, false);
if (hsvchannel->get_active_row_number()==0)
pack_start (*satbox);
else if (hsvchannel->get_active_row_number()==1)
pack_start (*valbox);
else if (hsvchannel->get_active_row_number()==2)
pack_start (*huebox);
}
void HSVEqualizer::setBatchMode (bool batchMode) {
ToolPanel::setBatchMode (batchMode);
for (int i = 0; i < 8; i++) {
sat[i]->showEditedCB();
val[i]->showEditedCB();
hue[i]->showEditedCB();
}
hsvchannel->append_text (M("GENERAL_UNCHANGED"));
}
ToolPanel::setBatchMode (batchMode);
void HSVEqualizer::neutralPressed () {
if (hsvchannel->get_active_row_number()==0)
for (int i = 0; i < 8; i++) {
sat[i]->setValue(0);
adjusterChanged(sat[i], 0);
}
else if (hsvchannel->get_active_row_number()==1)
for (int i = 0; i < 8; i++) {
val[i]->setValue(0);
adjusterChanged(val[i], 0);
}
else if (hsvchannel->get_active_row_number()==2)
for (int i = 0; i < 8; i++) {
hue[i]->setValue(0);
adjusterChanged(hue[i], 0);
}
curveEditorG->setBatchMode (batchMode);
}

View File

@@ -24,28 +24,23 @@
#include <adjuster.h>
#include <toolpanel.h>
#include <guiutils.h>
#include <curveeditor.h>
#include <curveeditorgroup.h>
#include <colorprovider.h>
class HSVEqualizer : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel
class HSVEqualizer : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel, public CurveListener, public ColorProvider
{
protected:
Gtk::CheckButton * enabled;
Gtk::ComboBoxText* hsvchannel;
Gtk::VBox* satbox;
Gtk::VBox* valbox;
Gtk::VBox* huebox;
Adjuster* sat[8];
Adjuster* val[8];
Adjuster* hue[8];
sigc::connection enaConn;
sigc::connection neutralPressedConn;
bool lastEnabled;
CurveEditorGroup* curveEditorG;
FlatCurveEditor* hshape;
FlatCurveEditor* sshape;
FlatCurveEditor* vshape;
public:
@@ -54,15 +49,12 @@ public:
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void curveChanged (CurveEditor* ce);
//void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
virtual void colorForValue (double valX, double valY);
void adjusterChanged (Adjuster* a, double newval);
void enabledToggled ();
void hsvchannelChanged ();
void neutralPressed ();
//void adjusterChanged (Adjuster* a, double newval);
};
#endif

View File

@@ -69,10 +69,11 @@ LCurve::LCurve () : Gtk::VBox(), FoldableToolPanel(this), brAdd(false), contrAdd
curveEditorG = new CurveEditorGroup ();
curveEditorG->setCurveListener (this);
curveEditorG->setColorProvider (this);
lshape = curveEditorG->addCurve("L");
ashape = curveEditorG->addCurve("a");
bshape = curveEditorG->addCurve("b");
lshape = (DiagonalCurveEditor*)curveEditorG->addCurve(CT_Diagonal, "L");
ashape = (DiagonalCurveEditor*)curveEditorG->addCurve(CT_Diagonal, "a");
bshape = (DiagonalCurveEditor*)curveEditorG->addCurve(CT_Diagonal, "b");
// This will add the reset button at the end of the curveType buttons
curveEditorG->curveListComplete();
@@ -305,6 +306,32 @@ void LCurve::adjusterChanged (Adjuster* a, double newval) {
}*/
void LCurve::colorForValue (double valX, double valY) {
CurveEditor* ce = curveEditorG->getDisplayedCurve();
if (ce == lshape) { // L = f(L)
red = (double)valY;
green = (double)valY;
blue = (double)valY;
}
else if (ce == ashape) { // a = f(a)
// TODO: To be implemented
red = (double)valY;
green = (double)valY;
blue = (double)valY;
}
else if (ce == bshape) { // b = f(b)
red = (double)valY;
green = (double)valY;
blue = (double)valY;
}
else {
printf("Error: no curve displayed!\n");
}
}
void LCurve::setBatchMode (bool batchMode) {
ToolPanel::setBatchMode (batchMode);

View File

@@ -23,9 +23,10 @@
#include <adjuster.h>
#include <toolpanel.h>
#include <curveeditor.h>
#include <mycurve.h>
#include <curveeditorgroup.h>
#include <colorprovider.h>
class LCurve : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel, public CurveListener {
class LCurve : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel, public CurveListener, public ColorProvider {
protected:
Gtk::ComboBoxText* channel;
@@ -34,9 +35,9 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public FoldableToolPan
Adjuster* brightness;
Adjuster* contrast;
Adjuster* saturation;
CurveEditor* lshape;
CurveEditor* ashape;
CurveEditor* bshape;
DiagonalCurveEditor* lshape;
DiagonalCurveEditor* ashape;
DiagonalCurveEditor* bshape;
//%%%%%%%%%%%%%%%%
Gtk::CheckButton* avoidclip;
@@ -65,6 +66,8 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public FoldableToolPan
void avoidclip_toggled ();
void enablelimiter_toggled ();
void updateCurveBackgroundHistogram (unsigned* hist);
virtual void colorForValue (double valX, double valY);
};
#endif

View File

@@ -40,7 +40,7 @@ LCurve::LCurve () : Gtk::VBox(), FoldableToolPanel(this), brAdd(false), contrAdd
hsep3->show ();
pack_start (*hsep3);
shape = Gtk::manage (new CurveEditor ());
shape = Gtk::manage (new DiagonalCurveEditor ());
shape->show ();
shape->setCurveListener (this);

View File

@@ -23,6 +23,7 @@
#include <adjuster.h>
#include <toolpanel.h>
#include <curveeditor.h>
#include <curveeditorgroup.h>
#include <mycurve.h>
class LCurve : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel, public CurveListener {
@@ -30,7 +31,7 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public FoldableToolPan
protected:
Adjuster* brightness;
Adjuster* contrast;
CurveEditor* shape;
DiagonalCurveEditor* shape;
bool brAdd, contrAdd;
public:

View File

@@ -1,695 +1,56 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mycurve.h>
#include <curves.h>
#include <string.h>
#include <gdkmm/types.h>
MyCurve::MyCurve () : listener(NULL), activeParam(-1), bghistvalid(false) {
cursor_type = CSArrow;
curve.type = Spline;
innerWidth = get_allocation().get_width() - RADIUS * 2;
innerHeight = get_allocation().get_height() - RADIUS * 2;
prevInnerHeight = innerHeight;
grab_point = -1;
lit_point = -1;
buttonPressed = false;
bghist = new unsigned int[256];
set_extension_events(Gdk::EXTENSION_EVENTS_ALL);
add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK);
signal_event().connect( sigc::mem_fun(*this, &MyCurve::handleEvents) );
curve.x.push_back(0.);
curve.y.push_back(0.);
curve.x.push_back(1.);
curve.y.push_back(1.);
curve.type = Spline;
mcih = new MyCurveIdleHelper;
mcih->myCurve = this;
mcih->destroyed = false;
mcih->pending = 0;
}
MyCurve::~MyCurve () {
if (mcih->pending)
mcih->destroyed = true;
else
delete mcih;
delete [] bghist;
}
std::vector<double> MyCurve::get_vector (int veclen) {
std::vector<double> vector;
vector.resize (veclen);
if (curve.type != Parametric) {
// count active points:
double prev =- 1.0;
int active = 0;
int firstact = -1;
for (int i = 0; i < (int)curve.x.size(); ++i)
if (curve.x[i] > prev) {
if (firstact < 0)
firstact = i;
prev = curve.x[i];
++active;
}
// handle degenerate case:
if (active < 2) {
double ry;
if (active > 0)
ry = curve.y[firstact];
else
ry = 0.0;
if (ry < 0.0) ry = 0.0;
if (ry > 1.0) ry = 1.0;
for (int x = 0; x < veclen; ++x)
vector[x] = ry;
return vector;
}
}
// calculate remaining points
std::vector<double> curveDescr = getPoints ();
rtengine::Curve* rtcurve = new rtengine::Curve (curveDescr, veclen*1.5);
std::vector<double> t;
t.resize (veclen);
for (int i = 0; i < veclen; i++)
t[i] = (double) i / (veclen - 1.0);
rtcurve->getVal (t, vector);
delete rtcurve;
return vector;
}
void MyCurve::interpolate () {
prevInnerHeight = innerHeight;
point.resize (innerWidth);
std::vector<double> vector = get_vector (innerWidth);
prevInnerHeight = innerHeight;
for (int i = 0; i < innerWidth; ++i)
point[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
upoint.clear ();
lpoint.clear ();
if (curve.type==Parametric && activeParam>0) {
double tmp = curve.x[activeParam-1];
if (activeParam>=4) {
upoint.resize(innerWidth);
lpoint.resize(innerWidth);
curve.x[activeParam-1] = 100;
vector = get_vector (innerWidth);
for (int i = 0; i < innerWidth; ++i)
upoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
curve.x[activeParam-1] = -100;
vector = get_vector (innerWidth);
for (int i = 0; i < innerWidth; ++i)
lpoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
curve.x[activeParam-1] = tmp;
}
}
}
void MyCurve::draw (int handle) {
if (!pixmap)
return;
// re-calculate curve if dimensions changed
if (prevInnerHeight != innerHeight || (int)point.size() != innerWidth)
interpolate ();
Gtk::StateType state = Gtk::STATE_NORMAL;
if (!is_sensitive())
state = Gtk::STATE_INSENSITIVE;
Glib::RefPtr<Gtk::Style> style = get_style ();
Cairo::RefPtr<Cairo::Context> cr = pixmap->create_cairo_context();
// bounding rectangle
Gdk::Color c = style->get_bg (state);
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
cr->rectangle (0, 0, innerWidth + RADIUS*2, innerHeight + RADIUS*2);
cr->fill ();
// histogram in the background
if (bghistvalid) {
// find highest bin
unsigned int histheight = 0;
for (int i=0; i<256; i++)
if (bghist[i]>histheight)
histheight = bghist[i];
// draw histogram
cr->set_line_width (1.0);
double stepSize = (innerWidth-1) / 256.0;
cr->move_to (RADIUS, innerHeight-1+RADIUS);
cr->set_source_rgb (0.75, 0.75, 0.75);
for (int i=0; i<256; i++) {
double val = bghist[i] * (double)(innerHeight-2) / (double)histheight;
if (val>innerHeight-1)
val = innerHeight-1;
if (i>0)
cr->line_to (i*stepSize+RADIUS, innerHeight-1+RADIUS-val);
}
cr->line_to (innerWidth-1+RADIUS, innerHeight-1+RADIUS);
cr->fill ();
}
// draw the grid lines:
cr->set_line_width (1.0);
c = style->get_dark (state);
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
cr->set_antialias (Cairo::ANTIALIAS_NONE);
for (int i = 0; i < 5; i++) { // + 0.5 to align well with f(x)=x so it will cut through the center
cr->move_to (RADIUS, MAX(0,i * (innerHeight + 0.5) / 4) + RADIUS);
cr->line_to (innerWidth + RADIUS, MAX(0,i * (innerHeight + 0.5) / 4) + RADIUS);
cr->move_to (MAX(0,i * innerWidth / 4) + RADIUS, RADIUS);
cr->line_to (MAX(0,i * innerWidth / 4) + RADIUS, innerHeight + RADIUS);
}
cr->stroke ();
// draw f(x)=x line
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
std::valarray<double> ds (1);
ds[0] = 4;
cr->set_dash (ds, 0);
cr->move_to (RADIUS, innerHeight + RADIUS);
cr->line_to (innerWidth + RADIUS, RADIUS);
cr->stroke ();
cr->unset_dash ();
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
cr->set_line_width (1.0);
// draw upper and lower bounds
if (curve.type==Parametric && activeParam>0 && lpoint.size()>1 && upoint.size()>1) {
cr->set_source_rgba (0.0, 0.0, 0.0, 0.15);
cr->move_to (upoint[0].get_x(), upoint[0].get_y());
for (int i=1; i<(int)upoint.size(); i++)
cr->line_to (upoint[i].get_x(), upoint[i].get_y());
cr->line_to (lpoint[lpoint.size()-1].get_x(), lpoint[lpoint.size()-1].get_y());
for (int i=(int)lpoint.size()-2; i>=0; i--)
cr->line_to (lpoint[i].get_x(), lpoint[i].get_y());
cr->line_to (upoint[0].get_x(), upoint[0].get_y());
cr->fill ();
}
// draw the cage of the NURBS curve
if (curve.type==NURBS) {
std::valarray<double> ch_ds (1);
ch_ds[0] = 2;
cr->set_dash (ch_ds, 0);
cr->set_source_rgb (0.0, 0.0, 0.0);
std::vector<double> points = getPoints();
for (int i = 1; i < (int)points.size(); ) {
double x = ((innerWidth-1) * points[i++] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y = innerHeight - ((innerHeight-1) * points[i++] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
if (i==3)
cr->move_to (x, y);
else
cr->line_to (x, y);
}
cr->stroke ();
cr->unset_dash ();
}
// draw curve
cr->set_source_rgb (0.0, 0.0, 0.0);
cr->move_to (point[0].get_x(), point[0].get_y());
for (int i=1; i<(int)point.size(); i++)
cr->line_to (point[i].get_x(), point[i].get_y());
cr->stroke ();
// draw bullets
if (curve.type!=Parametric)
for (int i = 0; i < (int)curve.x.size(); ++i) {
cr->set_source_rgb ((i == handle ? 1.0 : 0.0), 0.0, 0.0);
double x = ((innerWidth-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y = innerHeight - ((innerHeight-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
cr->arc (x, y, RADIUS+0.5, 0, 2*M_PI);
cr->fill ();
}
get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, innerWidth + RADIUS * 2, innerHeight + RADIUS * 2);
}
bool MyCurve::handleEvents (GdkEvent* event) {
CursorShape new_type = cursor_type;
int src, dst;
std::vector<double>::iterator itx, ity;
bool retval = false;
int num = (int)curve.x.size();
/* innerWidth and innerHeight are the size of the graph */
innerWidth = get_allocation().get_width() - RADIUS * 2;
innerHeight = get_allocation().get_height() - RADIUS * 2;
double minDistanceX = (double)(MIN_DISTANCE) / (double)(innerWidth-1);
double minDistanceY = (double)(MIN_DISTANCE) / (double)(innerHeight-1);
if ((innerWidth < 0) || (innerHeight < 0))
return false;
switch (event->type) {
case Gdk::CONFIGURE:
if (pixmap)
pixmap.clear ();
retval = true;
break;
case Gdk::EXPOSE:
if (!pixmap) {
pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height());
interpolate ();
}
draw (lit_point);
retval = true;
break;
case Gdk::BUTTON_PRESS:
if (curve.type!=Parametric) {
if (event->button.button == 1) {
buttonPressed = true;
add_modal_grab ();
// get the pointer position
getCursorPosition(event);
findClosestPoint();
new_type = CSMove;
if (distanceX > minDistanceX) {
/* insert a new control point */
if (num > 0) {
if (clampedX > curve.x[closest_point])
++closest_point;
}
itx = curve.x.begin();
ity = curve.y.begin();
for (int i=0; i<closest_point; i++) { itx++; ity++; }
curve.x.insert (itx, 0);
curve.y.insert (ity, 0);
num++;
// the graph is refreshed only if a new point is created (snaped to a pixel)
curve.x[closest_point] = clampedX;
curve.y[closest_point] = clampedY;
interpolate ();
draw (closest_point);
notifyListener ();
}
grab_point = closest_point;
lit_point = closest_point;
ugpX = curve.x[closest_point];
ugpY = curve.y[closest_point];
}
if (buttonPressed) retval = true;
}
break;
case Gdk::BUTTON_RELEASE:
if (curve.type!=Parametric) {
if (buttonPressed && event->button.button == 1) {
buttonPressed = false;
/* get the pointer position */
getCursorPosition(event);
findClosestPoint();
remove_modal_grab ();
int previous_lit_point = lit_point;
/* delete inactive points: */
itx = curve.x.begin();
ity = curve.y.begin();
for (src = dst = 0; src < num; ++src)
if (curve.x[src] >= 0.0) {
curve.x[dst] = curve.x[src];
curve.y[dst] = curve.y[src];
++dst;
++itx;
++ity;
}
if (dst < src) {
curve.x.erase (itx, curve.x.end());
curve.y.erase (ity, curve.y.end());
if (!curve.x.size()) {
curve.x.push_back (0);
curve.y.push_back (0);
interpolate ();
draw (lit_point);
}
}
if (distanceX <= minDistanceX) {
new_type = CSMove;
lit_point = closest_point;
}
else {
new_type = CSPlus;
lit_point = -1;
}
if (lit_point != previous_lit_point)
draw (lit_point);
grab_point = -1;
retval = true;
notifyListener ();
}
}
break;
case Gdk::LEAVE_NOTIFY:
// Pointer can LEAVE even when dragging the point, so we don't modify the cursor in this case
// The cursor will have to LEAVE another time after the drag...
if (!buttonPressed)
if (grab_point == -1) {
new_type = CSArrow;
lit_point = -1;
draw (lit_point);
}
retval = true;
break;
case Gdk::MOTION_NOTIFY:
if (curve.type == Linear || curve.type == Spline || curve.type == NURBS) {
// get the pointer position
getCursorPosition(event);
if (grab_point == -1) {
// there's no point currently being moved
int previous_lit_point = lit_point;
findClosestPoint();
if (distanceX <= minDistanceX) {
new_type = CSMove;
lit_point = closest_point;
}
else {
new_type = CSPlus;
lit_point = -1;
}
if (lit_point != previous_lit_point)
draw (lit_point);
}
else {
// a point is being moved
// bounds of the grabbed point
double leftBound = (grab_point == 0 ) ? 0. : curve.x[grab_point-1];
double rightBound = (grab_point == num-1) ? 1. : curve.x[grab_point+1];
double const bottomBound = 0.;
double const topBound = 1.;
double leftDeletionBound = leftBound - minDistanceX;
double rightDeletionBound = rightBound + minDistanceX;
double bottomDeletionBound = bottomBound - minDistanceY;
double topDeletionBound = topBound + minDistanceY;
// we memorize the previous position of the point, for optimization purpose
double prevPosX = curve.x[grab_point];
double prevPosY = curve.y[grab_point];
// we memorize the previous position of the point, for optimization purpose
ugpX += deltaX;
ugpY += deltaY;
// handling limitations along X axis
if (ugpX >= rightDeletionBound && (grab_point > 0 && grab_point < (num-1))) {
curve.x[grab_point] = -1.;
}
else if (ugpX <= leftDeletionBound && (grab_point > 0 && grab_point < (num-1))) {
curve.x[grab_point] = -1.;
}
else
// nextPosX is in bounds
curve.x[grab_point] = CLAMP(ugpX, leftBound, rightBound);
// Handling limitations along Y axis
if (ugpY >= topDeletionBound && grab_point != 0 && grab_point != num-1) {
curve.x[grab_point] = -1.;
}
else if (ugpY <= bottomDeletionBound && grab_point != 0 && grab_point != num-1) {
curve.x[grab_point] = -1.;
}
else
// nextPosY is in the bounds
curve.y[grab_point] = CLAMP(ugpY, 0.0, 1.0);
if (curve.x[grab_point] != prevPosX || curve.y[grab_point] != prevPosY) {
// we recalculate the curve only if we have to
interpolate ();
draw (lit_point);
notifyListener ();
}
}
}
retval = true;
break;
default:
break;
}
if (new_type != cursor_type) {
cursor_type = new_type;
cursorManager.setCursor(cursor_type);
}
return retval;
}
void MyCurve::getCursorPosition(GdkEvent* event) {
int tx, ty;
int prevCursorX, prevCursorY;
double incrementX = 1. / (double)(innerWidth-1);
double incrementY = 1. / (double)(innerHeight-1);
// getting the cursor position
switch (event->type) {
case (Gdk::MOTION_NOTIFY) :
if (event->motion.is_hint) {
get_window()->get_pointer (tx, ty, mod_type);
}
else {
tx = (int)event->button.x;
ty = (int)event->button.y;
mod_type = (Gdk::ModifierType)event->button.state;
}
break;
case (Gdk::BUTTON_PRESS) :
case (Gdk::BUTTON_RELEASE) :
tx = (int)event->button.x;
ty = (int)event->button.y;
mod_type = (Gdk::ModifierType)event->button.state;
break;
default :
// The cursor position is not available
return;
break;
}
if (grab_point != -1) {
prevCursorX = cursorX;
prevCursorY = cursorY;
}
cursorX = tx - RADIUS;
cursorY = (innerHeight-1) - (ty - RADIUS);
// update deltaX/Y if the user drags a point
if (grab_point != -1) {
// set the dragging factor
int control_key = mod_type & GDK_CONTROL_MASK;
int shift_key = mod_type & GDK_SHIFT_MASK;
// the increment get smaller if modifier key are used
if (control_key && shift_key) { incrementX *= 0.01; incrementY *= 0.01; }
else if (shift_key) { incrementX *= 0.07; incrementY *= 0.07; }
else if (control_key) { incrementX *= 0.25; incrementY *= 0.25; }
deltaX = (double)(cursorX - prevCursorX) * incrementX;
deltaY = (double)(cursorY - prevCursorY) * incrementY;
}
// otherwise set the position of the new point (modifier keys has no effect here)
else {
double tempCursorX = cursorX * incrementX;
double tempCursorY = cursorY * incrementY;
clampedX = CLAMP (tempCursorX, 0., 1.); // X position of the pointer from the origin of the graph
clampedY = CLAMP (tempCursorY, 0., 1.); // Y position of the pointer from the origin of the graph
}
}
void MyCurve::findClosestPoint() {
distanceX = 10.0; distanceY = 10.0;
closest_point = -1;
if (curve.type!=Parametric) {
for (int i = 0; i < (int)curve.x.size(); i++) {
double dX = curve.x[i] - clampedX;
double dY = curve.y[i] - clampedY;
double currDistX = dX < 0. ? -dX : dX; //abs (dX);
double currDistY = dY < 0. ? -dY : dY; //abs (dY);
if (currDistX < distanceX) {
distanceX = currDistX;
distanceY = currDistY;
closest_point = i;
}
else if (currDistX == distanceX && currDistY < distanceY) {
// there is more than 1 point for that X coordinate, we select the closest point to the cursor
distanceY = currDistY;
closest_point = i;
}
}
}
}
std::vector<double> MyCurve::getPoints () {
std::vector<double> result;
if (curve.type==Parametric) {
result.push_back ((double)(Parametric));
for (int i=0; i<(int)curve.x.size(); i++) {
result.push_back (curve.x[i]);
}
}
else {
// the first value gives the type of the curve
if (curve.type==Linear)
result.push_back ((double)(Linear));
else if (curve.type==Spline)
result.push_back ((double)(Spline));
else if (curve.type==NURBS)
result.push_back ((double)(NURBS));
// then we push all the points coordinate
for (int i=0; i<(int)curve.x.size(); i++) {
if (curve.x[i]>=0) {
result.push_back (curve.x[i]);
result.push_back (curve.y[i]);
}
}
}
return result;
}
void MyCurve::setPoints (const std::vector<double>& p) {
int ix = 0;
CurveType t = (CurveType)p[ix++];
curve.type = t;
if (t==Parametric) {
curve.x.clear ();
curve.y.clear ();
for (int i=1; i<(int)p.size(); i++)
curve.x.push_back (p[ix++]);
}
else {
curve.x.clear ();
curve.y.clear ();
for (int i=0; i<(int)p.size()/2; i++) {
curve.x.push_back (p[ix++]);
curve.y.push_back (p[ix++]);
}
activeParam = -1;
}
pixmap.clear ();
queue_draw ();
}
void MyCurve::setType (CurveType t) {
curve.type = t;
pixmap.clear ();
}
void MyCurve::notifyListener () {
if (listener)
listener->curveChanged ();
}
void MyCurve::setActiveParam (int ac) {
activeParam = ac;
pixmap.clear ();
queue_draw ();
}
int mchistupdate (void* data) {
gdk_threads_enter ();
MyCurveIdleHelper* mcih = (MyCurveIdleHelper*)data;
if (mcih->destroyed) {
if (mcih->pending == 1)
delete mcih;
else
mcih->pending--;
gdk_threads_leave ();
return 0;
}
mcih->myCurve->pixmap.clear ();
mcih->myCurve->queue_draw ();
mcih->pending--;
gdk_threads_leave ();
return 0;
}
void MyCurve::updateBackgroundHistogram (unsigned int* hist) {
if (hist!=NULL) {
memcpy (bghist, hist, 256*sizeof(unsigned int));
bghistvalid = true;
}
else
bghistvalid = false;
mcih->pending++;
g_idle_add (mchistupdate, mcih);
}
void MyCurve::reset() {
innerWidth = get_allocation().get_width() - RADIUS * 2;
innerHeight = get_allocation().get_height() - RADIUS * 2;
switch (curve.type) {
case Spline :
case NURBS :
curve.x.clear();
curve.y.clear();
curve.x.push_back(0.);
curve.y.push_back(0.);
curve.x.push_back(1.);
curve.y.push_back(1.);
grab_point = -1;
lit_point = -1;
interpolate ();
break;
case Parametric :
// Nothing to do (?)
default:
break;
}
draw(-1);
}
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mycurve.h>
#include <curves.h>
#include <string.h>
#include <gdkmm/types.h>
MyCurve::MyCurve () : listener(NULL) {
cursor_type = CSArrow;
innerWidth = get_allocation().get_width() - RADIUS * 2;
innerHeight = get_allocation().get_height() - RADIUS * 2;
prevInnerHeight = innerHeight;
buttonPressed = false;
snapTo = ST_None;
colorProvider = NULL;
sized = false;
set_extension_events(Gdk::EXTENSION_EVENTS_ALL);
add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK);
mcih = new MyCurveIdleHelper;
mcih->myCurve = this;
mcih->destroyed = false;
mcih->pending = 0;
}
MyCurve::~MyCurve () {
if (mcih->pending)
mcih->destroyed = true;
else
delete mcih;
}
void MyCurve::notifyListener () {
if (listener)
listener->curveChanged ();
}

View File

@@ -23,91 +23,73 @@
#include <vector>
#include <curvelistener.h>
#include <cursormanager.h>
#include <colorprovider.h>
#define RADIUS 3 /* radius of the control points. Assuming that the center of the spot is in the center of the pixel, the real RADIUS will be this value +0.5 */
#define MIN_DISTANCE 8 /* min distance between control points */
#define RADIUS 3 /* radius of the control points */
#define SQUARE 2 /* half length of the square shape of the tangent handles */
#define MIN_DISTANCE 5 /* min distance between control points */
#define GRAPH_SIZE 200 /* size of the curve editor graphic */
// For compatibility and simplicity reason, order shouldn't change, and must be identical to the order specified in the curveType widget
enum CurveType {
Empty = -1,
Linear, // 0
Spline, // 1
Parametric, // 2
NURBS, // 3
// Insert new curve type above this line
Unchanged // Must remain the last of the enum
CT_Flat,
CT_Diagonal
};
class CurveDescr {
public:
CurveType type;
std::vector<double> x, y; // in case of parametric curves the curve parameters are stored in vector x. In other cases these vectors store the coordinates of the bullets.
};
class MyCurve;
struct MyCurveIdleHelper {
MyCurve* myCurve;
bool destroyed;
int pending;
enum SnapToType {
ST_None,
ST_Identity, // Point snapped to the identity curve
ST_Neighbors // Point snapped to the neighbor points
};
class MyCurveIdleHelper;
class MyCurve : public Gtk::DrawingArea {
friend int mchistupdate (void* data);
friend class MyCurveIdleHelper;
protected:
CurveListener* listener;
CurveDescr curve;
CursorShape cursor_type;
Glib::RefPtr<Gdk::Pixmap> pixmap;
int innerWidth; // inner width of the editor, allocated by the system
int innerHeight; // inner height of the editor, allocated by the system
int prevInnerHeight;// previous inner height of the editor
int grab_point; // the point that the user is moving
int closest_point; // the point that is the closest from the cursor
int lit_point; // the point that is lit when the cursor is near it
//int last;
protected:
CurveListener* listener;
ColorProvider* colorProvider;
CursorShape cursor_type;
Glib::RefPtr<Gdk::Pixmap> pixmap;
int innerWidth; // inner width of the editor, allocated by the system
int innerHeight; // inner height of the editor, allocated by the system
int prevInnerHeight;// previous inner height of the editor
Gdk::ModifierType mod_type;
int cursorX; // X coordinate in the graph of the cursor
int cursorY; // Y coordinate in the graph of the cursor
double clampedX; // clamped grabbed point X coordinates in the [0;1] range
double clampedY; // clamped grabbed point Y coordinates in the [0;1] range
double deltaX; // signed X distance of the cursor between two consecutive MOTION_NOTIFY
double deltaY; // signed Y distance of the cursor between two consecutive MOTION_NOTIFY
double distanceX; // X distance from the cursor to the closest point
double distanceY; // Y distance from the cursor to the closest point
double ugpX; // unclamped grabbed point X coordinate in the graph
double ugpY; // unclamped grabbed point Y coordinate in the graph
std::vector<Gdk::Point> point;
std::vector<Gdk::Point> upoint;
std::vector<Gdk::Point> lpoint;
int activeParam;
unsigned int* bghist; // histogram values
bool bghistvalid;
bool buttonPressed;
MyCurveIdleHelper* mcih;
int cursorX; // X coordinate in the graph of the cursor
int cursorY; // Y coordinate in the graph of the cursor
std::vector<Gdk::Point> point;
std::vector<Gdk::Point> upoint;
std::vector<Gdk::Point> lpoint;
bool buttonPressed;
enum SnapToType snapTo;
MyCurveIdleHelper* mcih;
bool sized;
void draw (int handle);
void interpolate ();
void getCursorPosition(GdkEvent* event);
void findClosestPoint();
std::vector<double> get_vector (int veclen);
public:
MyCurve ();
~MyCurve ();
void setCurveListener (CurveListener* cl) { listener = cl; }
void setColorProvider (ColorProvider* cp) { colorProvider = cp; }
void notifyListener ();
void updateBackgroundHistogram (unsigned int* hist) {return;} ;
virtual std::vector<double> getPoints () = 0;
virtual void setPoints (const std::vector<double>& p) = 0;
virtual bool handleEvents (GdkEvent* event) = 0;
virtual void reset () = 0;
protected:
virtual std::vector<double> get_vector (int veclen) = 0;
};
class MyCurveIdleHelper {
public:
MyCurve* myCurve;
bool destroyed;
int pending;
void clearPixmap () { myCurve->pixmap.clear (); }
public:
MyCurve ();
~MyCurve ();
void setCurveListener (CurveListener* cl) { listener = cl; }
std::vector<double> getPoints ();
void setPoints (const std::vector<double>& p);
void setType (CurveType t);
bool handleEvents (GdkEvent* event);
void notifyListener ();
void setActiveParam (int ac);
void updateBackgroundHistogram (unsigned int* hist);
void reset ();
};
#endif

678
rtgui/mydiagonalcurve.cc Normal file
View File

@@ -0,0 +1,678 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mydiagonalcurve.h>
#include <curves.h>
#include <string.h>
#include <gdkmm/types.h>
MyDiagonalCurve::MyDiagonalCurve () : activeParam(-1), bghistvalid(false) {
innerWidth = get_allocation().get_width() - RADIUS * 2;
innerHeight = get_allocation().get_height() - RADIUS * 2;
prevInnerHeight = innerHeight;
grab_point = -1;
lit_point = -1;
buttonPressed = false;
bghist = new unsigned int[256];
signal_event().connect( sigc::mem_fun(*this, &MyDiagonalCurve::handleEvents) );
curve.type = DCT_Spline;
curve.x.push_back(0.);
curve.y.push_back(0.);
curve.x.push_back(1.);
curve.y.push_back(1.);
}
MyDiagonalCurve::~MyDiagonalCurve () {
delete [] bghist;
}
std::vector<double> MyDiagonalCurve::get_vector (int veclen) {
std::vector<double> vector;
vector.resize (veclen);
if (curve.type != DCT_Parametric) {
// count active points:
double prev =- 1.0;
int active = 0;
int firstact = -1;
for (int i = 0; i < (int)curve.x.size(); ++i)
if (curve.x[i] > prev) {
if (firstact < 0)
firstact = i;
prev = curve.x[i];
++active;
}
// handle degenerate case:
if (active < 2) {
double ry;
if (active > 0)
ry = curve.y[firstact];
else
ry = 0.0;
if (ry < 0.0) ry = 0.0;
if (ry > 1.0) ry = 1.0;
for (int x = 0; x < veclen; ++x)
vector[x] = ry;
return vector;
}
}
// calculate remaining points
std::vector<double> curveDescr = getPoints ();
rtengine::DiagonalCurve* rtcurve = new rtengine::DiagonalCurve (curveDescr, veclen*1.5);
std::vector<double> t;
t.resize (veclen);
for (int i = 0; i < veclen; i++)
t[i] = (double) i / (veclen - 1.0);
rtcurve->getVal (t, vector);
delete rtcurve;
return vector;
}
void MyDiagonalCurve::interpolate () {
prevInnerHeight = innerHeight;
point.resize (innerWidth);
std::vector<double> vector = get_vector (innerWidth);
prevInnerHeight = innerHeight;
for (int i = 0; i < innerWidth; ++i)
point[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
upoint.clear ();
lpoint.clear ();
if (curve.type==DCT_Parametric && activeParam>0) {
double tmp = curve.x[activeParam-1];
if (activeParam>=4) {
upoint.resize(innerWidth);
lpoint.resize(innerWidth);
curve.x[activeParam-1] = 100;
vector = get_vector (innerWidth);
for (int i = 0; i < innerWidth; ++i)
upoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
curve.x[activeParam-1] = -100;
vector = get_vector (innerWidth);
for (int i = 0; i < innerWidth; ++i)
lpoint[i] = Gdk::Point (RADIUS + i, RADIUS + innerHeight - (int)((innerHeight-1) * vector[i] + 0.5));
curve.x[activeParam-1] = tmp;
}
}
}
void MyDiagonalCurve::draw (int handle) {
if (!pixmap)
return;
// re-calculate curve if dimensions changed
if (prevInnerHeight != innerHeight || (int)point.size() != innerWidth)
interpolate ();
Gtk::StateType state = Gtk::STATE_NORMAL;
if (!is_sensitive())
state = Gtk::STATE_INSENSITIVE;
Glib::RefPtr<Gtk::Style> style = get_style ();
Cairo::RefPtr<Cairo::Context> cr = pixmap->create_cairo_context();
// bounding rectangle
Gdk::Color c = style->get_bg (state);
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
cr->rectangle (0, 0, innerWidth + RADIUS*2, innerHeight + RADIUS*2);
cr->fill ();
// histogram in the background
if (bghistvalid) {
// find highest bin
unsigned int histheight = 0;
for (int i=0; i<256; i++)
if (bghist[i]>histheight)
histheight = bghist[i];
// draw histogram
cr->set_line_width (1.0);
double stepSize = (innerWidth-1) / 256.0;
cr->move_to (RADIUS, innerHeight-1+RADIUS);
cr->set_source_rgb (0.75, 0.75, 0.75);
for (int i=0; i<256; i++) {
double val = bghist[i] * (double)(innerHeight-2) / (double)histheight;
if (val>innerHeight-1)
val = innerHeight-1;
if (i>0)
cr->line_to (i*stepSize+RADIUS, innerHeight-1+RADIUS-val);
}
cr->line_to (innerWidth-1+RADIUS, innerHeight-1+RADIUS);
cr->fill ();
}
// draw the grid lines:
cr->set_line_width (1.0);
c = style->get_dark (state);
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
cr->set_antialias (Cairo::ANTIALIAS_NONE);
for (int i = 0; i < 5; i++) { // + 0.5 to align well with f(x)=x so it will cut through the center
cr->move_to (RADIUS, MAX(0,i * (innerHeight + 0.5) / 4) + RADIUS);
cr->line_to (innerWidth + RADIUS, MAX(0,i * (innerHeight + 0.5) / 4) + RADIUS);
cr->move_to (MAX(0,i * innerWidth / 4) + RADIUS, RADIUS);
cr->line_to (MAX(0,i * innerWidth / 4) + RADIUS, innerHeight + RADIUS);
}
cr->stroke ();
// draw f(x)=x line
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
std::valarray<double> ds (1);
ds[0] = 4;
cr->set_dash (ds, 0);
cr->move_to (RADIUS, innerHeight + RADIUS);
cr->line_to (innerWidth + RADIUS, RADIUS);
cr->stroke ();
cr->unset_dash ();
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
cr->set_line_width (1.0);
// draw upper and lower bounds
if (curve.type==DCT_Parametric && activeParam>0 && lpoint.size()>1 && upoint.size()>1) {
cr->set_source_rgba (0.0, 0.0, 0.0, 0.15);
cr->move_to (upoint[0].get_x(), upoint[0].get_y());
for (int i=1; i<(int)upoint.size(); i++)
cr->line_to (upoint[i].get_x(), upoint[i].get_y());
cr->line_to (lpoint[lpoint.size()-1].get_x(), lpoint[lpoint.size()-1].get_y());
for (int i=(int)lpoint.size()-2; i>=0; i--)
cr->line_to (lpoint[i].get_x(), lpoint[i].get_y());
cr->line_to (upoint[0].get_x(), upoint[0].get_y());
cr->fill ();
}
// draw the cage of the NURBS curve
if (curve.type==DCT_NURBS) {
std::valarray<double> ch_ds (1);
ch_ds[0] = 2;
cr->set_dash (ch_ds, 0);
cr->set_source_rgb (0.0, 0.0, 0.0);
std::vector<double> points = getPoints();
for (int i = 1; i < (int)points.size(); ) {
double x = ((innerWidth-1) * points[i++] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y = innerHeight - ((innerHeight-1) * points[i++] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
if (i==3)
cr->move_to (x, y);
else
cr->line_to (x, y);
}
cr->stroke ();
cr->unset_dash ();
}
// draw curve
cr->set_source_rgb (0.0, 0.0, 0.0);
cr->move_to (point[0].get_x(), point[0].get_y());
for (int i=1; i<(int)point.size(); i++)
cr->line_to (point[i].get_x(), point[i].get_y());
cr->stroke ();
// draw bullets
if (curve.type!=DCT_Parametric)
for (int i = 0; i < (int)curve.x.size(); ++i) {
cr->set_source_rgb ((i == handle ? 1.0 : 0.0), 0.0, 0.0);
double x = ((innerWidth-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, innerWidth);
double y = innerHeight - ((innerHeight-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, innerHeight);
cr->arc (x, y, RADIUS+0.5, 0, 2*M_PI);
cr->fill ();
}
get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, innerWidth + RADIUS * 2, innerHeight + RADIUS * 2);
}
bool MyDiagonalCurve::handleEvents (GdkEvent* event) {
CursorShape new_type = cursor_type;
int src, dst;
std::vector<double>::iterator itx, ity;
bool retval = false;
int num = (int)curve.x.size();
/* innerWidth and innerHeight are the size of the graph */
innerWidth = get_allocation().get_width() - RADIUS * 2;
innerHeight = get_allocation().get_height() - RADIUS * 2;
double minDistanceX = (double)(MIN_DISTANCE) / (double)(innerWidth-1);
double minDistanceY = (double)(MIN_DISTANCE) / (double)(innerHeight-1);
if ((innerWidth < 0) || (innerHeight < 0))
return false;
switch (event->type) {
case Gdk::CONFIGURE:
if (pixmap)
pixmap.clear ();
retval = true;
break;
case Gdk::EXPOSE:
if (!pixmap) {
pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height());
interpolate ();
}
draw (lit_point);
retval = true;
break;
case Gdk::BUTTON_PRESS:
if (curve.type!=DCT_Parametric) {
if (event->button.button == 1) {
buttonPressed = true;
add_modal_grab ();
// get the pointer position
getCursorPosition(event);
findClosestPoint();
new_type = CSMove;
if (distanceX > minDistanceX) {
/* insert a new control point */
if (num > 0) {
if (clampedX > curve.x[closest_point])
++closest_point;
}
itx = curve.x.begin();
ity = curve.y.begin();
for (int i=0; i<closest_point; i++) { itx++; ity++; }
curve.x.insert (itx, 0);
curve.y.insert (ity, 0);
num++;
// the graph is refreshed only if a new point is created (snaped to a pixel)
curve.x[closest_point] = clampedX;
curve.y[closest_point] = clampedY;
interpolate ();
draw (closest_point);
notifyListener ();
}
grab_point = closest_point;
lit_point = closest_point;
ugpX = curve.x[closest_point];
ugpY = curve.y[closest_point];
}
if (buttonPressed) retval = true;
}
break;
case Gdk::BUTTON_RELEASE:
if (curve.type!=DCT_Parametric) {
if (buttonPressed && event->button.button == 1) {
buttonPressed = false;
/* get the pointer position */
getCursorPosition(event);
findClosestPoint();
remove_modal_grab ();
int previous_lit_point = lit_point;
/* delete inactive points: */
itx = curve.x.begin();
ity = curve.y.begin();
for (src = dst = 0; src < num; ++src)
if (curve.x[src] >= 0.0) {
curve.x[dst] = curve.x[src];
curve.y[dst] = curve.y[src];
++dst;
++itx;
++ity;
}
if (dst < src) {
curve.x.erase (itx, curve.x.end());
curve.y.erase (ity, curve.y.end());
if (!curve.x.size()) {
curve.x.push_back (0);
curve.y.push_back (0);
interpolate ();
draw (lit_point);
}
}
if (distanceX <= minDistanceX) {
new_type = CSMove;
lit_point = closest_point;
}
else {
new_type = CSPlus;
lit_point = -1;
}
if (lit_point != previous_lit_point)
draw (lit_point);
grab_point = -1;
retval = true;
notifyListener ();
}
}
break;
case Gdk::LEAVE_NOTIFY:
// Pointer can LEAVE even when dragging the point, so we don't modify the cursor in this case
// The cursor will have to LEAVE another time after the drag...
if (!buttonPressed)
if (grab_point == -1) {
new_type = CSArrow;
lit_point = -1;
draw (lit_point);
}
retval = true;
break;
case Gdk::MOTION_NOTIFY:
if (curve.type == DCT_Linear || curve.type == DCT_Spline || curve.type == DCT_NURBS) {
// get the pointer position
getCursorPosition(event);
if (grab_point == -1) {
// there's no point currently being moved
int previous_lit_point = lit_point;
findClosestPoint();
if (distanceX <= minDistanceX) {
new_type = CSMove;
lit_point = closest_point;
}
else {
new_type = CSPlus;
lit_point = -1;
}
if (lit_point != previous_lit_point)
draw (lit_point);
}
else {
// a point is being moved
// bounds of the grabbed point
double leftBound = (grab_point == 0 ) ? 0. : curve.x[grab_point-1];
double rightBound = (grab_point == num-1) ? 1. : curve.x[grab_point+1];
double const bottomBound = 0.;
double const topBound = 1.;
double leftDeletionBound = leftBound - minDistanceX;
double rightDeletionBound = rightBound + minDistanceX;
double bottomDeletionBound = bottomBound - minDistanceY;
double topDeletionBound = topBound + minDistanceY;
// we memorize the previous position of the point, for optimization purpose
double prevPosX = curve.x[grab_point];
double prevPosY = curve.y[grab_point];
// we memorize the previous position of the point, for optimization purpose
ugpX += deltaX;
ugpY += deltaY;
// handling limitations along X axis
if (ugpX >= rightDeletionBound && (grab_point > 0 && grab_point < (num-1))) {
curve.x[grab_point] = -1.;
}
else if (ugpX <= leftDeletionBound && (grab_point > 0 && grab_point < (num-1))) {
curve.x[grab_point] = -1.;
}
else
// nextPosX is in bounds
curve.x[grab_point] = CLAMP(ugpX, leftBound, rightBound);
// Handling limitations along Y axis
if (ugpY >= topDeletionBound && grab_point != 0 && grab_point != num-1) {
curve.x[grab_point] = -1.;
}
else if (ugpY <= bottomDeletionBound && grab_point != 0 && grab_point != num-1) {
curve.x[grab_point] = -1.;
}
else
// nextPosY is in the bounds
curve.y[grab_point] = CLAMP(ugpY, 0.0, 1.0);
if (curve.x[grab_point] != prevPosX || curve.y[grab_point] != prevPosY) {
// we recalculate the curve only if we have to
interpolate ();
draw (lit_point);
notifyListener ();
}
}
}
retval = true;
break;
default:
break;
}
if (new_type != cursor_type) {
cursor_type = new_type;
cursorManager.setCursor(cursor_type);
}
return retval;
}
void MyDiagonalCurve::getCursorPosition(GdkEvent* event) {
int tx, ty;
int prevCursorX, prevCursorY;
double incrementX = 1. / (double)(innerWidth-1);
double incrementY = 1. / (double)(innerHeight-1);
// getting the cursor position
switch (event->type) {
case (Gdk::MOTION_NOTIFY) :
if (event->motion.is_hint) {
get_window()->get_pointer (tx, ty, mod_type);
}
else {
tx = (int)event->button.x;
ty = (int)event->button.y;
mod_type = (Gdk::ModifierType)event->button.state;
}
break;
case (Gdk::BUTTON_PRESS) :
case (Gdk::BUTTON_RELEASE) :
tx = (int)event->button.x;
ty = (int)event->button.y;
mod_type = (Gdk::ModifierType)event->button.state;
break;
default :
// The cursor position is not available
return;
break;
}
if (grab_point != -1) {
prevCursorX = cursorX;
prevCursorY = cursorY;
}
cursorX = tx - RADIUS;
cursorY = (innerHeight-1) - (ty - RADIUS);
snapTo = ST_None;
// update deltaX/Y if the user drags a point
if (grab_point != -1) {
// set the dragging factor
int control_key = mod_type & GDK_CONTROL_MASK;
int shift_key = mod_type & GDK_SHIFT_MASK;
// the increment get smaller if modifier key are used, and "snap to" may be enabled
if (control_key && shift_key) { snapTo = ST_Neighbors; }
else if (control_key) { snapTo = ST_Identity; }
else if (shift_key) { incrementX *= 0.04; incrementY *= 0.04; }
deltaX = (double)(cursorX - prevCursorX) * incrementX;
deltaY = (double)(cursorY - prevCursorY) * incrementY;
}
// otherwise set the position of the new point (modifier keys has no effect here)
else {
double tempCursorX = cursorX * incrementX;
double tempCursorY = cursorY * incrementY;
clampedX = CLAMP (tempCursorX, 0., 1.); // X position of the pointer from the origin of the graph
clampedY = CLAMP (tempCursorY, 0., 1.); // Y position of the pointer from the origin of the graph
}
}
void MyDiagonalCurve::findClosestPoint() {
distanceX = 10.0; distanceY = 10.0;
closest_point = -1;
if (curve.type!=DCT_Parametric) {
for (int i = 0; i < (int)curve.x.size(); i++) {
double dX = curve.x[i] - clampedX;
double dY = curve.y[i] - clampedY;
double currDistX = dX < 0. ? -dX : dX; //abs (dX);
double currDistY = dY < 0. ? -dY : dY; //abs (dY);
if (currDistX < distanceX) {
distanceX = currDistX;
distanceY = currDistY;
closest_point = i;
}
else if (currDistX == distanceX && currDistY < distanceY) {
// there is more than 1 point for that X coordinate, we select the closest point to the cursor
distanceY = currDistY;
closest_point = i;
}
}
}
}
std::vector<double> MyDiagonalCurve::getPoints () {
std::vector<double> result;
if (curve.type==DCT_Parametric) {
result.push_back ((double)(DCT_Parametric));
for (int i=0; i<(int)curve.x.size(); i++) {
result.push_back (curve.x[i]);
}
}
else {
// the first value gives the type of the curve
if (curve.type==DCT_Linear)
result.push_back ((double)(DCT_Linear));
else if (curve.type==DCT_Spline)
result.push_back ((double)(DCT_Spline));
else if (curve.type==DCT_NURBS)
result.push_back ((double)(DCT_NURBS));
// then we push all the points coordinate
for (int i=0; i<(int)curve.x.size(); i++) {
if (curve.x[i]>=0) {
result.push_back (curve.x[i]);
result.push_back (curve.y[i]);
}
}
}
return result;
}
void MyDiagonalCurve::setPoints (const std::vector<double>& p) {
int ix = 0;
DiagonalCurveType t = (DiagonalCurveType)p[ix++];
curve.type = t;
if (t==DCT_Parametric) {
curve.x.clear ();
curve.y.clear ();
for (int i=1; i<(int)p.size(); i++)
curve.x.push_back (p[ix++]);
}
else {
curve.x.clear ();
curve.y.clear ();
for (int i=0; i<(int)p.size()/2; i++) {
curve.x.push_back (p[ix++]);
curve.y.push_back (p[ix++]);
}
activeParam = -1;
}
pixmap.clear ();
queue_draw ();
}
void MyDiagonalCurve::setType (DiagonalCurveType t) {
curve.type = t;
pixmap.clear ();
}
void MyDiagonalCurve::setActiveParam (int ac) {
activeParam = ac;
pixmap.clear ();
queue_draw ();
}
int diagonalmchistupdate (void* data) {
gdk_threads_enter ();
MyCurveIdleHelper* mcih = (MyCurveIdleHelper*)data;
if (mcih->destroyed) {
if (mcih->pending == 1)
delete mcih;
else
mcih->pending--;
gdk_threads_leave ();
return 0;
}
mcih->clearPixmap ();
mcih->myCurve->queue_draw ();
mcih->pending--;
gdk_threads_leave ();
return 0;
}
void MyDiagonalCurve::updateBackgroundHistogram (unsigned int* hist) {
if (hist!=NULL) {
memcpy (bghist, hist, 256*sizeof(unsigned int));
bghistvalid = true;
}
else
bghistvalid = false;
mcih->pending++;
g_idle_add (diagonalmchistupdate, mcih);
}
void MyDiagonalCurve::reset() {
innerWidth = get_allocation().get_width() - RADIUS * 2;
innerHeight = get_allocation().get_height() - RADIUS * 2;
switch (curve.type) {
case DCT_Spline :
case DCT_NURBS :
curve.x.clear();
curve.y.clear();
curve.x.push_back(0.);
curve.y.push_back(0.);
curve.x.push_back(1.);
curve.y.push_back(1.);
grab_point = -1;
lit_point = -1;
interpolate ();
break;
case DCT_Parametric :
// Nothing to do (?)
default:
break;
}
draw(-1);
}

83
rtgui/mydiagonalcurve.h Normal file
View File

@@ -0,0 +1,83 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MYDIAGONALCURVE_
#define _MYDIAGONALCURVE_
#include <gtkmm.h>
#include <vector>
#include <curvelistener.h>
#include <cursormanager.h>
#include <mycurve.h>
// For compatibility and simplicity reason, order shouldn't change, and must be identical to the order specified in the curveType widget
enum DiagonalCurveType {
DCT_Empty = -1,
DCT_Linear, // 0
DCT_Spline, // 1
DCT_Parametric, // 2
DCT_NURBS, // 3
// Insert new curve type above this line
DCT_Unchanged // Must remain the last of the enum
};
class DiagonalCurveDescr {
public:
DiagonalCurveType type;
std::vector<double> x, y; // in case of parametric curves the curve parameters are stored in vector x. In other cases these vectors store the coordinates of the bullets.
};
class MyDiagonalCurve : public MyCurve {
protected:
DiagonalCurveDescr curve;
int grab_point; // the point that the user is moving
int closest_point; // the point that is the closest from the cursor
int lit_point; // the point that is lit when the cursor is near it
double clampedX; // clamped grabbed point X coordinates in the [0;1] range
double clampedY; // clamped grabbed point Y coordinates in the [0;1] range
double deltaX; // signed X distance of the cursor between two consecutive MOTION_NOTIFY
double deltaY; // signed Y distance of the cursor between two consecutive MOTION_NOTIFY
double distanceX; // X distance from the cursor to the closest point
double distanceY; // Y distance from the cursor to the closest point
double ugpX; // unclamped grabbed point X coordinate in the graph
double ugpY; // unclamped grabbed point Y coordinate in the graph
int activeParam;
unsigned int* bghist; // histogram values
bool bghistvalid;
void draw (int handle);
void interpolate ();
void getCursorPosition(GdkEvent* event);
void findClosestPoint();
std::vector<double> get_vector (int veclen);
public:
MyDiagonalCurve ();
~MyDiagonalCurve ();
std::vector<double> getPoints ();
void setPoints (const std::vector<double>& p);
void setType (DiagonalCurveType t);
bool handleEvents (GdkEvent* event);
void setActiveParam (int ac);
void reset ();
void updateBackgroundHistogram (unsigned int* hist);
};
#endif

1296
rtgui/myflatcurve.cc Normal file

File diff suppressed because it is too large Load Diff

135
rtgui/myflatcurve.h Normal file
View File

@@ -0,0 +1,135 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MYFLATCURVE_
#define _MYFLATCURVE_
#include <gtkmm.h>
#include <vector>
#include <curvelistener.h>
#include <cursormanager.h>
#include <mycurve.h>
// For compatibility and simplicity reason, order shouldn't change, and must be identical to the order specified in the curveType widget
enum FlatCurveType {
FCT_Empty = -1,
FCT_Linear, // 0
FCT_MinMaxCPoints, // 1
//FCT_Parametric, // 2
// Insert new curve type above this line
FCT_Unchanged // Must remain the last of the enum
};
enum MouseOverAreas {
FCT_Area_None = 1<<0, // over a zone that don't have any
FCT_Area_Insertion = 1<<1, // where the user can insert a new point
FCT_Area_Point = 1<<2, // over an existing point
FCT_Area_H = 1<<3, // cursor is on the horizontal line going through the edited control point
FCT_Area_V = 1<<4, // cursor is on the vertical line going through the edited control point
FCT_Area_LeftTan = 1<<5, // in the left tangent edition area
FCT_Area_RightTan = 1<<6 // in the right tangent edition area
};
enum EditedHandle {
FCT_EditedHandle_None = 1<<0,
FCT_EditedHandle_CPointUD = 1<<1, // UD stands for Unknown Direction
FCT_EditedHandle_CPoint = 1<<2,
FCT_EditedHandle_CPointX = 1<<3,
FCT_EditedHandle_CPointY = 1<<4,
FCT_EditedHandle_LeftTan = 1<<5,
FCT_EditedHandle_RightTan = 1<<6
};
class FlatCurveDescr {
public:
FlatCurveType type;
std::vector<double> x, // Range: [0.0 - 1.0]
y, // Range: [0.0 - 1.0], default value = 0.5
leftTangent, // Range: [0.0 - 1.0], where 1.0 = distance from previous to this point
rightTangent; // Range: [0.0 - 1.0], where 1.0 = distance from this to next point
};
class RectArea {
public:
double top;
double left;
double bottom;
double right;
};
class HandlePosition {
public:
double centerX;
double centerY;
};
class MyFlatCurve : public MyCurve {
protected:
FlatCurveDescr curve;
int closest_point; // the point that is the closest from the cursor
int lit_point; // the point that is lit when the cursor is near it
double clampedX; // clamped grabbed point X coordinates in the [0;1] range
double clampedY; // clamped grabbed point Y coordinates in the [0;1] range
double deltaX; // signed X distance of the cursor between two consecutive MOTION_NOTIFY
double deltaY; // signed Y distance of the cursor between two consecutive MOTION_NOTIFY
double distanceX; // X distance from the cursor to the closest point
double distanceY; // Y distance from the cursor to the closest point
double ugpX; // unclamped grabbed point X coordinate in the graph
double ugpY; // unclamped grabbed point Y coordinate in the graph
double leftTanX; // X position of the left tangent handle
double rightTanX; // X position of the right tangent handle
double preciseCursorX; // X coordinate in the graph of the cursor, as a double value
double preciseCursorY; // Y coordinate in the graph of the cursor, as a double value
double minDistanceX; // X minimal distance before point suppression
double minDistanceY; // Y minimal distance before point suppression
double deletedPointX; // Backup of the X value of the edited point, when deleted while being dragged
//RectArea leftTanHandle; // XY coordinate if the upper left and bottom right corner of the left tangent handle
//RectArea rightTanHandle; // XY coordinate if the upper left and bottom right corner of the right tangent handle
HandlePosition leftTanHandle; // XY coordinate if the upper left and bottom right corner of the left tangent handle
HandlePosition rightTanHandle; // XY coordinate if the upper left and bottom right corner of the right tangent handle
bool tanHandlesDisplayed; // True if the tangent handles are displayed
bool periodic; // Flat curves are periodic by default
enum EditedHandle editedHandle;
bool draggingElement;
enum MouseOverAreas area;
void draw ();
void movePoint(bool moveX, bool moveY);
void defaultCurve ();
void interpolate ();
void getCursorPosition(GdkEvent* event);
void getMouseOverArea ();
bool getHandles(int n);
std::vector<double> get_vector (int veclen);
public:
MyFlatCurve ();
//~MyFlatCurve ();
std::vector<double> getPoints ();
void setPoints (const std::vector<double>& p);
void setType (FlatCurveType t);
bool handleEvents (GdkEvent* event);
void reset ();
//void updateBackgroundHistogram (unsigned int* hist);
};
#endif

View File

@@ -157,18 +157,15 @@ void ParamsEdited::set (bool v) {
raw.linenoise = v;
equalizer.enabled = v;
dirpyrequalizer.enabled = v;
hsvequalizer.enabled = v;
for(int i = 0; i < 8; i++) {
equalizer.c[i] = v;
}
for(int i = 0; i < 5; i++) {
dirpyrequalizer.mult[i] = v;
}
for(int i = 0; i < 8; i++) {
hsvequalizer.sat[i] = v;
hsvequalizer.val[i] = v;
hsvequalizer.hue[i] = v;
}
hsvequalizer.hcurve = v;
hsvequalizer.scurve = v;
hsvequalizer.vcurve = v;
exif.clear ();
iptc.clear ();
}
@@ -323,12 +320,9 @@ void ParamsEdited::initFrom (const std::vector<rtengine::procparams::ProcParams>
for(int i = 0; i < 8; i++) {
dirpyrequalizer.mult[i] = dirpyrequalizer.mult[i] && p.dirpyrequalizer.mult[i] == other.dirpyrequalizer.mult[i];
}
hsvequalizer.enabled = hsvequalizer.enabled && p.hsvequalizer.enabled == other.hsvequalizer.enabled;
for(int i = 0; i < 8; i++) {
hsvequalizer.sat[i] = hsvequalizer.sat[i] && p.hsvequalizer.sat[i] == other.hsvequalizer.sat[i];
hsvequalizer.val[i] = hsvequalizer.val[i] && p.hsvequalizer.val[i] == other.hsvequalizer.val[i];
hsvequalizer.hue[i] = hsvequalizer.hue[i] && p.hsvequalizer.hue[i] == other.hsvequalizer.hue[i];
}
hsvequalizer.hcurve = hsvequalizer.hcurve && p.hsvequalizer.hcurve == other.hsvequalizer.hcurve;
hsvequalizer.scurve = hsvequalizer.scurve && p.hsvequalizer.scurve == other.hsvequalizer.scurve;
hsvequalizer.vcurve = hsvequalizer.vcurve && p.hsvequalizer.vcurve == other.hsvequalizer.vcurve;
// exif = exif && p.exif==other.exif
// iptc = other.iptc;
}
@@ -474,12 +468,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
for(int i = 0; i < 5; i++) {
if(dirpyrequalizer.mult[i]) toEdit.dirpyrequalizer.mult[i] = mods.dirpyrequalizer.mult[i];
}
if (hsvequalizer.enabled) toEdit.hsvequalizer.enabled = mods.hsvequalizer.enabled;
for(int i = 0; i < 8; i++) {
if(hsvequalizer.sat[i]) toEdit.hsvequalizer.sat[i] = mods.hsvequalizer.sat[i];
if(hsvequalizer.val[i]) toEdit.hsvequalizer.val[i] = mods.hsvequalizer.val[i];
if(hsvequalizer.hue[i]) toEdit.hsvequalizer.hue[i] = mods.hsvequalizer.hue[i];
}
if (hsvequalizer.hcurve) toEdit.hsvequalizer.hcurve = mods.hsvequalizer.hcurve;
if (hsvequalizer.scurve) toEdit.hsvequalizer.scurve = mods.hsvequalizer.scurve;
if (hsvequalizer.vcurve) toEdit.hsvequalizer.vcurve = mods.hsvequalizer.vcurve;
// if (exif) toEdit.exif==mo.exif = mods.exif==other.exif;
// if (iptc;) toEdit.iptc==other.iptc; = mods.iptc==other.iptc;;
}

View File

@@ -269,11 +269,9 @@ public:
class HSVEqualizerParamsEdited {
public:
bool enabled;
bool sat[8];
bool val[8];
bool hue[8];
int hsvchannel;
bool hcurve;
bool scurve;
bool vcurve;
};
class RAWParamsEdited {
@@ -321,11 +319,9 @@ class ParamsEdited {
ColorShiftParamsEdited colorShift;
LumaDenoiseParamsEdited lumaDenoise;
ColorDenoiseParamsEdited colorDenoise;
DefringeParamsEdited defringe;
DirPyrDenoiseParamsEdited dirpyrDenoise;
ImpulseDenoiseParamsEdited impulseDenoise;
SHParamsEdited sh;
CropParamsEdited crop;
CoarseTransformParamsEdited coarse;

View File

@@ -78,7 +78,7 @@ ToneCurve::ToneCurve () : Gtk::VBox(), FoldableToolPanel(this), expAdd(false),hl
curveEditorG = new CurveEditorGroup (M("TP_EXPOSURE_CURVEEDITOR"));
curveEditorG->setCurveListener (this);
shape = curveEditorG->addCurve();
shape = (DiagonalCurveEditor*)curveEditorG->addCurve(CT_Diagonal, "");
// This will add the reset button at the end of the curveType buttons
curveEditorG->curveListComplete();
@@ -95,7 +95,7 @@ ToneCurve::ToneCurve () : Gtk::VBox(), FoldableToolPanel(this), expAdd(false),hl
hlcomprthresh->setAdjusterListener (this);
shcompr->setAdjusterListener (this);
contrast->setAdjusterListener (this);
saturation->setAdjusterListener (this);
saturation->setAdjusterListener (this);
}
void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) {
@@ -394,6 +394,6 @@ void ToneCurve::setAdjusterBehavior (bool expadd, bool hlcompadd, bool hlcompthr
}
void ToneCurve::updateCurveBackgroundHistogram (unsigned* hist) {
shape->updateBackgroundHistogram (hist);
}

View File

@@ -44,7 +44,7 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public FoldableTool
bool expAdd,hlcompAdd,hlcompthreshAdd, blackAdd, shcompAdd, brAdd, contrAdd, satAdd, clipDirty, lastAuto;
sigc::connection autoconn;
CurveEditorGroup* curveEditorG;
CurveEditor* shape;
DiagonalCurveEditor* shape;
double nextBr;
int nextBl;

157
tools/FlatCurveType.svg Normal file
View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docname="FlatCurveType.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="D:\Jean-Christophe\Developpement\WorkspaceCPP\rawtherapee-branch_3.0\rtdata\images\curveType-controlPoints.png"
inkscape:export-xdpi="67.5"
inkscape:export-ydpi="67.5">
<defs
id="defs4">
<linearGradient
id="linearGradient3205">
<stop
style="stop-color:#000000;stop-opacity:0.19512194;"
offset="0"
id="stop3207" />
<stop
style="stop-color:#ffffff;stop-opacity:0.19607843;"
offset="1"
id="stop3209" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3205"
id="linearGradient3211"
x1="12"
y1="24"
x2="12"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0434783,0,0,1.0434783,119.47826,-40.521739)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3205"
id="linearGradient3176"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0434783,0,0,1.0434783,79.47826,-40.521739)"
x1="12"
y1="24"
x2="12"
y2="0" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3205"
id="linearGradient3180"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0434783,0,0,1.0434783,39.47826,-40.521739)"
x1="12"
y1="24"
x2="12"
y2="0" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3205"
id="linearGradient3184"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0434783,0,0,1.0434783,159.47826,-40.521739)"
x1="12"
y1="24"
x2="12"
y2="0" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#212121"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="8.032733"
inkscape:cx="-1.3159037"
inkscape:cy="14.490083"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1680"
inkscape:window-height="994"
inkscape:window-x="-4"
inkscape:window-y="-4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:nodetypes="cc"
id="path3279"
d="M 0.79395018,4.7393358 L 13.496704,4.7393358"
style="opacity:0.7;fill:none;fill-rule:evenodd;stroke:#76a400;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
style="opacity:0.7;fill:none;fill-rule:evenodd;stroke:#76a400;stroke-width:1.50000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 11.878553,17.486282 L 26.412099,17.486282"
id="path3167"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#be0000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M -1.029338,14.45208 C 4.449378,0.014494216 11.372085,4.2483768 12.654577,10.859506 C 13.872041,17.135416 21.405958,21.479387 25.362732,12.567088"
id="path3159"
sodipodi:nodetypes="csc" />
<path
sodipodi:nodetypes="cc"
id="path3183"
d="M -39.25,12.033931 L -16.750002,11.966069"
style="opacity:1;fill:none;fill-rule:evenodd;stroke:#be0000;stroke-width:1.49999988;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:type="arc"
style="fill:#76a400;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path3155"
sodipodi:cx="5.8999224"
sodipodi:cy="10.497826"
sodipodi:rx="1.1711456"
sodipodi:ry="1.1711456"
d="M 7.0710679,10.497826 A 1.1711456,1.1711456 0 1 1 4.7287768,10.497826 A 1.1711456,1.1711456 0 1 1 7.0710679,10.497826 z"
transform="matrix(2.7600806,0,0,2.7600806,2.861066,-11.488563)" />
<path
transform="matrix(2.7600806,0,0,2.7600806,-9.138934,-24.235509)"
d="M 7.0710679,10.497826 A 1.1711456,1.1711456 0 1 1 4.7287768,10.497826 A 1.1711456,1.1711456 0 1 1 7.0710679,10.497826 z"
sodipodi:ry="1.1711456"
sodipodi:rx="1.1711456"
sodipodi:cy="10.497826"
sodipodi:cx="5.8999224"
id="path3247"
style="fill:#76a400;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
sodipodi:type="arc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB