playlist: move sorting dialog related functions to separate file
This commit is contained in:
@@ -37,6 +37,7 @@ ncmpcpp_SOURCES = \
|
||||
settings.cpp \
|
||||
song.cpp \
|
||||
song_info.cpp \
|
||||
sort_playlist.cpp \
|
||||
status.cpp \
|
||||
statusbar.cpp \
|
||||
tag_editor.cpp \
|
||||
@@ -92,6 +93,7 @@ noinst_HEADERS = \
|
||||
settings.h \
|
||||
song.h \
|
||||
song_info.h \
|
||||
sort_playlist.h \
|
||||
status.h \
|
||||
statusbar.h \
|
||||
tag_editor.h \
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "lyrics.h"
|
||||
#include "playlist.h"
|
||||
#include "playlist_editor.h"
|
||||
#include "sort_playlist.h"
|
||||
#include "search_engine.h"
|
||||
#include "sel_items_adder.h"
|
||||
#include "server_info.h"
|
||||
@@ -103,6 +104,7 @@ void Action::SetResizeFlags()
|
||||
myLyrics->hasToBeResized = 1;
|
||||
mySelectedItemsAdder->hasToBeResized = 1;
|
||||
mySongInfo->hasToBeResized = 1;
|
||||
mySortPlaylistDialog->hasToBeResized = 1;
|
||||
|
||||
# ifdef HAVE_CURL_CURL_H
|
||||
myLastfm->hasToBeResized = 1;
|
||||
@@ -743,11 +745,11 @@ void VolumeDown::Run()
|
||||
|
||||
void Delete::Run()
|
||||
{
|
||||
if (myScreen == myPlaylist && !myPlaylist->Items->empty())
|
||||
if (myScreen == myPlaylist && !myPlaylist->main()->empty())
|
||||
{
|
||||
Statusbar::msg("Deleting items...");
|
||||
auto delete_fun = std::bind(&MPD::Connection::Delete, _1, _2);
|
||||
if (deleteSelectedSongs(*myPlaylist->Items, delete_fun))
|
||||
if (deleteSelectedSongs(*myPlaylist->main(), delete_fun))
|
||||
Statusbar::msg("Item(s) deleted");
|
||||
}
|
||||
# ifndef WIN32
|
||||
@@ -874,11 +876,11 @@ void SavePlaylist::Run()
|
||||
}
|
||||
if (!playlist_name.empty())
|
||||
{
|
||||
if (myPlaylist->Items->isFiltered())
|
||||
if (myPlaylist->main()->isFiltered())
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
for (size_t i = 0; i < myPlaylist->Items->size(); ++i)
|
||||
Mpd.AddToPlaylist(playlist_name, (*myPlaylist->Items)[i].value());
|
||||
for (size_t i = 0; i < myPlaylist->main()->size(); ++i)
|
||||
Mpd.AddToPlaylist(playlist_name, (*myPlaylist->main())[i].value());
|
||||
Mpd.CommitCommandsList();
|
||||
if (Mpd.GetErrorMessage().empty())
|
||||
Statusbar::msg("Filtered items added to playlist \"%s\"", playlist_name.c_str());
|
||||
@@ -924,30 +926,28 @@ void Stop::Run()
|
||||
|
||||
bool MoveSortOrderUp::canBeRun() const
|
||||
{
|
||||
return myScreen == myPlaylist
|
||||
&& myPlaylist->SortingInProgress();
|
||||
return myScreen == mySortPlaylistDialog;
|
||||
}
|
||||
|
||||
void MoveSortOrderUp::Run()
|
||||
{
|
||||
myPlaylist->moveSortOrderUp();
|
||||
mySortPlaylistDialog->moveSortOrderUp();
|
||||
}
|
||||
|
||||
bool MoveSortOrderDown::canBeRun() const
|
||||
{
|
||||
return myScreen == myPlaylist
|
||||
&& myPlaylist->SortingInProgress();
|
||||
return myScreen == mySortPlaylistDialog;
|
||||
}
|
||||
|
||||
void MoveSortOrderDown::Run()
|
||||
{
|
||||
myPlaylist->moveSortOrderDown();
|
||||
mySortPlaylistDialog->moveSortOrderDown();
|
||||
}
|
||||
|
||||
bool MoveSelectedItemsUp::canBeRun() const
|
||||
{
|
||||
return ((myScreen->activeWindow() == myPlaylist->Items
|
||||
&& !myPlaylist->Items->empty()
|
||||
return ((myScreen->activeWindow() == myPlaylist->main()
|
||||
&& !myPlaylist->main()->empty()
|
||||
&& !myPlaylist->isFiltered())
|
||||
|| (myScreen->activeWindow() == myPlaylistEditor->Content
|
||||
&& !myPlaylistEditor->Content->empty()
|
||||
@@ -958,7 +958,7 @@ void MoveSelectedItemsUp::Run()
|
||||
{
|
||||
if (myScreen == myPlaylist)
|
||||
{
|
||||
moveSelectedItemsUp(*myPlaylist->Items, std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
moveSelectedItemsUp(*myPlaylist->main(), std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
}
|
||||
else if (myScreen == myPlaylistEditor)
|
||||
{
|
||||
@@ -971,8 +971,8 @@ void MoveSelectedItemsUp::Run()
|
||||
|
||||
bool MoveSelectedItemsDown::canBeRun() const
|
||||
{
|
||||
return ((myScreen->activeWindow() == myPlaylist->Items
|
||||
&& !myPlaylist->Items->empty()
|
||||
return ((myScreen->activeWindow() == myPlaylist->main()
|
||||
&& !myPlaylist->main()->empty()
|
||||
&& !myPlaylist->isFiltered())
|
||||
|| (myScreen->activeWindow() == myPlaylistEditor->Content
|
||||
&& !myPlaylistEditor->Content->empty()
|
||||
@@ -983,7 +983,7 @@ void MoveSelectedItemsDown::Run()
|
||||
{
|
||||
if (myScreen == myPlaylist)
|
||||
{
|
||||
moveSelectedItemsDown(*myPlaylist->Items, std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
moveSelectedItemsDown(*myPlaylist->main(), std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
}
|
||||
else if (myScreen == myPlaylistEditor)
|
||||
{
|
||||
@@ -996,14 +996,14 @@ void MoveSelectedItemsDown::Run()
|
||||
|
||||
bool MoveSelectedItemsTo::canBeRun() const
|
||||
{
|
||||
return myScreen->activeWindow() == myPlaylist->Items
|
||||
return myScreen->activeWindow() == myPlaylist->main()
|
||||
|| myScreen->activeWindow() == myPlaylistEditor->Content;
|
||||
}
|
||||
|
||||
void MoveSelectedItemsTo::Run()
|
||||
{
|
||||
if (myScreen == myPlaylist)
|
||||
moveSelectedItemsTo(*myPlaylist->Items, std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
moveSelectedItemsTo(*myPlaylist->main(), std::bind(&MPD::Connection::Move, _1, _2, _3));
|
||||
else
|
||||
{
|
||||
assert(!myPlaylistEditor->Playlists->empty());
|
||||
@@ -1086,16 +1086,16 @@ void ToggleDisplayMode::Run()
|
||||
|
||||
if (Config.columns_in_playlist)
|
||||
{
|
||||
myPlaylist->Items->setItemDisplayer(std::bind(Display::SongsInColumns, _1, myPlaylist));
|
||||
myPlaylist->main()->setItemDisplayer(std::bind(Display::SongsInColumns, _1, myPlaylist));
|
||||
if (Config.titles_visibility)
|
||||
myPlaylist->Items->setTitle(Display::Columns(myPlaylist->Items->getWidth()));
|
||||
myPlaylist->main()->setTitle(Display::Columns(myPlaylist->main()->getWidth()));
|
||||
else
|
||||
myPlaylist->Items->setTitle("");
|
||||
myPlaylist->main()->setTitle("");
|
||||
}
|
||||
else
|
||||
{
|
||||
myPlaylist->Items->setItemDisplayer(std::bind(Display::Songs, _1, myPlaylist, Config.song_list_format));
|
||||
myPlaylist->Items->setTitle("");
|
||||
myPlaylist->main()->setItemDisplayer(std::bind(Display::Songs, _1, myPlaylist, Config.song_list_format));
|
||||
myPlaylist->main()->setTitle("");
|
||||
}
|
||||
}
|
||||
else if (myScreen == myBrowser)
|
||||
@@ -1166,8 +1166,8 @@ void TogglePlayingSongCentering::Run()
|
||||
{
|
||||
Config.autocenter_mode = !Config.autocenter_mode;
|
||||
Statusbar::msg("Centering playing song: %s", Config.autocenter_mode ? "On" : "Off");
|
||||
if (Config.autocenter_mode && Mpd.isPlaying() && !myPlaylist->Items->isFiltered())
|
||||
myPlaylist->Items->highlight(Mpd.GetCurrentlyPlayingSongPos());
|
||||
if (Config.autocenter_mode && Mpd.isPlaying() && !myPlaylist->main()->isFiltered())
|
||||
myPlaylist->main()->highlight(Mpd.GetCurrentlyPlayingSongPos());
|
||||
}
|
||||
|
||||
void UpdateDatabase::Run()
|
||||
@@ -1193,7 +1193,7 @@ bool JumpToPlayingSong::canBeRun() const
|
||||
void JumpToPlayingSong::Run()
|
||||
{
|
||||
if (myScreen == myPlaylist)
|
||||
myPlaylist->Items->highlight(Mpd.GetCurrentlyPlayingSongPos());
|
||||
myPlaylist->main()->highlight(Mpd.GetCurrentlyPlayingSongPos());
|
||||
else if (myScreen == myBrowser)
|
||||
{
|
||||
myBrowser->LocateSong(myPlaylist->nowPlayingSong());
|
||||
@@ -1751,7 +1751,7 @@ void CropMainPlaylist::Run()
|
||||
if (yes)
|
||||
{
|
||||
Statusbar::msg("Cropping playlist...");
|
||||
if (cropPlaylist(*myPlaylist->Items, std::bind(&MPD::Connection::Delete, _1, _2)))
|
||||
if (cropPlaylist(*myPlaylist->main(), std::bind(&MPD::Connection::Delete, _1, _2)))
|
||||
Statusbar::msg("Cropping playlist...");
|
||||
}
|
||||
}
|
||||
@@ -1787,7 +1787,7 @@ void ClearMainPlaylist::Run()
|
||||
auto delete_fun = std::bind(&MPD::Connection::Delete, _1, _2);
|
||||
auto clear_fun = std::bind(&MPD::Connection::ClearMainPlaylist, _1);
|
||||
Statusbar::msg("Deleting items...");
|
||||
if (clearPlaylist(*myPlaylist->Items, delete_fun, clear_fun))
|
||||
if (clearPlaylist(*myPlaylist->main(), delete_fun, clear_fun))
|
||||
Statusbar::msg("Items deleted");
|
||||
}
|
||||
}
|
||||
@@ -1821,7 +1821,7 @@ bool SortPlaylist::canBeRun() const
|
||||
|
||||
void SortPlaylist::Run()
|
||||
{
|
||||
myPlaylist->Sort();
|
||||
mySortPlaylistDialog->switchTo();
|
||||
}
|
||||
|
||||
bool ReversePlaylist::canBeRun() const
|
||||
@@ -1857,7 +1857,7 @@ void ApplyFilter::Run()
|
||||
filter = f->currentFilter();
|
||||
if (filter.empty())
|
||||
{
|
||||
myPlaylist->Items->clearFilterResults();
|
||||
myPlaylist->main()->clearFilterResults();
|
||||
Statusbar::msg("Filtering disabled");
|
||||
}
|
||||
else
|
||||
@@ -2145,7 +2145,7 @@ bool SetSelectedItemsPriority::canBeRun() const
|
||||
Statusbar::msg("Priorities are supported in MPD >= 0.17.0");
|
||||
return false;
|
||||
}
|
||||
return myScreen->activeWindow() == myPlaylist->Items && !myPlaylist->Items->empty();
|
||||
return myScreen->activeWindow() == myPlaylist->main() && !myPlaylist->main()->empty();
|
||||
}
|
||||
|
||||
void SetSelectedItemsPriority::Run()
|
||||
@@ -2169,7 +2169,7 @@ void SetSelectedItemsPriority::Run()
|
||||
|
||||
bool FilterPlaylistOnPriorities::canBeRun() const
|
||||
{
|
||||
return myScreen->activeWindow() == myPlaylist->Items;
|
||||
return myScreen->activeWindow() == myPlaylist->main();
|
||||
}
|
||||
|
||||
void FilterPlaylistOnPriorities::Run()
|
||||
@@ -2183,7 +2183,7 @@ void FilterPlaylistOnPriorities::Run()
|
||||
if (!isInteger(strprio.c_str(), false))
|
||||
return;
|
||||
unsigned prio = stringToInt(strprio);
|
||||
myPlaylist->Items->filter(myPlaylist->Items->begin(), myPlaylist->Items->end(),
|
||||
myPlaylist->main()->filter(myPlaylist->main()->begin(), myPlaylist->main()->end(),
|
||||
[prio](const NC::Menu<MPD::Song>::Item &s) {
|
||||
return s.value().getPrio() > prio;
|
||||
});
|
||||
|
||||
@@ -441,9 +441,9 @@ void Browser::GetDirectory(std::string dir, std::string subdir)
|
||||
case itSong:
|
||||
{
|
||||
bool bold = 0;
|
||||
for (size_t i = 0; i < myPlaylist->Items->size(); ++i)
|
||||
for (size_t i = 0; i < myPlaylist->main()->size(); ++i)
|
||||
{
|
||||
if (myPlaylist->Items->at(i).value().getHash() == it->song->getHash())
|
||||
if (myPlaylist->main()->at(i).value().getHash() == it->song->getHash())
|
||||
{
|
||||
bold = 1;
|
||||
break;
|
||||
|
||||
@@ -96,7 +96,7 @@ void setProperties(NC::Menu<T> &menu, const MPD::Song &s, HasSongs &screen, bool
|
||||
discard_colors = Config.discard_colors_if_item_is_selected && is_selected;
|
||||
|
||||
int song_pos = menu.isFiltered() ? s.getPosition() : drawn_pos;
|
||||
is_now_playing = static_cast<void *>(&menu) == myPlaylist->Items
|
||||
is_now_playing = static_cast<void *>(&menu) == myPlaylist->main()
|
||||
&& song_pos == Mpd.GetCurrentlyPlayingSongPos();
|
||||
if (is_now_playing)
|
||||
menu << Config.now_playing_prefix;
|
||||
|
||||
@@ -43,6 +43,8 @@ template <typename T> class Menu : public Window
|
||||
public:
|
||||
struct Item
|
||||
{
|
||||
typedef T Type;
|
||||
|
||||
friend class Menu<T>;
|
||||
|
||||
Item()
|
||||
|
||||
@@ -203,7 +203,7 @@ int main(int argc, char **argv)
|
||||
Status::trace();
|
||||
int curr_pos = Mpd.GetCurrentSongPos();
|
||||
if (curr_pos >= 0)
|
||||
myPlaylist->Items->highlight(curr_pos);
|
||||
myPlaylist->main()->highlight(curr_pos);
|
||||
}
|
||||
|
||||
while (!Action::ExitMainLoop)
|
||||
|
||||
313
src/playlist.cpp
313
src/playlist.cpp
@@ -45,12 +45,6 @@ bool Playlist::ReloadRemaining = false;
|
||||
|
||||
namespace {//
|
||||
|
||||
NC::Menu< std::pair<std::string, MPD::Song::GetFunction> > *SortDialog = 0;
|
||||
size_t SortDialogHeight;
|
||||
|
||||
const size_t SortOptions = 10;
|
||||
const size_t SortDialogWidth = 30;
|
||||
|
||||
std::string songToString(const MPD::Song &s);
|
||||
bool playlistEntryMatcher(const Regex &rx, const MPD::Song &s);
|
||||
|
||||
@@ -58,42 +52,17 @@ bool playlistEntryMatcher(const Regex &rx, const MPD::Song &s);
|
||||
|
||||
void Playlist::init()
|
||||
{
|
||||
Items = new NC::Menu<MPD::Song>(0, MainStartY, COLS, MainHeight, Config.columns_in_playlist && Config.titles_visibility ? Display::Columns(COLS) : "", Config.main_color, NC::brNone);
|
||||
Items->cyclicScrolling(Config.use_cyclic_scrolling);
|
||||
Items->centeredCursor(Config.centered_cursor);
|
||||
Items->setHighlightColor(Config.main_highlight_color);
|
||||
Items->setSelectedPrefix(Config.selected_item_prefix);
|
||||
Items->setSelectedSuffix(Config.selected_item_suffix);
|
||||
w = new NC::Menu<MPD::Song>(0, MainStartY, COLS, MainHeight, Config.columns_in_playlist && Config.titles_visibility ? Display::Columns(COLS) : "", Config.main_color, NC::brNone);
|
||||
w->cyclicScrolling(Config.use_cyclic_scrolling);
|
||||
w->centeredCursor(Config.centered_cursor);
|
||||
w->setHighlightColor(Config.main_highlight_color);
|
||||
w->setSelectedPrefix(Config.selected_item_prefix);
|
||||
w->setSelectedSuffix(Config.selected_item_suffix);
|
||||
if (Config.columns_in_playlist)
|
||||
Items->setItemDisplayer(std::bind(Display::SongsInColumns, _1, this));
|
||||
w->setItemDisplayer(std::bind(Display::SongsInColumns, _1, this));
|
||||
else
|
||||
Items->setItemDisplayer(std::bind(Display::Songs, _1, this, Config.song_list_format));
|
||||
w->setItemDisplayer(std::bind(Display::Songs, _1, this, Config.song_list_format));
|
||||
|
||||
if (!SortDialog)
|
||||
{
|
||||
SortDialogHeight = std::min(int(MainHeight), 17);
|
||||
|
||||
SortDialog = new NC::Menu< std::pair<std::string, MPD::Song::GetFunction> >((COLS-SortDialogWidth)/2, (MainHeight-SortDialogHeight)/2+MainStartY, SortDialogWidth, SortDialogHeight, "Sort songs by...", Config.main_color, Config.window_border);
|
||||
SortDialog->cyclicScrolling(Config.use_cyclic_scrolling);
|
||||
SortDialog->centeredCursor(Config.centered_cursor);
|
||||
SortDialog->setItemDisplayer(Display::Pair<std::string, MPD::Song::GetFunction>);
|
||||
|
||||
SortDialog->addItem(std::make_pair("Artist", &MPD::Song::getArtist));
|
||||
SortDialog->addItem(std::make_pair("Album", &MPD::Song::getAlbum));
|
||||
SortDialog->addItem(std::make_pair("Disc", &MPD::Song::getDisc));
|
||||
SortDialog->addItem(std::make_pair("Track", &MPD::Song::getTrack));
|
||||
SortDialog->addItem(std::make_pair("Genre", &MPD::Song::getGenre));
|
||||
SortDialog->addItem(std::make_pair("Date", &MPD::Song::getDate));
|
||||
SortDialog->addItem(std::make_pair("Composer", &MPD::Song::getComposer));
|
||||
SortDialog->addItem(std::make_pair("Performer", &MPD::Song::getPerformer));
|
||||
SortDialog->addItem(std::make_pair("Title", &MPD::Song::getTitle));
|
||||
SortDialog->addItem(std::make_pair("Filename", &MPD::Song::getURI));
|
||||
SortDialog->addSeparator();
|
||||
SortDialog->addItem(std::make_pair("Sort", static_cast<MPD::Song::GetFunction>(0)));
|
||||
SortDialog->addItem(std::make_pair("Cancel", static_cast<MPD::Song::GetFunction>(0)));
|
||||
}
|
||||
|
||||
w = Items;
|
||||
isInitialized = 1;
|
||||
}
|
||||
|
||||
@@ -121,8 +90,6 @@ void Playlist::switchTo()
|
||||
Global::myPrevScreen = myScreen;
|
||||
myScreen = this;
|
||||
EnableHighlighting();
|
||||
if (w != Items) // even if sorting window is active, background has to be refreshed anyway
|
||||
Items->display();
|
||||
drawHeader();
|
||||
}
|
||||
|
||||
@@ -130,16 +97,13 @@ void Playlist::resize()
|
||||
{
|
||||
size_t x_offset, width;
|
||||
getWindowResizeParams(x_offset, width);
|
||||
Items->resize(width, MainHeight);
|
||||
Items->moveTo(x_offset, MainStartY);
|
||||
w->resize(width, MainHeight);
|
||||
w->moveTo(x_offset, MainStartY);
|
||||
|
||||
Items->setTitle(Config.columns_in_playlist && Config.titles_visibility ? Display::Columns(Items->getWidth()) : "");
|
||||
if (w == SortDialog) // if sorting window is active, playlist needs refreshing
|
||||
Items->display();
|
||||
|
||||
SortDialogHeight = std::min(size_t(17), MainHeight);
|
||||
SortDialog->resize(SortDialogWidth, SortDialogHeight);
|
||||
SortDialog->moveTo(x_offset+(width-SortDialogWidth)/2, (MainHeight-SortDialogHeight)/2+MainStartY);
|
||||
if (Config.columns_in_playlist && Config.titles_visibility)
|
||||
w->setTitle(Display::Columns(w->getWidth()));
|
||||
else
|
||||
w->setTitle("");
|
||||
|
||||
hasToBeResized = 0;
|
||||
}
|
||||
@@ -155,116 +119,31 @@ std::wstring Playlist::title()
|
||||
|
||||
void Playlist::enterPressed()
|
||||
{
|
||||
if (w == Items)
|
||||
{
|
||||
if (!Items->empty())
|
||||
Mpd.PlayID(Items->current().value().getID());
|
||||
}
|
||||
else if (w == SortDialog)
|
||||
{
|
||||
size_t pos = SortDialog->choice();
|
||||
|
||||
auto begin = Items->begin(), end = Items->end();
|
||||
// if songs are selected, sort range from first selected to last selected
|
||||
if (Items->hasSelected())
|
||||
{
|
||||
while (!begin->isSelected())
|
||||
++begin;
|
||||
while (!(end-1)->isSelected())
|
||||
--end;
|
||||
}
|
||||
|
||||
if (pos > SortOptions)
|
||||
{
|
||||
if (pos == SortOptions+2) // cancel
|
||||
{
|
||||
w = Items;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Statusbar::msg("Move tag types up and down to adjust sort order");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t start_pos = begin-Items->begin();
|
||||
MPD::SongList playlist;
|
||||
playlist.reserve(end-begin);
|
||||
for (; begin != end; ++begin)
|
||||
playlist.push_back(begin->value());
|
||||
|
||||
LocaleStringComparison cmp(std::locale(), Config.ignore_leading_the);
|
||||
std::function<void(MPD::SongList::iterator, MPD::SongList::iterator)> iter_swap, quick_sort;
|
||||
auto song_cmp = [&cmp](const MPD::Song &a, const MPD::Song &b) -> bool {
|
||||
for (size_t i = 0; i < SortOptions; ++i)
|
||||
if (int ret = cmp(a.getTags((*SortDialog)[i].value().second, Config.tags_separator), b.getTags((*SortDialog)[i].value().second, Config.tags_separator)))
|
||||
return ret < 0;
|
||||
return a.getPosition() < b.getPosition();
|
||||
};
|
||||
iter_swap = [&playlist, &start_pos](MPD::SongList::iterator a, MPD::SongList::iterator b) {
|
||||
std::iter_swap(a, b);
|
||||
Mpd.Swap(start_pos+a-playlist.begin(), start_pos+b-playlist.begin());
|
||||
};
|
||||
quick_sort = [this, &song_cmp, &quick_sort, &iter_swap](MPD::SongList::iterator first, MPD::SongList::iterator last) {
|
||||
if (last-first > 1)
|
||||
{
|
||||
MPD::SongList::iterator pivot = first+rand()%(last-first);
|
||||
iter_swap(pivot, last-1);
|
||||
pivot = last-1;
|
||||
|
||||
MPD::SongList::iterator tmp = first;
|
||||
for (MPD::SongList::iterator i = first; i != pivot; ++i)
|
||||
if (song_cmp(*i, *pivot))
|
||||
iter_swap(i, tmp++);
|
||||
iter_swap(tmp, pivot);
|
||||
|
||||
quick_sort(first, tmp);
|
||||
quick_sort(tmp+1, last);
|
||||
}
|
||||
};
|
||||
|
||||
Statusbar::msg("Sorting...");
|
||||
Mpd.StartCommandsList();
|
||||
quick_sort(playlist.begin(), playlist.end());
|
||||
if (Mpd.CommitCommandsList())
|
||||
Statusbar::msg("Playlist sorted");
|
||||
w = Items;
|
||||
}
|
||||
if (!w->empty())
|
||||
Mpd.PlayID(w->current().value().getID());
|
||||
}
|
||||
|
||||
void Playlist::spacePressed()
|
||||
{
|
||||
if (w == Items && !Items->empty())
|
||||
if (!w->empty())
|
||||
{
|
||||
Items->current().setSelected(!Items->current().isSelected());
|
||||
Items->scroll(NC::wDown);
|
||||
w->current().setSelected(!w->current().isSelected());
|
||||
w->scroll(NC::wDown);
|
||||
}
|
||||
}
|
||||
|
||||
void Playlist::mouseButtonPressed(MEVENT me)
|
||||
{
|
||||
if (w == Items && !Items->empty() && Items->hasCoords(me.x, me.y))
|
||||
if (!w->empty() && w->hasCoords(me.x, me.y))
|
||||
{
|
||||
if (size_t(me.y) < Items->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)))
|
||||
if (size_t(me.y) < w->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)))
|
||||
{
|
||||
Items->Goto(me.y);
|
||||
w->Goto(me.y);
|
||||
if (me.bstate & BUTTON3_PRESSED)
|
||||
enterPressed();
|
||||
}
|
||||
else
|
||||
Screen<NC::Window>::mouseButtonPressed(me);
|
||||
}
|
||||
else if (w == SortDialog && SortDialog->hasCoords(me.x, me.y))
|
||||
{
|
||||
if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))
|
||||
{
|
||||
SortDialog->Goto(me.y);
|
||||
if (me.bstate & BUTTON3_PRESSED)
|
||||
enterPressed();
|
||||
}
|
||||
else
|
||||
Screen<NC::Window>::mouseButtonPressed(me);
|
||||
Screen<ScreenType>::mouseButtonPressed(me);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,20 +156,14 @@ bool Playlist::allowsFiltering()
|
||||
|
||||
std::string Playlist::currentFilter()
|
||||
{
|
||||
std::string filter;
|
||||
if (w == Items)
|
||||
filter = RegexFilter<MPD::Song>::currentFilter(*Items);
|
||||
return filter;
|
||||
return RegexFilter<MPD::Song>::currentFilter(*w);
|
||||
}
|
||||
|
||||
void Playlist::applyFilter(const std::string &filter)
|
||||
{
|
||||
if (w == Items)
|
||||
{
|
||||
Items->showAll();
|
||||
auto rx = RegexFilter<MPD::Song>(filter, Config.regex_type, playlistEntryMatcher);
|
||||
Items->filter(Items->begin(), Items->end(), rx);
|
||||
}
|
||||
w->showAll();
|
||||
auto rx = RegexFilter<MPD::Song>(filter, Config.regex_type, playlistEntryMatcher);
|
||||
w->filter(w->begin(), w->end(), rx);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
@@ -302,60 +175,47 @@ bool Playlist::allowsSearching()
|
||||
|
||||
bool Playlist::search(const std::string &constraint)
|
||||
{
|
||||
bool result = false;
|
||||
if (w == Items)
|
||||
{
|
||||
auto rx = RegexFilter<MPD::Song>(constraint, Config.regex_type, playlistEntryMatcher);
|
||||
result = Items->search(Items->begin(), Items->end(), rx);
|
||||
}
|
||||
return result;
|
||||
auto rx = RegexFilter<MPD::Song>(constraint, Config.regex_type, playlistEntryMatcher);
|
||||
return w->search(w->begin(), w->end(), rx);
|
||||
}
|
||||
|
||||
void Playlist::nextFound(bool wrap)
|
||||
{
|
||||
if (w == Items)
|
||||
Items->nextFound(wrap);
|
||||
w->nextFound(wrap);
|
||||
}
|
||||
|
||||
void Playlist::prevFound(bool wrap)
|
||||
{
|
||||
if (w == Items)
|
||||
Items->prevFound(wrap);
|
||||
w->prevFound(wrap);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
std::shared_ptr<ProxySongList> Playlist::getProxySongList()
|
||||
{
|
||||
auto ptr = nullProxySongList();
|
||||
if (w == Items)
|
||||
ptr = mkProxySongList(*Items, [](NC::Menu<MPD::Song>::Item &item) {
|
||||
return &item.value();
|
||||
});
|
||||
return ptr;
|
||||
return mkProxySongList(*w, [](NC::Menu<MPD::Song>::Item &item) {
|
||||
return &item.value();
|
||||
});
|
||||
}
|
||||
|
||||
bool Playlist::allowsSelection()
|
||||
{
|
||||
return w == Items;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Playlist::reverseSelection()
|
||||
{
|
||||
reverseSelectionHelper(Items->begin(), Items->end());
|
||||
reverseSelectionHelper(w->begin(), w->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());
|
||||
}
|
||||
for (auto it = w->begin(); it != w->end(); ++it)
|
||||
if (it->isSelected())
|
||||
result.push_back(it->value());
|
||||
if (result.empty() && !w->empty())
|
||||
result.push_back(w->current().value());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -365,15 +225,15 @@ MPD::Song Playlist::nowPlayingSong()
|
||||
{
|
||||
MPD::Song s;
|
||||
if (Mpd.isPlaying())
|
||||
withUnfilteredMenu(*Items, [this, &s]() {
|
||||
s = Items->at(Mpd.GetCurrentSongPos()).value();
|
||||
withUnfilteredMenu(*w, [this, &s]() {
|
||||
s = w->at(Mpd.GetCurrentSongPos()).value();
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Playlist::isFiltered()
|
||||
{
|
||||
if (Items->isFiltered())
|
||||
if (w->isFiltered())
|
||||
{
|
||||
Statusbar::msg("Function currently unavailable due to filtered playlist");
|
||||
return true;
|
||||
@@ -381,23 +241,15 @@ bool Playlist::isFiltered()
|
||||
return false;
|
||||
}
|
||||
|
||||
void Playlist::Sort()
|
||||
{
|
||||
if (isFiltered())
|
||||
return;
|
||||
SortDialog->reset();
|
||||
w = SortDialog;
|
||||
}
|
||||
|
||||
void Playlist::Reverse()
|
||||
{
|
||||
if (isFiltered())
|
||||
return;
|
||||
Statusbar::msg("Reversing playlist order...");
|
||||
size_t beginning = -1, end = -1;
|
||||
for (size_t i = 0; i < Items->size(); ++i)
|
||||
for (size_t i = 0; i < w->size(); ++i)
|
||||
{
|
||||
if (Items->at(i).isSelected())
|
||||
if (w->at(i).isSelected())
|
||||
{
|
||||
if (beginning == size_t(-1))
|
||||
beginning = i;
|
||||
@@ -407,7 +259,7 @@ void Playlist::Reverse()
|
||||
if (beginning == size_t(-1)) // no selected items
|
||||
{
|
||||
beginning = 0;
|
||||
end = Items->size();
|
||||
end = w->size();
|
||||
}
|
||||
Mpd.StartCommandsList();
|
||||
for (size_t i = beginning, j = end-1; i < (beginning+end)/2; ++i, --j)
|
||||
@@ -418,7 +270,7 @@ void Playlist::Reverse()
|
||||
|
||||
void Playlist::EnableHighlighting()
|
||||
{
|
||||
Items->setHighlighting(1);
|
||||
w->setHighlighting(true);
|
||||
UpdateTimer();
|
||||
}
|
||||
|
||||
@@ -427,11 +279,6 @@ void Playlist::UpdateTimer()
|
||||
itsTimer = Global::Timer;
|
||||
}
|
||||
|
||||
bool Playlist::SortingInProgress()
|
||||
{
|
||||
return w == SortDialog;
|
||||
}
|
||||
|
||||
std::string Playlist::TotalLength()
|
||||
{
|
||||
std::ostringstream result;
|
||||
@@ -439,26 +286,26 @@ std::string Playlist::TotalLength()
|
||||
if (ReloadTotalLength)
|
||||
{
|
||||
itsTotalLength = 0;
|
||||
for (size_t i = 0; i < Items->size(); ++i)
|
||||
itsTotalLength += (*Items)[i].value().getDuration();
|
||||
for (size_t i = 0; i < w->size(); ++i)
|
||||
itsTotalLength += (*w)[i].value().getDuration();
|
||||
ReloadTotalLength = 0;
|
||||
}
|
||||
if (Config.playlist_show_remaining_time && ReloadRemaining && !Items->isFiltered())
|
||||
if (Config.playlist_show_remaining_time && ReloadRemaining && !w->isFiltered())
|
||||
{
|
||||
itsRemainingTime = 0;
|
||||
for (size_t i = Mpd.GetCurrentlyPlayingSongPos(); i < Items->size(); ++i)
|
||||
itsRemainingTime += (*Items)[i].value().getDuration();
|
||||
for (size_t i = Mpd.GetCurrentlyPlayingSongPos(); i < w->size(); ++i)
|
||||
itsRemainingTime += (*w)[i].value().getDuration();
|
||||
ReloadRemaining = false;
|
||||
}
|
||||
|
||||
result << '(' << Items->size() << (Items->size() == 1 ? " item" : " items");
|
||||
result << '(' << w->size() << (w->size() == 1 ? " item" : " items");
|
||||
|
||||
if (Items->isFiltered())
|
||||
if (w->isFiltered())
|
||||
{
|
||||
Items->showAll();
|
||||
size_t real_size = Items->size();
|
||||
Items->showFiltered();
|
||||
if (Items->size() != real_size)
|
||||
w->showAll();
|
||||
size_t real_size = w->size();
|
||||
w->showFiltered();
|
||||
if (w->size() != real_size)
|
||||
result << " (out of " << Mpd.GetPlaylistLength() << ")";
|
||||
}
|
||||
|
||||
@@ -467,7 +314,7 @@ std::string Playlist::TotalLength()
|
||||
result << ", length: ";
|
||||
ShowTime(result, itsTotalLength, Config.playlist_shorten_total_times);
|
||||
}
|
||||
if (Config.playlist_show_remaining_time && itsRemainingTime && !Items->isFiltered() && Items->size() > 1)
|
||||
if (Config.playlist_show_remaining_time && itsRemainingTime && !w->isFiltered() && w->size() > 1)
|
||||
{
|
||||
result << " :: remaining: ";
|
||||
ShowTime(result, itsRemainingTime, Config.playlist_shorten_total_times);
|
||||
@@ -483,9 +330,9 @@ bool Playlist::Add(const MPD::Song &s, bool play, int position)
|
||||
size_t hash = s.getHash();
|
||||
if (play)
|
||||
{
|
||||
for (size_t i = 0; i < Items->size(); ++i)
|
||||
for (size_t i = 0; i < w->size(); ++i)
|
||||
{
|
||||
if (Items->at(i).value().getHash() == hash)
|
||||
if (w->at(i).value().getHash() == hash)
|
||||
{
|
||||
Mpd.Play(i);
|
||||
break;
|
||||
@@ -496,8 +343,8 @@ bool Playlist::Add(const MPD::Song &s, bool play, int position)
|
||||
else
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
for (size_t i = 0; i < Items->size(); ++i)
|
||||
if ((*Items)[i].value().getHash() == hash)
|
||||
for (size_t i = 0; i < w->size(); ++i)
|
||||
if ((*w)[i].value().getHash() == hash)
|
||||
Mpd.Delete(i);
|
||||
Mpd.CommitCommandsList();
|
||||
return false;
|
||||
@@ -545,19 +392,19 @@ bool Playlist::Add(const MPD::SongList &l, bool play, int position)
|
||||
|
||||
void Playlist::PlayNewlyAddedSongs()
|
||||
{
|
||||
bool is_filtered = Items->isFiltered();
|
||||
Items->showAll();
|
||||
size_t old_size = Items->size();
|
||||
bool is_filtered = w->isFiltered();
|
||||
w->showAll();
|
||||
size_t old_size = w->size();
|
||||
Mpd.UpdateStatus();
|
||||
if (old_size < Items->size())
|
||||
if (old_size < w->size())
|
||||
Mpd.Play(old_size);
|
||||
if (is_filtered)
|
||||
Items->showFiltered();
|
||||
w->showFiltered();
|
||||
}
|
||||
|
||||
void Playlist::SetSelectedItemsPriority(int prio)
|
||||
{
|
||||
auto list = getSelectedOrCurrent(Items->begin(), Items->end(), Items->currentI());
|
||||
auto list = getSelectedOrCurrent(w->begin(), w->end(), w->currentI());
|
||||
Mpd.StartCommandsList();
|
||||
for (auto it = list.begin(); it != list.end(); ++it)
|
||||
Mpd.SetPriority((*it)->value(), prio);
|
||||
@@ -570,26 +417,6 @@ bool Playlist::checkForSong(const MPD::Song &s)
|
||||
return itsSongHashes.find(s.getHash()) != itsSongHashes.end();
|
||||
}
|
||||
|
||||
void Playlist::moveSortOrderDown()
|
||||
{
|
||||
size_t pos = SortDialog->choice();
|
||||
if (pos < SortOptions-1)
|
||||
{
|
||||
SortDialog->Swap(pos, pos+1);
|
||||
SortDialog->scroll(NC::wDown);
|
||||
}
|
||||
}
|
||||
|
||||
void Playlist::moveSortOrderUp()
|
||||
{
|
||||
size_t pos = SortDialog->choice();
|
||||
if (pos > 0 && pos < SortOptions)
|
||||
{
|
||||
SortDialog->Swap(pos, pos-1);
|
||||
SortDialog->scroll(NC::wUp);
|
||||
}
|
||||
}
|
||||
|
||||
void Playlist::registerHash(size_t hash)
|
||||
{
|
||||
itsSongHashes[hash] += 1;
|
||||
|
||||
@@ -27,13 +27,13 @@
|
||||
#include "screen.h"
|
||||
#include "song.h"
|
||||
|
||||
class Playlist : public Screen<NC::Window>, public Filterable, public HasSongs, public Searchable
|
||||
class Playlist : public Screen<NC::Menu<MPD::Song>>, public Filterable, public HasSongs, public Searchable
|
||||
{
|
||||
public:
|
||||
Playlist() : itsTotalLength(0), itsRemainingTime(0), itsScrollBegin(0) { }
|
||||
~Playlist() { }
|
||||
|
||||
// Screen<NC::Window> implementation
|
||||
// Screen<NC::Menu<MPD::Song>> implementation
|
||||
virtual void switchTo() OVERRIDE;
|
||||
virtual void resize() OVERRIDE;
|
||||
|
||||
@@ -70,10 +70,7 @@ class Playlist : public Screen<NC::Window>, public Filterable, public HasSongs,
|
||||
MPD::Song nowPlayingSong();
|
||||
|
||||
bool isFiltered();
|
||||
|
||||
void Sort();
|
||||
void Reverse();
|
||||
bool SortingInProgress();
|
||||
|
||||
void EnableHighlighting();
|
||||
void UpdateTimer();
|
||||
@@ -87,14 +84,9 @@ class Playlist : public Screen<NC::Window>, public Filterable, public HasSongs,
|
||||
|
||||
bool checkForSong(const MPD::Song &s);
|
||||
|
||||
void moveSortOrderUp();
|
||||
void moveSortOrderDown();
|
||||
|
||||
void registerHash(size_t hash);
|
||||
void unregisterHash(size_t hash);
|
||||
|
||||
NC::Menu<MPD::Song> *Items;
|
||||
|
||||
static bool ReloadTotalLength;
|
||||
static bool ReloadRemaining;
|
||||
|
||||
|
||||
@@ -127,6 +127,8 @@ bool isVisible(BasicScreen *screen);
|
||||
template <typename WindowT> class Screen : public BasicScreen
|
||||
{
|
||||
public:
|
||||
typedef WindowT ScreenType;
|
||||
|
||||
Screen() : w(0) { }
|
||||
virtual ~Screen() { }
|
||||
|
||||
|
||||
@@ -442,8 +442,8 @@ void SearchEngine::Search()
|
||||
list = Mpd.GetDirectoryRecursive("/");
|
||||
else
|
||||
{
|
||||
list.reserve(myPlaylist->Items->size());
|
||||
for (auto s = myPlaylist->Items->beginV(); s != myPlaylist->Items->endV(); ++s)
|
||||
list.reserve(myPlaylist->main()->size());
|
||||
for (auto s = myPlaylist->main()->beginV(); s != myPlaylist->main()->endV(); ++s)
|
||||
list.push_back(*s);
|
||||
}
|
||||
|
||||
|
||||
@@ -224,14 +224,14 @@ void SelectedItemsAdder::enterPressed()
|
||||
{
|
||||
std::string album = myPlaylist->nowPlayingSong().getAlbum();
|
||||
int i;
|
||||
for (i = Mpd.GetCurrentlyPlayingSongPos()+1; i < int(myPlaylist->Items->size()); ++i)
|
||||
if ((*myPlaylist->Items)[i].value().getAlbum() != album)
|
||||
for (i = Mpd.GetCurrentlyPlayingSongPos()+1; i < int(myPlaylist->main()->size()); ++i)
|
||||
if ((*myPlaylist->main())[i].value().getAlbum() != album)
|
||||
break;
|
||||
successful_operation = myPlaylist->Add(list, 0, i);
|
||||
}
|
||||
else if (pos == 4) // after highlighted item
|
||||
{
|
||||
successful_operation = myPlaylist->Add(list, 0, std::min(myPlaylist->Items->choice()+1, myPlaylist->Items->size()));
|
||||
successful_operation = myPlaylist->Add(list, 0, std::min(myPlaylist->main()->choice()+1, myPlaylist->main()->size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
211
src/sort_playlist.cpp
Normal file
211
src/sort_playlist.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#include "display.h"
|
||||
#include "global.h"
|
||||
#include "playlist.h"
|
||||
#include "settings.h"
|
||||
#include "sort_playlist.h"
|
||||
#include "statusbar.h"
|
||||
#include "utility/comparators.h"
|
||||
|
||||
using Global::MainHeight;
|
||||
using Global::MainStartY;
|
||||
|
||||
SortPlaylistDialog *mySortPlaylistDialog = new SortPlaylistDialog;
|
||||
|
||||
void SortPlaylistDialog::init()
|
||||
{
|
||||
setDimensions();
|
||||
|
||||
w = new NC::Menu< std::pair<std::string, MPD::Song::GetFunction> >((COLS-m_width)/2, (MainHeight-m_height)/2+MainStartY, m_width, m_height, "Sort songs by...", Config.main_color, Config.window_border);
|
||||
w->cyclicScrolling(Config.use_cyclic_scrolling);
|
||||
w->centeredCursor(Config.centered_cursor);
|
||||
w->setItemDisplayer(Display::Pair<std::string, MPD::Song::GetFunction>);
|
||||
|
||||
w->addItem(std::make_pair("Artist", &MPD::Song::getArtist));
|
||||
w->addItem(std::make_pair("Album", &MPD::Song::getAlbum));
|
||||
w->addItem(std::make_pair("Disc", &MPD::Song::getDisc));
|
||||
w->addItem(std::make_pair("Track", &MPD::Song::getTrack));
|
||||
w->addItem(std::make_pair("Genre", &MPD::Song::getGenre));
|
||||
w->addItem(std::make_pair("Date", &MPD::Song::getDate));
|
||||
w->addItem(std::make_pair("Composer", &MPD::Song::getComposer));
|
||||
w->addItem(std::make_pair("Performer", &MPD::Song::getPerformer));
|
||||
w->addItem(std::make_pair("Title", &MPD::Song::getTitle));
|
||||
w->addItem(std::make_pair("Filename", &MPD::Song::getURI));
|
||||
|
||||
m_sort_options = w->size();
|
||||
m_sort_entry = std::make_pair("Sort", static_cast<MPD::Song::GetFunction>(0));
|
||||
m_cancel_entry = std::make_pair("Cancel", static_cast<MPD::Song::GetFunction>(0));
|
||||
|
||||
w->addSeparator();
|
||||
w->addItem(m_sort_entry);
|
||||
w->addItem(m_cancel_entry);
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
void SortPlaylistDialog::switchTo()
|
||||
{
|
||||
using Global::myScreen;
|
||||
using Global::myOldScreen;
|
||||
using Global::myLockedScreen;
|
||||
using Global::myInactiveScreen;
|
||||
|
||||
assert(myScreen != this);
|
||||
|
||||
if (!isInitialized)
|
||||
init();
|
||||
|
||||
if (hasToBeResized)
|
||||
resize();
|
||||
|
||||
myOldScreen = myScreen;
|
||||
myScreen = this;
|
||||
|
||||
w->reset();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void SortPlaylistDialog::resize()
|
||||
{
|
||||
setDimensions();
|
||||
w->resize(m_width, m_height);
|
||||
w->moveTo((COLS-m_width)/2, (MainHeight-m_height)/2+MainStartY);
|
||||
|
||||
hasToBeResized = false;
|
||||
}
|
||||
|
||||
std::wstring SortPlaylistDialog::title()
|
||||
{
|
||||
return Global::myOldScreen->title();
|
||||
}
|
||||
|
||||
void SortPlaylistDialog::enterPressed()
|
||||
{
|
||||
auto option = w->currentVI();
|
||||
if (*option == m_sort_entry)
|
||||
{
|
||||
auto begin = myPlaylist->main()->begin(), end = myPlaylist->main()->end();
|
||||
// if songs are selected, sort range from first selected to last selected
|
||||
if (myPlaylist->main()->hasSelected())
|
||||
{
|
||||
while (!begin->isSelected())
|
||||
++begin;
|
||||
while (!(end-1)->isSelected())
|
||||
--end;
|
||||
}
|
||||
|
||||
size_t start_pos = begin - myPlaylist->main()->begin();
|
||||
MPD::SongList playlist;
|
||||
playlist.reserve(end - begin);
|
||||
for (; begin != end; ++begin)
|
||||
playlist.push_back(begin->value());
|
||||
|
||||
LocaleStringComparison cmp(std::locale(), Config.ignore_leading_the);
|
||||
std::function<void(MPD::SongList::iterator, MPD::SongList::iterator)> iter_swap, quick_sort;
|
||||
auto song_cmp = [this, &cmp](const MPD::Song &a, const MPD::Song &b) -> bool {
|
||||
for (size_t i = 0; i < m_sort_options; ++i)
|
||||
{
|
||||
int res = cmp(a.getTags((*w)[i].value().second, Config.tags_separator),
|
||||
b.getTags((*w)[i].value().second, Config.tags_separator));
|
||||
if (res != 0)
|
||||
return res < 0;
|
||||
}
|
||||
return a.getPosition() < b.getPosition();
|
||||
};
|
||||
iter_swap = [&playlist, &start_pos](MPD::SongList::iterator a, MPD::SongList::iterator b) {
|
||||
std::iter_swap(a, b);
|
||||
Mpd.Swap(start_pos+a-playlist.begin(), start_pos+b-playlist.begin());
|
||||
};
|
||||
quick_sort = [this, &song_cmp, &quick_sort, &iter_swap](MPD::SongList::iterator first, MPD::SongList::iterator last) {
|
||||
if (last-first > 1)
|
||||
{
|
||||
MPD::SongList::iterator pivot = first+rand()%(last-first);
|
||||
iter_swap(pivot, last-1);
|
||||
pivot = last-1;
|
||||
|
||||
MPD::SongList::iterator tmp = first;
|
||||
for (MPD::SongList::iterator i = first; i != pivot; ++i)
|
||||
if (song_cmp(*i, *pivot))
|
||||
iter_swap(i, tmp++);
|
||||
iter_swap(tmp, pivot);
|
||||
|
||||
quick_sort(first, tmp);
|
||||
quick_sort(tmp+1, last);
|
||||
}
|
||||
};
|
||||
|
||||
Statusbar::msg("Sorting...");
|
||||
Mpd.StartCommandsList();
|
||||
quick_sort(playlist.begin(), playlist.end());
|
||||
if (Mpd.CommitCommandsList())
|
||||
Statusbar::msg("Playlist sorted");
|
||||
|
||||
Global::myOldScreen->switchTo();
|
||||
}
|
||||
else if (*option == m_cancel_entry)
|
||||
{
|
||||
Global::myOldScreen->switchTo();
|
||||
}
|
||||
else
|
||||
Statusbar::msg("Move tag types up and down to adjust sort order");
|
||||
}
|
||||
|
||||
void SortPlaylistDialog::mouseButtonPressed(MEVENT me)
|
||||
{
|
||||
if (w->hasCoords(me.x, me.y))
|
||||
{
|
||||
if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))
|
||||
{
|
||||
w->Goto(me.y);
|
||||
if (me.bstate & BUTTON3_PRESSED)
|
||||
enterPressed();
|
||||
}
|
||||
else
|
||||
Screen<ScreenType>::mouseButtonPressed(me);
|
||||
}
|
||||
}
|
||||
|
||||
void SortPlaylistDialog::moveSortOrderDown()
|
||||
{
|
||||
size_t pos = w->choice();
|
||||
if (pos < m_sort_options-1)
|
||||
{
|
||||
w->Swap(pos, pos+1);
|
||||
w->scroll(NC::wDown);
|
||||
}
|
||||
}
|
||||
|
||||
void SortPlaylistDialog::moveSortOrderUp()
|
||||
{
|
||||
size_t pos = w->choice();
|
||||
if (pos > 0 && pos < m_sort_options)
|
||||
{
|
||||
w->Swap(pos, pos-1);
|
||||
w->scroll(NC::wUp);
|
||||
}
|
||||
}
|
||||
|
||||
void SortPlaylistDialog::setDimensions()
|
||||
{
|
||||
m_height = std::min(size_t(17), MainHeight);
|
||||
m_width = 30;
|
||||
}
|
||||
64
src/sort_playlist.h
Normal file
64
src/sort_playlist.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/***************************************************************************
|
||||
* 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. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _SORT_PLAYLIST
|
||||
#define _SORT_PLAYLIST
|
||||
|
||||
#include "screen.h"
|
||||
#include "song.h"
|
||||
|
||||
struct SortPlaylistDialog : public Screen< NC::Menu< std::pair<std::string, MPD::Song::GetFunction> > >
|
||||
{
|
||||
virtual void switchTo() OVERRIDE;
|
||||
virtual void resize() OVERRIDE;
|
||||
|
||||
virtual std::wstring title() OVERRIDE;
|
||||
|
||||
virtual void update() OVERRIDE { }
|
||||
|
||||
virtual void enterPressed() OVERRIDE;
|
||||
virtual void spacePressed() OVERRIDE { }
|
||||
virtual void mouseButtonPressed(MEVENT me) OVERRIDE;
|
||||
|
||||
virtual bool isTabbable() OVERRIDE { return false; }
|
||||
virtual bool isMergable() OVERRIDE { return false; }
|
||||
|
||||
// private members
|
||||
void moveSortOrderUp();
|
||||
void moveSortOrderDown();
|
||||
|
||||
protected:
|
||||
virtual void init();
|
||||
virtual bool isLockable() { return false; }
|
||||
|
||||
private:
|
||||
void setDimensions();
|
||||
|
||||
size_t m_sort_options;
|
||||
size_t m_height;
|
||||
size_t m_width;
|
||||
|
||||
ScreenType::Item::Type m_sort_entry;
|
||||
ScreenType::Item::Type m_cancel_entry;
|
||||
};
|
||||
|
||||
extern SortPlaylistDialog *mySortPlaylistDialog;
|
||||
|
||||
#endif // _SORT_PLAYLIST
|
||||
@@ -92,13 +92,13 @@ void Status::trace()
|
||||
|
||||
applyToVisibleWindows(&BasicScreen::update);
|
||||
|
||||
if (isVisible(myPlaylist) && myPlaylist->activeWindow() == myPlaylist->Items
|
||||
if (isVisible(myPlaylist) && myPlaylist->activeWindow() == myPlaylist->main()
|
||||
&& Timer.tv_sec == myPlaylist->Timer().tv_sec+Config.playlist_disable_highlight_delay
|
||||
&& myPlaylist->Items->isHighlighted()
|
||||
&& myPlaylist->main()->isHighlighted()
|
||||
&& Config.playlist_disable_highlight_delay)
|
||||
{
|
||||
myPlaylist->Items->setHighlighting(false);
|
||||
myPlaylist->Items->refresh();
|
||||
myPlaylist->main()->setHighlighting(false);
|
||||
myPlaylist->main()->refresh();
|
||||
}
|
||||
|
||||
Statusbar::tryRedraw();
|
||||
@@ -129,31 +129,31 @@ void Status::handleError(MPD::Connection * , int errorid, const char *msg, void
|
||||
|
||||
void Status::Changes::playlist()
|
||||
{
|
||||
myPlaylist->Items->clearSearchResults();
|
||||
withUnfilteredMenuReapplyFilter(*myPlaylist->Items, []() {
|
||||
myPlaylist->main()->clearSearchResults();
|
||||
withUnfilteredMenuReapplyFilter(*myPlaylist->main(), []() {
|
||||
size_t playlist_length = Mpd.GetPlaylistLength();
|
||||
if (playlist_length < myPlaylist->Items->size())
|
||||
if (playlist_length < myPlaylist->main()->size())
|
||||
{
|
||||
auto it = myPlaylist->Items->begin()+playlist_length;
|
||||
auto end = myPlaylist->Items->end();
|
||||
auto it = myPlaylist->main()->begin()+playlist_length;
|
||||
auto end = myPlaylist->main()->end();
|
||||
for (; it != end; ++it)
|
||||
myPlaylist->unregisterHash(it->value().getHash());
|
||||
myPlaylist->Items->resizeList(playlist_length);
|
||||
myPlaylist->main()->resizeList(playlist_length);
|
||||
}
|
||||
|
||||
auto songs = Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID());
|
||||
for (auto s = songs.begin(); s != songs.end(); ++s)
|
||||
{
|
||||
size_t pos = s->getPosition();
|
||||
if (pos < myPlaylist->Items->size())
|
||||
if (pos < myPlaylist->main()->size())
|
||||
{
|
||||
// if song's already in playlist, replace it with a new one
|
||||
MPD::Song &old_s = (*myPlaylist->Items)[pos].value();
|
||||
MPD::Song &old_s = (*myPlaylist->main())[pos].value();
|
||||
myPlaylist->unregisterHash(old_s.getHash());
|
||||
old_s = *s;
|
||||
}
|
||||
else // otherwise just add it to playlist
|
||||
myPlaylist->Items->addItem(*s);
|
||||
myPlaylist->main()->addItem(*s);
|
||||
myPlaylist->registerHash(s->getHash());
|
||||
}
|
||||
});
|
||||
@@ -299,8 +299,8 @@ void Status::Changes::songID()
|
||||
|
||||
drawTitle(myPlaylist->nowPlayingSong());
|
||||
|
||||
if (Config.autocenter_mode && !myPlaylist->Items->isFiltered())
|
||||
myPlaylist->Items->highlight(Mpd.GetCurrentlyPlayingSongPos());
|
||||
if (Config.autocenter_mode && !myPlaylist->main()->isFiltered())
|
||||
myPlaylist->main()->highlight(Mpd.GetCurrentlyPlayingSongPos());
|
||||
|
||||
if (Config.now_playing_lyrics && isVisible(myLyrics) && Global::myOldScreen == myPlaylist)
|
||||
myLyrics->ReloadNP = 1;
|
||||
|
||||
@@ -257,13 +257,13 @@ bool write(MPD::MutableSong &s)
|
||||
{
|
||||
// if we rename local file, it won't get updated
|
||||
// so just remove it from playlist and add again
|
||||
size_t pos = myPlaylist->Items->choice();
|
||||
size_t pos = myPlaylist->main()->choice();
|
||||
Mpd.StartCommandsList();
|
||||
Mpd.Delete(pos);
|
||||
int id = Mpd.AddSong("file://" + new_name);
|
||||
if (id >= 0)
|
||||
{
|
||||
s = myPlaylist->Items->back().value();
|
||||
s = myPlaylist->main()->back().value();
|
||||
Mpd.Move(s.getPosition(), pos);
|
||||
}
|
||||
Mpd.CommitCommandsList();
|
||||
|
||||
@@ -141,7 +141,7 @@ void TinyTagEditor::enterPressed()
|
||||
else
|
||||
{
|
||||
if (myOldScreen == myPlaylist)
|
||||
myPlaylist->Items->current().value() = itsEdited;
|
||||
myPlaylist->main()->current().value() = itsEdited;
|
||||
else if (myOldScreen == myBrowser)
|
||||
myBrowser->GetDirectory(myBrowser->CurrentDir());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user