discard custom colors of selected items also in classic display mode
[ncmpcpp.git] / src / menu.h
blob9fd45edf8b85d89bfa8de9852cd811efee6c22c9
1 /***************************************************************************
2 * Copyright (C) 2008-2010 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 _MENU_H
22 #define _MENU_H
24 #include <regex.h>
25 #include <algorithm>
26 #include <set>
28 #include "error.h"
29 #include "window.h"
30 #include "strbuffer.h"
32 namespace NCurses
34 /// List class is an interface for Menu class
35 ///
36 class List
38 public:
39 /// @see Menu::Select()
40 ///
41 virtual void Select(int pos, bool state) = 0;
43 /// @see Menu::isSelected()
44 ///
45 virtual bool isSelected(int pos = -1) const = 0;
47 /// @see Menu::hasSelected()
48 ///
49 virtual bool hasSelected() const = 0;
51 /// @see Menu::GetSelected()
52 ///
53 virtual void GetSelected(std::vector<size_t> &v) const = 0;
55 /// Highlights given position
56 /// @param pos position to be highlighted
57 ///
58 virtual void Highlight(size_t pos) = 0;
60 /// @return currently highlighted position
61 ///
62 virtual size_t Choice() const = 0;
64 /// @see Menu::Empty()
65 ///
66 virtual bool Empty() const = 0;
68 /// @see Menu::Size()
69 ///
70 virtual size_t Size() const = 0;
72 /// @see Menu::Search()
73 ///
74 virtual bool Search(const std::string &constraint, size_t beginning = 0, int flags = 0) = 0;
76 /// @see Menu::GetSearchConstraint()
77 ///
78 virtual const std::string &GetSearchConstraint() = 0;
80 /// @see Menu::NextFound()
81 ///
82 virtual void NextFound(bool wrap) = 0;
84 /// @see Menu::PrevFound()
85 ///
86 virtual void PrevFound(bool wrap) = 0;
88 /// @see Menu::ApplyFilter()
89 ///
90 virtual void ApplyFilter(const std::string &filter, size_t beginning = 0, int flags = 0) = 0;
92 /// @see Menu::GetFilter()
93 ///
94 virtual const std::string &GetFilter() = 0;
96 /// @see Menu::isFiltered()
97 ///
98 virtual bool isFiltered() = 0;
101 /// This template class is generic menu, that has holds
102 /// any values that are std::vector compatible.
104 template <typename T> class Menu : public Window, public List
106 /// Function helper prototype used to display each option on the screen.
107 /// If not set by SetItemDisplayer(), menu won't display anything.
108 /// @see SetItemDisplayer()
110 typedef void (*ItemDisplayer)(const T &, void *, Menu<T> *);
112 /// Function helper prototype used for converting items to strings.
113 /// If not set by SetGetStringFunction(), searching and filtering
114 /// won't work (note that Menu<std::string> doesn't need this)
115 /// @see SetGetStringFunction()
117 typedef std::string (*GetStringFunction)(const T &, void *);
119 /// Struct that holds each item in the list and its attributes
121 struct Option
123 Option() : isBold(0), isSelected(0), isStatic(0) { }
124 Option(const T &t, bool is_bold, bool is_static) :
125 Item(t), isBold(is_bold), isSelected(0), isStatic(is_static) { }
127 T Item;
128 bool isBold;
129 bool isSelected;
130 bool isStatic;
133 /// Functor that wraps around the functor passed to Sort()
134 /// to fit to internal container structure
136 template <typename Comparison> class InternalSorting
138 Comparison cmp;
140 public:
141 bool operator()(Option *a, Option *b)
143 return cmp(a->Item, b->Item);
147 typedef typename std::vector<Option *>::iterator option_iterator;
148 typedef typename std::vector<Option *>::const_iterator option_const_iterator;
150 public:
152 /// Constructs an empty menu with given parameters
153 /// @param startx X position of left upper corner of constructed menu
154 /// @param starty Y position of left upper corner of constructed menu
155 /// @param width width of constructed menu
156 /// @param height height of constructed menu
157 /// @param title title of constructed menu
158 /// @param color base color of constructed menu
159 /// @param border border of constructed menu
161 Menu(size_t startx, size_t starty, size_t width, size_t height,
162 const std::string &title, Color color, Border border);
164 /// Copies the menu
165 /// @param m copied menu
167 Menu(const Menu &m);
169 /// Destroys the object and frees memory
171 virtual ~Menu();
173 /// Sets helper function that is responsible for displaying items
174 /// @param ptr function pointer that matches the ItemDisplayer prototype
176 void SetItemDisplayer(ItemDisplayer ptr) { itsItemDisplayer = ptr; }
178 /// Sets optional user data, that is passed to
179 /// ItemDisplayer function each time it's invoked
180 /// @param data void pointer to userdata
182 void SetItemDisplayerUserData(void *data) { itsItemDisplayerUserdata = data; }
184 /// Sets helper function that is responsible for converting items to strings
185 /// @param f function pointer that matches the GetStringFunction prototype
187 void SetGetStringFunction(GetStringFunction f) { itsGetStringFunction = f; }
189 /// Sets optional user data, that is passed to
190 /// GetStringFunction function each time it's invoked
191 /// @param data void pointer to user data
193 void SetGetStringFunctionUserData(void *data) { itsGetStringFunctionUserData = data; }
195 /// Reserves the size for internal container (this just calls std::vector::reserve())
196 /// @param size requested size
198 void Reserve(size_t size);
200 /// Resizes the list to given size (adequate to std::vector::resize())
201 /// @param size requested size
203 void ResizeList(size_t size);
205 /// Adds new option to list
206 /// @param item object that has to be added
207 /// @param is_bold defines the initial state of bold attribute
208 /// @param is_static defines the initial state of static attribute
210 void AddOption(const T &item, bool is_bold = 0, bool is_static = 0);
212 /// Adds separator to list
214 void AddSeparator();
216 /// Inserts new option to list at given position
217 /// @param pos initial position of inserted item
218 /// @param item object that has to be inserted
219 /// @param is_bold defines the initial state of bold attribute
220 /// @param is_static defines the initial state of static attribute
222 void InsertOption(size_t pos, const T &Item, bool is_bold = 0, bool is_static = 0);
224 /// Inserts separator to list at given position
225 /// @param pos initial position of inserted separator
227 void InsertSeparator(size_t pos);
229 /// Deletes item from given position
230 /// @param pos given position of item to be deleted
232 void DeleteOption(size_t pos);
234 /// Converts the option into separator
235 /// @param pos position of item to be converted
237 void IntoSeparator(size_t pos);
239 /// Swaps the content of two items
240 /// @param one position of first item
241 /// @param two position of second item
243 void Swap(size_t one, size_t two);
245 /// Moves requested item from one position to another
246 /// @param from the position of item that has to be moved
247 /// @param to the position that indicates where the object has to be moved
249 void Move(size_t from, size_t to);
251 /// Moves the highlighted position to the given line of window
252 /// @param y Y position of menu window to be highlighted
253 /// @return true if the position is reachable, false otherwise
255 bool Goto(size_t y);
257 /// Checks if the given position has bold attribute set.
258 /// @param pos position to be checked. -1 = currently highlighted position
259 /// @return true if the bold is set, false otherwise
261 bool isBold(int pos = -1);
263 /// Sets bols attribute for given position
264 /// @param pos position of item to be bolded/unbolded
265 /// @param state state of bold attribute
267 void Bold(int pos, bool state);
269 /// Makes given position static/active.
270 /// Static positions cannot be highlighted.
271 /// @param pos position in list
272 /// @param state state of activity
274 void Static(int pos, bool state);
276 /// Checks whether given position is static or active
277 /// @param pos position to be checked, -1 checks currently highlighted position
278 /// @return true if position is static, false otherwise
280 bool isStatic(int pos = -1) const;
282 /// Selects/deselects given position
283 /// @param pos position in list
284 /// @param state state of selection
286 virtual void Select(int pos, bool state);
288 /// Checks if given position is selected
289 /// @param pos position to be checked, -1 checks currently highlighted position
290 /// @return true if position is selected, false otherwise
292 virtual bool isSelected(int pos = -1) const;
294 /// Checks whether list contains selected positions
295 /// @return true if it contains them, false otherwise
297 virtual bool hasSelected() const;
299 /// Gets positions of items that are selected
300 /// @param v vector to be filled with selected positions numbers
302 virtual void GetSelected(std::vector<size_t> &v) const;
304 /// Reverses selection of all items in list
305 /// @param beginning beginning of range that has to be reversed
307 void ReverseSelection(size_t beginning = 0);
309 /// Highlights given position
310 /// @param pos position to be highlighted
312 void Highlight(size_t pos);
314 /// @return currently highlighted position
316 size_t Choice() const;
318 /// @return real current positions, i.e it doesn't
319 /// count positions that are static or separators
321 size_t RealChoice() const;
323 /// Searches the list for a given contraint. It uses GetStringFunction to convert stored items
324 /// into strings and then performs pattern matching. Note that this supports regular expressions.
325 /// @param constraint a search constraint to be used
326 /// @param beginning beginning of range that has to be searched through
327 /// @param flags regex flags (REG_EXTENDED, REG_ICASE, REG_NOSUB, REG_NEWLINE)
328 /// @return true if at least one item matched the given pattern, false otherwise
330 virtual bool Search(const std::string &constraint, size_t beginning = 0, int flags = 0);
332 /// @return const reference to currently used search constraint
334 virtual const std::string &GetSearchConstraint() { return itsSearchConstraint; }
336 /// Moves current position in the list to the next found one
337 /// @param wrap if true, this function will go to the first
338 /// found pos after the last one, otherwise it'll do nothing.
340 virtual void NextFound(bool wrap);
342 /// Moves current position in the list to the previous found one
343 /// @param wrap if true, this function will go to the last
344 /// found pos after the first one, otherwise it'll do nothing.
346 virtual void PrevFound(bool wrap);
348 /// Filters the list, showing only the items that matches the pattern. It uses
349 /// GetStringFunction to convert stored items into strings and then performs
350 /// pattern matching. Note that this supports regular expressions.
351 /// @param filter a pattern to be used in pattern matching
352 /// @param beginning beginning of range that has to be filtered
353 /// @param flags regex flags (REG_EXTENDED, REG_ICASE, REG_NOSUB, REG_NEWLINE)
355 virtual void ApplyFilter(const std::string &filter, size_t beginning = 0, int flags = 0);
357 /// @return const reference to currently used filter
359 virtual const std::string &GetFilter();
361 /// @return true if list is currently filtered, false otherwise
363 virtual bool isFiltered() { return itsOptionsPtr == &itsFilteredOptions; }
365 /// Turns off filtering
367 void ShowAll() { itsOptionsPtr = &itsOptions; }
369 /// Turns on filtering
371 void ShowFiltered() { itsOptionsPtr = &itsFilteredOptions; }
373 /// Converts given position in list to string using GetStringFunction
374 /// if specified and an empty string otherwise
375 /// @param pos position to be converted
376 /// @return item converted to string
377 /// @see SetItemDisplayer()
379 std::string GetOption(size_t pos);
381 /// Refreshes the menu window
382 /// @see Window::Refresh()
384 virtual void Refresh();
386 /// Scrolls by given amount of lines
387 /// @param where indicated where exactly one wants to go
388 /// @see Window::Scroll()
390 virtual void Scroll(Where where);
392 /// Cleares all options, used filters etc. It doesn't reset highlighted position though.
393 /// @see Reset()
395 virtual void Clear();
397 /// Sets the highlighted position to 0
399 void Reset();
401 /// Sorts all items using Comparison object with defined operator()
402 /// @param beginning beginning of range that has to be sorted
404 template <typename Comparison> void Sort(size_t beginning = 0, size_t end = -1)
406 if (itsOptions.empty())
407 return;
408 sort(itsOptions.begin()+beginning, end == size_t(-1) ? itsOptions.end() : itsOptions.begin()+end, InternalSorting<Comparison>());
409 if (isFiltered())
410 ApplyFilter(itsFilter);
413 /// Sets prefix, that is put before each selected item to indicate its selection
414 /// Note that the passed variable is not deleted along with menu object.
415 /// @param b pointer to buffer that contains the prefix
417 void SetSelectPrefix(Buffer *b) { itsSelectedPrefix = b; }
419 /// Sets suffix, that is put after each selected item to indicate its selection
420 /// Note that the passed variable is not deleted along with menu object.
421 /// @param b pointer to buffer that contains the suffix
423 void SetSelectSuffix(Buffer *b) { itsSelectedSuffix = b; }
425 /// Sets custom color of highlighted position
426 /// @param col custom color
428 void HighlightColor(Color color) { itsHighlightColor = color; }
430 /// @return state of highlighting
432 bool isHighlighted() { return highlightEnabled; }
434 /// Turns on/off highlighting
435 /// @param state state of hihglighting
437 void Highlighting(bool state) { highlightEnabled = state; }
439 /// Turns on/off cyclic scrolling
440 /// @param state state of cyclic scrolling
442 void CyclicScrolling(bool state) { useCyclicScrolling = state; }
444 /// Checks if list is empty
445 /// @return true if list is empty, false otherwise
447 virtual bool Empty() const { return itsOptionsPtr->empty(); }
449 /// @return size of the list
451 virtual size_t Size() const;
453 /// @return position of currently drawed item. The result is
454 /// defined only within drawing function that is called by Refresh()
455 /// @see Refresh()
457 size_t CurrentlyDrawedPosition() const { return itsCurrentlyDrawedPosition; }
459 /// @return reference to last item on the list
460 /// @throw List::InvalidItem if requested item is separator
462 T &Back();
464 /// @return const reference to last item on the list
465 /// @throw List::InvalidItem if requested item is separator
467 const T &Back() const;
469 /// @return reference to curently highlighted object
470 /// @throw List::InvalidItem if requested item is separator
472 T &Current();
474 /// @return const reference to curently highlighted object
475 /// @throw List::InvalidItem if requested item is separator
477 const T &Current() const;
479 /// @param pos requested position
480 /// @return reference to item at given position
481 /// @throw std::out_of_range if given position is out of range
482 /// @throw List::InvalidItem if requested item is separator
484 T &at(size_t pos);
486 /// @param pos requested position
487 /// @return const reference to item at given position
488 /// @throw std::out_of_range if given position is out of range
489 /// @throw List::InvalidItem if requested item is separator
491 const T &at(size_t pos) const;
493 /// @param pos requested position
494 /// @return const reference to item at given position
495 /// @throw List::InvalidItem if requested item is separator
497 const T &operator[](size_t pos) const;
499 /// @param pos requested position
500 /// @return const reference to item at given position
501 /// @throw List::InvalidItem if requested item is separator
503 T &operator[](size_t pos);
505 protected:
506 /// Clears filter, filtered data etc.
508 void ClearFiltered();
510 ItemDisplayer itsItemDisplayer;
511 void *itsItemDisplayerUserdata;
512 GetStringFunction itsGetStringFunction;
513 void *itsGetStringFunctionUserData;
515 std::string itsFilter;
516 std::string itsSearchConstraint;
518 std::vector<Option *> *itsOptionsPtr;
519 std::vector<Option *> itsOptions;
520 std::vector<Option *> itsFilteredOptions;
521 std::vector<size_t> itsFilteredRealPositions;
522 std::set<size_t> itsFound;
524 int itsBeginning;
525 int itsHighlight;
527 Color itsHighlightColor;
528 bool highlightEnabled;
529 bool useCyclicScrolling;
531 size_t itsCurrentlyDrawedPosition;
533 Buffer *itsSelectedPrefix;
534 Buffer *itsSelectedSuffix;
537 /// Specialization of Menu<T>::GetOption for T = std::string, it's obvious
538 /// that if strings are stored, we don't need extra function to convert
539 /// them to strings by default
540 template <> std::string Menu<std::string>::GetOption(size_t pos);
543 template <typename T> NCurses::Menu<T>::Menu(size_t startx,
544 size_t starty,
545 size_t width,
546 size_t height,
547 const std::string &title,
548 Color color,
549 Border border)
550 : Window(startx, starty, width, height, title, color, border),
551 itsItemDisplayer(0),
552 itsItemDisplayerUserdata(0),
553 itsGetStringFunction(0),
554 itsGetStringFunctionUserData(0),
555 itsOptionsPtr(&itsOptions),
556 itsBeginning(0),
557 itsHighlight(0),
558 itsHighlightColor(itsBaseColor),
559 highlightEnabled(1),
560 useCyclicScrolling(0),
561 itsSelectedPrefix(0),
562 itsSelectedSuffix(0)
566 template <typename T> NCurses::Menu<T>::Menu(const Menu &m) : Window(m),
567 itsItemDisplayer(m.itsItemDisplayer),
568 itsItemDisplayerUserdata(m.itsItemDisplayerUserdata),
569 itsGetStringFunction(m.itsGetStringFunction),
570 itsGetStringFunctionUserData(m.itsGetStringFunctionUserData),
571 itsOptionsPtr(m.itsOptionsPtr),
572 itsBeginning(m.itsBeginning),
573 itsHighlight(m.itsHighlight),
574 itsHighlightColor(m.itsHighlightColor),
575 highlightEnabled(m.highlightEnabled),
576 itsSelectedPrefix(m.itsSelectedPrefix),
577 itsSelectedSuffix(m.itsSelectedSuffix)
579 itsOptions.reserve(m.itsOptions.size());
580 for (option_const_iterator it = m.itsOptions.begin(); it != m.itsOptions.end(); ++it)
581 itsOptions.push_back(new Option(**it));
584 template <typename T> NCurses::Menu<T>::~Menu()
586 for (option_iterator it = itsOptions.begin(); it != itsOptions.end(); ++it)
587 delete *it;
590 template <typename T> void NCurses::Menu<T>::Reserve(size_t size)
592 itsOptions.reserve(size);
595 template <typename T> void NCurses::Menu<T>::ResizeList(size_t size)
597 if (size > itsOptions.size())
599 itsOptions.resize(size);
600 for (size_t i = 0; i < size; ++i)
601 if (!itsOptions[i])
602 itsOptions[i] = new Option();
604 else if (size < itsOptions.size())
606 for (size_t i = size; i < itsOptions.size(); ++i)
607 delete itsOptions[i];
608 itsOptions.resize(size);
612 template <typename T> void NCurses::Menu<T>::AddOption(const T &item, bool is_bold, bool is_static)
614 itsOptions.push_back(new Option(item, is_bold, is_static));
617 template <typename T> void NCurses::Menu<T>::AddSeparator()
619 itsOptions.push_back(static_cast<Option *>(0));
622 template <typename T> void NCurses::Menu<T>::InsertOption(size_t pos, const T &item, bool is_bold, bool is_static)
624 itsOptions.insert(itsOptions.begin()+pos, new Option(item, is_bold, is_static));
627 template <typename T> void NCurses::Menu<T>::InsertSeparator(size_t pos)
629 itsOptions.insert(itsOptions.begin()+pos, 0);
632 template <typename T> void NCurses::Menu<T>::DeleteOption(size_t pos)
634 if (itsOptionsPtr->empty())
635 return;
636 if (itsOptionsPtr == &itsFilteredOptions)
638 delete itsOptions.at(itsFilteredRealPositions[pos]);
639 itsOptions.erase(itsOptions.begin()+itsFilteredRealPositions[pos]);
640 itsFilteredOptions.erase(itsFilteredOptions.begin()+pos);
641 itsFilteredRealPositions.erase(itsFilteredRealPositions.begin()+pos);
642 for (size_t i = pos; i < itsFilteredRealPositions.size(); ++i)
643 itsFilteredRealPositions[i]--;
645 else
647 delete itsOptions.at(pos);
648 itsOptions.erase(itsOptions.begin()+pos);
650 itsFound.clear();
651 if (itsOptionsPtr->empty())
652 Window::Clear();
655 template <typename T> void NCurses::Menu<T>::IntoSeparator(size_t pos)
657 delete itsOptionsPtr->at(pos);
658 (*itsOptionsPtr)[pos] = 0;
661 template <typename T> void NCurses::Menu<T>::Bold(int pos, bool state)
663 if (!itsOptionsPtr->at(pos))
664 return;
665 (*itsOptionsPtr)[pos]->isBold = state;
668 template <typename T> void NCurses::Menu<T>::Swap(size_t one, size_t two)
670 std::swap(itsOptions.at(one), itsOptions.at(two));
673 template <typename T> void NCurses::Menu<T>::Move(size_t from, size_t to)
675 int diff = from-to;
676 if (diff > 0)
678 for (size_t i = from; i > to; --i)
679 std::swap(itsOptions.at(i), itsOptions.at(i-1));
681 else if (diff < 0)
683 for (size_t i = from; i < to; ++i)
684 std::swap(itsOptions.at(i), itsOptions.at(i+1));
688 template <typename T> bool NCurses::Menu<T>::Goto(size_t y)
690 if (!itsOptionsPtr->at(itsBeginning+y) || itsOptionsPtr->at(itsBeginning+y)->isStatic)
691 return false;
692 itsHighlight = itsBeginning+y;
693 return true;
696 template <typename T> void NCurses::Menu<T>::Refresh()
698 if (itsOptionsPtr->empty())
700 Window::Refresh();
701 return;
703 int MaxBeginning = itsOptionsPtr->size() < itsHeight ? 0 : itsOptionsPtr->size()-itsHeight;
705 if (itsBeginning < itsHighlight-int(itsHeight)+1) // highlighted position is off the screen
706 itsBeginning = itsHighlight-itsHeight+1;
708 if (itsBeginning < 0)
709 itsBeginning = 0;
710 else if (itsBeginning > MaxBeginning)
711 itsBeginning = MaxBeginning;
713 if (!itsOptionsPtr->empty() && itsHighlight > int(itsOptionsPtr->size())-1)
714 itsHighlight = itsOptionsPtr->size()-1;
716 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic) // it shouldn't be here
718 Scroll(wUp);
719 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
720 Scroll(wDown);
723 size_t line = 0;
724 for (size_t &i = (itsCurrentlyDrawedPosition = itsBeginning); i < itsBeginning+itsHeight; ++i)
726 GotoXY(0, line);
727 if (i >= itsOptionsPtr->size())
729 for (; line < itsHeight; ++line)
730 mvwhline(itsWindow, line, 0, 32, itsWidth);
731 break;
733 if (!(*itsOptionsPtr)[i]) // separator
735 mvwhline(itsWindow, line++, 0, 0, itsWidth);
736 continue;
738 if ((*itsOptionsPtr)[i]->isBold)
739 *this << fmtBold;
740 if (highlightEnabled && int(i) == itsHighlight)
742 *this << fmtReverse;
743 *this << itsHighlightColor;
745 mvwhline(itsWindow, line, 0, 32, itsWidth);
746 if ((*itsOptionsPtr)[i]->isSelected && itsSelectedPrefix)
747 *this << *itsSelectedPrefix;
748 if (itsItemDisplayer)
749 itsItemDisplayer((*itsOptionsPtr)[i]->Item, itsItemDisplayerUserdata, this);
750 if ((*itsOptionsPtr)[i]->isSelected && itsSelectedSuffix)
751 *this << *itsSelectedSuffix;
752 if (highlightEnabled && int(i) == itsHighlight)
754 *this << clEnd;
755 *this << fmtReverseEnd;
757 if ((*itsOptionsPtr)[i]->isBold)
758 *this << fmtBoldEnd;
759 line++;
761 Window::Refresh();
764 template <typename T> void NCurses::Menu<T>::Scroll(Where where)
766 if (itsOptionsPtr->empty())
767 return;
768 int MaxHighlight = itsOptionsPtr->size()-1;
769 int MaxBeginning = itsOptionsPtr->size() < itsHeight ? 0 : itsOptionsPtr->size()-itsHeight;
770 int MaxCurrentHighlight = itsBeginning+itsHeight-1;
771 switch (where)
773 case wUp:
775 if (itsHighlight <= itsBeginning && itsHighlight > 0)
777 itsBeginning--;
779 if (itsHighlight == 0)
781 if (useCyclicScrolling)
782 return Scroll(wEnd);
783 break;
785 else
787 itsHighlight--;
789 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
791 Scroll(itsHighlight == 0 && !useCyclicScrolling ? wDown : wUp);
793 break;
795 case wDown:
797 if (itsHighlight >= MaxCurrentHighlight && itsHighlight < MaxHighlight)
799 itsBeginning++;
801 if (itsHighlight == MaxHighlight)
803 if (useCyclicScrolling)
804 return Scroll(wHome);
805 break;
807 else
809 itsHighlight++;
811 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
813 Scroll(itsHighlight == MaxHighlight && !useCyclicScrolling ? wUp : wDown);
815 break;
817 case wPageUp:
819 if (useCyclicScrolling && itsHighlight == 0)
820 return Scroll(wEnd);
821 itsHighlight -= itsHeight;
822 itsBeginning -= itsHeight;
823 if (itsBeginning < 0)
825 itsBeginning = 0;
826 if (itsHighlight < 0)
827 itsHighlight = 0;
829 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
831 Scroll(itsHighlight == 0 && !useCyclicScrolling ? wDown : wUp);
833 break;
835 case wPageDown:
837 if (useCyclicScrolling && itsHighlight == MaxHighlight)
838 return Scroll(wHome);
839 itsHighlight += itsHeight;
840 itsBeginning += itsHeight;
841 if (itsBeginning > MaxBeginning)
843 itsBeginning = MaxBeginning;
844 if (itsHighlight > MaxHighlight)
845 itsHighlight = MaxHighlight;
847 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
849 Scroll(itsHighlight == MaxHighlight && !useCyclicScrolling ? wUp : wDown);
851 break;
853 case wHome:
855 itsHighlight = 0;
856 itsBeginning = 0;
857 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
859 Scroll(itsHighlight == 0 ? wDown : wUp);
861 break;
863 case wEnd:
865 itsHighlight = MaxHighlight;
866 itsBeginning = MaxBeginning;
867 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
869 Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
871 break;
876 template <typename T> void NCurses::Menu<T>::Reset()
878 itsHighlight = 0;
879 itsBeginning = 0;
882 template <typename T> void NCurses::Menu<T>::ClearFiltered()
884 itsFilteredOptions.clear();
885 itsFilteredRealPositions.clear();
886 itsOptionsPtr = &itsOptions;
889 template <typename T> void NCurses::Menu<T>::Clear()
891 for (option_iterator it = itsOptions.begin(); it != itsOptions.end(); ++it)
892 delete *it;
893 itsOptions.clear();
894 itsFound.clear();
895 itsFilter.clear();
896 ClearFiltered();
897 itsOptionsPtr = &itsOptions;
898 Window::Clear();
901 template <typename T> bool NCurses::Menu<T>::isBold(int pos)
903 pos = pos == -1 ? itsHighlight : pos;
904 if (!itsOptionsPtr->at(pos))
905 return 0;
906 return (*itsOptionsPtr)[pos]->isBold;
909 template <typename T> void NCurses::Menu<T>::Select(int pos, bool state)
911 if (!itsOptionsPtr->at(pos))
912 return;
913 (*itsOptionsPtr)[pos]->isSelected = state;
916 template <typename T> void NCurses::Menu<T>::Static(int pos, bool state)
918 if (!itsOptionsPtr->at(pos))
919 return;
920 (*itsOptionsPtr)[pos]->isStatic = state;
923 template <typename T> bool NCurses::Menu<T>::isSelected(int pos) const
925 pos = pos == -1 ? itsHighlight : pos;
926 if (!itsOptionsPtr->at(pos))
927 return 0;
928 return (*itsOptionsPtr)[pos]->isSelected;
931 template <typename T> bool NCurses::Menu<T>::isStatic(int pos) const
933 pos = pos == -1 ? itsHighlight : pos;
934 if (!itsOptionsPtr->at(pos))
935 return 1;
936 return (*itsOptionsPtr)[pos]->isStatic;
939 template <typename T> bool NCurses::Menu<T>::hasSelected() const
941 for (option_const_iterator it = itsOptionsPtr->begin(); it != itsOptionsPtr->end(); ++it)
942 if (*it && (*it)->isSelected)
943 return true;
944 return false;
947 template <typename T> void NCurses::Menu<T>::GetSelected(std::vector<size_t> &v) const
949 for (size_t i = 0; i < itsOptionsPtr->size(); ++i)
950 if ((*itsOptionsPtr)[i] && (*itsOptionsPtr)[i]->isSelected)
951 v.push_back(i);
954 template <typename T> void NCurses::Menu<T>::Highlight(size_t pos)
956 itsHighlight = pos;
957 itsBeginning = pos-itsHeight/2;
960 template <typename T> size_t NCurses::Menu<T>::Size() const
962 return itsOptionsPtr->size();
965 template <typename T> size_t NCurses::Menu<T>::Choice() const
967 return itsHighlight;
970 template <typename T> size_t NCurses::Menu<T>::RealChoice() const
972 size_t result = 0;
973 for (option_const_iterator it = itsOptionsPtr->begin(); it != itsOptionsPtr->begin()+itsHighlight; ++it)
974 if (*it && !(*it)->isStatic)
975 result++;
976 return result;
979 template <typename T> void NCurses::Menu<T>::ReverseSelection(size_t beginning)
981 option_iterator it = itsOptionsPtr->begin()+beginning;
982 for (size_t i = beginning; i < Size(); ++i, ++it)
983 (*it)->isSelected = !(*it)->isSelected && !(*it)->isStatic;
986 template <typename T> bool NCurses::Menu<T>::Search(const std::string &constraint, size_t beginning, int flags)
988 itsFound.clear();
989 itsSearchConstraint.clear();
990 if (constraint.empty())
991 return false;
992 itsSearchConstraint = constraint;
993 regex_t rx;
994 if (regcomp(&rx, itsSearchConstraint.c_str(), flags) == 0)
996 for (size_t i = beginning; i < itsOptionsPtr->size(); ++i)
998 if (regexec(&rx, GetOption(i).c_str(), 0, 0, 0) == 0)
999 itsFound.insert(i);
1002 regfree(&rx);
1003 return !itsFound.empty();
1006 template <typename T> void NCurses::Menu<T>::NextFound(bool wrap)
1008 if (itsFound.empty())
1009 return;
1010 std::set<size_t>::iterator next = itsFound.upper_bound(itsHighlight);
1011 if (next != itsFound.end())
1012 Highlight(*next);
1013 else if (wrap)
1014 Highlight(*itsFound.begin());
1017 template <typename T> void NCurses::Menu<T>::PrevFound(bool wrap)
1019 if (itsFound.empty())
1020 return;
1021 std::set<size_t>::iterator prev = itsFound.lower_bound(itsHighlight);
1022 if (prev != itsFound.begin())
1023 Highlight(*--prev);
1024 else if (wrap)
1025 Highlight(*itsFound.rbegin());
1028 template <typename T> void NCurses::Menu<T>::ApplyFilter(const std::string &filter, size_t beginning, int flags)
1030 itsFound.clear();
1031 ClearFiltered();
1032 itsFilter = filter;
1033 if (itsFilter.empty())
1034 return;
1035 for (size_t i = 0; i < beginning; ++i)
1037 itsFilteredRealPositions.push_back(i);
1038 itsFilteredOptions.push_back(itsOptions[i]);
1040 regex_t rx;
1041 if (regcomp(&rx, itsFilter.c_str(), flags) == 0)
1043 for (size_t i = beginning; i < itsOptions.size(); ++i)
1045 if (regexec(&rx, GetOption(i).c_str(), 0, 0, 0) == 0)
1047 itsFilteredRealPositions.push_back(i);
1048 itsFilteredOptions.push_back(itsOptions[i]);
1052 regfree(&rx);
1053 itsOptionsPtr = &itsFilteredOptions;
1054 if (itsOptionsPtr->empty()) // oops, we didn't find anything
1055 Window::Clear();
1058 template <typename T> const std::string &NCurses::Menu<T>::GetFilter()
1060 return itsFilter;
1063 template <typename T> std::string NCurses::Menu<T>::GetOption(size_t pos)
1065 if (itsOptionsPtr->at(pos) && itsGetStringFunction)
1066 return itsGetStringFunction((*itsOptionsPtr)[pos]->Item, itsGetStringFunctionUserData);
1067 else
1068 return "";
1071 template <typename T> T &NCurses::Menu<T>::Back()
1073 if (!itsOptionsPtr->back())
1074 FatalError("Menu::Back() has requested separator!");
1075 return itsOptionsPtr->back()->Item;
1078 template <typename T> const T &NCurses::Menu<T>::Back() const
1080 if (!itsOptionsPtr->back())
1081 FatalError("Menu::Back() has requested separator!");
1082 return itsOptionsPtr->back()->Item;
1085 template <typename T> T &NCurses::Menu<T>::Current()
1087 if (!itsOptionsPtr->at(itsHighlight))
1088 FatalError("Menu::Current() has requested separator!");
1089 return (*itsOptionsPtr)[itsHighlight]->Item;
1092 template <typename T> const T &NCurses::Menu<T>::Current() const
1094 if (!itsOptionsPtr->at(itsHighlight))
1095 FatalError("Menu::Current() const has requested separator!");
1096 return (*itsOptionsPtr)[itsHighlight]->Item;
1099 template <typename T> T &NCurses::Menu<T>::at(size_t pos)
1101 if (!itsOptionsPtr->at(pos))
1102 FatalError("Menu::at() has requested separator!");
1103 return (*itsOptionsPtr)[pos]->Item;
1106 template <typename T> const T &NCurses::Menu<T>::at(size_t pos) const
1108 if (!itsOptions->at(pos))
1109 FatalError("Menu::at() const has requested separator!");
1110 return (*itsOptionsPtr)[pos]->Item;
1113 template <typename T> const T &NCurses::Menu<T>::operator[](size_t pos) const
1115 if (!(*itsOptionsPtr)[pos])
1116 FatalError("Menu::operator[] const has requested separator!");
1117 return (*itsOptionsPtr)[pos]->Item;
1120 template <typename T> T &NCurses::Menu<T>::operator[](size_t pos)
1122 if (!(*itsOptionsPtr)[pos])
1123 FatalError("Menu::operator[] has requested separator!");
1124 return (*itsOptionsPtr)[pos]->Item;
1127 #endif