Resurrect filtering of lists (playlist only for now)

This commit is contained in:
Andrzej Rybczak
2016-11-13 00:21:25 +01:00
parent 60e66b47b6
commit 29b1813c6d
14 changed files with 360 additions and 127 deletions

1
NEWS
View File

@@ -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.

View File

@@ -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<Searchable *>(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;
{
Statusbar::ScopedLock slock;
NC::Window::ScopedPromptHook prompt_hook(*wFooter,
Statusbar::Helpers::FindImmediately(w, direction)
);
Statusbar::put() << (boost::format("Find %1%: ") % direction).str();
constraint = wFooter->prompt(w->searchConstraint());
}
std::string constraint = w->searchConstraint();
try
{
if (constraint.empty())
{
Statusbar::printf("Constraint unset");
w->clearSearchConstraint();
}
else
{
w->setSearchConstraint(constraint);
Statusbar::printf("Using constraint \"%1%\"", constraint);
}
Statusbar::ScopedLock slock;
NC::Window::ScopedPromptHook prompt_hook(
*wFooter,
Statusbar::Helpers::FindImmediately(w, direction));
Statusbar::put() << (boost::format("Find %1%: ") % direction).str();
constraint = wFooter->prompt(constraint);
}
catch (boost::bad_expression &e)
catch (NC::PromptAborted &)
{
Statusbar::printf("%1%", e.what());
w->setSearchConstraint(constraint);
w->search(direction, Config.wrapped_search, false);
throw;
}
if (constraint.empty())
{
Statusbar::printf("Constraint unset");
w->clearSearchConstraint();
}
else
Statusbar::printf("Using constraint \"%1%\"", constraint);
}
void listsChangeFinisher()

View File

@@ -1044,6 +1044,8 @@ struct ApplyFilter: public BaseAction
private:
virtual bool canBeRun() OVERRIDE;
virtual void run() OVERRIDE;
Searchable *m_searchable;
};
struct Find: BaseAction

View File

@@ -101,9 +101,10 @@ void setProperties(NC::Menu<T> &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;
}

View File

