1 /*
2  * erasetiles.cpp
3  * Copyright 2009, Thorbjørn Lindeijer <thorbjorn@lindeijer.nl>
4  *
5  * This file is part of Tiled.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "erasetiles.h"
22 
23 #include "tilelayer.h"
24 #include "tilepainter.h"
25 
26 #include <QCoreApplication>
27 
28 using namespace Tiled;
29 
EraseTiles(MapDocument * mapDocument,TileLayer * tileLayer,const QRegion & region)30 EraseTiles::EraseTiles(MapDocument *mapDocument,
31                        TileLayer *tileLayer,
32                        const QRegion &region)
33     : mMapDocument(mapDocument)
34     , mMergeable(false)
35 {
36     setText(QCoreApplication::translate("Undo Commands", "Erase"));
37 
38     auto &data = mLayerData[tileLayer];
39     data.mRegion = region;
40 
41     // Store the tiles that are to be erased
42     const QRegion r = region.translated(-tileLayer->position());
43     data.mErasedCells = tileLayer->copy(r).release();
44 }
45 
~EraseTiles()46 EraseTiles::~EraseTiles()
47 {
48     for (LayerData &data : mLayerData)
49         delete data.mErasedCells;
50 }
51 
undo()52 void EraseTiles::undo()
53 {
54     QHashIterator<TileLayer*, LayerData> it(mLayerData);
55     while (it.hasNext()) {
56         const LayerData &data = it.next().value();
57         const QRect bounds = data.mRegion.boundingRect();
58         TilePainter painter(mMapDocument, it.key());
59         painter.drawCells(bounds.x(), bounds.y(), data.mErasedCells);
60     }
61 }
62 
redo()63 void EraseTiles::redo()
64 {
65     QHashIterator<TileLayer*, LayerData> it(mLayerData);
66     while (it.hasNext()) {
67         const LayerData &data = it.next().value();
68         TilePainter painter(mMapDocument, it.key());
69         painter.erase(data.mRegion);
70     }
71 }
72 
mergeWith(const EraseTiles::LayerData & o)73 void EraseTiles::LayerData::mergeWith(const EraseTiles::LayerData &o)
74 {
75     if (!mErasedCells) {
76         mErasedCells = o.mErasedCells->clone();
77         mRegion = o.mRegion;
78         return;
79     }
80 
81     const QRegion combinedRegion = mRegion.united(o.mRegion);
82     if (mRegion != combinedRegion) {
83         const QRect bounds = mRegion.boundingRect();
84         const QRect combinedBounds = combinedRegion.boundingRect();
85 
86         // Resize the erased tiles layer when necessary
87         if (bounds != combinedBounds) {
88             const QPoint shift = bounds.topLeft() - combinedBounds.topLeft();
89             mErasedCells->resize(combinedBounds.size(), shift);
90         }
91 
92         // Copy the newly erased tiles over
93         const QRect otherBounds = o.mRegion.boundingRect();
94         const QPoint pos = otherBounds.topLeft() - combinedBounds.topLeft();
95         mErasedCells->merge(pos, o.mErasedCells);
96 
97         mRegion = combinedRegion;
98     }
99 }
100 
mergeWith(const QUndoCommand * other)101 bool EraseTiles::mergeWith(const QUndoCommand *other)
102 {
103     const EraseTiles *o = static_cast<const EraseTiles*>(other);
104     if (!(mMapDocument == o->mMapDocument && o->mMergeable))
105         return false;
106     if (!cloneChildren(other, this))
107         return false;
108 
109     QHashIterator<TileLayer*, LayerData> it(o->mLayerData);
110     while (it.hasNext()) {
111         it.next();
112         mLayerData[it.key()].mergeWith(it.value());
113     }
114 
115     return true;
116 }
117