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 | |
22 | namespace doc { |
23 | |
24 | using namespace base::serialization; |
25 | using namespace base::serialization::little_endian; |
26 | |
27 | void SelectedLayers::clear() |
28 | { |
29 | m_set.clear(); |
30 | } |
31 | |
32 | void SelectedLayers::insert(Layer* layer) |
33 | { |
34 | ASSERT(layer); |
35 | m_set.insert(layer); |
36 | } |
37 | |
38 | void SelectedLayers::erase(const Layer* layer) |
39 | { |
40 | m_set.erase(const_cast<Layer*>(layer)); |
41 | } |
42 | |
43 | bool SelectedLayers::contains(const Layer* layer) const |
44 | { |
45 | return m_set.find(const_cast<Layer*>(layer)) != m_set.end(); |
46 | } |
47 | |
48 | bool 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 | |
62 | LayerList 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 | |
82 | LayerList 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 | |
102 | void 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 | |
121 | void 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 | |
130 | void 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 | |
139 | void SelectedLayers::displace(layer_t layerDelta) |
140 | { |
141 | // Do nothing case |
142 | if (layerDelta == 0) |
143 | return; |
144 | |
145 | const SelectedLayers original = *this; |
146 | |
147 | retry:; |
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 |
184 | void 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 | |
223 | bool 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 | |
231 | bool 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 |