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 */
130 ApplyToCurrentMatrix = 0x01,
131 /**
132 * Replace the current matrix
133 */
134 ReplaceCurrentMatrix = 0x02
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 */
150 UseInkscapeOrder = 0x02
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 */
296 void setSvgFilename(const QString &svgFilename);
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 */
345 QByteArray nodeToByteArray() const;
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 */
383 QDomNodeList linearGradients() const;
384
385 /**
386 * @brief Returns the radialGradients in the document
387 *
388 * @returns The radialGradients in the document
389 */
390 QDomNodeList radialGradients() const;
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 */
430 QHash<QString, QString> styleProperties() const;
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 */
452 QTransform transformMatrix() const;
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 */
466 void setTransformMatrix(QTransform &matrix, MatrixOptions options = ApplyToCurrentMatrix);
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_
A class for manipulating an SVG file using DOM.
QFlags< MatrixOption > MatrixOptions
Q_DECLARE_FLAGS macro confuses doxygen, so create typedef's manually.
virtual ~KGameSvgDocument()
Destructor.
MatrixOption
Options for applying (multiplying) or replacing the current matrix.
StylePropertySortOption
Options for sorting style properties when building a style attribute.
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-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:16:50 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.