KDEGames

kgamesvgdocument.h
1/*
2 SPDX-FileCopyrightText: 2007 Mark A. Taff <kde@marktaff.com>
3
4 SPDX-License-Identifier: LGPL-2.0-only
5*/
6
7#ifndef _KGAMESVGDOCUMENT_H_
8#define _KGAMESVGDOCUMENT_H_
9
10// own
11#include "kdegamesprivate_export.h"
12// Qt
13#include <QDomDocument>
14#include <QHash>
15#include <QTransform>
16// Std
17#include <memory>
18
19class KGameSvgDocumentPrivate;
20
21/**
22 * \class KGameSvgDocument kgamesvgdocument.h <KGameSvgDocument>
23 *
24 * @brief A class for manipulating an SVG file using DOM
25 *
26 * This class is a wrapper around QDomDocument for SVG files.
27 * It:
28 * @li implements elementById();
29 * @li manipulates a node's style properties; and,
30 * @li manipulates a node's transform properties.
31 *
32 * @note The DOM standard requires all changes to be "live", so we cannot cache any values
33 * from the file; instead, we always have to query the DOM for the current value. This also
34 * means that style & matrix changes we make happen to the DOM immediately.
35 *
36 * A typical use is to read in an SVG file, edit the style or transform attributes
37 * in DOM as desired, and then output a QByteArray suitable for being loaded with
38 * QSvgRenderer::load().
39 *
40 * To read an SVG file into DOM:
41 * @code
42 * KGameSvgDocument svgDom;
43 * svgDom.load("/path/to/svgFile.svg");
44 * @endcode
45 *
46 * To find a node with a specific value in its id attribute, for example where id="playerOneGamepiece":
47 * @code
48 * QDomNode playerOneGamepiece = svgDom.elementById("playerOneGamepiece");
49 *
50 * // This works too
51 * QDomNode playerOneGamepiece = svgDom.elementByUniqueAttributeValue("id", "playerOneGamepiece");
52 * @endcode
53 *
54 * Most methods operate on the last node found by @c elementById() or @c elementByUniqueAttributeValue().
55 * If the methods are working on the wrong node, then you are mistaken about which node was
56 * the last node (or you found a bug). Try calling @c setCurrentNode() with the node you are
57 * wanting to modify to see if this is the issue. Consider the following code for example:
58 * @code
59 * QDomNode playerOneGamepiece = svgDom.elementById("playerOneGamepiece");
60 * QDomNode playerTwoGamepiece = svgDom.elementById("playerTwoGamepiece");
61 *
62 * // Set player one's game piece to have a white fill
63 * svgDom.setStyleProperty("fill", "#ffffff"); // INCORRECT: playerTwoGamepiece is the last node, not playerOneGamepiece
64 *
65 * svgDom.setCurrentNode(playerOneGamepiece); // CORRECT: Set current node to the node we want,
66 * svgDom.setStyleProperty("fill", "#ffffff"); // then we modify the node
67 * @endcode
68 *
69 * To skew the @c currentNode():
70 * @code
71 * // Skew the horizontal axis 7.5 degrees
72 * svgDom.skew(-7.5, 0, KGameSvgDocument::ReplaceCurrentMatrix);
73 * @endcode
74 *
75 * @warning Be careful when using the KGameSvgDocument::ApplyToCurrentMatrix flag. It multiplies the matrices,
76 * so if you repeatedly apply the same matrix to a node, you have a polynomial series @c x^2, and you will
77 * very quickly run into overflow issues.
78 *
79 * To output @c currentNode() to be rendered:
80 * @code
81 * QSvgRenderer svgRenderer;
82 * QByteArray svg = svgDom.nodeToByteArray();
83 * svgRenderer.load(svg);
84 * @endcode
85 *
86 * To output the whole document to be rendered (See QDomDocument::toByteArray()):
87 * @code
88 * QSvgRenderer svgRenderer;
89 * QByteArray svg = svgDom.toByteArray();
90 * svgRenderer.load(svg);
91 * @endcode
92 *
93 * @see QDomDocument, QSvgRenderer
94 * @author Mark A. Taff <kde@marktaff.com>
95 * @version 0.1
96 *
97 * @todo Add convenience functions for getting/setting individual style properties.
98 * I haven't completely convinced myself of the utility of this, so don't hold your breathe. ;-)
99 */
100class KDEGAMESPRIVATE_EXPORT KGameSvgDocument : public QDomDocument
101{
102public:
103 /**
104 * @brief Constructor
105 */
106 explicit KGameSvgDocument();
107
108 /**
109 * @brief Copy Constructor
110 */
112
113 /**
114 * @brief Destructor
115 */
117
118 /**
119 * @brief Assignment Operator
120 */
122
123 /**
124 * @brief Options for applying (multiplying) or replacing the current matrix
125 */
127 /**
128 * Apply to current matrix
129 */
131 /**
132 * Replace the current matrix
133 */
135 };
136 /** @brief Q_DECLARE_FLAGS macro confuses doxygen, so create typedef's manually */
138
139 /**
140 * Options for sorting style properties when building a style attribute
141 */
143 /**
144 * When building a style attribute, do not sort
145 */
146 Unsorted = 0x01,
147 /**
148 * When building a style attribute, sort properties the same way Inkscape does
149 */
151 };
152 /** @brief Q_DECLARE_FLAGS macro confuses doxygen, so create typedef's manually */
154
155 /**
156 * @brief Returns the node with the given value for the given attribute.
157 *
158 * Returns the element whose attribute given in @p attributeName is equal to the value
159 * given in @p attributeValue.
160 *
161 * QDomDocument::elementById() always returns a null node because TT says they can't know
162 * which attribute is the id attribute. Here, we allow the id attribute to be specified.
163 *
164 * This function also sets @p m_currentNode to this node.
165 *
166 * @param attributeName The name of the identifying attribute, such as "id" to find.
167 * @param attributeValue The value to look for in the attribute @p attributeName
168 * The values held in this attribute must be unique in the document, or the consequences
169 * may be unpredictably incorrect. You've been warned. ;-)
170 * @returns the matching node, or a null node if no matching node found
171 */
172 QDomNode elementByUniqueAttributeValue(const QString &attributeName, const QString &attributeValue);
173
174 /**
175 * @brief Returns a node with the given id.
176 *
177 * This is a convenience function. We call elementByUniqueAttributeValue(), but we assume
178 * that the name of the attribute is "id". This assumption will be correct for valid SVG files.
179 *
180 * Returns the element whose ID is equal to elementId. If no element with the ID was found,
181 * this function returns a null element.
182 *
183 * @param attributeValue The value of the id attribute to find
184 * @returns the matching node, or a null node if no matching node found
185 * @see elementByUniqueAttributeValue()
186 */
187 QDomNode elementById(const QString &attributeValue);
188
189 /**
190 * @brief Reads the SVG file svgFilename() into DOM.
191 * @returns nothing
192 */
193 void load();
194
195 /**
196 * @overload
197 * @brief This function permits specifying the svg file and loading it at once.
198 *
199 * @param svgFilename The filename of the SVG file to open.
200 * @returns nothing
201 */
202 void load(const QString &svgFilename);
203
204 /**
205 * @brief Rotates the origin of the current node counterclockwise.
206 *
207 * @param degrees The amount in degrees to rotate by.
208 * @param options Apply to current matrix or replace current matrix.
209 * @returns nothing
210 * @see QTransform#rotate()
211 */
212 void rotate(double degrees, MatrixOptions options = ApplyToCurrentMatrix);
213
214 /**
215 * @brief Moves the origin of the current node
216 *
217 * @param xPixels The number of pixels to move the x-axis by.
218 * @param yPixels The number of pixels to move the y-axis by.
219 * @param options Apply to current matrix or replace current matrix.
220 * @returns nothing
221 * @see QTransform::translate()
222 */
223 void translate(int xPixels, int yPixels, MatrixOptions options = ApplyToCurrentMatrix);
224
225 /**
226 * @brief Shears the origin of the current node.
227 *
228 * @param xRadians The amount in radians to shear (skew) the x-axis by.
229 * @param yRadians The amount in radians to shear (skew) the y-axis by.
230 * @param options Apply to current matrix or replace current matrix.
231 * @returns nothing
232 * @see QTransform::shear()
233 */
234 void shear(double xRadians, double yRadians, MatrixOptions options = ApplyToCurrentMatrix);
235
236 /**
237 * @brief Skews the origin of the current node.
238 *
239 * This is a convenience function. It simply converts its arguments to
240 * radians, then calls shear().
241 *
242 * @param xDegrees The amount in degrees to shear (skew) the x-axis by.
243 * @param yDegrees The amount in degrees to shear (skew) the y-axis by.
244 * @param options Apply to current matrix or replace current matrix.
245 * @returns nothing
246 * @see shear()
247 */
248 void skew(double xDegrees, double yDegrees, MatrixOptions options = ApplyToCurrentMatrix);
249
250 /**
251 * @brief Scales the origin of the current node.
252 *
253 * @note Neither @c xFactor nor @c yFactor may be zero, otherwise you scale
254 * the element into nonexistence.
255 *
256 * @param xFactor The factor to scale the x-axis by.
257 * @param yFactor The factor to scale the y-axis by.
258 * @param options Apply to current matrix or replace current matrix.
259 * @returns nothing
260 * @see QTransform::scale()
261 */
262 void scale(double xFactor, double yFactor, MatrixOptions options = ApplyToCurrentMatrix);
263
264 /**
265 * @brief Returns the last node found by elementById, or null if node not found
266 *
267 * @returns The current node
268 * @see setCurrentNode()
269 */
270 QDomNode currentNode() const;
271
272 /**
273 * @brief Sets the current node.
274 *
275 * @param node The node to set currentNode to.
276 * @returns nothing
277 * @see currentNode()
278 */
279 void setCurrentNode(const QDomNode &node);
280
281 /**
282 * @brief Returns the name of the SVG file this DOM represents.
283 *
284 * @returns The current filename.
285 * @see setSvgFilename()
286 */
287 QString svgFilename() const;
288
289 /**
290 * @brief Sets the current SVG filename.
291 *
292 * @param svgFilename The filename of the SVG file to open.
293 * @returns nothing
294 * @see svgFilename()
295 */
297
298 /**
299 * @brief Returns the value of the style property given for the current node.
300 *
301 * @note Internally, we create a hash with @c styleProperties, then return the value
302 * of the @c propertyName property. As such, if you need the values of multiple
303 * properties, it will be more efficient to call @c styleProperties()
304 * and then use the hash directly.
305 *
306 * See KGameSvgDocumentPrivate::m_inkscapeOrder for a list of common SVG style properties
307 *
308 * @param propertyName the name of the property to return
309 * @returns The value style property given, or null if no such property for this node.
310 * @see setStyleProperty(), styleProperties(), setStyleProperties()
311 */
312 QString styleProperty(const QString &propertyName) const;
313
314 /**
315 * @brief Sets the value of the style property given for the current node.
316 *
317 * @note Internally, we create a hash with @c styleProperties, then update the
318 * @p propertyName to @p propertyValue, before finally applying the hash to
319 * DOM via @c setStyleProperties(). Because of this, if you need to set multiple
320 * properties per node, it will be more efficient to call @c styleProperties(),
321 * modify the hash it returns, and then apply the hash with @c setStyleProperties().
322 *
323 * @param propertyName The name of the property to set.
324 * @param propertyValue The value of the property to set.
325 * @returns nothing
326 * @see styleProperty(), styleProperties(), setStyleProperties()
327 */
328 void setStyleProperty(const QString &propertyName, const QString &propertyValue);
329
330 /**
331 * @brief Returns the current node and its children as a new xml svg document.
332 *
333 * @returns The xml for the new svg document
334 */
335 QString nodeToSvg() const;
336
337 /**
338 * @brief Builds a new svg document and returns a QByteArray suitable for passing to QSvgRenderer::load().
339 *
340 * Internally, we call @c nodeToSvg() and then convert to a QByteArray, so this method
341 * should be called @b instead of @c nodeToSvg().
342 *
343 * @returns the QByteArray
344 */
346
347 /**
348 * @brief Returns the style attribute of the current node.
349 *
350 * Unless you are parsing your own style attribute for some reason, you probably
351 * want to use styleProperty() or styleProperties().
352 *
353 * @returns The style attribute.
354 * @see styleProperty() styleProperties()
355 */
356 QString style() const;
357
358 /**
359 * @brief Sets the style attribute of the current node.
360 *
361 * Unless you are parsing your own style attribute for some reason, you probably
362 * want to use setStyleProperty() or setStyleProperties().
363 *
364 * @param styleAttribute The style attribute to apply.
365 * @returns nothing
366 *
367 * @see setStyleProperty() setStyleProperties()
368 */
369 void setStyle(const QString &styleAttribute);
370
371 /**
372 * @brief Returns the patterns in the document
373 *
374 * @returns The patterns in the document
375 */
376 QDomNodeList patterns() const;
377
378 /**
379 * @brief Returns the linearGradients in the document
380 *
381 * @returns The linearGradients in the document
382 */
384
385 /**
386 * @brief Returns the radialGradients in the document
387 *
388 * @returns The radialGradients in the document
389 */
391
392 /**
393 * @brief Returns the defs in the document
394 *
395 * @returns The defs in the document
396 */
397 QDomNodeList defs() const;
398
399 /**
400 * @brief Returns the first def in the document
401 *
402 * @returns The first def in the document
403 */
404 QDomNode def() const;
405
406 /**
407 * @brief Returns the transform attribute of the current node.
408 * @returns The transform attribute.
409 * @see setTransform(), transformMatrix(), setTransformMatrix()
410 */
411 QString transform() const;
412
413 /**
414 * @brief Sets the transform attribute of the current node.
415 *
416 * As this function works on QStrings, it <b>replaces</b> the existing
417 * transform attribute. If you need to multiply, use setTransformMatrix() instead.
418 *
419 * @param transformAttribute The transform attribute to apply.
420 * @returns nothing
421 * @see transform(), transformMatrix(), setTransformMatrix()
422 */
423 void setTransform(const QString &transformAttribute);
424
425 /**
426 * @brief Returns a hash of the style properties of the current node.
427 * @returns The style properties.
428 * @see setStyleProperties()
429 */
431
432 /**
433 * @brief Sets the style properties of the current node.
434 *
435 * The only(?) reason to set useInkscapeOrder to true is if you are saving the svg xml to a file
436 * that may be human-edited later, for consistency. There is a performance hit, since hashes store
437 * their data unsorted.
438 *
439 * @param _styleProperties The hash of style properties to apply.
440 * @param options Apply the hash so the properties are in the same order as Inkscape writes them.
441 * @returns nothing
442 * @see styleProperties()
443 */
444 void setStyleProperties(const QHash<QString, QString> &_styleProperties, const StylePropertySortOptions &options = Unsorted);
445
446 /**
447 * @brief Returns the transform attribute of the current node as a matrix.
448 *
449 * @returns The matrix for the transform attribute.
450 * @see setTransformMatrix()
451 */
453
454 /**
455 * @brief Sets the transform attribute of the current node.
456 *
457 * @param matrix The matrix to apply.
458 * @param options Should we apply matrix to the current matrix?
459 * We modify matrix internally if @p options includes ApplyToCurrentMatrix, so it can't
460 * be passed as const.
461 * Normally we want to apply the existing matrix. If we apply the matrix,
462 * we potentially end up squaring with each call, e.g. x^2.
463 * @returns nothing
464 * @see transformMatrix()
465 */
467
468private:
469 /**
470 * @brief d-pointer
471 */
472 std::unique_ptr<KGameSvgDocumentPrivate> const d;
473};
474Q_DECLARE_OPERATORS_FOR_FLAGS(KGameSvgDocument::MatrixOptions)
475Q_DECLARE_OPERATORS_FOR_FLAGS(KGameSvgDocument::StylePropertySortOptions)
476
477#endif // _KGAMESVGDOCUMENT_H_
void translate(int xPixels, int yPixels, MatrixOptions options=ApplyToCurrentMatrix)
Moves the origin of the current node.
void setTransformMatrix(QTransform &matrix, MatrixOptions options=ApplyToCurrentMatrix)
Sets the transform attribute of the current node.
void scale(double xFactor, double yFactor, MatrixOptions options=ApplyToCurrentMatrix)
Scales the origin of the current node.
QDomNodeList linearGradients() const
Returns the linearGradients in the document.
void setTransform(const QString &transformAttribute)
Sets the transform attribute of the current node.
QFlags< MatrixOption > MatrixOptions
Q_DECLARE_FLAGS macro confuses doxygen, so create typedef's manually.
virtual ~KGameSvgDocument()
Destructor.
void load()
Reads the SVG file svgFilename() into DOM.
void rotate(double degrees, MatrixOptions options=ApplyToCurrentMatrix)
Rotates the origin of the current node counterclockwise.
void setStyleProperties(const QHash< QString, QString > &_styleProperties, const StylePropertySortOptions &options=Unsorted)
Sets the style properties of the current node.
void setSvgFilename(const QString &svgFilename)
Sets the current SVG filename.
KGameSvgDocument()
Constructor.
void setStyleProperty(const QString &propertyName, const QString &propertyValue)
Sets the value of the style property given for the current node.
QString svgFilename() const
Returns the name of the SVG file this DOM represents.
QHash< QString, QString > styleProperties() const
Returns a hash of the style properties of the current node.
QDomNodeList defs() const
Returns the defs in the document.
QDomNode def() const
Returns the first def in the document.
QString nodeToSvg() const
Returns the current node and its children as a new xml svg document.
void shear(double xRadians, double yRadians, MatrixOptions options=ApplyToCurrentMatrix)
Shears the origin of the current node.
QString styleProperty(const QString &propertyName) const
Returns the value of the style property given for the current node.
MatrixOption
Options for applying (multiplying) or replacing the current matrix.
@ ApplyToCurrentMatrix
Apply to current matrix.
@ ReplaceCurrentMatrix
Replace the current matrix.
QDomNodeList radialGradients() const
Returns the radialGradients in the document.
void setStyle(const QString &styleAttribute)
Sets the style attribute of the current node.
void setCurrentNode(const QDomNode &node)
Sets the current node.
QDomNodeList patterns() const
Returns the patterns in the document.
QString transform() const
Returns the transform attribute of the current node.
QTransform transformMatrix() const
Returns the transform attribute of the current node as a matrix.
QString style() const
Returns the style attribute of the current node.
QDomNode currentNode() const
Returns the last node found by elementById, or null if node not found.
void skew(double xDegrees, double yDegrees, MatrixOptions options=ApplyToCurrentMatrix)
Skews the origin of the current node.
QDomNode elementByUniqueAttributeValue(const QString &attributeName, const QString &attributeValue)
Returns the node with the given value for the given attribute.
QByteArray nodeToByteArray() const
Builds a new svg document and returns a QByteArray suitable for passing to QSvgRenderer::load().
StylePropertySortOption
Options for sorting style properties when building a style attribute.
@ UseInkscapeOrder
When building a style attribute, sort properties the same way Inkscape does.
@ Unsorted
When building a style attribute, do not sort.
QFlags< StylePropertySortOption > StylePropertySortOptions
Q_DECLARE_FLAGS macro confuses doxygen, so create typedef's manually.
QDomElement elementById(const QString &elementId)
QDomDocument & operator=(const QDomDocument &x)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Thu Jan 23 2025 18:49:14 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.