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 }