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