From 29b1813c6d44ff74f939fd469251f998a31b072c Mon Sep 17 00:00:00 2001 From: Andrzej Rybczak Date: Sun, 13 Nov 2016 00:21:25 +0100 Subject: [PATCH] Resurrect filtering of lists (playlist only for now) --- NEWS | 1 + src/actions.cpp | 93 +++++++++++++++++++-------- src/actions.h | 2 + src/display.cpp | 7 +- src/helpers.h | 34 ++++++++++ src/interfaces.h | 3 + src/menu.h | 159 +++++++++++++++++++++++++++++----------------- src/menu_impl.h | 42 +++++++++--- src/playlist.cpp | 49 +++++++++++++- src/playlist.h | 8 ++- src/song.h | 2 +- src/status.cpp | 44 +++++++------ src/statusbar.cpp | 21 +++++- src/statusbar.h | 16 ++++- 14 files changed, 357 insertions(+), 124 deletions(-) diff --git a/NEWS b/NEWS index 63b91c6d..95b65db2 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ ncmpcpp-0.8 (????-??-??) * Configuration variable 'execute_on_player_state_change' was added. * Support for controlling whether ncmpcpp should display multiple tags as-is or make an effort to hide duplicate values (show_duplicate_tags configuration variable, enabled by default). +* Support for filtering of lists was brought back from the dead. ncmpcpp-0.7.7 (2016-10-31) * Fixed compilation on 32bit platforms. diff --git a/src/actions.cpp b/src/actions.cpp index f8f994f7..950c314d 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -880,7 +880,12 @@ void MoveSelectedItemsUp::run() { if (myScreen == myPlaylist) { - moveSelectedItemsUp(myPlaylist->main(), std::bind(&MPD::Connection::Move, ph::_1, ph::_2, ph::_3)); + if (myPlaylist->main().isFiltered()) + Statusbar::print("Moving items up is disabled in filtered playlist"); + else + moveSelectedItemsUp( + myPlaylist->main(), + std::bind(&MPD::Connection::Move, ph::_1, ph::_2, ph::_3)); } else if (myScreen == myPlaylistEditor) { @@ -903,7 +908,12 @@ void MoveSelectedItemsDown::run() { if (myScreen == myPlaylist) { - moveSelectedItemsDown(myPlaylist->main(), std::bind(&MPD::Connection::Move, ph::_1, ph::_2, ph::_3)); + if (myPlaylist->main().isFiltered()) + Statusbar::print("Moving items down is disabled in filtered playlist"); + else + moveSelectedItemsDown( + myPlaylist->main(), + std::bind(&MPD::Connection::Move, ph::_1, ph::_2, ph::_3)); } else if (myScreen == myPlaylistEditor) { @@ -1157,7 +1167,7 @@ void TogglePlayingSongCentering::run() { auto s = myPlaylist->nowPlayingSong(); if (!s.empty()) - myPlaylist->main().highlight(s.getPosition()); + myPlaylist->moveToSong(s); } } @@ -1187,7 +1197,7 @@ void JumpToPlayingSong::run() return; if (myScreen == myPlaylist) { - myPlaylist->main().highlight(s.getPosition()); + myPlaylist->moveToSong(s); } else if (myScreen == myBrowser) { @@ -1936,11 +1946,47 @@ void ReversePlaylist::run() bool ApplyFilter::canBeRun() { - return false; + m_searchable = dynamic_cast(myScreen); + return m_searchable != nullptr + && myScreen == myPlaylist; } void ApplyFilter::run() -{ } +{ + using Global::wFooter; + + std::string filter = m_searchable->currentFilter(); + if (!filter.empty()) + { + m_searchable->applyFilter(filter); + myScreen->refreshWindow(); + } + + try + { + Statusbar::ScopedLock slock; + NC::Window::ScopedPromptHook helper( + *wFooter, + Statusbar::Helpers::ApplyFilterImmediately(m_searchable)); + Statusbar::put() << "Apply filter: "; + filter = wFooter->prompt(filter); + } + catch (NC::PromptAborted &) + { + m_searchable->applyFilter(filter); + throw; + } + + if (filter.empty()) + Statusbar::printf("Filtering disabled"); + else + Statusbar::printf("Using filter \"%1%\"", filter); + + if (myScreen == myPlaylist) + myPlaylist->reloadTotalLength(); + + listsChangeFinisher(); +} bool Find::canBeRun() { @@ -2952,33 +2998,30 @@ void findItem(const SearchDirection direction) assert(w != nullptr); assert(w->allowsSearching()); - std::string constraint; + std::string constraint = w->searchConstraint(); + try { Statusbar::ScopedLock slock; - NC::Window::ScopedPromptHook prompt_hook(*wFooter, - Statusbar::Helpers::FindImmediately(w, direction) - ); + NC::Window::ScopedPromptHook prompt_hook( + *wFooter, + Statusbar::Helpers::FindImmediately(w, direction)); Statusbar::put() << (boost::format("Find %1%: ") % direction).str(); - constraint = wFooter->prompt(w->searchConstraint()); + constraint = wFooter->prompt(constraint); } - - try + catch (NC::PromptAborted &) { - if (constraint.empty()) - { - Statusbar::printf("Constraint unset"); - w->clearSearchConstraint(); - } - else - { - w->setSearchConstraint(constraint); - Statusbar::printf("Using constraint \"%1%\"", constraint); - } + w->setSearchConstraint(constraint); + w->search(direction, Config.wrapped_search, false); + throw; } - catch (boost::bad_expression &e) + + if (constraint.empty()) { - Statusbar::printf("%1%", e.what()); + Statusbar::printf("Constraint unset"); + w->clearSearchConstraint(); } + else + Statusbar::printf("Using constraint \"%1%\"", constraint); } void listsChangeFinisher() diff --git a/src/actions.h b/src/actions.h index 34c504bf..fb94bdfb 100644 --- a/src/actions.h +++ b/src/actions.h @@ -1044,6 +1044,8 @@ struct ApplyFilter: public BaseAction private: virtual bool canBeRun() OVERRIDE; virtual void run() OVERRIDE; + + Searchable *m_searchable; }; struct Find: BaseAction diff --git a/src/display.cpp b/src/display.cpp index ca21c848..3e9bb985 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -101,9 +101,10 @@ void setProperties(NC::Menu &menu, const MPD::Song &s, const SongList &list, is_selected = menu.drawn()->isSelected(); discard_colors = Config.discard_colors_if_item_is_selected && is_selected; - int song_pos = drawn_pos; - is_now_playing = Status::State::player() != MPD::psStop && myPlaylist->isActiveWindow(menu) - && song_pos == Status::State::currentSongPosition(); + int song_pos = s.getPosition(); + is_now_playing = Status::State::player() != MPD::psStop + && myPlaylist->isActiveWindow(menu) + && song_pos == Status::State::currentSongPosition(); if (is_now_playing) menu << Config.now_playing_prefix; } diff --git a/src/helpers.h b/src/helpers.h index ec95cd09..a9801cb7 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -31,6 +31,40 @@ #include "utility/type_conversions.h" #include "utility/wide_string.h" +enum ReapplyFilter { Yes, No }; + +template +struct ScopedUnfilteredMenu +{ + ScopedUnfilteredMenu(NC::Menu &menu) + : m_menu(menu) + { + m_is_filtered = m_menu.isFiltered(); + if (m_is_filtered) + m_menu.showAllItems(); + } + + ~ScopedUnfilteredMenu() + { + if (m_is_filtered) + { + switch (reapplyFilter) + { + case ReapplyFilter::Yes: + m_menu.reapplyFilter(); + break; + case ReapplyFilter::No: + m_menu.showFilteredItems(); + break; + } + } + } + +private: + bool m_is_filtered; + NC::Menu &m_menu; +}; + template Iterator wrappedSearch(Iterator begin, Iterator current, Iterator end, const PredicateT &pred, bool wrap, bool skip_current) diff --git a/src/interfaces.h b/src/interfaces.h index 09a8a648..6ac27063 100644 --- a/src/interfaces.h +++ b/src/interfaces.h @@ -37,6 +37,9 @@ struct Searchable virtual void setSearchConstraint(const std::string &constraint) = 0; virtual void clearSearchConstraint() = 0; virtual bool search(SearchDirection direction, bool wrap, bool skip_current) = 0; + + virtual std::string currentFilter() { return ""; } + virtual void applyFilter(const std::string &) { } }; struct HasActions diff --git a/src/menu.h b/src/menu.h index 5711fd7e..02972996 100644 --- a/src/menu.h +++ b/src/menu.h @@ -21,7 +21,6 @@ #ifndef NCMPCPP_MENU_H #define NCMPCPP_MENU_H -#include #include #include #include @@ -96,9 +95,6 @@ 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; }; @@ -154,51 +150,93 @@ inline List::ConstIterator begin(const List &list) { return list.beginP(); } inline List::Iterator end(List &list) { return list.endP(); } inline List::ConstIterator end(const List &list) { return list.endP(); } -/// This template class is generic menu capable of -/// holding any std::vector compatible values. -template struct Menu : Window, List +/// Generic menu capable of holding any std::vector compatible values. +template +struct Menu: Window, List { - struct Item : List::Properties + struct Item { - template - struct PropertiesExtractor - { - typedef PropertiesExtractor type; - - typedef typename std::conditional::type Properties_; - typedef typename std::conditional::type Item_; - - Properties_ &operator()(Item_ &i) const { - return static_cast(i); - } - }; + friend struct Menu; typedef ItemT Type; - - friend struct Menu; - + Item() - : m_value(std::make_shared(ItemT())) + : m_impl(std::make_shared>()) { } - template - Item(ValueT &&value_, Properties::Type properties) - : Properties(properties) - , m_value(std::make_shared(std::forward(value_))) + template + Item(ValueT &&value_, PropertiesT properties_) + : m_impl( + std::make_shared>( + std::forward(value_), + std::forward(properties_))) { } - - 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 &value() { return std::get<0>(*m_impl); } + const ItemT &value() const { return std::get<0>(*m_impl); } + + Properties &properties() { return std::get<1>(*m_impl); } + const Properties &properties() const { return std::get<1>(*m_impl); } + + // Forward methods to List::Properties. + void setBold (bool is_bold) { properties().setBold(is_bold); } + void setSelectable(bool is_selectable) { properties().setSelectable(is_selectable); } + void setSelected (bool is_selected) { properties().setSelected(is_selected); } + void setInactive (bool is_inactive) { properties().setInactive(is_inactive); } + void setSeparator (bool is_separator) { properties().setSeparator(is_separator); } + + bool isBold() const { return properties().isBold(); } + bool isSelectable() const { return properties().isSelectable(); } + bool isSelected() const { return properties().isSelected(); } + bool isInactive() const { return properties().isInactive(); } + bool isSeparator() const { return properties().isSeparator(); } // Make a deep copy of Item. Item copy() const { - return Item(*m_value, static_cast(properties())); + return Item(value(), properties()); } private: + enum class Const { Yes, No }; + + template + struct ExtractProperties + { + typedef ExtractProperties type; + + typedef typename std::conditional< + const_ == Const::Yes, + const Properties, + Properties>::type Properties_; + typedef typename std::conditional< + const_ == Const::Yes, + const Item, + Item>::type Item_; + + Properties_ &operator()(Item_ &i) const { + return i.properties(); + } + }; + + template + struct ExtractValue + { + typedef ExtractValue type; + + typedef typename std::conditional< + const_ == Const::Yes, + const ItemT, + ItemT>::type Value_; + typedef typename std::conditional< + const_ == Const::Yes, + const Item, + Item>::type Item_; + + Value_ &operator()(Item_ &i) const { + return i.value(); + } + }; + static Item mkSeparator() { Item item; @@ -207,7 +245,7 @@ template struct Menu : Window, List return item; } - std::shared_ptr m_value; + std::shared_ptr> m_impl; }; typedef typename std::vector::iterator Iterator; @@ -215,33 +253,29 @@ template struct Menu : Window, List typedef std::reverse_iterator ReverseIterator; typedef std::reverse_iterator ConstReverseIterator; - typedef boost::indirect_iterator< - Iterator, - ItemT, - boost::random_access_traversal_tag - > ValueIterator; - typedef boost::indirect_iterator< - ConstIterator, - const ItemT, - boost::random_access_traversal_tag - > ConstValueIterator; + typedef boost::transform_iterator< + typename Item::template ExtractValue, + Iterator> ValueIterator; + typedef boost::transform_iterator< + typename Item::template ExtractValue, + ConstIterator> ConstValueIterator; typedef std::reverse_iterator ReverseValueIterator; typedef std::reverse_iterator ConstReverseValueIterator; typedef boost::transform_iterator< - typename Item::template PropertiesExtractor, - Iterator - > PropertiesIterator; + typename Item::template ExtractProperties, + Iterator> PropertiesIterator; typedef boost::transform_iterator< - typename Item::template PropertiesExtractor, - ConstIterator - > ConstPropertiesIterator; + typename Item::template ExtractProperties, + ConstIterator> ConstPropertiesIterator; /// Function helper prototype used to display each option on the screen. /// If not set by setItemDisplayer(), menu won't display anything. /// @see setItemDisplayer() typedef std::function &)> ItemDisplayer; - + + typedef std::function FilterPredicate; + Menu(); Menu(size_t startx, size_t starty, size_t width, size_t height, @@ -253,7 +287,8 @@ template struct Menu : Window, List /// Sets helper function that is responsible for displaying items /// @param ptr function pointer that matches the ItemDisplayer prototype - void setItemDisplayer(const ItemDisplayer &f) { m_item_displayer = f; } + template + void setItemDisplayer(ItemDisplayerT &&displayer); /// Resizes the list to given size (adequate to std::vector::resize()) /// @param size requested size @@ -309,8 +344,15 @@ template struct Menu : Window, List /// Apply filter predicate to items in the menu and show the ones for which it /// returned true. - template - bool applyFilter(FilterPredicate &&p); + template + void applyFilter(PredicateT &&pred); + + /// Reapply previously applied filter. + void reapplyFilter(); + + /// Get current filter predicate. + template + const TargetT *filterPredicate() const; /// Clear results of applyFilter and show all items. void clearFilter(); @@ -451,9 +493,10 @@ private: return !(*m_items)[pos].isSeparator() && !(*m_items)[pos].isInactive(); } - + ItemDisplayer m_item_displayer; - + FilterPredicate m_filter_predicate; + std::vector *m_items; std::vector m_all_items; std::vector m_filtered_items; diff --git a/src/menu_impl.h b/src/menu_impl.h index 33b8a24f..1d562f92 100644 --- a/src/menu_impl.h +++ b/src/menu_impl.h @@ -40,7 +40,8 @@ Menu::Menu(size_t startx, Color color, Border border) : Window(startx, starty, width, height, title, std::move(color), border) - , m_item_displayer(0) + , m_item_displayer(nullptr) + , m_filter_predicate(nullptr) , m_beginning(0) , m_highlight(0) , m_highlight_color(m_base_color) @@ -55,6 +56,7 @@ template Menu::Menu(const Menu &rhs) : Window(rhs) , m_item_displayer(rhs.m_item_displayer) + , m_filter_predicate(rhs.m_filter_predicate) , m_beginning(rhs.m_beginning) , m_highlight(rhs.m_highlight) , m_highlight_color(rhs.m_highlight_color) @@ -75,7 +77,8 @@ Menu::Menu(const Menu &rhs) template Menu::Menu(Menu &&rhs) : Window(rhs) - , m_item_displayer(rhs.m_item_displayer) + , m_item_displayer(std::move(rhs.m_item_displayer)) + , m_filter_predicate(std::move(rhs.m_filter_predicate)) , m_all_items(std::move(rhs.m_all_items)) , m_filtered_items(std::move(rhs.m_filtered_items)) , m_beginning(rhs.m_beginning) @@ -99,6 +102,7 @@ Menu &Menu::operator=(Menu rhs) { std::swap(static_cast(*this), static_cast(rhs)); std::swap(m_item_displayer, rhs.m_item_displayer); + std::swap(m_filter_predicate, rhs.m_filter_predicate); 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); @@ -117,6 +121,12 @@ Menu &Menu::operator=(Menu rhs) return *this; } +template template +void Menu::setItemDisplayer(ItemDisplayerT &&displayer) +{ + m_item_displayer = std::forward(displayer); +} + template void Menu::resizeList(size_t new_size) { @@ -326,9 +336,8 @@ void Menu::reset() template void Menu::clear() { - m_all_items.clear(); - m_filtered_items.clear(); - m_items = &m_all_items; + clearFilter(); + m_items->clear(); } template @@ -350,20 +359,35 @@ size_t Menu::choice() const return m_highlight; } -template template -bool Menu::applyFilter(FilterPredicate &&p) +template template +void Menu::applyFilter(PredicateT &&pred) { + m_filter_predicate = std::forward(pred); m_filtered_items.clear(); + for (const auto &item : m_all_items) - if (p(item)) + if (m_filter_predicate(item)) m_filtered_items.push_back(item); + m_items = &m_filtered_items; - return !m_filtered_items.empty(); +} + +template +void Menu::reapplyFilter() +{ + applyFilter(m_filter_predicate); +} + +template template +const TargetT *Menu::filterPredicate() const +{ + return m_filter_predicate.template target(); } template void Menu::clearFilter() { + m_filter_predicate = nullptr; m_filtered_items.clear(); m_items = &m_all_items; } diff --git a/src/playlist.cpp b/src/playlist.cpp index b8994182..d2c9ce91 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -176,6 +176,27 @@ bool Playlist::search(SearchDirection direction, bool wrap, bool skip_current) return ::search(w, m_search_predicate, direction, wrap, skip_current); } +std::string Playlist::currentFilter() +{ + std::string result; + if (auto pred = w.filterPredicate>()) + result = pred->constraint(); + return result; +} + +void Playlist::applyFilter(const std::string &constraint) +{ + if (!constraint.empty()) + { + w.applyFilter(Regex::Filter( + constraint, + Config.regex_type, + playlistEntryMatcher)); + } + else + w.clearFilter(); +} + /***********************************************************************/ bool Playlist::itemAvailable() @@ -202,6 +223,7 @@ MPD::Song Playlist::nowPlayingSong() MPD::Song s; if (Status::State::player() != MPD::psUnknown) { + ScopedUnfilteredMenu sunfilter(w); auto sp = Status::State::currentSongPosition(); if (sp >= 0 && size_t(sp) < w.size()) s = w.at(sp).value(); @@ -209,6 +231,24 @@ MPD::Song Playlist::nowPlayingSong() return s; } +void Playlist::moveToSong(const MPD::Song &s) +{ + if (!w.isFiltered()) + w.highlight(s.getPosition()); + else + { + auto cmp = [](const MPD::Song &a, const MPD::Song &b) { + return a.getPosition() < b.getPosition(); + }; + auto first = w.beginV(), last = w.endV(); + auto it = std::lower_bound(first, last, s, cmp); + if (it != last && it->getPosition() == s.getPosition()) + w.highlight(it - first); + else + Statusbar::print("Song is filtered out"); + } +} + void Playlist::enableHighlighting() { w.setHighlighting(true); @@ -228,6 +268,7 @@ std::string Playlist::getTotalLength() } if (Config.playlist_show_remaining_time && m_reload_remaining) { + ScopedUnfilteredMenu sunfilter(w); m_remaining_time = 0; for (size_t i = Status::State::currentSongPosition(); i < w.size(); ++i) m_remaining_time += w[i].value().getDuration(); @@ -235,6 +276,12 @@ std::string Playlist::getTotalLength() } result << '(' << w.size() << (w.size() == 1 ? " item" : " items"); + + if (w.isFiltered()) + { + ScopedUnfilteredMenu sunfilter(w); + result << " (out of " << w.size() << ")"; + } if (m_total_length) { @@ -243,7 +290,7 @@ std::string Playlist::getTotalLength() } if (Config.playlist_show_remaining_time && m_remaining_time && w.size() > 1) { - result << " :: remaining: "; + result << ", remaining: "; ShowTime(result, m_remaining_time, Config.playlist_shorten_total_times); } result << ')'; diff --git a/src/playlist.h b/src/playlist.h index 8661d8eb..dcf398d2 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -54,15 +54,21 @@ struct Playlist: Screen, HasSongs, Searchable, Tabbable virtual void setSearchConstraint(const std::string &constraint) OVERRIDE; virtual void clearSearchConstraint() OVERRIDE; virtual bool search(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE; + + virtual std::string currentFilter() OVERRIDE; + virtual void applyFilter(const std::string &filter) OVERRIDE; // HasSongs implementation virtual bool itemAvailable() OVERRIDE; virtual bool addItemToPlaylist(bool play) OVERRIDE; virtual std::vector getSelectedSongs() OVERRIDE; - // private members + // other members MPD::Song nowPlayingSong(); + // Move to given song from playlist. + void moveToSong(const MPD::Song &s); + void enableHighlighting(); void setSelectedItemsPriority(int prio); diff --git a/src/song.h b/src/song.h index d0dfddce..fe822b17 100644 --- a/src/song.h +++ b/src/song.h @@ -96,7 +96,7 @@ struct Song { return !(operator==(rhs)); } - + const char *c_uri() const { return m_song ? mpd_song_get_uri(m_song.get()) : ""; } static std::string ShowTime(unsigned length); diff --git a/src/status.cpp b/src/status.cpp index 522373b7..19472cc6 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -408,29 +408,33 @@ int Status::State::volume() void Status::Changes::playlist(unsigned previous_version) { - if (m_playlist_length < myPlaylist->main().size()) { - auto it = myPlaylist->main().begin()+m_playlist_length; - auto end = myPlaylist->main().end(); - for (; it != end; ++it) - myPlaylist->unregisterSong(it->value()); - myPlaylist->main().resizeList(m_playlist_length); - } + ScopedUnfilteredMenu sunfilter(myPlaylist->main()); - MPD::SongIterator s = Mpd.GetPlaylistChanges(previous_version), end; - for (; s != end; ++s) - { - size_t pos = s->getPosition(); - myPlaylist->registerSong(*s); - if (pos < myPlaylist->main().size()) + if (m_playlist_length < myPlaylist->main().size()) { - // if song's already in playlist, replace it with a new one - MPD::Song &old_s = myPlaylist->main()[pos].value(); - myPlaylist->unregisterSong(old_s); - old_s = std::move(*s); + auto it = myPlaylist->main().begin()+m_playlist_length; + auto end = myPlaylist->main().end(); + for (; it != end; ++it) + myPlaylist->unregisterSong(it->value()); + myPlaylist->main().resizeList(m_playlist_length); + } + + MPD::SongIterator s = Mpd.GetPlaylistChanges(previous_version), end; + for (; s != end; ++s) + { + size_t pos = s->getPosition(); + myPlaylist->registerSong(*s); + if (pos < myPlaylist->main().size()) + { + // if song's already in playlist, replace it with a new one + MPD::Song &old_s = myPlaylist->main()[pos].value(); + myPlaylist->unregisterSong(old_s); + old_s = std::move(*s); + } + else // otherwise just add it to playlist + myPlaylist->main().addItem(std::move(*s)); } - else // otherwise just add it to playlist - myPlaylist->main().addItem(std::move(*s)); } myPlaylist->reloadTotalLength(); @@ -576,7 +580,7 @@ void Status::Changes::songID(int song_id) drawTitle(s); if (Config.autocenter_mode) - pl.highlight(Status::State::currentSongPosition()); + myPlaylist->moveToSong(s); if (Config.now_playing_lyrics && isVisible(myLyrics) && myLyrics->previousScreen() == myPlaylist) { diff --git a/src/statusbar.cpp b/src/statusbar.cpp index 718bbccf..4703d47c 100644 --- a/src/statusbar.cpp +++ b/src/statusbar.cpp @@ -220,19 +220,34 @@ bool Statusbar::Helpers::ImmediatelyReturnOneOf::operator()(const char *s) const return !isOneOf(s); } +bool Statusbar::Helpers::ApplyFilterImmediately::operator()(const char *s) +{ + using Global::myScreen; + Status::trace(); + try { + if (m_w->allowsSearching() && m_w->currentFilter() != s) + { + m_w->applyFilter(s); + if (myScreen == myPlaylist) + myPlaylist->enableHighlighting(); + myScreen->refreshWindow(); + } + } catch (boost::bad_expression &) { } + return true; +} + bool Statusbar::Helpers::FindImmediately::operator()(const char *s) { using Global::myScreen; Status::trace(); try { - if (m_w->allowsSearching() && m_s != s) + if (m_w->allowsSearching() && m_w->searchConstraint() != s) { m_w->setSearchConstraint(s); - m_found = m_w->search(m_direction, Config.wrapped_search, false); + m_w->search(m_direction, Config.wrapped_search, false); if (myScreen == myPlaylist) myPlaylist->enableHighlighting(); myScreen->refreshWindow(); - m_s = s; } } catch (boost::bad_expression &) { } return true; diff --git a/src/statusbar.h b/src/statusbar.h index 9bb6857f..25801c00 100644 --- a/src/statusbar.h +++ b/src/statusbar.h @@ -89,10 +89,22 @@ private: std::vector m_values; }; +struct ApplyFilterImmediately +{ + ApplyFilterImmediately(Searchable *w) + : m_w(w) + { } + + bool operator()(const char *s); + +private: + Searchable *m_w; +}; + struct FindImmediately { FindImmediately(Searchable *w, SearchDirection direction) - : m_w(w), m_direction(direction), m_found(true) + : m_w(w), m_direction(direction) { } bool operator()(const char *s); @@ -100,8 +112,6 @@ struct FindImmediately private: Searchable *m_w; const SearchDirection m_direction; - std::string m_s; - bool m_found; }; struct TryExecuteImmediateCommand