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 
20 #include "layer.h"
21 #include "layerstack.h"
22 #include "layerstackobserver.h"
23 #include "tile.h"
24 #include "rasterop.h"
25 #include "concurrent.h"
26 
27 #include <QPainter>
28 #include <QMimeData>
29 #include <QDataStream>
30 
31 namespace paintcore {
32 
33 static const Tile CENSORED_TILE = Tile::ZebraBlock(QColor("#232629"), QColor("#eff0f1"));
34 static const Tile ZEBRA_TILE = Tile::ZebraBlock(Qt::red, Qt::black, 2);
35 
36 static const int MAX_SIZE = 32767;
37 
LayerStack(QObject * parent)38 LayerStack::LayerStack(QObject *parent)
39 	: QObject(parent), m_width(0), m_height(0), m_xtiles(0), m_ytiles(0), m_dpix(0), m_dpiy(0),
40 	m_viewmode(NORMAL), m_viewlayeridx(0), m_highlightId(0),
41 	m_onionskinsBelow(4), m_onionskinsAbove(4), m_openEditors(0), m_onionskinTint(true), m_censorLayers(false)
42 {
43 	m_annotations = new AnnotationModel(this);
44 }
45 
LayerStack(const LayerStack * orig,QObject * parent)46 LayerStack::LayerStack(const LayerStack *orig, QObject *parent)
47 	: QObject(parent),
48 	  m_width(orig->m_width),
49 	  m_height(orig->m_height),
50 	  m_xtiles(orig->m_xtiles),
51 	  m_ytiles(orig->m_ytiles),
52 	  m_dpix(orig->m_dpix),
53 	  m_dpiy(orig->m_dpiy),
54 	  m_viewmode(orig->m_viewmode),
55 	  m_viewlayeridx(orig->m_viewlayeridx),
56 	  m_highlightId(orig->m_highlightId),
57 	  m_onionskinsBelow(orig->m_onionskinsBelow),
58 	  m_openEditors(0),
59 	  m_onionskinTint(orig->m_onionskinTint),
60 	  m_censorLayers(orig->m_censorLayers)
61 {
62 	m_annotations = orig->m_annotations->clone(this);
63 	m_backgroundTile = orig->m_backgroundTile;
64 	for(const Layer *l : orig->m_layers)
65 		m_layers << new Layer(*l);
66 }
67 
~LayerStack()68 LayerStack::~LayerStack()
69 {
70 	for(LayerStackObserver *observer : m_observers)
71 		observer->detachFromLayerStack();
72 
73 	for(Layer *l : m_layers)
74 		delete l;
75 }
76 
findChangeBounds(int contextId)77 QPair<int,QRect> LayerStack::findChangeBounds(int contextId)
78 {
79 	for(const Layer *l : m_layers) {
80 		const QRect r = l->changeBounds(contextId);
81 		if(!r.isNull())
82 			return QPair<int,QRect>(l->id(), r);
83 	}
84 	return QPair<int,QRect>(0, QRect());
85 }
86 
getLayerByIndex(int index) const87 const Layer *LayerStack::getLayerByIndex(int index) const
88 {
89 	return m_layers.at(index);
90 }
91 
getLayer(int id) const92 const Layer *LayerStack::getLayer(int id) const
93 {
94 	// Since the expected number of layers is always fairly low,
95 	// we can get away with a simple linear search. (Note that IDs
96 	// may appear in random order due to layers being moved around.)
97 	for(const Layer *l : m_layers)
98 		if(l->id() == id)
99 			return l;
100 	return nullptr;
101 }
102 
103 /**
104  * @param id layer id
105  * @return layer index. Returns a negative index if layer is not found
106  */
indexOf(int id) const107 int LayerStack::indexOf(int id) const
108 {
109 	for(int i=0;i<m_layers.size();++i)
110 		if(m_layers.at(i)->id() == id)
111 			return i;
112 	return -1;
113 }
114 
getFlatTile(int x,int y) const115 Tile LayerStack::getFlatTile(int x, int y) const
116 {
117 	Tile t = m_backgroundTile;
118 	flattenTile(t.data(), x, y);
119 	return t;
120 }
121 
layerAt(int x,int y) const122 const Layer *LayerStack::layerAt(int x, int y) const
123 {
124 	for(int i=m_layers.size()-1;i>=0;--i) {
125 		const Layer * l = m_layers.at(i);
126 		if(l->isVisible()) {
127 			if(l->pixelAt(x,y) > 0)
128 				return l;
129 
130 			// Check sublayers too
131 			for(const Layer *sl : l->sublayers()) {
132 				if(sl->isVisible() && sl->pixelAt(x, y) > 0)
133 					return l;
134 			}
135 		}
136 	}
137 	return nullptr;
138 }
139 
colorAt(int x,int y,int dia) const140 QColor LayerStack::colorAt(int x, int y, int dia) const
141 {
142 	if(m_layers.isEmpty())
143 		return QColor();
144 
145 	if(x<0 || y<0 || x>=m_width || y>=m_height)
146 		return QColor();
147 
148 	if(dia<=1) {
149 		// TODO some more efficient way of doing this
150 		Tile tile = getFlatTile(x/Tile::SIZE, y/Tile::SIZE);
151 		quint32 c = tile.data()[(y-Tile::roundDown(y)) * Tile::SIZE + (x-Tile::roundDown(x))];
152 		return QColor(c);
153 
154 	} else {
155 		const int r = dia/2+1;
156 		const int x1 = qBound(0, (x-r) / Tile::SIZE, m_xtiles-1);
157 		const int x2 = qBound(0, (x+r) / Tile::SIZE, m_xtiles-1);
158 		const int y1 = qBound(0, (y-r) / Tile::SIZE, m_ytiles-1);
159 		const int y2 = qBound(0, (y+r) / Tile::SIZE, m_ytiles-1);
160 
161 		Layer flat(0, QString(), Qt::transparent, size());
162 		EditableLayer ef(&flat, nullptr, 0);
163 
164 		ef.putTile(0, 0, 9999*9999, m_backgroundTile);
165 
166 		for(int tx=x1;tx<=x2;++tx) {
167 			for(int ty=y1;ty<=y2;++ty) {
168 				ef.putTile(tx, ty, 0, getFlatTile(tx, ty));
169 			}
170 		}
171 
172 		return flat.colorAt(x, y, dia);
173 	}
174 }
175 
tileLastEditedBy(int tx,int ty) const176 int LayerStack::tileLastEditedBy(int tx, int ty) const
177 {
178 	if(tx < 0 || ty < 0 || tx >= m_xtiles || ty >= m_ytiles)
179 		return 0;
180 
181 	for(int i=m_layers.size()-1;i>=0;--i) {
182 		if(isVisible(i)) {
183 			const Tile &t = m_layers.at(i)->tile(tx, ty);
184 			if(!t.isNull())
185 				return t.lastEditedBy();
186 		}
187 	}
188 
189 	return 0;
190 }
191 
toFlatImage(bool includeAnnotations,bool includeBackground,bool includeSublayers) const192 QImage LayerStack::toFlatImage(bool includeAnnotations, bool includeBackground, bool includeSublayers) const
193 {
194 	if(m_layers.isEmpty())
195 		return QImage();
196 
197 	Layer flat(0, QString(), Qt::transparent, size());
198 	EditableLayer ef(&flat, nullptr, 0);
199 
200 	if(includeBackground)
201 		ef.putTile(0, 0, 9999*9999, m_backgroundTile);
202 
203 	for(int i=0;i<m_layers.size();++i) {
204 		if(m_layers.at(i)->isVisible() && (includeBackground || !m_layers.at(i)->isFixed())) {
205 			const Layer *l = m_layers.at(i);
206 			if(includeSublayers && l->hasSublayers()) {
207 				Layer ll = Layer(*l);
208 				EditableLayer el(&ll, nullptr, 0);
209 				el.mergeAllSublayers();
210 				ef.merge(&ll);
211 
212 			} else {
213 				ef.merge(l);
214 			}
215 		}
216 	}
217 
218 	QImage image = ef->toImage();
219 
220 	if(includeAnnotations) {
221 		QPainter painter(&image);
222 		for(const Annotation &a : m_annotations->getAnnotations())
223 			a.paint(&painter);
224 	}
225 
226 	if(m_dpix > 0 && m_dpiy > 0) {
227 		image.setDotsPerMeterX(int(m_dpix / 0.0254));
228 		image.setDotsPerMeterY(int(m_dpiy / 0.0254));
229 	}
230 	return image;
231 }
232 
flatLayerImage(int layerIdx) const233 QImage LayerStack::flatLayerImage(int layerIdx) const
234 {
235 	Q_ASSERT(layerIdx>=0 && layerIdx < m_layers.size());
236 
237 	Layer flat(0, QString(), Qt::transparent, size());
238 	EditableLayer ef(&flat, nullptr, 0);
239 
240 	ef.putTile(0, 0, 9999*9999, m_backgroundTile);
241 
242 	for(int i=0;i<m_layers.size();++i) {
243 		if(i == layerIdx || m_layers.at(i)->isFixed())
244 			ef.merge(m_layers.at(i));
245 	}
246 
247 	QImage image = ef->toImage();
248 	if(m_dpix > 0 && m_dpiy > 0) {
249 		image.setDotsPerMeterX(int(m_dpix / 0.0254));
250 		image.setDotsPerMeterY(int(m_dpiy / 0.0254));
251 	}
252 
253 	return image;
254 }
255 
256 // Flatten a single tile
flattenTile(quint32 * data,int xindex,int yindex) const257 void LayerStack::flattenTile(quint32 *data, int xindex, int yindex) const
258 {
259 	// Composite visible layers
260 	int layeridx = 0;
261 	for(const Layer *l : m_layers) {
262 		if(isVisible(layeridx)) {
263 			const Tile &tile = l->tile(xindex, yindex);
264 			const quint32 tint = layerTint(layeridx);
265 
266 			if(m_censorLayers && l->isCensored()) {
267 				// This layer must be censored
268 				if(!tile.isNull())
269 					compositePixels(l->blendmode(), data, CENSORED_TILE.constData(),
270 							Tile::LENGTH, layerOpacity(layeridx));
271 
272 			} else if(l->sublayers().count() || tint!=0 || m_highlightId > 0) {
273 				// Sublayers (or tint) present, composite them first
274 				quint32 ldata[Tile::SIZE*Tile::SIZE];
275 				tile.copyTo(ldata);
276 
277 				for(const Layer *sl : l->sublayers()) {
278 					if(sl->isVisible()) {
279 						const Tile &subtile = sl->tile(xindex, yindex);
280 						if(!subtile.isNull()) {
281 							compositePixels(sl->blendmode(), ldata, subtile.constData(),
282 									Tile::LENGTH, sl->opacity());
283 						}
284 					}
285 				}
286 
287 				if(m_highlightId > 0 && m_highlightId == tile.lastEditedBy()) {
288 					// MODE_RECOLOR looks really nice here, but can be misleading.
289 					// Use per-pixel highlighting if/when per-pixel tagging is implemented.
290 					compositePixels(BlendMode::MODE_NORMAL, ldata, ZEBRA_TILE.constData(),
291 							Tile::LENGTH, 128);
292 				}
293 
294 				if(tint)
295 					tintPixels(ldata, sizeof ldata / sizeof *ldata, tint);
296 
297 
298 				// Composite merged tile
299 				compositePixels(l->blendmode(), data, ldata,
300 						Tile::SIZE*Tile::SIZE, layerOpacity(layeridx));
301 
302 			} else if(!tile.isNull()) {
303 				// No sublayers or tint, just this tile as it is
304 				compositePixels(l->blendmode(), data, tile.constData(),
305 						Tile::LENGTH, layerOpacity(layeridx));
306 			}
307 		}
308 
309 		++layeridx;
310 	}
311 }
312 
beginWriteSequence()313 void LayerStack::beginWriteSequence()
314 {
315 	++m_openEditors;
316 }
317 
endWriteSequence()318 void LayerStack::endWriteSequence()
319 {
320 	--m_openEditors;
321 	Q_ASSERT(m_openEditors>=0);
322 	if(m_openEditors == 0) {
323 		for(auto observer : m_observers)
324 			observer->canvasWriteSequenceDone();
325 	}
326 }
327 
layerOpacity(int idx) const328 int LayerStack::layerOpacity(int idx) const
329 {
330 	Q_ASSERT(idx>=0 && idx < m_layers.size());
331 	int o = m_layers.at(idx)->opacity();
332 
333 	if(viewMode()==ONIONSKIN && !m_layers.at(idx)->isFixed()) {
334 
335 		const int d = m_viewlayeridx - idx;
336 		qreal rd;
337 		if(d<0 && d>=-m_onionskinsAbove)
338 			rd = -d/qreal(m_onionskinsAbove+1);
339 		else if(d>=0 && d <=m_onionskinsBelow)
340 			rd = d/qreal(m_onionskinsBelow+1);
341 		else
342 			return 0;
343 
344 		return int(o * ((1-rd) * (1-rd)));
345 	}
346 
347 	return o;
348 }
349 
layerTint(int idx) const350 quint32 LayerStack::layerTint(int idx) const
351 {
352 	if(m_onionskinTint && viewMode() == ONIONSKIN && !m_layers.at(idx)->isFixed()) {
353 		if(idx < m_viewlayeridx)
354 			return 0x80ff3333;
355 		else if(idx > m_viewlayeridx)
356 			return 0x803333ff;
357 	}
358 
359 	return 0;
360 }
361 
isVisible(int idx) const362 bool LayerStack::isVisible(int idx) const
363 {
364 	Q_ASSERT(idx>=0 && idx < m_layers.size());
365 	if(!m_layers.at(idx)->isVisible())
366 		return false;
367 
368 	switch(viewMode()) {
369 	case NORMAL: break;
370 	case SOLO: return idx == m_viewlayeridx || m_layers.at(idx)->isFixed();
371 	case ONIONSKIN: return layerOpacity(idx) > 0;
372 	}
373 
374 	return true;
375 }
376 
makeSavepoint()377 Savepoint LayerStack::makeSavepoint()
378 {
379 	Savepoint sp;
380 	for(Layer *l : m_layers) {
381 		l->optimize();
382 		sp.layers.append(new Layer(*l));
383 	}
384 
385 	sp.annotations = m_annotations->getAnnotations();
386 	sp.background = m_backgroundTile;
387 
388 	sp.size = size();
389 
390 	return sp;
391 }
392 
Savepoint(const Savepoint & other)393 Savepoint::Savepoint(const Savepoint &other)
394 {
395 	for(Layer *l : other.layers)
396 		layers << new Layer(*l);
397 	annotations = other.annotations;
398 	background = other.background;
399 	size = other.size;
400 }
401 
operator =(const Savepoint & other)402 Savepoint &Savepoint::operator=(const Savepoint &other)
403 {
404 	if(&other != this) {
405 		for(Layer *l : layers)
406 			delete l;
407 		layers.clear();
408 		for(Layer *l : other.layers)
409 			layers << new Layer(*l);
410 		annotations = other.annotations;
411 		background = other.background;
412 		size = other.size;
413 	}
414 	return *this;
415 }
416 
~Savepoint()417 Savepoint::~Savepoint()
418 {
419 	for(Layer *l : layers)
420 		delete l;
421 }
422 
restoreSavepoint(const Savepoint & savepoint)423 void EditableLayerStack::restoreSavepoint(const Savepoint &savepoint)
424 {
425 	const QSize oldsize(d->m_width, d->m_height);
426 	if(d->width() != savepoint.size.width() || d->height() != savepoint.size.height()) {
427 		// Restore canvas size if it was different in the savepoint
428 		d->m_width = savepoint.size.width();
429 		d->m_height = savepoint.size.height();
430 		d->m_xtiles = Tile::roundTiles(d->m_width);
431 		d->m_ytiles = Tile::roundTiles(d->m_height);
432 		for(auto observer : d->m_observers)
433 			observer->canvasResized(0, 0, oldsize);
434 		emit d->resized(0, 0, oldsize);
435 
436 	} else {
437 		// Mark changed tiles as changed. Usually savepoints are quite close together
438 		// so most tiles will remain unchanged
439 		if(savepoint.layers.size() != d->m_layers.size()) {
440 			// Layers added or deleted, just refresh everything
441 			// (force refresh even if layer stack is empty)
442 			for(auto observer : d->m_observers)
443 				observer->markDirty();
444 
445 		} else {
446 			// Layer count has not changed, compare layer contents
447 			for(int l=0;l<savepoint.layers.size();++l) {
448 				const Layer *l0 = d->m_layers.at(l);
449 				const Layer *l1 = savepoint.layers.at(l);
450 				if(l0->effectiveOpacity() != l1->effectiveOpacity()) {
451 					// Layer opacity has changed, refresh everything
452 					for(auto observer : d->m_observers)
453 						observer->markDirty();
454 					break;
455 				}
456 
457 				// Gather list of sublayer IDs to compare
458 				QVarLengthArray<int, 10> sublayers;
459 				for(const Layer *sl : l0->sublayers())
460 					if(!sl->isHidden() && !sublayers.contains(sl->id()))
461 						sublayers << sl->id();
462 
463 				for(const Layer *sl : l1->sublayers())
464 					if(!sl->isHidden() && !sublayers.contains(sl->id()))
465 						sublayers << sl->id();
466 
467 				// Compare sublayers
468 				const int tilecount = d->m_xtiles * d->m_ytiles;
469 
470 				for(int sublayerId : sublayers) {
471 					const Layer *sl0 = l0->getVisibleSublayer(sublayerId);
472 					const Layer *sl1 = l1->getVisibleSublayer(sublayerId);
473 					const Layer *delta = nullptr;
474 
475 					if(sl0) {
476 						if(sl1) {
477 							// Visible in both, compare content
478 							for(int i=0;i<tilecount;++i) {
479 								// Note: An identity comparison works here, because the tiles
480 								// utilize copy-on-write semantics. Unchanged tiles will share
481 								// data pointers between savepoints.
482 								if(sl0->tile(i) != sl1->tile(i)) {
483 									for(auto observer : d->m_observers)
484 										observer->markDirty(i);
485 								}
486 							}
487 						} else {
488 							// Not visible in sl1
489 							delta = sl0;
490 						}
491 					} else {
492 						// Not visible in sl0, therefore must be visible in sl1
493 						delta = sl1;
494 					}
495 
496 					if(delta) {
497 						// Visible in one but not both: mark opaque areas as dirty
498 						for(int i=0;i<tilecount;++i) {
499 							if(!delta->tile(i).isNull())
500 								for(auto observer : d->m_observers)
501 									observer->markDirty(i);
502 						}
503 					}
504 				}
505 
506 				// Compare the main layer
507 				for(int i=0;i<d->m_xtiles*d->m_ytiles;++i) {
508 					// Note: An identity comparison works here, because the tiles
509 					// utilize copy-on-write semantics. Unchanged tiles will share
510 					// data pointers between savepoints.
511 					if(l0->tile(i) != l1->tile(i)) {
512 						for(auto observer : d->m_observers)
513 							observer->markDirty(i);
514 					}
515 				}
516 			}
517 		}
518 	}
519 
520 	// Restore layers
521 	while(!d->m_layers.isEmpty())
522 		delete d->m_layers.takeLast();
523 	for(const Layer *l : savepoint.layers)
524 		d->m_layers.append(new Layer(*l));
525 
526 	// Restore background
527 	setBackground(savepoint.background);
528 
529 	// Restore annotations
530 	d->m_annotations->setAnnotations(savepoint.annotations);
531 }
532 
resize(int top,int right,int bottom,int left)533 void EditableLayerStack::resize(int top, int right, int bottom, int left)
534 {
535 	const QSize oldsize(d->m_width, d->m_height);
536 
537 	const int newtop = -top;
538 	const int newleft = -left;
539 	const int newright = d->m_width + right;
540 	const int newbottom = d->m_height + bottom;
541 	if(newtop >= newbottom || newleft >= newright) {
542 		qWarning("Invalid resize: borders reversed");
543 		return;
544 	}
545 
546 	const int newwidth = newright - newleft;
547 	const int newheight = newbottom - newtop;
548 
549 	if(newwidth < 1 || newheight < 1 || newwidth > MAX_SIZE || newheight > MAX_SIZE) {
550 		qWarning("Invalid resize: size would be %d x %d", newwidth, newheight);
551 		return;
552 	}
553 
554 	d->m_width = newwidth;
555 	d->m_height = newheight;
556 
557 	d->m_xtiles = Tile::roundTiles(d->m_width);
558 	d->m_ytiles = Tile::roundTiles(d->m_height);
559 
560 	for(Layer *l : d->m_layers)
561 		EditableLayer(l, d, contextId).resize(top, right, bottom, left);
562 
563 	if(left || top) {
564 		// Update annotation positions
565 		QPoint offset(left, top);
566 		for(const Annotation &a : d->m_annotations->getAnnotations()) {
567 			d->m_annotations->reshapeAnnotation(a.id, a.rect.translated(offset));
568 		}
569 	}
570 
571 	for(auto observer : d->m_observers)
572 		observer->canvasResized(left, top, oldsize);
573 
574 	emit d->resized(left, top, oldsize);
575 }
576 
setBackground(const Tile & tile)577 void EditableLayerStack::setBackground(const Tile &tile)
578 {
579 	if(tile.equals(d->m_backgroundTile))
580 		return;
581 
582 	d->m_backgroundTile = tile;
583 
584 	for(auto observer : d->m_observers)
585 		observer->canvasBackgroundChanged(tile);
586 }
587 
588 /**
589  * @param id ID of the new layer
590  * @param source source layer ID (used when copy or insert is true)
591  * @param color background color (used when copy is false)
592  * @param insert if true, the new layer is inserted above source (source 0 inserts at the bottom of the stack)
593  * @param copy if true, the layer content is copied from the source
594  * @param name layer title
595  * @return newly created layer or null in case of error
596  */
createLayer(int id,int source,const QColor & color,bool insert,bool copy,const QString & name)597 EditableLayer EditableLayerStack::createLayer(int id, int source, const QColor &color, bool insert, bool copy, const QString &name)
598 {
599 	if(d->getLayer(id)) {
600 		qWarning("Layer #%d already exists!", id);
601 		return EditableLayer();
602 	}
603 
604 	if(d->m_width<=0 || d->m_height<=0) {
605 		// We tolerate this, but in normal operation the canvas size should be
606 		// set before creating any layers.
607 		qWarning("Layer created before canvas size was set!");
608 	}
609 
610 	// Find source layer if specified
611 	int sourceIdx=-1;
612 	if(source>0) {
613 		for(int i=0;i<d->m_layers.size();++i) {
614 			if(d->m_layers.at(i)->id() == source) {
615 				sourceIdx = i;
616 				break;
617 			}
618 		}
619 
620 		if(sourceIdx<0) {
621 			qWarning("Source layer %d not found!", source);
622 			return EditableLayer();
623 		}
624 	}
625 
626 	// Create or copy new layer
627 	Layer *nl;
628 	if(copy) {
629 		if(sourceIdx<0) {
630 			qWarning("No layer copy source specified!");
631 			return EditableLayer();
632 		}
633 
634 		nl = new Layer(*d->m_layers.at(sourceIdx));
635 		EditableLayer enl(nl, nullptr, 0);
636 		enl.setTitle(name);
637 		enl.setId(id);
638 
639 	} else {
640 		nl = new Layer(id, name, color, d->size());
641 	}
642 
643 	// Insert the new layer in the appropriate spot
644 	int pos;
645 	if(insert)
646 		pos = sourceIdx+1;
647 	else
648 		pos = d->m_layers.size();
649 
650 	d->m_layers.insert(pos, nl);
651 
652 	// Dirty regions must be marked after the layer is in the stack
653 	EditableLayer editable(nl, d, 0);
654 
655 	if(copy) {
656 		editable.markOpaqueDirty();
657 
658 	} else if(color.alpha()>0) {
659 		for(auto observer : d->m_observers)
660 			observer->markDirty();
661 	}
662 
663 	return editable;
664 }
665 
666 /**
667  * @param id layer ID
668  * @return true if layer was found and deleted
669  */
deleteLayer(int id)670 bool EditableLayerStack::deleteLayer(int id)
671 {
672 	for(int i=0;i<d->m_layers.size();++i) {
673 		if(d->m_layers.at(i)->id() == id) {
674 			EditableLayer(d->m_layers.at(i), d, contextId).markOpaqueDirty();
675 			delete d->m_layers.takeAt(i);
676 
677 			return true;
678 		}
679 	}
680 	return false;
681 }
682 
683 /**
684  * @param neworder list of layer IDs in the new order
685  * @pre neworder must be a permutation of the current layer order
686  */
reorderLayers(const QList<uint16_t> & neworder)687 void EditableLayerStack::reorderLayers(const QList<uint16_t> &neworder)
688 {
689 	Q_ASSERT(neworder.size() == d->m_layers.size());
690 	QList<Layer*> newstack;
691 	newstack.reserve(d->m_layers.size());
692 	for(const int id : neworder) {
693 		Layer *l = nullptr;
694 		for(int i=0;i<d->m_layers.size();++i) {
695 			if(d->m_layers.at(i)->id() == id) {
696 				l=d->m_layers.takeAt(i);
697 				break;
698 			}
699 		}
700 		Q_ASSERT(l);
701 		newstack.append(l);
702 	}
703 	d->m_layers = newstack;
704 	for(auto observer : d->m_observers)
705 		observer->markDirty();
706 }
707 
708 /**
709  * @param id id of the layer that will be merged
710  */
mergeLayerDown(int id)711 void EditableLayerStack::mergeLayerDown(int id) {
712 	const Layer *top;
713 	Layer *btm=nullptr;
714 	for(int i=0;i<d->m_layers.size();++i) {
715 		if(d->m_layers[i]->id() == id) {
716 			top = d->m_layers[i];
717 			if(i>0)
718 				btm = d->m_layers[i-1];
719 			break;
720 		}
721 	}
722 	if(btm)
723 		EditableLayer(btm, d, contextId).merge(top);
724 	else
725 		qWarning("Tried to merge bottom-most layer");
726 }
727 
getEditableLayerByIndex(int index)728 EditableLayer EditableLayerStack::getEditableLayerByIndex(int index)
729 {
730 	return EditableLayer(d->m_layers[index], d, contextId);
731 }
732 
getEditableLayer(int id)733 EditableLayer EditableLayerStack::getEditableLayer(int id)
734 {
735 	for(Layer *l : d->m_layers)
736 		if(l->id() == id)
737 			return EditableLayer(l, d, contextId);
738 	return EditableLayer();
739 }
740 
reset()741 void EditableLayerStack::reset()
742 {
743 	const QSize oldsize(d->m_width, d->m_height);
744 	d->m_width = 0;
745 	d->m_height = 0;
746 	d->m_xtiles = 0;
747 	d->m_ytiles = 0;
748 	for(Layer *l : d->m_layers)
749 		delete l;
750 	d->m_layers.clear();
751 	d->m_annotations->clear();
752 
753 	d->m_backgroundTile = Tile();
754 
755 	for(auto *observer : d->m_observers) {
756 		observer->canvasResized(0, 0, oldsize);
757 		observer->canvasBackgroundChanged(Tile());
758 	}
759 
760 	emit d->resized(0, 0, oldsize);
761 }
762 
removePreviews()763 void EditableLayerStack::removePreviews()
764 {
765 	for(Layer *l : d->m_layers) {
766 		EditableLayer(l, d, contextId).removePreviews();
767 	}
768 }
769 
mergeSublayers(int id)770 void EditableLayerStack::mergeSublayers(int id)
771 {
772 	for(Layer *l : d->m_layers) {
773 		EditableLayer(l, d, contextId).mergeSublayer(id);
774 	}
775 }
776 
mergeAllSublayers()777 void EditableLayerStack::mergeAllSublayers()
778 {
779 	for(Layer *l : d->m_layers) {
780 		EditableLayer(l, d, contextId).mergeAllSublayers();
781 	}
782 }
783 
setViewMode(LayerStack::ViewMode mode)784 void EditableLayerStack::setViewMode(LayerStack::ViewMode mode)
785 {
786 	if(mode != d->m_viewmode) {
787 		d->m_viewmode = mode;
788 		for(auto observer : d->m_observers)
789 			observer->markDirty();
790 	}
791 }
792 
setViewLayer(int id)793 void EditableLayerStack::setViewLayer(int id)
794 {
795 	for(int i=0;i<d->m_layers.size();++i) {
796 		if(d->m_layers.at(i)->id() == id) {
797 			d->m_viewlayeridx = i;
798 			if(d->m_viewmode != LayerStack::NORMAL) {
799 				for(auto observer : d->m_observers)
800 					observer->markDirty();
801 			}
802 			break;
803 		}
804 	}
805 }
806 
setInspectorHighlight(int contextId)807 void EditableLayerStack::setInspectorHighlight(int contextId)
808 {
809 	if(d->m_highlightId != contextId) {
810 		d->m_highlightId = contextId;
811 		for(auto observer : d->m_observers)
812 			observer->markDirty();
813 	}
814 }
815 
setOnionskinMode(int below,int above,bool tint)816 void EditableLayerStack::setOnionskinMode(int below, int above, bool tint)
817 {
818 	d->m_onionskinsBelow = below;
819 	d->m_onionskinsAbove = above;
820 	d->m_onionskinTint = tint;
821 
822 	if(d->m_viewmode == LayerStack::ONIONSKIN) {
823 		for(auto observer : d->m_observers)
824 			observer->markDirty();
825 	}
826 }
827 
setCensorship(bool censor)828 void EditableLayerStack::setCensorship(bool censor)
829 {
830 	if(d->m_censorLayers != censor) {
831 		d->m_censorLayers = censor;
832 		// We could check if this really needs to be called, but this
833 		// flag is changed very infrequently
834 		for(auto observer : d->m_observers)
835 			observer->markDirty();
836 	}
837 }
838 
839 }
840 
841