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