Merge pull request #526 from Wallacoloo/master

Add ability to delete songs from the collection through a keyboard shortcut
This commit is contained in:
Colby Klein
2015-03-26 23:58:16 -07:00
16 changed files with 130 additions and 8 deletions
+2
View File
@@ -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
+2 -1
View File
@@ -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"
+2 -1
View File
@@ -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
+1 -1
View File
@@ -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]
+18
View File
@@ -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. */
+2
View File
@@ -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 );
+1
View File
@@ -289,6 +289,7 @@ PrefsManager::PrefsManager() :
m_sMachineName ( "MachineName", "" ),
m_sCoursesToShowRanking ( "CoursesToShowRanking", "" ),
m_MuteActions("MuteActions", false),
m_bAllowSongDeletion("AllowSongDeletion", false),
m_bQuirksMode ( "QuirksMode", false ),
+1
View File
@@ -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;
+7
View File
@@ -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";
+1
View File
@@ -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 };
+3 -2
View File
@@ -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" ) );
+57
View File
@@ -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"
+3
View File
@@ -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
View File
@@ -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 )
+3
View File
@@ -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
+2
View File
@@ -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; }