From c452ff20b8280baf94e8766351b227110f9039fb Mon Sep 17 00:00:00 2001 From: torger Date: Sun, 3 Nov 2013 09:39:04 +0100 Subject: [PATCH] Issue 1615: added graduated filter tool --- rtdata/languages/default | 15 +++ rtengine/improcfun.h | 7 +- rtengine/iptransform.cc | 178 +++++++++++++++++++++++++++++++++-- rtengine/procevents.h | 4 +- rtengine/procparams.cc | 31 ++++++ rtengine/procparams.h | 15 +++ rtengine/refreshmap.cc | 4 +- rtgui/CMakeLists.txt | 2 +- rtgui/addsetids.h | 6 +- rtgui/batchtoolpanelcoord.cc | 7 ++ rtgui/gradient.cc | 173 ++++++++++++++++++++++++++++++++++ rtgui/gradient.h | 38 ++++++++ rtgui/options.cc | 4 + rtgui/paramsedited.cc | 18 ++++ rtgui/paramsedited.h | 12 +++ rtgui/partialpastedlg.cc | 7 ++ rtgui/partialpastedlg.h | 3 +- rtgui/preferences.cc | 7 ++ rtgui/toolpanelcoord.cc | 2 + rtgui/toolpanelcoord.h | 2 + 20 files changed, 518 insertions(+), 17 deletions(-) create mode 100644 rtgui/gradient.cc create mode 100644 rtgui/gradient.h diff --git a/rtdata/languages/default b/rtdata/languages/default index bc446c6f9..200e8bde8 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -443,6 +443,8 @@ HISTORY_MSG_205;CAM02 hot/bad pixels HISTORY_MSG_206;CAT02 - Adapt scene auto HISTORY_MSG_207;Defringing Hue curve HISTORY_MSG_208;Blue/Red Equalizer +HISTORY_MSG_210;Gradient Filter +HISTORY_MSG_211;Gradient Filter HISTORY_NEWSNAPSHOTAS;As... HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s @@ -633,6 +635,7 @@ PARTIALPASTE_DIALOGLABEL;Partial paste processing profile PARTIALPASTE_DIRPYRDENOISE;Noise reduction PARTIALPASTE_DIRPYREQUALIZER;Contrast by detail levels PARTIALPASTE_DISTORTION;Distortion correction +PARTIALPASTE_GRADIENT;Graduated Filter PARTIALPASTE_EPD;Tone mapping PARTIALPASTE_EVERYTHING;Everything PARTIALPASTE_EXIFCHANGES;Changes to Exif data @@ -1301,6 +1304,18 @@ TP_VIGNETTING_CENTER_Y;Center Y TP_VIGNETTING_LABEL;Vignetting Correction TP_VIGNETTING_RADIUS;Radius TP_VIGNETTING_STRENGTH;Strength +TP_GRADIENT_DEGREE;Angle +TP_GRADIENT_CENTER;Center +TP_GRADIENT_CENTER_X;Center X +TP_GRADIENT_CENTER_Y;Center Y +TP_GRADIENT_LABEL;Graduated Filter +TP_GRADIENT_FEATHER;Feather +TP_GRADIENT_STRENGTH;Strength +TP_GRADIENT_DEGREE_TOOLTIP;Rotation angle in degrees +TP_GRADIENT_CENTER_X_TOOLTIP;Rotation anchor point X: -100=left edge, 0=center, +100=right edge +TP_GRADIENT_CENTER_Y_TOOLTIP;Rotation anchor point Y: -100=top edge, 0=center, +100=bottom edge +TP_GRADIENT_FEATHER_TOOLTIP;Gradient width in percent of the image diagonal +TP_GRADIENT_STRENGTH_TOOLTIP;Filter strength in stops TP_WBALANCE_AUTO;Auto TP_WBALANCE_CAMERA;Camera TP_WBALANCE_CLOUDY;Cloudy diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index ff4950331..d9125549b 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -51,9 +51,9 @@ class ImProcFunctions { void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); - void transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap); - void transformVignetteOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH); - void transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap, bool fullImage); + void transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap); + void transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH); + void transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap, bool fullImage); void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H); void sharpenHaloCtrlcam (CieImage* ncie, float** blurmap, float** base, int W, int H); @@ -64,6 +64,7 @@ class ImProcFunctions { bool needsDistortion (); bool needsRotation (); bool needsPerspective (); + bool needsGradient (); bool needsVignetting (); bool needsLCP (); // static cmsUInt8Number* Mempro = NULL; diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index 911c8ed1a..6a3f0144f 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -211,8 +211,8 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, original->width, original->height, params->coarse, rawRotationDeg); } - if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && needsVignetting()) - transformVignetteOnly (original, transformed, cx, cy, oW, oH); + if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && (needsVignetting() || needsGradient())) + transformLuminanceOnly (original, transformed, cx, cy, oW, oH); else if (!needsCA() && scale!=1) transformPreview (original, transformed, cx, cy, sx, sy, oW, oH, pLCPMap); else @@ -241,11 +241,146 @@ void ImProcFunctions::calcVignettingParams(int oW, int oH, const VignettingParam mul = (1.0-v) / tanh(b); } +struct grad_params { + bool angle_is_zero, transpose, bright_top; + float ta, yc, xc; + float ys, ys_inv; + float scale, botmul, topmul; + float gamma; + float top_edge_0; + int h; +}; +static void calcGradientParams(int oW, int oH, const GradientParams& gradient, struct grad_params& gp) +{ + int w = oW; + int h = oH; + double gradient_stops = gradient.strength; + double gradient_span = gradient.feather / 100.0; + double gradient_center_x = gradient.centerX / 200.0 + 0.5; + double gradient_center_y = gradient.centerY / 200.0 + 0.5; + double gradient_angle = gradient.degree / 180.0 * M_PI; + //fprintf(stderr, "%f %f %f %f %f %d %d\n", gradient_stops, gradient_span, gradient_center_x, gradient_center_y, gradient_angle, w, h); + + // make 0.0 <= gradient_angle < 2 * M_PI + gradient_angle = fmod(gradient_angle, 2 * M_PI); + if (gradient_angle < 0.0) { + gradient_angle += 2.0 * M_PI; + } + + gp.bright_top = false; + gp.transpose = false; + gp.angle_is_zero = false; + gp.h = h; + double cosgrad = cos(gradient_angle); + if (fabs(cosgrad) < 0.707) { + // we transpose to avoid division by zero at 90 degrees + // (actually we could transpose only for 90 degrees, but this way we avoid + // division with extremely small numbers + gp.transpose = true; + gradient_angle += 0.5 * M_PI; + cosgrad = cos(gradient_angle); + double gxc = gradient_center_x; + gradient_center_x = 1.0 - gradient_center_y; + gradient_center_y = gxc; + } + gradient_angle = fmod(gradient_angle, 2 * M_PI); + if (gradient_angle > 0.5 * M_PI && gradient_angle < M_PI) { + gradient_angle += M_PI; + gp.bright_top = true; + } else if (gradient_angle >= M_PI && gradient_angle < 1.5 * M_PI) { + gradient_angle -= M_PI; + gp.bright_top = true; + } + if (fabs(gradient_angle) < 0.001 || fabs(gradient_angle - 2 * M_PI) < 0.001) { + gradient_angle = 0; + gp.angle_is_zero = true; + } + if (gp.transpose) { + gp.bright_top = !gp.bright_top; + } + float *grad = (float *)malloc(w * h * sizeof(float)); + if (gp.transpose) { + int tmp = w; + w = h; + h = tmp; + } + gp.scale = 1.0 / pow(2, gradient_stops); + if (gp.bright_top) { + gp.topmul = 1.0; + gp.botmul = gp.scale; + } else { + gp.topmul = gp.scale; + gp.botmul = 1.0; + } + gp.ta = tan(gradient_angle); + gp.xc = w * gradient_center_x; + gp.yc = h * gradient_center_y; + gp.ys = sqrt((float)h * h + (float)w * w) * (gradient_span / cos(gradient_angle)); + gp.ys_inv = 1.0 / gp.ys; + gp.top_edge_0 = gp.yc - gp.ys/2.0; + if (gp.ys < 1.0 / h) { + gp.ys_inv = 0; + gp.ys = 0; + } + gp.gamma = 1.5; // tested to be "visually pleasing" +} + +static float calcGradientFactor(const struct grad_params& gp, int x, int y) { + if (gp.angle_is_zero) { + int gy = gp.transpose ? x : y; + int gx = gp.transpose ? y : x; + if (gy < gp.top_edge_0) { + return gp.topmul; + } else if (gy >= gp.top_edge_0 + gp.ys) { + return gp.botmul; + } else { + float val = ((float)(gy - gp.top_edge_0) * gp.ys_inv); + if (gp.bright_top) { + val = 1.0 - val; + } + val = 2 * val - 1.0; // adjust range to -1 to 1 + val = 0.5 * (3 * val - powf(val, 3)); // s-curve + val = 0.5 * (1.0 + val); // adjust range back to 0 to 1 + val = powf(val, gp.gamma); // apply gamma + return gp.scale + val * (1.0 - gp.scale); + } + } else { + int gy = gp.transpose ? x : y; + int gx = gp.transpose ? gp.h - y - 1 : x; + float top_edge = gp.yc - gp.ys/2.0 - gp.ta * (gx - gp.xc); + if (gy < top_edge) { + return gp.topmul; + } else if (gy >= top_edge + gp.ys) { + return gp.botmul; + } else { + float val = ((float)(gy - top_edge) * gp.ys_inv); + if (gp.bright_top) { + val = 1.0 - val; + } + val = 2 * val - 1.0; + val = 0.5 * (3 * val - powf(val, 3)); + val = 0.5 * (1.0 + val); + val = powf(val, gp.gamma); + return gp.scale + val * (1.0 - gp.scale); + } + } +} + // Transform vignetting only -void ImProcFunctions::transformVignetteOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH) { +void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH) { + + const bool applyVignetting = needsVignetting(); + const bool applyGradient = needsGradient(); double vig_w2, vig_h2, maxRadius, v, b, mul; - calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); + if (applyVignetting) { + calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); + } + + struct grad_params gp; + if (applyGradient) { + calcGradientParams(transformed->width, transformed->height, params->gradient, gp); + } #pragma omp parallel for if (multiThread) for (int y=0; yheight; y++) { @@ -253,10 +388,16 @@ void ImProcFunctions::transformVignetteOnly (Imagefloat* original, Imagefloat* t for (int x=0; xwidth; x++) { double vig_x_d = (double) (x + cx) - vig_w2 ; double r = sqrt(vig_x_d*vig_x_d + vig_y_d*vig_y_d); - double vign = std::max(v + mul * tanh (b*(maxRadius-r) / maxRadius), 0.001); - transformed->r(y,x) = original->r(y,x) / vign; - transformed->g(y,x) = original->g(y,x) / vign; - transformed->b(y,x) = original->b(y,x) / vign; + double mul = 1.0; + if (applyVignetting) { + mul /= std::max(v + mul * tanh (b*(maxRadius-r) / maxRadius), 0.001); + } + if (applyGradient) { + mul *= calcGradientFactor(gp, x, y); + } + transformed->r(y,x) = original->r(y,x) * mul; + transformed->g(y,x) = original->g(y,x) * mul; + transformed->b(y,x) = original->b(y,x) * mul; } } } @@ -274,6 +415,11 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr double vig_w2,vig_h2,maxRadius,v,b,mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); + struct grad_params gp; + if (needsGradient()) { + calcGradientParams(transformed->width, transformed->height, params->gradient, gp); + } + float** chOrig[3]; chOrig[0] = original->r.ptrs; chOrig[1] = original->g.ptrs; @@ -385,6 +531,9 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr double vignmul = 1.0; if (needsVignetting()) vignmul /= std::max(v + mul * tanh (b*(maxRadius-s*r2) / maxRadius), 0.001); + if (needsGradient()) { + vignmul *= calcGradientFactor(gp, x, y); + } if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) { // all interpolation pixels inside image @@ -432,6 +581,11 @@ void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transf double vig_w2, vig_h2, maxRadius, v, b, mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); + struct grad_params gp; + if (needsGradient()) { + calcGradientParams(transformed->width, transformed->height, params->gradient, gp); + } + // auxiliary variables for distortion correction bool needsDist = needsDistortion(); // for performance double distAmount = params->distortion.amount; @@ -514,6 +668,8 @@ void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transf double vignmul = 1.0; if (needsVignetting()) vignmul /= std::max(v + mul * tanh (b*(maxRadius-s*r2) / maxRadius), 0.001); + if (needsGradient()) + vignmul *= calcGradientFactor(gp, x, y); if (yc < original->height-1 && xc < original->width-1) { // all interpolation pixels inside image @@ -579,6 +735,10 @@ bool ImProcFunctions::needsPerspective () { return params->perspective.horizontal || params->perspective.vertical; } +bool ImProcFunctions::needsGradient () { + return params->gradient.enabled && fabs(params->gradient.strength) > 1e-15; +} + bool ImProcFunctions::needsVignetting () { return params->vignetting.amount; } @@ -588,7 +748,7 @@ bool ImProcFunctions::needsLCP () { } bool ImProcFunctions::needsTransform () { - return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsVignetting () || needsLCP(); + return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsVignetting () || needsLCP(); } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 20e8dac38..bb3d02ace 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -232,7 +232,9 @@ enum ProcEvent { EvPFCurve=206, EvWBequal=207, EvWBequalbo=208, - NUMOFEVENTS=209 + EvGradient=209, + EvGradientEnabled=210, + NUMOFEVENTS=211 }; } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 11ee198b7..e1ae6ff34 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -331,6 +331,13 @@ void ProcParams::setDefaults () { perspective.horizontal = 0; perspective.vertical = 0; + gradient.enabled = false; + gradient.degree = 0; + gradient.feather = 25; + gradient.strength = 0; + gradient.centerX = 0; + gradient.centerY = 0; + cacorrection.red = 0; cacorrection.blue = 0; @@ -823,6 +830,14 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol if (!pedited || pedited->perspective.horizontal) keyFile.set_double ("Perspective", "Horizontal", perspective.horizontal); if (!pedited || pedited->perspective.vertical) keyFile.set_double ("Perspective", "Vertical", perspective.vertical); + // save gradient + if (!pedited || pedited->gradient.enabled) keyFile.set_boolean ("Gradient", "Enabled", gradient.enabled); + if (!pedited || pedited->gradient.degree) keyFile.set_double ("Gradient", "Degree", gradient.degree); + if (!pedited || pedited->gradient.feather) keyFile.set_integer ("Gradient", "Feather", gradient.feather); + if (!pedited || pedited->gradient.strength) keyFile.set_double ("Gradient", "Strength", gradient.strength); + if (!pedited || pedited->gradient.centerX) keyFile.set_integer ("Gradient", "CenterX", gradient.centerX); + if (!pedited || pedited->gradient.centerY) keyFile.set_integer ("Gradient", "CenterY", gradient.centerY); + // save C/A correction if (!pedited || pedited->cacorrection.red) keyFile.set_double ("CACorrection", "Red", cacorrection.red); if (!pedited || pedited->cacorrection.blue) keyFile.set_double ("CACorrection", "Blue", cacorrection.blue); @@ -1368,6 +1383,16 @@ if (keyFile.has_group ("Perspective")) { if (keyFile.has_key ("Perspective", "Vertical")) { perspective.vertical = keyFile.get_double ("Perspective", "Vertical"); if (pedited) pedited->perspective.vertical = true; } } + // load gradient +if (keyFile.has_group ("Gradient")) { + if (keyFile.has_key ("Gradient", "Enabled")) { gradient.enabled = keyFile.get_boolean ("Gradient", "Enabled"); if (pedited) pedited->gradient.enabled = true; } + if (keyFile.has_key ("Gradient", "Degree")) { gradient.degree = keyFile.get_double ("Gradient", "Degree"); if (pedited) pedited->gradient.degree = true; } + if (keyFile.has_key ("Gradient", "Feather")) { gradient.feather = keyFile.get_integer ("Gradient", "Feather"); if (pedited) pedited->gradient.feather = true; } + if (keyFile.has_key ("Gradient", "Strength")) { gradient.strength = keyFile.get_double ("Gradient", "Strength");if (pedited) pedited->gradient.strength = true; } + if (keyFile.has_key ("Gradient", "CenterX")) { gradient.centerX = keyFile.get_integer ("Gradient", "CenterX"); if (pedited) pedited->gradient.centerX = true; } + if (keyFile.has_key ("Gradient", "CenterY")) { gradient.centerY = keyFile.get_integer ("Gradient", "CenterY"); if (pedited) pedited->gradient.centerY = true; } +} + // load c/a correction if (keyFile.has_group ("CACorrection")) { if (keyFile.has_key ("CACorrection", "Red")) { cacorrection.red = keyFile.get_double ("CACorrection", "Red"); if (pedited) pedited->cacorrection.red = true; } @@ -1703,6 +1728,12 @@ bool ProcParams::operator== (const ProcParams& other) { && lensProf.useCA == other.lensProf.useCA && perspective.horizontal == other.perspective.horizontal && perspective.vertical == other.perspective.vertical + && gradient.enabled == other.gradient.enabled + && gradient.degree == other.gradient.degree + && gradient.feather == other.gradient.feather + && gradient.strength == other.gradient.strength + && gradient.centerX == other.gradient.centerX + && gradient.centerY == other.gradient.centerY && cacorrection.red == other.cacorrection.red && cacorrection.blue == other.cacorrection.blue && vignetting.amount == other.vignetting.amount diff --git a/rtengine/procparams.h b/rtengine/procparams.h index ea240b58d..627cd25c7 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -576,6 +576,20 @@ class PerspectiveParams { double vertical; }; +/** + * Parameters of the gradient filter + */ +class GradientParams { + + public: + bool enabled; + double degree; + int feather; + double strength; + int centerX; + int centerY; +}; + /** * Parameters of the vignetting correction */ @@ -771,6 +785,7 @@ class ProcParams { DistortionParams distortion; ///< Lens distortion correction parameters LensProfParams lensProf; ///< Lens correction profile parameters PerspectiveParams perspective; ///< Perspective correction parameters + GradientParams gradient; ///< Gradient filter parameters CACorrParams cacorrection; ///< Lens c/a correction parameters VignettingParams vignetting; ///< Lens vignetting correction parameters ChannelMixerParams chmixer; ///< Channel mixer parameters diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index e39d9da85..b132796e7 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -228,7 +228,9 @@ LUMINANCECURVE, // EvCATbadpix LUMINANCECURVE, // EvCATAutoadap DEFRINGE, // EvPFCurve, WHITEBALANCE, // EvWBequal, -WHITEBALANCE // EvWBequalbo, +WHITEBALANCE, // EvWBequalbo, +TRANSFORM, // EvGradient +TRANSFORM // EvGradientEnabled //LUMINANCECURVE // EvCATsharpcie diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 62a99bc71..55d3372a5 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -10,7 +10,7 @@ set (BASESOURCEFILES impulsedenoise.cc dirpyrdenoise.cc epd.cc exifpanel.cc toolpanel.cc lensprofile.cc sharpening.cc vibrance.cc rgbcurves.cc - whitebalance.cc vignetting.cc rotate.cc distortion.cc + whitebalance.cc vignetting.cc gradient.cc rotate.cc distortion.cc crophandler.cc dirbrowser.cc curveeditor.cc curveeditorgroup.cc diagonalcurveeditorsubgroup.cc flatcurveeditorsubgroup.cc filecatalog.cc extprog.cc diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 004f49c9d..37ad71d1c 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -66,8 +66,12 @@ #define ADDSET_CAT_HUE 58 #define ADDSET_CAT_BADPIX 59 #define ADDSET_WB_EQUAL 60 +#define ADDSET_GRADIENT_DEGREE 61 +#define ADDSET_GRADIENT_FEATHER 62 +#define ADDSET_GRADIENT_STRENGTH 63 +#define ADDSET_GRADIENT_CENTER 64 // When adding items, make sure to update ADDSET_PARAM_NUM -#define ADDSET_PARAM_NUM 61 // THIS IS USED AS A DELIMITER!! +#define ADDSET_PARAM_NUM 65 // THIS IS USED AS A DELIMITER!! #endif diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 311d52efb..7319baddb 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -133,6 +133,7 @@ void BatchToolPanelCoordinator::initSession () { rotate->setAdjusterBehavior (false); distortion->setAdjusterBehavior (false); perspective->setAdjusterBehavior (false); + gradient->setAdjusterBehavior (false, false, false, false); cacorrection->setAdjusterBehavior (false); sharpening->setAdjusterBehavior (false); sharpenEdge->setAdjusterBehavior (false, false); @@ -160,6 +161,7 @@ void BatchToolPanelCoordinator::initSession () { rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]); distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); perspective->setAdjusterBehavior (options.baBehav[ADDSET_PERSPECTIVE]); + gradient->setAdjusterBehavior (options.baBehav[ADDSET_GRADIENT_DEGREE], options.baBehav[ADDSET_GRADIENT_FEATHER], options.baBehav[ADDSET_GRADIENT_STRENGTH], options.baBehav[ADDSET_GRADIENT_CENTER]); cacorrection->setAdjusterBehavior (options.baBehav[ADDSET_CA]); sharpening->setAdjusterBehavior (options.baBehav[ADDSET_SHARP_AMOUNT]); sharpenEdge->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT],options.baBehav[ADDSET_SHARPENEDGE_PASS]); @@ -231,6 +233,11 @@ void BatchToolPanelCoordinator::initSession () { if (options.baBehav[ADDSET_ROTATE_DEGREE]) pparams.rotate.degree = 0; if (options.baBehav[ADDSET_DIST_AMOUNT]) pparams.distortion.amount = 0; if (options.baBehav[ADDSET_PERSPECTIVE]) pparams.perspective.horizontal = pparams.perspective.vertical = 0; + if (options.baBehav[ADDSET_GRADIENT_DEGREE]) pparams.gradient.degree = 0; + if (options.baBehav[ADDSET_GRADIENT_FEATHER]) pparams.gradient.feather = 0; + if (options.baBehav[ADDSET_GRADIENT_STRENGTH]) pparams.gradient.strength = 0; + if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerX = 0; + if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerY = 0; if (options.baBehav[ADDSET_CA]) pparams.cacorrection.red = 0; if (options.baBehav[ADDSET_CA]) pparams.cacorrection.blue = 0; if (options.baBehav[ADDSET_VIGN_AMOUNT]) pparams.vignetting.amount = 0; diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc new file mode 100644 index 000000000..48d605507 --- /dev/null +++ b/rtgui/gradient.cc @@ -0,0 +1,173 @@ +/* + * This file is part of RawTherapee. + */ +#include "gradient.h" +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +Gradient::Gradient () : Gtk::VBox(), FoldableToolPanel(this) +{ + set_border_width(4); + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (false); + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &Gradient::enabledChanged) ); + + strength = Gtk::manage (new Adjuster (M("TP_GRADIENT_STRENGTH"), -5, 5, 0.01, 0)); + strength->set_tooltip_text (M("TP_GRADIENT_STRENGTH_TOOLTIP")); + strength->setAdjusterListener (this); + + degree = Gtk::manage (new Adjuster (M("TP_GRADIENT_DEGREE"), -180, 180, 1, 0)); + degree->set_tooltip_text (M("TP_GRADIENT_DEGREE_TOOLTIP")); + degree->setAdjusterListener (this); + + feather = Gtk::manage (new Adjuster (M("TP_GRADIENT_FEATHER"), 0, 100, 1, 25)); + feather->set_tooltip_text (M("TP_GRADIENT_FEATHER_TOOLTIP")); + feather->setAdjusterListener (this); + + centerX = Gtk::manage (new Adjuster (M("TP_GRADIENT_CENTER_X"), -100, 100, 1, 0)); + centerX->set_tooltip_text (M("TP_GRADIENT_CENTER_X_TOOLTIP")); + centerX->setAdjusterListener (this); + + centerY = Gtk::manage (new Adjuster (M("TP_GRADIENT_CENTER_Y"), -100, 100, 1, 0)); + centerY->set_tooltip_text (M("TP_GRADIENT_CENTER_Y_TOOLTIP")); + centerY->setAdjusterListener (this); + + pack_start(*enabled); + pack_start(*Gtk::manage (new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET, 4); + pack_start (*strength); + pack_start (*degree); + pack_start (*feather); + pack_start (*centerX); + pack_start (*centerY); + + show_all(); +} + +void Gradient::read (const ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + + if (pedited) { + degree->setEditedState (pedited->gradient.degree ? Edited : UnEdited); + feather->setEditedState (pedited->gradient.feather ? Edited : UnEdited); + strength->setEditedState (pedited->gradient.strength ? Edited : UnEdited); + centerX->setEditedState (pedited->gradient.centerX ? Edited : UnEdited); + centerY->setEditedState (pedited->gradient.centerY ? Edited : UnEdited); + enabled->set_inconsistent (!pedited->gradient.enabled); + } + + enaConn.block (true); + enabled->set_active (pp->gradient.enabled); + enaConn.block (false); + degree->setValue (pp->gradient.degree); + feather->setValue (pp->gradient.feather); + strength->setValue (pp->gradient.strength); + centerX->setValue (pp->gradient.centerX); + centerY->setValue (pp->gradient.centerY); + + lastEnabled = pp->gradient.enabled; + + enableListener (); +} + +void Gradient::write (ProcParams* pp, ParamsEdited* pedited) +{ + pp->gradient.degree = degree->getValue (); + pp->gradient.feather = (int)feather->getValue (); + pp->gradient.strength = strength->getValue (); + pp->gradient.centerX = (int)centerX->getValue (); + pp->gradient.centerY = (int)centerY->getValue (); + pp->gradient.enabled = enabled->get_active(); + + if (pedited) { + pedited->gradient.degree = degree->getEditedState (); + pedited->gradient.feather = feather->getEditedState (); + pedited->gradient.strength = strength->getEditedState (); + pedited->gradient.centerX = centerX->getEditedState (); + pedited->gradient.centerY = centerY->getEditedState (); + pedited->gradient.enabled = !enabled->get_inconsistent(); + } +} + +void Gradient::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) +{ + degree->setDefault (defParams->gradient.degree); + feather->setDefault (defParams->gradient.feather); + strength->setDefault (defParams->gradient.strength); + centerX->setDefault (defParams->gradient.centerX); + centerY->setDefault (defParams->gradient.centerY); + + if (pedited) { + degree->setDefaultEditedState (pedited->gradient.degree ? Edited : UnEdited); + feather->setDefaultEditedState (pedited->gradient.feather ? Edited : UnEdited); + strength->setDefaultEditedState (pedited->gradient.strength ? Edited : UnEdited); + centerX->setDefaultEditedState (pedited->gradient.centerX ? Edited : UnEdited); + centerY->setDefaultEditedState (pedited->gradient.centerY ? Edited : UnEdited); + } else { + degree->setDefaultEditedState (Irrelevant); + feather->setDefaultEditedState (Irrelevant); + strength->setDefaultEditedState (Irrelevant); + centerX->setDefaultEditedState (Irrelevant); + centerY->setDefaultEditedState (Irrelevant); + } +} + +void Gradient::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + listener->panelChanged (EvGradient, Glib::ustring::compose ("%1=%5\n%2=%6\n%3=%7\n%4=%8 %9", M("TP_GRADIENT_DEGREE"), M("TP_GRADIENT_FEATHER"), M("TP_GRADIENT_STRENGTH"), M("TP_GRADIENT_CENTER"), degree->getValue(), (int)feather->getValue(), strength->getValue(), (int)centerX->getValue(), (int)centerY->getValue())); + } +} + +void Gradient::enabledChanged () { + + 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 (); + } + if (listener) { + if (enabled->get_active()) + listener->panelChanged (EvGradientEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvGradientEnabled, M("GENERAL_DISABLED")); + } +} + +void Gradient::setAdjusterBehavior (bool degreeadd, bool featheradd, bool strengthadd, bool centeradd) +{ + degree->setAddMode(degreeadd); + feather->setAddMode(featheradd); + strength->setAddMode(strengthadd); + centerX->setAddMode(centeradd); + centerY->setAddMode(centeradd); +} + +void Gradient::trimValues (rtengine::procparams::ProcParams* pp) +{ + degree->trimValue(pp->gradient.degree); + feather->trimValue(pp->gradient.feather); + strength->trimValue(pp->gradient.strength); + centerX->trimValue(pp->gradient.centerX); + centerY->trimValue(pp->gradient.centerY); +} + +void Gradient::setBatchMode (bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + degree->showEditedCB (); + feather->showEditedCB (); + strength->showEditedCB (); + centerX->showEditedCB (); + centerY->showEditedCB (); +} diff --git a/rtgui/gradient.h b/rtgui/gradient.h new file mode 100644 index 000000000..7b46b773f --- /dev/null +++ b/rtgui/gradient.h @@ -0,0 +1,38 @@ +/* + * This file is part of RawTherapee. + */ +#ifndef _GRADIENT_H_ +#define _GRADIENT_H_ + +#include +#include "adjuster.h" +#include "toolpanel.h" + +class Gradient : public Gtk::VBox, public AdjusterListener, public FoldableToolPanel { + + protected: + Gtk::CheckButton* enabled; + Adjuster* degree; + Adjuster* feather; + Adjuster* strength; + Adjuster* centerX; + Adjuster* centerY; + bool lastEnabled; + sigc::connection enaConn; + + public: + + Gradient (); + + 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 setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void enabledChanged (); + void setAdjusterBehavior (bool degreeadd, bool featheradd, bool strengthadd, bool centeradd); + void trimValues (rtengine::procparams::ProcParams* pp); +}; + +#endif diff --git a/rtgui/options.cc b/rtgui/options.cc index df53b7ed7..0dd0a2de4 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -452,6 +452,10 @@ void Options::setDefaults () { 0, // ADDSET_CAT_CHROMA 0, // ADDSET_CAT_CONTRAST 0, // ADDSET_WB_EQUAL + 0, // ADDSET_GRADIENT_AMOUNT + 0, // ADDSET_GRADIENT_RADIUS + 0, // ADDSET_GRADIENT_STRENGTH + 0, // ADDSET_GRADIENT_CENTER }; baBehav = std::vector (babehav, babehav+ADDSET_PARAM_NUM); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 6606f51b9..62f5b27b8 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -190,6 +190,12 @@ void ParamsEdited::set (bool v) { lensProf.useCA = v; perspective.horizontal = v; perspective.vertical = v; + gradient.enabled = v; + gradient.degree = v; + gradient.feather = v; + gradient.strength = v; + gradient.centerX = v; + gradient.centerY = v; cacorrection.red = v; cacorrection.blue = v; vignetting.amount = v; @@ -438,6 +444,12 @@ void ParamsEdited::initFrom (const std::vector lensProf.useCA = lensProf.useCA && p.lensProf.useCA == other.lensProf.useCA; perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal; perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical; + gradient.enabled = gradient.enabled && p.gradient.enabled == other.gradient.enabled; + gradient.degree = gradient.degree && p.gradient.degree == other.gradient.degree; + gradient.feather = gradient.feather && p.gradient.feather == other.gradient.feather; + gradient.strength = gradient.strength && p.gradient.strength == other.gradient.strength; + gradient.centerX = gradient.centerX && p.gradient.centerX == other.gradient.centerX; + gradient.centerY = gradient.centerY && p.gradient.centerY == other.gradient.centerY; cacorrection.red = cacorrection.red && p.cacorrection.red == other.cacorrection.red; cacorrection.blue = cacorrection.blue && p.cacorrection.blue == other.cacorrection.blue; vignetting.amount = vignetting.amount && p.vignetting.amount == other.vignetting.amount; @@ -693,6 +705,12 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (perspective.horizontal) toEdit.perspective.horizontal = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.horizontal + mods.perspective.horizontal : mods.perspective.horizontal; if (perspective.vertical) toEdit.perspective.vertical = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vertical + mods.perspective.vertical : mods.perspective.vertical; + if (gradient.enabled) toEdit.gradient.enabled = mods.gradient.enabled; + if (gradient.degree) toEdit.gradient.degree = dontforceSet && options.baBehav[ADDSET_GRADIENT_DEGREE] ? toEdit.gradient.degree + mods.gradient.degree : mods.gradient.degree; + if (gradient.feather) toEdit.gradient.feather = mods.gradient.feather; + if (gradient.strength) toEdit.gradient.strength = mods.gradient.strength; + if (gradient.centerX) toEdit.gradient.centerX = mods.gradient.centerX; + if (gradient.centerY) toEdit.gradient.centerY = mods.gradient.centerY; if (cacorrection.red) toEdit.cacorrection.red = dontforceSet && options.baBehav[ADDSET_CA] ? toEdit.cacorrection.red + mods.cacorrection.red : mods.cacorrection.red; if (cacorrection.blue) toEdit.cacorrection.blue = dontforceSet && options.baBehav[ADDSET_CA] ? toEdit.cacorrection.blue + mods.cacorrection.blue : mods.cacorrection.blue; if (vignetting.amount) toEdit.vignetting.amount = dontforceSet && options.baBehav[ADDSET_VIGN_AMOUNT] ? toEdit.vignetting.amount + mods.vignetting.amount : mods.vignetting.amount; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 2897a51e3..d9b7bca78 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -313,6 +313,17 @@ class PerspectiveParamsEdited { bool vertical; }; +class GradientParamsEdited { + + public: + bool enabled; + bool degree; + bool feather; + bool strength; + bool centerX; + bool centerY; +}; + class VignettingParamsEdited { public: @@ -450,6 +461,7 @@ class ParamsEdited { DistortionParamsEdited distortion; LensProfParamsEdited lensProf; PerspectiveParamsEdited perspective; + GradientParamsEdited gradient; CACorrParamsEdited cacorrection; VignettingParamsEdited vignetting; ChannelMixerParamsEdited chmixer; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 0fb14c9bc..cf66e73be 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -49,6 +49,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { hlrec = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_HLRECONSTRUCTION"))); sh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHADOWSHIGHLIGHTS"))); epd = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EPD"))); + gradient = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_GRADIENT"))); labcurve = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LABCURVE"))); colorappearance= Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORAPP"))); // options in detail: @@ -126,6 +127,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { vboxes[0]->pack_start (*hlrec, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*sh, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*epd, Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*gradient, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*labcurve, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*colorappearance, Gtk::PACK_SHRINK, 2); @@ -246,6 +248,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { hlrecConn = hlrec->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); shConn = sh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); epdConn = epd->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); + gradientConn = gradient->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); labcurveConn = labcurve->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); colorappearanceConn=colorappearance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); @@ -427,6 +430,7 @@ void PartialPasteDlg::basicToggled () { hlrecConn.block (true); shConn.block (true); epdConn.block(true); + gradientConn.block (true); labcurveConn.block (true); colorappearanceConn.block (true); @@ -437,6 +441,7 @@ void PartialPasteDlg::basicToggled () { hlrec->set_active (basic->get_active ()); sh->set_active (basic->get_active ()); epd->set_active (basic->get_active ()); + gradient->set_active (basic->get_active ()); labcurve->set_active (basic->get_active ()); colorappearance->set_active (basic->get_active ()); @@ -445,6 +450,7 @@ void PartialPasteDlg::basicToggled () { hlrecConn.block (false); shConn.block (false); epdConn.block (false); + gradientConn.block (false); labcurveConn.block (false); colorappearanceConn.block (false); } @@ -598,6 +604,7 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!hlrec->get_active ()) filterPE.hlrecovery = falsePE.hlrecovery; if (!sh->get_active ()) filterPE.sh = falsePE.sh; if (!epd->get_active ()) filterPE.edgePreservingDecompositionUI = falsePE.edgePreservingDecompositionUI; + if (!gradient->get_active ()) filterPE.gradient = falsePE.gradient; if (!labcurve->get_active ()) filterPE.labCurve = falsePE.labCurve; if (!colorappearance->get_active ()) filterPE.colorappearance= falsePE.colorappearance; diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 68512fefe..d100ec881 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -43,6 +43,7 @@ class PartialPasteDlg : public Gtk::Dialog { Gtk::CheckButton* hlrec; Gtk::CheckButton* sh; Gtk::CheckButton* epd; + Gtk::CheckButton* gradient; Gtk::CheckButton* labcurve; Gtk::CheckButton* colorappearance; @@ -109,7 +110,7 @@ class PartialPasteDlg : public Gtk::Dialog { sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaicmConn, rawConn; - sigc::connection wbConn, exposureConn, hlrecConn, shConn, labcurveConn, colorappearanceConn; + sigc::connection wbConn, exposureConn, hlrecConn, shConn, gradientConn, labcurveConn, colorappearanceConn; sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, waveqConn, defringeConn, epdConn, dirpyreqConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 09bdb07de..f368d6ac9 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -248,6 +248,13 @@ Gtk::Widget* Preferences::getBatchProcPanel () { mi->set_value (behavColumns.label, M("TP_PERSPECTIVE_LABEL")); appendBehavList (mi, M("TP_PERSPECTIVE_HORIZONTAL")+", "+M("TP_PERSPECTIVE_VERTICAL"), ADDSET_PERSPECTIVE, false); + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_GRADIENT_LABEL")); + appendBehavList (mi, M("TP_GRADIENT_DEGREE"), ADDSET_GRADIENT_DEGREE, false); + appendBehavList (mi, M("TP_GRADIENT_FEATHER"), ADDSET_GRADIENT_FEATHER, false); + appendBehavList (mi, M("TP_GRADIENT_STRENGTH"), ADDSET_GRADIENT_STRENGTH, false); + appendBehavList (mi, M("TP_GRADIENT_CENTER_X")+", "+M("TP_GRADIENT_CENTER_Y"), ADDSET_GRADIENT_CENTER, false); + mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_CACORRECTION_LABEL")); appendBehavList (mi, M("TP_CACORRECTION_BLUE")+", "+M("TP_CACORRECTION_RED"), ADDSET_CA, true); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 3c163b994..5604bcc56 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -59,6 +59,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { colorappearance = Gtk::manage (new ColorAppearance ()); whitebalance = Gtk::manage (new WhiteBalance ()); vignetting = Gtk::manage (new Vignetting ()); + gradient = Gtk::manage (new Gradient ()); perspective = Gtk::manage (new PerspCorrection ()); cacorrection = Gtk::manage (new CACorrection ()); hlrecovery = Gtk::manage (new HLRecovery ()); @@ -89,6 +90,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { addPanel (colorPanel, hsvequalizer, M("TP_HSVEQUALIZER_LABEL")); toolPanels.push_back (hsvequalizer); addPanel (colorPanel, rgbcurves, M("TP_RGBCURVES_LABEL")); toolPanels.push_back (rgbcurves); addPanel (exposurePanel, edgePreservingDecompositionUI, M("TP_EPD_LABEL")); toolPanels.push_back (edgePreservingDecompositionUI); + addPanel (exposurePanel, gradient, M("TP_GRADIENT_LABEL")); toolPanels.push_back (gradient); addPanel (exposurePanel, lcurve, M("TP_LABCURVE_LABEL")); toolPanels.push_back (lcurve); // addPanel (exposurePanel, edgePreservingDecompositionUI, M("TP_EPD_LABEL")); toolPanels.push_back (edgePreservingDecompositionUI); addPanel (exposurePanel, colorappearance, M("TP_COLORAPP_LABEL")); toolPanels.push_back (colorappearance); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 15a917316..a46e53721 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -51,6 +51,7 @@ #include "perspective.h" #include "rotate.h" #include "vignetting.h" +#include "gradient.h" #include "toolbar.h" #include "lensgeom.h" #include "lensgeomlistener.h" @@ -86,6 +87,7 @@ class ToolPanelCoordinator : public ToolPanelListener, WhiteBalance* whitebalance; Vignetting* vignetting; + Gradient* gradient; LensGeometry* lensgeom; LensProfilePanel* lensProf; Rotate* rotate;