1// Aseprite
2// Copyright (C) 2020 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/doc_range.h"
13
14#include "app/util/layer_utils.h"
15#include "base/serialization.h"
16#include "doc/cel.h"
17#include "doc/image.h"
18#include "doc/layer.h"
19#include "doc/sprite.h"
20
21#include <iostream>
22
23namespace app {
24
25using namespace base::serialization;
26using namespace base::serialization::little_endian;
27using namespace doc;
28
29DocRange::DocRange()
30 : m_type(kNone)
31 , m_flags(m_type)
32 , m_selectingFromLayer(nullptr)
33 , m_selectingFromFrame(-1)
34{
35}
36
37DocRange::DocRange(Cel* cel)
38 : m_type(kCels)
39 , m_flags(m_type)
40 , m_selectingFromLayer(nullptr)
41 , m_selectingFromFrame(-1)
42{
43 m_selectedLayers.insert(cel->layer());
44 m_selectedFrames.insert(cel->frame());
45}
46
47void DocRange::clearRange()
48{
49 m_type = kNone;
50 m_flags = kNone;
51 m_selectedLayers.clear();
52 m_selectedFrames.clear();
53
54 // Reset the starting point of a previous startRange/endRange(), we
55 // don't want to store a pointer to an invalid
56 // "m_selectingFromLayer" layer.
57 m_selectingFromLayer = nullptr;
58 m_selectingFromFrame = -1;
59}
60
61void DocRange::startRange(Layer* fromLayer, frame_t fromFrame, Type type)
62{
63 m_type = type;
64 m_flags |= type;
65 m_selectingFromLayer = fromLayer;
66 m_selectingFromFrame = fromFrame;
67
68 if (fromLayer)
69 m_selectedLayers.insert(fromLayer);
70 if (fromFrame >= 0)
71 m_selectedFrames.insert(fromFrame);
72}
73
74void DocRange::endRange(Layer* toLayer, frame_t toFrame)
75{
76 ASSERT(enabled());
77
78 if (m_selectingFromLayer && toLayer)
79 selectLayerRange(m_selectingFromLayer, toLayer);
80
81 if (m_selectingFromFrame >= 0)
82 selectFrameRange(m_selectingFromFrame, toFrame);
83}
84
85void DocRange::selectLayer(Layer* layer)
86{
87 if (m_type == kNone)
88 m_type = kLayers;
89 m_flags |= kLayers;
90
91 m_selectedLayers.insert(layer);
92}
93
94void DocRange::selectLayers(const SelectedLayers& selLayers)
95{
96 if (m_type == kNone)
97 m_type = kLayers;
98 m_flags |= kLayers;
99
100 for (auto layer : selLayers)
101 m_selectedLayers.insert(layer);
102}
103
104void DocRange::eraseAndAdjust(const Layer* layer)
105{
106 if (!enabled())
107 return;
108
109 // Check that the sprite of m_selectingFromLayer is the same than
110 // the given layer. In the past if we stored an invalid
111 // "m_selectingFromLayer" for too much time this could fail (even
112 // more, "m_selectingFromLayer" could be pointing to an already
113 // closed/deleted sprite).
114 ASSERT(!m_selectingFromLayer || !layer ||
115 m_selectingFromLayer->sprite() == layer->sprite());
116
117 if (m_selectingFromLayer)
118 m_selectingFromLayer = candidate_if_layer_is_deleted(m_selectingFromLayer, layer);
119
120 SelectedLayers copy = m_selectedLayers;
121 m_selectedLayers.clear();
122 for (Layer* selectedLayer : copy) {
123 Layer* layerToSelect = candidate_if_layer_is_deleted(selectedLayer, layer);
124 if (layerToSelect)
125 m_selectedLayers.insert(layerToSelect);
126 }
127}
128
129bool DocRange::contains(const Layer* layer) const
130{
131 if (enabled())
132 return m_selectedLayers.contains(const_cast<Layer*>(layer));
133 else
134 return false;
135}
136
137bool DocRange::contains(const Layer* layer,
138 const frame_t frame) const
139{
140 switch (m_type) {
141 case DocRange::kNone:
142 return false;
143 case DocRange::kCels:
144 return contains(layer) && contains(frame);
145 case DocRange::kFrames:
146 if (contains(frame)) {
147 if ((m_flags & (kCels | kLayers)) != 0)
148 return contains(layer);
149 else
150 return true;
151 }
152 break;
153 case DocRange::kLayers:
154 if (contains(layer)) {
155 if ((m_flags & (kCels | kFrames)) != 0)
156 return contains(frame);
157 else
158 return true;
159 }
160 break;
161 }
162 return false;
163}
164
165void DocRange::displace(layer_t layerDelta, frame_t frameDelta)
166{
167 m_selectedLayers.displace(layerDelta);
168 m_selectedFrames.displace(frameDelta);
169}
170
171bool DocRange::convertToCels(const Sprite* sprite)
172{
173 switch (m_type) {
174 case DocRange::kNone:
175 return false;
176 case DocRange::kCels:
177 break;
178 case DocRange::kFrames: {
179 if ((m_flags & (kCels | kLayers)) == 0) {
180 for (auto layer : sprite->allBrowsableLayers())
181 m_selectedLayers.insert(layer);
182 }
183 m_type = DocRange::kCels;
184 break;
185 }
186 case DocRange::kLayers:
187 if ((m_flags & (kCels | kFrames)) == 0)
188 selectFrameRange(0, sprite->lastFrame());
189 m_type = DocRange::kCels;
190 break;
191 }
192 return true;
193}
194
195bool DocRange::write(std::ostream& os) const
196{
197 write32(os, m_type);
198 write32(os, m_flags);
199
200 if (!m_selectedLayers.write(os)) return false;
201 if (!m_selectedFrames.write(os)) return false;
202
203 write32(os, m_selectingFromLayer ? m_selectingFromLayer->id(): 0);
204 write32(os, m_selectingFromFrame);
205 return os.good();
206}
207
208bool DocRange::read(std::istream& is)
209{
210 clearRange();
211
212 m_type = (Type)read32(is);
213 m_flags = read32(is);
214
215 if (!m_selectedLayers.read(is)) return false;
216 if (!m_selectedFrames.read(is)) return false;
217
218 ObjectId id = read32(is);
219 m_selectingFromLayer = doc::get<Layer>(id);
220 m_selectingFromFrame = read32(is);
221 return is.good();
222}
223
224void DocRange::selectLayerRange(Layer* fromLayer, Layer* toLayer)
225{
226 ASSERT(fromLayer);
227 ASSERT(toLayer);
228
229 bool goNext = false;
230 bool goPrev = false;
231 Layer* it;
232
233 if (fromLayer != toLayer) {
234 it = m_selectingFromLayer;
235 while (it) {
236 if (it == toLayer) {
237 goNext = true;
238 break;
239 }
240 it = it->getNextBrowsable();
241 }
242
243 if (!goNext) {
244 it = m_selectingFromLayer;
245 while (it) {
246 if (it == toLayer) {
247 goPrev = true;
248 break;
249 }
250 it = it->getPreviousBrowsable();
251 }
252 }
253 }
254
255 it = m_selectingFromLayer;
256 do {
257 m_selectedLayers.insert(it);
258 if (it == toLayer)
259 break;
260
261 if (goNext)
262 it = it->getNextBrowsable();
263 else if (goPrev)
264 it = it->getPreviousBrowsable();
265 else
266 break;
267 } while (it);
268}
269
270void DocRange::selectFrameRange(frame_t fromFrame, frame_t toFrame)
271{
272 m_selectedFrames.insert(fromFrame, toFrame);
273}
274
275void DocRange::setType(const Type type)
276{
277 if (type != kNone) {
278 m_type = type;
279 m_flags |= type;
280 }
281 else {
282 m_type = kNone;
283 m_flags = kNone;
284 }
285}
286
287void DocRange::setSelectedLayers(const SelectedLayers& layers)
288{
289 if (layers.empty()) {
290 m_type = kNone;
291 m_selectedLayers.clear();
292 return;
293 }
294
295 m_type = kLayers;
296 m_flags |= kLayers;
297 m_selectedLayers = layers;
298}
299
300void DocRange::setSelectedFrames(const SelectedFrames& frames)
301{
302 if (frames.empty()) {
303 m_type = kNone;
304 m_selectedFrames.clear();
305 return;
306 }
307
308 m_type = kFrames;
309 m_flags |= kFrames;
310 m_selectedFrames = frames;
311}
312
313} // namespace app
314