1 /*
2    Drawpile - a collaborative drawing program.
3 
4    Copyright (C) 2008-2019 Calle Laakkonen
5 
6    Drawpile is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    Drawpile is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Drawpile.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef LAYERSTACK_H
20 #define LAYERSTACK_H
21 
22 #include "annotationmodel.h"
23 #include "tile.h"
24 
25 #include <cstdint>
26 
27 #include <QObject>
28 #include <QList>
29 #include <QImage>
30 
31 class QDataStream;
32 
33 namespace paintcore {
34 
35 class LayerStackObserver;
36 class Layer;
37 class EditableLayer;
38 class EditableLayerStack;
39 class Tile;
40 struct Savepoint;
41 struct LayerInfo;
42 
43 /**
44  * \brief A stack of layers.
45  */
46 class LayerStack : public QObject {
47 	Q_PROPERTY(AnnotationModel* annotations READ annotations CONSTANT)
48 	Q_OBJECT
49 	friend class EditableLayerStack;
50 	friend class LayerStackObserver;
51 public:
52 	enum ViewMode {
53 		NORMAL,   // show all layers normally
54 		SOLO,     // show only the view layer
55 		ONIONSKIN // show view layer + few layers below it with decreasing opacity
56 	};
57 
58 	LayerStack(QObject *parent=nullptr);
59 	~LayerStack();
60 
61 	//! Return a copy of this LayerStack
62 	LayerStack *clone(QObject *newParent=nullptr) const { return new LayerStack(this, newParent); }
63 
64 	//! Get the background tile
background()65 	Tile background() const { return m_backgroundTile; }
66 
67 	//! Get the number of layers in the stack
layerCount()68 	int layerCount() const { return m_layers.count(); }
69 
70 	//! Get a read only layer by its index
71 	const Layer *getLayerByIndex(int index) const;
72 
73 	//! Get a read only layer by its ID
74 	const Layer *getLayer(int id) const;
75 
76 	//! Get this layer stack's annotations
annotations()77 	const AnnotationModel *annotations() const { return m_annotations; }
annotations()78 	AnnotationModel *annotations() { return m_annotations; }
79 
80 	//! Get the index of the specified layer
81 	int indexOf(int id) const;
82 
83 	//! Get the width of the layer stack
width()84 	int width() const { return m_width; }
85 
86 	//! Get the height of the layer stack
height()87 	int height() const { return m_height; }
88 
89 	//! Get the width and height of the layer stack
size()90 	QSize size() const { return QSize(m_width, m_height); }
91 
92 	//! Paint all changed tiles in the given area
93 	void paintChangedTiles(const QRect& rect, QPaintDevice *target, bool clean=true);
94 
95 	//! Return the topmost visible layer with a color at the point
96 	const Layer *layerAt(int x, int y) const;
97 
98 	//! Get the merged color value at the point
99 	QColor colorAt(int x, int y, int dia=0) const;
100 
101 	//! Get the "last edited by" tag of the topmost visible tile
102 	int tileLastEditedBy(int tx, int ty) const;
103 
104 	/**
105 	 * @brief Return a flattened image of the layer stack
106 	 *
107 	 * Note: if includeBackground is false, layers marked as *fixed* will not
108 	 * be included in the flattened image.
109 	 *
110 	 * @param includeAnnotations merge annotations onto the final image
111 	 * @param includeBackground include canvas background and fixed layers
112 	 */
113 	QImage toFlatImage(bool includeAnnotations, bool includeBackground, bool includeSublayers) const;
114 
115 	/**
116 	 * @brief Return a single layer merged with the background
117 	 *
118 	 * Note: fixed layers are also considered background and will be included as well,
119 	 * even those above the target index
120 	 */
121 	QImage flatLayerImage(int layerIdx) const;
122 
123 	//! Get a merged tile
124 	Tile getFlatTile(int x, int y) const;
125 
126 	//! Create a new savepoint
127 	Savepoint makeSavepoint();
128 
129 	//! Get the current view rendering mode
viewMode()130 	ViewMode viewMode() const { return m_viewmode; }
131 
132 	//! Are layers tagged for censoring actually censored?
isCensored()133 	bool isCensored() const { return m_censorLayers; }
134 
135 	/**
136 	 * @brief Set the canvas resolution (dots per inch)
137 	 *
138 	 * This information is not used internally by Drawpile, but it
139 	 * can be saved in files to be used by other programs.
140 	 */
setDpi(int x,int y)141 	void setDpi(int x, int y) { m_dpix = x; m_dpiy = y; }
setDpi(QPair<int,int> dpi)142 	void setDpi(QPair<int,int> dpi) { m_dpix = dpi.first; m_dpiy = dpi.second; }
143 
144 	/**
145 	 * @brief Get the canvas resolution
146 	 *
147 	 * If either component is zero, the default DPI should be assumed.
148 	 */
dotsPerInch()149 	QPair<int,int> dotsPerInch() const { return QPair<int,int>(m_dpix, m_dpiy); }
150 
151 	/**
152 	 * @brief Find a layer with a sublayer with the given ID and return its change bounds
153 	 * @param contextid
154 	 * @return Layer ID, Change bounds pair
155 	 */
156 	QPair<int,QRect> findChangeBounds(int contextid);
157 
158 	//! Get a list of layer stack observers
observers()159 	const QList<LayerStackObserver*> observers() const { return m_observers; }
160 
161 	//! Start a layer stack editing sequence
162 	inline EditableLayerStack editor(int contextId);
163 
164 signals:
165 	//! Canvas width/height changed
166 	void resized(int xoffset, int yoffset, const QSize &oldsize);
167 
168 private:
169 	LayerStack(const LayerStack *orig, QObject *parent);
170 
171 	// Emission of areaChanged is suppressed during an active write sequence
172 	void beginWriteSequence();
173 	void endWriteSequence();
174 
175 	void flattenTile(quint32 *data, int xindex, int yindex) const;
176 
177 	bool isVisible(int idx) const;
178 	int layerOpacity(int idx) const;
179 	quint32 layerTint(int idx) const;
180 
181 	QList<LayerStackObserver*> m_observers;
182 
183 	int m_width, m_height;
184 	int m_xtiles, m_ytiles;
185 	int m_dpix, m_dpiy;
186 
187 	QList<Layer*> m_layers;
188 	AnnotationModel *m_annotations;
189 
190 	Tile m_backgroundTile;
191 
192 	ViewMode m_viewmode;
193 	int m_viewlayeridx;
194 	int m_highlightId;
195 	int m_onionskinsBelow, m_onionskinsAbove;
196 	int m_openEditors;
197 
198 	bool m_onionskinTint;
199 	bool m_censorLayers;
200 };
201 
202 /// Layer stack savepoint for undo use
203 struct Savepoint {
204 	Savepoint() = default;
205 	Savepoint(const Savepoint &other);
206 	~Savepoint();
207 
208 	Savepoint &operator=(const Savepoint &other);
209 
210 	QList<Layer*> layers;
211 	QList<Annotation> annotations;
212 	Tile background;
213 	QSize size;
214 };
215 
216 /**
217  * @brief A wrapper class for editing a LayerStack
218  */
219 class EditableLayerStack {
220 public:
EditableLayerStack(LayerStack * layerstack,int contextId)221 	explicit EditableLayerStack(LayerStack *layerstack, int contextId)
222 		: d(layerstack), contextId(contextId)
223 	{
224 		Q_ASSERT(d);
225 		d->beginWriteSequence();
226 	}
EditableLayerStack(EditableLayerStack && other)227 	EditableLayerStack(EditableLayerStack &&other)
228 	{
229 		d = other.d;
230 		other.d = nullptr;
231 	}
232 
233 	EditableLayerStack(const EditableLayerStack&) = delete;
234 	EditableLayerStack &operator=(const EditableLayerStack&) = delete;
235 
~EditableLayerStack()236 	~EditableLayerStack()
237 	{
238 		if(d)
239 			d->endWriteSequence();
240 	}
241 
242 	//! Adjust layer stack size
243 	void resize(int top, int right, int bottom, int left);
244 
245 	//! Set the background tile
246 	void setBackground(const Tile &tile);
247 
248 	//! Create a new layer
249 	EditableLayer createLayer(int id, int source, const QColor &color, bool insert, bool copy, const QString &name);
250 
251 	//! Delete a layer
252 	bool deleteLayer(int id);
253 
254 	//! Merge the layer to the one below it
255 	void mergeLayerDown(int id);
256 
257 	//! Re-order the layer stack
258 	void reorderLayers(const QList<uint16_t> &neworder);
259 
260 	//! Get a layer by its index
261 	EditableLayer getEditableLayerByIndex(int index);
262 
263 	//! Get a layer wrapped in EditableLayer
264 	EditableLayer getEditableLayer(int id);
265 
266 	//! Clear the entire layer stack
267 	void reset();
268 
269 	//! Remove all preview layers (ephemeral sublayers)
270 	void removePreviews();
271 
272 	//! Merge all sublayers with the given ID
273 	void mergeSublayers(int id);
274 
275 	//! Merge all sublayers with positive IDs
276 	void mergeAllSublayers();
277 
278 	//! Set layer view mode
279 	void setViewMode(LayerStack::ViewMode mode);
280 
281 	//! Highlight all tiles last edited by this user. If set to 0, highlighting is disabled
282 	void setInspectorHighlight(int contextId);
283 
284 	//! Set the selected layer (used by view modes other than NORMAL)
285 	void setViewLayer(int id);
286 
287 	//! Set onionskin view mode parameters
288 	void setOnionskinMode(int below, int above, bool tint);
289 
290 	//! Enable/disable censoring of layers
291 	void setCensorship(bool censor);
292 
293 	//! Restore layer stack to a previous savepoint
294 	void restoreSavepoint(const Savepoint &savepoint);
295 
layerStack()296 	const LayerStack *layerStack() const { return d; }
297 
298 	const LayerStack *operator ->() const { return d; }
299 
300 private:
301 	LayerStack *d;
302 	int contextId;
303 };
304 
editor(int contextId)305 EditableLayerStack LayerStack::editor(int contextId) { return EditableLayerStack(this, contextId); }
306 
307 }
308 
309 #endif
310 
311