1 /*
2  *  This file is part of RawTherapee.
3  *
4  *  RawTherapee is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  RawTherapee is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with RawTherapee.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  *  2010 Ilya Popov <ilia_popov@rambler.ru>
18  */
19 
20 #include "hslequalizer.h"
21 #include "eventmapper.h"
22 #include "../rtengine/color.h"
23 #include "../rtengine/iccmatrices.h"
24 
25 using namespace rtengine;
26 using namespace rtengine::procparams;
27 
28 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29 
30 namespace {
31 
hsv2rgb01(float h,float s,float v,float & r,float & g,float & b)32 void hsv2rgb01(float h, float s, float v, float &r, float &g, float &b)
33 {
34     // try to get a better visual match -- this is empirical and to be confirmed
35     h -= 1.f/19.f;
36     if (h > 1.f) {
37         h -= 1.f;
38     } else if (h < 0.f) {
39         h += 1.f;
40     }
41 
42     Color::hsv2rgb01(h, s, v, r, g, b);
43 }
44 
45 } // namespace
46 
HSLEqualizer()47 HSLEqualizer::HSLEqualizer():
48     FoldableToolPanel(this, "hslequalizer", M("TP_HSVEQUALIZER_LABEL"), false, true, true)
49 {
50     auto m = ProcEventMapper::getInstance();
51     EvHSLSmoothing = m->newEvent(RGBCURVE, "HISTORY_MSG_HSL_SMOOTHING");
52     EvToolReset.set_action(RGBCURVE);
53 
54     std::vector<GradientMilestone> bottomMilestones;
55     for (int i = 0; i < 7; i++) {
56         float R, G, B;
57         float x = float(i) * (1.0f / 6.0);
58         hsv2rgb01(x, 0.5f, 0.6f, R, G, B);
59         bottomMilestones.push_back(GradientMilestone(double(x), double(R), double(G), double(B)));
60     }
61 
62     curveEditorG = new CurveEditorGroup(options.lastHsvCurvesDir, M("TP_HSVEQUALIZER_CHANNEL"));
63     curveEditorG->setCurveListener(this);
64 
65     hshape = static_cast<FlatCurveEditor *>(curveEditorG->addCurve(CT_Flat, M("TP_HSVEQUALIZER_HUE")));
66     hshape->setEditID(EUID_HSL_H, BT_SINGLEPLANE_FLOAT);
67     hshape->setBottomBarBgGradient(bottomMilestones);
68     hshape->setCurveColorProvider(this, 1);
69 
70     sshape = static_cast<FlatCurveEditor *>(curveEditorG->addCurve(CT_Flat, M("TP_HSVEQUALIZER_SAT")));
71     sshape->setEditID(EUID_HSL_S, BT_SINGLEPLANE_FLOAT);
72     sshape->setBottomBarBgGradient(bottomMilestones);
73     sshape->setCurveColorProvider(this, 2);
74 
75     lshape = static_cast<FlatCurveEditor *>(curveEditorG->addCurve(CT_Flat, M("TP_HSVEQUALIZER_VAL")));
76     lshape->setEditID(EUID_HSL_V, BT_SINGLEPLANE_FLOAT);
77     lshape->setBottomBarBgGradient(bottomMilestones);
78     lshape->setCurveColorProvider(this, 3);
79 
80     setMulti(true);
81 
82     curveEditorG->curveListComplete();
83 
84     smoothing = Gtk::manage(new Adjuster(M("TP_HSL_SMOOTHING"), 0, 10, 1, 0));
85     smoothing->setAdjusterListener(this);
86 
87     pack_start(*curveEditorG, Gtk::PACK_SHRINK, 4);
88     pack_start(*smoothing);
89 
90     default_flat_curve_ = { FCT_MinMaxCPoints };
91     // Point for RGBCMY colors
92     for (int i = 0; i < 6; i++) {
93         default_flat_curve_.push_back((1. / 6.) * i);
94         default_flat_curve_.push_back(0.5);
95         default_flat_curve_.push_back(0.35);
96         default_flat_curve_.push_back(0.35);
97     }
98 
99 }
100 
101 
~HSLEqualizer()102 HSLEqualizer::~HSLEqualizer()
103 {
104     delete curveEditorG;
105 }
106 
107 
read(const ProcParams * pp)108 void HSLEqualizer::read(const ProcParams *pp)
109 {
110     disableListener();
111 
112     hshape->setCurve(default_flat_curve_);
113     sshape->setCurve(default_flat_curve_);
114     lshape->setCurve(default_flat_curve_);
115 
116     hshape->setCurve(pp->hsl.hCurve);
117     sshape->setCurve(pp->hsl.sCurve);
118     lshape->setCurve(pp->hsl.lCurve);
119     smoothing->setValue(pp->hsl.smoothing);
120     setEnabled(pp->hsl.enabled);
121 
122     enableListener();
123 }
124 
125 
setEditProvider(EditDataProvider * provider)126 void HSLEqualizer::setEditProvider(EditDataProvider *provider)
127 {
128     hshape->setEditProvider(provider);
129     sshape->setEditProvider(provider);
130     lshape->setEditProvider(provider);
131 }
132 
133 
adjusterChanged(Adjuster * a,double newval)134 void HSLEqualizer::adjusterChanged(Adjuster* a, double newval)
135 {
136     if (listener && getEnabled()) {
137         listener->panelChanged(EvHSLSmoothing, a->getTextValue());
138     }
139 }
140 
141 
adjusterAutoToggled(Adjuster * a,bool newval)142 void HSLEqualizer::adjusterAutoToggled(Adjuster* a, bool newval)
143 {
144 }
145 
146 
autoOpenCurve()147 void HSLEqualizer::autoOpenCurve()
148 {
149     // Open up the first curve if selected
150     bool active = hshape->openIfNonlinear();
151 
152     if (!active) {
153         sshape->openIfNonlinear();
154     }
155 
156     if (!active) {
157         lshape->openIfNonlinear();
158     }
159 }
160 
161 
write(ProcParams * pp)162 void HSLEqualizer::write(ProcParams *pp)
163 {
164     pp->hsl.enabled = getEnabled();
165     pp->hsl.hCurve = hshape->getCurve();
166     pp->hsl.sCurve = sshape->getCurve();
167     pp->hsl.lCurve = lshape->getCurve();
168     pp->hsl.smoothing = smoothing->getValue();
169 }
170 
171 /*
172  * Curve listener
173  *
174  * If more than one curve has been added, the curve listener is automatically
175  * set to 'multi=true', and send a pointer of the modified curve in a parameter
176  */
curveChanged(CurveEditor * ce)177 void HSLEqualizer::curveChanged(CurveEditor *ce)
178 {
179     if (listener && getEnabled()) {
180         if (ce == hshape) {
181             listener->panelChanged(EvHSVEqualizerH, M("HISTORY_CUSTOMCURVE"));
182         }
183 
184         if (ce == sshape) {
185             listener->panelChanged(EvHSVEqualizerS, M("HISTORY_CUSTOMCURVE"));
186         }
187 
188         if (ce == lshape) {
189             listener->panelChanged(EvHSVEqualizerV, M("HISTORY_CUSTOMCURVE"));
190         }
191     }
192 }
193 
194 
colorForValue(double valX,double valY,enum ColorCaller::ElemType elemType,int callerId,ColorCaller * caller)195 void HSLEqualizer::colorForValue(double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller)
196 {
197     float R = 0.5, G = 0.5, B = 0.5;
198 
199     if (callerId == 1) {
200         float h = (valY - 0.5) * 0.3 + valX;
201         if (h > 1.0f) {
202             h -= 1.0f;
203         } else if (h < 0.0f) {
204             h += 1.0f;
205         }
206         hsv2rgb01(h, 0.5f, 0.6f, R, G, B);
207     } else if (callerId == 2) { // Saturation = f(Hue)
208         hsv2rgb01(valX, valY, 0.6f, R, G, B);
209     } else if (callerId == 3) { // Value = f(Hue)
210         hsv2rgb01(valX, 0.5f, 0.6f + (valY - 0.5f) * 0.2, R, G, B);
211     }
212     caller->ccRed = R;
213     caller->ccGreen = G;
214     caller->ccBlue = B;
215 }
216 
217 
enabledChanged()218 void HSLEqualizer::enabledChanged()
219 {
220     if (listener) {
221         if (get_inconsistent()) {
222             listener->panelChanged(EvHSVEqEnabled, M("GENERAL_UNCHANGED"));
223         } else if (getEnabled()) {
224             listener->panelChanged(EvHSVEqEnabled, M("GENERAL_ENABLED"));
225         } else {
226             listener->panelChanged(EvHSVEqEnabled, M("GENERAL_DISABLED"));
227         }
228     }
229 }
230 
231 
setDefaults(const ProcParams * def)232 void HSLEqualizer::setDefaults(const ProcParams *def)
233 {
234     smoothing->setDefault(def->hsl.smoothing);
235     initial_params = def->hsl;
236 }
237 
238 
toolReset(bool to_initial)239 void HSLEqualizer::toolReset(bool to_initial)
240 {
241     ProcParams pp;
242     if (to_initial) {
243         pp.hsl = initial_params;
244     }
245     pp.hsl.enabled = getEnabled();
246     read(&pp);
247 }
248