1// Aseprite
2// Copyright (C) 2019-2022 Igara Studio S.A.
3// Copyright (C) 2016-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/ui/layer_frame_comboboxes.h"
13
14#include "app/i18n/strings.h"
15#include "app/restore_visible_layers.h"
16#include "app/site.h"
17#include "doc/anidir.h"
18#include "doc/layer.h"
19#include "doc/selected_frames.h"
20#include "doc/selected_layers.h"
21#include "doc/slice.h"
22#include "doc/sprite.h"
23#include "doc/tag.h"
24#include "ui/combobox.h"
25
26namespace app {
27
28const char* kWholeCanvas = "";
29const char* kAllLayers = "";
30const char* kAllFrames = "";
31const char* kSelectedCanvas = "**selected-canvas**";
32const char* kSelectedLayers = "**selected-layers**";
33const char* kSelectedFrames = "**selected-frames**";
34
35SliceListItem::SliceListItem(doc::Slice* slice)
36 : ListItem("Slice: " + slice->name())
37 , m_slice(slice)
38{
39 setValue(m_slice->name());
40}
41
42LayerListItem::LayerListItem(doc::Layer* layer)
43 : ListItem(buildName(layer))
44 , m_layer(layer)
45{
46 setValue(layer->name());
47}
48
49// static
50std::string LayerListItem::buildName(const doc::Layer* layer)
51{
52 bool isGroup = layer->isGroup();
53 std::string name;
54 while (layer != layer->sprite()->root()) {
55 if (!name.empty())
56 name.insert(0, " > ");
57 name.insert(0, layer->name());
58 layer = layer->parent();
59 }
60 const std::string namePrefix =
61 (isGroup ? Strings::layer_combo_group() :
62 Strings::layer_combo_layer()) + " ";
63 name.insert(0, namePrefix);
64 return name;
65}
66
67FrameListItem::FrameListItem(doc::Tag* tag)
68 : ListItem(Strings::frame_combo_tag() + " " + tag->name())
69 , m_tag(tag)
70{
71 setValue(m_tag->name());
72}
73
74void fill_area_combobox(const doc::Sprite* sprite, ui::ComboBox* area, const std::string& defArea)
75{
76 int i = area->addItem("Canvas");
77 dynamic_cast<ui::ListItem*>(area->getItem(i))->setValue(kWholeCanvas);
78
79 i = area->addItem("Selection");
80 dynamic_cast<ui::ListItem*>(area->getItem(i))->setValue(kSelectedCanvas);
81 if (defArea == kSelectedCanvas)
82 area->setSelectedItemIndex(i);
83
84 for (auto slice : sprite->slices()) {
85 if (slice->name().empty())
86 continue;
87
88 i = area->addItem(new SliceListItem(slice));
89 if (defArea == slice->name())
90 area->setSelectedItemIndex(i);
91 }
92}
93
94void fill_layers_combobox(const doc::Sprite* sprite, ui::ComboBox* layers, const std::string& defLayer, const int defLayerIndex)
95{
96 int i = layers->addItem(Strings::layer_combo_visible_layers());
97 dynamic_cast<ui::ListItem*>(layers->getItem(i))->setValue(kAllLayers);
98
99 i = layers->addItem(Strings::layer_combo_selected_layers());
100 dynamic_cast<ui::ListItem*>(layers->getItem(i))->setValue(kSelectedLayers);
101 if (defLayer == kSelectedLayers)
102 layers->setSelectedItemIndex(i);
103
104 assert(layers->getItemCount() == kLayersComboboxExtraInitialItems);
105 static_assert(kLayersComboboxExtraInitialItems == 2,
106 "Update kLayersComboboxExtraInitialItems value to match the number of initial items in layers combobox");
107
108 doc::LayerList layersList = sprite->allLayers();
109 for (auto it=layersList.rbegin(), end=layersList.rend(); it!=end; ++it) {
110 doc::Layer* layer = *it;
111 i = layers->addItem(new LayerListItem(layer));
112 if (defLayer == layer->name() && (defLayerIndex == -1 ||
113 defLayerIndex == i-kLayersComboboxExtraInitialItems))
114 layers->setSelectedItemIndex(i);
115 }
116}
117
118void fill_frames_combobox(const doc::Sprite* sprite, ui::ComboBox* frames, const std::string& defFrame)
119{
120 int i = frames->addItem(Strings::frame_combo_all_frames());
121 dynamic_cast<ui::ListItem*>(frames->getItem(i))->setValue(kAllFrames);
122
123 i = frames->addItem(Strings::frame_combo_selected_frames());
124 dynamic_cast<ui::ListItem*>(frames->getItem(i))->setValue(kSelectedFrames);
125 if (defFrame == kSelectedFrames)
126 frames->setSelectedItemIndex(i);
127
128 for (auto tag : sprite->tags()) {
129 // Don't allow to select empty frame tags
130 if (tag->name().empty())
131 continue;
132
133 i = frames->addItem(new FrameListItem(tag));
134 if (defFrame == tag->name())
135 frames->setSelectedItemIndex(i);
136 }
137}
138
139void fill_anidir_combobox(ui::ComboBox* anidir, doc::AniDir defAnidir)
140{
141 static_assert(
142 int(doc::AniDir::FORWARD) == 0 &&
143 int(doc::AniDir::REVERSE) == 1 &&
144 int(doc::AniDir::PING_PONG) == 2, "doc::AniDir has changed");
145
146 anidir->addItem(Strings::anidir_combo_forward());
147 anidir->addItem(Strings::anidir_combo_reverse());
148 anidir->addItem(Strings::anidir_combo_ping_pong());
149 anidir->setSelectedItemIndex(int(defAnidir));
150}
151
152void calculate_visible_layers(const Site& site,
153 const std::string& layersValue,
154 const int layersIndex,
155 RestoreVisibleLayers& layersVisibility)
156{
157 if (layersValue == kSelectedLayers) {
158 if (!site.selectedLayers().empty()) {
159 layersVisibility.showSelectedLayers(
160 const_cast<Sprite*>(site.sprite()),
161 site.selectedLayers());
162 }
163 else {
164 layersVisibility.showLayer(const_cast<Layer*>(site.layer()));
165 }
166 }
167 else if (layersValue != kAllLayers) {
168 int i = site.sprite()->allLayersCount();
169 // TODO add a getLayerByName
170 for (doc::Layer* layer : site.sprite()->allLayers()) {
171 i--;
172 if (layer->name() == layersValue && (layersIndex == -1 ||
173 layersIndex == i)) {
174 layersVisibility.showLayer(layer);
175 break;
176 }
177 }
178 }
179}
180
181doc::Tag* calculate_selected_frames(const Site& site,
182 const std::string& framesValue,
183 doc::SelectedFrames& selFrames)
184{
185 doc::Tag* tag = nullptr;
186
187 if (framesValue == kSelectedFrames) {
188 if (!site.selectedFrames().empty()) {
189 selFrames = site.selectedFrames();
190 }
191 else {
192 selFrames.insert(site.frame(), site.frame());
193 }
194 }
195 else if (framesValue != kAllFrames) {
196 tag = site.sprite()->tags().getByName(framesValue);
197 if (tag)
198 selFrames.insert(tag->fromFrame(),
199 tag->toFrame());
200 else
201 selFrames.insert(0, site.sprite()->lastFrame());
202 }
203 else
204 selFrames.insert(0, site.sprite()->lastFrame());
205
206 return tag;
207}
208
209} // namespace app
210