1// Aseprite
2// Copyright (C) 2019-2021 Igara Studio S.A.
3//
4// This program is distributed under the terms of
5// the End-User License Agreement for Aseprite.
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include "app/active_site_handler.h"
12#include "app/doc.h"
13#include "app/doc_event.h"
14#include "app/site.h"
15#include "app/util/layer_utils.h"
16#include "doc/layer.h"
17
18namespace app {
19
20ActiveSiteHandler::ActiveSiteHandler()
21{
22}
23
24ActiveSiteHandler::~ActiveSiteHandler()
25{
26}
27
28void ActiveSiteHandler::addDoc(Doc* doc)
29{
30 Data data;
31 data.layer = doc::NullId;
32 if (doc->sprite()) { // The sprite can be nullptr in some tests
33 if (doc::Layer* layer = doc->sprite()->root()->firstLayer())
34 data.layer = layer->id();
35 }
36 data.frame = 0;
37 m_data.insert(std::make_pair(doc, data));
38 doc->add_observer(this);
39}
40
41void ActiveSiteHandler::removeDoc(Doc* doc)
42{
43 auto it = m_data.find(doc);
44 if (it == m_data.end())
45 return;
46
47 doc->remove_observer(this);
48 m_data.erase(it);
49}
50
51ActiveSiteHandler::Data& ActiveSiteHandler::getData(Doc* doc)
52{
53 auto it = m_data.find(doc);
54 if (it == m_data.end()) {
55 addDoc(doc);
56 it = m_data.find(doc);
57 ASSERT(it != m_data.end());
58 }
59 return it->second;
60}
61
62void ActiveSiteHandler::getActiveSiteForDoc(Doc* doc, Site* site)
63{
64 Data& data = getData(doc);
65 site->document(doc);
66 site->sprite(doc->sprite());
67 site->layer(doc::get<doc::Layer>(data.layer));
68 site->frame(data.frame);
69 site->range(data.range);
70 site->selectedColors(data.selectedColors);
71 site->selectedTiles(data.selectedTiles);
72}
73
74void ActiveSiteHandler::setActiveLayerInDoc(Doc* doc, doc::Layer* layer)
75{
76 Data& data = getData(doc);
77 data.layer = (layer ? layer->id(): 0);
78}
79
80void ActiveSiteHandler::setActiveFrameInDoc(Doc* doc, doc::frame_t frame)
81{
82 Data& data = getData(doc);
83 data.frame = frame;
84}
85
86void ActiveSiteHandler::setRangeInDoc(Doc* doc, const DocRange& range)
87{
88 Data& data = getData(doc);
89 data.range = range;
90
91 // Select at least the active layer
92 if (data.range.selectedLayers().empty()) {
93 if (auto layer = doc::get<Layer>(data.layer)) {
94 data.range.selectLayer(layer);
95 }
96 }
97
98 // Select at least the active frame
99 if (data.range.selectedFrames().empty()) {
100 SelectedFrames frames;
101 frames.insert(data.frame);
102 data.range.setSelectedFrames(frames);
103 }
104
105 data.range.setType(range.type());
106}
107
108void ActiveSiteHandler::setSelectedColorsInDoc(Doc* doc, const doc::PalettePicks& picks)
109{
110 Data& data = getData(doc);
111 data.selectedColors = picks;
112}
113
114void ActiveSiteHandler::setSelectedTilesInDoc(Doc* doc, const doc::PalettePicks& picks)
115{
116 Data& data = getData(doc);
117 data.selectedTiles = picks;
118}
119
120void ActiveSiteHandler::onAddLayer(DocEvent& ev)
121{
122 Data& data = getData(ev.document());
123 data.layer = ev.layer()->id();
124}
125
126void ActiveSiteHandler::onAddFrame(DocEvent& ev)
127{
128 Data& data = getData(ev.document());
129 data.frame = ev.frame();
130}
131
132// TODO similar to Timeline::onBeforeRemoveLayer() and Editor::onBeforeRemoveLayer()
133void ActiveSiteHandler::onBeforeRemoveLayer(DocEvent& ev)
134{
135 Data& data = getData(ev.document());
136 doc::Layer* selectedLayer = (data.layer != doc::NullId ?
137 doc::get<doc::Layer>(data.layer):
138 nullptr);
139 if (!selectedLayer)
140 return;
141
142 // Remove layer from range
143 data.range.eraseAndAdjust(ev.layer());
144
145 // Select other layer as active
146 doc::Layer* layerToSelect = candidate_if_layer_is_deleted(selectedLayer, ev.layer());
147 if (selectedLayer != layerToSelect) {
148 data.layer = (layerToSelect ? layerToSelect->id():
149 doc::NullId);
150 }
151}
152
153// TODO similar to Timeline::onRemoveFrame()
154void ActiveSiteHandler::onRemoveFrame(DocEvent& ev)
155{
156 Data& data = getData(ev.document());
157
158 // Adjust current frame of the data that are in a frame more
159 // advanced that the removed one.
160 if (data.frame > ev.frame()) {
161 --data.frame;
162 }
163 // If the data was in the previous "last frame" (current value of
164 // totalFrames()), we've to adjust it to the new last frame
165 // (lastFrame())
166 else if (data.frame >= ev.sprite()->totalFrames()) {
167 data.frame = ev.sprite()->lastFrame();
168 }
169
170 if (data.frame < ev.frame())
171 --data.frame;
172}
173
174} // namespace app
175