1 /*
2  * editablewangset.cpp
3  * Copyright 2019, Your Name <your.name@domain>
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 "editablewangset.h"
22 
23 #include "changetilewangid.h"
24 #include "changewangsetdata.h"
25 #include "editablemanager.h"
26 #include "editabletile.h"
27 #include "editabletileset.h"
28 #include "scriptmanager.h"
29 
30 #include <QCoreApplication>
31 #include <QJSEngine>
32 
33 namespace Tiled {
34 
EditableWangSet(EditableTileset * tileset,WangSet * wangSet,QObject * parent)35 EditableWangSet::EditableWangSet(EditableTileset *tileset,
36                                  WangSet *wangSet,
37                                  QObject *parent)
38     : EditableObject(tileset, wangSet, parent)
39 {
40 
41 }
42 
~EditableWangSet()43 EditableWangSet::~EditableWangSet()
44 {
45     EditableManager::instance().mEditableWangSets.remove(wangSet());
46 }
47 
imageTile() const48 EditableTile *EditableWangSet::imageTile() const
49 {
50     return EditableManager::instance().editableTile(tileset(), wangSet()->imageTile());
51 }
52 
tileset() const53 EditableTileset *EditableWangSet::tileset() const
54 {
55     return static_cast<EditableTileset*>(asset());
56 }
57 
wangId(EditableTile * editableTile)58 QJSValue EditableWangSet::wangId(EditableTile *editableTile)
59 {
60     if (!editableTile) {
61         ScriptManager::instance().throwNullArgError(0);
62         return {};
63     }
64 
65     QJSEngine *engine = ScriptManager::instance().engine();
66     WangId wangId = wangSet()->wangIdOfTile(editableTile->tile());
67 
68     QJSValue wangIdArray = engine->newArray(WangId::NumIndexes);
69     for (quint32 i = 0; i < WangId::NumIndexes; ++i)
70         wangIdArray.setProperty(i, wangId.indexColor(i));
71 
72     return wangIdArray;
73 }
74 
setWangId(EditableTile * editableTile,QJSValue value)75 void EditableWangSet::setWangId(EditableTile *editableTile, QJSValue value)
76 {
77     if (!editableTile) {
78         ScriptManager::instance().throwNullArgError(0);
79         return;
80     }
81 
82     const int length = value.property(QStringLiteral("length")).toInt();
83     if (!value.isArray() || length != WangId::NumIndexes) {
84         ScriptManager::instance().throwError(QCoreApplication::translate("Script Errors", "Wang ID must be an array of length 8"));
85         return;
86     }
87 
88     WangId wangId;
89 
90     for (quint32 i = 0; i < WangId::NumIndexes; ++i) {
91         const unsigned color = value.property(i).toUInt();
92         wangId.setIndexColor(i, color);
93     }
94 
95     if (!wangSet()->wangIdIsValid(wangId)) {
96         ScriptManager::instance().throwError(QCoreApplication::translate("Script Errors", "Invalid Wang ID"));
97         return;
98     }
99 
100     if (auto doc = tilesetDocument())
101         asset()->push(new ChangeTileWangId(doc, wangSet(), editableTile->tile(), wangId));
102     else if (!checkReadOnly())
103         wangSet()->setWangId(editableTile->id(), wangId);
104 }
105 
setName(const QString & name)106 void EditableWangSet::setName(const QString &name)
107 {
108     if (auto document = tilesetDocument())
109         asset()->push(new RenameWangSet(document, wangSet(), name));
110     else if (!checkReadOnly())
111         wangSet()->setName(name);
112 }
113 
setType(EditableWangSet::Type type)114 void EditableWangSet::setType(EditableWangSet::Type type)
115 {
116     if (auto document = tilesetDocument()) {
117         asset()->push(new ChangeWangSetType(document, wangSet(),
118                                             static_cast<WangSet::Type>(type)));
119     } else if (!checkReadOnly()) {
120         wangSet()->setType(static_cast<WangSet::Type>(type));
121     }
122 }
123 
setImageTile(EditableTile * imageTile)124 void EditableWangSet::setImageTile(EditableTile *imageTile)
125 {
126     if (imageTile && imageTile->tileset() != tileset()) {
127         ScriptManager::instance().throwError(QCoreApplication::translate("Script Errors", "Tile not from the same tileset"));
128         return;
129     }
130 
131     int tileId = imageTile ? imageTile->id() : -1;
132 
133     if (auto document = tilesetDocument())
134         asset()->push(new SetWangSetImage(document, wangSet(), tileId));
135     else if (!checkReadOnly())
136         wangSet()->setImageTileId(tileId);
137 }
138 
setColorCount(int n)139 void EditableWangSet::setColorCount(int n)
140 {
141     if (auto document = tilesetDocument()) {
142         asset()->push(new ChangeWangSetColorCount(document, wangSet(), n));
143     } else if (!checkReadOnly()) {
144         ChangeTileWangId::applyChanges(wangSet(),
145                                        ChangeTileWangId::changesOnSetColorCount(wangSet(), n));
146         wangSet()->setColorCount(n);
147     }
148 }
149 
detach()150 void EditableWangSet::detach()
151 {
152     Q_ASSERT(tileset());
153 
154     auto &editableManager = EditableManager::instance();
155 
156     editableManager.mEditableWangSets.remove(wangSet());
157     setAsset(nullptr);
158 
159     mDetachedWangSet.reset(wangSet()->clone(nullptr));
160     setObject(mDetachedWangSet.get());
161     editableManager.mEditableWangSets.insert(wangSet(), this);
162 }
163 
attach(EditableTileset * tileset)164 void EditableWangSet::attach(EditableTileset *tileset)
165 {
166     Q_ASSERT(!asset() && tileset);
167 
168     setAsset(tileset);
169     mDetachedWangSet.release();
170 }
171 
hold()172 void EditableWangSet::hold()
173 {
174     Q_ASSERT(!asset());             // if asset exists, it holds the object (possibly indirectly)
175     Q_ASSERT(!mDetachedWangSet);    // can't already be holding the object
176 
177     mDetachedWangSet.reset(wangSet());
178 }
179 
release()180 void EditableWangSet::release()
181 {
182     Q_ASSERT(mDetachedWangSet.get() == wangSet());
183 
184     mDetachedWangSet.release();
185 }
186 
tilesetDocument() const187 TilesetDocument *EditableWangSet::tilesetDocument() const
188 {
189     return tileset() ? tileset()->tilesetDocument() : nullptr;
190 }
191 
192 } // namespace Tiled
193 
194 #include "moc_editablewangset.cpp"
195