1 /*
2  * tilelayeredit.cpp
3  * Copyright 2019, Thorbjørn Lindeijer <bjorn@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 "tilelayeredit.h"
22 
23 #include "addremovetileset.h"
24 #include "editablemap.h"
25 #include "editabletile.h"
26 #include "editabletilelayer.h"
27 #include "painttilelayer.h"
28 #include "scriptmanager.h"
29 
30 namespace Tiled {
31 
TileLayerEdit(EditableTileLayer * tileLayer,QObject * parent)32 TileLayerEdit::TileLayerEdit(EditableTileLayer *tileLayer, QObject *parent)
33     : QObject(parent)
34     , mTargetLayer(tileLayer)
35 {
36     mTargetLayer->mActiveEdits.append(this);
37 }
38 
~TileLayerEdit()39 TileLayerEdit::~TileLayerEdit()
40 {
41     mTargetLayer->mActiveEdits.removeOne(this);
42 }
43 
setTile(int x,int y,EditableTile * tile,int flags)44 void TileLayerEdit::setTile(int x, int y, EditableTile *tile, int flags)
45 {
46     Cell cell(tile ? tile->tile() : nullptr);
47     cell.setChecked(true);  // Used to find painted region later (allows erasing)
48 
49     if (flags & EditableTile::FlippedHorizontally)
50         cell.setFlippedHorizontally(true);
51     if (flags & EditableTile::FlippedVertically)
52         cell.setFlippedVertically(true);
53     if (flags & EditableTile::FlippedAntiDiagonally)
54         cell.setFlippedAntiDiagonally(true);
55     if (flags & EditableTile::RotatedHexagonal120)
56         cell.setRotatedHexagonal120(true);
57 
58     mChanges.setCell(x, y, cell);
59 }
60 
apply()61 void TileLayerEdit::apply()
62 {
63     // Applying an edit automatically makes it mergeable, so that further
64     // changes made through the same edit are merged by default.
65     bool mergeable = std::exchange(mMergeable, true);
66 
67     // Determine painted region and normalize the changes layer
68     auto paintedRegion = mChanges.region([] (const Cell &cell) { return cell.checked(); });
69 
70     // If the painted region is empty there's nothing else to do
71     if (paintedRegion.isEmpty())
72         return;
73 
74     auto rect = paintedRegion.boundingRect();
75     mChanges.resize(rect.size(), -rect.topLeft());
76 
77     if (mTargetLayer->mapDocument()) {
78         // Apply the change using an undo command
79         auto mapDocument = mTargetLayer->map()->mapDocument();
80         auto paint = new PaintTileLayer(mapDocument,
81                                         mTargetLayer->tileLayer(),
82                                         rect.x(), rect.y(),
83                                         &mChanges,
84                                         paintedRegion);
85         paint->setMergeable(mergeable);
86 
87         // Add any used tilesets that aren't yet part of the target map
88         const auto tilesets = mChanges.usedTilesets();
89         const auto existingTilesets = mapDocument->map()->tilesets();
90         for (const SharedTileset &tileset : tilesets)
91             if (!existingTilesets.contains(tileset))
92                 new AddTileset(mapDocument, tileset, paint);
93 
94         mTargetLayer->map()->push(paint);
95     } else {
96         // Apply the change directly
97         mTargetLayer->tileLayer()->setCells(rect.x(), rect.y(), &mChanges, paintedRegion);
98     }
99 
100     mChanges.clear();
101 }
102 
103 } // namespace Tiled
104 
105 #include "moc_tilelayeredit.cpp"
106