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