1// Aseprite Document Library
2// Copyright (C) 2020 Igara Studio S.A.
3// Copyright (C) 2016-2018 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "doc/selected_layers.h"
13
14#include "base/base.h"
15#include "base/debug.h"
16#include "base/serialization.h"
17#include "doc/layer.h"
18#include "doc/sprite.h"
19
20#include <iostream>
21
22namespace doc {
23
24using namespace base::serialization;
25using namespace base::serialization::little_endian;
26
27void SelectedLayers::clear()
28{
29 m_set.clear();
30}
31
32void SelectedLayers::insert(Layer* layer)
33{
34 ASSERT(layer);
35 m_set.insert(layer);
36}
37
38void SelectedLayers::erase(const Layer* layer)
39{
40 m_set.erase(const_cast<Layer*>(layer));
41}
42
43bool SelectedLayers::contains(const Layer* layer) const
44{
45 return m_set.find(const_cast<Layer*>(layer)) != m_set.end();
46}
47
48bool SelectedLayers::hasSameParent() const
49{
50 Layer* parent = nullptr;
51 for (auto layer : *this) {
52 if (parent) {
53 if (layer->parent() != parent)
54 return false;
55 }
56 else
57 parent = layer->parent();
58 }
59 return true;
60}
61
62LayerList SelectedLayers::toAllLayersList() const
63{
64 LayerList output;
65
66 if (empty())
67 return output;
68
69 ASSERT(*begin());
70 ASSERT((*begin())->sprite());
71
72 for (Layer* layer = (*begin())->sprite()->firstLayer();
73 layer != nullptr;
74 layer = layer->getNextInWholeHierarchy()) {
75 if (contains(layer))
76 output.push_back(layer);
77 }
78
79 return output;
80}
81
82LayerList SelectedLayers::toBrowsableLayerList() const
83{
84 LayerList output;
85
86 if (empty())
87 return output;
88
89 ASSERT(*begin());
90 ASSERT((*begin())->sprite());
91
92 for (Layer* layer = (*begin())->sprite()->firstBrowsableLayer();
93 layer != nullptr;
94 layer = layer->getNextBrowsable()) {
95 if (contains(layer))
96 output.push_back(layer);
97 }
98
99 return output;
100}
101
102void SelectedLayers::removeChildrenIfParentIsSelected()
103{
104 SelectedLayers removeThese;
105
106 for (Layer* child : *this) {
107 Layer* parent = child->parent();
108 while (parent) {
109 if (contains(parent)) {
110 removeThese.insert(child);
111 break;
112 }
113 parent = parent->parent();
114 }
115 }
116
117 for (Layer* child : removeThese)
118 erase(child);
119}
120
121void SelectedLayers::selectAllLayers(LayerGroup* group)
122{
123 for (Layer* layer : group->layers()) {
124 if (layer->isGroup())
125 selectAllLayers(static_cast<LayerGroup*>(layer));
126 insert(layer);
127 }
128}
129
130void SelectedLayers::expandCollapsedGroups()
131{
132 auto copy = m_set;
133 for (Layer* layer : copy) {
134 if (layer->isGroup() && layer->isCollapsed())
135 selectAllLayers(static_cast<LayerGroup*>(layer));
136 }
137}
138
139void SelectedLayers::displace(layer_t layerDelta)
140{
141 // Do nothing case
142 if (layerDelta == 0)
143 return;
144
145 const SelectedLayers original = *this;
146
147retry:;
148 clear();
149
150 for (auto it : original) {
151 Layer* layer = it;
152
153 if (layerDelta > 0) {
154 for (layer_t i=0; layer && i<layerDelta; ++i)
155 layer = layer->getNextBrowsable();
156 }
157 else if (layerDelta < 0) {
158 for (layer_t i=0; layer && i>layerDelta; --i) {
159 layer = layer->getPreviousBrowsable();
160 }
161 }
162
163 if (layer) {
164 insert(layer);
165 }
166 // If some layer is outside the range it means that the delta is
167 // too big (out of bounds), we reduce the delta and try again the
168 // whole process.
169 else {
170 layerDelta -= SGN(layerDelta);
171 if (layerDelta == 0) {
172 m_set = original.m_set;
173 break;
174 }
175 goto retry;
176 }
177 }
178}
179
180// This will select:
181// 1. all visible children in case the parent is selected and none of
182// its children is selected.
183// 2. all parent if one children is selected
184void SelectedLayers::propagateSelection()
185{
186 SelectedLayers newSel;
187
188 for (Layer* layer : *this) {
189 if (!layer->isGroup())
190 continue;
191
192 LayerList children;
193 static_cast<LayerGroup*>(layer)->allLayers(children);
194
195 bool allDeselected = true;
196 for (Layer* child : children) {
197 if (contains(child)) {
198 allDeselected = false;
199 break;
200 }
201 }
202 if (allDeselected) {
203 for (Layer* child : children) {
204 if (child->isVisible())
205 newSel.insert(child);
206 }
207 }
208 }
209
210 for (Layer* layer : *this) {
211 Layer* parent = layer->parent();
212 while (parent != layer->sprite()->root() &&
213 !contains(parent)) {
214 newSel.insert(parent);
215 parent = parent->parent();
216 }
217 }
218
219 for (Layer* layer : newSel)
220 insert(layer);
221}
222
223bool SelectedLayers::write(std::ostream& os) const
224{
225 write32(os, size());
226 for (const Layer* layer : *this)
227 write32(os, layer->id());
228 return os.good();
229}
230
231bool SelectedLayers::read(std::istream& is)
232{
233 clear();
234
235 int nlayers = read32(is);
236 for (int i=0; i<nlayers && is; ++i) {
237 ObjectId id = read32(is);
238 Layer* layer = doc::get<Layer>(id);
239
240 // Check that the layer does exist. You will see a little trick in
241 // UndoCommand::onExecute() deserializing the DocumentRange stream
242 // after the undo/redo is executed so layers exist at this point.
243
244 // TODO This should be an assert, but there is a bug that make this fail
245 //ASSERT(layer);
246
247 if (layer)
248 insert(layer);
249 }
250 return is.good();
251}
252
253} // namespace doc
254