1// Aseprite
2// Copyright (C) 2020-2021 Igara Studio S.A.
3// Copyright (C) 2001-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/util/range_utils.h"
13
14#include "app/context_access.h"
15#include "app/doc.h"
16#include "app/doc_range.h"
17#include "doc/cel.h"
18#include "doc/layer.h"
19#include "doc/sprite.h"
20
21#include <set>
22
23namespace app {
24
25using namespace doc;
26
27enum class Target {
28 kAllCels,
29 kUniqueCels,
30 kUniqueCanMoveCels,
31 kUniqueCanEditPixelsCels,
32};
33
34// TODO the DocRange should be "iteratable" to replace this function
35// or we can wait to C++20 coroutines and co_yield
36static CelList get_cels_templ(const Sprite* sprite,
37 DocRange range,
38 const Target target)
39{
40 CelList cels;
41 if (!range.convertToCels(sprite))
42 return cels;
43
44 // Used to visit linked cels just once.
45 std::set<ObjectId> visited;
46
47 for (Layer* layer : range.selectedLayers()) {
48 if (!layer ||
49 !layer->isImage() ||
50 (target == Target::kUniqueCanMoveCels && !layer->isEditableHierarchy()) ||
51 (target == Target::kUniqueCanEditPixelsCels && !layer->canEditPixels())) {
52 continue;
53 }
54
55 LayerImage* layerImage = static_cast<LayerImage*>(layer);
56 for (frame_t frame : range.selectedFrames()) {
57 Cel* cel = layerImage->cel(frame);
58 if (!cel)
59 continue;
60
61 if (target == Target::kAllCels ||
62 visited.find(cel->data()->id()) == visited.end()) {
63 // Only unique cels (avoid visited cels)
64 if (target != Target::kAllCels)
65 visited.insert(cel->data()->id());
66
67 cels.push_back(cel);
68 }
69 }
70 }
71 return cels;
72}
73
74CelList get_cels(const doc::Sprite* sprite, const DocRange& range)
75{
76 return get_cels_templ(sprite, range, Target::kAllCels);
77}
78
79CelList get_unique_cels(const Sprite* sprite, const DocRange& range)
80{
81 return get_cels_templ(sprite, range, Target::kUniqueCels);
82}
83
84CelList get_unique_cels_to_move_cel(const Sprite* sprite, const DocRange& range)
85{
86 return get_cels_templ(sprite, range, Target::kUniqueCanMoveCels);
87}
88
89CelList get_unique_cels_to_edit_pixels(const Sprite* sprite, const DocRange& range)
90{
91 return get_cels_templ(sprite, range, Target::kUniqueCanEditPixelsCels);
92}
93
94} // namespace app
95