1 /***************************************************************************
2 * Copyright (C) 2008-2016 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_H
22 #define NCMPCPP_MENU_H
24 #include <boost/iterator/transform_iterator.hpp>
25 #include <boost/range/detail/any_iterator.hpp>
32 #include "strbuffer.h"
44 Selectable
= (1 << 1),
50 Properties(Type properties
= Selectable
)
51 : m_properties(properties
)
54 void setBold(bool is_bold
)
59 m_properties
&= ~Bold
;
61 void setSelectable(bool is_selectable
)
64 m_properties
|= Selectable
;
66 m_properties
&= ~(Selectable
| Selected
);
68 void setSelected(bool is_selected
)
73 m_properties
|= Selected
;
75 m_properties
&= ~Selected
;
77 void setInactive(bool is_inactive
)
80 m_properties
|= Inactive
;
82 m_properties
&= ~Inactive
;
84 void setSeparator(bool is_separator
)
87 m_properties
|= Separator
;
89 m_properties
&= ~Separator
;
92 bool isBold() const { return m_properties
& Bold
; }
93 bool isSelectable() const { return m_properties
& Selectable
; }
94 bool isSelected() const { return m_properties
& Selected
; }
95 bool isInactive() const { return m_properties
& Inactive
; }
96 bool isSeparator() const { return m_properties
& Separator
; }
99 unsigned m_properties
;
102 template <typename ValueT
>
103 using PropertiesIterator
= boost::range_detail::any_iterator
<
105 boost::random_access_traversal_tag
,
110 typedef PropertiesIterator
<Properties
> Iterator
;
111 typedef PropertiesIterator
<const Properties
> ConstIterator
;
115 virtual bool empty() const = 0;
116 virtual size_t size() const = 0;
117 virtual size_t choice() const = 0;
118 virtual void highlight(size_t pos
) = 0;
120 virtual Iterator
currentP() = 0;
121 virtual ConstIterator
currentP() const = 0;
122 virtual Iterator
beginP() = 0;
123 virtual ConstIterator
beginP() const = 0;
124 virtual Iterator
endP() = 0;
125 virtual ConstIterator
endP() const = 0;
128 inline List::Properties::Type
operator|(List::Properties::Type lhs
, List::Properties::Type rhs
)
130 return List::Properties::Type(unsigned(lhs
) | unsigned(rhs
));
132 inline List::Properties::Type
&operator|=(List::Properties::Type
&lhs
, List::Properties::Type rhs
)
137 inline List::Properties::Type
operator&(List::Properties::Type lhs
, List::Properties::Type rhs
)
139 return List::Properties::Type(unsigned(lhs
) & unsigned(rhs
));
141 inline List::Properties::Type
&operator&=(List::Properties::Type
&lhs
, List::Properties::Type rhs
)
147 // for range-based for loop
148 inline List::Iterator
begin(List
&list
) { return list
.beginP(); }
149 inline List::ConstIterator
begin(const List
&list
) { return list
.beginP(); }
150 inline List::Iterator
end(List
&list
) { return list
.endP(); }
151 inline List::ConstIterator
end(const List
&list
) { return list
.endP(); }
153 /// Generic menu capable of holding any std::vector compatible values.
154 template <typename ItemT
>
155 struct Menu
: Window
, List
159 friend struct Menu
<ItemT
>;
164 : m_impl(std::make_shared
<std::tuple
<ItemT
, Properties
>>())
167 template <typename ValueT
, typename PropertiesT
>
168 Item(ValueT
&&value_
, PropertiesT properties_
)
170 std::make_shared
<std::tuple
<ItemT
, List::Properties
>>(
171 std::forward
<ValueT
>(value_
),
172 std::forward
<PropertiesT
>(properties_
)))
175 ItemT
&value() { return std::get
<0>(*m_impl
); }
176 const ItemT
&value() const { return std::get
<0>(*m_impl
); }
178 Properties
&properties() { return std::get
<1>(*m_impl
); }
179 const Properties
&properties() const { return std::get
<1>(*m_impl
); }
181 // Forward methods to List::Properties.
182 void setBold (bool is_bold
) { properties().setBold(is_bold
); }
183 void setSelectable(bool is_selectable
) { properties().setSelectable(is_selectable
); }
184 void setSelected (bool is_selected
) { properties().setSelected(is_selected
); }
185 void setInactive (bool is_inactive
) { properties().setInactive(is_inactive
); }
186 void setSeparator (bool is_separator
) { properties().setSeparator(is_separator
); }
188 bool isBold() const { return properties().isBold(); }
189 bool isSelectable() const { return properties().isSelectable(); }
190 bool isSelected() const { return properties().isSelected(); }
191 bool isInactive() const { return properties().isInactive(); }
192 bool isSeparator() const { return properties().isSeparator(); }
194 // Make a deep copy of Item.
196 return Item(value(), properties());
200 enum class Const
{ Yes
, No
};
202 template <Const const_
>
203 struct ExtractProperties
205 typedef ExtractProperties type
;
207 typedef typename
std::conditional
<
208 const_
== Const::Yes
,
210 Properties
>::type Properties_
;
211 typedef typename
std::conditional
<
212 const_
== Const::Yes
,
216 Properties_
&operator()(Item_
&i
) const {
217 return i
.properties();
221 template <Const const_
>
224 typedef ExtractValue type
;
226 typedef typename
std::conditional
<
227 const_
== Const::Yes
,
230 typedef typename
std::conditional
<
231 const_
== Const::Yes
,
235 Value_
&operator()(Item_
&i
) const {
240 static Item
mkSeparator()
243 item
.setSelectable(false);
244 item
.setSeparator(true);
248 std::shared_ptr
<std::tuple
<ItemT
, Properties
>> m_impl
;
251 typedef typename
std::vector
<Item
>::iterator Iterator
;
252 typedef typename
std::vector
<Item
>::const_iterator ConstIterator
;
253 typedef std::reverse_iterator
<Iterator
> ReverseIterator
;
254 typedef std::reverse_iterator
<ConstIterator
> ConstReverseIterator
;
256 typedef boost::transform_iterator
<
257 typename
Item::template ExtractValue
<Item::Const::No
>,
258 Iterator
> ValueIterator
;
259 typedef boost::transform_iterator
<
260 typename
Item::template ExtractValue
<Item::Const::Yes
>,
261 ConstIterator
> ConstValueIterator
;
262 typedef std::reverse_iterator
<ValueIterator
> ReverseValueIterator
;
263 typedef std::reverse_iterator
<ConstValueIterator
> ConstReverseValueIterator
;
265 typedef boost::transform_iterator
<
266 typename
Item::template ExtractProperties
<Item::Const::No
>,
267 Iterator
> PropertiesIterator
;
268 typedef boost::transform_iterator
<
269 typename
Item::template ExtractProperties
<Item::Const::Yes
>,
270 ConstIterator
> ConstPropertiesIterator
;
272 /// Function helper prototype used to display each option on the screen.
273 /// If not set by setItemDisplayer(), menu won't display anything.
274 /// @see setItemDisplayer()
275 typedef std::function
<void(Menu
<ItemT
> &)> ItemDisplayer
;
277 typedef std::function
<bool(const Item
&)> FilterPredicate
;
281 Menu(size_t startx
, size_t starty
, size_t width
, size_t height
,
282 const std::string
&title
, Color color
, Border border
);
284 Menu(const Menu
&rhs
);
286 Menu
&operator=(Menu rhs
);
288 /// Sets helper function that is responsible for displaying items
289 /// @param ptr function pointer that matches the ItemDisplayer prototype
290 template <typename ItemDisplayerT
>
291 void setItemDisplayer(ItemDisplayerT
&&displayer
);
293 /// Resizes the list to given size (adequate to std::vector::resize())
294 /// @param size requested size
295 void resizeList(size_t new_size
);
297 /// Adds a new option to list
298 void addItem(ItemT item
, Properties::Type properties
= Properties::Selectable
);
300 /// Adds separator to list
303 /// Inserts a new option to the list at given position
304 void insertItem(size_t pos
, ItemT item
, Properties::Type properties
= Properties::Selectable
);
306 /// Inserts separator to list at given position
307 /// @param pos initial position of inserted separator
308 void insertSeparator(size_t pos
);
310 /// Moves the highlighted position to the given line of window
311 /// @param y Y position of menu window to be highlighted
312 /// @return true if the position is reachable, false otherwise
315 /// Checks if list is empty
316 /// @return true if list is empty, false otherwise
317 virtual bool empty() const override
{ return m_items
->empty(); }
319 /// @return size of the list
320 virtual size_t size() const override
{ return m_items
->size(); }
322 /// @return currently highlighted position
323 virtual size_t choice() const override
;
325 /// Highlights given position
326 /// @param pos position to be highlighted
327 virtual void highlight(size_t position
) override
;
329 /// Refreshes the menu window
330 /// @see Window::refresh()
331 virtual void refresh() override
;
333 /// Scrolls by given amount of lines
334 /// @param where indicated where exactly one wants to go
335 /// @see Window::scroll()
336 virtual void scroll(Scroll where
) override
;
338 /// Cleares all options, used filters etc. It doesn't reset highlighted position though.
340 virtual void clear() override
;
342 /// Sets highlighted position to 0
345 /// Apply filter predicate to items in the menu and show the ones for which it
347 template <typename PredicateT
>
348 void applyFilter(PredicateT
&&pred
);
350 /// Reapply previously applied filter.
351 void reapplyFilter();
353 /// Get current filter predicate.
354 template <typename TargetT
>
355 const TargetT
*filterPredicate() const;
357 /// Clear results of applyFilter and show all items.
360 /// @return true if menu is filtered.
361 bool isFiltered() const { return m_items
== &m_filtered_items
; }
364 void showAllItems() { m_items
= &m_all_items
; }
366 /// Show filtered items.
367 void showFilteredItems() { m_items
= &m_filtered_items
; }
369 /// Sets prefix, that is put before each selected item to indicate its selection
370 /// Note that the passed variable is not deleted along with menu object.
371 /// @param b pointer to buffer that contains the prefix
372 void setSelectedPrefix(const Buffer
&b
) { m_selected_prefix
= b
; }
374 /// Sets suffix, that is put after each selected item to indicate its selection
375 /// Note that the passed variable is not deleted along with menu object.
376 /// @param b pointer to buffer that contains the suffix
377 void setSelectedSuffix(const Buffer
&b
) { m_selected_suffix
= b
; }
379 /// Sets custom color of highlighted position
380 /// @param col custom color
381 void setHighlightColor(Color color
) { m_highlight_color
= std::move(color
); }
383 /// @return state of highlighting
384 bool isHighlighted() { return m_highlight_enabled
; }
386 /// Turns on/off highlighting
387 /// @param state state of hihglighting
388 void setHighlighting(bool state
) { m_highlight_enabled
= state
; }
390 /// Turns on/off cyclic scrolling
391 /// @param state state of cyclic scrolling
392 void cyclicScrolling(bool state
) { m_cyclic_scroll_enabled
= state
; }
394 /// Turns on/off centered cursor
395 /// @param state state of centered cursor
396 void centeredCursor(bool state
) { m_autocenter_cursor
= state
; }
398 /// @return currently drawn item. The result is defined only within
399 /// drawing function that is called by refresh()
401 ConstIterator
drawn() const { return begin() + m_drawn_position
; }
403 /// @param pos requested position
404 /// @return reference to item at given position
405 /// @throw std::out_of_range if given position is out of range
406 Menu
<ItemT
>::Item
&at(size_t pos
) { return m_items
->at(pos
); }
408 /// @param pos requested position
409 /// @return const reference to item at given position
410 /// @throw std::out_of_range if given position is out of range
411 const Menu
<ItemT
>::Item
&at(size_t pos
) const { return m_items
->at(pos
); }
413 /// @param pos requested position
414 /// @return const reference to item at given position
415 const Menu
<ItemT
>::Item
&operator[](size_t pos
) const { return (*m_items
)[pos
]; }
417 /// @param pos requested position
418 /// @return const reference to item at given position
419 Menu
<ItemT
>::Item
&operator[](size_t pos
) { return (*m_items
)[pos
]; }
421 Iterator
current() { return Iterator(m_items
->begin() + m_highlight
); }
422 ConstIterator
current() const { return ConstIterator(m_items
->begin() + m_highlight
); }
423 ReverseIterator
rcurrent() {
427 return ReverseIterator(++current());
429 ConstReverseIterator
rcurrent() const {
433 return ConstReverseIterator(++current());
436 ValueIterator
currentV() { return ValueIterator(m_items
->begin() + m_highlight
); }
437 ConstValueIterator
currentV() const { return ConstValueIterator(m_items
->begin() + m_highlight
); }
438 ReverseValueIterator
rcurrentV() {
442 return ReverseValueIterator(++currentV());
444 ConstReverseValueIterator
rcurrentV() const {
448 return ConstReverseValueIterator(++currentV());
451 Iterator
begin() { return Iterator(m_items
->begin()); }
452 ConstIterator
begin() const { return ConstIterator(m_items
->begin()); }
453 Iterator
end() { return Iterator(m_items
->end()); }
454 ConstIterator
end() const { return ConstIterator(m_items
->end()); }
456 ReverseIterator
rbegin() { return ReverseIterator(end()); }
457 ConstReverseIterator
rbegin() const { return ConstReverseIterator(end()); }
458 ReverseIterator
rend() { return ReverseIterator(begin()); }
459 ConstReverseIterator
rend() const { return ConstReverseIterator(begin()); }
461 ValueIterator
beginV() { return ValueIterator(begin()); }
462 ConstValueIterator
beginV() const { return ConstValueIterator(begin()); }
463 ValueIterator
endV() { return ValueIterator(end()); }
464 ConstValueIterator
endV() const { return ConstValueIterator(end()); }
466 ReverseValueIterator
rbeginV() { return ReverseValueIterator(endV()); }
467 ConstReverseIterator
rbeginV() const { return ConstReverseValueIterator(endV()); }
468 ReverseValueIterator
rendV() { return ReverseValueIterator(beginV()); }
469 ConstReverseValueIterator
rendV() const { return ConstReverseValueIterator(beginV()); }
471 virtual List::Iterator
currentP() override
{
472 return List::Iterator(PropertiesIterator(m_items
->begin() + m_highlight
));
474 virtual List::ConstIterator
currentP() const override
{
475 return List::ConstIterator(ConstPropertiesIterator(m_items
->begin() + m_highlight
));
477 virtual List::Iterator
beginP() override
{
478 return List::Iterator(PropertiesIterator(m_items
->begin()));
480 virtual List::ConstIterator
beginP() const override
{
481 return List::ConstIterator(ConstPropertiesIterator(m_items
->begin()));
483 virtual List::Iterator
endP() override
{
484 return List::Iterator(PropertiesIterator(m_items
->end()));
486 virtual List::ConstIterator
endP() const override
{
487 return List::ConstIterator(ConstPropertiesIterator(m_items
->end()));
491 bool isHighlightable(size_t pos
)
493 return !(*m_items
)[pos
].isSeparator()
494 && !(*m_items
)[pos
].isInactive();
497 ItemDisplayer m_item_displayer
;
498 FilterPredicate m_filter_predicate
;
500 std::vector
<Item
> *m_items
;
501 std::vector
<Item
> m_all_items
;
502 std::vector
<Item
> m_filtered_items
;
507 Color m_highlight_color
;
508 bool m_highlight_enabled
;
509 bool m_cyclic_scroll_enabled
;
511 bool m_autocenter_cursor
;
513 size_t m_drawn_position
;
515 Buffer m_selected_prefix
;
516 Buffer m_selected_suffix
;
521 #endif // NCMPCPP_MENU_H