Merge pull request #526 from Wallacoloo/master
Add ability to delete songs from the collection through a keyboard shortcut
This commit is contained in:
@@ -342,6 +342,7 @@ Not Supported=Mode not supported while networked.
|
||||
[OptionExplanations]
|
||||
Accel=Accelerate, Decelerate or otherwise adjust the arrow speed.
|
||||
AllowExtraStage=When enabled (and Event Mode isn't on), allows the player to earn extra stages after completing certain requirements.
|
||||
AllowSongDeletion=Allow players to permanently delete songs from the system by pressing Ctrl+Backspace when browsing the music wheel.
|
||||
AllowW1=Enable or disable fantastic judgement. NEVER - never show Fantastic, COURSES ONLY - only during nonstop/oni modes, ALWAYS - all modes of play.
|
||||
AllowMultipleHighScoreWithSameName=If turned off, only the highest score with a given name will be saved. If turned on, it will allow mutliple high scores with a given name to be saved.
|
||||
Announcer=Choose from this list of installed announcer packs.
|
||||
@@ -934,6 +935,7 @@ Add Attack=Add Attack
|
||||
Add Mod=Add Mod
|
||||
Air=Air
|
||||
AllowExtraStage=Allow Extra Stage
|
||||
AllowSongDeletion=Allow Song Deletion
|
||||
AllowW1=Fantastic Timing
|
||||
AllowMultipleHighScoreWithSameName=Competitive Mode
|
||||
Alter=Alter
|
||||
|
||||
@@ -2751,7 +2751,7 @@ IdleTimeoutSeconds=0
|
||||
|
||||
[ScreenOptionsAdvanced]
|
||||
Fallback="ScreenOptionsServiceChild"
|
||||
LineNames="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31"
|
||||
LineNames="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32"
|
||||
Line1="conf,MenuTimer"
|
||||
Line2="conf,ScoringType"
|
||||
Line3="conf,TimingWindowScale"
|
||||
@@ -2783,6 +2783,7 @@ Line28="conf,AutogenSteps"
|
||||
Line29="conf,AutogenGroupCourses"
|
||||
Line30="conf,FastLoad"
|
||||
Line31="conf,OnlyPreferredDifficulties"
|
||||
Line32="conf,HiddenSongs"
|
||||
|
||||
[ScreenOptionsGraphicsSound]
|
||||
Fallback="ScreenOptionsServiceChild"
|
||||
|
||||
@@ -3012,7 +3012,7 @@ Line20="conf,VisualDelaySeconds"
|
||||
Fallback="ScreenOptionsServiceChild"
|
||||
NextScreen="ScreenOptionsService"
|
||||
PrevScreen="ScreenOptionsService"
|
||||
LineNames="3,4,8,SI,SM,HN,11,13,14,15,16,28,29,30,31,ECPT"
|
||||
LineNames="3,4,8,SI,SM,HN,11,13,14,15,16,28,29,30,31,32,ECPT"
|
||||
#LineScore="lua,UserPrefScoringMode()"
|
||||
Line3="conf,TimingWindowScale"
|
||||
Line4="conf,LifeDifficulty"
|
||||
@@ -3029,6 +3029,7 @@ Line28="conf,AutogenSteps"
|
||||
Line29="conf,AutogenGroupCourses"
|
||||
Line30="conf,FastLoad"
|
||||
Line31="conf,FastLoadAdditionalSongs"
|
||||
Line32="conf,AllowSongDeletion"
|
||||
LineECPT="conf,EditClearPromptThreshold"
|
||||
|
||||
# unused options
|
||||
|
||||
@@ -1322,7 +1322,7 @@ LineFlashyCombo="lua,ThemePrefRow('FlashyCombo')"
|
||||
[ScreenOptionsGraphicsSound]
|
||||
|
||||
[ScreenOptionsAdvanced]
|
||||
LineNames="3,4,8,SI,SM,11,13,14,16,28,29,30,RollCombo,ECPT"
|
||||
LineNames="3,4,8,SI,SM,11,13,14,16,28,29,30,32,RollCombo,ECPT"
|
||||
LineRollCombo="lua,ThemePrefRow('ComboOnRolls')"
|
||||
|
||||
[ScreenAppearanceOptions]
|
||||
|
||||
@@ -255,6 +255,24 @@ MusicWheel::~MusicWheel()
|
||||
}
|
||||
}
|
||||
|
||||
void MusicWheel::ReloadSongList()
|
||||
{
|
||||
int songIdxToPreserve = m_iSelection;
|
||||
// Remove the song from any sorting caches:
|
||||
FOREACH_ENUM( SortOrder, so ) {
|
||||
m_WheelItemDatasStatus[so]=INVALID;
|
||||
}
|
||||
// rebuild the info associated with this sort order
|
||||
readyWheelItemsData(GAMESTATE->m_SortOrder);
|
||||
// re-open the section to refresh song counts, etc.
|
||||
SetOpenSection(m_sExpandedSectionName);
|
||||
// navigate to the song nearest to what was previously selected
|
||||
m_iSelection = songIdxToPreserve;
|
||||
RebuildWheelItems();
|
||||
// refresh the song preview
|
||||
SCREENMAN->PostMessageToTopScreen( SM_SongChanged, 0 );
|
||||
}
|
||||
|
||||
/* If a song or course is set in GAMESTATE and available, select it. Otherwise, choose the
|
||||
* first available song or course. Return true if an item was set, false if no items are
|
||||
* available. */
|
||||
|
||||
@@ -50,6 +50,8 @@ public:
|
||||
RString JumpToPrevGroup();
|
||||
const MusicWheelItemData *GetCurWheelItemData( int i ) { return (const MusicWheelItemData *) m_CurWheelItemData[i]; }
|
||||
|
||||
virtual void ReloadSongList();
|
||||
|
||||
// Lua
|
||||
void PushSelf( lua_State *L );
|
||||
|
||||
|
||||
@@ -289,6 +289,7 @@ PrefsManager::PrefsManager() :
|
||||
m_sMachineName ( "MachineName", "" ),
|
||||
m_sCoursesToShowRanking ( "CoursesToShowRanking", "" ),
|
||||
m_MuteActions("MuteActions", false),
|
||||
m_bAllowSongDeletion("AllowSongDeletion", false),
|
||||
|
||||
m_bQuirksMode ( "QuirksMode", false ),
|
||||
|
||||
|
||||
@@ -299,6 +299,7 @@ public:
|
||||
Preference<RString> m_sMachineName;
|
||||
Preference<RString> m_sCoursesToShowRanking;
|
||||
Preference<bool> m_MuteActions;
|
||||
Preference<bool> m_bAllowSongDeletion; // Allow the user to remove songs from their collection through UI / keyboard shortcut
|
||||
|
||||
/** @brief Enable some quirky behavior used by some older versions of StepMania. */
|
||||
Preference<bool> m_bQuirksMode;
|
||||
|
||||
@@ -464,6 +464,13 @@ bool RageFileManager::Remove( const RString &sPath_ )
|
||||
return bDeleted;
|
||||
}
|
||||
|
||||
bool RageFileManager::DeleteRecursive( const RString &sPath )
|
||||
{
|
||||
// On some OS's, non-empty directories cannot be deleted.
|
||||
// This is a work-around that can delete both files and non-empty directories
|
||||
return ::DeleteRecursive(sPath);
|
||||
}
|
||||
|
||||
void RageFileManager::CreateDir( const RString &sDir )
|
||||
{
|
||||
RString sTempFile = sDir + "newdir.temp.newdir";
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
bool bOnlyDirs= false, bool bReturnPathToo= false);
|
||||
bool Move( const RString &sOldPath, const RString &sNewPath );
|
||||
bool Remove( const RString &sPath );
|
||||
bool DeleteRecursive( const RString &sPath );
|
||||
void CreateDir( const RString &sDir );
|
||||
|
||||
enum FileType { TYPE_FILE, TYPE_DIR, TYPE_NONE };
|
||||
|
||||
@@ -786,12 +786,13 @@ static void InitializeConfOptions()
|
||||
ADD( ConfOption( "AllowMultipleHighScoreWithSameName", MovePref<bool>, "Off", "On" ) );
|
||||
ADD( ConfOption( "ComboContinuesBetweenSongs", MovePref<bool>, "Off", "On") );
|
||||
ADD( ConfOption( "Disqualification", MovePref<bool>, "Off","On" ) );
|
||||
ADD(ConfOption("HarshHotLifePenalty", MovePref<bool>, "Off", "On"));
|
||||
ADD( ConfOption( "HarshHotLifePenalty", MovePref<bool>, "Off", "On") );
|
||||
ADD( ConfOption( "FailOffForFirstStageEasy", MovePref<bool>, "Off","On" ) );
|
||||
ADD( ConfOption( "FailOffInBeginner", MovePref<bool>, "Off","On" ) );
|
||||
ADD( ConfOption( "FailOffInBeginner", MovePref<bool>, "Off","On" ) );
|
||||
ADD( ConfOption( "LockCourseDifficulties", MovePref<bool>, "Off", "On" ) );
|
||||
ADD( ConfOption( "PickExtraStage", MovePref<bool>, "Off","On" ) );
|
||||
ADD( ConfOption( "UseUnlockSystem", MovePref<bool>, "Off","On" ) );
|
||||
ADD( ConfOption( "AllowSongDeletion", MovePref<bool>, "Off","On" ) );
|
||||
|
||||
// Machine options
|
||||
ADD( ConfOption( "MenuTimer", MovePref<bool>, "Off","On" ) );
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include "CommonMetrics.h"
|
||||
#include "BannerCache.h"
|
||||
//#include "BackgroundCache.h"
|
||||
#include "ScreenPrompt.h"
|
||||
#include "Song.h"
|
||||
#include "InputEventPlus.h"
|
||||
#include "RageInput.h"
|
||||
#include "OptionsList.h"
|
||||
#include "RageFileManager.h"
|
||||
|
||||
static const char *SelectionStateNames[] = {
|
||||
"SelectingSong",
|
||||
@@ -50,6 +52,7 @@ AutoScreenMessage( SM_SongChanged );
|
||||
AutoScreenMessage( SM_SortOrderChanging );
|
||||
AutoScreenMessage( SM_SortOrderChanged );
|
||||
AutoScreenMessage( SM_BackFromPlayerOptions );
|
||||
AutoScreenMessage( SM_ConfirmDeleteSong );
|
||||
|
||||
static RString g_sCDTitlePath;
|
||||
static bool g_bWantFallbackCdTitle;
|
||||
@@ -398,6 +401,8 @@ void ScreenSelectMusic::Update( float fDeltaTime )
|
||||
|
||||
CheckBackgroundRequests( false );
|
||||
}
|
||||
|
||||
|
||||
bool ScreenSelectMusic::Input( const InputEventPlus &input )
|
||||
{
|
||||
// HACK: This screen eats mouse inputs if we don't check for them first.
|
||||
@@ -462,6 +467,18 @@ bool ScreenSelectMusic::Input( const InputEventPlus &input )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if( input.DeviceI.device == DEVICE_KEYBOARD && bHoldingCtrl && input.DeviceI.button == KEY_BACK && input.type == IET_FIRST_PRESS
|
||||
&& m_MusicWheel.IsSettled() )
|
||||
{
|
||||
// Keyboard shortcut to delete a song from disk (ctrl + backspace)
|
||||
Song* songToDelete = m_MusicWheel.GetSelectedSong();
|
||||
if ( songToDelete && PREFSMAN->m_bAllowSongDeletion.Get() )
|
||||
{
|
||||
m_pSongAwaitingDeletionConfirmation = songToDelete;
|
||||
ScreenPrompt::Prompt(SM_ConfirmDeleteSong, ssprintf("Permanently delete '%s' ( %s ) from disk?", songToDelete->m_sMainTitle.c_str(), songToDelete->GetSongDir().c_str()), PROMPT_YES_NO);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !input.GameI.IsValid() )
|
||||
@@ -1169,6 +1186,18 @@ void ScreenSelectMusic::HandleScreenMessage( const ScreenMessage SM )
|
||||
{
|
||||
CodeDetector::RefreshCacheItems(); // reset for other screens
|
||||
}
|
||||
else if( SM == SM_ConfirmDeleteSong )
|
||||
{
|
||||
if( ScreenPrompt::s_LastAnswer == ANSWER_YES )
|
||||
{
|
||||
OnConfirmSongDeletion();
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to resume the song preview that was automatically paused
|
||||
m_MusicWheel.ChangeMusic(0);
|
||||
}
|
||||
}
|
||||
|
||||
ScreenWithMenuElements::HandleScreenMessage( SM );
|
||||
}
|
||||
@@ -1907,6 +1936,34 @@ void ScreenSelectMusic::OpenOptionsList(PlayerNumber pn)
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSelectMusic::OnConfirmSongDeletion()
|
||||
{
|
||||
Song* deletedSong = m_pSongAwaitingDeletionConfirmation;
|
||||
if ( !deletedSong )
|
||||
{
|
||||
LOG->Warn("Attempted to delete a null song (ScreenSelectMusic::OnConfirmSongDeletion)");
|
||||
return;
|
||||
}
|
||||
// ensure Stepmania is configured to allow song deletion
|
||||
if ( !PREFSMAN->m_bAllowSongDeletion.Get() )
|
||||
{
|
||||
LOG->Warn("Attemped to delete a song but AllowSongDeletion was set to false (ScreenSelectMusic::OnConfirmSongDeletion)");
|
||||
return;
|
||||
}
|
||||
|
||||
RString deleteDir = deletedSong->GetSongDir();
|
||||
// flush the deleted song from any caches
|
||||
SONGMAN->UnlistSong(deletedSong);
|
||||
// refresh the song list
|
||||
m_MusicWheel.ReloadSongList();
|
||||
LOG->Trace("Deleting song: '%s'\n", deleteDir.c_str());
|
||||
// delete the song directory from disk
|
||||
FILEMAN->DeleteRecursive(deleteDir);
|
||||
|
||||
m_pSongAwaitingDeletionConfirmation = NULL;
|
||||
}
|
||||
|
||||
|
||||
// lua start
|
||||
#include "LuaBinding.h"
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
MusicWheel *GetMusicWheel() { return &m_MusicWheel; }
|
||||
|
||||
void OpenOptionsList( PlayerNumber pn );
|
||||
void OnConfirmSongDeletion();
|
||||
|
||||
// Lua
|
||||
virtual void PushSelf( lua_State *L );
|
||||
@@ -153,6 +154,8 @@ protected:
|
||||
|
||||
BackgroundLoader m_BackgroundLoader;
|
||||
RageTexturePreloader m_TexturePreload;
|
||||
|
||||
Song* m_pSongAwaitingDeletionConfirmation;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+25
-3
@@ -423,16 +423,38 @@ void SongManager::FreeSongs()
|
||||
for( unsigned i=0; i<m_pSongs.size(); i++ )
|
||||
SAFE_DELETE( m_pSongs[i] );
|
||||
m_pSongs.clear();
|
||||
m_mapSongGroupIndex.clear();
|
||||
|
||||
// wait why is it cleared twice? -aj
|
||||
// also free the songs that have been deleted from disk
|
||||
for ( unsigned i=0; i<m_pDeletedSongs.size(); ++i )
|
||||
SAFE_DELETE( m_pDeletedSongs[i] );
|
||||
m_pDeletedSongs.clear();
|
||||
|
||||
m_mapSongGroupIndex.clear();
|
||||
m_sSongGroupBannerPaths.clear();
|
||||
//m_sSongGroupBackgroundPaths.clear(); // when in Rome... -aj
|
||||
|
||||
m_pPopularSongs.clear();
|
||||
m_pShuffledSongs.clear();
|
||||
}
|
||||
|
||||
void SongManager::UnlistSong(Song *song)
|
||||
{
|
||||
// cannot immediately free song data, as it is needed temporarily for smooth audio transitions, etc.
|
||||
// Instead, remove it from the m_pSongs list and store it in a special place where it can safely be deleted later.
|
||||
m_pDeletedSongs.push_back(song);
|
||||
|
||||
// remove all occurences of the song in each of our song vectors
|
||||
vector<Song*>* songVectors[3] = { &m_pSongs, &m_pPopularSongs, &m_pShuffledSongs };
|
||||
for (int songVecIdx=0; songVecIdx<3; ++songVecIdx) {
|
||||
vector<Song*>& v = *songVectors[songVecIdx];
|
||||
for (int i=0; i<v.size(); ++i) {
|
||||
if (v[i] == song) {
|
||||
v.erase(v.begin()+i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RString SongManager::GetSongGroupBannerPath( RString sSongGroup ) const
|
||||
{
|
||||
for( unsigned i = 0; i < m_sSongGroupNames.size(); ++i )
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
|
||||
void InitSongsFromDisk( LoadingWindow *ld );
|
||||
void FreeSongs();
|
||||
void UnlistSong(Song *song);
|
||||
void Cleanup();
|
||||
|
||||
void Invalidate( const Song *pStaleSong );
|
||||
@@ -179,6 +180,8 @@ protected:
|
||||
|
||||
/** @brief All of the songs that can be played. */
|
||||
vector<Song*> m_pSongs;
|
||||
/** @brief Hold pointers to all the songs that have been deleted from disk but must at least be kept temporarily alive for smooth audio transitions. */
|
||||
vector<Song*> m_pDeletedSongs;
|
||||
/** @brief The most popular songs ranked by number of plays. */
|
||||
vector<Song*> m_pPopularSongs;
|
||||
//vector<Song*> m_pRecentSongs; // songs recently played on the machine
|
||||
|
||||
@@ -56,6 +56,8 @@ public:
|
||||
WheelState GetWheelState() { return m_WheelState; }
|
||||
bool WheelIsLocked() { return (m_WheelState == STATE_LOCKED ? true : false); }
|
||||
void RebuildWheelItems( int dist = INT_MAX ); // INT_MAX = refresh all
|
||||
// Update the list of songs to match whatever songs are indexed by the song manager (SONGMAN)
|
||||
virtual void ReloadSongList() {}
|
||||
|
||||
virtual unsigned int GetNumItems() const { return m_CurWheelItemData.size(); }
|
||||
bool IsEmpty() { return m_bEmpty; }
|
||||
|
||||
Reference in New Issue
Block a user