Implement filtering in media library
This commit is contained in:
@@ -1167,7 +1167,7 @@ void TogglePlayingSongCentering::run()
|
|||||||
{
|
{
|
||||||
auto s = myPlaylist->nowPlayingSong();
|
auto s = myPlaylist->nowPlayingSong();
|
||||||
if (!s.empty())
|
if (!s.empty())
|
||||||
myPlaylist->moveToSong(s);
|
myPlaylist->locateSong(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1197,7 +1197,7 @@ void JumpToPlayingSong::run()
|
|||||||
return;
|
return;
|
||||||
if (myScreen == myPlaylist)
|
if (myScreen == myPlaylist)
|
||||||
{
|
{
|
||||||
myPlaylist->moveToSong(s);
|
myPlaylist->locateSong(s);
|
||||||
}
|
}
|
||||||
else if (myScreen == myBrowser)
|
else if (myScreen == myBrowser)
|
||||||
{
|
{
|
||||||
@@ -1205,7 +1205,7 @@ void JumpToPlayingSong::run()
|
|||||||
}
|
}
|
||||||
else if (myScreen == myLibrary)
|
else if (myScreen == myLibrary)
|
||||||
{
|
{
|
||||||
myLibrary->LocateSong(s);
|
myLibrary->locateSong(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1611,7 +1611,7 @@ bool JumpToMediaLibrary::canBeRun()
|
|||||||
|
|
||||||
void JumpToMediaLibrary::run()
|
void JumpToMediaLibrary::run()
|
||||||
{
|
{
|
||||||
myLibrary->LocateSong(*m_song);
|
myLibrary->locateSong(*m_song);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JumpToPlaylistEditor::canBeRun()
|
bool JumpToPlaylistEditor::canBeRun()
|
||||||
@@ -2226,7 +2226,7 @@ void ToggleBrowserSortMode::run()
|
|||||||
bool ToggleLibraryTagType::canBeRun()
|
bool ToggleLibraryTagType::canBeRun()
|
||||||
{
|
{
|
||||||
return (myScreen->isActiveWindow(myLibrary->Tags))
|
return (myScreen->isActiveWindow(myLibrary->Tags))
|
||||||
|| (myLibrary->Columns() == 2 && myScreen->isActiveWindow(myLibrary->Albums));
|
|| (myLibrary->columns() == 2 && myScreen->isActiveWindow(myLibrary->Albums));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToggleLibraryTagType::run()
|
void ToggleLibraryTagType::run()
|
||||||
@@ -2257,7 +2257,7 @@ void ToggleLibraryTagType::run()
|
|||||||
std::string and_mtime = Config.media_library_sort_by_mtime ?
|
std::string and_mtime = Config.media_library_sort_by_mtime ?
|
||||||
" and mtime" :
|
" and mtime" :
|
||||||
"";
|
"";
|
||||||
if (myLibrary->Columns() == 2)
|
if (myLibrary->columns() == 2)
|
||||||
{
|
{
|
||||||
myLibrary->Songs.clear();
|
myLibrary->Songs.clear();
|
||||||
myLibrary->Albums.reset();
|
myLibrary->Albums.reset();
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ bool Browser::enterDirectory()
|
|||||||
|
|
||||||
void Browser::getDirectory(std::string directory)
|
void Browser::getDirectory(std::string directory)
|
||||||
{
|
{
|
||||||
ScopedUnfilteredMenu<MPD::Item, ReapplyFilter::Yes> sunfilter(w);
|
ScopedUnfilteredMenu<MPD::Item> sunfilter(ReapplyFilter::Yes, w);
|
||||||
|
|
||||||
m_scroll_beginning = 0;
|
m_scroll_beginning = 0;
|
||||||
w.clear();
|
w.clear();
|
||||||
|
|||||||
@@ -34,11 +34,11 @@
|
|||||||
|
|
||||||
enum ReapplyFilter { Yes, No };
|
enum ReapplyFilter { Yes, No };
|
||||||
|
|
||||||
template <typename ItemT, ReapplyFilter reapplyFilter>
|
template <typename ItemT>
|
||||||
struct ScopedUnfilteredMenu
|
struct ScopedUnfilteredMenu
|
||||||
{
|
{
|
||||||
ScopedUnfilteredMenu(NC::Menu<ItemT> &menu)
|
ScopedUnfilteredMenu(ReapplyFilter reapply_filter, NC::Menu<ItemT> &menu)
|
||||||
: m_menu(menu)
|
: m_refresh(false), m_reapply_filter(reapply_filter), m_menu(menu)
|
||||||
{
|
{
|
||||||
m_is_filtered = m_menu.isFiltered();
|
m_is_filtered = m_menu.isFiltered();
|
||||||
if (m_is_filtered)
|
if (m_is_filtered)
|
||||||
@@ -49,7 +49,7 @@ struct ScopedUnfilteredMenu
|
|||||||
{
|
{
|
||||||
if (m_is_filtered)
|
if (m_is_filtered)
|
||||||
{
|
{
|
||||||
switch (reapplyFilter)
|
switch (m_reapply_filter)
|
||||||
{
|
{
|
||||||
case ReapplyFilter::Yes:
|
case ReapplyFilter::Yes:
|
||||||
m_menu.reapplyFilter();
|
m_menu.reapplyFilter();
|
||||||
@@ -59,10 +59,20 @@ struct ScopedUnfilteredMenu
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (m_refresh)
|
||||||
|
m_menu.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(ReapplyFilter reapply_filter, bool refresh)
|
||||||
|
{
|
||||||
|
m_reapply_filter = reapply_filter;
|
||||||
|
m_refresh = refresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_is_filtered;
|
bool m_is_filtered;
|
||||||
|
bool m_refresh;
|
||||||
|
ReapplyFilter m_reapply_filter;
|
||||||
NC::Menu<ItemT> &m_menu;
|
NC::Menu<ItemT> &m_menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -375,9 +385,7 @@ template <typename Iterator> std::string getSharedDirectory(Iterator first, Iter
|
|||||||
template <typename ListT>
|
template <typename ListT>
|
||||||
void markSongsInPlaylist(ListT &list)
|
void markSongsInPlaylist(ListT &list)
|
||||||
{
|
{
|
||||||
ScopedUnfilteredMenu<
|
ScopedUnfilteredMenu<typename ListT::Item::Type> sunfilter(ReapplyFilter::No, list);
|
||||||
typename ListT::Item::Type,
|
|
||||||
ReapplyFilter::No> sunfilter(list);
|
|
||||||
MPD::Song *s;
|
MPD::Song *s;
|
||||||
for (auto &p : static_cast<SongList &>(list))
|
for (auto &p : static_cast<SongList &>(list))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -279,9 +279,11 @@ void MediaLibrary::update()
|
|||||||
{
|
{
|
||||||
if (hasTwoColumns)
|
if (hasTwoColumns)
|
||||||
{
|
{
|
||||||
|
ScopedUnfilteredMenu<AlbumEntry> sunfilter_albums(ReapplyFilter::No, Albums);
|
||||||
if (Albums.empty() || m_albums_update_request)
|
if (Albums.empty() || m_albums_update_request)
|
||||||
{
|
{
|
||||||
m_albums_update_request = false;
|
m_albums_update_request = false;
|
||||||
|
sunfilter_albums.set(ReapplyFilter::Yes, true);
|
||||||
std::map<std::tuple<std::string, std::string, std::string>, time_t> albums;
|
std::map<std::tuple<std::string, std::string, std::string>, time_t> albums;
|
||||||
for (MPD::SongIterator s = getDatabaseIterator(Mpd), end; s != end; ++s)
|
for (MPD::SongIterator s = getDatabaseIterator(Mpd), end; s != end; ++s)
|
||||||
{
|
{
|
||||||
@@ -300,12 +302,11 @@ void MediaLibrary::update()
|
|||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
for (const auto &album : albums)
|
for (const auto &album : albums)
|
||||||
{
|
{
|
||||||
auto entry = AlbumEntry(Album(
|
auto entry = AlbumEntry(
|
||||||
std::move(std::get<0>(album.first)),
|
Album(std::move(std::get<0>(album.first)),
|
||||||
std::move(std::get<1>(album.first)),
|
std::move(std::get<1>(album.first)),
|
||||||
std::move(std::get<2>(album.first)),
|
std::move(std::get<2>(album.first)),
|
||||||
album.second)
|
album.second));
|
||||||
);
|
|
||||||
if (idx < Albums.size())
|
if (idx < Albums.size())
|
||||||
Albums[idx].value() = std::move(entry);
|
Albums[idx].value() = std::move(entry);
|
||||||
else
|
else
|
||||||
@@ -315,106 +316,112 @@ void MediaLibrary::update()
|
|||||||
if (idx < Albums.size())
|
if (idx < Albums.size())
|
||||||
Albums.resizeList(idx);
|
Albums.resizeList(idx);
|
||||||
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
||||||
Albums.refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Tags.empty() || m_tags_update_request)
|
|
||||||
{
|
{
|
||||||
m_tags_update_request = false;
|
ScopedUnfilteredMenu<PrimaryTag> sunfilter_tags(ReapplyFilter::No, Tags);
|
||||||
std::map<std::string, time_t> tags;
|
if (Tags.empty() || m_tags_update_request)
|
||||||
if (Config.media_library_sort_by_mtime)
|
|
||||||
{
|
{
|
||||||
for (MPD::SongIterator s = getDatabaseIterator(Mpd), end; s != end; ++s)
|
m_tags_update_request = false;
|
||||||
|
sunfilter_tags.set(ReapplyFilter::Yes, true);
|
||||||
|
std::map<std::string, time_t> tags;
|
||||||
|
if (Config.media_library_sort_by_mtime)
|
||||||
{
|
{
|
||||||
std::string tag;
|
for (MPD::SongIterator s = getDatabaseIterator(Mpd), end; s != end; ++s)
|
||||||
unsigned idx = 0;
|
|
||||||
while (!(tag = s->get(Config.media_lib_primary_tag, idx++)).empty())
|
|
||||||
{
|
{
|
||||||
auto it = tags.find(tag);
|
std::string tag;
|
||||||
if (it == tags.end())
|
unsigned idx = 0;
|
||||||
tags[std::move(tag)] = s->getMTime();
|
while (!(tag = s->get(Config.media_lib_primary_tag, idx++)).empty())
|
||||||
else
|
{
|
||||||
it->second = std::max(it->second, s->getMTime());
|
auto it = tags.find(tag);
|
||||||
|
if (it == tags.end())
|
||||||
|
tags[std::move(tag)] = s->getMTime();
|
||||||
|
else
|
||||||
|
it->second = std::max(it->second, s->getMTime());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MPD::StringIterator tag = Mpd.GetList(Config.media_lib_primary_tag), end;
|
|
||||||
for (; tag != end; ++tag)
|
|
||||||
tags[std::move(*tag)] = 0;
|
|
||||||
}
|
|
||||||
size_t idx = 0;
|
|
||||||
for (const auto &tag : tags)
|
|
||||||
{
|
|
||||||
auto ptag = PrimaryTag(std::move(tag.first), tag.second);
|
|
||||||
if (idx < Tags.size())
|
|
||||||
Tags[idx].value() = std::move(ptag);
|
|
||||||
else
|
else
|
||||||
Tags.addItem(std::move(ptag));
|
{
|
||||||
++idx;
|
MPD::StringIterator tag = Mpd.GetList(Config.media_lib_primary_tag), end;
|
||||||
|
for (; tag != end; ++tag)
|
||||||
|
tags[std::move(*tag)] = 0;
|
||||||
|
}
|
||||||
|
size_t idx = 0;
|
||||||
|
for (const auto &tag : tags)
|
||||||
|
{
|
||||||
|
auto ptag = PrimaryTag(std::move(tag.first), tag.second);
|
||||||
|
if (idx < Tags.size())
|
||||||
|
Tags[idx].value() = std::move(ptag);
|
||||||
|
else
|
||||||
|
Tags.addItem(std::move(ptag));
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
if (idx < Tags.size())
|
||||||
|
Tags.resizeList(idx);
|
||||||
|
std::sort(Tags.beginV(), Tags.endV(), SortPrimaryTags());
|
||||||
}
|
}
|
||||||
if (idx < Tags.size())
|
|
||||||
Tags.resizeList(idx);
|
|
||||||
std::sort(Tags.beginV(), Tags.endV(), SortPrimaryTags());
|
|
||||||
Tags.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Tags.empty()
|
|
||||||
&& ((Albums.empty() && Global::Timer - m_timer > m_fetching_delay) || m_albums_update_request)
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
m_albums_update_request = false;
|
ScopedUnfilteredMenu<AlbumEntry> sunfilter_albums(ReapplyFilter::No, Albums);
|
||||||
auto &primary_tag = Tags.current()->value().tag();
|
if (!Tags.empty()
|
||||||
Mpd.StartSearch(true);
|
&& ((Albums.empty() && Global::Timer - m_timer > m_fetching_delay)
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, primary_tag);
|
|| m_albums_update_request))
|
||||||
std::map<std::tuple<std::string, std::string>, time_t> albums;
|
|
||||||
for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s)
|
|
||||||
{
|
{
|
||||||
auto key = std::make_tuple(s->getAlbum(), s->getDate());
|
m_albums_update_request = false;
|
||||||
auto it = albums.find(key);
|
sunfilter_albums.set(ReapplyFilter::Yes, true);
|
||||||
if (it == albums.end())
|
auto &primary_tag = Tags.current()->value().tag();
|
||||||
albums[std::move(key)] = s->getMTime();
|
Mpd.StartSearch(true);
|
||||||
else
|
Mpd.AddSearch(Config.media_lib_primary_tag, primary_tag);
|
||||||
it->second = std::max(it->second, s->getMTime());
|
std::map<std::tuple<std::string, std::string>, time_t> albums;
|
||||||
};
|
for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s)
|
||||||
size_t idx = 0;
|
|
||||||
for (const auto &album : albums)
|
|
||||||
{
|
|
||||||
auto entry = AlbumEntry(Album(
|
|
||||||
primary_tag,
|
|
||||||
std::move(std::get<0>(album.first)),
|
|
||||||
std::move(std::get<1>(album.first)),
|
|
||||||
album.second)
|
|
||||||
);
|
|
||||||
if (idx < Albums.size())
|
|
||||||
{
|
{
|
||||||
Albums[idx].value() = std::move(entry);
|
auto key = std::make_tuple(s->getAlbum(), s->getDate());
|
||||||
Albums[idx].setSeparator(false);
|
auto it = albums.find(key);
|
||||||
|
if (it == albums.end())
|
||||||
|
albums[std::move(key)] = s->getMTime();
|
||||||
|
else
|
||||||
|
it->second = std::max(it->second, s->getMTime());
|
||||||
|
};
|
||||||
|
size_t idx = 0;
|
||||||
|
for (const auto &album : albums)
|
||||||
|
{
|
||||||
|
auto entry = AlbumEntry(
|
||||||
|
Album(primary_tag,
|
||||||
|
std::move(std::get<0>(album.first)),
|
||||||
|
std::move(std::get<1>(album.first)),
|
||||||
|
album.second));
|
||||||
|
if (idx < Albums.size())
|
||||||
|
{
|
||||||
|
Albums[idx].value() = std::move(entry);
|
||||||
|
Albums[idx].setSeparator(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Albums.addItem(std::move(entry));
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
if (idx < Albums.size())
|
||||||
|
Albums.resizeList(idx);
|
||||||
|
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
||||||
|
if (albums.size() > 1)
|
||||||
|
{
|
||||||
|
Albums.addSeparator();
|
||||||
|
Albums.addItem(AlbumEntry::mkAllTracksEntry(primary_tag));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
Albums.addItem(std::move(entry));
|
|
||||||
++idx;
|
|
||||||
}
|
}
|
||||||
if (idx < Albums.size())
|
|
||||||
Albums.resizeList(idx);
|
|
||||||
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
|
||||||
if (albums.size() > 1)
|
|
||||||
{
|
|
||||||
Albums.addSeparator();
|
|
||||||
Albums.addItem(AlbumEntry::mkAllTracksEntry(primary_tag));
|
|
||||||
}
|
|
||||||
Albums.refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopedUnfilteredMenu<MPD::Song> sunfilter_songs(ReapplyFilter::No, Songs);
|
||||||
if (!Albums.empty()
|
if (!Albums.empty()
|
||||||
&& ((Songs.empty() && Global::Timer - m_timer > m_fetching_delay) || m_songs_update_request)
|
&& ((Songs.empty() && Global::Timer - m_timer > m_fetching_delay)
|
||||||
)
|
|| m_songs_update_request))
|
||||||
{
|
{
|
||||||
m_songs_update_request = false;
|
m_songs_update_request = false;
|
||||||
|
sunfilter_songs.set(ReapplyFilter::Yes, true);
|
||||||
auto &album = Albums.current()->value();
|
auto &album = Albums.current()->value();
|
||||||
Mpd.StartSearch(true);
|
Mpd.StartSearch(true);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, album.entry().tag());
|
Mpd.AddSearch(Config.media_lib_primary_tag, album.entry().tag());
|
||||||
@@ -443,12 +450,13 @@ void MediaLibrary::update()
|
|||||||
if (idx < Songs.size())
|
if (idx < Songs.size())
|
||||||
Songs.resizeList(idx);
|
Songs.resizeList(idx);
|
||||||
std::sort(Songs.begin(), Songs.end(), SortSongs(!album.isAllTracksEntry()));
|
std::sort(Songs.begin(), Songs.end(), SortSongs(!album.isAllTracksEntry()));
|
||||||
Songs.refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int MediaLibrary::windowTimeout()
|
int MediaLibrary::windowTimeout()
|
||||||
{
|
{
|
||||||
|
ScopedUnfilteredMenu<AlbumEntry> sunfilter_albums(ReapplyFilter::No, Albums);
|
||||||
|
ScopedUnfilteredMenu<MPD::Song> sunfilter_songs(ReapplyFilter::No, Songs);
|
||||||
if (Albums.empty() || Songs.empty())
|
if (Albums.empty() || Songs.empty())
|
||||||
return m_window_timeout;
|
return m_window_timeout;
|
||||||
else
|
else
|
||||||
@@ -596,6 +604,68 @@ bool MediaLibrary::search(SearchDirection direction, bool wrap, bool skip_curren
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MediaLibrary::currentFilter()
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
if (isActiveWindow(Tags))
|
||||||
|
{
|
||||||
|
if (auto pred = Tags.filterPredicate<Regex::Filter<PrimaryTag>>())
|
||||||
|
result = pred->constraint();
|
||||||
|
}
|
||||||
|
else if (isActiveWindow(Albums))
|
||||||
|
{
|
||||||
|
if (auto pred = Albums.filterPredicate<Regex::ItemFilter<AlbumEntry>>())
|
||||||
|
result = pred->constraint();
|
||||||
|
}
|
||||||
|
else if (isActiveWindow(Songs))
|
||||||
|
{
|
||||||
|
if (auto pred = Songs.filterPredicate<Regex::Filter<MPD::Song>>())
|
||||||
|
result = pred->constraint();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaLibrary::applyFilter(const std::string &constraint)
|
||||||
|
{
|
||||||
|
if (isActiveWindow(Tags))
|
||||||
|
{
|
||||||
|
if (!constraint.empty())
|
||||||
|
{
|
||||||
|
Tags.applyFilter(Regex::Filter<PrimaryTag>(
|
||||||
|
constraint,
|
||||||
|
Config.regex_type,
|
||||||
|
TagEntryMatcher));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Tags.clearFilter();
|
||||||
|
}
|
||||||
|
else if (isActiveWindow(Albums))
|
||||||
|
{
|
||||||
|
if (!constraint.empty())
|
||||||
|
{
|
||||||
|
Albums.applyFilter(Regex::ItemFilter<AlbumEntry>(
|
||||||
|
constraint,
|
||||||
|
Config.regex_type,
|
||||||
|
std::bind(AlbumEntryMatcher, ph::_1, ph::_2, true)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Albums.clearFilter();
|
||||||
|
}
|
||||||
|
else if (isActiveWindow(Songs))
|
||||||
|
{
|
||||||
|
if (!constraint.empty())
|
||||||
|
{
|
||||||
|
Songs.applyFilter(Regex::Filter<MPD::Song>(
|
||||||
|
constraint,
|
||||||
|
Config.regex_type,
|
||||||
|
SongEntryMatcher));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Songs.clearFilter();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
bool MediaLibrary::itemAvailable()
|
bool MediaLibrary::itemAvailable()
|
||||||
@@ -701,6 +771,7 @@ std::vector<MPD::Song> MediaLibrary::getSelectedSongs()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if no item is selected, add songs from right column
|
// if no item is selected, add songs from right column
|
||||||
|
ScopedUnfilteredMenu<MPD::Song> sunfilter_songs(ReapplyFilter::No, Songs);
|
||||||
if (!any_selected && !Albums.empty())
|
if (!any_selected && !Albums.empty())
|
||||||
{
|
{
|
||||||
size_t begin = result.size();
|
size_t begin = result.size();
|
||||||
@@ -724,11 +795,13 @@ bool MediaLibrary::previousColumnAvailable()
|
|||||||
assert(!hasTwoColumns || !isActiveWindow(Tags));
|
assert(!hasTwoColumns || !isActiveWindow(Tags));
|
||||||
if (isActiveWindow(Songs))
|
if (isActiveWindow(Songs))
|
||||||
{
|
{
|
||||||
if (!Albums.empty() && (hasTwoColumns || !Tags.empty()))
|
ScopedUnfilteredMenu<AlbumEntry> sunfilter_albums(ReapplyFilter::No, Albums);
|
||||||
|
if (!Albums.empty())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (isActiveWindow(Albums))
|
else if (isActiveWindow(Albums))
|
||||||
{
|
{
|
||||||
|
ScopedUnfilteredMenu<PrimaryTag> sunfilter_tags(ReapplyFilter::No, Tags);
|
||||||
if (!hasTwoColumns && !Tags.empty())
|
if (!hasTwoColumns && !Tags.empty())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -758,11 +831,13 @@ bool MediaLibrary::nextColumnAvailable()
|
|||||||
assert(!hasTwoColumns || !isActiveWindow(Tags));
|
assert(!hasTwoColumns || !isActiveWindow(Tags));
|
||||||
if (isActiveWindow(Tags))
|
if (isActiveWindow(Tags))
|
||||||
{
|
{
|
||||||
if (!Albums.empty() && !Songs.empty())
|
ScopedUnfilteredMenu<AlbumEntry> sunfilter_albums(ReapplyFilter::No, Albums);
|
||||||
|
if (!Albums.empty())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (isActiveWindow(Albums))
|
else if (isActiveWindow(Albums))
|
||||||
{
|
{
|
||||||
|
ScopedUnfilteredMenu<MPD::Song> sunfilter_songs(ReapplyFilter::No, Songs);
|
||||||
if (!Songs.empty())
|
if (!Songs.empty())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -818,7 +893,7 @@ void MediaLibrary::toggleColumnsMode()
|
|||||||
resize();
|
resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
int MediaLibrary::Columns()
|
int MediaLibrary::columns()
|
||||||
{
|
{
|
||||||
if (hasTwoColumns)
|
if (hasTwoColumns)
|
||||||
return 2;
|
return 2;
|
||||||
@@ -833,6 +908,7 @@ void MediaLibrary::toggleSortMode()
|
|||||||
Config.media_library_sort_by_mtime ? "modification time" : "name");
|
Config.media_library_sort_by_mtime ? "modification time" : "name");
|
||||||
if (hasTwoColumns)
|
if (hasTwoColumns)
|
||||||
{
|
{
|
||||||
|
ScopedUnfilteredMenu<AlbumEntry> sunfilter_albums(ReapplyFilter::No, Albums);
|
||||||
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
||||||
Albums.refresh();
|
Albums.refresh();
|
||||||
Songs.clear();
|
Songs.clear();
|
||||||
@@ -846,6 +922,7 @@ void MediaLibrary::toggleSortMode()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ScopedUnfilteredMenu<PrimaryTag> sunfilter_tags(ReapplyFilter::No, Tags);
|
||||||
// if we already have modification times, just resort. otherwise refetch the list.
|
// if we already have modification times, just resort. otherwise refetch the list.
|
||||||
if (!Tags.empty() && Tags[0].value().mtime() > 0)
|
if (!Tags.empty() && Tags[0].value().mtime() > 0)
|
||||||
{
|
{
|
||||||
@@ -853,14 +930,16 @@ void MediaLibrary::toggleSortMode()
|
|||||||
Tags.refresh();
|
Tags.refresh();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Tags.clear();
|
Tags.clear();
|
||||||
|
}
|
||||||
Albums.clear();
|
Albums.clear();
|
||||||
Songs.clear();
|
Songs.clear();
|
||||||
}
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaLibrary::LocateSong(const MPD::Song &s)
|
void MediaLibrary::locateSong(const MPD::Song &s)
|
||||||
{
|
{
|
||||||
std::string primary_tag = s.get(Config.media_lib_primary_tag);
|
std::string primary_tag = s.get(Config.media_lib_primary_tag);
|
||||||
if (primary_tag.empty())
|
if (primary_tag.empty())
|
||||||
@@ -884,6 +963,7 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
|||||||
|
|
||||||
if (!hasTwoColumns)
|
if (!hasTwoColumns)
|
||||||
{
|
{
|
||||||
|
Tags.clearFilter();
|
||||||
if (Tags.empty())
|
if (Tags.empty())
|
||||||
update();
|
update();
|
||||||
|
|
||||||
@@ -902,6 +982,7 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
|||||||
Albums.clear();
|
Albums.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Albums.clearFilter();
|
||||||
if (Albums.empty())
|
if (Albums.empty())
|
||||||
update();
|
update();
|
||||||
|
|
||||||
@@ -939,6 +1020,7 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
|||||||
MoveToAlbum(Albums, primary_tag, s);
|
MoveToAlbum(Albums, primary_tag, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Songs.clearFilter();
|
||||||
Songs.clear();
|
Songs.clear();
|
||||||
update();
|
update();
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ struct MediaLibrary: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tab
|
|||||||
virtual void clearSearchConstraint() OVERRIDE;
|
virtual void clearSearchConstraint() OVERRIDE;
|
||||||
virtual bool search(SearchDirection direction, bool wrap, bool skip_current) 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
|
// HasSongs implementation
|
||||||
virtual bool itemAvailable() OVERRIDE;
|
virtual bool itemAvailable() OVERRIDE;
|
||||||
virtual bool addItemToPlaylist(bool play) OVERRIDE;
|
virtual bool addItemToPlaylist(bool play) OVERRIDE;
|
||||||
@@ -67,11 +70,11 @@ struct MediaLibrary: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tab
|
|||||||
virtual bool nextColumnAvailable() OVERRIDE;
|
virtual bool nextColumnAvailable() OVERRIDE;
|
||||||
virtual void nextColumn() OVERRIDE;
|
virtual void nextColumn() OVERRIDE;
|
||||||
|
|
||||||
// private members
|
// other members
|
||||||
void updateTimer();
|
void updateTimer();
|
||||||
void toggleColumnsMode();
|
void toggleColumnsMode();
|
||||||
int Columns();
|
int columns();
|
||||||
void LocateSong(const MPD::Song &);
|
void locateSong(const MPD::Song &s);
|
||||||
void toggleSortMode();
|
void toggleSortMode();
|
||||||
|
|
||||||
void requestTagsUpdate() { m_tags_update_request = true; }
|
void requestTagsUpdate() { m_tags_update_request = true; }
|
||||||
|
|||||||
@@ -336,10 +336,9 @@ void Menu<ItemT>::reset()
|
|||||||
template <typename ItemT>
|
template <typename ItemT>
|
||||||
void Menu<ItemT>::clear()
|
void Menu<ItemT>::clear()
|
||||||
{
|
{
|
||||||
// Don't clear the filter here.
|
// Don't clear filter related stuff here.
|
||||||
m_all_items.clear();
|
m_all_items.clear();
|
||||||
m_filtered_items.clear();
|
m_filtered_items.clear();
|
||||||
m_items = &m_all_items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ItemT>
|
template <typename ItemT>
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ MPD::Song Playlist::nowPlayingSong()
|
|||||||
MPD::Song s;
|
MPD::Song s;
|
||||||
if (Status::State::player() != MPD::psUnknown)
|
if (Status::State::player() != MPD::psUnknown)
|
||||||
{
|
{
|
||||||
ScopedUnfilteredMenu<MPD::Song, ReapplyFilter::No> sunfilter(w);
|
ScopedUnfilteredMenu<MPD::Song> sunfilter(ReapplyFilter::No, w);
|
||||||
auto sp = Status::State::currentSongPosition();
|
auto sp = Status::State::currentSongPosition();
|
||||||
if (sp >= 0 && size_t(sp) < w.size())
|
if (sp >= 0 && size_t(sp) < w.size())
|
||||||
s = w.at(sp).value();
|
s = w.at(sp).value();
|
||||||
@@ -231,7 +231,7 @@ MPD::Song Playlist::nowPlayingSong()
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Playlist::moveToSong(const MPD::Song &s)
|
void Playlist::locateSong(const MPD::Song &s)
|
||||||
{
|
{
|
||||||
if (!w.isFiltered())
|
if (!w.isFiltered())
|
||||||
w.highlight(s.getPosition());
|
w.highlight(s.getPosition());
|
||||||
@@ -268,7 +268,7 @@ std::string Playlist::getTotalLength()
|
|||||||
}
|
}
|
||||||
if (Config.playlist_show_remaining_time && m_reload_remaining)
|
if (Config.playlist_show_remaining_time && m_reload_remaining)
|
||||||
{
|
{
|
||||||
ScopedUnfilteredMenu<MPD::Song, ReapplyFilter::No> sunfilter(w);
|
ScopedUnfilteredMenu<MPD::Song> sunfilter(ReapplyFilter::No, w);
|
||||||
m_remaining_time = 0;
|
m_remaining_time = 0;
|
||||||
for (size_t i = Status::State::currentSongPosition(); i < w.size(); ++i)
|
for (size_t i = Status::State::currentSongPosition(); i < w.size(); ++i)
|
||||||
m_remaining_time += w[i].value().getDuration();
|
m_remaining_time += w[i].value().getDuration();
|
||||||
@@ -279,7 +279,7 @@ std::string Playlist::getTotalLength()
|
|||||||
|
|
||||||
if (w.isFiltered())
|
if (w.isFiltered())
|
||||||
{
|
{
|
||||||
ScopedUnfilteredMenu<MPD::Song, ReapplyFilter::No> sunfilter(w);
|
ScopedUnfilteredMenu<MPD::Song> sunfilter(ReapplyFilter::No, w);
|
||||||
result << " (out of " << w.size() << ")";
|
result << " (out of " << w.size() << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ struct Playlist: Screen<SongMenu>, HasSongs, Searchable, Tabbable
|
|||||||
// other members
|
// other members
|
||||||
MPD::Song nowPlayingSong();
|
MPD::Song nowPlayingSong();
|
||||||
|
|
||||||
// Move to given song from playlist.
|
// Locate song in playlist.
|
||||||
void moveToSong(const MPD::Song &s);
|
void locateSong(const MPD::Song &s);
|
||||||
|
|
||||||
void enableHighlighting();
|
void enableHighlighting();
|
||||||
|
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ int Status::State::volume()
|
|||||||
void Status::Changes::playlist(unsigned previous_version)
|
void Status::Changes::playlist(unsigned previous_version)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
ScopedUnfilteredMenu<MPD::Song, ReapplyFilter::Yes> sunfilter(myPlaylist->main());
|
ScopedUnfilteredMenu<MPD::Song> sunfilter(ReapplyFilter::Yes, myPlaylist->main());
|
||||||
|
|
||||||
if (m_playlist_length < myPlaylist->main().size())
|
if (m_playlist_length < myPlaylist->main().size())
|
||||||
{
|
{
|
||||||
@@ -580,7 +580,7 @@ void Status::Changes::songID(int song_id)
|
|||||||
drawTitle(s);
|
drawTitle(s);
|
||||||
|
|
||||||
if (Config.autocenter_mode)
|
if (Config.autocenter_mode)
|
||||||
myPlaylist->moveToSong(s);
|
myPlaylist->locateSong(s);
|
||||||
|
|
||||||
if (Config.now_playing_lyrics && isVisible(myLyrics) && myLyrics->previousScreen() == myPlaylist)
|
if (Config.now_playing_lyrics && isVisible(myLyrics) && myLyrics->previousScreen() == myPlaylist)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user