implement HasSongs interface
This commit is contained in:
@@ -19,7 +19,6 @@ ncmpcpp_SOURCES = \
|
|||||||
lyrics.cpp \
|
lyrics.cpp \
|
||||||
lyrics_fetcher.cpp \
|
lyrics_fetcher.cpp \
|
||||||
media_library.cpp \
|
media_library.cpp \
|
||||||
menu.cpp \
|
|
||||||
mpdpp.cpp \
|
mpdpp.cpp \
|
||||||
mutable_song.cpp \
|
mutable_song.cpp \
|
||||||
ncmpcpp.cpp \
|
ncmpcpp.cpp \
|
||||||
|
|||||||
104
src/actions.cpp
104
src/actions.cpp
@@ -503,7 +503,8 @@ void ScrollDown::Run()
|
|||||||
|
|
||||||
void ScrollUpArtist::Run()
|
void ScrollUpArtist::Run()
|
||||||
{
|
{
|
||||||
List *mList = myScreen->GetList();
|
// FIXME
|
||||||
|
/*List *mList = myScreen->GetList();
|
||||||
if (!mList || mList->Empty())
|
if (!mList || mList->Empty())
|
||||||
return;
|
return;
|
||||||
size_t pos = mList->Choice();
|
size_t pos = mList->Choice();
|
||||||
@@ -517,12 +518,13 @@ void ScrollUpArtist::Run()
|
|||||||
if (!s || s->getArtist() != artist)
|
if (!s || s->getArtist() != artist)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollUpAlbum::Run()
|
void ScrollUpAlbum::Run()
|
||||||
{
|
{
|
||||||
List *mList = myScreen->GetList();
|
// FIXME
|
||||||
|
/*List *mList = myScreen->GetList();
|
||||||
if (!mList || mList->Empty())
|
if (!mList || mList->Empty())
|
||||||
return;
|
return;
|
||||||
size_t pos = mList->Choice();
|
size_t pos = mList->Choice();
|
||||||
@@ -536,12 +538,13 @@ void ScrollUpAlbum::Run()
|
|||||||
if (!s || s->getAlbum() != album)
|
if (!s || s->getAlbum() != album)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollDownArtist::Run()
|
void ScrollDownArtist::Run()
|
||||||
{
|
{
|
||||||
List *mList = myScreen->GetList();
|
// FIXME
|
||||||
|
/*List *mList = myScreen->GetList();
|
||||||
if (!mList || mList->Empty())
|
if (!mList || mList->Empty())
|
||||||
return;
|
return;
|
||||||
size_t pos = mList->Choice();
|
size_t pos = mList->Choice();
|
||||||
@@ -555,12 +558,13 @@ void ScrollDownArtist::Run()
|
|||||||
if (!s || s->getArtist() != artist)
|
if (!s || s->getArtist() != artist)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollDownAlbum::Run()
|
void ScrollDownAlbum::Run()
|
||||||
{
|
{
|
||||||
List *mList = myScreen->GetList();
|
// FIXME
|
||||||
|
/*List *mList = myScreen->GetList();
|
||||||
if (!mList || mList->Empty())
|
if (!mList || mList->Empty())
|
||||||
return;
|
return;
|
||||||
size_t pos = mList->Choice();
|
size_t pos = mList->Choice();
|
||||||
@@ -574,7 +578,7 @@ void ScrollDownAlbum::Run()
|
|||||||
if (!s || s->getAlbum() != album)
|
if (!s || s->getAlbum() != album)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageUp::Run()
|
void PageUp::Run()
|
||||||
@@ -769,7 +773,7 @@ void Delete::Run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Mpd.DeleteID(myPlaylist->CurrentSong()->getID());
|
Mpd.DeleteID(myPlaylist->currentSong()->getID());
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
(myScreen == myBrowser && !myBrowser->Main()->Empty() && myBrowser->CurrentDir() == "/" && myBrowser->Main()->Current().value().type == itPlaylist)
|
(myScreen == myBrowser && !myBrowser->Main()->Empty() && myBrowser->CurrentDir() == "/" && myBrowser->Main()->Current().value().type == itPlaylist)
|
||||||
@@ -1184,13 +1188,9 @@ void ToggleDisplayMode::Run()
|
|||||||
Config.columns_in_playlist_editor = !Config.columns_in_playlist_editor;
|
Config.columns_in_playlist_editor = !Config.columns_in_playlist_editor;
|
||||||
ShowMessage("Playlist editor display mode: %s", Config.columns_in_playlist_editor ? "Columns" : "Classic");
|
ShowMessage("Playlist editor display mode: %s", Config.columns_in_playlist_editor ? "Columns" : "Classic");
|
||||||
if (Config.columns_in_playlist_editor)
|
if (Config.columns_in_playlist_editor)
|
||||||
{
|
|
||||||
myPlaylistEditor->Content->setItemDisplayer(std::bind(Display::SongsInColumns, _1, *myPlaylistEditor));
|
myPlaylistEditor->Content->setItemDisplayer(std::bind(Display::SongsInColumns, _1, *myPlaylistEditor));
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
myPlaylistEditor->Content->setItemDisplayer(std::bind(Display::Songs, _1, *myPlaylistEditor, Config.song_list_format));
|
myPlaylistEditor->Content->setItemDisplayer(std::bind(Display::Songs, _1, *myPlaylistEditor, Config.song_list_format));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1377,7 +1377,8 @@ void SetCrossfade::Run()
|
|||||||
bool EditSong::canBeRun() const
|
bool EditSong::canBeRun() const
|
||||||
{
|
{
|
||||||
# ifdef HAVE_TAGLIB_H
|
# ifdef HAVE_TAGLIB_H
|
||||||
return myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
return w && w->currentSong();
|
||||||
# else
|
# else
|
||||||
return false;
|
return false;
|
||||||
# endif // HAVE_TAGLIB_H
|
# endif // HAVE_TAGLIB_H
|
||||||
@@ -1388,7 +1389,9 @@ void EditSong::Run()
|
|||||||
# ifdef HAVE_TAGLIB_H
|
# ifdef HAVE_TAGLIB_H
|
||||||
if (!isMPDMusicDirSet())
|
if (!isMPDMusicDirSet())
|
||||||
return;
|
return;
|
||||||
const MPD::Song *s = myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
assert(w);
|
||||||
|
auto s = w->currentSong();
|
||||||
assert(s);
|
assert(s);
|
||||||
myTinyTagEditor->SetEdited(*s);
|
myTinyTagEditor->SetEdited(*s);
|
||||||
myTinyTagEditor->SwitchTo();
|
myTinyTagEditor->SwitchTo();
|
||||||
@@ -1424,11 +1427,10 @@ void EditLibraryTag::Run()
|
|||||||
MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag);
|
MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag);
|
||||||
assert(set);
|
assert(set);
|
||||||
bool success = true;
|
bool success = true;
|
||||||
std::string dir_to_update;
|
MPD::SongList songs = Mpd.CommitSearchSongs();
|
||||||
Mpd.CommitSearchSongs([set, &new_tag, &success, &dir_to_update](MPD::Song &&s) {
|
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||||
if (!success)
|
{
|
||||||
return;
|
MPD::MutableSong es = *s;
|
||||||
MPD::MutableSong es = s;
|
|
||||||
es.setTag(set, new_tag);
|
es.setTag(set, new_tag);
|
||||||
ShowMessage("Updating tags in \"%s\"...", es.getName().c_str());
|
ShowMessage("Updating tags in \"%s\"...", es.getName().c_str());
|
||||||
std::string path = Config.mpd_music_dir + es.getURI();
|
std::string path = Config.mpd_music_dir + es.getURI();
|
||||||
@@ -1437,15 +1439,12 @@ void EditLibraryTag::Run()
|
|||||||
const char msg[] = "Error while updating tags in \"%s\"";
|
const char msg[] = "Error while updating tags in \"%s\"";
|
||||||
ShowMessage(msg, Shorten(TO_WSTRING(es.getURI()), COLS-const_strlen(msg)).c_str());
|
ShowMessage(msg, Shorten(TO_WSTRING(es.getURI()), COLS-const_strlen(msg)).c_str());
|
||||||
success = false;
|
success = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (dir_to_update.empty())
|
}
|
||||||
dir_to_update = es.getDirectory();
|
|
||||||
else
|
|
||||||
getSharedDirectory(es.getDirectory(), dir_to_update);
|
|
||||||
});
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
Mpd.UpdateDirectory(dir_to_update);
|
Mpd.UpdateDirectory(getSharedDirectory(songs.begin(), songs.end()));
|
||||||
ShowMessage("Tags updated successfully");
|
ShowMessage("Tags updated successfully");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1500,7 +1499,7 @@ void EditLibraryAlbum::Run()
|
|||||||
}
|
}
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
Mpd.UpdateDirectory(getSharedDirectory(myLibrary->Songs));
|
Mpd.UpdateDirectory(getSharedDirectory(myLibrary->Songs->BeginV(), myLibrary->Songs->EndV()));
|
||||||
ShowMessage("Tags updated successfully");
|
ShowMessage("Tags updated successfully");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1635,24 +1634,29 @@ void EditLyrics::Run()
|
|||||||
|
|
||||||
bool JumpToBrowser::canBeRun() const
|
bool JumpToBrowser::canBeRun() const
|
||||||
{
|
{
|
||||||
return myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
return w && w->currentSong();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JumpToBrowser::Run()
|
void JumpToBrowser::Run()
|
||||||
{
|
{
|
||||||
MPD::Song *s = myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
auto s = w->currentSong();
|
||||||
assert(s);
|
assert(s);
|
||||||
myBrowser->LocateSong(*s);
|
myBrowser->LocateSong(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JumpToMediaLibrary::canBeRun() const
|
bool JumpToMediaLibrary::canBeRun() const
|
||||||
{
|
{
|
||||||
return myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
return w && w->currentSong();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JumpToMediaLibrary::Run()
|
void JumpToMediaLibrary::Run()
|
||||||
{
|
{
|
||||||
MPD::Song *s = myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
assert(w);
|
||||||
|
auto s = w->currentSong();
|
||||||
assert(s);
|
assert(s);
|
||||||
myLibrary->LocateSong(*s);
|
myLibrary->LocateSong(*s);
|
||||||
}
|
}
|
||||||
@@ -1708,7 +1712,8 @@ void ToggleScreenLock::Run()
|
|||||||
bool JumpToTagEditor::canBeRun() const
|
bool JumpToTagEditor::canBeRun() const
|
||||||
{
|
{
|
||||||
# ifdef HAVE_TAGLIB_H
|
# ifdef HAVE_TAGLIB_H
|
||||||
return myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
return w && w->currentSong();
|
||||||
# else
|
# else
|
||||||
return false;
|
return false;
|
||||||
# endif // HAVE_TAGLIB_H
|
# endif // HAVE_TAGLIB_H
|
||||||
@@ -1719,7 +1724,9 @@ void JumpToTagEditor::Run()
|
|||||||
# ifdef HAVE_TAGLIB_H
|
# ifdef HAVE_TAGLIB_H
|
||||||
if (!isMPDMusicDirSet())
|
if (!isMPDMusicDirSet())
|
||||||
return;
|
return;
|
||||||
MPD::Song *s = myScreen->CurrentSong();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
assert(w);
|
||||||
|
auto s = w->currentSong();
|
||||||
assert(s);
|
assert(s);
|
||||||
myTagEditor->LocateSong(*s);
|
myTagEditor->LocateSong(*s);
|
||||||
# endif // HAVE_TAGLIB_H
|
# endif // HAVE_TAGLIB_H
|
||||||
@@ -1780,32 +1787,35 @@ void JumpToPositionInSong::Run()
|
|||||||
|
|
||||||
bool ReverseSelection::canBeRun() const
|
bool ReverseSelection::canBeRun() const
|
||||||
{
|
{
|
||||||
return myScreen->allowsSelection();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
return w && w->allowsSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReverseSelection::Run()
|
void ReverseSelection::Run()
|
||||||
{
|
{
|
||||||
myScreen->ReverseSelection();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
assert(w);
|
||||||
|
w->reverseSelection();
|
||||||
ShowMessage("Selection reversed");
|
ShowMessage("Selection reversed");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeselectItems::canBeRun() const
|
bool DeselectItems::canBeRun() const
|
||||||
{
|
{
|
||||||
return myScreen->allowsSelection();
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
return w && w->allowsSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeselectItems::Run()
|
void DeselectItems::Run()
|
||||||
{
|
{
|
||||||
// FIXME
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
/*List *mList = myScreen->GetList();
|
assert(w);
|
||||||
for (size_t i = 0; i < mList->Size(); ++i)
|
w->removeSelection();
|
||||||
mList->Select(i, 0);
|
|
||||||
ShowMessage("Items deselected");*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SelectAlbum::canBeRun() const
|
bool SelectAlbum::canBeRun() const
|
||||||
{
|
{
|
||||||
return myScreen->allowsSelection()
|
auto w = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
return w && w->allowsSelection()
|
||||||
&& myScreen->GetList();
|
&& myScreen->GetList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2334,12 +2344,14 @@ void ShowSongInfo::Run()
|
|||||||
mySongInfo->SwitchTo();
|
mySongInfo->SwitchTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_CURL_CURL_H
|
|
||||||
bool ShowArtistInfo::canBeRun() const
|
bool ShowArtistInfo::canBeRun() const
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_CURL_CURL_H
|
||||||
|
return myScreen == myLastfm || dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
# else
|
||||||
return false;
|
return false;
|
||||||
|
# endif // NOT HAVE_CURL_CURL_H
|
||||||
}
|
}
|
||||||
#endif // NOT HAVE_CURL_CURL_H
|
|
||||||
|
|
||||||
void ShowArtistInfo::Run()
|
void ShowArtistInfo::Run()
|
||||||
{
|
{
|
||||||
@@ -2351,7 +2363,9 @@ void ShowArtistInfo::Run()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string artist;
|
std::string artist;
|
||||||
MPD::Song *s = myScreen->CurrentSong();
|
auto hs = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
assert(hs);
|
||||||
|
auto s = hs->currentSong();
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
artist = s->getArtist();
|
artist = s->getArtist();
|
||||||
|
|||||||
@@ -766,9 +766,7 @@ struct ShowSongInfo : public Action
|
|||||||
struct ShowArtistInfo : public Action
|
struct ShowArtistInfo : public Action
|
||||||
{
|
{
|
||||||
ShowArtistInfo() : Action(aShowArtistInfo, "show_artist_info") { }
|
ShowArtistInfo() : Action(aShowArtistInfo, "show_artist_info") { }
|
||||||
# ifndef HAVE_CURL_CURL_H
|
|
||||||
virtual bool canBeRun() const;
|
virtual bool canBeRun() const;
|
||||||
# endif // NOT HAVE_CURL_CURL_H
|
|
||||||
virtual void Run();
|
virtual void Run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
141
src/browser.cpp
141
src/browser.cpp
@@ -263,68 +263,6 @@ void Browser::MouseButtonPressed(MEVENT me)
|
|||||||
Screen< Menu<MPD::Item> >::MouseButtonPressed(me);
|
Screen< Menu<MPD::Item> >::MouseButtonPressed(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::Song *Browser::CurrentSong()
|
|
||||||
{
|
|
||||||
const MPD::Item &item = w->Current().value();
|
|
||||||
if (!w->Empty() && item.type == itSong)
|
|
||||||
return item.song.get();
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Browser::ReverseSelection()
|
|
||||||
{
|
|
||||||
w->ReverseSelection(itsBrowsedDir == "/" ? 0 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Browser::GetSelectedSongs(MPD::SongList &v)
|
|
||||||
{
|
|
||||||
if (w->Empty())
|
|
||||||
return;
|
|
||||||
std::vector<size_t> selected;
|
|
||||||
w->GetSelected(selected);
|
|
||||||
if (selected.empty())
|
|
||||||
selected.push_back(w->Choice());
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
{
|
|
||||||
const MPD::Item &item = w->at(*it).value();
|
|
||||||
switch (item.type)
|
|
||||||
{
|
|
||||||
case itDirectory:
|
|
||||||
{
|
|
||||||
# ifndef WIN32
|
|
||||||
if (isLocal())
|
|
||||||
{
|
|
||||||
MPD::ItemList list;
|
|
||||||
GetLocalDirectory(list, item.name, 1);
|
|
||||||
for (auto j = list.begin(); j != list.end(); ++j)
|
|
||||||
v.push_back(*j->song);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
# endif // !WIN32
|
|
||||||
{
|
|
||||||
Mpd.GetDirectoryRecursive(locale_to_utf_cpy(item.name), [&v](MPD::Song &&s) {
|
|
||||||
v.push_back(s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case itSong:
|
|
||||||
{
|
|
||||||
v.push_back(*item.song);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case itPlaylist:
|
|
||||||
{
|
|
||||||
Mpd.GetPlaylistContent(locale_to_utf_cpy(item.name), [&v](MPD::Song &&s) {
|
|
||||||
v.push_back(s);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
std::string Browser::currentFilter()
|
std::string Browser::currentFilter()
|
||||||
@@ -361,6 +299,75 @@ void Browser::prevFound(bool wrap)
|
|||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
|
MPD::Song *Browser::getSong(size_t pos)
|
||||||
|
{
|
||||||
|
MPD::Song *ptr = 0;
|
||||||
|
if ((*w)[pos].value().type == itSong)
|
||||||
|
ptr = (*w)[pos].value().song.get();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::Song *Browser::currentSong()
|
||||||
|
{
|
||||||
|
if (w->Empty())
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return getSong(w->Choice());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Browser::allowsSelection()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Browser::removeSelection()
|
||||||
|
{
|
||||||
|
removeSelectionHelper(w->Begin(), w->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Browser::reverseSelection()
|
||||||
|
{
|
||||||
|
reverseSelectionHelper(w->Begin()+(itsBrowsedDir == "/" ? 0 : 1), w->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::SongList Browser::getSelectedSongs()
|
||||||
|
{
|
||||||
|
MPD::SongList result;
|
||||||
|
auto item_handler = [this, &result](const MPD::Item &item) {
|
||||||
|
if (item.type == itDirectory)
|
||||||
|
{
|
||||||
|
# ifndef WIN32
|
||||||
|
if (isLocal())
|
||||||
|
{
|
||||||
|
MPD::ItemList list;
|
||||||
|
GetLocalDirectory(list, item.name, true);
|
||||||
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
|
result.push_back(*it->song);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
# endif // !WIN32
|
||||||
|
{
|
||||||
|
auto list = Mpd.GetDirectoryRecursive(item.name);
|
||||||
|
result.insert(result.end(), list.begin(), list.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (item.type == itSong)
|
||||||
|
result.push_back(*item.song);
|
||||||
|
else if (item.type == itPlaylist)
|
||||||
|
{
|
||||||
|
auto list = Mpd.GetPlaylistContent(item.name);
|
||||||
|
result.insert(result.end(), list.begin(), list.end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (auto it = w->Begin(); it != w->End(); ++it)
|
||||||
|
if (it->isSelected())
|
||||||
|
item_handler(it->value());
|
||||||
|
// if no item is selected, add current one
|
||||||
|
if (result.empty() && !w->Empty())
|
||||||
|
item_handler(w->Current().value());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Browser::LocateSong(const MPD::Song &s)
|
void Browser::LocateSong(const MPD::Song &s)
|
||||||
{
|
{
|
||||||
if (s.getDirectory().empty())
|
if (s.getDirectory().empty())
|
||||||
@@ -411,15 +418,9 @@ void Browser::GetDirectory(std::string dir, std::string subdir)
|
|||||||
if (isLocal())
|
if (isLocal())
|
||||||
GetLocalDirectory(list);
|
GetLocalDirectory(list);
|
||||||
else
|
else
|
||||||
{
|
list = Mpd.GetDirectory(dir);
|
||||||
Mpd.GetDirectory(dir, [&list](MPD::Item &&i) {
|
|
||||||
list.push_back(i);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
# else
|
# else
|
||||||
Mpd.GetDirectory(dir, [&list](MPD::Item &&i) {
|
list = Mpd.GetDirectory(dir);
|
||||||
list.push_back(i);
|
|
||||||
});
|
|
||||||
# endif // !WIN32
|
# endif // !WIN32
|
||||||
if (!isLocal()) // local directory is already sorted
|
if (!isLocal()) // local directory is already sorted
|
||||||
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "regex_filter.h"
|
#include "regex_filter.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
|
||||||
class Browser : public Screen< Menu<MPD::Item> >, public Filterable, public Searchable
|
class Browser : public Screen< Menu<MPD::Item> >, public Filterable, public HasSongs, public Searchable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Browser() : itsBrowseLocally(0), itsScrollBeginning(0), itsBrowsedDir("/") { }
|
Browser() : itsBrowseLocally(0), itsScrollBeginning(0), itsBrowsedDir("/") { }
|
||||||
@@ -41,13 +41,6 @@ class Browser : public Screen< Menu<MPD::Item> >, public Filterable, public Sear
|
|||||||
virtual void MouseButtonPressed(MEVENT);
|
virtual void MouseButtonPressed(MEVENT);
|
||||||
virtual bool isTabbable() { return true; }
|
virtual bool isTabbable() { return true; }
|
||||||
|
|
||||||
virtual MPD::Song *CurrentSong();
|
|
||||||
virtual MPD::Song *GetSong(size_t pos) { return w->at(pos).value().type == MPD::itSong ? (*w)[pos].value().song.get() : 0; }
|
|
||||||
|
|
||||||
virtual bool allowsSelection() { return true; }
|
|
||||||
virtual void ReverseSelection();
|
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
|
||||||
|
|
||||||
/// Filterable implementation
|
/// Filterable implementation
|
||||||
virtual std::string currentFilter();
|
virtual std::string currentFilter();
|
||||||
virtual void applyFilter(const std::string &filter);
|
virtual void applyFilter(const std::string &filter);
|
||||||
@@ -57,6 +50,15 @@ class Browser : public Screen< Menu<MPD::Item> >, public Filterable, public Sear
|
|||||||
virtual void nextFound(bool wrap);
|
virtual void nextFound(bool wrap);
|
||||||
virtual void prevFound(bool wrap);
|
virtual void prevFound(bool wrap);
|
||||||
|
|
||||||
|
/// HasSongs implementation
|
||||||
|
virtual MPD::Song *getSong(size_t pos);
|
||||||
|
virtual MPD::Song *currentSong();
|
||||||
|
|
||||||
|
virtual bool allowsSelection();
|
||||||
|
virtual void reverseSelection();
|
||||||
|
virtual void removeSelection();
|
||||||
|
virtual MPD::SongList getSelectedSongs();
|
||||||
|
|
||||||
virtual List *GetList() { return w; }
|
virtual List *GetList() { return w; }
|
||||||
|
|
||||||
virtual bool isMergable() { return true; }
|
virtual bool isMergable() { return true; }
|
||||||
|
|||||||
@@ -73,13 +73,13 @@ const my_char_t *toColumnName(char c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void setProperties(Menu<T> &menu, const MPD::Song &s, BasicScreen &screen, bool &separate_albums,
|
void setProperties(Menu<T> &menu, const MPD::Song &s, HasSongs &screen, bool &separate_albums,
|
||||||
bool &is_now_playing, bool &is_selected, bool &discard_colors)
|
bool &is_now_playing, bool &is_selected, bool &discard_colors)
|
||||||
{
|
{
|
||||||
separate_albums = false;
|
separate_albums = false;
|
||||||
if (Config.playlist_separate_albums)
|
if (Config.playlist_separate_albums)
|
||||||
{
|
{
|
||||||
MPD::Song *next = screen.GetSong(menu.DrawnPosition()+1);
|
auto next = screen.getSong(menu.DrawnPosition()+1);
|
||||||
if (next && next->getAlbum() != s.getAlbum())
|
if (next && next->getAlbum() != s.getAlbum())
|
||||||
separate_albums = true;
|
separate_albums = true;
|
||||||
}
|
}
|
||||||
@@ -87,13 +87,14 @@ void setProperties(Menu<T> &menu, const MPD::Song &s, BasicScreen &screen, bool
|
|||||||
menu << fmtUnderline;
|
menu << fmtUnderline;
|
||||||
|
|
||||||
int song_pos = menu.isFiltered() ? s.getPosition() : menu.DrawnPosition();
|
int song_pos = menu.isFiltered() ? s.getPosition() : menu.DrawnPosition();
|
||||||
is_now_playing = song_pos == myPlaylist->NowPlaying && s.getID() > 0; // playlist
|
is_now_playing = static_cast<void *>(&menu) == myPlaylist->Items
|
||||||
|
&& song_pos == myPlaylist->NowPlaying;
|
||||||
is_selected = menu.Drawn().isSelected();
|
is_selected = menu.Drawn().isSelected();
|
||||||
discard_colors = Config.discard_colors_if_item_is_selected && is_selected;
|
discard_colors = Config.discard_colors_if_item_is_selected && is_selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void showSongs(Menu<T> &menu, const MPD::Song &s, BasicScreen &screen, const std::string &format)
|
void showSongs(Menu<T> &menu, const MPD::Song &s, HasSongs &screen, const std::string &format)
|
||||||
{
|
{
|
||||||
bool separate_albums, is_now_playing, is_selected, discard_colors;
|
bool separate_albums, is_now_playing, is_selected, discard_colors;
|
||||||
setProperties(menu, s, screen, separate_albums, is_now_playing, is_selected, discard_colors);
|
setProperties(menu, s, screen, separate_albums, is_now_playing, is_selected, discard_colors);
|
||||||
@@ -147,7 +148,7 @@ void showSongs(Menu<T> &menu, const MPD::Song &s, BasicScreen &screen, const std
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void showSongsInColumns(Menu<T> &menu, const MPD::Song &s, BasicScreen &screen)
|
void showSongsInColumns(Menu<T> &menu, const MPD::Song &s, HasSongs &screen)
|
||||||
{
|
{
|
||||||
if (Config.columns.empty())
|
if (Config.columns.empty())
|
||||||
return;
|
return;
|
||||||
@@ -332,12 +333,12 @@ std::string Display::Columns(size_t list_width)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::SongsInColumns(Menu<MPD::Song> &menu, BasicScreen &screen)
|
void Display::SongsInColumns(Menu<MPD::Song> &menu, HasSongs &screen)
|
||||||
{
|
{
|
||||||
showSongsInColumns(menu, menu.Drawn().value(), screen);
|
showSongsInColumns(menu, menu.Drawn().value(), screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::Songs(Menu<MPD::Song> &menu, BasicScreen &screen, const std::string &format)
|
void Display::Songs(Menu<MPD::Song> &menu, HasSongs &screen, const std::string &format)
|
||||||
{
|
{
|
||||||
showSongs(menu, menu.Drawn().value(), screen, format);
|
showSongs(menu, menu.Drawn().value(), screen, format);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,11 @@
|
|||||||
#ifndef _DISPLAY_H
|
#ifndef _DISPLAY_H
|
||||||
#define _DISPLAY_H
|
#define _DISPLAY_H
|
||||||
|
|
||||||
|
#include "interfaces.h"
|
||||||
#include "ncmpcpp.h"
|
#include "ncmpcpp.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
#include "mpdpp.h"
|
#include "mpdpp.h"
|
||||||
#include "mutable_song.h"
|
#include "mutable_song.h"
|
||||||
#include "screen.h"
|
|
||||||
#include "search_engine.h"
|
#include "search_engine.h"
|
||||||
|
|
||||||
namespace Display
|
namespace Display
|
||||||
@@ -42,9 +42,9 @@ namespace Display
|
|||||||
menu << menu.Drawn().value().first;
|
menu << menu.Drawn().value().first;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SongsInColumns(Menu<MPD::Song> &menu, BasicScreen &screen);
|
void SongsInColumns(Menu<MPD::Song> &menu, HasSongs &screen);
|
||||||
|
|
||||||
void Songs(Menu<MPD::Song> &menu, BasicScreen &screen, const std::string &format);
|
void Songs(Menu<MPD::Song> &menu, HasSongs &screen, const std::string &format);
|
||||||
|
|
||||||
void Tags(Menu<MPD::MutableSong> &menu);
|
void Tags(Menu<MPD::MutableSong> &menu);
|
||||||
|
|
||||||
|
|||||||
@@ -270,11 +270,6 @@ void ParseArgv(int argc, char **argv)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string StringPairToString(const std::pair<std::string, std::string> &pair)
|
|
||||||
{
|
|
||||||
return pair.first;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Timestamp(time_t t)
|
std::string Timestamp(time_t t)
|
||||||
{
|
{
|
||||||
char result[32];
|
char result[32];
|
||||||
@@ -306,26 +301,6 @@ void UpdateSongList(Menu<MPD::Song> *menu)
|
|||||||
menu->Refresh();
|
menu->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_TAGLIB_H
|
|
||||||
std::string getSharedDirectory(const MPD::SongList &v)
|
|
||||||
{
|
|
||||||
if (v.empty()) // this should never happen, but in case...
|
|
||||||
FatalError("empty SongList passed to getSharedDirectory(const SongList &)!");
|
|
||||||
size_t i = -1;
|
|
||||||
std::string first = v.front().getDirectory();
|
|
||||||
for (MPD::SongList::const_iterator it = ++v.begin(); it != v.end(); ++it)
|
|
||||||
{
|
|
||||||
size_t j = 0;
|
|
||||||
std::string dir = it->getDirectory();
|
|
||||||
size_t length = std::min(first.length(), dir.length());
|
|
||||||
while (!first.compare(j, 1, dir, j, 1) && j < length && j < i)
|
|
||||||
++j;
|
|
||||||
i = j;
|
|
||||||
}
|
|
||||||
return i ? first.substr(0, i) : "/";
|
|
||||||
}
|
|
||||||
#endif // HAVE_TAGLIB_H
|
|
||||||
|
|
||||||
std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width)
|
std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width)
|
||||||
{
|
{
|
||||||
std::basic_string<my_char_t> s(str);
|
std::basic_string<my_char_t> s(str);
|
||||||
|
|||||||
@@ -26,9 +26,41 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
|
|
||||||
void ParseArgv(int, char **);
|
template <typename Iterator> void removeSelectionHelper(Iterator first, Iterator last)
|
||||||
|
{
|
||||||
|
for (; first != last; ++first)
|
||||||
|
first->setSelected(false);
|
||||||
|
}
|
||||||
|
|
||||||
std::string StringPairToString(const std::pair<std::string, std::string> &pair);
|
template <typename Iterator> void reverseSelectionHelper(Iterator first, Iterator last)
|
||||||
|
{
|
||||||
|
for (; first != last; ++first)
|
||||||
|
first->setSelected(!first->isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator> std::string getSharedDirectory(Iterator first, Iterator last)
|
||||||
|
{
|
||||||
|
assert(first != last);
|
||||||
|
std::string result = first->getDirectory();
|
||||||
|
while (++first != last)
|
||||||
|
{
|
||||||
|
result = getSharedDirectory(result, first->getDirectory());
|
||||||
|
if (result == "/")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void withUnfilteredMenu(Menu<T> &menu, std::function<void()> action)
|
||||||
|
{
|
||||||
|
bool is_filtered = menu.isFiltered();
|
||||||
|
menu.ShowAll();
|
||||||
|
action();
|
||||||
|
if (is_filtered)
|
||||||
|
menu.ShowFiltered();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ParseArgv(int, char **);
|
||||||
|
|
||||||
template <typename T> struct StringConverter {
|
template <typename T> struct StringConverter {
|
||||||
const char *operator()(const char *s) { return s; }
|
const char *operator()(const char *s) { return s; }
|
||||||
@@ -172,22 +204,6 @@ std::string Timestamp(time_t t);
|
|||||||
|
|
||||||
void UpdateSongList(Menu<MPD::Song> *);
|
void UpdateSongList(Menu<MPD::Song> *);
|
||||||
|
|
||||||
#ifdef HAVE_TAGLIB_H
|
|
||||||
template <typename T> std::string getSharedDirectory(Menu<T> *menu)
|
|
||||||
{
|
|
||||||
assert(!menu->Empty());
|
|
||||||
std::string dir;
|
|
||||||
// dir = (*menu)[0].value().getDirectory();
|
|
||||||
for (size_t i = 1; i < menu->Size(); ++i)
|
|
||||||
{
|
|
||||||
dir = getSharedDirectory(dir, (*menu)[i].value().getDirectory());
|
|
||||||
if (dir == "/")
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
#endif // HAVE_TAGLIB_H
|
|
||||||
|
|
||||||
std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width);
|
std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width);
|
||||||
|
|
||||||
std::string Shorten(const std::basic_string<my_char_t> &s, size_t max_length);
|
std::string Shorten(const std::basic_string<my_char_t> &s, size_t max_length);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#define _INTERFACES_H
|
#define _INTERFACES_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "mpdpp.h"
|
||||||
#include "gcc.h"
|
#include "gcc.h"
|
||||||
|
|
||||||
struct Filterable
|
struct Filterable
|
||||||
@@ -37,4 +38,15 @@ struct Searchable
|
|||||||
virtual void prevFound(bool wrap) = 0;
|
virtual void prevFound(bool wrap) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HasSongs
|
||||||
|
{
|
||||||
|
virtual MPD::Song *getSong(size_t pos) = 0;
|
||||||
|
virtual MPD::Song *currentSong() = 0;
|
||||||
|
|
||||||
|
virtual bool allowsSelection() = 0;
|
||||||
|
virtual void reverseSelection() = 0;
|
||||||
|
virtual void removeSelection() = 0;
|
||||||
|
virtual MPD::SongList getSelectedSongs() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // _INTERFACES_H
|
#endif // _INTERFACES_H
|
||||||
|
|||||||
@@ -116,7 +116,11 @@ void Lyrics::SwitchTo()
|
|||||||
}
|
}
|
||||||
# endif // HAVE_CURL_CURL_H
|
# endif // HAVE_CURL_CURL_H
|
||||||
|
|
||||||
if (const MPD::Song *s = myScreen->CurrentSong())
|
auto hs = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
if (!hs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (const MPD::Song *s = hs->currentSong())
|
||||||
{
|
{
|
||||||
if (!s->getArtist().empty() && !s->getTitle().empty())
|
if (!s->getArtist().empty() && !s->getTitle().empty())
|
||||||
{
|
{
|
||||||
@@ -137,7 +141,7 @@ void Lyrics::SwitchTo()
|
|||||||
// if we resize for locked screen, we have to do that in the end since
|
// if we resize for locked screen, we have to do that in the end since
|
||||||
// fetching lyrics may fail (eg. if tags are missing) and we don't want
|
// fetching lyrics may fail (eg. if tags are missing) and we don't want
|
||||||
// to adjust screen size then.
|
// to adjust screen size then.
|
||||||
if (myLockedScreen)
|
if (myLockedScreen) // BUG
|
||||||
{
|
{
|
||||||
UpdateInactiveScreen(this);
|
UpdateInactiveScreen(this);
|
||||||
Resize();
|
Resize();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "charset.h"
|
#include "charset.h"
|
||||||
@@ -216,19 +217,16 @@ void MediaLibrary::Update()
|
|||||||
{
|
{
|
||||||
if (!hasTwoColumns && Tags->ReallyEmpty())
|
if (!hasTwoColumns && Tags->ReallyEmpty())
|
||||||
{
|
{
|
||||||
MPD::TagList list;
|
|
||||||
Albums->Clear();
|
Albums->Clear();
|
||||||
Songs->Clear();
|
Songs->Clear();
|
||||||
Mpd.GetList(list, Config.media_lib_primary_tag);
|
auto list = Mpd.GetList(Config.media_lib_primary_tag);
|
||||||
sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
||||||
for (MPD::TagList::iterator it = list.begin(); it != list.end(); ++it)
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->empty() && !Config.media_library_display_empty_tag)
|
if (it->empty() && !Config.media_library_display_empty_tag)
|
||||||
continue;
|
continue;
|
||||||
utf_to_locale(*it);
|
|
||||||
Tags->AddItem(*it);
|
Tags->AddItem(*it);
|
||||||
}
|
}
|
||||||
Tags->Window::Clear();
|
|
||||||
Tags->Refresh();
|
Tags->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,35 +235,25 @@ void MediaLibrary::Update()
|
|||||||
// idle has to be blocked for now since it would be enabled and
|
// idle has to be blocked for now since it would be enabled and
|
||||||
// disabled a few times by each mpd command, which makes no sense
|
// disabled a few times by each mpd command, which makes no sense
|
||||||
// and slows down the whole process.
|
// and slows down the whole process.
|
||||||
Mpd.BlockIdle(1);
|
Mpd.BlockIdle(true);
|
||||||
Albums->Reset();
|
Albums->Reset();
|
||||||
MPD::TagList list;
|
|
||||||
locale_to_utf(Tags->Current().value());
|
|
||||||
Mpd.StartFieldSearch(MPD_TAG_ALBUM);
|
Mpd.StartFieldSearch(MPD_TAG_ALBUM);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value());
|
Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value());
|
||||||
Mpd.CommitSearchTags([&list](std::string &&album) {
|
auto albums = Mpd.CommitSearchTags();
|
||||||
list.push_back(album);
|
for (auto album = albums.begin(); album != albums.end(); ++album)
|
||||||
});
|
|
||||||
for (auto album = list.begin(); album != list.end(); ++album)
|
|
||||||
{
|
{
|
||||||
if (Config.media_library_display_date)
|
if (Config.media_library_display_date)
|
||||||
{
|
{
|
||||||
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value());
|
Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value());
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, *album);
|
Mpd.AddSearch(MPD_TAG_ALBUM, *album);
|
||||||
utf_to_locale(*album);
|
auto dates = Mpd.CommitSearchTags();
|
||||||
Mpd.CommitSearchTags([this, &album](std::string &&date) {
|
for (auto date = dates.begin(); date != dates.end(); ++date)
|
||||||
utf_to_locale(date);
|
Albums->AddItem(SearchConstraints(*album, *date));
|
||||||
Albums->AddItem(SearchConstraints(*album, date));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
utf_to_locale(*album);
|
|
||||||
Albums->AddItem(SearchConstraints(*album, ""));
|
Albums->AddItem(SearchConstraints(*album, ""));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
utf_to_locale(Tags->Current().value());
|
|
||||||
if (!Albums->Empty())
|
if (!Albums->Empty())
|
||||||
std::sort(Albums->BeginV(), Albums->EndV(), SortSearchConstraints);
|
std::sort(Albums->BeginV(), Albums->EndV(), SortSearchConstraints);
|
||||||
if (Albums->Size() > 1)
|
if (Albums->Size() > 1)
|
||||||
@@ -274,24 +262,20 @@ void MediaLibrary::Update()
|
|||||||
Albums->AddItem(SearchConstraints("", AllTracksMarker));
|
Albums->AddItem(SearchConstraints("", AllTracksMarker));
|
||||||
}
|
}
|
||||||
Albums->Refresh();
|
Albums->Refresh();
|
||||||
Mpd.BlockIdle(0);
|
Mpd.BlockIdle(false);
|
||||||
}
|
}
|
||||||
else if (hasTwoColumns && Albums->ReallyEmpty())
|
else if (hasTwoColumns && Albums->ReallyEmpty())
|
||||||
{
|
{
|
||||||
Songs->Clear();
|
Songs->Clear();
|
||||||
MPD::TagList artists;
|
|
||||||
*Albums << XY(0, 0) << "Fetching albums...";
|
*Albums << XY(0, 0) << "Fetching albums...";
|
||||||
Albums->Window::Refresh();
|
Albums->Window::Refresh();
|
||||||
Mpd.BlockIdle(1);
|
Mpd.BlockIdle(true);
|
||||||
Mpd.GetList(artists, Config.media_lib_primary_tag);
|
auto artists = Mpd.GetList(Config.media_lib_primary_tag);
|
||||||
for (auto artist = artists.begin(); artist != artists.end(); ++artist)
|
for (auto artist = artists.begin(); artist != artists.end(); ++artist)
|
||||||
{
|
{
|
||||||
MPD::TagList albums;
|
|
||||||
Mpd.StartFieldSearch(MPD_TAG_ALBUM);
|
Mpd.StartFieldSearch(MPD_TAG_ALBUM);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
||||||
Mpd.CommitSearchTags([&albums](std::string &&album) {
|
auto albums = Mpd.CommitSearchTags();
|
||||||
albums.push_back(album);
|
|
||||||
});
|
|
||||||
for (auto album = albums.begin(); album != albums.end(); ++album)
|
for (auto album = albums.begin(); album != albums.end(); ++album)
|
||||||
{
|
{
|
||||||
if (Config.media_library_display_date)
|
if (Config.media_library_display_date)
|
||||||
@@ -301,26 +285,15 @@ void MediaLibrary::Update()
|
|||||||
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
Mpd.StartFieldSearch(MPD_TAG_DATE);
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
Mpd.AddSearch(Config.media_lib_primary_tag, *artist);
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, *album);
|
Mpd.AddSearch(MPD_TAG_ALBUM, *album);
|
||||||
utf_to_locale(*artist);
|
auto dates = Mpd.CommitSearchTags();
|
||||||
utf_to_locale(*album);
|
for (auto date = dates.begin(); date != dates.end(); ++date)
|
||||||
Mpd.CommitSearchTags([this, &artist, &album](std::string &&tag) {
|
Albums->AddItem(SearchConstraints(*artist, *album, *date));
|
||||||
utf_to_locale(tag);
|
|
||||||
Albums->AddItem(SearchConstraints(*artist, *album, tag));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
utf_to_locale(*artist);
|
|
||||||
utf_to_locale(*album);
|
|
||||||
Albums->AddItem(SearchConstraints(*artist, *album, *artist));
|
Albums->AddItem(SearchConstraints(*artist, *album, *artist));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
utf_to_locale(*artist);
|
|
||||||
utf_to_locale(*album);
|
|
||||||
Albums->AddItem(SearchConstraints(*artist, *album, ""));
|
Albums->AddItem(SearchConstraints(*artist, *album, ""));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mpd.BlockIdle(0);
|
Mpd.BlockIdle(0);
|
||||||
@@ -348,16 +321,15 @@ void MediaLibrary::Update()
|
|||||||
if (Config.media_library_display_date)
|
if (Config.media_library_display_date)
|
||||||
Mpd.AddSearch(MPD_TAG_DATE, locale_to_utf_cpy(Albums->Current().value().Date));
|
Mpd.AddSearch(MPD_TAG_DATE, locale_to_utf_cpy(Albums->Current().value().Date));
|
||||||
}
|
}
|
||||||
Mpd.CommitSearchSongs([this](MPD::Song &&s) {
|
auto songs = Mpd.CommitSearchSongs();
|
||||||
Songs->AddItem(s, myPlaylist->checkForSong(s));
|
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||||
});
|
Songs->AddItem(*s, myPlaylist->checkForSong(*s));
|
||||||
|
|
||||||
if (Albums->Current().value().Date == AllTracksMarker)
|
if (Albums->Current().value().Date == AllTracksMarker)
|
||||||
std::sort(Songs->BeginV(), Songs->EndV(), SortAllTracks);
|
std::sort(Songs->BeginV(), Songs->EndV(), SortAllTracks);
|
||||||
else
|
else
|
||||||
std::sort(Songs->BeginV(), Songs->EndV(), SortSongsByTrack);
|
std::sort(Songs->BeginV(), Songs->EndV(), SortSongsByTrack);
|
||||||
|
|
||||||
Songs->Window::Clear();
|
|
||||||
Songs->Refresh();
|
Songs->Refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -462,11 +434,6 @@ void MediaLibrary::MouseButtonPressed(MEVENT me)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::Song *MediaLibrary::CurrentSong()
|
|
||||||
{
|
|
||||||
return w == Songs && !Songs->Empty() ? &Songs->Current().value() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
List *MediaLibrary::GetList()
|
List *MediaLibrary::GetList()
|
||||||
{
|
{
|
||||||
if (w == Tags)
|
if (w == Tags)
|
||||||
@@ -479,73 +446,6 @@ List *MediaLibrary::GetList()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaLibrary::ReverseSelection()
|
|
||||||
{
|
|
||||||
if (w == Tags)
|
|
||||||
Tags->ReverseSelection();
|
|
||||||
else if (w == Albums)
|
|
||||||
Albums->ReverseSelection();
|
|
||||||
else if (w == Songs)
|
|
||||||
Songs->ReverseSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MediaLibrary::GetSelectedSongs(MPD::SongList &v)
|
|
||||||
{
|
|
||||||
std::vector<size_t> selected;
|
|
||||||
if (w == Tags && !Tags->Empty())
|
|
||||||
{
|
|
||||||
Tags->GetSelected(selected);
|
|
||||||
if (selected.empty())
|
|
||||||
selected.push_back(Tags->Choice());
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
{
|
|
||||||
MPD::SongList list;
|
|
||||||
Mpd.StartSearch(1);
|
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(Tags->at(*it).value()));
|
|
||||||
Mpd.CommitSearchSongs([&list](MPD::Song &&s) {
|
|
||||||
list.push_back(s);
|
|
||||||
});
|
|
||||||
std::sort(list.begin(), list.end(), SortAllTracks);
|
|
||||||
std::copy(list.begin(), list.end(), std::back_inserter(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (w == Albums && !Albums->Empty())
|
|
||||||
{
|
|
||||||
Albums->GetSelected(selected);
|
|
||||||
if (selected.empty())
|
|
||||||
{
|
|
||||||
// shortcut via the existing song list in right column
|
|
||||||
if (v.empty())
|
|
||||||
v.reserve(Songs->Size());
|
|
||||||
for (size_t i = 0; i < Songs->Size(); ++i)
|
|
||||||
v.push_back((*Songs)[i].value());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
{
|
|
||||||
Mpd.StartSearch(1);
|
|
||||||
Mpd.AddSearch(Config.media_lib_primary_tag, hasTwoColumns
|
|
||||||
? Albums->at(*it).value().PrimaryTag
|
|
||||||
: locale_to_utf_cpy(Tags->Current().value()));
|
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, Albums->at(*it).value().Album);
|
|
||||||
Mpd.AddSearch(MPD_TAG_DATE, Albums->at(*it).value().Date);
|
|
||||||
Mpd.CommitSearchSongs([&v](MPD::Song &&s) {
|
|
||||||
v.push_back(s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (w == Songs && !Songs->Empty())
|
|
||||||
{
|
|
||||||
Songs->GetSelected(selected);
|
|
||||||
if (selected.empty())
|
|
||||||
selected.push_back(Songs->Choice());
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
v.push_back(Songs->at(*it).value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
std::string MediaLibrary::currentFilter()
|
std::string MediaLibrary::currentFilter()
|
||||||
@@ -629,6 +529,113 @@ void MediaLibrary::prevFound(bool wrap)
|
|||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
|
MPD::Song *MediaLibrary::getSong(size_t pos)
|
||||||
|
{
|
||||||
|
MPD::Song *ptr = 0;
|
||||||
|
if (w == Songs)
|
||||||
|
ptr = &(*Songs)[pos].value();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::Song *MediaLibrary::currentSong()
|
||||||
|
{
|
||||||
|
if (w == Songs && !Songs->Empty())
|
||||||
|
return getSong(Songs->Choice());
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MediaLibrary::allowsSelection()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaLibrary::removeSelection()
|
||||||
|
{
|
||||||
|
if (w == Tags)
|
||||||
|
removeSelectionHelper(Tags->Begin(), Tags->End());
|
||||||
|
else if (w == Albums)
|
||||||
|
removeSelectionHelper(Albums->Begin(), Albums->End());
|
||||||
|
else if (w == Songs)
|
||||||
|
removeSelectionHelper(Songs->Begin(), Songs->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaLibrary::reverseSelection()
|
||||||
|
{
|
||||||
|
if (w == Tags)
|
||||||
|
reverseSelectionHelper(Tags->Begin(), Tags->End());
|
||||||
|
else if (w == Albums)
|
||||||
|
{
|
||||||
|
// omit "All tracks"
|
||||||
|
if (Albums->Size() > 1)
|
||||||
|
reverseSelectionHelper(Albums->Begin(), Albums->End()-2);
|
||||||
|
else
|
||||||
|
reverseSelectionHelper(Albums->Begin(), Albums->End());
|
||||||
|
}
|
||||||
|
else if (w == Songs)
|
||||||
|
reverseSelectionHelper(Songs->Begin(), Songs->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::SongList MediaLibrary::getSelectedSongs()
|
||||||
|
{
|
||||||
|
MPD::SongList result;
|
||||||
|
if (w == Tags)
|
||||||
|
{
|
||||||
|
auto tag_handler = [&result](const std::string &tag) {
|
||||||
|
Mpd.StartSearch(true);
|
||||||
|
Mpd.AddSearch(Config.media_lib_primary_tag, tag);
|
||||||
|
auto songs = Mpd.CommitSearchSongs();
|
||||||
|
std::sort(songs.begin(), songs.end(), SortAllTracks);
|
||||||
|
result.insert(result.end(), songs.begin(), songs.end());
|
||||||
|
};
|
||||||
|
for (auto it = Tags->Begin(); it != Tags->End(); ++it)
|
||||||
|
if (it->isSelected())
|
||||||
|
tag_handler(it->value());
|
||||||
|
// if no item is selected, add current one
|
||||||
|
if (result.empty() && !Tags->Empty())
|
||||||
|
tag_handler(Tags->Current().value());
|
||||||
|
}
|
||||||
|
else if (w == Albums)
|
||||||
|
{
|
||||||
|
for (auto it = Albums->Begin(); it != Albums->End() && !it->isSeparator(); ++it)
|
||||||
|
{
|
||||||
|
if (it->isSelected())
|
||||||
|
{
|
||||||
|
auto &sc = it->value();
|
||||||
|
Mpd.StartSearch(true);
|
||||||
|
if (hasTwoColumns)
|
||||||
|
Mpd.AddSearch(Config.media_lib_primary_tag, sc.PrimaryTag);
|
||||||
|
else
|
||||||
|
Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value());
|
||||||
|
Mpd.AddSearch(MPD_TAG_ALBUM, sc.Album);
|
||||||
|
Mpd.AddSearch(MPD_TAG_DATE, sc.Date);
|
||||||
|
auto songs = Mpd.CommitSearchSongs();
|
||||||
|
std::sort(songs.begin(), songs.end(), SortSongsByTrack);
|
||||||
|
result.insert(result.end(), songs.begin(), songs.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if no item is selected, add songs from right column
|
||||||
|
if (result.empty() && !Albums->Empty())
|
||||||
|
{
|
||||||
|
withUnfilteredMenu(*Songs, [this, &result]() {
|
||||||
|
result.insert(result.end(), Songs->BeginV(), Songs->EndV());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (w == Songs)
|
||||||
|
{
|
||||||
|
for (auto it = Songs->Begin(); it != Songs->End(); ++it)
|
||||||
|
if (it->isSelected())
|
||||||
|
result.push_back(it->value());
|
||||||
|
// if no item is selected, add current one
|
||||||
|
if (result.empty() && !Songs->Empty())
|
||||||
|
result.push_back(Songs->Current().value());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
int MediaLibrary::Columns()
|
int MediaLibrary::Columns()
|
||||||
{
|
{
|
||||||
if (hasTwoColumns)
|
if (hasTwoColumns)
|
||||||
@@ -817,9 +824,7 @@ void MediaLibrary::AddToPlaylist(bool add_n_play)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MPD::SongList list;
|
auto list = getSelectedSongs();
|
||||||
GetSelectedSongs(list);
|
|
||||||
|
|
||||||
if (myPlaylist->Add(list, add_n_play))
|
if (myPlaylist->Add(list, add_n_play))
|
||||||
{
|
{
|
||||||
if ((!Tags->Empty() && w == Tags)
|
if ((!Tags->Empty() && w == Tags)
|
||||||
@@ -915,20 +920,27 @@ void DisplayPrimaryTags(Menu<std::string> &menu)
|
|||||||
|
|
||||||
bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b)
|
bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b)
|
||||||
{
|
{
|
||||||
if (a.getDisc() == b.getDisc())
|
int cmp = a.getDisc().compare(a.getDisc());
|
||||||
return stringToInt(a.getTrack()) < stringToInt(b.getTrack());
|
if (cmp != 0)
|
||||||
else
|
return cmp;
|
||||||
return stringToInt(a.getDisc()) < stringToInt(b.getDisc());
|
return a.getTrack() < b.getTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SortAllTracks(const MPD::Song &a, const MPD::Song &b)
|
bool SortAllTracks(const MPD::Song &a, const MPD::Song &b)
|
||||||
{
|
{
|
||||||
static MPD::Song::GetFunction gets[] = { &MPD::Song::getDate, &MPD::Song::getAlbum, &MPD::Song::getDisc, 0 };
|
const std::array<MPD::Song::GetFunction, 3> gets = {{
|
||||||
|
&MPD::Song::getDate,
|
||||||
|
&MPD::Song::getAlbum,
|
||||||
|
&MPD::Song::getDisc
|
||||||
|
}};
|
||||||
CaseInsensitiveStringComparison cmp;
|
CaseInsensitiveStringComparison cmp;
|
||||||
for (MPD::Song::GetFunction *get = gets; *get; ++get)
|
for (auto get = gets.begin(); get != gets.end(); ++get)
|
||||||
if (int ret = cmp(a.getTags(*get), b.getTags(*get)))
|
{
|
||||||
|
int ret = cmp(a.getTags(*get), b.getTags(*get));
|
||||||
|
if (ret != 0)
|
||||||
return ret < 0;
|
return ret < 0;
|
||||||
return a.getTrack() < b.getTrack();
|
}
|
||||||
|
return a.getTrack() < b.getTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SortSearchConstraints(const SearchConstraints &a, const SearchConstraints &b)
|
bool SortSearchConstraints(const SearchConstraints &a, const SearchConstraints &b)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
#include "ncmpcpp.h"
|
#include "ncmpcpp.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
|
||||||
class MediaLibrary : public Screen<Window>, public Filterable, public Searchable
|
class MediaLibrary : public Screen<Window>, public Filterable, public HasSongs, public Searchable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void SwitchTo();
|
virtual void SwitchTo();
|
||||||
@@ -41,13 +41,6 @@ class MediaLibrary : public Screen<Window>, public Filterable, public Searchable
|
|||||||
virtual void MouseButtonPressed(MEVENT);
|
virtual void MouseButtonPressed(MEVENT);
|
||||||
virtual bool isTabbable() { return true; }
|
virtual bool isTabbable() { return true; }
|
||||||
|
|
||||||
virtual MPD::Song *CurrentSong();
|
|
||||||
virtual MPD::Song *GetSong(size_t pos) { return w == Songs ? &Songs->at(pos).value() : 0; }
|
|
||||||
|
|
||||||
virtual bool allowsSelection() { return true; }
|
|
||||||
virtual void ReverseSelection();
|
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
|
||||||
|
|
||||||
/// Filterable implementation
|
/// Filterable implementation
|
||||||
virtual std::string currentFilter();
|
virtual std::string currentFilter();
|
||||||
virtual void applyFilter(const std::string &filter);
|
virtual void applyFilter(const std::string &filter);
|
||||||
@@ -57,6 +50,15 @@ class MediaLibrary : public Screen<Window>, public Filterable, public Searchable
|
|||||||
virtual void nextFound(bool wrap);
|
virtual void nextFound(bool wrap);
|
||||||
virtual void prevFound(bool wrap);
|
virtual void prevFound(bool wrap);
|
||||||
|
|
||||||
|
/// HasSongs implementation
|
||||||
|
virtual MPD::Song *getSong(size_t pos);
|
||||||
|
virtual MPD::Song *currentSong();
|
||||||
|
|
||||||
|
virtual bool allowsSelection();
|
||||||
|
virtual void reverseSelection();
|
||||||
|
virtual void removeSelection();
|
||||||
|
virtual MPD::SongList getSelectedSongs();
|
||||||
|
|
||||||
virtual List *GetList();
|
virtual List *GetList();
|
||||||
|
|
||||||
virtual bool isMergable() { return true; }
|
virtual bool isMergable() { return true; }
|
||||||
|
|||||||
19
src/menu.cpp
19
src/menu.cpp
@@ -1,19 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 2008-2012 by Andrzej Rybczak *
|
|
||||||
* electricityispower@gmail.com *
|
|
||||||
* *
|
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
|
||||||
* it under the terms of the GNU General Public License as published by *
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or *
|
|
||||||
* (at your option) any later version. *
|
|
||||||
* *
|
|
||||||
* This program is distributed in the hope that it will be useful, *
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
||||||
* GNU General Public License for more details. *
|
|
||||||
* *
|
|
||||||
* You should have received a copy of the GNU General Public License *
|
|
||||||
* along with this program; if not, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
20
src/menu.h
20
src/menu.h
@@ -153,7 +153,7 @@ template <typename T> struct Menu : public Window, public List
|
|||||||
return ItemIterator<typename std::add_const<ValueT>::type, Iterator>(m_it);
|
return ItemIterator<typename std::add_const<ValueT>::type, Iterator>(m_it);
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseIterator &base() { return m_it; }
|
const BaseIterator &base() const { return m_it; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ItemIterator<
|
typedef ItemIterator<
|
||||||
@@ -251,10 +251,6 @@ template <typename T> struct Menu : public Window, public List
|
|||||||
/// @param v vector to be filled with selected positions numbers
|
/// @param v vector to be filled with selected positions numbers
|
||||||
void GetSelected(std::vector<size_t> &v) const;
|
void GetSelected(std::vector<size_t> &v) const;
|
||||||
|
|
||||||
/// Reverses selection of all items in list
|
|
||||||
/// @param beginning beginning of range that has to be reversed
|
|
||||||
void ReverseSelection(size_t beginning = 0);
|
|
||||||
|
|
||||||
/// Highlights given position
|
/// Highlights given position
|
||||||
/// @param pos position to be highlighted
|
/// @param pos position to be highlighted
|
||||||
void Highlight(size_t pos);
|
void Highlight(size_t pos);
|
||||||
@@ -372,33 +368,27 @@ template <typename T> struct Menu : public Window, public List
|
|||||||
const Menu<T>::Item &Back() const;
|
const Menu<T>::Item &Back() const;
|
||||||
|
|
||||||
/// @return reference to curently highlighted object
|
/// @return reference to curently highlighted object
|
||||||
/// @throw List::InvalidItem if requested item is separator
|
|
||||||
Menu<T>::Item &Current();
|
Menu<T>::Item &Current();
|
||||||
|
|
||||||
/// @return const reference to curently highlighted object
|
/// @return const reference to curently highlighted object
|
||||||
/// @throw List::InvalidItem if requested item is separator
|
|
||||||
const Menu<T>::Item &Current() const;
|
const Menu<T>::Item &Current() const;
|
||||||
|
|
||||||
/// @param pos requested position
|
/// @param pos requested position
|
||||||
/// @return reference to item at given position
|
/// @return reference to item at given position
|
||||||
/// @throw std::out_of_range if given position is out of range
|
/// @throw std::out_of_range if given position is out of range
|
||||||
/// @throw List::InvalidItem if requested item is separator
|
|
||||||
Menu<T>::Item &at(size_t pos);
|
Menu<T>::Item &at(size_t pos);
|
||||||
|
|
||||||
/// @param pos requested position
|
/// @param pos requested position
|
||||||
/// @return const reference to item at given position
|
/// @return const reference to item at given position
|
||||||
/// @throw std::out_of_range if given position is out of range
|
/// @throw std::out_of_range if given position is out of range
|
||||||
/// @throw List::InvalidItem if requested item is separator
|
|
||||||
const Menu<T>::Item &at(size_t pos) const;
|
const Menu<T>::Item &at(size_t pos) const;
|
||||||
|
|
||||||
/// @param pos requested position
|
/// @param pos requested position
|
||||||
/// @return const reference to item at given position
|
/// @return const reference to item at given position
|
||||||
/// @throw List::InvalidItem if requested item is separator
|
|
||||||
const Menu<T>::Item &operator[](size_t pos) const;
|
const Menu<T>::Item &operator[](size_t pos) const;
|
||||||
|
|
||||||
/// @param pos requested position
|
/// @param pos requested position
|
||||||
/// @return const reference to item at given position
|
/// @return const reference to item at given position
|
||||||
/// @throw List::InvalidItem if requested item is separator
|
|
||||||
Menu<T>::Item &operator[](size_t pos);
|
Menu<T>::Item &operator[](size_t pos);
|
||||||
|
|
||||||
Iterator Begin() { return Iterator(m_options_ptr->begin()); }
|
Iterator Begin() { return Iterator(m_options_ptr->begin()); }
|
||||||
@@ -744,6 +734,7 @@ template <typename T> size_t Menu<T>::Size() const
|
|||||||
|
|
||||||
template <typename T> size_t Menu<T>::Choice() const
|
template <typename T> size_t Menu<T>::Choice() const
|
||||||
{
|
{
|
||||||
|
assert(!Empty());
|
||||||
return m_highlight;
|
return m_highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,13 +784,6 @@ template <typename T> void Menu<T>::clearSearchResults()
|
|||||||
m_found_positions.clear();
|
m_found_positions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void Menu<T>::ReverseSelection(size_t beginning)
|
|
||||||
{
|
|
||||||
auto it = m_options_ptr->begin()+beginning;
|
|
||||||
for (size_t i = beginning; i < Size(); ++i, ++it)
|
|
||||||
(*it)->setSelected(!(*it)->isSelected() && !(*it)->isInactive());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> void Menu<T>::NextFound(bool wrap)
|
template <typename T> void Menu<T>::NextFound(bool wrap)
|
||||||
{
|
{
|
||||||
if (m_found_positions.empty())
|
if (m_found_positions.empty())
|
||||||
|
|||||||
134
src/mpdpp.cpp
134
src/mpdpp.cpp
@@ -621,17 +621,19 @@ bool MPD::Connection::Rename(const std::string &from, const std::string &to)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetPlaylistChanges(unsigned version, std::function<void(MPD::Song &&)> f)
|
MPD::SongList MPD::Connection::GetPlaylistChanges(unsigned version)
|
||||||
{
|
{
|
||||||
|
SongList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_queue_changes_meta(itsConnection, version);
|
mpd_send_queue_changes_meta(itsConnection, version);
|
||||||
while (mpd_song *s = mpd_recv_song(itsConnection))
|
while (mpd_song *s = mpd_recv_song(itsConnection))
|
||||||
f(Song(s));
|
result.push_back(Song(s));
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::Song MPD::Connection::GetSong(const std::string &path)
|
MPD::Song MPD::Connection::GetSong(const std::string &path)
|
||||||
@@ -667,17 +669,19 @@ MPD::Song MPD::Connection::GetCurrentlyPlayingSong()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetPlaylistContent(const std::string &path, std::function<void(MPD::Song &&)> f)
|
MPD::SongList MPD::Connection::GetPlaylistContent(const std::string &path)
|
||||||
{
|
{
|
||||||
|
SongList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_playlist_meta(itsConnection, path.c_str());
|
mpd_send_list_playlist_meta(itsConnection, path.c_str());
|
||||||
while (mpd_song *s = mpd_recv_song(itsConnection))
|
while (mpd_song *s = mpd_recv_song(itsConnection))
|
||||||
f(Song(s));
|
result.push_back(Song(s));
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetSupportedExtensions(std::set<std::string> &acc)
|
void MPD::Connection::GetSupportedExtensions(std::set<std::string> &acc)
|
||||||
@@ -903,9 +907,7 @@ bool MPD::Connection::AddRandomTag(mpd_tag_type tag, size_t number)
|
|||||||
return false;
|
return false;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
|
|
||||||
TagList tags;
|
auto tags = GetList(tag);
|
||||||
GetList(tags, tag);
|
|
||||||
|
|
||||||
if (number > tags.size())
|
if (number > tags.size())
|
||||||
{
|
{
|
||||||
if (itsErrorHandler)
|
if (itsErrorHandler)
|
||||||
@@ -915,18 +917,15 @@ bool MPD::Connection::AddRandomTag(mpd_tag_type tag, size_t number)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::random_shuffle(tags.begin(), tags.end());
|
std::random_shuffle(tags.begin(), tags.end());
|
||||||
TagList::const_iterator it = tags.begin()+rand()%(tags.size()-number);
|
auto it = tags.begin()+rand()%(tags.size()-number);
|
||||||
for (size_t i = 0; i < number && it != tags.end(); ++i)
|
for (size_t i = 0; i < number && it != tags.end(); ++i)
|
||||||
{
|
{
|
||||||
StartSearch(1);
|
StartSearch(1);
|
||||||
AddSearch(tag, *it++);
|
AddSearch(tag, *it++);
|
||||||
SongList list;
|
auto songs = CommitSearchSongs();
|
||||||
CommitSearchSongs([&list](MPD::Song &&s) {
|
|
||||||
list.push_back(s);
|
|
||||||
});
|
|
||||||
StartCommandsList();
|
StartCommandsList();
|
||||||
for (auto j = list.begin(); j != list.end(); ++j)
|
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||||
AddSong(*j);
|
AddSong(*s);
|
||||||
CommitCommandsList();
|
CommitCommandsList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,7 +938,7 @@ bool MPD::Connection::AddRandomSongs(size_t number)
|
|||||||
return false;
|
return false;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
|
|
||||||
TagList files;
|
StringList files;
|
||||||
|
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_all(itsConnection, "/");
|
mpd_send_list_all(itsConnection, "/");
|
||||||
@@ -958,12 +957,11 @@ bool MPD::Connection::AddRandomSongs(size_t number)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
srand(time(0));
|
|
||||||
std::random_shuffle(files.begin(), files.end());
|
std::random_shuffle(files.begin(), files.end());
|
||||||
StartCommandsList();
|
StartCommandsList();
|
||||||
TagList::const_iterator it = files.begin()+rand()%(std::max(size_t(1), files.size()-number));
|
auto it = files.begin()+rand()%(std::max(size_t(1), files.size()-number));
|
||||||
for (size_t i = 0; i < number && it != files.end(); ++i)
|
for (size_t i = 0; i < number && it != files.end(); ++i, ++it)
|
||||||
AddSong(*it++);
|
AddSong(*it);
|
||||||
CommitCommandsList();
|
CommitCommandsList();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -1075,31 +1073,35 @@ int MPD::Connection::SavePlaylist(const std::string &name)
|
|||||||
return CheckForErrors();
|
return CheckForErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetPlaylists(TagList &v)
|
MPD::StringList MPD::Connection::GetPlaylists()
|
||||||
{
|
{
|
||||||
|
StringList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
GetDirectory("/", [&v](Item &&it) {
|
auto items = GetDirectory("/");
|
||||||
if (it.type == itPlaylist)
|
for (auto it = items.begin(); it != items.end(); ++it)
|
||||||
v.push_back(it.name);
|
if (it->type == itPlaylist)
|
||||||
});
|
result.push_back(it->name);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetList(TagList &v, mpd_tag_type type)
|
MPD::StringList MPD::Connection::GetList(mpd_tag_type type)
|
||||||
{
|
{
|
||||||
|
StringList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_search_db_tags(itsConnection, type);
|
mpd_search_db_tags(itsConnection, type);
|
||||||
mpd_search_commit(itsConnection);
|
mpd_search_commit(itsConnection);
|
||||||
while (mpd_pair *item = mpd_recv_pair_tag(itsConnection, type))
|
while (mpd_pair *item = mpd_recv_pair_tag(itsConnection, type))
|
||||||
{
|
{
|
||||||
v.push_back(item->value);
|
result.push_back(item->value);
|
||||||
mpd_return_pair(itsConnection, item);
|
mpd_return_pair(itsConnection, item);
|
||||||
}
|
}
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::StartSearch(bool exact_match)
|
void MPD::Connection::StartSearch(bool exact_match)
|
||||||
@@ -1140,39 +1142,44 @@ void MPD::Connection::AddSearchURI(const std::string &str) const
|
|||||||
mpd_search_add_uri_constraint(itsConnection, MPD_OPERATOR_DEFAULT, str.c_str());
|
mpd_search_add_uri_constraint(itsConnection, MPD_OPERATOR_DEFAULT, str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::CommitSearchSongs(std::function<void(MPD::Song &&)> f)
|
MPD::SongList MPD::Connection::CommitSearchSongs()
|
||||||
{
|
{
|
||||||
|
SongList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_search_commit(itsConnection);
|
mpd_search_commit(itsConnection);
|
||||||
while (mpd_song *s = mpd_recv_song(itsConnection))
|
while (mpd_song *s = mpd_recv_song(itsConnection))
|
||||||
f(Song(s));
|
result.push_back(Song(s));
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::CommitSearchTags(std::function<void(std::string &&)> f)
|
MPD::StringList MPD::Connection::CommitSearchTags()
|
||||||
{
|
{
|
||||||
|
StringList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_search_commit(itsConnection);
|
mpd_search_commit(itsConnection);
|
||||||
while (mpd_pair *tag = mpd_recv_pair_tag(itsConnection, itsSearchedField))
|
while (mpd_pair *tag = mpd_recv_pair_tag(itsConnection, itsSearchedField))
|
||||||
{
|
{
|
||||||
f(tag->value);
|
result.push_back(tag->value);
|
||||||
mpd_return_pair(itsConnection, tag);
|
mpd_return_pair(itsConnection, tag);
|
||||||
}
|
}
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetDirectory(const std::string &path, std::function<void(Item &&)> f)
|
MPD::ItemList MPD::Connection::GetDirectory(const std::string &path)
|
||||||
{
|
{
|
||||||
|
ItemList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_meta(itsConnection, path.c_str());
|
mpd_send_list_meta(itsConnection, path.c_str());
|
||||||
@@ -1197,68 +1204,77 @@ void MPD::Connection::GetDirectory(const std::string &path, std::function<void(I
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
mpd_entity_free(item);
|
mpd_entity_free(item);
|
||||||
f(std::move(it));
|
result.push_back(std::move(it));
|
||||||
}
|
}
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetDirectoryRecursive(const std::string &path, std::function<void(MPD::Song &&)> f)
|
MPD::SongList MPD::Connection::GetDirectoryRecursive(const std::string &path)
|
||||||
{
|
{
|
||||||
|
SongList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_all_meta(itsConnection, path.c_str());
|
mpd_send_list_all_meta(itsConnection, path.c_str());
|
||||||
while (mpd_song *s = mpd_recv_song(itsConnection))
|
while (mpd_song *s = mpd_recv_song(itsConnection))
|
||||||
f(Song(s));
|
result.push_back(Song(s));
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetDirectories(const std::string &path, TagList &v)
|
MPD::StringList MPD::Connection::GetDirectories(const std::string &path)
|
||||||
{
|
{
|
||||||
|
StringList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_meta(itsConnection, path.c_str());
|
mpd_send_list_meta(itsConnection, path.c_str());
|
||||||
while (mpd_directory *dir = mpd_recv_directory(itsConnection))
|
while (mpd_directory *dir = mpd_recv_directory(itsConnection))
|
||||||
{
|
{
|
||||||
v.push_back(mpd_directory_get_path(dir));
|
result.push_back(mpd_directory_get_path(dir));
|
||||||
mpd_directory_free(dir);
|
mpd_directory_free(dir);
|
||||||
}
|
}
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetSongs(const std::string &path, SongList &v)
|
MPD::SongList MPD::Connection::GetSongs(const std::string &path)
|
||||||
{
|
{
|
||||||
|
SongList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_meta(itsConnection, path.c_str());
|
mpd_send_list_meta(itsConnection, path.c_str());
|
||||||
while (mpd_song *s = mpd_recv_song(itsConnection))
|
while (mpd_song *s = mpd_recv_song(itsConnection))
|
||||||
v.push_back(Song(s));
|
result.push_back(Song(s));
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetOutputs(std::function<void(Output &&)> f)
|
MPD::OutputList MPD::Connection::GetOutputs()
|
||||||
{
|
{
|
||||||
|
OutputList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_outputs(itsConnection);
|
mpd_send_outputs(itsConnection);
|
||||||
while (mpd_output *output = mpd_recv_output(itsConnection))
|
while (mpd_output *output = mpd_recv_output(itsConnection))
|
||||||
{
|
{
|
||||||
f(Output(mpd_output_get_name(output), mpd_output_get_enabled(output)));
|
result.push_back(Output(mpd_output_get_name(output), mpd_output_get_enabled(output)));
|
||||||
mpd_output_free(output);
|
mpd_output_free(output);
|
||||||
}
|
}
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MPD::Connection::EnableOutput(int id)
|
bool MPD::Connection::EnableOutput(int id)
|
||||||
@@ -1293,36 +1309,40 @@ bool MPD::Connection::DisableOutput(int id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetURLHandlers(std::function<void(std::string &&)> f)
|
MPD::StringList MPD::Connection::GetURLHandlers()
|
||||||
{
|
{
|
||||||
|
StringList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_url_schemes(itsConnection);
|
mpd_send_list_url_schemes(itsConnection);
|
||||||
while (mpd_pair *handler = mpd_recv_pair_named(itsConnection, "handler"))
|
while (mpd_pair *handler = mpd_recv_pair_named(itsConnection, "handler"))
|
||||||
{
|
{
|
||||||
f(handler->value);
|
result.push_back(handler->value);
|
||||||
mpd_return_pair(itsConnection, handler);
|
mpd_return_pair(itsConnection, handler);
|
||||||
}
|
}
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MPD::Connection::GetTagTypes(std::function<void(std::string &&)> f)
|
MPD::StringList MPD::Connection::GetTagTypes()
|
||||||
{
|
{
|
||||||
|
StringList result;
|
||||||
if (!itsConnection)
|
if (!itsConnection)
|
||||||
return;
|
return result;
|
||||||
assert(!isCommandsListEnabled);
|
assert(!isCommandsListEnabled);
|
||||||
GoBusy();
|
GoBusy();
|
||||||
mpd_send_list_tag_types(itsConnection);
|
mpd_send_list_tag_types(itsConnection);
|
||||||
while (mpd_pair *tag_type = mpd_recv_pair_named(itsConnection, "tagtype"))
|
while (mpd_pair *tag_type = mpd_recv_pair_named(itsConnection, "tagtype"))
|
||||||
{
|
{
|
||||||
f(tag_type->value);
|
result.push_back(tag_type->value);
|
||||||
mpd_return_pair(itsConnection, tag_type);
|
mpd_return_pair(itsConnection, tag_type);
|
||||||
}
|
}
|
||||||
mpd_response_finish(itsConnection);
|
mpd_response_finish(itsConnection);
|
||||||
GoIdle();
|
GoIdle();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MPD::Connection::CheckForErrors()
|
int MPD::Connection::CheckForErrors()
|
||||||
|
|||||||
30
src/mpdpp.h
30
src/mpdpp.h
@@ -74,7 +74,7 @@ namespace MPD
|
|||||||
|
|
||||||
typedef std::vector<Item> ItemList;
|
typedef std::vector<Item> ItemList;
|
||||||
typedef std::vector<Song> SongList;
|
typedef std::vector<Song> SongList;
|
||||||
typedef std::vector<std::string> TagList;
|
typedef std::vector<std::string> StringList;
|
||||||
typedef std::vector<Output> OutputList;
|
typedef std::vector<Output> OutputList;
|
||||||
|
|
||||||
class Connection
|
class Connection
|
||||||
@@ -153,15 +153,15 @@ namespace MPD
|
|||||||
unsigned long DBPlayTime() const { return itsStats ? mpd_stats_get_db_play_time(itsStats) : 0; }
|
unsigned long DBPlayTime() const { return itsStats ? mpd_stats_get_db_play_time(itsStats) : 0; }
|
||||||
|
|
||||||
size_t GetPlaylistLength() const { return itsCurrentStatus ? mpd_status_get_queue_length(itsCurrentStatus) : 0; }
|
size_t GetPlaylistLength() const { return itsCurrentStatus ? mpd_status_get_queue_length(itsCurrentStatus) : 0; }
|
||||||
void GetPlaylistChanges(unsigned, std::function<void(Song &&)> f);
|
SongList GetPlaylistChanges(unsigned);
|
||||||
|
|
||||||
const std::string & GetErrorMessage() const { return itsErrorMessage; }
|
const std::string &GetErrorMessage() const { return itsErrorMessage; }
|
||||||
|
|
||||||
Song GetCurrentlyPlayingSong();
|
Song GetCurrentlyPlayingSong();
|
||||||
int GetCurrentlyPlayingSongPos() const;
|
int GetCurrentlyPlayingSongPos() const;
|
||||||
int GetCurrentSongPos() const;
|
int GetCurrentSongPos() const;
|
||||||
Song GetSong(const std::string &);
|
Song GetSong(const std::string &);
|
||||||
void GetPlaylistContent(const std::string &, std::function<void(Song &&)> f);
|
SongList GetPlaylistContent(const std::string &);
|
||||||
|
|
||||||
void GetSupportedExtensions(std::set<std::string> &);
|
void GetSupportedExtensions(std::set<std::string> &);
|
||||||
|
|
||||||
@@ -202,22 +202,22 @@ namespace MPD
|
|||||||
void AddSearch(mpd_tag_type, const std::string &) const;
|
void AddSearch(mpd_tag_type, const std::string &) const;
|
||||||
void AddSearchAny(const std::string &str) const;
|
void AddSearchAny(const std::string &str) const;
|
||||||
void AddSearchURI(const std::string &str) const;
|
void AddSearchURI(const std::string &str) const;
|
||||||
void CommitSearchSongs(std::function<void(Song &&)> f);
|
SongList CommitSearchSongs();
|
||||||
void CommitSearchTags(std::function<void(std::string &&)> f);
|
StringList CommitSearchTags();
|
||||||
|
|
||||||
void GetPlaylists(TagList &);
|
StringList GetPlaylists();
|
||||||
void GetList(TagList &, mpd_tag_type);
|
StringList GetList(mpd_tag_type);
|
||||||
void GetDirectory(const std::string &, std::function<void(Item &&)> f);
|
ItemList GetDirectory(const std::string &);
|
||||||
void GetDirectoryRecursive(const std::string &, std::function<void(Song &&)> f);
|
SongList GetDirectoryRecursive(const std::string &);
|
||||||
void GetSongs(const std::string &, SongList &);
|
SongList GetSongs(const std::string &);
|
||||||
void GetDirectories(const std::string &, TagList &);
|
StringList GetDirectories(const std::string &);
|
||||||
|
|
||||||
void GetOutputs(std::function<void(Output &&)> f);
|
OutputList GetOutputs();
|
||||||
bool EnableOutput(int);
|
bool EnableOutput(int);
|
||||||
bool DisableOutput(int);
|
bool DisableOutput(int);
|
||||||
|
|
||||||
void GetURLHandlers(std::function<void(std::string &&)> f);
|
StringList GetURLHandlers();
|
||||||
void GetTagTypes(std::function<void(std::string &&)> f);
|
StringList GetTagTypes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GoIdle();
|
void GoIdle();
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ void Outputs::FetchList()
|
|||||||
if (!isInitialized)
|
if (!isInitialized)
|
||||||
return;
|
return;
|
||||||
w->Clear();
|
w->Clear();
|
||||||
Mpd.GetOutputs([this](MPD::Output &&o) {
|
auto outputs = Mpd.GetOutputs();
|
||||||
w->AddItem(o, o.isEnabled());
|
for (auto o = outputs.begin(); o != outputs.end(); ++o)
|
||||||
});
|
w->AddItem(*o, o->isEnabled());
|
||||||
if (myScreen == this)
|
if (myScreen == this)
|
||||||
w->Refresh();
|
w->Refresh();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,23 +269,6 @@ void Playlist::MouseButtonPressed(MEVENT me)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::Song *Playlist::CurrentSong()
|
|
||||||
{
|
|
||||||
return w == Items && !Items->Empty() ? &Items->Current().value() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Playlist::GetSelectedSongs(MPD::SongList &v)
|
|
||||||
{
|
|
||||||
if (Items->Empty())
|
|
||||||
return;
|
|
||||||
std::vector<size_t> selected;
|
|
||||||
Items->GetSelected(selected);
|
|
||||||
if (selected.empty())
|
|
||||||
selected.push_back(Items->Choice());
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
v.push_back(Items->at(*it).value());
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
std::string Playlist::currentFilter()
|
std::string Playlist::currentFilter()
|
||||||
@@ -333,6 +316,54 @@ void Playlist::prevFound(bool wrap)
|
|||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
|
MPD::Song *Playlist::getSong(size_t pos)
|
||||||
|
{
|
||||||
|
MPD::Song *ptr = 0;
|
||||||
|
if (w == Items)
|
||||||
|
ptr = &(*Items)[pos].value();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::Song *Playlist::currentSong()
|
||||||
|
{
|
||||||
|
if (Items->Empty())
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return getSong(Items->Choice());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Playlist::allowsSelection()
|
||||||
|
{
|
||||||
|
return w == Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Playlist::removeSelection()
|
||||||
|
{
|
||||||
|
removeSelectionHelper(Items->Begin(), Items->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Playlist::reverseSelection()
|
||||||
|
{
|
||||||
|
reverseSelectionHelper(Items->Begin(), Items->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::SongList Playlist::getSelectedSongs()
|
||||||
|
{
|
||||||
|
MPD::SongList result;
|
||||||
|
if (w == Items)
|
||||||
|
{
|
||||||
|
for (auto it = Items->Begin(); it != Items->End(); ++it)
|
||||||
|
if (it->isSelected())
|
||||||
|
result.push_back(it->value());
|
||||||
|
if (result.empty() && !Items->Empty())
|
||||||
|
result.push_back(Items->Current().value());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
bool Playlist::isFiltered()
|
bool Playlist::isFiltered()
|
||||||
{
|
{
|
||||||
if (Items->isFiltered())
|
if (Items->isFiltered())
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
|
|
||||||
class Playlist : public Screen<Window>, public Filterable, public Searchable
|
class Playlist : public Screen<Window>, public Filterable, public HasSongs, public Searchable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Movement { mUp, mDown };
|
enum Movement { mUp, mDown };
|
||||||
@@ -44,13 +44,6 @@ class Playlist : public Screen<Window>, public Filterable, public Searchable
|
|||||||
virtual void MouseButtonPressed(MEVENT);
|
virtual void MouseButtonPressed(MEVENT);
|
||||||
virtual bool isTabbable() { return true; }
|
virtual bool isTabbable() { return true; }
|
||||||
|
|
||||||
virtual MPD::Song *CurrentSong();
|
|
||||||
virtual MPD::Song *GetSong(size_t pos) { return w == Items ? &Items->at(pos).value() : 0; }
|
|
||||||
|
|
||||||
virtual bool allowsSelection() { return w == Items; }
|
|
||||||
virtual void ReverseSelection() { Items->ReverseSelection(); }
|
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
|
||||||
|
|
||||||
/// Filterable implementation
|
/// Filterable implementation
|
||||||
virtual std::string currentFilter();
|
virtual std::string currentFilter();
|
||||||
virtual void applyFilter(const std::string &filter);
|
virtual void applyFilter(const std::string &filter);
|
||||||
@@ -60,6 +53,15 @@ class Playlist : public Screen<Window>, public Filterable, public Searchable
|
|||||||
virtual void nextFound(bool wrap);
|
virtual void nextFound(bool wrap);
|
||||||
virtual void prevFound(bool wrap);
|
virtual void prevFound(bool wrap);
|
||||||
|
|
||||||
|
/// HasSongs implementation
|
||||||
|
virtual MPD::Song *getSong(size_t pos);
|
||||||
|
virtual MPD::Song *currentSong();
|
||||||
|
|
||||||
|
virtual bool allowsSelection();
|
||||||
|
virtual void reverseSelection();
|
||||||
|
virtual void removeSelection();
|
||||||
|
virtual MPD::SongList getSelectedSongs();
|
||||||
|
|
||||||
virtual List *GetList() { return w == Items ? Items : 0; }
|
virtual List *GetList() { return w == Items ? Items : 0; }
|
||||||
|
|
||||||
virtual bool isMergable() { return true; }
|
virtual bool isMergable() { return true; }
|
||||||
|
|||||||
@@ -60,9 +60,11 @@ void PlaylistEditor::Init()
|
|||||||
Playlists->HighlightColor(Config.active_column_color);
|
Playlists->HighlightColor(Config.active_column_color);
|
||||||
Playlists->CyclicScrolling(Config.use_cyclic_scrolling);
|
Playlists->CyclicScrolling(Config.use_cyclic_scrolling);
|
||||||
Playlists->CenteredCursor(Config.centered_cursor);
|
Playlists->CenteredCursor(Config.centered_cursor);
|
||||||
|
Playlists->SetSelectPrefix(Config.selected_item_prefix);
|
||||||
|
Playlists->SetSelectSuffix(Config.selected_item_suffix);
|
||||||
Playlists->setItemDisplayer(Display::Default<std::string>);
|
Playlists->setItemDisplayer(Display::Default<std::string>);
|
||||||
|
|
||||||
Content = new Menu<MPD::Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, Config.titles_visibility ? "Playlist's content" : "", Config.main_color, brNone);
|
Content = new Menu<MPD::Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, Config.titles_visibility ? "Playlist content" : "", Config.main_color, brNone);
|
||||||
Content->HighlightColor(Config.main_highlight_color);
|
Content->HighlightColor(Config.main_highlight_color);
|
||||||
Content->CyclicScrolling(Config.use_cyclic_scrolling);
|
Content->CyclicScrolling(Config.use_cyclic_scrolling);
|
||||||
Content->CenteredCursor(Config.centered_cursor);
|
Content->CenteredCursor(Config.centered_cursor);
|
||||||
@@ -138,15 +140,10 @@ void PlaylistEditor::Update()
|
|||||||
if (Playlists->ReallyEmpty())
|
if (Playlists->ReallyEmpty())
|
||||||
{
|
{
|
||||||
Content->Clear();
|
Content->Clear();
|
||||||
MPD::TagList list;
|
auto list = Mpd.GetPlaylists();
|
||||||
Mpd.GetPlaylists(list);
|
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
||||||
sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
for (MPD::TagList::iterator it = list.begin(); it != list.end(); ++it)
|
|
||||||
{
|
|
||||||
utf_to_locale(*it);
|
|
||||||
Playlists->AddItem(*it);
|
Playlists->AddItem(*it);
|
||||||
}
|
|
||||||
Playlists->Window::Clear();
|
|
||||||
Playlists->Refresh();
|
Playlists->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,20 +151,26 @@ void PlaylistEditor::Update()
|
|||||||
{
|
{
|
||||||
Content->Reset();
|
Content->Reset();
|
||||||
size_t plsize = 0;
|
size_t plsize = 0;
|
||||||
Mpd.GetPlaylistContent(locale_to_utf_cpy(Playlists->Current().value()), [this, &plsize](MPD::Song &&s) {
|
auto songs = Mpd.GetPlaylistContent(Playlists->Current().value());
|
||||||
Content->AddItem(s, myPlaylist->checkForSong(s));
|
for (auto s = songs.begin(); s != songs.end(); ++s, ++plsize)
|
||||||
++plsize;
|
Content->AddItem(*s, myPlaylist->checkForSong(*s));
|
||||||
});
|
std::string title;
|
||||||
if (plsize > 0)
|
if (Config.titles_visibility)
|
||||||
{
|
{
|
||||||
std::string title = Config.titles_visibility ? "Playlist content (" + unsignedLongIntTo<std::string>::apply(plsize) + " item" + (plsize == 1 ? ")" : "s)") : "";
|
title = "Playlist content";
|
||||||
|
if (plsize > 0)
|
||||||
|
{
|
||||||
|
title += " (";
|
||||||
|
title += unsignedLongIntTo<std::string>::apply(plsize);
|
||||||
|
title += " item";
|
||||||
|
if (plsize == 1)
|
||||||
|
title += ")";
|
||||||
|
else
|
||||||
|
title += "s)";
|
||||||
|
}
|
||||||
title.resize(Content->GetWidth());
|
title.resize(Content->GetWidth());
|
||||||
Content->SetTitle(title);
|
|
||||||
}
|
}
|
||||||
else
|
Content->SetTitle(title);
|
||||||
Content->SetTitle(Config.titles_visibility ? "Playlist content" : "");
|
|
||||||
|
|
||||||
Content->Window::Clear();
|
|
||||||
Content->Display();
|
Content->Display();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,13 +354,27 @@ void PlaylistEditor::AddToPlaylist(bool add_n_play)
|
|||||||
|
|
||||||
void PlaylistEditor::SpacePressed()
|
void PlaylistEditor::SpacePressed()
|
||||||
{
|
{
|
||||||
if (Config.space_selects && w == Content)
|
if (Config.space_selects)
|
||||||
{
|
{
|
||||||
Content->Current().setSelected(!Content->Current().isSelected());
|
if (w == Playlists)
|
||||||
w->Scroll(wDown);
|
{
|
||||||
|
if (!Playlists->Empty())
|
||||||
|
{
|
||||||
|
Playlists->Current().setSelected(!Playlists->Current().isSelected());
|
||||||
|
Playlists->Scroll(wDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (w == Content)
|
||||||
|
{
|
||||||
|
if (!Content->Empty())
|
||||||
|
{
|
||||||
|
Content->Current().setSelected(!Content->Current().isSelected());
|
||||||
|
Content->Scroll(wDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
AddToPlaylist(0);
|
AddToPlaylist(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaylistEditor::MouseButtonPressed(MEVENT me)
|
void PlaylistEditor::MouseButtonPressed(MEVENT me)
|
||||||
@@ -403,21 +420,6 @@ void PlaylistEditor::MouseButtonPressed(MEVENT me)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::Song *PlaylistEditor::CurrentSong()
|
|
||||||
{
|
|
||||||
return w == Content && !Content->Empty() ? &Content->Current().value() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlaylistEditor::GetSelectedSongs(MPD::SongList &v)
|
|
||||||
{
|
|
||||||
std::vector<size_t> selected;
|
|
||||||
Content->GetSelected(selected);
|
|
||||||
if (selected.empty())
|
|
||||||
selected.push_back(Content->Choice());
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
v.push_back(Content->at(*it).value());
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
std::string PlaylistEditor::currentFilter()
|
std::string PlaylistEditor::currentFilter()
|
||||||
@@ -482,6 +484,81 @@ void PlaylistEditor::prevFound(bool wrap)
|
|||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
|
MPD::Song *PlaylistEditor::getSong(size_t pos)
|
||||||
|
{
|
||||||
|
MPD::Song *ptr = 0;
|
||||||
|
if (w == Content)
|
||||||
|
ptr = &(*Content)[pos].value();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::Song *PlaylistEditor::currentSong()
|
||||||
|
{
|
||||||
|
if (w == Content && !Content->Empty())
|
||||||
|
return getSong(Content->Choice());
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlaylistEditor::allowsSelection()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaylistEditor::removeSelection()
|
||||||
|
{
|
||||||
|
if (w == Playlists)
|
||||||
|
removeSelectionHelper(Playlists->Begin(), Playlists->End());
|
||||||
|
else if (w == Content)
|
||||||
|
removeSelectionHelper(Content->Begin(), Content->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaylistEditor::reverseSelection()
|
||||||
|
{
|
||||||
|
if (w == Playlists)
|
||||||
|
reverseSelectionHelper(Playlists->Begin(), Playlists->End());
|
||||||
|
else if (w == Content)
|
||||||
|
reverseSelectionHelper(Content->Begin(), Content->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::SongList PlaylistEditor::getSelectedSongs()
|
||||||
|
{
|
||||||
|
MPD::SongList result;
|
||||||
|
if (w == Playlists)
|
||||||
|
{
|
||||||
|
bool any_selected = false;
|
||||||
|
for (auto it = Playlists->Begin(); it != Playlists->End(); ++it)
|
||||||
|
{
|
||||||
|
if (it->isSelected())
|
||||||
|
{
|
||||||
|
any_selected = true;
|
||||||
|
auto songs = Mpd.GetPlaylistContent(it->value());
|
||||||
|
result.insert(result.end(), songs.begin(), songs.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// we don't check for empty result here as it's possible that
|
||||||
|
// all selected playlists are empty.
|
||||||
|
if (!any_selected && !Content->Empty())
|
||||||
|
{
|
||||||
|
withUnfilteredMenu(*Content, [this, &result]() {
|
||||||
|
result.insert(result.end(), Content->BeginV(), Content->EndV());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (w == Content)
|
||||||
|
{
|
||||||
|
for (auto it = Content->Begin(); it != Content->End(); ++it)
|
||||||
|
if (it->isSelected())
|
||||||
|
result.push_back(it->value());
|
||||||
|
// if no item is selected, add current one
|
||||||
|
if (result.empty() && !Content->Empty())
|
||||||
|
result.push_back(Content->Current().value());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
void PlaylistEditor::Locate(const std::string &name)
|
void PlaylistEditor::Locate(const std::string &name)
|
||||||
{
|
{
|
||||||
if (!isInitialized)
|
if (!isInitialized)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
#include "ncmpcpp.h"
|
#include "ncmpcpp.h"
|
||||||
|
|
||||||
class PlaylistEditor : public Screen<Window>, public Filterable, public Searchable
|
class PlaylistEditor : public Screen<Window>, public Filterable, public HasSongs, public Searchable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void SwitchTo();
|
virtual void SwitchTo();
|
||||||
@@ -40,13 +40,6 @@ class PlaylistEditor : public Screen<Window>, public Filterable, public Searchab
|
|||||||
virtual void MouseButtonPressed(MEVENT);
|
virtual void MouseButtonPressed(MEVENT);
|
||||||
virtual bool isTabbable() { return true; }
|
virtual bool isTabbable() { return true; }
|
||||||
|
|
||||||
virtual MPD::Song *CurrentSong();
|
|
||||||
virtual MPD::Song *GetSong(size_t pos) { return w == Content ? &Content->at(pos).value() : 0; }
|
|
||||||
|
|
||||||
virtual bool allowsSelection() { return w == Content; }
|
|
||||||
virtual void ReverseSelection() { Content->ReverseSelection(); }
|
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
|
||||||
|
|
||||||
/// Filterable implementation
|
/// Filterable implementation
|
||||||
virtual std::string currentFilter();
|
virtual std::string currentFilter();
|
||||||
virtual void applyFilter(const std::string &filter);
|
virtual void applyFilter(const std::string &filter);
|
||||||
@@ -56,6 +49,15 @@ class PlaylistEditor : public Screen<Window>, public Filterable, public Searchab
|
|||||||
virtual void nextFound(bool wrap);
|
virtual void nextFound(bool wrap);
|
||||||
virtual void prevFound(bool wrap);
|
virtual void prevFound(bool wrap);
|
||||||
|
|
||||||
|
/// HasSongs implementation
|
||||||
|
virtual MPD::Song *getSong(size_t pos);
|
||||||
|
virtual MPD::Song *currentSong();
|
||||||
|
|
||||||
|
virtual bool allowsSelection();
|
||||||
|
virtual void reverseSelection();
|
||||||
|
virtual void removeSelection();
|
||||||
|
virtual MPD::SongList getSelectedSongs();
|
||||||
|
|
||||||
virtual void Locate(const std::string &);
|
virtual void Locate(const std::string &);
|
||||||
|
|
||||||
virtual List *GetList();
|
virtual List *GetList();
|
||||||
|
|||||||
@@ -42,6 +42,16 @@ Regex::~Regex()
|
|||||||
regfree(&m_rx);
|
regfree(&m_rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &Regex::regex() const
|
||||||
|
{
|
||||||
|
return m_regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &Regex::error() const
|
||||||
|
{
|
||||||
|
return m_error;
|
||||||
|
}
|
||||||
|
|
||||||
bool Regex::compile()
|
bool Regex::compile()
|
||||||
{
|
{
|
||||||
if (m_compiled)
|
if (m_compiled)
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ struct Regex
|
|||||||
virtual ~Regex();
|
virtual ~Regex();
|
||||||
|
|
||||||
/// @return regular expression
|
/// @return regular expression
|
||||||
const std::string ®ex() const { return m_regex; }
|
const std::string ®ex() const;
|
||||||
|
|
||||||
/// @return compilation error (if there was any)
|
/// @return compilation error (if there was any)
|
||||||
const std::string &error() const { return m_error; }
|
const std::string &error() const;
|
||||||
|
|
||||||
/// compiles regular expression
|
/// compiles regular expression
|
||||||
/// @result true if compilation was successful, false otherwise
|
/// @result true if compilation was successful, false otherwise
|
||||||
@@ -59,4 +59,4 @@ private:
|
|||||||
bool m_compiled;
|
bool m_compiled;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _REGEXES_H
|
#endif // _REGEXES_H
|
||||||
|
|||||||
48
src/screen.h
48
src/screen.h
@@ -46,84 +46,46 @@ class BasicScreen
|
|||||||
virtual ~BasicScreen() { }
|
virtual ~BasicScreen() { }
|
||||||
|
|
||||||
/// @see Screen::ActiveWindow()
|
/// @see Screen::ActiveWindow()
|
||||||
///
|
|
||||||
virtual Window *ActiveWindow() = 0;
|
virtual Window *ActiveWindow() = 0;
|
||||||
|
|
||||||
/// Method used for switching to screen
|
/// Method used for switching to screen
|
||||||
///
|
|
||||||
virtual void SwitchTo() = 0;
|
virtual void SwitchTo() = 0;
|
||||||
|
|
||||||
/// Method that should resize screen
|
/// Method that should resize screen
|
||||||
/// if requested by hasToBeResized
|
/// if requested by hasToBeResized
|
||||||
///
|
|
||||||
virtual void Resize() = 0;
|
virtual void Resize() = 0;
|
||||||
|
|
||||||
/// @return title of the screen
|
/// @return title of the screen
|
||||||
///
|
|
||||||
virtual std::basic_string<my_char_t> Title() = 0;
|
virtual std::basic_string<my_char_t> Title() = 0;
|
||||||
|
|
||||||
/// If the screen contantly has to update itself
|
/// If the screen contantly has to update itself
|
||||||
/// somehow, it should be called by this function.
|
/// somehow, it should be called by this function.
|
||||||
///
|
|
||||||
virtual void Update() { }
|
virtual void Update() { }
|
||||||
|
|
||||||
/// @see Screen::Refresh()
|
/// @see Screen::Refresh()
|
||||||
///
|
|
||||||
virtual void Refresh() = 0;
|
virtual void Refresh() = 0;
|
||||||
|
|
||||||
/// @see Screen::RefreshWindow()
|
/// @see Screen::RefreshWindow()
|
||||||
///
|
|
||||||
virtual void RefreshWindow() = 0;
|
virtual void RefreshWindow() = 0;
|
||||||
|
|
||||||
/// @see Screen::Scroll()
|
/// @see Screen::Scroll()
|
||||||
///
|
|
||||||
virtual void Scroll(Where where) = 0;
|
virtual void Scroll(Where where) = 0;
|
||||||
|
|
||||||
/// Invoked after Enter was pressed
|
/// Invoked after Enter was pressed
|
||||||
///
|
|
||||||
virtual void EnterPressed() = 0;
|
virtual void EnterPressed() = 0;
|
||||||
|
|
||||||
/// Invoked after Space was pressed
|
/// Invoked after Space was pressed
|
||||||
///
|
|
||||||
virtual void SpacePressed() = 0;
|
virtual void SpacePressed() = 0;
|
||||||
|
|
||||||
/// @see Screen::MouseButtonPressed()
|
/// @see Screen::MouseButtonPressed()
|
||||||
///
|
|
||||||
virtual void MouseButtonPressed(MEVENT) { }
|
virtual void MouseButtonPressed(MEVENT) { }
|
||||||
|
|
||||||
/// @return pointer to currently selected song in the screen
|
|
||||||
/// (if screen provides one) or null pointer otherwise.
|
|
||||||
///
|
|
||||||
virtual MPD::Song *CurrentSong() { return 0; }
|
|
||||||
|
|
||||||
/// @return pointer to song at given position in the screen
|
|
||||||
/// (if screen is provides one) or null pointer otherwise.
|
|
||||||
///
|
|
||||||
virtual MPD::Song *GetSong(GNUC_UNUSED size_t pos) { return 0; }
|
|
||||||
|
|
||||||
/// @return true if the screen allows selecting items, false otherwise
|
|
||||||
///
|
|
||||||
virtual bool allowsSelection() = 0;
|
|
||||||
|
|
||||||
/// Reverses selection. Does nothing by default since pure
|
|
||||||
/// virtual allowsSelection() should remind of this function
|
|
||||||
/// to be defined
|
|
||||||
///
|
|
||||||
virtual void ReverseSelection() { }
|
|
||||||
|
|
||||||
/// Gets selected songs' positions from the screen
|
|
||||||
/// @param v vector to be filled with positions
|
|
||||||
///
|
|
||||||
virtual void GetSelectedSongs(GNUC_UNUSED MPD::SongList &v) { }
|
|
||||||
|
|
||||||
/// @return pointer to instantiation of Menu template class
|
/// @return pointer to instantiation of Menu template class
|
||||||
/// cast to List if available or null pointer otherwise
|
/// cast to List if available or null pointer otherwise
|
||||||
///
|
|
||||||
virtual List *GetList() = 0;
|
virtual List *GetList() = 0;
|
||||||
|
|
||||||
/// When this is overwritten with a function returning true, the
|
/// When this is overwritten with a function returning true, the
|
||||||
/// screen will be used in tab switching.
|
/// screen will be used in tab switching.
|
||||||
///
|
|
||||||
virtual bool isTabbable() { return false; }
|
virtual bool isTabbable() { return false; }
|
||||||
|
|
||||||
/// @return true if screen is mergable, ie. can be "proper" subwindow
|
/// @return true if screen is mergable, ie. can be "proper" subwindow
|
||||||
@@ -137,7 +99,6 @@ class BasicScreen
|
|||||||
bool Lock();
|
bool Lock();
|
||||||
|
|
||||||
/// Should be set to true each time screen needs resize
|
/// Should be set to true each time screen needs resize
|
||||||
///
|
|
||||||
bool hasToBeResized;
|
bool hasToBeResized;
|
||||||
|
|
||||||
/// Unlocks a screen, ie. hides merged window (if there is one set).
|
/// Unlocks a screen, ie. hides merged window (if there is one set).
|
||||||
@@ -182,33 +143,26 @@ template <typename WindowType> class Screen : public BasicScreen
|
|||||||
/// it's useful to determine the one that is being
|
/// it's useful to determine the one that is being
|
||||||
/// active
|
/// active
|
||||||
/// @return address to window object cast to void *
|
/// @return address to window object cast to void *
|
||||||
///
|
|
||||||
virtual Window *ActiveWindow();
|
virtual Window *ActiveWindow();
|
||||||
|
|
||||||
/// @return pointer to currently active window
|
/// @return pointer to currently active window
|
||||||
///
|
|
||||||
WindowType *Main();
|
WindowType *Main();
|
||||||
|
|
||||||
/// Refreshes whole screen
|
/// Refreshes whole screen
|
||||||
///
|
|
||||||
virtual void Refresh();
|
virtual void Refresh();
|
||||||
|
|
||||||
/// Refreshes active window of the screen
|
/// Refreshes active window of the screen
|
||||||
///
|
|
||||||
virtual void RefreshWindow();
|
virtual void RefreshWindow();
|
||||||
|
|
||||||
|
|
||||||
/// Scrolls the screen by given amount of lines and
|
/// Scrolls the screen by given amount of lines and
|
||||||
/// if fancy scrolling feature is disabled, enters the
|
/// if fancy scrolling feature is disabled, enters the
|
||||||
/// loop that holds main loop until user releases the key
|
/// loop that holds main loop until user releases the key
|
||||||
/// @param where indicates where one wants to scroll
|
/// @param where indicates where one wants to scroll
|
||||||
///
|
|
||||||
virtual void Scroll(Where where);
|
virtual void Scroll(Where where);
|
||||||
|
|
||||||
/// Invoked after there was one of mouse buttons pressed
|
/// Invoked after there was one of mouse buttons pressed
|
||||||
/// @param me struct that contains coords of where the click
|
/// @param me struct that contains coords of where the click
|
||||||
/// had its place and button actions
|
/// had its place and button actions
|
||||||
///
|
|
||||||
virtual void MouseButtonPressed(MEVENT me);
|
virtual void MouseButtonPressed(MEVENT me);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -216,7 +170,6 @@ template <typename WindowType> class Screen : public BasicScreen
|
|||||||
/// of window used by the screen. What is more, it should
|
/// of window used by the screen. What is more, it should
|
||||||
/// always be assigned to the currently active window (if
|
/// always be assigned to the currently active window (if
|
||||||
/// acreen contains more that one)
|
/// acreen contains more that one)
|
||||||
///
|
|
||||||
WindowType *w;
|
WindowType *w;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -268,7 +221,6 @@ template <typename WindowType> void Screen<WindowType>::MouseButtonPressed(MEVEN
|
|||||||
/// Specialization for Screen<Scrollpad>::MouseButtonPressed, that should
|
/// Specialization for Screen<Scrollpad>::MouseButtonPressed, that should
|
||||||
/// not scroll whole page, but rather a few lines (the number of them is
|
/// not scroll whole page, but rather a few lines (the number of them is
|
||||||
/// defined in the config)
|
/// defined in the config)
|
||||||
///
|
|
||||||
template <> inline void Screen<Scrollpad>::MouseButtonPressed(MEVENT me)
|
template <> inline void Screen<Scrollpad>::MouseButtonPressed(MEVENT me)
|
||||||
{
|
{
|
||||||
if (me.bstate & BUTTON2_PRESSED)
|
if (me.bstate & BUTTON2_PRESSED)
|
||||||
|
|||||||
@@ -276,26 +276,6 @@ void SearchEngine::MouseButtonPressed(MEVENT me)
|
|||||||
Screen< Menu<SEItem> >::MouseButtonPressed(me);
|
Screen< Menu<SEItem> >::MouseButtonPressed(me);
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::Song *SearchEngine::CurrentSong()
|
|
||||||
{
|
|
||||||
return !w->Empty() && w->Current().value().isSong() ? &w->Current().value().song() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SearchEngine::GetSelectedSongs(MPD::SongList &v)
|
|
||||||
{
|
|
||||||
if (w->Empty())
|
|
||||||
return;
|
|
||||||
std::vector<size_t> selected;
|
|
||||||
w->GetSelected(selected);
|
|
||||||
if (selected.empty() && w->Choice() >= StaticOptions)
|
|
||||||
selected.push_back(w->Choice());
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
{
|
|
||||||
assert(w->at(*it).value().isSong());
|
|
||||||
v.push_back(w->at(*it).value().song());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
std::string SearchEngine::currentFilter()
|
std::string SearchEngine::currentFilter()
|
||||||
@@ -332,22 +312,65 @@ void SearchEngine::prevFound(bool wrap)
|
|||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
|
MPD::Song *SearchEngine::getSong(size_t pos)
|
||||||
|
{
|
||||||
|
MPD::Song *ptr = 0;
|
||||||
|
auto &item = (*w)[pos];
|
||||||
|
if (!item.isSeparator() && item.value().isSong())
|
||||||
|
ptr = &item.value().song();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::Song *SearchEngine::currentSong()
|
||||||
|
{
|
||||||
|
if (w->Empty())
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return getSong(w->Choice());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchEngine::allowsSelection()
|
||||||
|
{
|
||||||
|
return w->Current().value().isSong();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchEngine::removeSelection()
|
||||||
|
{
|
||||||
|
removeSelectionHelper(w->Begin(), w->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchEngine::reverseSelection()
|
||||||
|
{
|
||||||
|
reverseSelectionHelper(w->Begin()+std::min(StaticOptions, w->Size()), w->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::SongList SearchEngine::getSelectedSongs()
|
||||||
|
{
|
||||||
|
MPD::SongList result;
|
||||||
|
for (auto it = w->Begin(); it != w->End(); ++it)
|
||||||
|
{
|
||||||
|
if (it->isSelected())
|
||||||
|
{
|
||||||
|
assert(it->value().isSong());
|
||||||
|
result.push_back(it->value().song());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if no item is selected, add current one
|
||||||
|
if (result.empty() && !w->Empty())
|
||||||
|
{
|
||||||
|
assert(w->Current().value().isSong());
|
||||||
|
result.push_back(w->Current().value().song());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
void SearchEngine::UpdateFoundList()
|
void SearchEngine::UpdateFoundList()
|
||||||
{
|
{
|
||||||
bool bold = 0;
|
for (auto it = w->Begin(); it != w->End(); ++it)
|
||||||
for (size_t i = StaticOptions; i < w->Size(); ++i)
|
if (it->value().isSong())
|
||||||
{
|
it->setBold(myPlaylist->checkForSong(it->value().song()));
|
||||||
for (size_t j = 0; j < myPlaylist->Items->Size(); ++j)
|
|
||||||
{
|
|
||||||
if (myPlaylist->Items->at(j).value().getHash() == w->at(i).value().song().getHash())
|
|
||||||
{
|
|
||||||
bold = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w->at(i).setBold(bold);
|
|
||||||
bold = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SearchEngine::Prepare()
|
void SearchEngine::Prepare()
|
||||||
@@ -422,30 +445,26 @@ void SearchEngine::Search()
|
|||||||
Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]);
|
Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]);
|
||||||
if (!itsConstraints[10].empty())
|
if (!itsConstraints[10].empty())
|
||||||
Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]);
|
Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]);
|
||||||
Mpd.CommitSearchSongs([this](MPD::Song &&s) {
|
auto songs = Mpd.CommitSearchSongs();
|
||||||
w->AddItem(s);
|
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||||
});
|
w->AddItem(*s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::SongList list;
|
MPD::SongList list;
|
||||||
if (Config.search_in_db)
|
if (Config.search_in_db)
|
||||||
{
|
list = Mpd.GetDirectoryRecursive("/");
|
||||||
Mpd.GetDirectoryRecursive("/", [&list](MPD::Song &&s) {
|
|
||||||
list.push_back(s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
list.reserve(myPlaylist->Items->Size());
|
list.reserve(myPlaylist->Items->Size());
|
||||||
for (size_t i = 0; i < myPlaylist->Items->Size(); ++i)
|
for (auto s = myPlaylist->Items->BeginV(); s != myPlaylist->Items->EndV(); ++s)
|
||||||
list.push_back((*myPlaylist->Items)[i].value());
|
list.push_back(*s);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool any_found = 1;
|
bool any_found = 1;
|
||||||
bool found = 1;
|
bool found = 1;
|
||||||
|
|
||||||
for (MPD::SongList::const_iterator it = list.begin(); it != list.end(); ++it)
|
for (auto it = list.begin(); it != list.end(); ++it)
|
||||||
{
|
{
|
||||||
if (SearchMode != &SearchModes[2]) // match to pattern
|
if (SearchMode != &SearchModes[2]) // match to pattern
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "interfaces.h"
|
#include "interfaces.h"
|
||||||
#include "mpdpp.h"
|
#include "mpdpp.h"
|
||||||
#include "ncmpcpp.h"
|
#include "ncmpcpp.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
struct SEItem
|
struct SEItem
|
||||||
{
|
{
|
||||||
@@ -73,7 +74,7 @@ struct SEItem
|
|||||||
MPD::Song itsSong;
|
MPD::Song itsSong;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SearchEngine : public Screen< Menu<SEItem> >, public Filterable, public Searchable
|
class SearchEngine : public Screen< Menu<SEItem> >, public Filterable, public HasSongs, public Searchable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void Resize();
|
virtual void Resize();
|
||||||
@@ -86,13 +87,6 @@ class SearchEngine : public Screen< Menu<SEItem> >, public Filterable, public Se
|
|||||||
virtual void MouseButtonPressed(MEVENT);
|
virtual void MouseButtonPressed(MEVENT);
|
||||||
virtual bool isTabbable() { return true; }
|
virtual bool isTabbable() { return true; }
|
||||||
|
|
||||||
virtual MPD::Song *CurrentSong();
|
|
||||||
virtual MPD::Song *GetSong(size_t pos) { return !(*w)[pos].isSeparator() && w->at(pos).value().isSong() ? &w->at(pos).value().song() : 0; }
|
|
||||||
|
|
||||||
virtual bool allowsSelection() { return w->Choice() >= StaticOptions; }
|
|
||||||
virtual void ReverseSelection() { w->ReverseSelection(StaticOptions); }
|
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
|
||||||
|
|
||||||
/// Filterable implementation
|
/// Filterable implementation
|
||||||
virtual std::string currentFilter();
|
virtual std::string currentFilter();
|
||||||
virtual void applyFilter(const std::string &filter);
|
virtual void applyFilter(const std::string &filter);
|
||||||
@@ -102,6 +96,15 @@ class SearchEngine : public Screen< Menu<SEItem> >, public Filterable, public Se
|
|||||||
virtual void nextFound(bool wrap);
|
virtual void nextFound(bool wrap);
|
||||||
virtual void prevFound(bool wrap);
|
virtual void prevFound(bool wrap);
|
||||||
|
|
||||||
|
/// HasSongs implementation
|
||||||
|
virtual MPD::Song *getSong(size_t pos);
|
||||||
|
virtual MPD::Song *currentSong();
|
||||||
|
|
||||||
|
virtual bool allowsSelection();
|
||||||
|
virtual void reverseSelection();
|
||||||
|
virtual void removeSelection();
|
||||||
|
virtual MPD::SongList getSelectedSongs();
|
||||||
|
|
||||||
virtual List *GetList() { return w->Size() >= StaticOptions ? w : 0; }
|
virtual List *GetList() { return w->Size() >= StaticOptions ? w : 0; }
|
||||||
|
|
||||||
virtual bool isMergable() { return true; }
|
virtual bool isMergable() { return true; }
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ void SelectedItemsAdder::SwitchTo()
|
|||||||
myOldScreen->SwitchTo();
|
myOldScreen->SwitchTo();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!myScreen->allowsSelection())
|
auto hs = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
if (!hs || !hs->allowsSelection())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (MainHeight < 5)
|
if (MainHeight < 5)
|
||||||
@@ -101,19 +102,14 @@ void SelectedItemsAdder::SwitchTo()
|
|||||||
w->AddItem("New playlist", 0, playlists_not_active);
|
w->AddItem("New playlist", 0, playlists_not_active);
|
||||||
w->AddSeparator();
|
w->AddSeparator();
|
||||||
|
|
||||||
MPD::TagList playlists;
|
auto playlists = Mpd.GetPlaylists();
|
||||||
Mpd.GetPlaylists(playlists);
|
|
||||||
std::sort(playlists.begin(), playlists.end(), CaseInsensitiveSorting());
|
std::sort(playlists.begin(), playlists.end(), CaseInsensitiveSorting());
|
||||||
for (MPD::TagList::iterator it = playlists.begin(); it != playlists.end(); ++it)
|
for (auto it = playlists.begin(); it != playlists.end(); ++it)
|
||||||
{
|
|
||||||
utf_to_locale(*it);
|
|
||||||
w->AddItem(*it, 0, playlists_not_active);
|
w->AddItem(*it, 0, playlists_not_active);
|
||||||
}
|
|
||||||
w->AddSeparator();
|
w->AddSeparator();
|
||||||
w->AddItem("Cancel");
|
w->AddItem("Cancel");
|
||||||
|
|
||||||
myScreen = this;
|
myScreen = this;
|
||||||
w->Window::Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectedItemsAdder::Resize()
|
void SelectedItemsAdder::Resize()
|
||||||
@@ -161,7 +157,7 @@ void SelectedItemsAdder::EnterPressed()
|
|||||||
|
|
||||||
MPD::SongList list;
|
MPD::SongList list;
|
||||||
if ((w != itsPlaylistSelector || pos != 0) && pos != w->Size()-1)
|
if ((w != itsPlaylistSelector || pos != 0) && pos != w->Size()-1)
|
||||||
myOldScreen->GetSelectedSongs(list);
|
list = dynamic_cast<HasSongs &>(*myOldScreen).getSelectedSongs();
|
||||||
|
|
||||||
if (w == itsPlaylistSelector)
|
if (w == itsPlaylistSelector)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,12 +35,8 @@ void ServerInfo::Init()
|
|||||||
SetDimensions();
|
SetDimensions();
|
||||||
w = new Scrollpad((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "MPD server info", Config.main_color, Config.window_border);
|
w = new Scrollpad((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "MPD server info", Config.main_color, Config.window_border);
|
||||||
|
|
||||||
Mpd.GetURLHandlers([this](std::string &&handler) {
|
itsURLHandlers = Mpd.GetURLHandlers();
|
||||||
itsURLHandlers.push_back(handler);
|
itsTagTypes = Mpd.GetTagTypes();
|
||||||
});
|
|
||||||
Mpd.GetTagTypes([this](std::string &&tag_type) {
|
|
||||||
itsTagTypes.push_back(tag_type);
|
|
||||||
});
|
|
||||||
|
|
||||||
isInitialized = 1;
|
isInitialized = 1;
|
||||||
}
|
}
|
||||||
@@ -119,11 +115,11 @@ void ServerInfo::Update()
|
|||||||
*w << fmtBold << U("Last DB update: ") << fmtBoldEnd << Timestamp(Mpd.DBUpdateTime()) << '\n';
|
*w << fmtBold << U("Last DB update: ") << fmtBoldEnd << Timestamp(Mpd.DBUpdateTime()) << '\n';
|
||||||
*w << '\n';
|
*w << '\n';
|
||||||
*w << fmtBold << U("URL Handlers:") << fmtBoldEnd;
|
*w << fmtBold << U("URL Handlers:") << fmtBoldEnd;
|
||||||
for (MPD::TagList::const_iterator it = itsURLHandlers.begin(); it != itsURLHandlers.end(); ++it)
|
for (auto it = itsURLHandlers.begin(); it != itsURLHandlers.end(); ++it)
|
||||||
*w << (it != itsURLHandlers.begin() ? U(", ") : U(" ")) << *it;
|
*w << (it != itsURLHandlers.begin() ? U(", ") : U(" ")) << *it;
|
||||||
*w << U("\n\n");
|
*w << U("\n\n");
|
||||||
*w << fmtBold << U("Tag Types:") << fmtBoldEnd;
|
*w << fmtBold << U("Tag Types:") << fmtBoldEnd;
|
||||||
for (MPD::TagList::const_iterator it = itsTagTypes.begin(); it != itsTagTypes.end(); ++it)
|
for (auto it = itsTagTypes.begin(); it != itsTagTypes.end(); ++it)
|
||||||
*w << (it != itsTagTypes.begin() ? U(", ") : U(" ")) << *it;
|
*w << (it != itsTagTypes.begin() ? U(", ") : U(" ")) << *it;
|
||||||
|
|
||||||
w->Flush();
|
w->Flush();
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ class ServerInfo : public Screen<Scrollpad>
|
|||||||
private:
|
private:
|
||||||
void SetDimensions();
|
void SetDimensions();
|
||||||
|
|
||||||
MPD::TagList itsURLHandlers;
|
MPD::StringList itsURLHandlers;
|
||||||
MPD::TagList itsTagTypes;
|
MPD::StringList itsTagTypes;
|
||||||
|
|
||||||
size_t itsWidth;
|
size_t itsWidth;
|
||||||
size_t itsHeight;
|
size_t itsHeight;
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
|
|
||||||
namespace {//
|
namespace {//
|
||||||
|
|
||||||
unsigned calc_hash(const char* s, unsigned seed = 0)
|
size_t calc_hash(const char* s, unsigned seed = 0)
|
||||||
{
|
{
|
||||||
unsigned hash = seed;
|
size_t hash = seed;
|
||||||
while (*s)
|
while (*s)
|
||||||
hash = hash * 101 + *s++;
|
hash = hash * 101 + *s++;
|
||||||
return hash;
|
return hash;
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ struct Song
|
|||||||
const std::string &escape_chars) const;
|
const std::string &escape_chars) const;
|
||||||
|
|
||||||
std::shared_ptr<mpd_song> m_song;
|
std::shared_ptr<mpd_song> m_song;
|
||||||
unsigned m_hash;
|
size_t m_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,8 +78,10 @@ void SongInfo::SwitchTo()
|
|||||||
if (myLockedScreen)
|
if (myLockedScreen)
|
||||||
UpdateInactiveScreen(this);
|
UpdateInactiveScreen(this);
|
||||||
|
|
||||||
MPD::Song *s = myScreen->CurrentSong();
|
auto hs = dynamic_cast<HasSongs *>(myScreen);
|
||||||
|
if (!hs)
|
||||||
|
return;
|
||||||
|
auto s = hs->currentSong();
|
||||||
if (!s)
|
if (!s)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -236,19 +236,21 @@ void NcmpcppStatusChanged(MPD::Connection *, MPD::StatusChanges changed, void *)
|
|||||||
if (playlist_length < myPlaylist->Items->Size())
|
if (playlist_length < myPlaylist->Items->Size())
|
||||||
myPlaylist->Items->ResizeList(playlist_length);
|
myPlaylist->Items->ResizeList(playlist_length);
|
||||||
|
|
||||||
Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID(), [](MPD::Song &&s) {
|
auto songs = Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID());
|
||||||
int pos = s.getPosition();
|
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||||
if (pos < int(myPlaylist->Items->Size()))
|
{
|
||||||
|
size_t pos = s->getPosition();
|
||||||
|
if (pos < myPlaylist->Items->Size())
|
||||||
{
|
{
|
||||||
// if song's already in playlist, replace it with a new one
|
// if song's already in playlist, replace it with a new one
|
||||||
myPlaylist->Items->at(pos).value() = s;
|
myPlaylist->Items->at(pos).value() = *s;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// otherwise just add it to playlist
|
// otherwise just add it to playlist
|
||||||
myPlaylist->Items->AddItem(s);
|
myPlaylist->Items->AddItem(*s);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
if (is_filtered)
|
if (is_filtered)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -259,32 +259,28 @@ void TagEditor::Update()
|
|||||||
{
|
{
|
||||||
LeftColumn->Window::Clear();
|
LeftColumn->Window::Clear();
|
||||||
Tags->Clear();
|
Tags->Clear();
|
||||||
MPD::TagList list;
|
|
||||||
if (Config.albums_in_tag_editor)
|
if (Config.albums_in_tag_editor)
|
||||||
{
|
{
|
||||||
*Albums << XY(0, 0) << "Fetching albums...";
|
*Albums << XY(0, 0) << "Fetching albums...";
|
||||||
Albums->Window::Refresh();
|
Albums->Window::Refresh();
|
||||||
Mpd.BlockIdle(1); // for the same reason as in media library
|
Mpd.BlockIdle(true); // for the same reason as in media library
|
||||||
Mpd.GetList(list, MPD_TAG_ALBUM);
|
auto albums = Mpd.GetList(MPD_TAG_ALBUM);
|
||||||
for (MPD::TagList::const_iterator it = list.begin(); it != list.end(); ++it)
|
for (auto album = albums.begin(); album != albums.end(); ++album)
|
||||||
{
|
{
|
||||||
MPD::SongList l;
|
|
||||||
Mpd.StartSearch(1);
|
Mpd.StartSearch(1);
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, *it);
|
Mpd.AddSearch(MPD_TAG_ALBUM, *album);
|
||||||
Mpd.CommitSearchSongs([&l](MPD::Song &&s) {
|
auto songs = Mpd.CommitSearchSongs();
|
||||||
l.push_back(s);
|
if (!songs.empty())
|
||||||
});
|
Albums->AddItem(std::make_pair(songs[0].toString(Config.tag_editor_album_format), *album));
|
||||||
if (!l.empty())
|
|
||||||
Albums->AddItem(std::make_pair(l[0].toString(Config.tag_editor_album_format), *it));
|
|
||||||
}
|
}
|
||||||
Mpd.BlockIdle(0);
|
Mpd.BlockIdle(false);
|
||||||
std::sort(Albums->BeginV(), Albums->EndV(), CaseInsensitiveSorting());
|
std::sort(Albums->BeginV(), Albums->EndV(), CaseInsensitiveSorting());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int highlightme = -1;
|
int highlightme = -1;
|
||||||
Mpd.GetDirectories(itsBrowsedDir, list);
|
auto dirs = Mpd.GetDirectories(itsBrowsedDir);
|
||||||
sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
std::sort(dirs.begin(), dirs.end(), CaseInsensitiveSorting());
|
||||||
if (itsBrowsedDir != "/")
|
if (itsBrowsedDir != "/")
|
||||||
{
|
{
|
||||||
size_t slash = itsBrowsedDir.rfind("/");
|
size_t slash = itsBrowsedDir.rfind("/");
|
||||||
@@ -292,16 +288,13 @@ void TagEditor::Update()
|
|||||||
Dirs->AddItem(make_pair("..", parent));
|
Dirs->AddItem(make_pair("..", parent));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
Dirs->AddItem(std::make_pair(".", "/"));
|
Dirs->AddItem(std::make_pair(".", "/"));
|
||||||
}
|
for (auto dir = dirs.begin(); dir != dirs.end(); ++dir)
|
||||||
for (MPD::TagList::const_iterator it = list.begin(); it != list.end(); ++it)
|
|
||||||
{
|
{
|
||||||
size_t slash = it->rfind("/");
|
size_t slash = dir->rfind("/");
|
||||||
std::string to_display = slash != std::string::npos ? it->substr(slash+1) : *it;
|
std::string to_display = slash != std::string::npos ? dir->substr(slash+1) : *dir;
|
||||||
utf_to_locale(to_display);
|
Dirs->AddItem(make_pair(to_display, *dir));
|
||||||
Dirs->AddItem(make_pair(to_display, *it));
|
if (*dir == itsHighlightedDir)
|
||||||
if (*it == itsHighlightedDir)
|
|
||||||
highlightme = Dirs->Size()-1;
|
highlightme = Dirs->Size()-1;
|
||||||
}
|
}
|
||||||
if (highlightme != -1)
|
if (highlightme != -1)
|
||||||
@@ -314,29 +307,25 @@ void TagEditor::Update()
|
|||||||
if (Tags->ReallyEmpty())
|
if (Tags->ReallyEmpty())
|
||||||
{
|
{
|
||||||
Tags->Reset();
|
Tags->Reset();
|
||||||
MPD::SongList list;
|
|
||||||
if (Config.albums_in_tag_editor)
|
if (Config.albums_in_tag_editor)
|
||||||
{
|
{
|
||||||
if (!Albums->Empty())
|
if (!Albums->Empty())
|
||||||
{
|
{
|
||||||
Mpd.StartSearch(1);
|
Mpd.StartSearch(1);
|
||||||
Mpd.AddSearch(MPD_TAG_ALBUM, Albums->Current().value().second);
|
Mpd.AddSearch(MPD_TAG_ALBUM, Albums->Current().value().second);
|
||||||
Mpd.CommitSearchSongs([&list](MPD::Song &&s) {
|
auto albums = Mpd.CommitSearchSongs();
|
||||||
list.push_back(s);
|
std::sort(albums.begin(), albums.end(), CaseInsensitiveSorting());
|
||||||
});
|
for (auto album = albums.begin(); album != albums.end(); ++album)
|
||||||
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
Tags->AddItem(*album);
|
||||||
for (auto it = list.begin(); it != list.end(); ++it)
|
|
||||||
Tags->AddItem(*it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Mpd.GetSongs(Dirs->Current().value().second, list);
|
auto songs = Mpd.GetSongs(Dirs->Current().value().second);
|
||||||
std::sort(list.begin(), list.end(), CaseInsensitiveSorting());
|
std::sort(songs.begin(), songs.end(), CaseInsensitiveSorting());
|
||||||
for (auto it = list.begin(); it != list.end(); ++it)
|
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||||
Tags->AddItem(*it);
|
Tags->AddItem(*s);
|
||||||
}
|
}
|
||||||
Tags->Window::Clear();
|
|
||||||
Tags->Refresh();
|
Tags->Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,9 +346,8 @@ void TagEditor::EnterPressed()
|
|||||||
|
|
||||||
if (w == Dirs)
|
if (w == Dirs)
|
||||||
{
|
{
|
||||||
MPD::TagList test;
|
auto dirs = Mpd.GetDirectories(LeftColumn->Current().value().second);
|
||||||
Mpd.GetDirectories(LeftColumn->Current().value().second, test);
|
if (!dirs.empty())
|
||||||
if (!test.empty())
|
|
||||||
{
|
{
|
||||||
itsHighlightedDir = itsBrowsedDir;
|
itsHighlightedDir = itsBrowsedDir;
|
||||||
itsBrowsedDir = LeftColumn->Current().value().second;
|
itsBrowsedDir = LeftColumn->Current().value().second;
|
||||||
@@ -659,7 +647,7 @@ void TagEditor::EnterPressed()
|
|||||||
w->Refresh();
|
w->Refresh();
|
||||||
w = LeftColumn;
|
w = LeftColumn;
|
||||||
LeftColumn->HighlightColor(Config.active_column_color);
|
LeftColumn->HighlightColor(Config.active_column_color);
|
||||||
Mpd.UpdateDirectory(getSharedDirectory(Tags));
|
Mpd.UpdateDirectory(getSharedDirectory(Tags->BeginV(), Tags->EndV()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Tags->Clear();
|
Tags->Clear();
|
||||||
@@ -777,23 +765,6 @@ void TagEditor::MouseButtonPressed(MEVENT me)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MPD::Song *TagEditor::CurrentSong()
|
|
||||||
{
|
|
||||||
return w == Tags && !Tags->Empty() ? &Tags->Current().value() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TagEditor::GetSelectedSongs(MPD::SongList &v)
|
|
||||||
{
|
|
||||||
if (w != Tags || Tags->Empty())
|
|
||||||
return;
|
|
||||||
std::vector<size_t> selected;
|
|
||||||
Tags->GetSelected(selected);
|
|
||||||
if (selected.empty())
|
|
||||||
selected.push_back(Tags->Choice());
|
|
||||||
for (auto it = selected.begin(); it != selected.end(); ++it)
|
|
||||||
v.push_back(static_cast<MPD::Song>((*Tags)[*it].value()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
std::string TagEditor::currentFilter()
|
std::string TagEditor::currentFilter()
|
||||||
@@ -877,6 +848,56 @@ void TagEditor::prevFound(bool wrap)
|
|||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
|
MPD::Song *TagEditor::getSong(size_t pos)
|
||||||
|
{
|
||||||
|
MPD::Song *ptr = 0;
|
||||||
|
if (w == Tags)
|
||||||
|
ptr = &(*Tags)[pos].value();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::Song *TagEditor::currentSong()
|
||||||
|
{
|
||||||
|
if (w == Tags && !Tags->Empty())
|
||||||
|
return getSong(Tags->Choice());
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TagEditor::allowsSelection()
|
||||||
|
{
|
||||||
|
return w == Tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagEditor::removeSelection()
|
||||||
|
{
|
||||||
|
if (w == Tags)
|
||||||
|
removeSelectionHelper(Tags->Begin(), Tags->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TagEditor::reverseSelection()
|
||||||
|
{
|
||||||
|
if (w == Tags)
|
||||||
|
reverseSelectionHelper(Tags->Begin(), Tags->End());
|
||||||
|
}
|
||||||
|
|
||||||
|
MPD::SongList TagEditor::getSelectedSongs()
|
||||||
|
{
|
||||||
|
MPD::SongList result;
|
||||||
|
if (w == Tags)
|
||||||
|
{
|
||||||
|
for (auto it = Tags->Begin(); it != Tags->End(); ++it)
|
||||||
|
if (it->isSelected())
|
||||||
|
result.push_back(it->value());
|
||||||
|
// if no song was selected, add current one
|
||||||
|
if (result.empty() && !Tags->Empty())
|
||||||
|
result.push_back(Tags->Current().value());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
List *TagEditor::GetList()
|
List *TagEditor::GetList()
|
||||||
{
|
{
|
||||||
if (w == LeftColumn)
|
if (w == LeftColumn)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#include "regex_filter.h"
|
#include "regex_filter.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
|
||||||
class TagEditor : public Screen<Window>, public Filterable, public Searchable
|
class TagEditor : public Screen<Window>, public Filterable, public HasSongs, public Searchable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TagEditor() : FParser(0), FParserHelper(0), FParserLegend(0), FParserPreview(0), itsBrowsedDir("/") { }
|
TagEditor() : FParser(0), FParserHelper(0), FParserLegend(0), FParserPreview(0), itsBrowsedDir("/") { }
|
||||||
@@ -55,13 +55,6 @@ class TagEditor : public Screen<Window>, public Filterable, public Searchable
|
|||||||
virtual void MouseButtonPressed(MEVENT);
|
virtual void MouseButtonPressed(MEVENT);
|
||||||
virtual bool isTabbable() { return true; }
|
virtual bool isTabbable() { return true; }
|
||||||
|
|
||||||
virtual MPD::Song *CurrentSong();
|
|
||||||
virtual MPD::Song *GetSong(size_t pos) { return w == Tags ? &Tags->at(pos).value() : 0; }
|
|
||||||
|
|
||||||
virtual bool allowsSelection() { return w == Tags; }
|
|
||||||
virtual void ReverseSelection() { Tags->ReverseSelection(); }
|
|
||||||
virtual void GetSelectedSongs(MPD::SongList &);
|
|
||||||
|
|
||||||
/// Filterable implementation
|
/// Filterable implementation
|
||||||
virtual std::string currentFilter();
|
virtual std::string currentFilter();
|
||||||
virtual void applyFilter(const std::string &filter);
|
virtual void applyFilter(const std::string &filter);
|
||||||
@@ -71,6 +64,15 @@ class TagEditor : public Screen<Window>, public Filterable, public Searchable
|
|||||||
virtual void nextFound(bool wrap);
|
virtual void nextFound(bool wrap);
|
||||||
virtual void prevFound(bool wrap);
|
virtual void prevFound(bool wrap);
|
||||||
|
|
||||||
|
/// HasSongs implementation
|
||||||
|
virtual MPD::Song *getSong(size_t pos);
|
||||||
|
virtual MPD::Song *currentSong();
|
||||||
|
|
||||||
|
virtual bool allowsSelection();
|
||||||
|
virtual void reverseSelection();
|
||||||
|
virtual void removeSelection();
|
||||||
|
virtual MPD::SongList getSelectedSongs();
|
||||||
|
|
||||||
virtual List *GetList();
|
virtual List *GetList();
|
||||||
|
|
||||||
virtual bool isMergable() { return true; }
|
virtual bool isMergable() { return true; }
|
||||||
|
|||||||
@@ -237,11 +237,10 @@ void Visualizer::FindOutputID()
|
|||||||
if (!Config.visualizer_output_name.empty())
|
if (!Config.visualizer_output_name.empty())
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
Mpd.GetOutputs([this, &i](MPD::Output &&o) {
|
auto outputs = Mpd.GetOutputs();
|
||||||
if (o.name() == Config.visualizer_output_name)
|
for (auto o = outputs.begin(); o != outputs.end(); ++o, ++i)
|
||||||
|
if (o->name() == Config.visualizer_output_name)
|
||||||
itsOutputID = i;
|
itsOutputID = i;
|
||||||
++i;
|
|
||||||
});
|
|
||||||
if (itsOutputID == -1)
|
if (itsOutputID == -1)
|
||||||
ShowMessage("There is no output named \"%s\"", Config.visualizer_output_name.c_str());
|
ShowMessage("There is no output named \"%s\"", Config.visualizer_output_name.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user