BasicColors: add `noexcept`
[ncmpc-debian.git] / src / ListCursor.hxx
1 /* ncmpc (Ncurses MPD Client)
2  * (c) 2004-2019 The Music Player Daemon Project
3  * Project homepage: http://musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #ifndef LIST_CURSOR_HXX
21 #define LIST_CURSOR_HXX
22
23 #include "util/Compiler.h"
24
25 /**
26  * The bounds of a range selection, see list_window_get_range().
27  */
28 struct ListWindowRange {
29         /**
30          * The index of the first selected item.
31          */
32         unsigned start_index;
33
34         /**
35          * The index after the last selected item.  The selection is
36          * empty when this is the same as "start".
37          */
38         unsigned end_index;
39
40         constexpr bool empty() const noexcept {
41                 return start_index >= end_index;
42         }
43
44         constexpr bool Contains(unsigned i) const noexcept {
45                 return i >= start_index && i < end_index;
46         }
47
48         struct const_iterator {
49                 unsigned value;
50
51                 const_iterator &operator++() noexcept {
52                         ++value;
53                         return *this;
54                 }
55
56                 constexpr bool operator==(const const_iterator &other) const noexcept {
57                         return value == other.value;
58                 }
59
60                 constexpr bool operator!=(const const_iterator &other) const noexcept {
61                         return !(*this == other);
62                 }
63
64                 const unsigned &operator *() const noexcept {
65                         return value;
66                 }
67         };
68
69         constexpr const_iterator begin() const noexcept {
70                 return {start_index};
71         }
72
73         constexpr const_iterator end() const noexcept {
74                 return {end_index};
75         }
76 };
77
78 class ListCursor {
79         unsigned height;
80
81         /**
82          * Number of items in this list.
83          */
84         unsigned length = 0;
85
86         unsigned start = 0;
87         unsigned selected = 0;
88
89         /**
90          * Represents the base item.
91          */
92         unsigned range_base = 0;
93
94         /**
95          * Range selection activated?
96          */
97         bool range_selection = false;
98
99         bool hide_cursor = false;
100
101 public:
102         explicit constexpr ListCursor(unsigned _height) noexcept
103                 :height(_height) {}
104
105         constexpr unsigned GetHeight() const noexcept {
106                 return height;
107         }
108
109         constexpr unsigned GetOrigin() const noexcept {
110                 return start;
111         }
112
113         constexpr bool IsVisible(unsigned i) const noexcept {
114                 return i >= GetOrigin() && i < GetOrigin() + GetHeight();
115         }
116
117         void SetOrigin(unsigned new_orign) noexcept {
118                 start = new_orign;
119         }
120
121         void DisableCursor() {
122                 hide_cursor = true;
123         }
124
125         void EnableCursor() {
126                 hide_cursor = false;
127         }
128
129         constexpr bool HasCursor() const noexcept {
130                 return !hide_cursor;
131         }
132
133         constexpr bool HasRangeSelection() const noexcept {
134                 return range_selection;
135         }
136
137         /**
138          * Is the cursor currently pointing to a single valid item?
139          */
140         constexpr bool IsSingleCursor() const noexcept {
141                 return !HasRangeSelection() && selected < length;
142         }
143
144         constexpr unsigned GetCursorIndex() const noexcept {
145                 return selected;
146         }
147
148         void SelectionMovedUp() noexcept {
149                 selected--;
150                 range_base--;
151
152                 EnsureSelectionVisible();
153         }
154
155         void SelectionMovedDown() noexcept {
156                 selected++;
157                 range_base++;
158
159                 EnsureSelectionVisible();
160         }
161
162         void EnsureSelectionVisible() noexcept {
163                 if (range_selection)
164                         ScrollTo(range_base);
165                 ScrollTo(selected);
166         }
167
168         /** reset a list window (selected=0, start=0) */
169         void Reset() noexcept;
170
171         void SetHeight(unsigned _height) noexcept;
172
173         void SetLength(unsigned length) noexcept;
174
175         constexpr unsigned GetLength() const noexcept {
176                 return length;
177         }
178
179         /**
180          * Centers the visible range around item n on the list.
181          */
182         void Center(unsigned n) noexcept;
183
184         /**
185          * Scrolls the view to item n, as if the cursor would have been moved
186          * to the position.
187          */
188         void ScrollTo(unsigned n) noexcept;
189
190         /**
191          * Sets the position of the cursor.  Disables range selection.
192          */
193         void SetCursor(unsigned i) noexcept;
194
195         void SetCursorFromOrigin(unsigned i) noexcept {
196                 SetCursor(GetOrigin() + i);
197         }
198
199         void EnableRangeSelection() noexcept {
200                 range_base = selected;
201                 range_selection = true;
202         }
203
204         void DisableRangeSelection() noexcept {
205                 SetCursor(GetCursorIndex());
206         }
207
208         /**
209          * Moves the cursor.  Modifies the range if range selection is
210          * enabled.
211          */
212         void MoveCursor(unsigned n) noexcept;
213
214         void MoveCursorNext() noexcept;
215         void MoveCursorPrevious() noexcept;
216         void MoveCursorTop() noexcept;
217         void MoveCursorMiddle() noexcept;
218         void MoveCursorBottom() noexcept;
219         void MoveCursorFirst() noexcept;
220         void MoveCursorLast() noexcept;
221         void MoveCursorNextPage() noexcept;
222         void MoveCursorPreviousPage() noexcept;
223
224         void ScrollUp(unsigned n) noexcept;
225         void ScrollDown(unsigned n) noexcept;
226
227         void ScrollNextPage() noexcept;
228         void ScrollPreviousPage() noexcept;
229
230         void ScrollNextHalfPage() noexcept;
231         void ScrollPreviousHalfPage() noexcept;
232
233         void ScrollToBottom() noexcept {
234                 start = length > GetHeight()
235                         ? GetLength() - GetHeight()
236                         : 0;
237         }
238
239         /**
240          * Ensures that the cursor is visible on the screen, i.e. it is not
241          * outside the current scrolling range.
242          */
243         void FetchCursor() noexcept;
244
245         /**
246          * Determines the lower and upper bound of the range selection.  If
247          * range selection is disabled, it returns the cursor position (range
248          * length is 1).
249          */
250         gcc_pure
251         ListWindowRange GetRange() const noexcept;
252
253 private:
254         gcc_pure
255         unsigned ValidateIndex(unsigned i) const noexcept;
256
257         void CheckSelected() noexcept;
258
259         /**
260          * Scroll after the cursor was moved, the list was changed or
261          * the window was resized.
262          */
263         void CheckOrigin() noexcept {
264                 ScrollTo(selected);
265         }
266 };
267
268 #endif