playlist: move sorting dialog related functions to separate file

This commit is contained in:
Andrzej Rybczak
2012-09-13 21:57:17 +02:00
parent fcc097fc76
commit 9ddfca8f31
16 changed files with 414 additions and 314 deletions

View File

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