File indexing completed on 2024-05-12 15:56:09
0001 /* 0002 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_abr_translator.h" 0008 #include <kis_debug.h> 0009 #include <QStringList> 0010 #include <kis_dom_utils.h> 0011 0012 KisAbrTranslator::KisAbrTranslator() 0013 { 0014 init(); 0015 } 0016 0017 KisAbrTranslator::~KisAbrTranslator() 0018 { 0019 0020 } 0021 0022 void KisAbrTranslator::init() 0023 { 0024 m_root = m_doc.createElement("Preset"); 0025 m_root.setAttribute("paintopid", "paintbrush"); 0026 } 0027 0028 void KisAbrTranslator::addEntry(const QString& attributeName, const QString& type, const QString& value) 0029 { 0030 // setup object type 0031 // shape dynamics is not separated in the Objc so workaround by attribute name 0032 if (type == ABR_OBJECT || 0033 attributeName == ABR_USE_TIP_DYNAMICS || 0034 attributeName == ABR_USE_SCATTER) { 0035 0036 if (m_currentObjectName == ABR_DUAL_BRUSH && attributeName == OBJECT_NAME_BRUSH) { 0037 m_currentObjectName = ABR_DUAL_BRUSH + '_' + attributeName; 0038 } 0039 else { 0040 m_currentObjectName = attributeName; 0041 } 0042 0043 dbgKrita << "---- Object type changed to " << m_currentObjectName; 0044 } 0045 0046 // behaviour according object's attribute name 0047 if (m_currentObjectName == ABR_PRESET_START) { 0048 if (attributeName == ABR_PRESET_START) { 0049 clean(); 0050 } 0051 else if (attributeName == ABR_PRESET_NAME) { 0052 m_root.setAttribute("name", value); 0053 } 0054 else { 0055 //dbgKrita << "--Unknown attribute: " << attributeName; 0056 } 0057 } 0058 else if (m_currentObjectName == OBJECT_NAME_BRUSH) { 0059 m_abrBrushProperties.setupProperty(attributeName, type, value); 0060 // this is not object name but shape dynamics does not start with objc :/ 0061 // those objects has been merged with shape attributes due to serialization 0062 // e.g. minumumDiameter belongs to ABR_SZVR and is ABR_USE_TIP_DYNAMICS object 0063 } 0064 else if (m_currentObjectName == ABR_USE_TIP_DYNAMICS || 0065 m_currentObjectName == ABR_SZVR || 0066 m_currentObjectName == ABR_ANGLE_DYNAMICS || 0067 m_currentObjectName == ABR_ROUNDNESS_DYNAMICS) { 0068 m_abrTipDynamics.setupProperty(attributeName, type, value); 0069 } 0070 else if (m_currentObjectName == ABR_USE_SCATTER) { 0071 // TODO 0072 } 0073 else { 0074 dbgKrita << "Unknown attribute of " << m_currentObjectName << "| " << attributeName << type << value << " |"; 0075 } 0076 0077 0078 0079 } 0080 0081 void KisAbrTranslator::finishPreset() 0082 { 0083 m_abrBrushProperties.toXML(m_doc, m_root); 0084 m_abrTipDynamics.toXML(m_doc, m_root); 0085 m_doc.appendChild(m_root); 0086 0087 m_abrTipDynamics.reset(); 0088 m_currentObjectName.clear(); 0089 } 0090 0091 0092 QString KisAbrTranslator::toString() 0093 { 0094 return m_doc.toString(); 0095 } 0096 0097 void KisAbrTranslator::clean() 0098 { 0099 m_doc.clear(); 0100 m_root.clear(); 0101 init(); 0102 } 0103 0104 0105 void AbrBrushProperties::setupProperty(const QString& attributeName, const QString& type, const QString& value) 0106 { 0107 Q_UNUSED(type); 0108 double valueDbl = 0.0; 0109 QStringList list; 0110 if (attributeName == ABR_BRUSH_DIAMETER || 0111 attributeName == ABR_BRUSH_HARDNESS || 0112 attributeName == ABR_BRUSH_ANGLE || 0113 attributeName == ABR_BRUSH_ROUNDNESS || 0114 attributeName == ABR_BRUSH_SPACING || 0115 attributeName == OBJECT_NAME_BRUSH) { 0116 list = value.split(' '); 0117 //e.g. "#Pxl 10" -> ['#Pxl','10'] 0118 Q_ASSERT(list.count() == 2); 0119 valueDbl = KisDomUtils::toDouble(list.at(1)); 0120 } 0121 0122 if (attributeName == OBJECT_NAME_BRUSH) { 0123 m_brushType = list.at(0); 0124 } 0125 else if (attributeName == ABR_BRUSH_DIAMETER) { 0126 m_diameter = valueDbl; 0127 } 0128 else if (attributeName == ABR_BRUSH_HARDNESS) { 0129 m_hardness = valueDbl; 0130 } 0131 else if (attributeName == ABR_BRUSH_ANGLE) { 0132 m_angle = valueDbl; 0133 } 0134 else if (attributeName == ABR_BRUSH_ROUNDNESS) { 0135 m_roundness = valueDbl; 0136 } 0137 else if (attributeName == ABR_BRUSH_SPACING) { 0138 m_spacing = valueDbl; 0139 } 0140 else if (attributeName == ABR_BRUSH_INTR) { 0141 m_intr = value.toInt(); 0142 } 0143 else if (attributeName == ABR_FLIP_X) { 0144 m_flipX = value.toInt(); 0145 } 0146 else if (attributeName == ABR_FLIP_Y) { 0147 m_flipY = value.toInt(); 0148 } 0149 else { 0150 dbgKrita << "Unknown attribute " << attributeName; 0151 } 0152 } 0153 0154 // <param name="brush_definition"> 0155 // <![CDATA[ 0156 // <Brush type="auto_brush" spacing="0.1" angle="0"> 0157 // <MaskGenerator radius="5" ratio="1" type="circle" vfade="0.5" spikes="2" hfade="0.5"/> 0158 // </Brush> ]]> 0159 // </param> 0160 void AbrBrushProperties::toXML(QDomDocument& doc, QDomElement& root) const 0161 { 0162 if (m_brushType != BRUSH_TYPE_COMPUTED) { 0163 dbgKrita << m_brushType << "saved as computed brush..."; 0164 } 0165 0166 QDomDocument d; 0167 QDomElement e = d.createElement("Brush"); 0168 0169 QDomElement shapeElement = d.createElement("MaskGenerator"); 0170 shapeElement.setAttribute("radius", KisDomUtils::toString(m_diameter * 0.5)); // radius == diameter / 2 0171 shapeElement.setAttribute("ratio", KisDomUtils::toString(m_roundness / 100.0)); // roundness in (0..100) to ratio in (0.0..1.0) 0172 shapeElement.setAttribute("hfade", KisDomUtils::toString(m_hardness / 100.0)); // same here 0173 shapeElement.setAttribute("vfade", KisDomUtils::toString(m_hardness / 100.0)); // and here too 0174 shapeElement.setAttribute("spikes", KisDomUtils::toString(2)); // just circle so far 0175 shapeElement.setAttribute("type", "circle"); 0176 e.appendChild(shapeElement); 0177 0178 e.setAttribute("type", "auto_brush"); 0179 e.setAttribute("spacing", KisDomUtils::toString(m_spacing / 100.0)); // spacing from 0..1000 to 0180 e.setAttribute("angle", KisDomUtils::toString(m_angle < 0 ? m_angle + 360.0 : m_angle)); // angle from -180..180 to 0..360 0181 e.setAttribute("randomness", "0"); // default here 0182 d.appendChild(e); 0183 0184 QDomElement elementParam = doc.createElement("param"); 0185 elementParam.setAttribute("name", "brush_definition"); 0186 QDomText text = doc.createCDATASection(d.toString()); 0187 elementParam.appendChild(text); 0188 root.appendChild(elementParam); 0189 0190 } 0191 0192 AbrTipDynamicsProperties::AbrTipDynamicsProperties() 0193 { 0194 m_groups[ ABR_SZVR ] = &m_sizeVarianceProperties; 0195 m_groups[ ABR_ANGLE_DYNAMICS ] = &m_angleProperties; 0196 m_groups[ ABR_ROUNDNESS_DYNAMICS ] = &m_RoundnessProperties; 0197 Q_ASSERT(m_groupType.isNull()); 0198 } 0199 0200 0201 void AbrTipDynamicsProperties::setupProperty(const QString& attributeName, const QString& type, const QString& value) 0202 { 0203 if (type == ABR_OBJECT) { 0204 if (!m_groups.contains(attributeName)) { 0205 dbgKrita << "Unknown " << type << " in Tip dynamics called " << attributeName << " : " << value; 0206 } 0207 else { 0208 m_groupType = attributeName; 0209 } 0210 return; 0211 } 0212 0213 Q_UNUSED(type); 0214 double valueDbl = 0.0; 0215 QStringList list; 0216 if (attributeName == ABR_TIP_DYNAMICS_MINUMUM_DIAMETER || 0217 attributeName == ABR_TIP_DYNAMICS_MINUMUM_ROUNDNESS || 0218 attributeName == ABR_TIP_DYNAMICS_TILT_SCALE 0219 ) { 0220 list = value.split(' '); 0221 //e.g. "#Pxl 10" -> ['#Pxl','10'] 0222 Q_ASSERT(list.count() == 2); 0223 valueDbl = KisDomUtils::toDouble(list.at(1)); 0224 } 0225 0226 if (m_groupType.isNull()) { 0227 0228 if (attributeName == ABR_USE_TIP_DYNAMICS) { 0229 m_useTipDynamics = value.toInt(); 0230 } 0231 else if (attributeName == ABR_FLIP_X) { 0232 m_flipX = value.toInt(); 0233 } 0234 else if (attributeName == ABR_FLIP_Y) { 0235 m_flipY = value.toInt(); 0236 } 0237 else if (attributeName == ABR_TIP_DYNAMICS_MINUMUM_DIAMETER) { 0238 m_minumumDiameter = valueDbl; 0239 } 0240 else if (attributeName == ABR_TIP_DYNAMICS_MINUMUM_ROUNDNESS) { 0241 m_minumumRoundness = valueDbl; 0242 } 0243 else if (attributeName == ABR_TIP_DYNAMICS_TILT_SCALE) { 0244 m_tiltScale = valueDbl; 0245 } 0246 else { 0247 dbgKrita << "Unknown attribute for tip dynamics" << attributeName; 0248 } 0249 0250 } else { 0251 m_groups[ m_groupType ]->setupProperty(attributeName, type, value); 0252 } 0253 } 0254 0255 void AbrTipDynamicsProperties::toXML(QDomDocument& doc, QDomElement& root) const 0256 { 0257 QDomElement el = doc.createElement("shape_dynamics"); 0258 el.setAttribute("useTipDynamics", m_useTipDynamics); 0259 el.setAttribute("flipX", m_flipX); 0260 el.setAttribute("flipY", m_flipY); 0261 0262 root.appendChild(el); 0263 0264 el = doc.createElement("angleDynamics"); 0265 0266 el.setAttribute("angleJitter", KisDomUtils::toString(m_angleProperties.m_sizeJitter)); 0267 el.setAttribute("angleController", KisDomUtils::toString(m_angleProperties.m_bVTy)); 0268 el.setAttribute("angleFadeStep", KisDomUtils::toString(m_angleProperties.m_fadeStep)); 0269 root.appendChild(el); 0270 0271 el = doc.createElement("roundnessDynamics"); 0272 el.setAttribute("minumumRoundness", KisDomUtils::toString(m_minumumRoundness)); 0273 el.setAttribute("roundnessJitter", KisDomUtils::toString(m_RoundnessProperties.m_sizeJitter)); 0274 el.setAttribute("roundnessController", KisDomUtils::toString(m_RoundnessProperties.m_bVTy)); 0275 el.setAttribute("roundnessFadeStep", KisDomUtils::toString(m_RoundnessProperties.m_fadeStep)); 0276 root.appendChild(el); 0277 0278 el = doc.createElement("sizeDynamics"); 0279 el.setAttribute("tiltScale", KisDomUtils::toString(m_tiltScale)); 0280 el.setAttribute("minumumDiameter", KisDomUtils::toString(m_minumumDiameter)); 0281 el.setAttribute("roundnessJitter", KisDomUtils::toString(m_RoundnessProperties.m_sizeJitter)); 0282 el.setAttribute("roundnessController", KisDomUtils::toString(m_RoundnessProperties.m_bVTy)); 0283 el.setAttribute("roundnessFadeStep", KisDomUtils::toString(m_RoundnessProperties.m_fadeStep)); 0284 root.appendChild(el); 0285 0286 } 0287 0288 // <param name="CurveSize"><![CDATA[0,0.257028;1,0.493976;]]></param> 0289 // 0,m_minimumDiameter 1,m_sizeJitter 0290 // <param name="PressureSize">true</param> 0291 // <param name="SizeSensor"><![CDATA[<!DOCTYPE params> 0292 // <params id="fuzzy"/> ]]></param> // controller 0293 void AbrGroupProperties::setupProperty(const QString& attributeName, const QString& type, const QString& value) 0294 { 0295 Q_UNUSED(type); 0296 double valueDbl = 0.0; 0297 QStringList list; 0298 if (attributeName == ABR_DYNAMICS_JITTER) { 0299 list = value.split(' '); 0300 //e.g. "#Pxl 10" -> ['#Pxl','10'] 0301 Q_ASSERT(list.count() == 2); 0302 valueDbl = KisDomUtils::toDouble(list.at(1)); 0303 } 0304 0305 if (attributeName == ABR_DYNAMICS_FADE_STEP) { 0306 m_fadeStep = value.toInt(); 0307 } 0308 else if (attributeName == ABR_DYNAMICS_JITTER) { 0309 m_sizeJitter = valueDbl; 0310 } 0311 else if (attributeName == ABR_CONTROL) { 0312 m_bVTy = (enumAbrControllers)value.toInt(); 0313 } 0314 else { 0315 dbgKrita << "Unknown attribute for Group!" << attributeName; 0316 } 0317 0318 } 0319 0320 0321