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:
BIN
rtdata/images/curveType-controlPoints.png
Normal file
BIN
rtdata/images/curveType-controlPoints.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 586 B |
BIN
rtdata/images/curveType-flatLinear.png
Normal file
BIN
rtdata/images/curveType-flatLinear.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 186 B |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
292
rtengine/diagonalcurves.cc
Normal 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
336
rtengine/flatcurves.cc
Normal 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]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
33
rtgui/colorprovider.h
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
474
rtgui/diagonalcurveeditorsubgroup.cc
Normal file
474
rtgui/diagonalcurveeditorsubgroup.cc
Normal 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);
|
||||
}
|
||||
}
|
||||
77
rtgui/diagonalcurveeditorsubgroup.h
Normal file
77
rtgui/diagonalcurveeditorsubgroup.h
Normal 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
|
||||
272
rtgui/flatcurveeditorsubgroup.cc
Normal file
272
rtgui/flatcurveeditorsubgroup.cc
Normal 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);
|
||||
}
|
||||
}*/
|
||||
59
rtgui/flatcurveeditorsubgroup.h
Normal file
59
rtgui/flatcurveeditorsubgroup.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
751
rtgui/mycurve.cc
751
rtgui/mycurve.cc
@@ -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 ();
|
||||
}
|
||||
|
||||
122
rtgui/mycurve.h
122
rtgui/mycurve.h
@@ -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
678
rtgui/mydiagonalcurve.cc
Normal 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
83
rtgui/mydiagonalcurve.h
Normal 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
1296
rtgui/myflatcurve.cc
Normal file
File diff suppressed because it is too large
Load Diff
135
rtgui/myflatcurve.h
Normal file
135
rtgui/myflatcurve.h
Normal 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
|
||||
@@ -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;;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
157
tools/FlatCurveType.svg
Normal 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 |
Reference in New Issue
Block a user