1 | // Aseprite Document Library |
---|---|
2 | // Copyright (c) 2022 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 | #ifndef DOC_SELECTED_FRAMES_H_INCLUDED |
9 | #define DOC_SELECTED_FRAMES_H_INCLUDED |
10 | #pragma once |
11 | |
12 | #include "doc/frame_range.h" |
13 | |
14 | #include <iosfwd> |
15 | #include <vector> |
16 | |
17 | namespace doc { |
18 | |
19 | class SelectedFrames { |
20 | typedef std::vector<FrameRange> Ranges; |
21 | |
22 | public: |
23 | class const_iterator { |
24 | static const int kNullFrame = -2; |
25 | public: |
26 | using iterator_category = std::forward_iterator_tag; |
27 | using value_type = frame_t; |
28 | using difference_type = std::ptrdiff_t; |
29 | using pointer = frame_t*; |
30 | using reference = frame_t&; |
31 | |
32 | const_iterator(const Ranges::const_iterator& it) |
33 | : m_it(it), m_frame(kNullFrame) { |
34 | } |
35 | |
36 | const_iterator& operator++() { |
37 | if (m_frame == kNullFrame) |
38 | m_frame = m_it->fromFrame; |
39 | |
40 | if (m_it->fromFrame <= m_it->toFrame) { |
41 | if (m_frame < m_it->toFrame) |
42 | ++m_frame; |
43 | else { |
44 | m_frame = kNullFrame; |
45 | ++m_it; |
46 | } |
47 | } |
48 | else { |
49 | if (m_frame > m_it->toFrame) |
50 | --m_frame; |
51 | else { |
52 | m_frame = kNullFrame; |
53 | ++m_it; |
54 | } |
55 | } |
56 | |
57 | return *this; |
58 | } |
59 | |
60 | frame_t operator*() const { |
61 | if (m_frame == kNullFrame) |
62 | m_frame = m_it->fromFrame; |
63 | return m_frame; |
64 | } |
65 | |
66 | bool operator==(const const_iterator& o) const { |
67 | return (m_it == o.m_it && m_frame == o.m_frame); |
68 | } |
69 | |
70 | bool operator!=(const const_iterator& it) const { |
71 | return !operator==(it); |
72 | } |
73 | |
74 | private: |
75 | mutable Ranges::const_iterator m_it; |
76 | mutable frame_t m_frame; |
77 | }; |
78 | |
79 | class const_reverse_iterator { |
80 | public: |
81 | using iterator_category = std::forward_iterator_tag; |
82 | using value_type = frame_t; |
83 | using difference_type = std::ptrdiff_t; |
84 | using pointer = frame_t*; |
85 | using reference = frame_t&; |
86 | |
87 | const_reverse_iterator(const Ranges::const_reverse_iterator& it) |
88 | : m_it(it), m_frame(-1) { |
89 | } |
90 | |
91 | const_reverse_iterator& operator++() { |
92 | if (m_frame < 0) |
93 | m_frame = m_it->toFrame; |
94 | |
95 | if (m_frame > m_it->fromFrame) |
96 | --m_frame; |
97 | else { |
98 | m_frame = -1; |
99 | ++m_it; |
100 | } |
101 | |
102 | return *this; |
103 | } |
104 | |
105 | frame_t operator*() const { |
106 | if (m_frame < 0) |
107 | m_frame = m_it->toFrame; |
108 | return m_frame; |
109 | } |
110 | |
111 | bool operator==(const const_reverse_iterator& o) const { |
112 | return (m_it == o.m_it && m_frame == o.m_frame); |
113 | } |
114 | |
115 | bool operator!=(const const_reverse_iterator& it) const { |
116 | return !operator==(it); |
117 | } |
118 | |
119 | private: |
120 | mutable Ranges::const_reverse_iterator m_it; |
121 | mutable frame_t m_frame; |
122 | }; |
123 | |
124 | class Reversed { |
125 | public: |
126 | typedef const_reverse_iterator const_iterator; |
127 | |
128 | const_iterator begin() const { return m_selectedFrames.rbegin(); } |
129 | const_iterator end() const { return m_selectedFrames.rend(); } |
130 | |
131 | Reversed(const SelectedFrames& selectedFrames) |
132 | : m_selectedFrames(selectedFrames) { |
133 | } |
134 | |
135 | private: |
136 | const SelectedFrames& m_selectedFrames; |
137 | }; |
138 | |
139 | const_iterator begin() const { return const_iterator(m_ranges.begin()); } |
140 | const_iterator end() const { return const_iterator(m_ranges.end()); } |
141 | const_reverse_iterator rbegin() const { return const_reverse_iterator(m_ranges.rbegin()); } |
142 | const_reverse_iterator rend() const { return const_reverse_iterator(m_ranges.rend()); } |
143 | |
144 | std::size_t size() const; |
145 | std::size_t ranges() const { return m_ranges.size(); } |
146 | bool empty() const { return m_ranges.empty(); } |
147 | |
148 | void clear(); |
149 | void insert(frame_t frame); |
150 | void insert(frame_t fromFrame, frame_t toFrame); |
151 | SelectedFrames filter(frame_t fromFrame, frame_t toFrame) const; |
152 | |
153 | bool contains(frame_t frame) const; |
154 | |
155 | frame_t firstFrame() const { return (!m_ranges.empty() ? m_ranges.front().fromFrame: -1); } |
156 | frame_t lastFrame() const { return (!m_ranges.empty() ? m_ranges.back().toFrame: -1); } |
157 | |
158 | void displace(frame_t frameDelta); |
159 | Reversed reversed() const { return Reversed(*this); } |
160 | |
161 | SelectedFrames makeReverse() const; |
162 | SelectedFrames makePingPong() const; |
163 | |
164 | bool operator==(const SelectedFrames& o) const { |
165 | return m_ranges == o.m_ranges; |
166 | } |
167 | |
168 | bool operator!=(const SelectedFrames& o) const { |
169 | return !operator==(o); |
170 | } |
171 | |
172 | bool write(std::ostream& os) const; |
173 | bool read(std::istream& is); |
174 | |
175 | private: |
176 | Ranges m_ranges; |
177 | }; |
178 | |
179 | } // namespace doc |
180 | |
181 | #endif // DOC_SELECTED_FRAMES_H_INCLUDED |
182 |