1 /*
2 * changetilewangid.cpp
3 * Copyright 2017, Benjamin Trotter <bdtrotte@ucsc.edu>
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 "changetilewangid.h"
22
23 #include "tilesetdocument.h"
24 #include "tile.h"
25
26 #include <QCoreApplication>
27
28 #include "qtcompat_p.h"
29
30 using namespace Tiled;
31
ChangeTileWangId()32 ChangeTileWangId::ChangeTileWangId()
33 : mTilesetDocument(nullptr)
34 , mWangSet(nullptr)
35 , mMergeable(false)
36 {
37 setText(QCoreApplication::translate("Undo Commands", "Change Tile Terrain"));
38 }
39
ChangeTileWangId(TilesetDocument * tilesetDocument,WangSet * wangSet,Tile * tile,WangId wangId)40 ChangeTileWangId::ChangeTileWangId(TilesetDocument *tilesetDocument,
41 WangSet *wangSet,
42 Tile *tile,
43 WangId wangId)
44 : mTilesetDocument(tilesetDocument)
45 , mWangSet(wangSet)
46 , mMergeable(true)
47 {
48 Q_ASSERT(mWangSet);
49 setText(QCoreApplication::translate("Undo Commands", "Change Tile Terrain"));
50 mChanges.append(WangIdChange(mWangSet->wangIdOfTile(tile), wangId, tile->id()));
51 }
52
ChangeTileWangId(TilesetDocument * tilesetDocument,WangSet * wangSet,const QVector<WangIdChange> & changes,QUndoCommand * parent)53 ChangeTileWangId::ChangeTileWangId(TilesetDocument *tilesetDocument,
54 WangSet *wangSet,
55 const QVector<WangIdChange> &changes,
56 QUndoCommand *parent)
57 : QUndoCommand(parent)
58 , mTilesetDocument(tilesetDocument)
59 , mWangSet(wangSet)
60 , mChanges(changes)
61 , mMergeable(true)
62 {
63 setText(QCoreApplication::translate("Undo Commands", "Change Tile Terrain"));
64 }
65
undo()66 void ChangeTileWangId::undo()
67 {
68 if (mChanges.isEmpty())
69 return;
70
71 QList<Tile *> changedTiles;
72
73 QVectorIterator<WangIdChange> changes(mChanges);
74 changes.toBack();
75
76 while (changes.hasPrevious()) {
77 const WangIdChange &wangIdChange = changes.previous();
78
79 if (Tile *tile = findTile(wangIdChange.tileId))
80 changedTiles.append(tile);
81 mWangSet->setWangId(wangIdChange.tileId, wangIdChange.from);
82 }
83
84 emit mTilesetDocument->tileWangSetChanged(changedTiles);
85 }
86
redo()87 void ChangeTileWangId::redo()
88 {
89 if (mChanges.isEmpty())
90 return;
91
92 QList<Tile *> changedTiles;
93
94 for (const WangIdChange &wangIdChange : qAsConst(mChanges)) {
95 if (Tile *tile = findTile(wangIdChange.tileId))
96 changedTiles.append(tile);
97 mWangSet->setWangId(wangIdChange.tileId, wangIdChange.to);
98 }
99
100 emit mTilesetDocument->tileWangSetChanged(changedTiles);
101 }
102
mergeWith(const QUndoCommand * other)103 bool ChangeTileWangId::mergeWith(const QUndoCommand *other)
104 {
105 if (!mMergeable)
106 return false;
107
108 const ChangeTileWangId *o = static_cast<const ChangeTileWangId*>(other);
109 if (o->mTilesetDocument && !(mTilesetDocument == o->mTilesetDocument &&
110 mWangSet == o->mWangSet))
111 return false;
112
113 // suboptimal, could use a map to remove any unnessesary changes if the
114 // same tile has multiple changes.
115 mChanges += o->mChanges;
116
117 mMergeable = o->mMergeable;
118
119 return true;
120 }
121
changesOnSetColorCount(const WangSet * wangSet,int colorCount)122 QVector<ChangeTileWangId::WangIdChange> ChangeTileWangId::changesOnSetColorCount(
123 const WangSet *wangSet, int colorCount)
124 {
125 QVector<WangIdChange> changes;
126
127 QHashIterator<int, WangId> it(wangSet->wangIdByTileId());
128 while (it.hasNext()) {
129 it.next();
130 WangId newWangId = it.value();
131
132 for (int i = 0; i < WangId::NumIndexes; ++i)
133 if (newWangId.indexColor(i) > colorCount)
134 newWangId.setIndexColor(i, 0);
135
136 if (it.value() != newWangId)
137 changes.append(WangIdChange(it.value(), newWangId, it.key()));
138 }
139
140 return changes;
141 }
142
changesOnRemoveColor(const WangSet * wangSet,int removedColor)143 QVector<ChangeTileWangId::WangIdChange> ChangeTileWangId::changesOnRemoveColor(
144 const WangSet *wangSet, int removedColor)
145 {
146 QVector<WangIdChange> changes;
147
148 QHashIterator<int, WangId> it(wangSet->wangIdByTileId());
149 while (it.hasNext()) {
150 it.next();
151 WangId newWangId = it.value();
152
153 for (int i = 0; i < WangId::NumIndexes; ++i) {
154 const int color = newWangId.indexColor(i);
155 if (color == removedColor)
156 newWangId.setIndexColor(i, 0);
157 else if (color > removedColor)
158 newWangId.setIndexColor(i, color - 1);
159 }
160
161 if (it.value() != newWangId)
162 changes.append(WangIdChange(it.value(), newWangId, it.key()));
163 }
164
165 return changes;
166 }
167
applyChanges(WangSet * wangSet,const QVector<WangIdChange> & changes)168 void ChangeTileWangId::applyChanges(WangSet *wangSet, const QVector<WangIdChange> &changes)
169 {
170 for (const WangIdChange &change : changes)
171 wangSet->setWangId(change.tileId, change.to);
172 }
173
findTile(int tileId) const174 Tile *ChangeTileWangId::findTile(int tileId) const
175 {
176 return mTilesetDocument->tileset()->findTile(tileId);
177 }
178