diff --git a/NEWS b/NEWS index 7567c02e..2e6e09f3 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ ncmpcpp-0.7 (????-??-??) * Support for Alt, Ctrl and Shift modifiers as well as Escape key was added. * Action that updates the environment can now be used in bindings configuration file. * Monolithic 'press_space' action was split into 'add_item_to_playlist', 'toggle_lyrics_update_on_song_change' and 'toggle_visualization_type'. +* Monolithic 'press_enter' action was split into 'enter_directory', 'play_item', run_action' and 'toggle_output'. * Sorting actions were rebound to Ctrl-S. * Support for range selection was added (bound to Ctrl-V by default). In addition, sorting, reversing and shuffling items in playlist now works on ranges. * Support for selecting found items was added (bound to Ctrl-_ by default). diff --git a/doc/bindings b/doc/bindings index 196e7eed..cf22f41b 100644 --- a/doc/bindings +++ b/doc/bindings @@ -193,13 +193,16 @@ # select_item # #def_key "enter" -# play +# enter_directory # #def_key "enter" # toggle_output # #def_key "enter" -# press_enter +# play_item +# +#def_key "enter" +# run_action # #def_key "space" # add_item_to_playlist diff --git a/src/actions.cpp b/src/actions.cpp index 3ed8e505..a089ca82 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -502,7 +502,7 @@ void JumpToParentDirectory::run() if (!myBrowser->inRootDirectory()) { myBrowser->main().reset(); - myBrowser->enterPressed(); + myBrowser->enterDirectory(); } } # ifdef HAVE_TAGLIB_H @@ -511,37 +511,46 @@ void JumpToParentDirectory::run() if (myTagEditor->CurrentDir() != "/") { myTagEditor->Dirs->reset(); - myTagEditor->enterPressed(); + myTagEditor->enterDirectory(); } } # endif // HAVE_TAGLIB_H } -void PressEnter::run() +bool RunAction::canBeRun() { - myScreen->enterPressed(); + m_ha = dynamic_cast(myScreen); + return m_ha != nullptr + && m_ha->actionRunnable(); +} + +void RunAction::run() +{ + m_ha->runAction(); } bool PreviousColumn::canBeRun() { - auto hc = hasColumns(myScreen); - return hc && hc->previousColumnAvailable(); + m_hc = dynamic_cast(myScreen); + return m_hc != nullptr + && m_hc->previousColumnAvailable(); } void PreviousColumn::run() { - hasColumns(myScreen)->previousColumn(); + m_hc->previousColumn(); } bool NextColumn::canBeRun() { - auto hc = hasColumns(myScreen); - return hc && hc->nextColumnAvailable(); + m_hc = dynamic_cast(myScreen); + return m_hc != nullptr + && m_hc->nextColumnAvailable(); } void NextColumn::run() { - hasColumns(myScreen)->nextColumn(); + m_hc->nextColumn(); } bool MasterScreen::canBeRun() @@ -600,14 +609,13 @@ void VolumeDown::run() bool AddItemToPlaylist::canBeRun() { - if (m_hs != static_cast(myScreen)) - m_hs = dynamic_cast(myScreen); - return m_hs != nullptr; + m_hs = dynamic_cast(myScreen); + return m_hs != nullptr && m_hs->itemAvailable(); } void AddItemToPlaylist::run() { - bool success = m_hs->addItemToPlaylist(); + bool success = m_hs->addItemToPlaylist(false); if (success) { myScreen->scroll(NC::Scroll::Down); @@ -615,6 +623,19 @@ void AddItemToPlaylist::run() } } +bool PlayItem::canBeRun() +{ + m_hs = dynamic_cast(myScreen); + return m_hs != nullptr && m_hs->itemAvailable(); +} + +void PlayItem::run() +{ + bool success = m_hs->addItemToPlaylist(true); + if (success) + listsChangeFinisher(); +} + bool DeletePlaylistItems::canBeRun() { return (myScreen == myPlaylist && !myPlaylist->main().empty()) @@ -957,17 +978,6 @@ void Add::run() } } -bool Play::canBeRun() -{ - return myScreen == myPlaylist - && !myPlaylist->main().empty(); -} - -void Play::run() -{ - Mpd.PlayID(myPlaylist->main().current()->value().getID()); -} - bool SeekForward::canBeRun() { return Status::State::player() != MPD::psStop && Status::State::totalTime() > 0; @@ -1226,7 +1236,7 @@ void StartSearching::run() mySearcher->main().setHighlighting(0); mySearcher->main().refresh(); mySearcher->main().setHighlighting(1); - mySearcher->enterPressed(); + mySearcher->runAction(); } bool SaveTagChanges::canBeRun() @@ -1245,12 +1255,12 @@ void SaveTagChanges::run() if (myScreen == myTinyTagEditor) { myTinyTagEditor->main().highlight(myTinyTagEditor->main().size()-2); // Save - myTinyTagEditor->enterPressed(); + myTinyTagEditor->runAction(); } else if (myScreen->activeWindow() == myTagEditor->TagTypes) { myTagEditor->TagTypes->highlight(myTagEditor->TagTypes->size()-1); // Save - myTagEditor->enterPressed(); + myTagEditor->runAction(); } # endif // HAVE_TAGLIB_H } @@ -1297,6 +1307,34 @@ void SetVolume::run() Statusbar::printf("Volume set to %1%%%", volume); } +bool EnterDirectory::canBeRun() +{ + bool result = false; + if (myScreen == myBrowser && !myBrowser->main().empty()) + { + result = myBrowser->main().current()->value().type() + == MPD::Item::Type::Directory; + } +#ifdef HAVE_TAGLIB_H + else if (myScreen->activeWindow() == myTagEditor->Dirs) + result = true; +#endif // HAVE_TAGLIB_H + return result; +} + +void EnterDirectory::run() +{ + if (myScreen == myBrowser) + myBrowser->enterDirectory(); +#ifdef HAVE_TAGLIB_H + else if (myScreen->activeWindow() == myTagEditor->Dirs) + { + if (!myTagEditor->enterDirectory()) + Statusbar::print("No subdirectories found"); + } +#endif // HAVE_TAGLIB_H +} + bool EditSong::canBeRun() { # ifdef HAVE_TAGLIB_H @@ -2603,7 +2641,7 @@ void populateActions() insert_action(new Actions::MoveEnd()); insert_action(new Actions::ToggleInterface()); insert_action(new Actions::JumpToParentDirectory()); - insert_action(new Actions::PressEnter()); + insert_action(new Actions::RunAction()); insert_action(new Actions::SelectItem()); insert_action(new Actions::SelectRange()); insert_action(new Actions::PreviousColumn()); @@ -2629,7 +2667,7 @@ void populateActions() insert_action(new Actions::MoveSelectedItemsDown()); insert_action(new Actions::MoveSelectedItemsTo()); insert_action(new Actions::Add()); - insert_action(new Actions::Play()); + insert_action(new Actions::PlayItem()); insert_action(new Actions::SeekForward()); insert_action(new Actions::SeekBackward()); insert_action(new Actions::ToggleDisplayMode()); @@ -2650,6 +2688,7 @@ void populateActions() insert_action(new Actions::ToggleCrossfade()); insert_action(new Actions::SetCrossfade()); insert_action(new Actions::SetVolume()); + insert_action(new Actions::EnterDirectory()); insert_action(new Actions::EditSong()); insert_action(new Actions::EditLibraryTag()); insert_action(new Actions::EditLibraryAlbum()); diff --git a/src/actions.h b/src/actions.h index f37f7148..5d22ecc2 100644 --- a/src/actions.h +++ b/src/actions.h @@ -28,6 +28,7 @@ #include "interfaces.h" #include "window.h" +// forward declarations struct SongList; namespace Actions { @@ -37,16 +38,16 @@ enum class Type MacroUtility = 0, Dummy, UpdateEnvironment, MouseEvent, ScrollUp, ScrollDown, ScrollUpArtist, ScrollUpAlbum, ScrollDownArtist, ScrollDownAlbum, PageUp, PageDown, MoveHome, MoveEnd, - ToggleInterface, JumpToParentDirectory, PressEnter, PreviousColumn, - NextColumn, MasterScreen, SlaveScreen, VolumeUp, VolumeDown, AddItemToPlaylist, + ToggleInterface, JumpToParentDirectory, RunAction, PreviousColumn, + NextColumn, MasterScreen, SlaveScreen, VolumeUp, VolumeDown, AddItemToPlaylist, PlayItem, DeletePlaylistItems, DeleteStoredPlaylist, DeleteBrowserItems, ReplaySong, Previous, Next, Pause, Stop, ExecuteCommand, SavePlaylist, MoveSortOrderUp, MoveSortOrderDown, - MoveSelectedItemsUp, MoveSelectedItemsDown, MoveSelectedItemsTo, Add, Play, + MoveSelectedItemsUp, MoveSelectedItemsDown, MoveSelectedItemsTo, Add, SeekForward, SeekBackward, ToggleDisplayMode, ToggleSeparatorsBetweenAlbums, ToggleLyricsUpdateOnSongChange, ToggleLyricsFetcher, ToggleFetchingLyricsInBackground, TogglePlayingSongCentering, UpdateDatabase, JumpToPlayingSong, ToggleRepeat, Shuffle, ToggleRandom, StartSearching, SaveTagChanges, ToggleSingle, ToggleConsume, ToggleCrossfade, - SetCrossfade, SetVolume, EditSong, EditLibraryTag, EditLibraryAlbum, EditDirectoryName, + SetCrossfade, SetVolume, EnterDirectory, EditSong, EditLibraryTag, EditLibraryAlbum, EditDirectoryName, EditPlaylistName, EditLyrics, JumpToBrowser, JumpToMediaLibrary, JumpToPlaylistEditor, ToggleScreenLock, JumpToTagEditor, JumpToPositionInSong, SelectItem, SelectRange, ReverseSelection, RemoveSelection, SelectAlbum, SelectFoundItems, @@ -266,12 +267,15 @@ private: virtual void run() OVERRIDE; }; -struct PressEnter: BaseAction +struct RunAction: BaseAction { - PressEnter(): BaseAction(Type::PressEnter, "press_enter") { } - + RunAction(): BaseAction(Type::RunAction, "run_action") { } + private: + virtual bool canBeRun() OVERRIDE; virtual void run() OVERRIDE; + + HasActions *m_ha; }; struct PreviousColumn: BaseAction @@ -281,6 +285,8 @@ struct PreviousColumn: BaseAction private: virtual bool canBeRun() OVERRIDE; virtual void run() OVERRIDE; + + HasColumns *m_hc; }; struct NextColumn: BaseAction @@ -290,6 +296,8 @@ struct NextColumn: BaseAction private: virtual bool canBeRun() OVERRIDE; virtual void run() OVERRIDE; + + HasColumns *m_hc; }; struct MasterScreen: BaseAction @@ -337,6 +345,17 @@ private: HasSongs *m_hs; }; +struct PlayItem: BaseAction +{ + PlayItem(): BaseAction(Type::PlayItem, "play_item") { } + +private: + virtual bool canBeRun() OVERRIDE; + virtual void run() OVERRIDE; + + HasSongs *m_hs; +}; + struct DeletePlaylistItems: BaseAction { DeletePlaylistItems(): BaseAction(Type::DeletePlaylistItems, "delete_playlist_items") { } @@ -474,15 +493,6 @@ private: virtual void run() OVERRIDE; }; -struct Play: BaseAction -{ - Play(): BaseAction(Type::Play, "play") { } - -private: - virtual bool canBeRun() OVERRIDE; - virtual void run() OVERRIDE; -}; - struct SeekForward: BaseAction { SeekForward(): BaseAction(Type::SeekForward, "seek_forward") { } @@ -665,6 +675,16 @@ private: virtual void run() OVERRIDE; }; +struct EnterDirectory: BaseAction +{ + EnterDirectory(): BaseAction(Type::EnterDirectory, "enter_directory") { } + +private: + virtual bool canBeRun() OVERRIDE; + virtual void run() OVERRIDE; +}; + + struct EditSong: BaseAction { EditSong(): BaseAction(Type::EditSong, "edit_song") { } diff --git a/src/bindings.cpp b/src/bindings.cpp index ebd26fe1..f5249e23 100644 --- a/src/bindings.cpp +++ b/src/bindings.cpp @@ -497,9 +497,10 @@ void BindingsConfiguration::generateDefaults() bind(k, Actions::Type::SelectItem); if (notBound(k = stringToKey("enter"))) { - bind(k, Actions::Type::Play); + bind(k, Actions::Type::EnterDirectory); bind(k, Actions::Type::ToggleOutput); - bind(k, Actions::Type::PressEnter); + bind(k, Actions::Type::PlayItem); + bind(k, Actions::Type::RunAction); } if (notBound(k = stringToKey("space"))) { diff --git a/src/browser.cpp b/src/browser.cpp index 1922ea08..714b5c44 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -209,40 +209,6 @@ void Browser::update() } } -void Browser::enterPressed() -{ - if (w.empty()) - return; - - const MPD::Item &item = w.current()->value(); - switch (item.type()) - { - case MPD::Item::Type::Directory: - { - getDirectory(item.directory().path()); - drawHeader(); - break; - } - case MPD::Item::Type::Song: - { - addSongToPlaylist(item.song(), true, -1); - break; - } - case MPD::Item::Type::Playlist: - { - std::vector list( - std::make_move_iterator(Mpd.GetPlaylistContentNoInfo(item.playlist().path())), - std::make_move_iterator(MPD::SongIterator()) - ); - // TODO: ask on failure if we want to continue - bool success = addSongsToPlaylist(list.begin(), list.end(), true, -1); - Statusbar::printf("Playlist \"%1%\" loaded%2%", - item.playlist().path(), withErrors(success) - ); - } - } -} - void Browser::mouseButtonPressed(MEVENT me) { if (w.empty() || !w.hasCoords(me.x, me.y) || size_t(me.y) >= w.size()) @@ -254,20 +220,17 @@ void Browser::mouseButtonPressed(MEVENT me) { case MPD::Item::Type::Directory: if (me.bstate & BUTTON1_PRESSED) - { - getDirectory(w.current()->value().directory().path()); - drawHeader(); - } + enterDirectory(); else - addItemToPlaylist(); + addItemToPlaylist(false); break; case MPD::Item::Type::Playlist: case MPD::Item::Type::Song: - if (me.bstate & BUTTON1_PRESSED) - addItemToPlaylist(); - else - enterPressed(); + { + bool play = me.bstate & BUTTON3_PRESSED; + addItemToPlaylist(play); break; + } } } else @@ -301,17 +264,36 @@ bool Browser::find(SearchDirection direction, bool wrap, bool skip_current) /***********************************************************************/ -bool Browser::addItemToPlaylist() +bool Browser::itemAvailable() +{ + return !w.empty() + // ignore parent directory + && !isParentDirectory(w.current()->value()); +} + +bool Browser::addItemToPlaylist(bool play) { bool result = false; - if (w.empty()) - return result; + + auto tryToPlay = [] { + // Cheap trick that might fail in presence of multiple + // clients modifying the playlist at the same time, but + // oh well, this approach correctly loads cue playlists + // and is much faster in general as it doesn't require + // fetching song data. + try + { + Mpd.Play(Status::State::playlistLength()); + } + catch (MPD::ServerError &e) + { + // If not bad index, rethrow. + if (e.code() != MPD_SERVER_ERROR_ARG) + throw; + } + }; const MPD::Item &item = w.current()->value(); - // ignore parent directory - if (isParentDirectory(item)) - return result; - switch (item.type()) { case MPD::Item::Type::Directory: @@ -320,23 +302,26 @@ bool Browser::addItemToPlaylist() { std::vector songs; getLocalDirectoryRecursively(songs, item.directory().path()); - result = addSongsToPlaylist(songs.begin(), songs.end(), false, -1); + result = addSongsToPlaylist(songs.begin(), songs.end(), play, -1); } else { Mpd.Add(item.directory().path()); + if (play) + tryToPlay(); result = true; } Statusbar::printf("Directory \"%1%\" added%2%", - item.directory().path(), withErrors(result) - ); + item.directory().path(), withErrors(result)); break; } case MPD::Item::Type::Song: - result = addSongToPlaylist(item.song(), false); + result = addSongToPlaylist(item.song(), play); break; case MPD::Item::Type::Playlist: Mpd.LoadPlaylist(item.playlist().path()); + if (play) + tryToPlay(); Statusbar::printf("Playlist \"%1%\" loaded", item.playlist().path()); result = true; break; @@ -424,6 +409,22 @@ void Browser::locateSong(const MPD::Song &s) w.highlight(it-begin); } +bool Browser::enterDirectory() +{ + bool result = false; + if (!w.empty()) + { + const auto &item = w.current()->value(); + if (item.type() == MPD::Item::Type::Directory) + { + getDirectory(item.directory().path()); + drawHeader(); + result = true; + } + } + return result; +} + void Browser::getDirectory(std::string directory) { m_scroll_beginning = 0; diff --git a/src/browser.h b/src/browser.h index 6ff46039..4eb8a614 100644 --- a/src/browser.h +++ b/src/browser.h @@ -56,7 +56,6 @@ struct Browser: Screen, HasSongs, Searchable, Tabbable virtual void update() OVERRIDE; - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return true; } @@ -69,7 +68,8 @@ struct Browser: Screen, HasSongs, Searchable, Tabbable virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE; // HasSongs implementation - virtual bool addItemToPlaylist() OVERRIDE; + virtual bool itemAvailable() OVERRIDE; + virtual bool addItemToPlaylist(bool play) OVERRIDE; virtual std::vector getSelectedSongs() OVERRIDE; // private members @@ -81,6 +81,7 @@ struct Browser: Screen, HasSongs, Searchable, Tabbable bool isLocal() { return m_local_browser; } void locateSong(const MPD::Song &s); + bool enterDirectory(); void getDirectory(std::string directory); void changeBrowseMode(); void remove(const MPD::Item &item); diff --git a/src/clock.h b/src/clock.h index 08ced206..2ac4f98e 100644 --- a/src/clock.h +++ b/src/clock.h @@ -42,7 +42,6 @@ struct Clock: Screen, Tabbable virtual void update() OVERRIDE; virtual void scroll(NC::Scroll) OVERRIDE { } - virtual void enterPressed() OVERRIDE { } virtual void mouseButtonPressed(MEVENT) OVERRIDE { } virtual bool isLockable() OVERRIDE { return false; } diff --git a/src/help.cpp b/src/help.cpp index d14f7d96..15fc1031 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -238,7 +238,7 @@ void write_bindings(NC::Scrollpad &w) key(w, Type::Quit, "Quit"); key_section(w, "Playlist"); - key(w, Type::Play, "Play selected item"); + key(w, Type::PlayItem, "Play selected item"); key(w, Type::DeletePlaylistItems, "Delete selected item(s) from playlist"); key(w, Type::ClearMainPlaylist, "Clear playlist"); key(w, Type::CropMainPlaylist, "Clear playlist except selected item(s)"); @@ -258,7 +258,8 @@ void write_bindings(NC::Scrollpad &w) key(w, Type::TogglePlayingSongCentering, "Toggle playing song centering"); key_section(w, "Browser"); - key(w, Type::PressEnter, "Enter directory/Add item to playlist and play it"); + key(w, Type::EnterDirectory, "Enter directory"); + key(w, Type::PlayItem, "Add item to playlist and play it"); key(w, Type::AddItemToPlaylist, "Add item to playlist"); # ifdef HAVE_TAGLIB_H key(w, Type::EditSong, "Edit song"); @@ -273,8 +274,9 @@ void write_bindings(NC::Scrollpad &w) key(w, Type::JumpToPlaylistEditor, "Jump to playlist editor (playlists only)"); key_section(w, "Search engine"); - key(w, Type::PressEnter, "Add item to playlist and play it/change option"); + key(w, Type::RunAction, "Modify option / Run action"); key(w, Type::AddItemToPlaylist, "Add item to playlist"); + key(w, Type::PlayItem, "Add item to playlist and play it"); # ifdef HAVE_TAGLIB_H key(w, Type::EditSong, "Edit song"); # endif // HAVE_TAGLIB_H @@ -285,7 +287,7 @@ void write_bindings(NC::Scrollpad &w) key(w, Type::ToggleMediaLibraryColumnsMode, "Switch between two/three columns mode"); key(w, Type::PreviousColumn, "Previous column"); key(w, Type::NextColumn, "Next column"); - key(w, Type::PressEnter, "Add item to playlist and play it"); + key(w, Type::PlayItem, "Add item to playlist and play it"); key(w, Type::AddItemToPlaylist, "Add item to playlist"); # ifdef HAVE_TAGLIB_H key(w, Type::EditSong, "Edit song"); @@ -297,7 +299,7 @@ void write_bindings(NC::Scrollpad &w) key_section(w, "Playlist editor"); key(w, Type::PreviousColumn, "Previous column"); key(w, Type::NextColumn, "Next column"); - key(w, Type::PressEnter, "Add item to playlist and play it"); + key(w, Type::PlayItem, "Add item to playlist and play it"); key(w, Type::AddItemToPlaylist, "Add item to playlist"); # ifdef HAVE_TAGLIB_H key(w, Type::EditSong, "Edit song"); @@ -317,12 +319,13 @@ void write_bindings(NC::Scrollpad &w) # ifdef HAVE_TAGLIB_H key_section(w, "Tiny tag editor"); - key(w, Type::PressEnter, "Edit tag"); + key(w, Type::RunAction, "Edit tag / Run action"); key(w, Type::SaveTagChanges, "Save"); key_section(w, "Tag editor"); - key(w, Type::PressEnter, "Edit tag/filename of selected item (left column)"); - key(w, Type::PressEnter, "Perform operation on all/selected items (middle column)"); + key(w, Type::EnterDirectory, "Enter directory (right column)"); + key(w, Type::RunAction, "Perform operation on selected items (middle column)"); + key(w, Type::RunAction, "Edit item (left column)"); key(w, Type::PreviousColumn, "Previous column"); key(w, Type::NextColumn, "Next column"); key(w, Type::JumpToParentDirectory, "Jump to parent directory (left column, directories view)"); diff --git a/src/help.h b/src/help.h index 3d7e4a4c..b715f3df 100644 --- a/src/help.h +++ b/src/help.h @@ -37,8 +37,6 @@ struct Help: Screen, Tabbable virtual void update() OVERRIDE { } - virtual void enterPressed() OVERRIDE { } - virtual bool isLockable() OVERRIDE { return true; } virtual bool isMergable() OVERRIDE { return true; } }; diff --git a/src/helpers.h b/src/helpers.h index 9a100732..2b820ca3 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -84,16 +84,6 @@ bool search(NC::Menu &m, const PredicateT &pred, return result; } -inline HasColumns *hasColumns(BaseScreen *screen) -{ - return dynamic_cast(screen); -} - -inline HasSongs *hasSongs(BaseScreen *screen) -{ - return dynamic_cast(screen); -} - template bool hasSelected(Iterator first, Iterator last) { diff --git a/src/interfaces.h b/src/interfaces.h index f18068e1..97329fb5 100644 --- a/src/interfaces.h +++ b/src/interfaces.h @@ -37,9 +37,16 @@ struct Searchable virtual bool find(SearchDirection direction, bool wrap, bool skip_current) = 0; }; +struct HasActions +{ + virtual bool actionRunnable() = 0; + virtual void runAction() = 0; +}; + struct HasSongs { - virtual bool addItemToPlaylist() = 0; + virtual bool itemAvailable() = 0; + virtual bool addItemToPlaylist(bool play) = 0; virtual std::vector getSelectedSongs() = 0; }; diff --git a/src/lastfm.h b/src/lastfm.h index 0998d3ce..8903447d 100644 --- a/src/lastfm.h +++ b/src/lastfm.h @@ -45,8 +45,6 @@ struct Lastfm: Screen, Tabbable virtual void update() OVERRIDE; - virtual void enterPressed() OVERRIDE { } - virtual bool isLockable() OVERRIDE { return false; } virtual bool isMergable() OVERRIDE { return true; } diff --git a/src/lyrics.h b/src/lyrics.h index 09903e92..a37ea262 100644 --- a/src/lyrics.h +++ b/src/lyrics.h @@ -42,8 +42,6 @@ struct Lyrics: Screen, Tabbable virtual void update() OVERRIDE; - virtual void enterPressed() OVERRIDE { } - virtual bool isLockable() OVERRIDE { return false; } virtual bool isMergable() OVERRIDE { return true; } diff --git a/src/media_library.cpp b/src/media_library.cpp index 2063141f..44ff9925 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -455,11 +455,6 @@ int MediaLibrary::windowTimeout() return Screen::windowTimeout(); } -void MediaLibrary::enterPressed() -{ - addItemToPlaylist(true); -} - void MediaLibrary::mouseButtonPressed(MEVENT me) { auto tryNextColumn = [this]() -> bool { @@ -492,7 +487,7 @@ void MediaLibrary::mouseButtonPressed(MEVENT me) { Tags.Goto(me.y); if (me.bstate & BUTTON3_PRESSED) - addItemToPlaylist(); + addItemToPlaylist(false); } else Screen::mouseButtonPressed(me); @@ -515,7 +510,7 @@ void MediaLibrary::mouseButtonPressed(MEVENT me) { Albums.Goto(me.y); if (me.bstate & BUTTON3_PRESSED) - addItemToPlaylist(); + addItemToPlaylist(false); } else Screen::mouseButtonPressed(me); @@ -528,10 +523,8 @@ void MediaLibrary::mouseButtonPressed(MEVENT me) if (size_t(me.y) < Songs.size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) { Songs.Goto(me.y); - if (me.bstate & BUTTON1_PRESSED) - addItemToPlaylist(); - else - enterPressed(); + bool play = me.bstate & BUTTON3_PRESSED; + addItemToPlaylist(play); } else Screen::mouseButtonPressed(me); @@ -594,9 +587,53 @@ bool MediaLibrary::find(SearchDirection direction, bool wrap, bool skip_current) /***********************************************************************/ -bool MediaLibrary::addItemToPlaylist() +bool MediaLibrary::itemAvailable() { - return addItemToPlaylist(false); + if (isActiveWindow(Tags)) + return !Tags.empty(); + if (isActiveWindow(Albums)) + return !Albums.empty(); + if (isActiveWindow(Songs)) + return !Songs.empty(); + return false; +} + +bool MediaLibrary::addItemToPlaylist(bool play) +{ + bool result = false; + if (isActiveWindow(Songs)) + result = addSongToPlaylist(Songs.current()->value(), play); + else + { + if (isActiveWindow(Tags) + || (isActiveWindow(Albums) && Albums.current()->value().isAllTracksEntry())) + { + Mpd.StartSearch(true); + Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current()->value().tag()); + std::vector list( + std::make_move_iterator(Mpd.CommitSearchSongs()), + std::make_move_iterator(MPD::SongIterator()) + ); + result = addSongsToPlaylist(list.begin(), list.end(), play, -1); + std::string tag_type = boost::locale::to_lower( + tagTypeToString(Config.media_lib_primary_tag)); + Statusbar::printf("Songs with %1% \"%2%\" added%3%", + tag_type, Tags.current()->value().tag(), withErrors(result) + ); + } + else if (isActiveWindow(Albums)) + { + std::vector list( + std::make_move_iterator(getSongsFromAlbum(Albums.current()->value())), + std::make_move_iterator(MPD::SongIterator()) + ); + result = addSongsToPlaylist(list.begin(), list.end(), play, -1); + Statusbar::printf("Songs from album \"%1%\" added%2%", + Albums.current()->value().entry().album(), withErrors(result) + ); + } + } + return result; } std::vector MediaLibrary::getSelectedSongs() @@ -914,44 +951,6 @@ void MediaLibrary::LocateSong(const MPD::Song &s) refresh(); } -bool MediaLibrary::addItemToPlaylist(bool play) -{ - bool result = false; - if (isActiveWindow(Songs) && !Songs.empty()) - result = addSongToPlaylist(Songs.current()->value(), play); - else - { - if ((!Tags.empty() && isActiveWindow(Tags)) - || (isActiveWindow(Albums) && Albums.current()->value().isAllTracksEntry())) - { - Mpd.StartSearch(true); - Mpd.AddSearch(Config.media_lib_primary_tag, Tags.current()->value().tag()); - std::vector list( - std::make_move_iterator(Mpd.CommitSearchSongs()), - std::make_move_iterator(MPD::SongIterator()) - ); - result = addSongsToPlaylist(list.begin(), list.end(), play, -1); - std::string tag_type = boost::locale::to_lower( - tagTypeToString(Config.media_lib_primary_tag)); - Statusbar::printf("Songs with %1% \"%2%\" added%3%", - tag_type, Tags.current()->value().tag(), withErrors(result) - ); - } - else if (isActiveWindow(Albums)) - { - std::vector list( - std::make_move_iterator(getSongsFromAlbum(Albums.current()->value())), - std::make_move_iterator(MPD::SongIterator()) - ); - result = addSongsToPlaylist(list.begin(), list.end(), play, -1); - Statusbar::printf("Songs from album \"%1%\" added%2%", - Albums.current()->value().entry().album(), withErrors(result) - ); - } - } - return result; -} - namespace { std::string AlbumToString(const AlbumEntry &ae) diff --git a/src/media_library.h b/src/media_library.h index 22e858a8..dbe17b37 100644 --- a/src/media_library.h +++ b/src/media_library.h @@ -43,7 +43,6 @@ struct MediaLibrary: Screen, HasColumns, HasSongs, Searchable, Tab virtual int windowTimeout() OVERRIDE; - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return true; } @@ -56,7 +55,8 @@ struct MediaLibrary: Screen, HasColumns, HasSongs, Searchable, Tab virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE; // HasSongs implementation - virtual bool addItemToPlaylist() OVERRIDE; + virtual bool itemAvailable() OVERRIDE; + virtual bool addItemToPlaylist(bool play) OVERRIDE; virtual std::vector getSelectedSongs() OVERRIDE; // HasColumns implementation @@ -133,8 +133,6 @@ struct MediaLibrary: Screen, HasColumns, HasSongs, Searchable, Tab SongMenu Songs; private: - bool addItemToPlaylist(bool play); - bool m_tags_update_request; bool m_albums_update_request; bool m_songs_update_request; diff --git a/src/outputs.cpp b/src/outputs.cpp index 3b076108..48adcef6 100644 --- a/src/outputs.cpp +++ b/src/outputs.cpp @@ -77,7 +77,7 @@ void Outputs::mouseButtonPressed(MEVENT me) { w.Goto(me.y); if (me.bstate & BUTTON3_PRESSED) - enterPressed(); + toggleOutput(); } else Screen::mouseButtonPressed(me); diff --git a/src/outputs.h b/src/outputs.h index 7da62a2c..f767391e 100644 --- a/src/outputs.h +++ b/src/outputs.h @@ -43,7 +43,6 @@ struct Outputs: Screen>, Tabbable virtual void update() OVERRIDE { } - virtual void enterPressed() OVERRIDE { } virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return true; } diff --git a/src/playlist.cpp b/src/playlist.cpp index a8e2f775..9dd9bcc3 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -139,7 +139,7 @@ void Playlist::mouseButtonPressed(MEVENT me) { w.Goto(me.y); if (me.bstate & BUTTON3_PRESSED) - enterPressed(); + addItemToPlaylist(true); } else Screen::mouseButtonPressed(me); @@ -172,6 +172,18 @@ bool Playlist::find(SearchDirection direction, bool wrap, bool skip_current) /***********************************************************************/ +bool Playlist::itemAvailable() +{ + return !w.empty(); +} + +bool Playlist::addItemToPlaylist(bool play) +{ + if (play) + Mpd.PlayID(w.currentV()->getID()); + return true; +} + std::vector Playlist::getSelectedSongs() { return w.getSelectedSongs(); diff --git a/src/playlist.h b/src/playlist.h index 65f32568..d922795b 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -43,7 +43,6 @@ struct Playlist: Screen, HasSongs, Searchable, Tabbable virtual void update() OVERRIDE; - virtual void enterPressed() OVERRIDE { } virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return true; } @@ -56,7 +55,8 @@ struct Playlist: Screen, HasSongs, Searchable, Tabbable virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE; // HasSongs implementation - virtual bool addItemToPlaylist() OVERRIDE { return false; }; + virtual bool itemAvailable() OVERRIDE; + virtual bool addItemToPlaylist(bool play) OVERRIDE; virtual std::vector getSelectedSongs() OVERRIDE; // private members diff --git a/src/playlist_editor.cpp b/src/playlist_editor.cpp index 6012b704..2dd7eb75 100644 --- a/src/playlist_editor.cpp +++ b/src/playlist_editor.cpp @@ -225,11 +225,6 @@ int PlaylistEditor::windowTimeout() return Screen::windowTimeout(); } -void PlaylistEditor::enterPressed() -{ - addItemToPlaylist(true); -} - void PlaylistEditor::mouseButtonPressed(MEVENT me) { if (!Playlists.empty() && Playlists.hasCoords(me.x, me.y)) @@ -245,7 +240,7 @@ void PlaylistEditor::mouseButtonPressed(MEVENT me) { Playlists.Goto(me.y); if (me.bstate & BUTTON3_PRESSED) - addItemToPlaylist(); + addItemToPlaylist(false); } else Screen::mouseButtonPressed(me); @@ -263,10 +258,8 @@ void PlaylistEditor::mouseButtonPressed(MEVENT me) if (size_t(me.y) < Content.size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) { Content.Goto(me.y); - if (me.bstate & BUTTON1_PRESSED) - addItemToPlaylist(); - else - enterPressed(); + bool play = me.bstate & BUTTON3_PRESSED; + addItemToPlaylist(play); } else Screen::mouseButtonPressed(me); @@ -318,9 +311,32 @@ bool PlaylistEditor::find(SearchDirection direction, bool wrap, bool skip_curren /***********************************************************************/ -bool PlaylistEditor::addItemToPlaylist() +bool PlaylistEditor::itemAvailable() { - return addItemToPlaylist(false); + if (isActiveWindow(Playlists)) + return !Playlists.empty(); + if (isActiveWindow(Content)) + return !Content.empty(); + return false; +} + +bool PlaylistEditor::addItemToPlaylist(bool play) +{ + bool result = false; + if (isActiveWindow(Playlists)) + { + std::vector list( + std::make_move_iterator(Mpd.GetPlaylistContent(Playlists.current()->value().path())), + std::make_move_iterator(MPD::SongIterator()) + ); + result = addSongsToPlaylist(list.begin(), list.end(), play, -1); + Statusbar::printf("Playlist \"%1%\" loaded%2%", + Playlists.current()->value().path(), withErrors(result) + ); + } + else if (isActiveWindow(Content)) + result = addSongToPlaylist(Content.current()->value(), play); + return result; } std::vector PlaylistEditor::getSelectedSongs() @@ -420,25 +436,6 @@ void PlaylistEditor::Locate(const MPD::Playlist &playlist) } } -bool PlaylistEditor::addItemToPlaylist(bool play) -{ - bool result = false; - if (isActiveWindow(Playlists) && !Playlists.empty()) - { - std::vector list( - std::make_move_iterator(Mpd.GetPlaylistContent(Playlists.current()->value().path())), - std::make_move_iterator(MPD::SongIterator()) - ); - result = addSongsToPlaylist(list.begin(), list.end(), play, -1); - Statusbar::printf("Playlist \"%1%\" loaded%2%", - Playlists.current()->value().path(), withErrors(result) - ); - } - else if (isActiveWindow(Content) && !Content.empty()) - result = addSongToPlaylist(Content.current()->value(), play); - return result; -} - namespace { std::string SongToString(const MPD::Song &s) diff --git a/src/playlist_editor.h b/src/playlist_editor.h index 92583c9e..b5ff33ca 100644 --- a/src/playlist_editor.h +++ b/src/playlist_editor.h @@ -43,7 +43,6 @@ struct PlaylistEditor: Screen, HasColumns, HasSongs, Searchable, T virtual int windowTimeout() OVERRIDE; - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return true; } @@ -56,7 +55,8 @@ struct PlaylistEditor: Screen, HasColumns, HasSongs, Searchable, T virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE; // HasSongs implementation - virtual bool addItemToPlaylist() OVERRIDE; + virtual bool itemAvailable() OVERRIDE; + virtual bool addItemToPlaylist(bool play) OVERRIDE; virtual std::vector getSelectedSongs() OVERRIDE; // HasColumns implementation @@ -78,8 +78,6 @@ struct PlaylistEditor: Screen, HasColumns, HasSongs, Searchable, T SongMenu Content; private: - bool addItemToPlaylist(bool play); - bool m_playlists_update_requested; bool m_content_update_requested; diff --git a/src/screen.h b/src/screen.h index a8c88959..ec98a666 100644 --- a/src/screen.h +++ b/src/screen.h @@ -73,9 +73,6 @@ struct BaseScreen /// somehow, it should be called by this function. virtual void update() = 0; - /// Invoked after Enter was pressed - virtual void enterPressed() = 0; - /// @see Screen::mouseButtonPressed() virtual void mouseButtonPressed(MEVENT me) = 0; diff --git a/src/search_engine.cpp b/src/search_engine.cpp index 7979c3d2..222e93e4 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -205,12 +205,66 @@ std::wstring SearchEngine::title() return L"Search engine"; } -void SearchEngine::enterPressed() +void SearchEngine::mouseButtonPressed(MEVENT me) +{ + if (w.empty() || !w.hasCoords(me.x, me.y) || size_t(me.y) >= w.size()) + return; + if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)) + { + if (!w.Goto(me.y)) + return; + w.refresh(); + if ((me.bstate & BUTTON3_PRESSED) + && w.choice() < StaticOptions) + runAction(); + else if (w.choice() >= StaticOptions) + { + bool play = me.bstate & BUTTON3_PRESSED; + addItemToPlaylist(play); + } + } + else + Screen::mouseButtonPressed(me); +} + +/***********************************************************************/ + +bool SearchEngine::allowsSearching() +{ + return w.rbegin()->value().isSong(); +} + +void SearchEngine::setSearchConstraint(const std::string &constraint) +{ + m_search_predicate = Regex::ItemFilter( + Regex::make(constraint, Config.regex_type), + std::bind(SEItemEntryMatcher, ph::_1, ph::_2, false) + ); +} + +void SearchEngine::clearConstraint() +{ + m_search_predicate.clear(); +} + +bool SearchEngine::find(SearchDirection direction, bool wrap, bool skip_current) +{ + return search(w, m_search_predicate, direction, wrap, skip_current); +} + +/***********************************************************************/ + +bool SearchEngine::actionRunnable() +{ + return !w.empty() && !w.current()->value().isSong(); +} + +void SearchEngine::runAction() { size_t option = w.choice(); if (option > ConstraintsNumber && option < SearchButton) w.current()->value().buffer().clear(); - + if (option < ConstraintsNumber) { Statusbar::ScopedLock slock; @@ -268,62 +322,16 @@ void SearchEngine::enterPressed() addSongToPlaylist(w.current()->value().song(), true); } -void SearchEngine::mouseButtonPressed(MEVENT me) -{ - if (w.empty() || !w.hasCoords(me.x, me.y) || size_t(me.y) >= w.size()) - return; - if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)) - { - if (!w.Goto(me.y)) - return; - w.refresh(); - if ((me.bstate & BUTTON3_PRESSED || w.choice() > ConstraintsNumber) && w.choice() < StaticOptions) - enterPressed(); - else if (w.choice() >= StaticOptions) - { - if (me.bstate & BUTTON1_PRESSED) - addItemToPlaylist(); - else - enterPressed(); - } - } - else - Screen::mouseButtonPressed(me); -} - /***********************************************************************/ -bool SearchEngine::allowsSearching() +bool SearchEngine::itemAvailable() { - return w.rbegin()->value().isSong(); + return !w.empty() && w.current()->value().isSong(); } -void SearchEngine::setSearchConstraint(const std::string &constraint) +bool SearchEngine::addItemToPlaylist(bool play) { - m_search_predicate = Regex::ItemFilter( - Regex::make(constraint, Config.regex_type), - std::bind(SEItemEntryMatcher, ph::_1, ph::_2, false) - ); -} - -void SearchEngine::clearConstraint() -{ - m_search_predicate.clear(); -} - -bool SearchEngine::find(SearchDirection direction, bool wrap, bool skip_current) -{ - return search(w, m_search_predicate, direction, wrap, skip_current); -} - -/***********************************************************************/ - -bool SearchEngine::addItemToPlaylist() -{ - bool result = false; - if (!w.empty() && w.current()->value().isSong()) - result = addSongToPlaylist(w.current()->value().song(), false); - return result; + return addSongToPlaylist(w.current()->value().song(), play); } std::vector SearchEngine::getSelectedSongs() diff --git a/src/search_engine.h b/src/search_engine.h index cd81750a..863e3db5 100644 --- a/src/search_engine.h +++ b/src/search_engine.h @@ -91,7 +91,7 @@ struct SearchEngineWindow: NC::Menu, SongList virtual std::vector getSelectedSongs() OVERRIDE; }; -struct SearchEngine: Screen, HasSongs, Searchable, Tabbable +struct SearchEngine: Screen, HasActions, HasSongs, Searchable, Tabbable { SearchEngine(); @@ -104,7 +104,6 @@ struct SearchEngine: Screen, HasSongs, Searchable, Tabbable virtual void update() OVERRIDE { } - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return true; } @@ -115,9 +114,14 @@ struct SearchEngine: Screen, HasSongs, Searchable, Tabbable virtual void setSearchConstraint(const std::string &constraint) OVERRIDE; virtual void clearConstraint() OVERRIDE; virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE; - + + // HasActions implementation + virtual bool actionRunnable() OVERRIDE; + virtual void runAction() OVERRIDE; + // HasSongs implementation - virtual bool addItemToPlaylist() OVERRIDE; + virtual bool itemAvailable() OVERRIDE; + virtual bool addItemToPlaylist(bool play) OVERRIDE; virtual std::vector getSelectedSongs() OVERRIDE; // private members diff --git a/src/sel_items_adder.cpp b/src/sel_items_adder.cpp index 81644096..007b3b5f 100644 --- a/src/sel_items_adder.cpp +++ b/src/sel_items_adder.cpp @@ -113,7 +113,7 @@ void SelectedItemsAdder::switchTo() { using Global::myScreen; - auto hs = hasSongs(myScreen); + auto hs = dynamic_cast(myScreen); if (!hs) return; @@ -169,11 +169,6 @@ std::wstring SelectedItemsAdder::title() return previousScreen()->title(); } -void SelectedItemsAdder::enterPressed() -{ - w->current()->value().run(); -} - void SelectedItemsAdder::mouseButtonPressed(MEVENT me) { if (w->empty() || !w->hasCoords(me.x, me.y) || size_t(me.y) >= w->size()) @@ -182,7 +177,7 @@ void SelectedItemsAdder::mouseButtonPressed(MEVENT me) { w->Goto(me.y); if (me.bstate & BUTTON3_PRESSED) - enterPressed(); + runAction(); } else Screen::mouseButtonPressed(me); @@ -190,6 +185,18 @@ void SelectedItemsAdder::mouseButtonPressed(MEVENT me) /***********************************************************************/ +bool SelectedItemsAdder::actionRunnable() +{ + return !w->empty(); +} + +void SelectedItemsAdder::runAction() +{ + w->current()->value().run(); +} + +/***********************************************************************/ + bool SelectedItemsAdder::allowsSearching() { return true; diff --git a/src/sel_items_adder.h b/src/sel_items_adder.h index b3208785..4b27ba65 100644 --- a/src/sel_items_adder.h +++ b/src/sel_items_adder.h @@ -27,7 +27,7 @@ #include "screen.h" #include "song.h" -struct SelectedItemsAdder: Screen> *>, Searchable, Tabbable +struct SelectedItemsAdder: Screen> *>, HasActions, Searchable, Tabbable { typedef SelectedItemsAdder Self; typedef typename std::remove_pointer::type Component; @@ -44,12 +44,15 @@ struct SelectedItemsAdder: Screen> *> virtual void update() OVERRIDE { } - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return false; } virtual bool isMergable() OVERRIDE { return false; } - + + // HasActions implemenetation + virtual bool actionRunnable() OVERRIDE; + virtual void runAction() OVERRIDE; + // Searchable implementation virtual bool allowsSearching() OVERRIDE; virtual void setSearchConstraint(const std::string &constraint) OVERRIDE; diff --git a/src/server_info.h b/src/server_info.h index e0550c81..4efc95df 100644 --- a/src/server_info.h +++ b/src/server_info.h @@ -39,8 +39,6 @@ struct ServerInfo: Screen, Tabbable virtual void update() OVERRIDE; - virtual void enterPressed() OVERRIDE { } - virtual bool isLockable() OVERRIDE { return false; } virtual bool isMergable() OVERRIDE { return false; } diff --git a/src/song_info.h b/src/song_info.h index 57bd1d2c..95f974d8 100644 --- a/src/song_info.h +++ b/src/song_info.h @@ -45,8 +45,6 @@ struct SongInfo: Screen, Tabbable virtual void update() OVERRIDE { } - virtual void enterPressed() OVERRIDE { } - virtual bool isLockable() OVERRIDE { return false; } virtual bool isMergable() OVERRIDE { return true; } diff --git a/src/sort_playlist.cpp b/src/sort_playlist.cpp index c21ca71a..69851b9a 100644 --- a/src/sort_playlist.cpp +++ b/src/sort_playlist.cpp @@ -107,11 +107,6 @@ std::wstring SortPlaylistDialog::title() return previousScreen()->title(); } -void SortPlaylistDialog::enterPressed() -{ - w.current()->value().run(); -} - void SortPlaylistDialog::mouseButtonPressed(MEVENT me) { if (w.hasCoords(me.x, me.y)) @@ -120,13 +115,27 @@ void SortPlaylistDialog::mouseButtonPressed(MEVENT me) { w.Goto(me.y); if (me.bstate & BUTTON3_PRESSED) - enterPressed(); + runAction(); } else Screen::mouseButtonPressed(me); } } +/**********************************************************************/ + +bool SortPlaylistDialog::actionRunnable() +{ + return !w.empty(); +} + +void SortPlaylistDialog::runAction() +{ + w.current()->value().run(); +} + +/**********************************************************************/ + void SortPlaylistDialog::moveSortOrderDown() { auto cur = w.currentV(); diff --git a/src/sort_playlist.h b/src/sort_playlist.h index c3e66c38..0befa94b 100644 --- a/src/sort_playlist.h +++ b/src/sort_playlist.h @@ -27,7 +27,7 @@ #include "song.h" struct SortPlaylistDialog -: Screen, void()>>>, Tabbable + : Screen, void()>>>, HasActions, Tabbable { typedef SortPlaylistDialog Self; @@ -41,12 +41,15 @@ struct SortPlaylistDialog virtual void update() OVERRIDE { } - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return false; } virtual bool isMergable() OVERRIDE { return false; } - + + // HasActions implementation + virtual bool actionRunnable() OVERRIDE; + virtual void runAction() OVERRIDE; + // private members void moveSortOrderUp(); void moveSortOrderDown(); diff --git a/src/status.cpp b/src/status.cpp index e1cdab73..d242340c 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -379,6 +379,11 @@ int Status::State::currentSongPosition() return m_current_song_pos; } +unsigned Status::State::playlistLength() +{ + return m_playlist_length; +} + unsigned Status::State::elapsedTime() { return m_elapsed_time; diff --git a/src/status.h b/src/status.h index bfdd8bab..2fb70c4b 100644 --- a/src/status.h +++ b/src/status.h @@ -46,6 +46,7 @@ bool single(); // misc int currentSongID(); int currentSongPosition(); +unsigned playlistLength(); unsigned elapsedTime(); MPD::PlayerState player(); unsigned totalTime(); diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index b1666ee7..cd4dd770 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -329,11 +329,10 @@ void TagEditor::update() } } -void TagEditor::enterPressed() +bool TagEditor::enterDirectory() { - using Global::wFooter; - - if (w == Dirs) + bool result = false; + if (w == Dirs && !Dirs->empty()) { MPD::DirectoryIterator directory = Mpd.GetDirectories(Dirs->current()->value().second), end; bool has_subdirs = directory != end; @@ -344,11 +343,194 @@ void TagEditor::enterPressed() itsBrowsedDir = Dirs->current()->value().second; Dirs->clear(); Dirs->reset(); + result = true; + } + } + return result; +} + +void TagEditor::mouseButtonPressed(MEVENT me) +{ + auto tryPreviousColumn = [this]() -> bool { + bool result = true; + if (w != Dirs) + { + if (previousColumnAvailable()) + previousColumn(); + else + result = false; + } + return result; + }; + auto tryNextColumn = [this]() -> bool { + bool result = true; + if (w != Tags) + { + if (nextColumnAvailable()) + nextColumn(); + else + result = false; + } + return result; + }; + if (w == FParserDialog) + { + if (FParserDialog->hasCoords(me.x, me.y)) + { + if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)) + { + FParserDialog->Goto(me.y); + if (me.bstate & BUTTON3_PRESSED) + runAction(); + } + else + Screen::mouseButtonPressed(me); + } + } + else if (w == FParser || w == FParserHelper) + { + if (FParser->hasCoords(me.x, me.y)) + { + if (w != FParser) + { + if (previousColumnAvailable()) + previousColumn(); + else + return; + } + if (size_t(me.y) < FParser->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) + { + FParser->Goto(me.y); + if (me.bstate & BUTTON3_PRESSED) + runAction(); + } + else + Screen::mouseButtonPressed(me); + } + else if (FParserHelper->hasCoords(me.x, me.y)) + { + if (w != FParserHelper) + { + if (nextColumnAvailable()) + nextColumn(); + else + return; + } + scrollpadMouseButtonPressed(*FParserHelper, me); + } + } + else if (!Dirs->empty() && Dirs->hasCoords(me.x, me.y)) + { + if (!tryPreviousColumn() || !tryPreviousColumn()) + return; + if (size_t(me.y) < Dirs->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) + { + Dirs->Goto(me.y); + if (me.bstate & BUTTON1_PRESSED) + enterDirectory(); } else - Statusbar::print("No subdirectories found"); + Screen::mouseButtonPressed(me); + Tags->clear(); } - else if (w == FParserDialog) + else if (!TagTypes->empty() && TagTypes->hasCoords(me.x, me.y)) + { + if (w != TagTypes) + { + bool success; + if (w == Dirs) + success = tryNextColumn(); + else + success = tryPreviousColumn(); + if (!success) + return; + } + if (size_t(me.y) < TagTypes->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) + { + if (!TagTypes->Goto(me.y)) + return; + TagTypes->refresh(); + Tags->refresh(); + if (me.bstate & BUTTON3_PRESSED) + runAction(); + } + else + Screen::mouseButtonPressed(me); + } + else if (!Tags->empty() && Tags->hasCoords(me.x, me.y)) + { + if (!tryNextColumn() || !tryNextColumn()) + return; + if (size_t(me.y) < Tags->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) + { + Tags->Goto(me.y); + Tags->refresh(); + if (me.bstate & BUTTON3_PRESSED) + runAction(); + } + else + Screen::mouseButtonPressed(me); + } +} + +/***********************************************************************/ + +bool TagEditor::allowsSearching() +{ + return w == Dirs || w == Tags; +} + +void TagEditor::setSearchConstraint(const std::string &constraint) +{ + if (w == Dirs) + { + m_directories_search_predicate = Regex::Filter>( + Regex::make(constraint, Config.regex_type), + std::bind(DirEntryMatcher, ph::_1, ph::_2, false) + ); + } + else if (w == Tags) + { + m_songs_search_predicate = Regex::Filter( + Regex::make(constraint, Config.regex_type), + SongEntryMatcher + ); + } +} + +void TagEditor::clearConstraint() +{ + if (w == Dirs) + m_directories_search_predicate.clear(); + else if (w == Tags) + m_songs_search_predicate.clear(); +} + +bool TagEditor::find(SearchDirection direction, bool wrap, bool skip_current) +{ + bool result = false; + if (w == Dirs) + result = search(*Dirs, m_directories_search_predicate, direction, wrap, skip_current); + else if (w == Tags) + result = search(*Tags, m_songs_search_predicate, direction, wrap, skip_current); + return result; +} + +/***********************************************************************/ + +bool TagEditor::actionRunnable() +{ + // TODO: put something more refined here. It requires reworking + // runAction though, i.e. splitting it into smaller parts. + return (w == Tags && !Tags->empty()) + || w != Tags; +} + +void TagEditor::runAction() +{ + using Global::wFooter; + + if (w == FParserDialog) { size_t choice = FParserDialog->choice(); if (choice == 2) // cancel @@ -358,9 +540,9 @@ void TagEditor::enterPressed() return; } GetPatternList(); - + // prepare additional windows - + FParserLegend->clear(); *FParserLegend << "%a - artist\n"; *FParserLegend << "%A - album artist\n"; @@ -377,7 +559,7 @@ void TagEditor::enterPressed() for (auto it = EditedSongs.begin(); it != EditedSongs.end(); ++it) *FParserLegend << Config.color2 << " * " << NC::Color::End << (*it)->getName() << '\n'; FParserLegend->flush(); - + if (!Patterns.empty()) Config.pattern = Patterns.front(); FParser->clear(); @@ -396,7 +578,7 @@ void TagEditor::enterPressed() for (std::list::const_iterator it = Patterns.begin(); it != Patterns.end(); ++it) FParser->addItem(*it); } - + FParser->setTitle(choice == 0 ? "Get tags from filename" : "Rename files"); w = FParser; FParserUsePreview = 1; @@ -407,10 +589,10 @@ void TagEditor::enterPressed() { bool quit = 0; size_t pos = FParser->choice(); - + if (pos == 4) // save FParserUsePreview = 0; - + if (pos == 0) // change pattern { std::string new_pattern; @@ -494,7 +676,7 @@ void TagEditor::enterPressed() Config.pattern = FParser->current()->value(); FParser->at(0).value() = "Pattern: " + Config.pattern; } - + if (quit) { SavePatternList(); @@ -503,10 +685,10 @@ void TagEditor::enterPressed() return; } } - + if ((w != TagTypes && w != Tags) || Tags->empty()) // after this point we start dealing with tags return; - + EditedSongs.clear(); // if there are selected songs, perform operations only on them if (hasSelected(Tags->begin(), Tags->end())) @@ -520,9 +702,9 @@ void TagEditor::enterPressed() for (auto it = Tags->begin(); it != Tags->end(); ++it) EditedSongs.push_back(&it->value()); } - + size_t id = TagTypes->choice(); - + if (w == TagTypes && id == 5) { Actions::confirmAction("Number tracks?"); @@ -539,7 +721,7 @@ void TagEditor::enterPressed() Statusbar::print("Tracks numbered"); return; } - + if (id < 11) { MPD::Song::GetFunction get = SongInfo::Tags[id].Get; @@ -637,181 +819,19 @@ void TagEditor::enterPressed() } } -void TagEditor::mouseButtonPressed(MEVENT me) -{ - auto tryPreviousColumn = [this]() -> bool { - bool result = true; - if (w != Dirs) - { - if (previousColumnAvailable()) - previousColumn(); - else - result = false; - } - return result; - }; - auto tryNextColumn = [this]() -> bool { - bool result = true; - if (w != Tags) - { - if (nextColumnAvailable()) - nextColumn(); - else - result = false; - } - return result; - }; - if (w == FParserDialog) - { - if (FParserDialog->hasCoords(me.x, me.y)) - { - if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)) - { - FParserDialog->Goto(me.y); - if (me.bstate & BUTTON3_PRESSED) - enterPressed(); - } - else - Screen::mouseButtonPressed(me); - } - } - else if (w == FParser || w == FParserHelper) - { - if (FParser->hasCoords(me.x, me.y)) - { - if (w != FParser) - { - if (previousColumnAvailable()) - previousColumn(); - else - return; - } - if (size_t(me.y) < FParser->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) - { - FParser->Goto(me.y); - if (me.bstate & BUTTON3_PRESSED) - enterPressed(); - } - else - Screen::mouseButtonPressed(me); - } - else if (FParserHelper->hasCoords(me.x, me.y)) - { - if (w != FParserHelper) - { - if (nextColumnAvailable()) - nextColumn(); - else - return; - } - scrollpadMouseButtonPressed(*FParserHelper, me); - } - } - else if (!Dirs->empty() && Dirs->hasCoords(me.x, me.y)) - { - if (!tryPreviousColumn() || !tryPreviousColumn()) - return; - if (size_t(me.y) < Dirs->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) - { - Dirs->Goto(me.y); - if (me.bstate & BUTTON1_PRESSED) - enterPressed(); - } - else - Screen::mouseButtonPressed(me); - Tags->clear(); - } - else if (!TagTypes->empty() && TagTypes->hasCoords(me.x, me.y)) - { - if (w != TagTypes) - { - bool success; - if (w == Dirs) - success = tryNextColumn(); - else - success = tryPreviousColumn(); - if (!success) - return; - } - if (size_t(me.y) < TagTypes->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) - { - if (!TagTypes->Goto(me.y)) - return; - TagTypes->refresh(); - Tags->refresh(); - if (me.bstate & BUTTON3_PRESSED) - enterPressed(); - } - else - Screen::mouseButtonPressed(me); - } - else if (!Tags->empty() && Tags->hasCoords(me.x, me.y)) - { - if (!tryNextColumn() || !tryNextColumn()) - return; - if (size_t(me.y) < Tags->size() && (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED))) - { - Tags->Goto(me.y); - Tags->refresh(); - if (me.bstate & BUTTON3_PRESSED) - enterPressed(); - } - else - Screen::mouseButtonPressed(me); - } -} /***********************************************************************/ -bool TagEditor::allowsSearching() +bool TagEditor::itemAvailable() { - return w == Dirs || w == Tags; + if (w == Tags) + return !Tags->empty(); + return false; } -void TagEditor::setSearchConstraint(const std::string &constraint) +bool TagEditor::addItemToPlaylist(bool play) { - if (w == Dirs) - { - m_directories_search_predicate = Regex::Filter>( - Regex::make(constraint, Config.regex_type), - std::bind(DirEntryMatcher, ph::_1, ph::_2, false) - ); - } - else if (w == Tags) - { - m_songs_search_predicate = Regex::Filter( - Regex::make(constraint, Config.regex_type), - SongEntryMatcher - ); - } -} - -void TagEditor::clearConstraint() -{ - if (w == Dirs) - m_directories_search_predicate.clear(); - else if (w == Tags) - m_songs_search_predicate.clear(); -} - -bool TagEditor::find(SearchDirection direction, bool wrap, bool skip_current) -{ - bool result = false; - if (w == Dirs) - result = search(*Dirs, m_directories_search_predicate, direction, wrap, skip_current); - else if (w == Tags) - result = search(*Tags, m_songs_search_predicate, direction, wrap, skip_current); - return result; -} - -/***********************************************************************/ - -bool TagEditor::addItemToPlaylist() -{ - bool result = false; - if (w == Tags && !Tags->empty()) - result = addSongToPlaylist(*Tags->currentV(), false); - return result; + return addSongToPlaylist(*Tags->currentV(), play); } std::vector TagEditor::getSelectedSongs() diff --git a/src/tag_editor.h b/src/tag_editor.h index 7b9a86d6..bd72ae59 100644 --- a/src/tag_editor.h +++ b/src/tag_editor.h @@ -49,7 +49,7 @@ struct TagsWindow: NC::Menu, SongList virtual std::vector getSelectedSongs() OVERRIDE; }; -struct TagEditor: Screen, HasColumns, HasSongs, Searchable, Tabbable +struct TagEditor: Screen, HasActions, HasColumns, HasSongs, Searchable, Tabbable { TagEditor(); @@ -62,7 +62,6 @@ struct TagEditor: Screen, HasColumns, HasSongs, Searchable, Tabbab virtual void refresh() OVERRIDE; virtual void update() OVERRIDE; - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT) OVERRIDE; virtual bool isLockable() OVERRIDE { return true; } @@ -73,9 +72,14 @@ struct TagEditor: Screen, HasColumns, HasSongs, Searchable, Tabbab virtual void setSearchConstraint(const std::string &constraint) OVERRIDE; virtual void clearConstraint() OVERRIDE; virtual bool find(SearchDirection direction, bool wrap, bool skip_current) OVERRIDE; - + + // HasActions implementation + virtual bool actionRunnable() OVERRIDE; + virtual void runAction() OVERRIDE; + // HasSongs implementation - virtual bool addItemToPlaylist() OVERRIDE; + virtual bool itemAvailable() OVERRIDE; + virtual bool addItemToPlaylist(bool play) OVERRIDE; virtual std::vector getSelectedSongs() OVERRIDE; // HasColumns implementation @@ -86,6 +90,7 @@ struct TagEditor: Screen, HasColumns, HasSongs, Searchable, Tabbab virtual void nextColumn() OVERRIDE; // private members + bool enterDirectory(); void LocateSong(const MPD::Song &s); const std::string &CurrentDir() { return itsBrowsedDir; } diff --git a/src/tiny_tag_editor.cpp b/src/tiny_tag_editor.cpp index a18698b3..a029f470 100644 --- a/src/tiny_tag_editor.cpp +++ b/src/tiny_tag_editor.cpp @@ -99,7 +99,32 @@ std::wstring TinyTagEditor::title() return L"Tiny tag editor"; } -void TinyTagEditor::enterPressed() +void TinyTagEditor::mouseButtonPressed(MEVENT me) +{ + if (w.empty() || !w.hasCoords(me.x, me.y) || size_t(me.y) >= w.size()) + return; + if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)) + { + if (!w.Goto(me.y)) + return; + if (me.bstate & BUTTON3_PRESSED) + { + w.refresh(); + runAction(); + } + } + else + Screen::mouseButtonPressed(me); +} + +/**********************************************************************/ + +bool TinyTagEditor::actionRunnable() +{ + return !w.empty(); +} + +void TinyTagEditor::runAction() { size_t option = w.choice(); if (option < 19) // separator after comment @@ -129,7 +154,7 @@ void TinyTagEditor::enterPressed() w.at(option).value() << NC::Format::Bold << "Filename:" << NC::Format::NoBold << ' ' << (itsEdited.getNewName().empty() ? itsEdited.getName() : itsEdited.getNewName()); } } - + if (option == 22) { Statusbar::print("Updating tags..."); @@ -153,23 +178,7 @@ void TinyTagEditor::enterPressed() m_previous_screen->switchTo(); } -void TinyTagEditor::mouseButtonPressed(MEVENT me) -{ - if (w.empty() || !w.hasCoords(me.x, me.y) || size_t(me.y) >= w.size()) - return; - if (me.bstate & (BUTTON1_PRESSED | BUTTON3_PRESSED)) - { - if (!w.Goto(me.y)) - return; - if (me.bstate & BUTTON3_PRESSED) - { - w.refresh(); - enterPressed(); - } - } - else - Screen::mouseButtonPressed(me); -} +/**********************************************************************/ void TinyTagEditor::SetEdited(const MPD::Song &s) { diff --git a/src/tiny_tag_editor.h b/src/tiny_tag_editor.h index 2506d954..3e85eb70 100644 --- a/src/tiny_tag_editor.h +++ b/src/tiny_tag_editor.h @@ -29,7 +29,7 @@ #include "mutable_song.h" #include "screen.h" -struct TinyTagEditor: Screen> +struct TinyTagEditor: Screen>, HasActions { TinyTagEditor(); @@ -42,12 +42,15 @@ struct TinyTagEditor: Screen> virtual void update() OVERRIDE { } - virtual void enterPressed() OVERRIDE; virtual void mouseButtonPressed(MEVENT me) OVERRIDE; virtual bool isLockable() OVERRIDE { return false; } virtual bool isMergable() OVERRIDE { return true; } - + + // HasActions implemenetation + virtual bool actionRunnable() OVERRIDE; + virtual void runAction() OVERRIDE; + // private members void SetEdited(const MPD::Song &); diff --git a/src/visualizer.h b/src/visualizer.h index 8baf608a..eb525b99 100644 --- a/src/visualizer.h +++ b/src/visualizer.h @@ -49,7 +49,6 @@ struct Visualizer: Screen, Tabbable virtual int windowTimeout() OVERRIDE; - virtual void enterPressed() OVERRIDE { } virtual void mouseButtonPressed(MEVENT) OVERRIDE { } virtual bool isLockable() OVERRIDE { return true; }