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 "utility/const.h"
33 #include "strbuffer.h"
45 Selectable
= (1 << 1),
51 Properties(Type properties
= Selectable
)
52 : m_properties(properties
)
55 void setBold(bool is_bold
)
60 m_properties
&= ~Bold
;
62 void setSelectable(bool is_selectable
)
65 m_properties
|= Selectable
;
67 m_properties
&= ~(Selectable
| Selected
);
69 void setSelected(bool is_selected
)
74 m_properties
|= Selected
;
76 m_properties
&= ~Selected
;
78 void setInactive(bool is_inactive
)
81 m_properties
|= Inactive
;
83 m_properties
&= ~Inactive
;
85 void setSeparator(bool is_separator
)
88 m_properties
|= Separator
;
90 m_properties
&= ~Separator
;
93 bool isBold() const { return m_properties
& Bold
; }
94 bool isSelectable() const { return m_properties
& Selectable
; }
95 bool isSelected() const { return m_properties
& Selected
; }
96 bool isInactive() const { return m_properties
& Inactive
; }
97 bool isSeparator() const { return m_properties
& Separator
; }
100 unsigned m_properties
;
103 template <typename ValueT
>
104 using PropertiesIterator
= boost::range_detail::any_iterator
<
106 boost::random_access_traversal_tag
,
111 typedef PropertiesIterator
<Properties
> Iterator
;
112 typedef PropertiesIterator
<const Properties
> ConstIterator
;
116 virtual bool empty() const = 0;
117 virtual size_t size() const = 0;
118 virtual size_t choice() const = 0;
119 virtual void highlight(size_t pos
) = 0;
121 virtual Iterator
currentP() = 0;
122 virtual ConstIterator
currentP() const = 0;
123 virtual Iterator
beginP() = 0;
124 virtual ConstIterator
beginP() const = 0;
125 virtual Iterator
endP() = 0;
126 virtual ConstIterator
endP() const = 0;
129 inline List::Properties::Type
operator|(List::Properties::Type lhs
, List::Properties::Type rhs
)
131 return List::Properties::Type(unsigned(lhs
) | unsigned(rhs
));
133 inline List::Properties::Type
&operator|=(List::Properties::Type
&lhs
, List::Properties::Type rhs
)
138 inline List::Properties::Type
operator&(List::Properties::Type lhs
, List::Properties::Type rhs
)
140 return List::Properties::Type(unsigned(lhs
) & unsigned(rhs
));
142 inline List::Properties::Type
&operator&=(List::Properties::Type
&lhs
, List::Properties::Type rhs
)
148 // for range-based for loop
149 inline List::Iterator
begin(List
&list
) { return list
.beginP(); }
150 inline List::ConstIterator
begin(const List
&list
) { return list
.beginP(); }
151 inline List::Iterator
end(List
&list
) { return list
.endP(); }
152 inline List::ConstIterator
end(const List
&list
) { return list
.endP(); }
154 /// Generic menu capable of holding any std::vector compatible values.
155 template <typename ItemT
>
156 struct Menu
: Window
, List
160 friend struct Menu
<ItemT
>;
165 : m_impl(std::make_shared
<std::tuple
<ItemT
, Properties
>>())
168 template <typename ValueT
, typename PropertiesT
>
169 Item(ValueT
&&value_
, PropertiesT properties_
)
171 std::make_shared
<std::tuple
<ItemT
, List::Properties
>>(
172 std::forward
<ValueT
>(value_
),
173 std::forward
<PropertiesT
>(properties_
)))
176 ItemT
&value() { return std::get
<0>(*m_impl
); }
177 const ItemT
&value() const { return std::get
<0>(*m_impl
); }
179 Properties
&properties() { return std::get
<1>(*m_impl
); }
180 const Properties
&properties() const { return std::get
<1>(*m_impl
); }
182 // Forward methods to List::Properties.
183 void setBold (bool is_bold
) { properties().setBold(is_bold
); }
184 void setSelectable(bool is_selectable
) { properties().setSelectable(is_selectable
); }
185 void setSelected (bool is_selected
) { properties().setSelected(is_selected
); }
186 void setInactive (bool is_inactive
) { properties().setInactive(is_inactive
); }
187 void setSeparator (bool is_separator
) { properties().setSeparator(is_separator
); }
189 bool isBold() const { return properties().isBold(); }
190 bool isSelectable() const { return properties().isSelectable(); }
191 bool isSelected() const { return properties().isSelected(); }
192 bool isInactive() const { return properties().isInactive(); }
193 bool isSeparator() const { return properties().isSeparator(); }
195 // Make a deep copy of Item.
197 return Item(value(), properties());
201 template <Const const_
>
202 struct ExtractProperties
204 typedef ExtractProperties type
;
206 typedef typename
std::conditional
<
207 const_
== Const::Yes
,
209 Properties
>::type Properties_
;
210 typedef typename
std::conditional
<
211 const_
== Const::Yes
,
215 Properties_
&operator()(Item_
&i
) const {
216 return i
.properties();
220 template <Const const_
>
223 typedef ExtractValue type
;
225 typedef typename
std::conditional
<
226 const_
== Const::Yes
,
229 typedef typename
std::conditional
<
230 const_
== Const::Yes
,
234 Value_
&operator()(Item_
&i
) const {
239 static Item
mkSeparator()
242 item
.setSelectable(false);
243 item
.setSeparator(true);
247 std::shared_ptr
<std::tuple
<ItemT
, Properties
>> m_impl
;
250 typedef typename
std::vector
<Item
>::iterator Iterator
;
251 typedef typename
std::vector
<Item
>::const_iterator ConstIterator
;
252 typedef std::reverse_iterator
<Iterator
> ReverseIterator
;
253 typedef std::reverse_iterator
<ConstIterator
> ConstReverseIterator
;
255 typedef boost::transform_iterator
<
256 typename
Item::template ExtractValue
<Const::No
>,
257 Iterator
> ValueIterator
;
258 typedef boost::transform_iterator
<
259 typename
Item::template ExtractValue
<Const::Yes
>,
260 ConstIterator
> ConstValueIterator
;
261 typedef std::reverse_iterator
<ValueIterator
> ReverseValueIterator
;
262 typedef std::reverse_iterator
<ConstValueIterator
> ConstReverseValueIterator
;
264 typedef boost::transform_iterator
<
265 typename
Item::template ExtractProperties
<Const::No
>,
266 Iterator
> PropertiesIterator
;
267 typedef boost::transform_iterator
<
268 typename
Item::template ExtractProperties
<Const::Yes
>,
269 ConstIterator
> ConstPropertiesIterator
;
271 /// Function helper prototype used to display each option on the screen.
272 /// If not set by setItemDisplayer(), menu won't display anything.
273 /// @see setItemDisplayer()
274 typedef std::function
<void(Menu
<ItemT
> &)> ItemDisplayer
;
276 typedef std::function
<bool(const Item
&)> FilterPredicate
;
280 Menu(size_t startx
, size_t starty
, size_t width
, size_t height
,
281 const std::string
&title
, Color color
, Border border
);
283 Menu(const Menu
&rhs
);
285 Menu
&operator=(Menu rhs
);
287 /// Sets helper function that is responsible for displaying items
288 /// @param ptr function pointer that matches the ItemDisplayer prototype
289 template <typename ItemDisplayerT
>
290 void setItemDisplayer(ItemDisplayerT
&&displayer
);
292 /// Resizes the list to given size (adequate to std::vector::resize())
293 /// @param size requested size
294 void resizeList(size_t new_size
);
296 /// Adds a new option to list
297 void addItem(ItemT item
, Properties::Type properties
= Properties::Selectable
);
299 /// Adds separator to list
302 /// Inserts a new option to the list at given position
303 void insertItem(size_t pos
, ItemT item
, Properties::Type properties
= Properties::Selectable
);
305 /// Inserts separator to list at given position
306 /// @param pos initial position of inserted separator
307 void insertSeparator(size_t pos
);
309 /// Moves the highlighted position to the given line of window
310 /// @param y Y position of menu window to be highlighted
311 /// @return true if the position is reachable, false otherwise
314 /// Checks if list is empty
315 /// @return true if list is empty, false otherwise
316 virtual bool empty() const override
{ return m_items
->empty(); }
318 /// @return size of the list
319 virtual size_t size() const override
{ return m_items
->size(); }
321 /// @return currently highlighted position
322 virtual size_t choice() const override
;
324 /// Highlights given position
325 /// @param pos position to be highlighted
326 virtual void highlight(size_t position
) override
;
328 /// Refreshes the menu window
329 /// @see Window::refresh()
330 virtual void refresh() override
;
332 /// Scrolls by given amount of lines
333 /// @param where indicated where exactly one wants to go
334 /// @see Window::scroll()
335 virtual void scroll(Scroll where
) override
;
337 /// Cleares all options, used filters etc. It doesn't reset highlighted position though.
339 virtual void clear() override
;
341 /// Sets highlighted position to 0
344 /// Apply filter predicate to items in the menu and show the ones for which it
346 template <typename PredicateT
>
347 void applyFilter(PredicateT
&&pred
);
349 /// Reapply previously applied filter.
350 void reapplyFilter();
352 /// Get current filter predicate.
353 template <typename TargetT
>
354 const TargetT
*filterPredicate() const;
356 /// Clear results of applyFilter and show all items.
359 /// @return true if menu is filtered.
360 bool isFiltered() const { return m_items
== &m_filtered_items
; }
363 void showAllItems() { m_items
= &m_all_items
; }
365 /// Show filtered items.
366 void showFilteredItems() { m_items
= &m_filtered_items
; }
368 /// Sets prefix, that is put before each selected item to indicate its selection
369 /// Note that the passed variable is not deleted along with menu object.
370 /// @param b pointer to buffer that contains the prefix
371 void setSelectedPrefix(const Buffer
&b
) { m_selected_prefix
= b
; }
373 /// Sets suffix, that is put after each selected item to indicate its selection
374 /// Note that the passed variable is not deleted along with menu object.
375 /// @param b pointer to buffer that contains the suffix
376 void setSelectedSuffix(const Buffer
&b
) { m_selected_suffix
= b
; }
378 /// Sets custom color of highlighted position
379 /// @param col custom color
380 void setHighlightColor(Color color
) { m_highlight_color
= std::move(color
); }
382 /// @return state of highlighting
383 bool isHighlighted() { return m_highlight_enabled
; }
385 /// Turns on/off highlighting
386 /// @param state state of hihglighting
387 void setHighlighting(bool state
) { m_highlight_enabled
= state
; }
389 /// Turns on/off cyclic scrolling
390 /// @param state state of cyclic scrolling
391 void cyclicScrolling(bool state
) { m_cyclic_scroll_enabled
= state
; }
393 /// Turns on/off centered cursor
394 /// @param state state of centered cursor
395 void centeredCursor(bool state
) { m_autocenter_cursor
= state
; }
397 /// @return currently drawn item. The result is defined only within
398 /// drawing function that is called by refresh()
400 ConstIterator
drawn() const { return begin() + m_drawn_position
; }
402 /// @param pos requested position
403 /// @return reference to item at given position
404 /// @throw std::out_of_range if given position is out of range
405 Menu
<ItemT
>::Item
&at(size_t pos
) { return m_items
->at(pos
); }
407 /// @param pos requested position
408 /// @return const reference to item at given position
409 /// @throw std::out_of_range if given position is out of range
410 const Menu
<ItemT
>::Item
&at(size_t pos
) const { return m_items
->at(pos
); }
412 /// @param pos requested position
413 /// @return const reference to item at given position
414 const Menu
<ItemT
>::Item
&operator[](size_t pos
) const { return (*m_items
)[pos
]; }
416 /// @param pos requested position
417 /// @return const reference to item at given position
418 Menu
<ItemT
>::Item
&operator[](size_t pos
) { return (*m_items
)[pos
]; }
420 Iterator
current() { return Iterator(m_items
->begin() + m_highlight
); }
421 ConstIterator
current() const { return ConstIterator(m_items
->begin() + m_highlight
); }
422 ReverseIterator
rcurrent() {
426 return ReverseIterator(++current());
428 ConstReverseIterator
rcurrent() const {
432 return ConstReverseIterator(++current());
435 ValueIterator
currentV() { return ValueIterator(m_items
->begin() + m_highlight
); }
436 ConstValueIterator
currentV() const { return ConstValueIterator(m_items
->begin() + m_highlight
); }
437 ReverseValueIterator
rcurrentV() {
441 return ReverseValueIterator(++currentV());
443 ConstReverseValueIterator
rcurrentV() const {
447 return ConstReverseValueIterator(++currentV());
450 Iterator
begin() { return Iterator(m_items
->begin()); }
451 ConstIterator
begin() const { return ConstIterator(m_items
->begin()); }
452 Iterator
end() { return Iterator(m_items
->end()); }
453 ConstIterator
end() const { return ConstIterator(m_items
->end()); }
455 ReverseIterator
rbegin() { return ReverseIterator(end()); }
456 ConstReverseIterator
rbegin() const { return ConstReverseIterator(end()); }
457 ReverseIterator
rend() { return ReverseIterator(begin()); }
458 ConstReverseIterator
rend() const { return ConstReverseIterator(begin()); }
460 ValueIterator
beginV() { return ValueIterator(begin()); }
461 ConstValueIterator
beginV() const { return ConstValueIterator(begin()); }
462 ValueIterator
endV() { return ValueIterator(end()); }
463 ConstValueIterator
endV() const { return ConstValueIterator(end()); }
465 ReverseValueIterator
rbeginV() { return ReverseValueIterator(endV()); }
466 ConstReverseIterator
rbeginV() const { return ConstReverseValueIterator(endV()); }
467 ReverseValueIterator
rendV() { return ReverseValueIterator(beginV()); }
468 ConstReverseValueIterator
rendV() const { return ConstReverseValueIterator(beginV()); }
470 virtual List::Iterator
currentP() override
{
471 return List::Iterator(PropertiesIterator(m_items
->begin() + m_highlight
));
473 virtual List::ConstIterator
currentP() const override
{
474 return List::ConstIterator(ConstPropertiesIterator(m_items
->begin() + m_highlight
));
476 virtual List::Iterator
beginP() override
{
477 return List::Iterator(PropertiesIterator(m_items
->begin()));
479 virtual List::ConstIterator
beginP() const override
{
480 return List::ConstIterator(ConstPropertiesIterator(m_items
->begin()));
482 virtual List::Iterator
endP() override
{
483 return List::Iterator(PropertiesIterator(m_items
->end()));
485 virtual List::ConstIterator
endP() const override
{
486 return List::ConstIterator(ConstPropertiesIterator(m_items
->end()));
490 bool isHighlightable(size_t pos
)
492 return !(*m_items
)[pos
].isSeparator()
493 && !(*m_items
)[pos
].isInactive();
496 ItemDisplayer m_item_displayer
;
497 FilterPredicate m_filter_predicate
;
499 std::vector
<Item
> *m_items
;
500 std::vector
<Item
> m_all_items
;
501 std::vector
<Item
> m_filtered_items
;
506 Color m_highlight_color
;
507 bool m_highlight_enabled
;
508 bool m_cyclic_scroll_enabled
;
510 bool m_autocenter_cursor
;
512 size_t m_drawn_position
;
514 Buffer m_selected_prefix
;
515 Buffer m_selected_suffix
;
520 #endif // NCMPCPP_MENU_H