1 /***************************************************************************
2 * Copyright (C) 2008-2014 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
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. *
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. *
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
28 template <typename ItemT
>
29 Menu
<ItemT
>::Menu(size_t startx
,
33 const std::string
&title
,
36 : Window(startx
, starty
, width
, height
, title
, std::move(color
), border
),
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
)
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
)
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
);
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
)
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
))
152 m_highlight
= m_beginning
+y
;
156 template <typename ItemT
>
157 void Menu
<ItemT
>::refresh()
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
))
179 if (!isHighlightable(m_highlight
))
180 scroll(Scroll::Down
);
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
)
189 if (m_drawn_position
>= m_items
.size())
191 for (; line
< m_height
; ++line
)
192 mvwhline(m_window
, line
, 0, KEY_SPACE
, m_width
);
195 if (m_items
[m_drawn_position
].isSeparator())
197 mvwhline(m_window
, line
, 0, 0, m_width
);
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
)
217 *this << Format::NoReverse
;
219 if (m_items
[m_drawn_position
].isBold())
220 *this << Format::NoBold
;
225 template <typename ItemT
>
226 void Menu
<ItemT
>::scroll(Scroll where
)
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;
237 if (m_highlight
<= m_beginning
&& m_highlight
> 0)
239 if (m_highlight
== 0)
241 if (m_cyclic_scroll_enabled
)
242 return scroll(Scroll::End
);
247 if (!isHighlightable(m_highlight
))
248 scroll(m_highlight
== 0 && !m_cyclic_scroll_enabled
? Scroll::Down
: Scroll::Up
);
253 if (m_highlight
>= max_visible_highlight
&& m_highlight
< max_highlight
)
255 if (m_highlight
== max_highlight
)
257 if (m_cyclic_scroll_enabled
)
258 return scroll(Scroll::Home
);
263 if (!isHighlightable(m_highlight
))
264 scroll(m_highlight
== max_highlight
&& !m_cyclic_scroll_enabled
? Scroll::Up
: Scroll::Down
);
269 if (m_cyclic_scroll_enabled
&& m_highlight
== 0)
270 return scroll(Scroll::End
);
271 if (m_highlight
< m_height
)
274 m_highlight
-= m_height
;
275 if (m_beginning
< m_height
)
278 m_beginning
-= m_height
;
279 if (!isHighlightable(m_highlight
))
280 scroll(m_highlight
== 0 && !m_cyclic_scroll_enabled
? Scroll::Down
: Scroll::Up
);
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
);
299 if (!isHighlightable(m_highlight
))
300 scroll(Scroll::Down
);
305 m_highlight
= max_highlight
;
306 m_beginning
= max_beginning
;
307 if (!isHighlightable(m_highlight
))
312 if (m_autocenter_cursor
)
313 highlight(m_highlight
);
316 template <typename ItemT
>
317 void Menu
<ItemT
>::reset()
323 template <typename ItemT
>
324 void Menu
<ItemT
>::clear()
329 template <typename ItemT
>
330 void Menu
<ItemT
>::highlight(size_t pos
)
332 assert(pos
< m_items
.size());
334 size_t half_height
= m_height
/2;
335 if (pos
< half_height
)
338 m_beginning
= pos
-half_height
;
341 template <typename ItemT
>
342 size_t Menu
<ItemT
>::choice() const
350 #endif // NCMPCPP_MENU_IMPL_H