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