visualizer: refresh screen immediately after clearing it
[ncmpcpp.git] / src / menu.h
blobecb2e7e18668fe050e02f587334ca570a8d5137c
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 /// Turns on/off centered cursor
445 /// @param state state of centered cursor
447 void CenteredCursor(bool state) { useCenteredCursor = state; }
449 /// Checks if list is empty
450 /// @return true if list is empty, false otherwise
452 virtual bool Empty() const { return itsOptionsPtr->empty(); }
454 /// @return size of the list
456 virtual size_t Size() const;
458 /// @return position of currently drawed item. The result is
459 /// defined only within drawing function that is called by Refresh()
460 /// @see Refresh()
462 size_t CurrentlyDrawedPosition() const { return itsCurrentlyDrawedPosition; }
464 /// @return reference to last item on the list
465 /// @throw List::InvalidItem if requested item is separator
467 T &Back();
469 /// @return const reference to last item on the list
470 /// @throw List::InvalidItem if requested item is separator
472 const T &Back() const;
474 /// @return reference to curently highlighted object
475 /// @throw List::InvalidItem if requested item is separator
477 T &Current();
479 /// @return const reference to curently highlighted object
480 /// @throw List::InvalidItem if requested item is separator
482 const T &Current() const;
484 /// @param pos requested position
485 /// @return reference to item at given position
486 /// @throw std::out_of_range if given position is out of range
487 /// @throw List::InvalidItem if requested item is separator
489 T &at(size_t pos);
491 /// @param pos requested position
492 /// @return const reference to item at given position
493 /// @throw std::out_of_range if given position is out of range
494 /// @throw List::InvalidItem if requested item is separator
496 const T &at(size_t pos) const;
498 /// @param pos requested position
499 /// @return const reference to item at given position
500 /// @throw List::InvalidItem if requested item is separator
502 const T &operator[](size_t pos) const;
504 /// @param pos requested position
505 /// @return const reference to item at given position
506 /// @throw List::InvalidItem if requested item is separator
508 T &operator[](size_t pos);
510 protected:
511 /// Clears filter, filtered data etc.
513 void ClearFiltered();
515 ItemDisplayer itsItemDisplayer;
516 void *itsItemDisplayerUserdata;
517 GetStringFunction itsGetStringFunction;
518 void *itsGetStringFunctionUserData;
520 std::string itsFilter;
521 std::string itsSearchConstraint;
523 std::vector<Option *> *itsOptionsPtr;
524 std::vector<Option *> itsOptions;
525 std::vector<Option *> itsFilteredOptions;
526 std::vector<size_t> itsFilteredRealPositions;
527 std::set<size_t> itsFound;
529 int itsBeginning;
530 int itsHighlight;
532 Color itsHighlightColor;
533 bool highlightEnabled;
534 bool useCyclicScrolling;
536 bool useCenteredCursor;
538 size_t itsCurrentlyDrawedPosition;
540 Buffer *itsSelectedPrefix;
541 Buffer *itsSelectedSuffix;
544 /// Specialization of Menu<T>::GetOption for T = std::string, it's obvious
545 /// that if strings are stored, we don't need extra function to convert
546 /// them to strings by default
547 template <> std::string Menu<std::string>::GetOption(size_t pos);
550 template <typename T> NCurses::Menu<T>::Menu(size_t startx,
551 size_t starty,
552 size_t width,
553 size_t height,
554 const std::string &title,
555 Color color,
556 Border border)
557 : Window(startx, starty, width, height, title, color, border),
558 itsItemDisplayer(0),
559 itsItemDisplayerUserdata(0),
560 itsGetStringFunction(0),
561 itsGetStringFunctionUserData(0),
562 itsOptionsPtr(&itsOptions),
563 itsBeginning(0),
564 itsHighlight(0),
565 itsHighlightColor(itsBaseColor),
566 highlightEnabled(1),
567 useCyclicScrolling(0),
568 useCenteredCursor(0),
569 itsSelectedPrefix(0),
570 itsSelectedSuffix(0)
574 template <typename T> NCurses::Menu<T>::Menu(const Menu &m) : Window(m),
575 itsItemDisplayer(m.itsItemDisplayer),
576 itsItemDisplayerUserdata(m.itsItemDisplayerUserdata),
577 itsGetStringFunction(m.itsGetStringFunction),
578 itsGetStringFunctionUserData(m.itsGetStringFunctionUserData),
579 itsOptionsPtr(m.itsOptionsPtr),
580 itsBeginning(m.itsBeginning),
581 itsHighlight(m.itsHighlight),
582 itsHighlightColor(m.itsHighlightColor),
583 highlightEnabled(m.highlightEnabled),
584 useCyclicScrolling(m.useCyclicScrolling),
585 useCenteredCursor(m.useCenteredCursor),
586 itsSelectedPrefix(m.itsSelectedPrefix),
587 itsSelectedSuffix(m.itsSelectedSuffix)
589 itsOptions.reserve(m.itsOptions.size());
590 for (option_const_iterator it = m.itsOptions.begin(); it != m.itsOptions.end(); ++it)
591 itsOptions.push_back(new Option(**it));
594 template <typename T> NCurses::Menu<T>::~Menu()
596 for (option_iterator it = itsOptions.begin(); it != itsOptions.end(); ++it)
597 delete *it;
600 template <typename T> void NCurses::Menu<T>::Reserve(size_t size)
602 itsOptions.reserve(size);
605 template <typename T> void NCurses::Menu<T>::ResizeList(size_t size)
607 if (size > itsOptions.size())
609 itsOptions.resize(size);
610 for (size_t i = 0; i < size; ++i)
611 if (!itsOptions[i])
612 itsOptions[i] = new Option();
614 else if (size < itsOptions.size())
616 for (size_t i = size; i < itsOptions.size(); ++i)
617 delete itsOptions[i];
618 itsOptions.resize(size);
622 template <typename T> void NCurses::Menu<T>::AddOption(const T &item, bool is_bold, bool is_static)
624 itsOptions.push_back(new Option(item, is_bold, is_static));
627 template <typename T> void NCurses::Menu<T>::AddSeparator()
629 itsOptions.push_back(static_cast<Option *>(0));
632 template <typename T> void NCurses::Menu<T>::InsertOption(size_t pos, const T &item, bool is_bold, bool is_static)
634 itsOptions.insert(itsOptions.begin()+pos, new Option(item, is_bold, is_static));
637 template <typename T> void NCurses::Menu<T>::InsertSeparator(size_t pos)
639 itsOptions.insert(itsOptions.begin()+pos, 0);
642 template <typename T> void NCurses::Menu<T>::DeleteOption(size_t pos)
644 if (itsOptionsPtr->empty())
645 return;
646 if (itsOptionsPtr == &itsFilteredOptions)
648 delete itsOptions.at(itsFilteredRealPositions[pos]);
649 itsOptions.erase(itsOptions.begin()+itsFilteredRealPositions[pos]);
650 itsFilteredOptions.erase(itsFilteredOptions.begin()+pos);
651 itsFilteredRealPositions.erase(itsFilteredRealPositions.begin()+pos);
652 for (size_t i = pos; i < itsFilteredRealPositions.size(); ++i)
653 itsFilteredRealPositions[i]--;
655 else
657 delete itsOptions.at(pos);
658 itsOptions.erase(itsOptions.begin()+pos);
660 itsFound.clear();
661 if (itsOptionsPtr->empty())
662 Window::Clear();
665 template <typename T> void NCurses::Menu<T>::IntoSeparator(size_t pos)
667 delete itsOptionsPtr->at(pos);
668 (*itsOptionsPtr)[pos] = 0;
671 template <typename T> void NCurses::Menu<T>::Bold(int pos, bool state)
673 if (!itsOptionsPtr->at(pos))
674 return;
675 (*itsOptionsPtr)[pos]->isBold = state;
678 template <typename T> void NCurses::Menu<T>::Swap(size_t one, size_t two)
680 std::swap(itsOptions.at(one), itsOptions.at(two));
683 template <typename T> void NCurses::Menu<T>::Move(size_t from, size_t to)
685 int diff = from-to;
686 if (diff > 0)
688 for (size_t i = from; i > to; --i)
689 std::swap(itsOptions.at(i), itsOptions.at(i-1));
691 else if (diff < 0)
693 for (size_t i = from; i < to; ++i)
694 std::swap(itsOptions.at(i), itsOptions.at(i+1));
698 template <typename T> bool NCurses::Menu<T>::Goto(size_t y)
700 if (!itsOptionsPtr->at(itsBeginning+y) || itsOptionsPtr->at(itsBeginning+y)->isStatic)
701 return false;
702 itsHighlight = itsBeginning+y;
703 return true;
706 template <typename T> void NCurses::Menu<T>::Refresh()
708 if (itsOptionsPtr->empty())
710 Window::Refresh();
711 return;
713 int MaxBeginning = itsOptionsPtr->size() < itsHeight ? 0 : itsOptionsPtr->size()-itsHeight;
715 if (itsBeginning < itsHighlight-int(itsHeight)+1) // highlighted position is off the screen
716 itsBeginning = itsHighlight-itsHeight+1;
718 if (itsBeginning < 0)
719 itsBeginning = 0;
720 else if (itsBeginning > MaxBeginning)
721 itsBeginning = MaxBeginning;
723 if (!itsOptionsPtr->empty() && itsHighlight > int(itsOptionsPtr->size())-1)
724 itsHighlight = itsOptionsPtr->size()-1;
726 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic) // it shouldn't be here
728 Scroll(wUp);
729 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
730 Scroll(wDown);
733 size_t line = 0;
734 for (size_t &i = (itsCurrentlyDrawedPosition = itsBeginning); i < itsBeginning+itsHeight; ++i)
736 GotoXY(0, line);
737 if (i >= itsOptionsPtr->size())
739 for (; line < itsHeight; ++line)
740 mvwhline(itsWindow, line, 0, 32, itsWidth);
741 break;
743 if (!(*itsOptionsPtr)[i]) // separator
745 mvwhline(itsWindow, line++, 0, 0, itsWidth);
746 continue;
748 if ((*itsOptionsPtr)[i]->isBold)
749 *this << fmtBold;
750 if (highlightEnabled && int(i) == itsHighlight)
752 *this << fmtReverse;
753 *this << itsHighlightColor;
755 mvwhline(itsWindow, line, 0, 32, itsWidth);
756 if ((*itsOptionsPtr)[i]->isSelected && itsSelectedPrefix)
757 *this << *itsSelectedPrefix;
758 if (itsItemDisplayer)
759 itsItemDisplayer((*itsOptionsPtr)[i]->Item, itsItemDisplayerUserdata, this);
760 if ((*itsOptionsPtr)[i]->isSelected && itsSelectedSuffix)
761 *this << *itsSelectedSuffix;
762 if (highlightEnabled && int(i) == itsHighlight)
764 *this << clEnd;
765 *this << fmtReverseEnd;
767 if ((*itsOptionsPtr)[i]->isBold)
768 *this << fmtBoldEnd;
769 line++;
771 Window::Refresh();
774 template <typename T> void NCurses::Menu<T>::Scroll(Where where)
776 if (itsOptionsPtr->empty())
777 return;
778 int MaxHighlight = itsOptionsPtr->size()-1;
779 int MaxBeginning = itsOptionsPtr->size() < itsHeight ? 0 : itsOptionsPtr->size()-itsHeight;
780 int MaxCurrentHighlight = itsBeginning+itsHeight-1;
781 switch (where)
783 case wUp:
785 if (itsHighlight <= itsBeginning && itsHighlight > 0)
787 itsBeginning--;
789 if (itsHighlight == 0)
791 if (useCyclicScrolling)
792 return Scroll(wEnd);
793 break;
795 else
797 itsHighlight--;
799 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
801 Scroll(itsHighlight == 0 && !useCyclicScrolling ? wDown : wUp);
803 break;
805 case wDown:
807 if (itsHighlight >= MaxCurrentHighlight && itsHighlight < MaxHighlight)
809 itsBeginning++;
811 if (itsHighlight == MaxHighlight)
813 if (useCyclicScrolling)
814 return Scroll(wHome);
815 break;
817 else
819 itsHighlight++;
821 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
823 Scroll(itsHighlight == MaxHighlight && !useCyclicScrolling ? wUp : wDown);
825 break;
827 case wPageUp:
829 if (useCyclicScrolling && itsHighlight == 0)
830 return Scroll(wEnd);
831 itsHighlight -= itsHeight;
832 itsBeginning -= itsHeight;
833 if (itsBeginning < 0)
835 itsBeginning = 0;
836 if (itsHighlight < 0)
837 itsHighlight = 0;
839 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
841 Scroll(itsHighlight == 0 && !useCyclicScrolling ? wDown : wUp);
843 break;
845 case wPageDown:
847 if (useCyclicScrolling && itsHighlight == MaxHighlight)
848 return Scroll(wHome);
849 itsHighlight += itsHeight;
850 itsBeginning += itsHeight;
851 if (itsBeginning > MaxBeginning)
853 itsBeginning = MaxBeginning;
854 if (itsHighlight > MaxHighlight)
855 itsHighlight = MaxHighlight;
857 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
859 Scroll(itsHighlight == MaxHighlight && !useCyclicScrolling ? wUp : wDown);
861 break;
863 case wHome:
865 itsHighlight = 0;
866 itsBeginning = 0;
867 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
869 Scroll(itsHighlight == 0 ? wDown : wUp);
871 break;
873 case wEnd:
875 itsHighlight = MaxHighlight;
876 itsBeginning = MaxBeginning;
877 if (!(*itsOptionsPtr)[itsHighlight] || (*itsOptionsPtr)[itsHighlight]->isStatic)
879 Scroll(itsHighlight == MaxHighlight ? wUp : wDown);
881 break;
884 if (useCenteredCursor)
885 Highlight(itsHighlight);
888 template <typename T> void NCurses::Menu<T>::Reset()
890 itsHighlight = 0;
891 itsBeginning = 0;
894 template <typename T> void NCurses::Menu<T>::ClearFiltered()
896 itsFilteredOptions.clear();
897 itsFilteredRealPositions.clear();
898 itsOptionsPtr = &itsOptions;
901 template <typename T> void NCurses::Menu<T>::Clear()
903 for (option_iterator it = itsOptions.begin(); it != itsOptions.end(); ++it)
904 delete *it;
905 itsOptions.clear();
906 itsFound.clear();
907 itsFilter.clear();
908 ClearFiltered();
909 itsOptionsPtr = &itsOptions;
910 Window::Clear();
913 template <typename T> bool NCurses::Menu<T>::isBold(int pos)
915 pos = pos == -1 ? itsHighlight : pos;
916 if (!itsOptionsPtr->at(pos))
917 return 0;
918 return (*itsOptionsPtr)[pos]->isBold;
921 template <typename T> void NCurses::Menu<T>::Select(int pos, bool state)
923 if (!itsOptionsPtr->at(pos))
924 return;
925 (*itsOptionsPtr)[pos]->isSelected = state;
928 template <typename T> void NCurses::Menu<T>::Static(int pos, bool state)
930 if (!itsOptionsPtr->at(pos))
931 return;
932 (*itsOptionsPtr)[pos]->isStatic = state;
935 template <typename T> bool NCurses::Menu<T>::isSelected(int pos) const
937 pos = pos == -1 ? itsHighlight : pos;
938 if (!itsOptionsPtr->at(pos))
939 return 0;
940 return (*itsOptionsPtr)[pos]->isSelected;
943 template <typename T> bool NCurses::Menu<T>::isStatic(int pos) const
945 pos = pos == -1 ? itsHighlight : pos;
946 if (!itsOptionsPtr->at(pos))
947 return 1;
948 return (*itsOptionsPtr)[pos]->isStatic;
951 template <typename T> bool NCurses::Menu<T>::hasSelected() const
953 for (option_const_iterator it = itsOptionsPtr->begin(); it != itsOptionsPtr->end(); ++it)
954 if (*it && (*it)->isSelected)
955 return true;
956 return false;
959 template <typename T> void NCurses::Menu<T>::GetSelected(std::vector<size_t> &v) const
961 for (size_t i = 0; i < itsOptionsPtr->size(); ++i)
962 if ((*itsOptionsPtr)[i] && (*itsOptionsPtr)[i]->isSelected)
963 v.push_back(i);
966 template <typename T> void NCurses::Menu<T>::Highlight(size_t pos)
968 itsHighlight = pos;
969 itsBeginning = pos-itsHeight/2;
972 template <typename T> size_t NCurses::Menu<T>::Size() const
974 return itsOptionsPtr->size();
977 template <typename T> size_t NCurses::Menu<T>::Choice() const
979 return itsHighlight;
982 template <typename T> size_t NCurses::Menu<T>::RealChoice() const
984 size_t result = 0;
985 for (option_const_iterator it = itsOptionsPtr->begin(); it != itsOptionsPtr->begin()+itsHighlight; ++it)
986 if (*it && !(*it)->isStatic)
987 result++;
988 return result;
991 template <typename T> void NCurses::Menu<T>::ReverseSelection(size_t beginning)
993 option_iterator it = itsOptionsPtr->begin()+beginning;
994 for (size_t i = beginning; i < Size(); ++i, ++it)
995 (*it)->isSelected = !(*it)->isSelected && !(*it)->isStatic;
998 template <typename T> bool NCurses::Menu<T>::Search(const std::string &constraint, size_t beginning, int flags)
1000 itsFound.clear();
1001 itsSearchConstraint.clear();
1002 if (constraint.empty())
1003 return false;
1004 itsSearchConstraint = constraint;
1005 regex_t rx;
1006 if (regcomp(&rx, itsSearchConstraint.c_str(), flags) == 0)
1008 for (size_t i = beginning; i < itsOptionsPtr->size(); ++i)
1010 if (regexec(&rx, GetOption(i).c_str(), 0, 0, 0) == 0)
1011 itsFound.insert(i);
1014 regfree(&rx);
1015 return !itsFound.empty();
1018 template <typename T> void NCurses::Menu<T>::NextFound(bool wrap)
1020 if (itsFound.empty())
1021 return;
1022 std::set<size_t>::iterator next = itsFound.upper_bound(itsHighlight);
1023 if (next != itsFound.end())
1024 Highlight(*next);
1025 else if (wrap)
1026 Highlight(*itsFound.begin());
1029 template <typename T> void NCurses::Menu<T>::PrevFound(bool wrap)
1031 if (itsFound.empty())
1032 return;
1033 std::set<size_t>::iterator prev = itsFound.lower_bound(itsHighlight);
1034 if (prev != itsFound.begin())
1035 Highlight(*--prev);
1036 else if (wrap)
1037 Highlight(*itsFound.rbegin());
1040 template <typename T> void NCurses::Menu<T>::ApplyFilter(const std::string &filter, size_t beginning, int flags)
1042 itsFound.clear();
1043 ClearFiltered();
1044 itsFilter = filter;
1045 if (itsFilter.empty())
1046 return;
1047 for (size_t i = 0; i < beginning; ++i)
1049 itsFilteredRealPositions.push_back(i);
1050 itsFilteredOptions.push_back(itsOptions[i]);
1052 regex_t rx;
1053 if (regcomp(&rx, itsFilter.c_str(), flags) == 0)
1055 for (size_t i = beginning; i < itsOptions.size(); ++i)
1057 if (regexec(&rx, GetOption(i).c_str(), 0, 0, 0) == 0)
1059 itsFilteredRealPositions.push_back(i);
1060 itsFilteredOptions.push_back(itsOptions[i]);
1064 regfree(&rx);
1065 itsOptionsPtr = &itsFilteredOptions;
1066 if (itsOptionsPtr->empty()) // oops, we didn't find anything
1067 Window::Clear();
1070 template <typename T> const std::string &NCurses::Menu<T>::GetFilter()
1072 return itsFilter;
1075 template <typename T> std::string NCurses::Menu<T>::GetOption(size_t pos)
1077 if (itsOptionsPtr->at(pos) && itsGetStringFunction)
1078 return itsGetStringFunction((*itsOptionsPtr)[pos]->Item, itsGetStringFunctionUserData);
1079 else
1080 return "";
1083 template <typename T> T &NCurses::Menu<T>::Back()
1085 if (!itsOptionsPtr->back())
1086 FatalError("Menu::Back() has requested separator!");
1087 return itsOptionsPtr->back()->Item;
1090 template <typename T> const T &NCurses::Menu<T>::Back() const
1092 if (!itsOptionsPtr->back())
1093 FatalError("Menu::Back() has requested separator!");
1094 return itsOptionsPtr->back()->Item;
1097 template <typename T> T &NCurses::Menu<T>::Current()
1099 if (!itsOptionsPtr->at(itsHighlight))
1100 FatalError("Menu::Current() has requested separator!");
1101 return (*itsOptionsPtr)[itsHighlight]->Item;
1104 template <typename T> const T &NCurses::Menu<T>::Current() const
1106 if (!itsOptionsPtr->at(itsHighlight))
1107 FatalError("Menu::Current() const has requested separator!");
1108 return (*itsOptionsPtr)[itsHighlight]->Item;
1111 template <typename T> T &NCurses::Menu<T>::at(size_t pos)
1113 if (!itsOptionsPtr->at(pos))
1114 FatalError("Menu::at() has requested separator!");
1115 return (*itsOptionsPtr)[pos]->Item;
1118 template <typename T> const T &NCurses::Menu<T>::at(size_t pos) const
1120 if (!itsOptions->at(pos))
1121 FatalError("Menu::at() const has requested separator!");
1122 return (*itsOptionsPtr)[pos]->Item;
1125 template <typename T> const T &NCurses::Menu<T>::operator[](size_t pos) const
1127 if (!(*itsOptionsPtr)[pos])
1128 FatalError("Menu::operator[] const has requested separator!");
1129 return (*itsOptionsPtr)[pos]->Item;
1132 template <typename T> T &NCurses::Menu<T>::operator[](size_t pos)
1134 if (!(*itsOptionsPtr)[pos])
1135 FatalError("Menu::operator[] has requested separator!");
1136 return (*itsOptionsPtr)[pos]->Item;
1139 #endif