@@ -31,6 +31,40 @@
#include "utility/type_conversions.h"
#include "utility/wide_string.h"
enum ReapplyFilter { Yes, No };
template <typename ItemT, ReapplyFilter reapplyFilter>
struct ScopedUnfilteredMenu
{
ScopedUnfilteredMenu(NC::Menu<ItemT> &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<ItemT> &m_menu;
};
template <typename Iterator, typename PredicateT>
Iterator wrappedSearch(Iterator begin, Iterator current, Iterator end,
const PredicateT &pred, bool wrap, bool skip_current)

View File

@@ -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

View File

@@ -21,7 +21,6 @@
#ifndef NCMPCPP_MENU_H
#define NCMPCPP_MENU_H
#include <boost/iterator/indirect_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/detail/any_iterator.hpp>
#include <cassert>
@@ -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 <typename ItemT> struct Menu : Window, List
/// Generic menu capable of holding any std::vector compatible values.
template <typename ItemT>
struct Menu: Window, List
{
struct Item : List::Properties
struct Item
{
template <bool Const>
struct PropertiesExtractor
{
typedef PropertiesExtractor type;
typedef typename std::conditional<Const, const Properties, Properties>::type Properties_;
typedef typename std::conditional<Const, const Item, Item>::type Item_;
Properties_ &operator()(Item_ &i) const {
return static_cast<Properties_ &>(i);
}
};
friend struct Menu<ItemT>;
typedef ItemT Type;
friend struct Menu<ItemT>;
Item()
: m_value(std::make_shared<ItemT>(ItemT()))
: m_impl(std::make_shared<std::tuple<ItemT, Properties>>())
{ }
template <typename ValueT>
Item(ValueT &&value_, Properties::Type properties)
: Properties(properties)
, m_value(std::make_shared<ItemT>(std::forward<ValueT>(value_)))
template <typename ValueT, typename PropertiesT>
Item(ValueT &&value_, PropertiesT properties_)
: m_impl(
std::make_shared<std::tuple<ItemT, List::Properties>>(
std::forward<ValueT>(value_),
std::forward<PropertiesT>(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::Type>(properties()));
return Item(value(), properties());
}
private:
enum class Const { Yes, No };
template <Const const_>
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 <Const const_>
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 <typename ItemT> struct Menu : Window, List
return item;
}
std::shared_ptr<ItemT> m_value;
std::shared_ptr<std::tuple<ItemT, Properties>> m_impl;
};
typedef typename std::vector<Item>::iterator Iterator;
@@ -215,33 +253,29 @@ template <typename ItemT> struct Menu : Window, List
typedef std::reverse_iterator<Iterator> ReverseIterator;
typedef std::reverse_iterator<ConstIterator> 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<Item::Const::No>,
Iterator> ValueIterator;
typedef boost::transform_iterator<
typename Item::template ExtractValue<Item::Const::Yes>,
ConstIterator> ConstValueIterator;
typedef std::reverse_iterator<ValueIterator> ReverseValueIterator;
typedef std::reverse_iterator<ConstValueIterator> ConstReverseValueIterator;
typedef boost::transform_iterator<
typename Item::template PropertiesExtractor<false>,
Iterator
> PropertiesIterator;
typename Item::template ExtractProperties<Item::Const::No>,
Iterator> PropertiesIterator;
typedef boost::transform_iterator<
typename Item::template PropertiesExtractor<true>,
ConstIterator
> ConstPropertiesIterator;
typename Item::template ExtractProperties<Item::Const::Yes>,
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<void(Menu<ItemT> &)> ItemDisplayer;
typedef std::function<bool(const Item &)> FilterPredicate;
Menu();
Menu(size_t startx, size_t starty, size_t width, size_t height,
@@ -253,7 +287,8 @@ template <typename ItemT> 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 <typename ItemDisplayerT>
void setItemDisplayer(ItemDisplayerT &&displayer);
/// Resizes the list to given size (adequate to std::vector::resize())
/// @param size requested size
@@ -309,8 +344,15 @@ template <typename ItemT> struct Menu : Window, List
/// Apply filter predicate to items in the menu and show the ones for which it
/// returned true.
template <typename FilterPredicate>
bool applyFilter(FilterPredicate &&p);
template <typename PredicateT>
void applyFilter(PredicateT &&pred);
/// Reapply previously applied filter.
void reapplyFilter();
/// Get current filter predicate.
template <typename TargetT>
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<Item> *m_items;
std::vector<Item> m_all_items;
std::vector<Item> m_filtered_items;

View File

@@ -40,7 +40,8 @@ Menu<ItemT>::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 <typename ItemT>
Menu<ItemT>::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<ItemT>::Menu(const Menu &rhs)
template <typename ItemT>
Menu<ItemT>::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<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_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<ItemT> &Menu<ItemT>::operator=(Menu rhs)
return *this;
}
template <typename ItemT> template <typename ItemDisplayerT>
void Menu<ItemT>::setItemDisplayer(ItemDisplayerT &&displayer)
{
m_item_displayer = std::forward<ItemDisplayerT>(displayer);
}
template <typename ItemT>
void Menu<ItemT>::resizeList(size_t new_size)
{
@@ -326,9 +336,8 @@ void Menu<ItemT>::reset()
template <typename ItemT>
void Menu<ItemT>::clear()
{
m_all_items.clear();
m_filtered_items.clear();
m_items = &m_all_items;
clearFilter();
m_items->clear();
}
template <typename ItemT>
@@ -350,20 +359,35 @@ size_t Menu<ItemT>::choice() const
return m_highlight;
}
template <typename ItemT> template <typename FilterPredicate>
bool Menu<ItemT>::applyFilter(FilterPredicate &&p)
template <typename ItemT> template <typename PredicateT>
void Menu<ItemT>::applyFilter(PredicateT &&pred)
{
m_filter_predicate = std::forward<PredicateT>(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 <typename ItemT>
void Menu<ItemT>::reapplyFilter()
{
applyFilter(m_filter_predicate);
}
template <typename ItemT> template <typename TargetT>
const TargetT *Menu<ItemT>::filterPredicate() const
{
return m_filter_predicate.template target<TargetT>();
}
template <typename ItemT>
void Menu<ItemT>::clearFilter()
{
m_filter_predicate = nullptr;
m_filtered_items.clear();
m_items = &m_all_items;
}

View File

@@ -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<Regex::Filter<MPD::Song>>())
result = pred->constraint();
return result;
}
void Playlist::applyFilter(const std::string &constraint)
{
if (!constraint.empty())
{
w.applyFilter(Regex::Filter<MPD::Song>(
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<MPD::Song, ReapplyFilter::No> 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<MPD::Song, ReapplyFilter::No> 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<MPD::Song, ReapplyFilter::No> 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 << ')';

View File

@@ -54,15 +54,21 @@ struct Playlist: Screen<SongMenu>, 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<MPD::Song> 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);

View File

@@ -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);

View File

@@ -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<MPD::Song, ReapplyFilter::Yes> 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)
{

View File

@@ -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;

View File

@@ -89,10 +89,22 @@ private:
std::vector<std::string> 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