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