1 /* This file is part of the KDE project
2  * Copyright (C) 2008 Boudewijn Rempt <boud@valdyas.org>
3  * Copyright (C) 2011 Silvio Heinrich <plassy@web.de>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 #include "kis_curve_option.h"
21 
22 #include <QDomNode>
23 
KisCurveOption(const QString & name,KisPaintOpOption::PaintopCategory category,bool checked,qreal value,qreal min,qreal max)24 KisCurveOption::KisCurveOption(const QString& name, KisPaintOpOption::PaintopCategory category,
25                                bool checked, qreal value, qreal min, qreal max)
26     : m_name(name)
27     , m_category(category)
28     , m_checkable(true)
29     , m_checked(checked)
30     , m_useCurve(true)
31     , m_useSameCurve(true)
32     , m_separateCurveValue(false)
33     , m_curveMode(0)
34 {
35     Q_FOREACH (const DynamicSensorType sensorType, KisDynamicSensor::sensorsTypes()) {
36         KisDynamicSensorSP sensor = KisDynamicSensor::type2Sensor(sensorType, m_name);
37         sensor->setActive(false);
38         replaceSensor(sensor);
39     }
40     m_sensorMap[PRESSURE]->setActive(true);
41 
42     setValueRange(min, max);
43     setValue(value);
44 
45 
46     m_commonCurve = defaultCurve();
47 }
48 
~KisCurveOption()49 KisCurveOption::~KisCurveOption()
50 {
51 }
52 
name() const53 const QString& KisCurveOption::name() const
54 {
55     return m_name;
56 }
57 
category() const58 KisPaintOpOption::PaintopCategory KisCurveOption::category() const
59 {
60     return m_category;
61 }
62 
minValue() const63 qreal KisCurveOption::minValue() const
64 {
65     return m_minValue;
66 }
67 
maxValue() const68 qreal KisCurveOption::maxValue() const
69 {
70     return m_maxValue;
71 }
72 
value() const73 qreal KisCurveOption::value() const
74 {
75     return m_value;
76 }
77 
resetAllSensors()78 void KisCurveOption::resetAllSensors()
79 {
80     Q_FOREACH (KisDynamicSensorSP sensor, m_sensorMap.values()) {
81         if (sensor->isActive()) {
82             sensor->reset();
83         }
84     }
85 }
86 
writeOptionSetting(KisPropertiesConfigurationSP setting) const87 void KisCurveOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const
88 {
89     if (m_checkable) {
90         setting->setProperty("Pressure" + m_name, isChecked());
91     }
92 
93     if (activeSensors().size() == 1) {
94         setting->setProperty(m_name + "Sensor", activeSensors().first()->toXML());
95     }
96     else {
97         QDomDocument doc = QDomDocument("params");
98         QDomElement root = doc.createElement("params");
99         doc.appendChild(root);
100         root.setAttribute("id", "sensorslist");
101 
102         Q_FOREACH (KisDynamicSensorSP sensor, activeSensors()) {
103             QDomElement childelt = doc.createElement("ChildSensor");
104             sensor->toXML(doc, childelt);
105             root.appendChild(childelt);
106         }
107         setting->setProperty(m_name + "Sensor", doc.toString());
108     }
109     setting->setProperty(m_name + "UseCurve", m_useCurve);
110     setting->setProperty(m_name + "UseSameCurve", m_useSameCurve);
111     setting->setProperty(m_name + "Value", m_value);
112     setting->setProperty(m_name + "curveMode", m_curveMode);
113     setting->setProperty(m_name + "commonCurve", qVariantFromValue(m_commonCurve));
114 
115 }
116 
readOptionSetting(KisPropertiesConfigurationSP setting)117 void KisCurveOption::readOptionSetting(KisPropertiesConfigurationSP setting)
118 {
119     readNamedOptionSetting(m_name, setting);
120 }
121 
lodLimitations(KisPaintopLodLimitations * l) const122 void KisCurveOption::lodLimitations(KisPaintopLodLimitations *l) const
123 {
124     Q_UNUSED(l);
125 }
126 
intMinValue() const127 int KisCurveOption::intMinValue() const
128 {
129     return 0;
130 }
131 
intMaxValue() const132 int KisCurveOption::intMaxValue() const
133 {
134     return 100;
135 }
136 
valueSuffix() const137 QString KisCurveOption::valueSuffix() const
138 {
139     return i18n("%");
140 }
141 
readNamedOptionSetting(const QString & prefix,const KisPropertiesConfigurationSP setting)142 void KisCurveOption::readNamedOptionSetting(const QString& prefix, const KisPropertiesConfigurationSP setting)
143 {
144     if (!setting) return;
145 
146     KisCubicCurve commonCurve = m_commonCurve;
147 
148     //dbgKrita << "readNamedOptionSetting" << prefix;
149     // setting->dump();
150 
151     if (m_checkable) {
152         setChecked(setting->getBool("Pressure" + prefix, false));
153     }
154     //dbgKrita << "\tPressure" + prefix << isChecked();
155 
156     m_sensorMap.clear();
157 
158     // Replace all sensors with the inactive defaults
159     Q_FOREACH (const DynamicSensorType sensorType, KisDynamicSensor::sensorsTypes()) {
160         replaceSensor(KisDynamicSensor::type2Sensor(sensorType, m_name));
161     }
162 
163     QString sensorDefinition = setting->getString(prefix + "Sensor");
164     if (!sensorDefinition.contains("sensorslist")) {
165         KisDynamicSensorSP s = KisDynamicSensor::createFromXML(sensorDefinition, m_name);
166         if (s) {
167             replaceSensor(s);
168             s->setActive(true);
169             commonCurve = s->curve();
170             //dbgKrita << "\tsingle sensor" << s::id(s->sensorType()) << s->isActive() << "added";
171         }
172     }
173     else {
174         QDomDocument doc;
175         doc.setContent(sensorDefinition);
176         QDomElement elt = doc.documentElement();
177         QDomNode node = elt.firstChild();
178         while (!node.isNull()) {
179             if (node.isElement())  {
180                 QDomElement childelt = node.toElement();
181                 if (childelt.tagName() == "ChildSensor") {
182                     KisDynamicSensorSP s = KisDynamicSensor::createFromXML(childelt, m_name);
183                     if (s) {
184                         replaceSensor(s);
185                         s->setActive(true);
186                         commonCurve = s->curve();
187                         //dbgKrita << "\tchild sensor" << s::id(s->sensorType()) << s->isActive() << "added";
188                     }
189                 }
190             }
191             node = node.nextSibling();
192         }
193     }
194 
195 
196     m_useSameCurve = setting->getBool(m_name + "UseSameCurve", true);
197 
198     // Only load the old curve format if the curve wasn't saved by the sensor
199     // This will give every sensor the same curve.
200     //dbgKrita << ">>>>>>>>>>>" << prefix + "Sensor" << setting->getString(prefix + "Sensor");
201     if (!setting->getString(prefix + "Sensor").contains("curve")) {
202         //dbgKrita << "\told format";
203         if (setting->getBool("Custom" + prefix, false)) {
204             Q_FOREACH (KisDynamicSensorSP s, m_sensorMap.values()) {
205                 s->setCurve(setting->getCubicCurve("Curve" + prefix));
206                 commonCurve = s->curve();
207             }
208         } else {
209             commonCurve = emptyCurve();
210         }
211     }
212 
213     if (m_useSameCurve) {
214         m_commonCurve = setting->getCubicCurve(prefix + "commonCurve", commonCurve);
215     }
216 
217     // At least one sensor needs to be active
218     if (activeSensors().size() == 0) {
219         m_sensorMap[PRESSURE]->setActive(true);
220     }
221 
222     m_value = setting->getDouble(m_name + "Value", m_maxValue);
223     //dbgKrita << "\t" + m_name + "Value" << m_value;
224 
225     m_useCurve = setting->getBool(m_name + "UseCurve", true);
226     //dbgKrita << "\t" + m_name + "UseCurve" << m_useSameCurve;
227 
228 
229     //dbgKrita << "\t" + m_name + "UseSameCurve" << m_useSameCurve;
230 
231     m_curveMode = setting->getInt(m_name + "curveMode");
232     //dbgKrita << "-----------------";
233 }
234 
replaceSensor(KisDynamicSensorSP s)235 void KisCurveOption::replaceSensor(KisDynamicSensorSP s)
236 {
237     Q_ASSERT(s);
238     m_sensorMap[s->sensorType()] = s;
239 }
240 
sensor(DynamicSensorType sensorType,bool active) const241 KisDynamicSensorSP KisCurveOption::sensor(DynamicSensorType sensorType, bool active) const
242 {
243     if (m_sensorMap.contains(sensorType)) {
244         if (!active) {
245             return m_sensorMap[sensorType];
246         }
247         else {
248              if (m_sensorMap[sensorType]->isActive()) {
249                  return m_sensorMap[sensorType];
250              }
251         }
252     }
253     return 0;
254 }
255 
256 
isRandom() const257 bool KisCurveOption::isRandom() const
258 {
259     return bool(sensor(FUZZY_PER_DAB, true)) ||
260         bool(sensor(FUZZY_PER_STROKE, true));
261 }
262 
isCurveUsed() const263 bool KisCurveOption::isCurveUsed() const
264 {
265     return m_useCurve;
266 }
267 
isSameCurveUsed() const268 bool KisCurveOption::isSameCurveUsed() const
269 {
270     return m_useSameCurve;
271 }
272 
getCurveMode() const273 int KisCurveOption::getCurveMode() const
274 {
275     return m_curveMode;
276 }
277 
getCommonCurve() const278 KisCubicCurve KisCurveOption::getCommonCurve() const
279 {
280     return m_commonCurve;
281 }
282 
setSeparateCurveValue(bool separateCurveValue)283 void KisCurveOption::setSeparateCurveValue(bool separateCurveValue)
284 {
285     m_separateCurveValue = separateCurveValue;
286 }
287 
isCheckable()288 bool KisCurveOption::isCheckable()
289 {
290     return m_checkable;
291 }
292 
isChecked() const293 bool KisCurveOption::isChecked() const
294 {
295     return m_checked;
296 }
297 
setChecked(bool checked)298 void KisCurveOption::setChecked(bool checked)
299 {
300     m_checked = checked;
301 }
302 
setCurveUsed(bool useCurve)303 void KisCurveOption::setCurveUsed(bool useCurve)
304 {
305     m_useCurve = useCurve;
306 }
307 
setCurveMode(int mode)308 void KisCurveOption::setCurveMode(int mode)
309 {
310     m_curveMode = mode;
311 }
312 
setUseSameCurve(bool useSameCurve)313 void KisCurveOption::setUseSameCurve(bool useSameCurve)
314 {
315     m_useSameCurve = useSameCurve;
316 }
317 
setCommonCurve(KisCubicCurve curve)318 void KisCurveOption::setCommonCurve(KisCubicCurve curve)
319 {
320     m_commonCurve = curve;
321 }
322 
setCurve(DynamicSensorType sensorType,bool useSameCurve,const KisCubicCurve & curve)323 void KisCurveOption::setCurve(DynamicSensorType sensorType, bool useSameCurve, const KisCubicCurve &curve)
324 {
325     if (useSameCurve == m_useSameCurve) {
326         if (useSameCurve) {
327             m_commonCurve = curve;
328         }
329         else {
330             KisDynamicSensorSP s = sensor(sensorType, false);
331             if (s) {
332                 s->setCurve(curve);
333             }
334 
335         }
336     }
337     else {
338         if (!m_useSameCurve && useSameCurve) {
339             m_commonCurve = curve;
340         }
341         else { //if (m_useSameCurve && !useSameCurve)
342             KisDynamicSensorSP s = 0;
343             // And set the current sensor to the current curve
344             if (!m_sensorMap.contains(sensorType)) {
345                 s = KisDynamicSensor::type2Sensor(sensorType, m_name);
346             } else {
347                 KisDynamicSensorSP s = sensor(sensorType, false);
348             }
349             if (s) {
350                 s->setCurve(curve);
351             }
352 
353         }
354         m_useSameCurve = useSameCurve;
355     }
356 }
357 
setValueRange(qreal min,qreal max)358 void KisCurveOption::setValueRange(qreal min, qreal max)
359 {
360     m_minValue = qMin(min, max);
361     m_maxValue = qMax(min, max);
362 }
363 
setValue(qreal value)364 void KisCurveOption::setValue(qreal value)
365 {
366     m_value = qBound(m_minValue, value, m_maxValue);
367 }
368 
computeValueComponents(const KisPaintInformation & info) const369 KisCurveOption::ValueComponents KisCurveOption::computeValueComponents(const KisPaintInformation& info) const
370 {
371     ValueComponents components;
372 
373     if (m_useCurve) {
374         QMap<DynamicSensorType, KisDynamicSensorSP>::const_iterator i;
375         QList<double> sensorValues;
376         for (i = m_sensorMap.constBegin(); i != m_sensorMap.constEnd(); ++i) {
377             KisDynamicSensorSP s(i.value());
378 
379             if (s->isActive()) {
380                 qreal valueFromCurve = m_useSameCurve ? s->parameter(info, m_commonCurve, true) : s->parameter(info);
381                 if (s->isAdditive()) {
382                     components.additive += valueFromCurve;
383                     components.hasAdditive = true;
384                 } else if (s->isAbsoluteRotation()) {
385                     components.absoluteOffset = valueFromCurve;
386                     components.hasAbsoluteOffset =true;
387                 } else {
388                     sensorValues << valueFromCurve;
389                     components.hasScaling = true;
390                 }
391             }
392         }
393 
394         if (sensorValues.count() == 1) {
395             components.scaling = sensorValues.first();
396         } else {
397 
398             if (m_curveMode == 1){           // add
399                 components.scaling = 0;
400                 double i;
401                 foreach (i, sensorValues) {
402                     components.scaling += i;
403                 }
404             } else if (m_curveMode == 2){    //max
405                 components.scaling = *std::max_element(sensorValues.begin(), sensorValues.end());
406 
407             } else if (m_curveMode == 3){    //min
408                 components.scaling = *std::min_element(sensorValues.begin(), sensorValues.end());
409 
410             } else if (m_curveMode == 4){    //difference
411                 double max = *std::max_element(sensorValues.begin(), sensorValues.end());
412                 double min = *std::min_element(sensorValues.begin(), sensorValues.end());
413                 components.scaling = max-min;
414 
415             } else {                         //multuply - default
416                 double i;
417                 foreach (i, sensorValues) {
418                     components.scaling *= i;
419                 }
420             }
421         }
422 
423     }
424 
425     if (!m_separateCurveValue) {
426         components.constant = m_value;
427     }
428 
429     components.minSizeLikeValue = m_minValue;
430     components.maxSizeLikeValue = m_maxValue;
431 
432     return components;
433 }
434 
computeSizeLikeValue(const KisPaintInformation & info) const435 qreal KisCurveOption::computeSizeLikeValue(const KisPaintInformation& info) const
436 {
437     const ValueComponents components = computeValueComponents(info);
438     return components.sizeLikeValue();
439 }
440 
computeRotationLikeValue(const KisPaintInformation & info,qreal baseValue,bool absoluteAxesFlipped) const441 qreal KisCurveOption::computeRotationLikeValue(const KisPaintInformation& info, qreal baseValue, bool absoluteAxesFlipped) const
442 {
443     const ValueComponents components = computeValueComponents(info);
444     return components.rotationLikeValue(baseValue, absoluteAxesFlipped);
445 }
446 
defaultCurve()447 KisCubicCurve KisCurveOption::defaultCurve()
448 {
449     QList<QPointF> points;
450     // needs to be set to something, weird curve is better for debugging
451     // it will be reset to the curve from the preset anyway though
452     points.push_back(QPointF(0,0));
453     points.push_back(QPointF(0.25,0.9));
454     points.push_back(QPointF(0.5,0));
455     points.push_back(QPointF(0.75,0.6));
456     points.push_back(QPointF(1,0));
457     return KisCubicCurve(points);
458 }
459 
emptyCurve()460 KisCubicCurve KisCurveOption::emptyCurve()
461 {
462     QList<QPointF> points;
463     points.push_back(QPointF(0,0));
464     points.push_back(QPointF(1,1));
465     return KisCubicCurve(points);
466 }
467 
sensors()468 QList<KisDynamicSensorSP> KisCurveOption::sensors()
469 {
470     //dbgKrita << "ID" << name() << "has" <<  m_sensorMap.count() << "Sensors of which" << sensorList.count() << "are active.";
471     return m_sensorMap.values();
472 }
473 
activeSensors() const474 QList<KisDynamicSensorSP> KisCurveOption::activeSensors() const
475 {
476     QList<KisDynamicSensorSP> sensorList;
477     Q_FOREACH (KisDynamicSensorSP sensor, m_sensorMap.values()) {
478         if (sensor->isActive()) {
479             sensorList << sensor;
480         }
481     }
482     //dbgKrita << "ID" << name() << "has" <<  m_sensorMap.count() << "Sensors of which" << sensorList.count() << "are active.";
483     return sensorList;
484 }
485