menu: refresh: rename variables a bit
[ncmpcpp.git] / src / menu_impl.h
blob5b04699339372482313e933edc6d0bcb5c992ac1
1 /***************************************************************************
2 * Copyright (C) 2008-2014 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
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 *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #ifndef NCMPCPP_MENU_IMPL_H
22 #define NCMPCPP_MENU_IMPL_H
24 #include "menu.h"
26 namespace NC {
28 template <typename ItemT>
29 Menu<ItemT>::Menu(size_t startx,
30 size_t starty,
31 size_t width,
32 size_t height,
33 const std::string &title,
34 Color color,
35 Border border)
36 : Window(startx, starty, width, height, title, std::move(color), border),
37 m_item_displayer(0),
38 m_beginning(0),
39 m_highlight(0),
40 m_highlight_color(m_base_color),
41 m_highlight_enabled(true),
42 m_cyclic_scroll_enabled(false),
43 m_autocenter_cursor(false)
47 template <typename ItemT>
48 Menu<ItemT>::Menu(const Menu &rhs)
49 : Window(rhs)
50 , m_item_displayer(rhs.m_item_displayer)
51 , m_beginning(rhs.m_beginning)
52 , m_highlight(rhs.m_highlight)
53 , m_highlight_color(rhs.m_highlight_color)
54 , m_highlight_enabled(rhs.m_highlight_enabled)
55 , m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
56 , m_autocenter_cursor(rhs.m_autocenter_cursor)
57 , m_drawn_position(rhs.m_drawn_position)
58 , m_selected_prefix(rhs.m_selected_prefix)
59 , m_selected_suffix(rhs.m_selected_suffix)
61 // there is no way to properly fill m_filtered_options
62 // (if rhs is filtered), so we just don't do it.
63 m_items.reserve(rhs.m_items.size());
64 std::copy(rhs.begin(), rhs.end(), std::back_inserter(m_items));
67 template <typename ItemT>
68 Menu<ItemT>::Menu(Menu &&rhs)
69 : Window(rhs)
70 , m_item_displayer(rhs.m_item_displayer)
71 , m_items(std::move(rhs.m_items))
72 , m_beginning(rhs.m_beginning)
73 , m_highlight(rhs.m_highlight)
74 , m_highlight_color(rhs.m_highlight_color)
75 , m_highlight_enabled(rhs.m_highlight_enabled)
76 , m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
77 , m_autocenter_cursor(rhs.m_autocenter_cursor)
78 , m_drawn_position(rhs.m_drawn_position)
79 , m_selected_prefix(std::move(rhs.m_selected_prefix))
80 , m_selected_suffix(std::move(rhs.m_selected_suffix))
84 template <typename ItemT>
85 Menu<ItemT> &Menu<ItemT>::operator=(Menu rhs)
87 std::swap(static_cast<Window &>(*this), static_cast<Window &>(rhs));
88 std::swap(m_item_displayer, rhs.m_item_displayer);
89 std::swap(m_items, rhs.m_items);
90 std::swap(m_beginning, rhs.m_beginning);
91 std::swap(m_highlight, rhs.m_highlight);
92 std::swap(m_highlight_color, rhs.m_highlight_color);
93 std::swap(m_highlight_enabled, rhs.m_highlight_enabled);
94 std::swap(m_cyclic_scroll_enabled, rhs.m_cyclic_scroll_enabled);
95 std::swap(m_autocenter_cursor, rhs.m_autocenter_cursor);
96 std::swap(m_drawn_position, rhs.m_drawn_position);
97 std::swap(m_selected_prefix, rhs.m_selected_prefix);
98 std::swap(m_selected_suffix, rhs.m_selected_suffix);
99 return *this;
102 template <typename ItemT>
103 void Menu<ItemT>::resizeList(size_t new_size)
105 if (new_size > m_items.size())
107 size_t old_size = m_items.size();
108 m_items.resize(new_size);
109 for (size_t i = old_size; i < new_size; ++i)
110 m_items[i] = Item();
112 else
113 m_items.resize(new_size);
116 template <typename ItemT>
117 void Menu<ItemT>::addItem(ItemT item, bool is_bold, bool is_inactive)
119 m_items.push_back(Item(std::move(item), is_bold, is_inactive));
122 template <typename ItemT>
123 void Menu<ItemT>::addSeparator()
125 m_items.push_back(Item::mkSeparator());
128 template <typename ItemT>
129 void Menu<ItemT>::insertItem(size_t pos, const ItemT &item, bool is_bold, bool is_inactive)
131 m_items.insert(m_items.begin()+pos, Item(item, is_bold, is_inactive));
134 template <typename ItemT>
135 void Menu<ItemT>::insertSeparator(size_t pos)
137 m_items.insert(m_items.begin()+pos, Item::mkSeparator());
140 template <typename ItemT>
141 void Menu<ItemT>::deleteItem(size_t pos)
143 assert(pos < m_items.size());
144 m_items.erase(m_items.begin()+pos);
147 template <typename ItemT>
148 bool Menu<ItemT>::Goto(size_t y)
150 if (!isHighlightable(m_beginning+y))
151 return false;
152 m_highlight = m_beginning+y;
153 return true;
156 template <typename ItemT>
157 void Menu<ItemT>::refresh()
159 if (m_items.empty())
161 Window::clear();
162 Window::refresh();
163 return;
166 size_t max_beginning = 0;
167 if (m_items.size() > m_height)
168 max_beginning = m_items.size() - m_height;
169 m_beginning = std::min(m_beginning, max_beginning);
171 // if highlighted position is off the screen, make it visible
172 m_highlight = std::min(m_highlight, m_beginning+m_height-1);
173 // if highlighted position is invalid, correct it
174 m_highlight = std::min(m_highlight, m_items.size()-1);
176 if (!isHighlightable(m_highlight))
178 scroll(Scroll::Up);
179 if (!isHighlightable(m_highlight))
180 scroll(Scroll::Down);
183 size_t line = 0;
184 const size_t end = m_beginning+m_height;
185 m_drawn_position = m_beginning;
186 for (; m_drawn_position < end; ++m_drawn_position, ++line)
188 goToXY(0, line);
189 if (m_drawn_position >= m_items.size())
191 for (; line < m_height; ++line)
192 mvwhline(m_window, line, 0, KEY_SPACE, m_width);
193 break;
195 if (m_items[m_drawn_position].isSeparator())
197 mvwhline(m_window, line, 0, 0, m_width);
198 continue;
200 if (m_items[m_drawn_position].isBold())
201 *this << Format::Bold;
202 if (m_highlight_enabled && m_drawn_position == m_highlight)
204 *this << Format::Reverse;
205 *this << m_highlight_color;
207 mvwhline(m_window, line, 0, KEY_SPACE, m_width);
208 if (m_items[m_drawn_position].isSelected())
209 *this << m_selected_prefix;
210 if (m_item_displayer)
211 m_item_displayer(*this);
212 if (m_items[m_drawn_position].isSelected())
213 *this << m_selected_suffix;
214 if (m_highlight_enabled && m_drawn_position == m_highlight)
216 *this << Color::End;
217 *this << Format::NoReverse;
219 if (m_items[m_drawn_position].isBold())
220 *this << Format::NoBold;
222 Window::refresh();
225 template <typename ItemT>
226 void Menu<ItemT>::scroll(Scroll where)
228 if (m_items.empty())
229 return;
230 size_t max_highlight = m_items.size()-1;
231 size_t max_beginning = m_items.size() < m_height ? 0 : m_items.size()-m_height;
232 size_t max_visible_highlight = m_beginning+m_height-1;
233 switch (where)
235 case Scroll::Up:
237 if (m_highlight <= m_beginning && m_highlight > 0)
238 --m_beginning;
239 if (m_highlight == 0)
241 if (m_cyclic_scroll_enabled)
242 return scroll(Scroll::End);
243 break;
245 else
246 --m_highlight;
247 if (!isHighlightable(m_highlight))
248 scroll(m_highlight == 0 && !m_cyclic_scroll_enabled ? Scroll::Down : Scroll::Up);
249 break;
251 case Scroll::Down:
253 if (m_highlight >= max_visible_highlight && m_highlight < max_highlight)
254 ++m_beginning;
255 if (m_highlight == max_highlight)
257 if (m_cyclic_scroll_enabled)
258 return scroll(Scroll::Home);
259 break;
261 else
262 ++m_highlight;
263 if (!isHighlightable(m_highlight))
264 scroll(m_highlight == max_highlight && !m_cyclic_scroll_enabled ? Scroll::Up : Scroll::Down);
265 break;
267 case Scroll::PageUp:
269 if (m_cyclic_scroll_enabled && m_highlight == 0)
270 return scroll(Scroll::End);
271 if (m_highlight < m_height)
272 m_highlight = 0;
273 else
274 m_highlight -= m_height;
275 if (m_beginning < m_height)
276 m_beginning = 0;
277 else
278 m_beginning -= m_height;
279 if (!isHighlightable(m_highlight))
280 scroll(m_highlight == 0 && !m_cyclic_scroll_enabled ? Scroll::Down : Scroll::Up);
281 break;
283 case Scroll::PageDown:
285 if (m_cyclic_scroll_enabled && m_highlight == max_highlight)
286 return scroll(Scroll::Home);
287 m_highlight += m_height;
288 m_beginning += m_height;
289 m_beginning = std::min(m_beginning, max_beginning);
290 m_highlight = std::min(m_highlight, max_highlight);
291 if (!isHighlightable(m_highlight))
292 scroll(m_highlight == max_highlight && !m_cyclic_scroll_enabled ? Scroll::Up : Scroll::Down);
293 break;
295 case Scroll::Home:
297 m_highlight = 0;
298 m_beginning = 0;
299 if (!isHighlightable(m_highlight))
300 scroll(Scroll::Down);
301 break;
303 case Scroll::End:
305 m_highlight = max_highlight;
306 m_beginning = max_beginning;
307 if (!isHighlightable(m_highlight))
308 scroll(Scroll::Up);
309 break;
312 if (m_autocenter_cursor)
313 highlight(m_highlight);
316 template <typename ItemT>
317 void Menu<ItemT>::reset()
319 m_highlight = 0;
320 m_beginning = 0;
323 template <typename ItemT>
324 void Menu<ItemT>::clear()
326 m_items.clear();
329 template <typename ItemT>
330 void Menu<ItemT>::highlight(size_t pos)
332 assert(pos < m_items.size());
333 m_highlight = pos;
334 size_t half_height = m_height/2;
335 if (pos < half_height)
336 m_beginning = 0;
337 else
338 m_beginning = pos-half_height;
341 template <typename ItemT>
342 size_t Menu<ItemT>::choice() const
344 assert(!empty());
345 return m_highlight;
350 #endif // NCMPCPP_MENU_IMPL_H