Prepare for the ressurection of filtering
This commit is contained in:
@@ -381,6 +381,9 @@
|
||||
#def_key "ctrl-r"
|
||||
# reverse_playlist
|
||||
#
|
||||
#def_key "ctrl-f"
|
||||
# apply_filter
|
||||
#
|
||||
#def_key "ctrl-_"
|
||||
# select_found_items
|
||||
#
|
||||
|
||||
@@ -1934,6 +1934,14 @@ void ReversePlaylist::run()
|
||||
Statusbar::print("Range reversed");
|
||||
}
|
||||
|
||||
bool ApplyFilter::canBeRun()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApplyFilter::run()
|
||||
{ }
|
||||
|
||||
bool Find::canBeRun()
|
||||
{
|
||||
return myScreen == myHelp
|
||||
@@ -2724,6 +2732,7 @@ void populateActions()
|
||||
insert_action(new Actions::ClearPlaylist());
|
||||
insert_action(new Actions::SortPlaylist());
|
||||
insert_action(new Actions::ReversePlaylist());
|
||||
insert_action(new Actions::ApplyFilter());
|
||||
insert_action(new Actions::Find());
|
||||
insert_action(new Actions::FindItemForward());
|
||||
insert_action(new Actions::FindItemBackward());
|
||||
|
||||
@@ -122,6 +122,7 @@ enum class Type
|
||||
ClearPlaylist,
|
||||
SortPlaylist,
|
||||
ReversePlaylist,
|
||||
ApplyFilter,
|
||||
Find,
|
||||
FindItemForward,
|
||||
FindItemBackward,
|
||||
@@ -1036,6 +1037,15 @@ private:
|
||||
NC::Menu<MPD::Song>::ConstIterator m_end;
|
||||
};
|
||||
|
||||
struct ApplyFilter: public BaseAction
|
||||
{
|
||||
ApplyFilter(): BaseAction(Type::ApplyFilter, "apply_filter") { }
|
||||
|
||||
private:
|
||||
virtual bool canBeRun() OVERRIDE;
|
||||
virtual void run() OVERRIDE;
|
||||
};
|
||||
|
||||
struct Find: BaseAction
|
||||
{
|
||||
Find(): BaseAction(Type::Find, "find") { }
|
||||
|
||||
@@ -625,6 +625,8 @@ void BindingsConfiguration::generateDefaults()
|
||||
}
|
||||
if (notBound(k = stringToKey("ctrl-r")))
|
||||
bind(k, Actions::Type::ReversePlaylist);
|
||||
if (notBound(k = stringToKey("ctrl-f")))
|
||||
bind(k, Actions::Type::ApplyFilter);
|
||||
if (notBound(k = stringToKey("ctrl-_")))
|
||||
bind(k, Actions::Type::SelectFoundItems);
|
||||
if (notBound(k = stringToKey("/")))
|
||||
|
||||
@@ -210,6 +210,7 @@ void write_bindings(NC::Scrollpad &w)
|
||||
key(w, Type::UpdateDatabase, "Start music database update");
|
||||
w << '\n';
|
||||
key(w, Type::ExecuteCommand, "Execute command");
|
||||
key(w, Type::ApplyFilter, "Apply filter");
|
||||
key(w, Type::FindItemForward, "Find item forward");
|
||||
key(w, Type::FindItemBackward, "Find item backward");
|
||||
key(w, Type::PreviousFoundItem, "Jump to previous found item");
|
||||
|
||||
103
src/menu.h
103
src/menu.h
@@ -96,6 +96,9 @@ struct List
|
||||
bool isInactive() const { return m_properties & Inactive; }
|
||||
bool isSeparator() const { return m_properties & Separator; }
|
||||
|
||||
protected:
|
||||
unsigned properties() const { return m_properties; }
|
||||
|
||||
private:
|
||||
unsigned m_properties;
|
||||
};
|
||||
@@ -174,17 +177,26 @@ template <typename ItemT> struct Menu : Window, List
|
||||
|
||||
friend struct Menu<ItemT>;
|
||||
|
||||
Item() { }
|
||||
Item(ItemT value_, Properties::Type properties)
|
||||
Item()
|
||||
: m_value(std::make_shared<ItemT>(ItemT()))
|
||||
{ }
|
||||
|
||||
template <typename ValueT>
|
||||
Item(ValueT &&value_, Properties::Type properties)
|
||||
: Properties(properties)
|
||||
, m_value(value_)
|
||||
, m_value(std::make_shared<ItemT>(std::forward<ValueT>(value_)))
|
||||
{ }
|
||||
|
||||
ItemT &value() { return m_value; }
|
||||
const ItemT &value() const { return m_value; }
|
||||
ItemT &value() { return *m_value; }
|
||||
const ItemT &value() const { return *m_value; }
|
||||
|
||||
ItemT &operator*() { return m_value; }
|
||||
const ItemT &operator*() const { return m_value; }
|
||||
ItemT &operator*() { return *m_value; }
|
||||
const ItemT &operator*() const { return *m_value; }
|
||||
|
||||
// Make a deep copy of Item.
|
||||
Item copy() const {
|
||||
return Item(*m_value, static_cast<Properties::Type>(properties()));
|
||||
}
|
||||
|
||||
private:
|
||||
static Item mkSeparator()
|
||||
@@ -195,9 +207,9 @@ template <typename ItemT> struct Menu : Window, List
|
||||
return item;
|
||||
}
|
||||
|
||||
ItemT m_value;
|
||||
std::shared_ptr<ItemT> m_value;
|
||||
};
|
||||
|
||||
|
||||
typedef typename std::vector<Item>::iterator Iterator;
|
||||
typedef typename std::vector<Item>::const_iterator ConstIterator;
|
||||
typedef std::reverse_iterator<Iterator> ReverseIterator;
|
||||
@@ -230,7 +242,7 @@ template <typename ItemT> struct Menu : Window, List
|
||||
/// @see setItemDisplayer()
|
||||
typedef std::function<void(Menu<ItemT> &)> ItemDisplayer;
|
||||
|
||||
Menu() { }
|
||||
Menu();
|
||||
|
||||
Menu(size_t startx, size_t starty, size_t width, size_t height,
|
||||
const std::string &title, Color color, Border border);
|
||||
@@ -260,10 +272,6 @@ template <typename ItemT> struct Menu : Window, List
|
||||
/// @param pos initial position of inserted separator
|
||||
void insertSeparator(size_t pos);
|
||||
|
||||
/// Deletes item from given position
|
||||
/// @param pos given position of item to be deleted
|
||||
void deleteItem(size_t pos);
|
||||
|
||||
/// Moves the highlighted position to the given line of window
|
||||
/// @param y Y position of menu window to be highlighted
|
||||
/// @return true if the position is reachable, false otherwise
|
||||
@@ -271,10 +279,10 @@ template <typename ItemT> struct Menu : Window, List
|
||||
|
||||
/// Checks if list is empty
|
||||
/// @return true if list is empty, false otherwise
|
||||
virtual bool empty() const OVERRIDE { return m_items.empty(); }
|
||||
virtual bool empty() const OVERRIDE { return m_items->empty(); }
|
||||
|
||||
/// @return size of the list
|
||||
virtual size_t size() const OVERRIDE { return m_items.size(); }
|
||||
virtual size_t size() const OVERRIDE { return m_items->size(); }
|
||||
|
||||
/// @return currently highlighted position
|
||||
virtual size_t choice() const OVERRIDE;
|
||||
@@ -298,7 +306,24 @@ template <typename ItemT> struct Menu : Window, List
|
||||
|
||||
/// Sets highlighted position to 0
|
||||
void reset();
|
||||
|
||||
|
||||
/// Apply filter predicate to items in the menu and show the ones for which it
|
||||
/// returned true.
|
||||
template <typename FilterPredicate>
|
||||
bool applyFilter(FilterPredicate &&p);
|
||||
|
||||
/// Clear results of applyFilter and show all items.
|
||||
void clearFilter();
|
||||
|
||||
/// @return true if menu is filtered.
|
||||
bool isFiltered() const { return m_items == &m_filtered_items; }
|
||||
|
||||
/// Show all items.
|
||||
void showAllItems() { m_items = &m_all_items; }
|
||||
|
||||
/// Show filtered items.
|
||||
void showFilteredItems() { m_items = &m_filtered_items; }
|
||||
|
||||
/// Sets prefix, that is put before each selected item to indicate its selection
|
||||
/// Note that the passed variable is not deleted along with menu object.
|
||||
/// @param b pointer to buffer that contains the prefix
|
||||
@@ -336,23 +361,23 @@ template <typename ItemT> struct Menu : Window, List
|
||||
/// @param pos requested position
|
||||
/// @return reference to item at given position
|
||||
/// @throw std::out_of_range if given position is out of range
|
||||
Menu<ItemT>::Item &at(size_t pos) { return m_items.at(pos); }
|
||||
Menu<ItemT>::Item &at(size_t pos) { return m_items->at(pos); }
|
||||
|
||||
/// @param pos requested position
|
||||
/// @return const reference to item at given position
|
||||
/// @throw std::out_of_range if given position is out of range
|
||||
const Menu<ItemT>::Item &at(size_t pos) const { return m_items.at(pos); }
|
||||
const Menu<ItemT>::Item &at(size_t pos) const { return m_items->at(pos); }
|
||||
|
||||
/// @param pos requested position
|
||||
/// @return const reference to item at given position
|
||||
const Menu<ItemT>::Item &operator[](size_t pos) const { return m_items[pos]; }
|
||||
const Menu<ItemT>::Item &operator[](size_t pos) const { return (*m_items)[pos]; }
|
||||
|
||||
/// @param pos requested position
|
||||
/// @return const reference to item at given position
|
||||
Menu<ItemT>::Item &operator[](size_t pos) { return m_items[pos]; }
|
||||
Menu<ItemT>::Item &operator[](size_t pos) { return (*m_items)[pos]; }
|
||||
|
||||
Iterator current() { return Iterator(m_items.begin() + m_highlight); }
|
||||
ConstIterator current() const { return ConstIterator(m_items.begin() + m_highlight); }
|
||||
Iterator current() { return Iterator(m_items->begin() + m_highlight); }
|
||||
ConstIterator current() const { return ConstIterator(m_items->begin() + m_highlight); }
|
||||
ReverseIterator rcurrent() {
|
||||
if (empty())
|
||||
return rend();
|
||||
@@ -366,8 +391,8 @@ template <typename ItemT> struct Menu : Window, List
|
||||
return ConstReverseIterator(++current());
|
||||
}
|
||||
|
||||
ValueIterator currentV() { return ValueIterator(m_items.begin() + m_highlight); }
|
||||
ConstValueIterator currentV() const { return ConstValueIterator(m_items.begin() + m_highlight); }
|
||||
ValueIterator currentV() { return ValueIterator(m_items->begin() + m_highlight); }
|
||||
ConstValueIterator currentV() const { return ConstValueIterator(m_items->begin() + m_highlight); }
|
||||
ReverseValueIterator rcurrentV() {
|
||||
if (empty())
|
||||
return rendV();
|
||||
@@ -381,10 +406,10 @@ template <typename ItemT> struct Menu : Window, List
|
||||
return ConstReverseValueIterator(++currentV());
|
||||
}
|
||||
|
||||
Iterator begin() { return Iterator(m_items.begin()); }
|
||||
ConstIterator begin() const { return ConstIterator(m_items.begin()); }
|
||||
Iterator end() { return Iterator(m_items.end()); }
|
||||
ConstIterator end() const { return ConstIterator(m_items.end()); }
|
||||
Iterator begin() { return Iterator(m_items->begin()); }
|
||||
ConstIterator begin() const { return ConstIterator(m_items->begin()); }
|
||||
Iterator end() { return Iterator(m_items->end()); }
|
||||
ConstIterator end() const { return ConstIterator(m_items->end()); }
|
||||
|
||||
ReverseIterator rbegin() { return ReverseIterator(end()); }
|
||||
ConstReverseIterator rbegin() const { return ConstReverseIterator(end()); }
|
||||
@@ -402,34 +427,36 @@ template <typename ItemT> struct Menu : Window, List
|
||||
ConstReverseValueIterator rendV() const { return ConstReverseValueIterator(beginV()); }
|
||||
|
||||
virtual List::Iterator currentP() OVERRIDE {
|
||||
return List::Iterator(PropertiesIterator(m_items.begin() + m_highlight));
|
||||
return List::Iterator(PropertiesIterator(m_items->begin() + m_highlight));
|
||||
}
|
||||
virtual List::ConstIterator currentP() const OVERRIDE {
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items.begin() + m_highlight));
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items->begin() + m_highlight));
|
||||
}
|
||||
virtual List::Iterator beginP() OVERRIDE {
|
||||
return List::Iterator(PropertiesIterator(m_items.begin()));
|
||||
return List::Iterator(PropertiesIterator(m_items->begin()));
|
||||
}
|
||||
virtual List::ConstIterator beginP() const OVERRIDE {
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items.begin()));
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items->begin()));
|
||||
}
|
||||
virtual List::Iterator endP() OVERRIDE {
|
||||
return List::Iterator(PropertiesIterator(m_items.end()));
|
||||
return List::Iterator(PropertiesIterator(m_items->end()));
|
||||
}
|
||||
virtual List::ConstIterator endP() const OVERRIDE {
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items.end()));
|
||||
return List::ConstIterator(ConstPropertiesIterator(m_items->end()));
|
||||
}
|
||||
|
||||
private:
|
||||
bool isHighlightable(size_t pos)
|
||||
{
|
||||
return !m_items[pos].isSeparator()
|
||||
&& !m_items[pos].isInactive();
|
||||
return !(*m_items)[pos].isSeparator()
|
||||
&& !(*m_items)[pos].isInactive();
|
||||
}
|
||||
|
||||
ItemDisplayer m_item_displayer;
|
||||
|
||||
std::vector<Item> m_items;
|
||||
std::vector<Item> *m_items;
|
||||
std::vector<Item> m_all_items;
|
||||
std::vector<Item> m_filtered_items;
|
||||
|
||||
size_t m_beginning;
|
||||
size_t m_highlight;
|
||||
|
||||
181
src/menu_impl.h
181
src/menu_impl.h
@@ -26,59 +26,72 @@
|
||||
namespace NC {
|
||||
|
||||
template <typename ItemT>
|
||||
Menu<ItemT>::Menu(size_t startx,
|
||||
size_t starty,
|
||||
size_t width,
|
||||
size_t height,
|
||||
const std::string &title,
|
||||
Color color,
|
||||
Border border)
|
||||
: Window(startx, starty, width, height, title, std::move(color), border),
|
||||
m_item_displayer(0),
|
||||
m_beginning(0),
|
||||
m_highlight(0),
|
||||
m_highlight_color(m_base_color),
|
||||
m_highlight_enabled(true),
|
||||
m_cyclic_scroll_enabled(false),
|
||||
m_autocenter_cursor(false)
|
||||
Menu<ItemT>::Menu()
|
||||
{
|
||||
m_items = &m_all_items;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
Menu<ItemT>::Menu(size_t startx,
|
||||
size_t starty,
|
||||
size_t width,
|
||||
size_t height,
|
||||
const std::string &title,
|
||||
Color color,
|
||||
Border border)
|
||||
: Window(startx, starty, width, height, title, std::move(color), border)
|
||||
, m_item_displayer(0)
|
||||
, m_beginning(0)
|
||||
, m_highlight(0)
|
||||
, m_highlight_color(m_base_color)
|
||||
, m_highlight_enabled(true)
|
||||
, m_cyclic_scroll_enabled(false)
|
||||
, m_autocenter_cursor(false)
|
||||
{
|
||||
m_items = &m_all_items;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
Menu<ItemT>::Menu(const Menu &rhs)
|
||||
: Window(rhs)
|
||||
, m_item_displayer(rhs.m_item_displayer)
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
, m_highlight_enabled(rhs.m_highlight_enabled)
|
||||
, m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
|
||||
, m_autocenter_cursor(rhs.m_autocenter_cursor)
|
||||
, m_drawn_position(rhs.m_drawn_position)
|
||||
, m_selected_prefix(rhs.m_selected_prefix)
|
||||
, m_selected_suffix(rhs.m_selected_suffix)
|
||||
: Window(rhs)
|
||||
, m_item_displayer(rhs.m_item_displayer)
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
, m_highlight_enabled(rhs.m_highlight_enabled)
|
||||
, m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
|
||||
, m_autocenter_cursor(rhs.m_autocenter_cursor)
|
||||
, m_drawn_position(rhs.m_drawn_position)
|
||||
, m_selected_prefix(rhs.m_selected_prefix)
|
||||
, m_selected_suffix(rhs.m_selected_suffix)
|
||||
{
|
||||
// there is no way to properly fill m_filtered_options
|
||||
// (if rhs is filtered), so we just don't do it.
|
||||
m_items.reserve(rhs.m_items.size());
|
||||
std::copy(rhs.begin(), rhs.end(), std::back_inserter(m_items));
|
||||
// TODO: move filtered items
|
||||
m_all_items.reserve(rhs.m_all_items.size());
|
||||
for (const auto &item : rhs.m_all_items)
|
||||
m_all_items.push_back(item.copy());
|
||||
m_items = &m_all_items;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
Menu<ItemT>::Menu(Menu &&rhs)
|
||||
: Window(rhs)
|
||||
, m_item_displayer(rhs.m_item_displayer)
|
||||
, m_items(std::move(rhs.m_items))
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
, m_highlight_enabled(rhs.m_highlight_enabled)
|
||||
, m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
|
||||
, m_autocenter_cursor(rhs.m_autocenter_cursor)
|
||||
, m_drawn_position(rhs.m_drawn_position)
|
||||
, m_selected_prefix(std::move(rhs.m_selected_prefix))
|
||||
, m_selected_suffix(std::move(rhs.m_selected_suffix))
|
||||
: Window(rhs)
|
||||
, m_item_displayer(rhs.m_item_displayer)
|
||||
, m_all_items(std::move(rhs.m_all_items))
|
||||
, m_filtered_items(std::move(rhs.m_filtered_items))
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
, m_highlight_enabled(rhs.m_highlight_enabled)
|
||||
, m_cyclic_scroll_enabled(rhs.m_cyclic_scroll_enabled)
|
||||
, m_autocenter_cursor(rhs.m_autocenter_cursor)
|
||||
, m_drawn_position(rhs.m_drawn_position)
|
||||
, m_selected_prefix(std::move(rhs.m_selected_prefix))
|
||||
, m_selected_suffix(std::move(rhs.m_selected_suffix))
|
||||
{
|
||||
if (rhs.m_items == &rhs.m_all_items)
|
||||
m_items = &m_all_items;
|
||||
else
|
||||
m_items = &m_filtered_items;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
@@ -86,7 +99,8 @@ Menu<ItemT> &Menu<ItemT>::operator=(Menu rhs)
|
||||
{
|
||||
std::swap(static_cast<Window &>(*this), static_cast<Window &>(rhs));
|
||||
std::swap(m_item_displayer, rhs.m_item_displayer);
|
||||
std::swap(m_items, rhs.m_items);
|
||||
std::swap(m_all_items, rhs.m_all_items);
|
||||
std::swap(m_filtered_items, rhs.m_filtered_items);
|
||||
std::swap(m_beginning, rhs.m_beginning);
|
||||
std::swap(m_highlight, rhs.m_highlight);
|
||||
std::swap(m_highlight_color, rhs.m_highlight_color);
|
||||
@@ -96,52 +110,41 @@ Menu<ItemT> &Menu<ItemT>::operator=(Menu rhs)
|
||||
std::swap(m_drawn_position, rhs.m_drawn_position);
|
||||
std::swap(m_selected_prefix, rhs.m_selected_prefix);
|
||||
std::swap(m_selected_suffix, rhs.m_selected_suffix);
|
||||
if (rhs.m_items == &rhs.m_all_items)
|
||||
m_items = &m_all_items;
|
||||
else
|
||||
m_items = &m_filtered_items;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::resizeList(size_t new_size)
|
||||
{
|
||||
if (new_size > m_items.size())
|
||||
{
|
||||
size_t old_size = m_items.size();
|
||||
m_items.resize(new_size);
|
||||
for (size_t i = old_size; i < new_size; ++i)
|
||||
m_items[i] = Item();
|
||||
}
|
||||
else
|
||||
m_items.resize(new_size);
|
||||
m_all_items.resize(new_size);
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::addItem(ItemT item, Properties::Type properties)
|
||||
{
|
||||
m_items.push_back(Item(std::move(item), properties));
|
||||
m_all_items.push_back(Item(std::move(item), properties));
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::addSeparator()
|
||||
{
|
||||
m_items.push_back(Item::mkSeparator());
|
||||
m_all_items.push_back(Item::mkSeparator());
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::insertItem(size_t pos, ItemT item, Properties::Type properties)
|
||||
{
|
||||
m_items.insert(m_items.begin()+pos, Item(std::move(item), properties));
|
||||
m_all_items.insert(m_all_items.begin()+pos, Item(std::move(item), properties));
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::insertSeparator(size_t pos)
|
||||
{
|
||||
m_items.insert(m_items.begin()+pos, Item::mkSeparator());
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::deleteItem(size_t pos)
|
||||
{
|
||||
assert(pos < m_items.size());
|
||||
m_items.erase(m_items.begin()+pos);
|
||||
m_all_items.insert(m_all_items.begin()+pos, Item::mkSeparator());
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
@@ -156,7 +159,7 @@ bool Menu<ItemT>::Goto(size_t y)
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::refresh()
|
||||
{
|
||||
if (m_items.empty())
|
||||
if (m_items->empty())
|
||||
{
|
||||
Window::clear();
|
||||
Window::refresh();
|
||||
@@ -164,14 +167,14 @@ void Menu<ItemT>::refresh()
|
||||
}
|
||||
|
||||
size_t max_beginning = 0;
|
||||
if (m_items.size() > m_height)
|
||||
max_beginning = m_items.size() - m_height;
|
||||
if (m_items->size() > m_height)
|
||||
max_beginning = m_items->size() - m_height;
|
||||
m_beginning = std::min(m_beginning, max_beginning);
|
||||
|
||||
// if highlighted position is off the screen, make it visible
|
||||
m_highlight = std::min(m_highlight, m_beginning+m_height-1);
|
||||
// if highlighted position is invalid, correct it
|
||||
m_highlight = std::min(m_highlight, m_items.size()-1);
|
||||
m_highlight = std::min(m_highlight, m_items->size()-1);
|
||||
|
||||
if (!isHighlightable(m_highlight))
|
||||
{
|
||||
@@ -186,18 +189,18 @@ void Menu<ItemT>::refresh()
|
||||
for (; m_drawn_position < end_; ++m_drawn_position, ++line)
|
||||
{
|
||||
goToXY(0, line);
|
||||
if (m_drawn_position >= m_items.size())
|
||||
if (m_drawn_position >= m_items->size())
|
||||
{
|
||||
for (; line < m_height; ++line)
|
||||
mvwhline(m_window, line, 0, NC::Key::Space, m_width);
|
||||
break;
|
||||
}
|
||||
if (m_items[m_drawn_position].isSeparator())
|
||||
if ((*m_items)[m_drawn_position].isSeparator())
|
||||
{
|
||||
mvwhline(m_window, line, 0, 0, m_width);
|
||||
continue;
|
||||
}
|
||||
if (m_items[m_drawn_position].isBold())
|
||||
if ((*m_items)[m_drawn_position].isBold())
|
||||
*this << Format::Bold;
|
||||
if (m_highlight_enabled && m_drawn_position == m_highlight)
|
||||
{
|
||||
@@ -205,18 +208,18 @@ void Menu<ItemT>::refresh()
|
||||
*this << m_highlight_color;
|
||||
}
|
||||
mvwhline(m_window, line, 0, NC::Key::Space, m_width);
|
||||
if (m_items[m_drawn_position].isSelected())
|
||||
if ((*m_items)[m_drawn_position].isSelected())
|
||||
*this << m_selected_prefix;
|
||||
if (m_item_displayer)
|
||||
m_item_displayer(*this);
|
||||
if (m_items[m_drawn_position].isSelected())
|
||||
if ((*m_items)[m_drawn_position].isSelected())
|
||||
*this << m_selected_suffix;
|
||||
if (m_highlight_enabled && m_drawn_position == m_highlight)
|
||||
{
|
||||
*this << Color::End;
|
||||
*this << Format::NoReverse;
|
||||
}
|
||||
if (m_items[m_drawn_position].isBold())
|
||||
if ((*m_items)[m_drawn_position].isBold())
|
||||
*this << Format::NoBold;
|
||||
}
|
||||
Window::refresh();
|
||||
@@ -225,10 +228,10 @@ void Menu<ItemT>::refresh()
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::scroll(Scroll where)
|
||||
{
|
||||
if (m_items.empty())
|
||||
if (m_items->empty())
|
||||
return;
|
||||
size_t max_highlight = m_items.size()-1;
|
||||
size_t max_beginning = m_items.size() < m_height ? 0 : m_items.size()-m_height;
|
||||
size_t max_highlight = m_items->size()-1;
|
||||
size_t max_beginning = m_items->size() < m_height ? 0 : m_items->size()-m_height;
|
||||
size_t max_visible_highlight = m_beginning+m_height-1;
|
||||
switch (where)
|
||||
{
|
||||
@@ -323,13 +326,15 @@ void Menu<ItemT>::reset()
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::clear()
|
||||
{
|
||||
m_items.clear();
|
||||
m_all_items.clear();
|
||||
m_filtered_items.clear();
|
||||
m_items = &m_all_items;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::highlight(size_t pos)
|
||||
{
|
||||
assert(pos < m_items.size());
|
||||
assert(pos < m_items->size());
|
||||
m_highlight = pos;
|
||||
size_t half_height = m_height/2;
|
||||
if (pos < half_height)
|
||||
@@ -345,6 +350,24 @@ size_t Menu<ItemT>::choice() const
|
||||
return m_highlight;
|
||||
}
|
||||
|
||||
template <typename ItemT> template <typename FilterPredicate>
|
||||
bool Menu<ItemT>::applyFilter(FilterPredicate &&p)
|
||||
{
|
||||
m_filtered_items.clear();
|
||||
for (const auto &item : m_all_items)
|
||||
if (p(item))
|
||||
m_filtered_items.push_back(item);
|
||||
m_items = &m_filtered_items;
|
||||
return !m_filtered_items.empty();
|
||||
}
|
||||
|
||||
#endif // NCMPCPP_MENU_IMPL_H
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::clearFilter()
|
||||
{
|
||||
m_filtered_items.clear();
|
||||
m_items = &m_all_items;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // NCMPCPP_MENU_IMPL_H
|
||||
|
||||
Reference in New Issue
Block a user