File indexing completed on 2025-01-26 04:11:27

0001 /*
0002  *  SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "KisKritaSensorPack.h"
0008 #include "KisCppQuirks.h"
0009 #include "kis_assert.h"
0010 
0011 #include <QDomDocument>
0012 #include <QDomElement>
0013 
0014 #include <KisCurveOptionData.h>
0015 
0016 namespace detail {
0017 template <typename Data,
0018           typename SensorData =
0019               std::copy_const_t<Data,
0020                                KisSensorData>>
0021 inline std::vector<SensorData*> sensors(Data *data)
0022 {
0023     std::vector<SensorData*> result;
0024 
0025     result.reserve(16);
0026 
0027     result.push_back(&data->sensorPressure);
0028     result.push_back(&data->sensorPressureIn);
0029     result.push_back(&data->sensorTangentialPressure);
0030 
0031     result.push_back(&data->sensorDrawingAngle);
0032     result.push_back(&data->sensorXTilt);
0033     result.push_back(&data->sensorYTilt);
0034     result.push_back(&data->sensorTiltDirection);
0035     result.push_back(&data->sensorTiltElevation);
0036     result.push_back(&data->sensorRotation);
0037 
0038     result.push_back(&data->sensorFuzzyPerDab);
0039     result.push_back(&data->sensorFuzzyPerStroke);
0040 
0041     result.push_back(&data->sensorSpeed);
0042     result.push_back(&data->sensorFade);
0043     result.push_back(&data->sensorDistance);
0044     result.push_back(&data->sensorTime);
0045 
0046     result.push_back(&data->sensorPerspective);
0047 
0048 
0049     return result;
0050 }
0051 } // namespace detail
0052 
0053 KisKritaSensorData::KisKritaSensorData()
0054     : sensorPressure(PressureId),
0055       sensorPressureIn(PressureInId),
0056       sensorXTilt(XTiltId),
0057       sensorYTilt(YTiltId),
0058       sensorTiltDirection(TiltDirectionId),
0059       sensorTiltElevation(TiltElevationId),
0060       sensorSpeed(SpeedId),
0061       sensorDrawingAngle(),
0062       sensorRotation(RotationId),
0063       sensorDistance(DistanceId),
0064       sensorTime(TimeId, QLatin1Literal("duration")),
0065       sensorFuzzyPerDab(FuzzyPerDabId),
0066       sensorFuzzyPerStroke(FuzzyPerStrokeId),
0067       sensorFade(FadeId),
0068       sensorPerspective(PerspectiveId),
0069       sensorTangentialPressure(TangentialPressureId)
0070 {
0071     sensorPressure.isActive = true;
0072 }
0073 
0074 KisKritaSensorPack::KisKritaSensorPack(Checkability checkability)
0075     : m_checkability(checkability)
0076 {
0077 }
0078 
0079 KisSensorPackInterface * KisKritaSensorPack::clone() const
0080 {
0081     return new KisKritaSensorPack(*this);
0082 }
0083 
0084 std::vector<const KisSensorData *> KisKritaSensorPack::constSensors() const
0085 {
0086     return detail::sensors(&m_data);
0087 }
0088 
0089 std::vector<KisSensorData *> KisKritaSensorPack::sensors()
0090 {
0091     return detail::sensors(&m_data);
0092 }
0093 
0094 const KisKritaSensorData& KisKritaSensorPack::constSensorsStruct() const 
0095 {
0096     return m_data;
0097 }
0098 
0099 KisKritaSensorData& KisKritaSensorPack::sensorsStruct()
0100 {
0101     return m_data;
0102 }
0103 
0104 bool KisKritaSensorPack::compare(const KisSensorPackInterface *rhs) const
0105 {
0106     const KisKritaSensorPack *pack = dynamic_cast<const KisKritaSensorPack*>(rhs);
0107     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(pack, false);
0108     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_checkability == pack->m_checkability, false);
0109 
0110     return m_data == pack->m_data;
0111 }
0112 
0113 bool KisKritaSensorPack::read(KisCurveOptionDataCommon &data, const KisPropertiesConfiguration *setting) const
0114 {
0115     data.isCheckable = m_checkability == Checkability::Checkable ||
0116         (m_checkability == Checkability::CheckableIfHasPrefix &&
0117          (!data.prefix.isEmpty() ||
0118           !setting->getString(KisPropertiesConfiguration::extractedPrefixKey()).isEmpty()));
0119 
0120     data.isChecked = !data.isCheckable || setting->getBool("Pressure" + data.id.id(), false);
0121 
0122     std::vector<KisSensorData*> sensors = data.sensors();
0123     QMap<QString, KisSensorData*> sensorById;
0124 
0125     Q_FOREACH (KisSensorData *sensor, sensors) {
0126         sensorById.insert(sensor->id.id(), sensor);
0127     }
0128 
0129     QSet<KisSensorData*> sensorsToReset;
0130 
0131 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
0132 
0133     QList l = sensorById.values();
0134     if (!l.isEmpty()) {
0135         sensorsToReset = QSet<KisSensorData*>(l.begin(), l.end());
0136     }
0137 #else
0138     sensorsToReset =
0139         QSet<KisSensorData*>::fromList(sensorById.values());
0140 #endif
0141 
0142     const QString sensorDefinition = setting->getString(data.id.id() + "Sensor");
0143 
0144     if (sensorDefinition.isEmpty()) {
0145         // noop
0146     } else if (!sensorDefinition.contains("sensorslist")) {
0147         QDomDocument doc;
0148         doc.setContent(sensorDefinition);
0149         QDomElement e = doc.documentElement();
0150 
0151         const QString sensorId = e.attribute("id", "");
0152         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!sensorId.isEmpty(), false);
0153         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(sensorById.contains(sensorId), false);
0154 
0155         KisSensorData *sensor = sensorById[sensorId];
0156         sensor->read(e);
0157         sensor->isActive = true;
0158         sensorsToReset.remove(sensor);
0159 
0160         data.commonCurve = sensor->curve;
0161 
0162     } else {
0163         QString proposedCommonCurve;
0164 
0165         QDomDocument doc;
0166         doc.setContent(sensorDefinition);
0167         QDomElement elt = doc.documentElement();
0168         QDomNode node = elt.firstChild();
0169         while (!node.isNull()) {
0170             if (node.isElement())  {
0171                 QDomElement childelt = node.toElement();
0172                 if (childelt.tagName() == "ChildSensor") {
0173 
0174                     const QString sensorId = childelt.attribute("id", "");
0175                     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!sensorId.isEmpty(), false);
0176                     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(sensorById.contains(sensorId), false);
0177 
0178                     KisSensorData *sensor = sensorById[sensorId];
0179                     sensor->read(childelt);
0180                     sensor->isActive = true;
0181                     sensorsToReset.remove(sensor);
0182 
0183                     /// due to legacy reasons we initialize common curve
0184                     /// with the "last read curve value"
0185                     proposedCommonCurve = sensor->curve;
0186                 }
0187             }
0188             node = node.nextSibling();
0189         }
0190 
0191         data.commonCurve = !proposedCommonCurve.isEmpty() ? proposedCommonCurve : DEFAULT_CURVE_STRING;
0192     }
0193 
0194     data.useSameCurve = setting->getBool(data.id.id() + "UseSameCurve", true);
0195 
0196     // Only load the old curve format if the curve wasn't saved by the sensor
0197     // This will give every sensor the same curve.
0198     if (!sensorDefinition.contains("curve")) {
0199         if (setting->getBool("Custom" + data.id.id(), false)) {
0200             data.commonCurve = setting->getString("Curve" + data.id.id(), DEFAULT_CURVE_STRING);
0201             Q_FOREACH (KisSensorData *sensor, sensors) {
0202                 sensor->curve = data.commonCurve;
0203                 sensorsToReset.remove(sensor);
0204             }
0205         } else {
0206             data.commonCurve = DEFAULT_CURVE_STRING;
0207         }
0208     }
0209 
0210     if (data.useSameCurve) {
0211         data.commonCurve = setting->getString(data.id.id() + "commonCurve",
0212                                               !data.commonCurve.isEmpty() ?
0213                                                   data.commonCurve :
0214                                                   DEFAULT_CURVE_STRING);
0215         if (data.commonCurve.isEmpty()) {
0216             data.commonCurve = DEFAULT_CURVE_STRING;
0217         }
0218     }
0219 
0220     Q_FOREACH (KisSensorData *sensor, sensorsToReset) {
0221         sensor->reset();
0222     }
0223 
0224     // At least one sensor needs to be active
0225     if (std::find_if(sensors.begin(), sensors.end(),
0226                      std::mem_fn(&KisSensorData::isActive)) == sensors.end()) {
0227 
0228         sensorById[PressureId.id()]->isActive = true;
0229     }
0230 
0231     data.strengthValue = setting->getDouble(data.id.id() + "Value", data.strengthMaxValue);
0232 
0233     if (data.valueFixUpReadCallback) {
0234         data.valueFixUpReadCallback(&data, setting);
0235     }
0236 
0237     data.useCurve = setting->getBool(data.id.id() + "UseCurve", true);
0238     data.curveMode = setting->getInt(data.id.id() + "curveMode", 0);
0239 
0240     return true;
0241 }
0242 
0243 void KisKritaSensorPack::write(const KisCurveOptionDataCommon &data, KisPropertiesConfiguration *setting) const
0244 {
0245     setting->setProperty("Pressure" + data.id.id(), data.isChecked || !data.isCheckable);
0246 
0247     QVector<const KisSensorData*> activeSensors;
0248     Q_FOREACH(const KisSensorData *sensor, data.sensors()) {
0249         if (sensor->isActive) {
0250             activeSensors.append(sensor);
0251         }
0252     }
0253 
0254     QDomDocument doc = QDomDocument("params");
0255     QDomElement root = doc.createElement("params");
0256     doc.appendChild(root);
0257 
0258     if (activeSensors.size() == 1) {
0259         activeSensors.first()->write(doc, root);
0260     } else {
0261         root.setAttribute("id", "sensorslist");
0262         Q_FOREACH (const KisSensorData *sensor, activeSensors) {
0263             QDomElement childelt = doc.createElement("ChildSensor");
0264             sensor->write(doc, childelt);
0265             root.appendChild(childelt);
0266         }
0267     }
0268     setting->setProperty(data.id.id() + "Sensor", doc.toString());
0269 
0270     setting->setProperty(data.id.id() + "UseCurve", data.useCurve);
0271     setting->setProperty(data.id.id() + "UseSameCurve", data.useSameCurve);
0272     setting->setProperty(data.id.id() + "Value", data.strengthValue);
0273     if (data.valueFixUpWriteCallback) {
0274         data.valueFixUpWriteCallback(data.strengthValue, setting);
0275     }
0276     setting->setProperty(data.id.id() + "curveMode", data.curveMode);
0277     setting->setProperty(data.id.id() + "commonCurve", data.commonCurve);
0278 }
0279 
0280 int KisKritaSensorPack::calcActiveSensorLength(const QString &activeSensorId) const
0281 {
0282     if (activeSensorId == FadeId.id()) {
0283         return m_data.sensorFade.length;
0284     } else if (activeSensorId == DistanceId.id()) {
0285         return m_data.sensorDistance.length;
0286     } else if (activeSensorId == TimeId.id()) {
0287         return m_data.sensorTime.length;
0288     }
0289 
0290     return -1;
0291 }