actions: add support for range selection and make a few actions work on ranges
This commit is contained in:
@@ -89,6 +89,15 @@ void seek();
|
||||
void findItem(const SearchDirection direction);
|
||||
void listsChangeFinisher();
|
||||
|
||||
template <typename Iterator>
|
||||
bool findSelectedRangeAndPrintInfoIfNot(Iterator &first, Iterator &last)
|
||||
{
|
||||
bool success = findSelectedRange(first, last);
|
||||
if (!success)
|
||||
Statusbar::print("No range selected");
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Actions {
|
||||
@@ -1173,11 +1182,19 @@ void ToggleRepeat::run()
|
||||
Mpd.SetRepeat(!Status::State::repeat());
|
||||
}
|
||||
|
||||
bool Shuffle::canBeRun()
|
||||
{
|
||||
if (myScreen != myPlaylist)
|
||||
return false;
|
||||
m_begin = myPlaylist->main().begin();
|
||||
m_end = myPlaylist->main().end();
|
||||
return findSelectedRangeAndPrintInfoIfNot(m_begin, m_end);
|
||||
}
|
||||
|
||||
void Shuffle::run()
|
||||
{
|
||||
auto begin = myPlaylist->main().begin(), end = myPlaylist->main().end();
|
||||
auto range = getSelectedRange(begin, end);
|
||||
Mpd.ShuffleRange(range.first-begin, range.second-begin);
|
||||
auto begin = myPlaylist->main().begin();
|
||||
Mpd.ShuffleRange(m_begin-begin, m_end-begin);
|
||||
Statusbar::print("Range shuffled");
|
||||
}
|
||||
|
||||
@@ -1654,6 +1671,23 @@ void SelectItem::run()
|
||||
current->setSelected(!current->isSelected());
|
||||
}
|
||||
|
||||
bool SelectRange::canBeRun()
|
||||
{
|
||||
m_list = dynamic_cast<NC::List *>(myScreen->activeWindow());
|
||||
if (m_list == nullptr)
|
||||
return false;
|
||||
m_begin = m_list->beginP();
|
||||
m_end = m_list->endP();
|
||||
return findRange(m_begin, m_end);
|
||||
}
|
||||
|
||||
void SelectRange::run()
|
||||
{
|
||||
for (; m_begin != m_end; ++m_begin)
|
||||
m_begin->setSelected(true);
|
||||
Statusbar::print("Range selected");
|
||||
}
|
||||
|
||||
bool ReverseSelection::canBeRun()
|
||||
{
|
||||
m_list = dynamic_cast<NC::List *>(myScreen->activeWindow());
|
||||
@@ -1793,7 +1827,10 @@ void ClearPlaylist::run()
|
||||
|
||||
bool SortPlaylist::canBeRun()
|
||||
{
|
||||
return myScreen == myPlaylist;
|
||||
if (myScreen != myPlaylist)
|
||||
return false;
|
||||
auto first = myPlaylist->main().begin(), last = myPlaylist->main().end();
|
||||
return findSelectedRangeAndPrintInfoIfNot(first, last);
|
||||
}
|
||||
|
||||
void SortPlaylist::run()
|
||||
@@ -1803,12 +1840,21 @@ void SortPlaylist::run()
|
||||
|
||||
bool ReversePlaylist::canBeRun()
|
||||
{
|
||||
return myScreen == myPlaylist;
|
||||
if (myScreen != myPlaylist)
|
||||
return false;
|
||||
m_begin = myPlaylist->main().begin();
|
||||
m_end = myPlaylist->main().end();
|
||||
return findSelectedRangeAndPrintInfoIfNot(m_begin, m_end);
|
||||
}
|
||||
|
||||
void ReversePlaylist::run()
|
||||
{
|
||||
myPlaylist->Reverse();
|
||||
Statusbar::print("Reversing range...");
|
||||
Mpd.StartCommandsList();
|
||||
for (--m_end; m_begin < m_end; ++m_begin, --m_end)
|
||||
Mpd.Swap(m_begin->value().getPosition(), m_end->value().getPosition());
|
||||
Mpd.CommitCommandsList();
|
||||
Statusbar::print("Range reversed");
|
||||
}
|
||||
|
||||
bool Find::canBeRun()
|
||||
@@ -2512,6 +2558,7 @@ void populateActions()
|
||||
insert_action(new Actions::JumpToParentDirectory());
|
||||
insert_action(new Actions::PressEnter());
|
||||
insert_action(new Actions::SelectItem());
|
||||
insert_action(new Actions::SelectRange());
|
||||
insert_action(new Actions::PreviousColumn());
|
||||
insert_action(new Actions::NextColumn());
|
||||
insert_action(new Actions::MasterScreen());
|
||||
|
||||
@@ -49,7 +49,7 @@ enum class Type
|
||||
SetCrossfade, SetVolume, EditSong, EditLibraryTag, EditLibraryAlbum, EditDirectoryName,
|
||||
EditPlaylistName, EditLyrics, JumpToBrowser, JumpToMediaLibrary,
|
||||
JumpToPlaylistEditor, ToggleScreenLock, JumpToTagEditor, JumpToPositionInSong,
|
||||
SelectItem, ReverseSelection, RemoveSelection, SelectAlbum, AddSelectedItems,
|
||||
SelectItem, SelectRange, ReverseSelection, RemoveSelection, SelectAlbum, AddSelectedItems,
|
||||
CropMainPlaylist, CropPlaylist, ClearMainPlaylist, ClearPlaylist, SortPlaylist,
|
||||
ReversePlaylist, Find, FindItemForward, FindItemBackward,
|
||||
NextFoundItem, PreviousFoundItem, ToggleFindMode, ToggleReplayGainMode,
|
||||
@@ -581,7 +581,11 @@ struct Shuffle: BaseAction
|
||||
Shuffle(): BaseAction(Type::Shuffle, "shuffle") { }
|
||||
|
||||
private:
|
||||
virtual bool canBeRun() OVERRIDE;
|
||||
virtual void run() OVERRIDE;
|
||||
|
||||
NC::Menu<MPD::Song>::ConstIterator m_begin;
|
||||
NC::Menu<MPD::Song>::ConstIterator m_end;
|
||||
};
|
||||
|
||||
struct ToggleRandom: BaseAction
|
||||
@@ -776,6 +780,19 @@ private:
|
||||
NC::List *m_list;
|
||||
};
|
||||
|
||||
struct SelectRange: BaseAction
|
||||
{
|
||||
SelectRange(): BaseAction(Type::SelectRange, "select_range") { }
|
||||
|
||||
private:
|
||||
virtual bool canBeRun() OVERRIDE;
|
||||
virtual void run() OVERRIDE;
|
||||
|
||||
NC::List *m_list;
|
||||
NC::List::Iterator m_begin;
|
||||
NC::List::Iterator m_end;
|
||||
};
|
||||
|
||||
struct ReverseSelection: BaseAction
|
||||
{
|
||||
ReverseSelection(): BaseAction(Type::ReverseSelection, "reverse_selection") { }
|
||||
@@ -869,6 +886,9 @@ struct ReversePlaylist: BaseAction
|
||||
private:
|
||||
virtual bool canBeRun() OVERRIDE;
|
||||
virtual void run() OVERRIDE;
|
||||
|
||||
NC::Menu<MPD::Song>::ConstIterator m_begin;
|
||||
NC::Menu<MPD::Song>::ConstIterator m_end;
|
||||
};
|
||||
|
||||
struct Find: BaseAction
|
||||
|
||||
@@ -630,6 +630,8 @@ void BindingsConfiguration::generateDefaults()
|
||||
bind(k, Actions::Type::JumpToPositionInSong);
|
||||
if (notBound(k = stringToKey("l")))
|
||||
bind(k, Actions::Type::ShowLyrics);
|
||||
if (notBound(k = stringToKey("ctrl_v")))
|
||||
bind(k, Actions::Type::SelectRange);
|
||||
if (notBound(k = stringToKey("v")))
|
||||
bind(k, Actions::Type::ReverseSelection);
|
||||
if (notBound(k = stringToKey("V")))
|
||||
|
||||
@@ -178,6 +178,7 @@ void write_bindings(NC::Scrollpad &w)
|
||||
w << '\n';
|
||||
key(w, Type::ToggleAddMode, "Toggle add mode (add or remove/always add)");
|
||||
key(w, Type::ToggleMouse, "Toggle mouse support");
|
||||
key(w, Type::SelectRange, "Select range");
|
||||
key(w, Type::ReverseSelection, "Reverse selection");
|
||||
key(w, Type::RemoveSelection, "Remove selection");
|
||||
key(w, Type::SelectItem, "Select current item");
|
||||
@@ -191,7 +192,6 @@ void write_bindings(NC::Scrollpad &w)
|
||||
key(w, Type::ToggleConsume, "Toggle consume mode");
|
||||
key(w, Type::ToggleReplayGainMode, "Toggle replay gain mode");
|
||||
key(w, Type::ToggleBitrateVisibility, "Toggle bitrate visibility");
|
||||
key(w, Type::Shuffle, "Shuffle selected range in playlist");
|
||||
key(w, Type::ToggleCrossfade, "Toggle crossfade mode");
|
||||
key(w, Type::SetCrossfade, "Set crossfade");
|
||||
key(w, Type::SetVolume, "Set volume");
|
||||
@@ -239,8 +239,9 @@ void write_bindings(NC::Scrollpad &w)
|
||||
key(w, Type::EditSong, "Edit song");
|
||||
# endif // HAVE_TAGLIB_H
|
||||
key(w, Type::SavePlaylist, "Save playlist");
|
||||
key(w, Type::SortPlaylist, "Sort playlist");
|
||||
key(w, Type::ReversePlaylist, "Reverse playlist");
|
||||
key(w, Type::Shuffle, "Shuffle range");
|
||||
key(w, Type::SortPlaylist, "Sort range");
|
||||
key(w, Type::ReversePlaylist, "Reverse range");
|
||||
key(w, Type::JumpToPlayingSong, "Jump to current song");
|
||||
key(w, Type::TogglePlayingSongCentering, "Toggle playing song centering");
|
||||
|
||||
|
||||
@@ -113,21 +113,40 @@ std::vector<Iterator> getSelected(Iterator first, Iterator last)
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @return selected range within given range or original range if no item is selected
|
||||
/// @return true if range that begins and ends with selected items was found
|
||||
template <typename Iterator>
|
||||
std::pair<Iterator, Iterator> getSelectedRange(Iterator first, Iterator second)
|
||||
bool findRange(Iterator &first, Iterator &last)
|
||||
{
|
||||
auto result = std::make_pair(first, second);
|
||||
if (hasSelected(first, second))
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
while (!result.first->isSelected())
|
||||
++result.first;
|
||||
do
|
||||
--result.second;
|
||||
while (!result.second->isSelected());
|
||||
++result.second;
|
||||
if (first->isSelected())
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
if (first == last)
|
||||
return false;
|
||||
--last;
|
||||
for (; first != last; --last)
|
||||
{
|
||||
if (last->isSelected())
|
||||
break;
|
||||
}
|
||||
++last;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @return true if fully selected range was found, false otherwise.
|
||||
template <typename Iterator>
|
||||
bool findSelectedRange(Iterator &first, Iterator &last)
|
||||
{
|
||||
if (!findRange(first, last))
|
||||
return false;
|
||||
// we have range, now check if it's filled with selected items
|
||||
for (auto it = first; it != last; ++it)
|
||||
{
|
||||
if (!it->isSelected())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -197,18 +197,6 @@ MPD::Song Playlist::nowPlayingSong()
|
||||
return s;
|
||||
}
|
||||
|
||||
void Playlist::Reverse()
|
||||
{
|
||||
Statusbar::print("Reversing playlist order...");
|
||||
auto begin = w.begin(), end = w.end();
|
||||
std::tie(begin, end) = getSelectedRange(begin, end);
|
||||
Mpd.StartCommandsList();
|
||||
for (--end; begin < end; ++begin, --end)
|
||||
Mpd.Swap(begin->value().getPosition(), end->value().getPosition());
|
||||
Mpd.CommitCommandsList();
|
||||
Statusbar::print("Playlist reversed");
|
||||
}
|
||||
|
||||
void Playlist::EnableHighlighting()
|
||||
{
|
||||
w.setHighlighting(true);
|
||||
|
||||
@@ -62,8 +62,7 @@ struct Playlist: Screen<SongMenu>, HasSongs, Searchable, Tabbable
|
||||
// private members
|
||||
MPD::Song nowPlayingSong();
|
||||
|
||||
void Reverse();
|
||||
|
||||
|
||||
void EnableHighlighting();
|
||||
|
||||
void SetSelectedItemsPriority(int prio);
|
||||
|
||||
@@ -156,8 +156,9 @@ void SortPlaylistDialog::sort() const
|
||||
{
|
||||
auto &pl = myPlaylist->main();
|
||||
auto begin = pl.begin(), end = pl.end();
|
||||
std::tie(begin, end) = getSelectedRange(begin, end);
|
||||
|
||||
if (!findSelectedRange(begin, end))
|
||||
return;
|
||||
|
||||
size_t start_pos = begin - pl.begin();
|
||||
std::vector<MPD::Song> playlist;
|
||||
playlist.reserve(end - begin);
|
||||
@@ -203,7 +204,7 @@ void SortPlaylistDialog::sort() const
|
||||
Mpd.StartCommandsList();
|
||||
quick_sort(playlist.begin(), playlist.end());
|
||||
Mpd.CommitCommandsList();
|
||||
Statusbar::print("Playlist sorted");
|
||||
Statusbar::print("Range sorted");
|
||||
switchToPreviousScreen();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user