actions: add support for range selection and make a few actions work on ranges

This commit is contained in:
Andrzej Rybczak
2015-05-23 22:55:04 +02:00
parent 274c075ffd
commit 1b6cb65f3a
10 changed files with 119 additions and 38 deletions

View File

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

View File

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

View File

@@ -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")))

View File

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

View File

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

View File

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

View File

@@ -62,8 +62,7 @@ struct Playlist: Screen<SongMenu>, HasSongs, Searchable, Tabbable
// private members
MPD::Song nowPlayingSong();
void Reverse();
void EnableHighlighting();
void SetSelectedItemsPriority(int prio);

View File

@@ -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();
}