2012-07-11 00:13:36 -05:00
#include "global.h"
#include "ScreenEditMenu.h"
#include "CommonMetrics.h"
#include "GameConstantsAndTypes.h"
#include "GameManager.h"
#include "GameSoundManager.h"
#include "GameState.h"
#include "LocalizedString.h"
#include "RageFile.h"
#include "RageFileManager.h"
#include "RageLog.h"
#include "RageUtil.h"
#include "ScreenManager.h"
#include "ScreenPrompt.h"
#include "ScreenTextEntry.h"
#include "Song.h"
#include "SongManager.h"
#include "SongUtil.h"
#include "Steps.h"
#include "ThemeManager.h"
static const RString TEMP_FILE_NAME = "--temp--" ;
#define EXPLANATION_TEXT( row ) THEME->GetString(m_sName,"Explanation"+EditMenuRowToString(row))
#define EDIT_MENU_TYPE THEME->GetMetric(m_sName,"EditMenuType")
AutoScreenMessage ( SM_RefreshSelector );
AutoScreenMessage ( SM_BackFromEditDescription );
REGISTER_SCREEN_CLASS ( ScreenEditMenu );
void ScreenEditMenu :: Init ()
{
// HACK: Disable any style set by the editor.
2014-12-07 01:53:17 -07:00
GAMESTATE -> SetCurrentStyle ( NULL , PLAYER_INVALID );
2012-07-11 00:13:36 -05:00
// Enable all players.
FOREACH_PlayerNumber ( pn )
GAMESTATE -> JoinPlayer ( pn );
2015-08-29 18:48:44 -06:00
// Edit mode DOES NOT WORK if the master player is not player 1. The same
// is true of various parts of this poorly designed screen. -Kyz
if ( GAMESTATE -> GetMasterPlayerNumber () != PLAYER_1 )
{
LOG -> Warn ( "Master player number was not player 1, forcing it to player 1 so that edit mode will work. If playing in edit mode doesn't work, this might be related." );
GAMESTATE -> SetMasterPlayerNumber ( PLAYER_1 );
}
2012-07-11 00:13:36 -05:00
ScreenWithMenuElements :: Init ();
m_Selector . SetName ( "EditMenu" );
m_Selector . Load ( EDIT_MENU_TYPE );
m_Selector . SetXY ( 0 , 0 );
this -> AddChild ( & m_Selector );
m_textExplanation . SetName ( "Explanation" );
m_textExplanation . LoadFromFont ( THEME -> GetPathF ( m_sName , "explanation" ) );
LOAD_ALL_COMMANDS_AND_SET_XY ( m_textExplanation );
RefreshExplanationText ();
this -> AddChild ( & m_textExplanation );
m_textNumStepsLoadedFromProfile . SetName ( "NumStepsLoadedFromProfile" );
m_textNumStepsLoadedFromProfile . LoadFromFont ( THEME -> GetPathF ( m_sName , "NumStepsLoadedFromProfile" ) );
LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND ( m_textNumStepsLoadedFromProfile );
RefreshNumStepsLoadedFromProfile ();
this -> AddChild ( & m_textNumStepsLoadedFromProfile );
2014-12-24 02:27:46 -07:00
if ( ! m_Selector . SafeToUse ())
{
m_NoSongsMessage . SetName ( "NoSongsMessage" );
m_NoSongsMessage . LoadFromFont ( THEME -> GetPathF ( m_sName , "NoSongsMessage" ));
LOAD_ALL_COMMANDS_AND_SET_XY_AND_ON_COMMAND ( m_NoSongsMessage );
AddChild ( & m_NoSongsMessage );
m_Selector . SetVisible ( false );
m_textExplanation . SetVisible ( false );
m_textNumStepsLoadedFromProfile . SetVisible ( false );
}
2012-07-11 00:13:36 -05:00
}
void ScreenEditMenu :: HandleScreenMessage ( const ScreenMessage SM )
{
if ( SM == SM_RefreshSelector )
{
m_Selector . RefreshAll ();
RefreshNumStepsLoadedFromProfile ();
}
else if ( SM == SM_Success && m_Selector . GetSelectedAction () == EditMenuAction_Delete )
{
LOG -> Trace ( "Delete successful; deleting steps from memory" );
Song * pSong = GAMESTATE -> m_pCurSong ;
Steps * pStepsToDelete = GAMESTATE -> m_pCurSteps [ PLAYER_1 ];
2015-02-26 14:51:54 -07:00
FOREACH_PlayerNumber ( pn )
{
GAMESTATE -> m_pCurSteps [ pn ]. Set ( NULL );
}
2012-07-11 00:13:36 -05:00
bool bSaveSong = ! pStepsToDelete -> WasLoadedFromProfile ();
pSong -> DeleteSteps ( pStepsToDelete );
SONGMAN -> Invalidate ( pSong );
/* Only save to the main .SM file if the steps we're deleting
* were loaded from it. */
if ( bSaveSong )
{
pSong -> Save ();
SCREENMAN -> ZeroNextUpdate ();
}
SCREENMAN -> SendMessageToTopScreen ( SM_RefreshSelector );
}
else if ( SM == SM_Failure && m_Selector . GetSelectedAction () == EditMenuAction_Delete )
{
LOG -> Trace ( "Delete failed; not deleting steps" );
}
else if ( SM == SM_BackFromEditDescription )
{
if ( ! ScreenTextEntry :: s_bCancelledLast )
{
SOUND -> StopMusic ();
StartTransitioningScreen ( SM_GoToNextScreen );
}
}
ScreenWithMenuElements :: HandleScreenMessage ( SM );
}
2013-01-12 22:48:38 -05:00
bool ScreenEditMenu :: MenuUp ( const InputEventPlus & )
2012-07-11 00:13:36 -05:00
{
if ( m_Selector . CanGoUp () )
{
m_Selector . Up ();
RefreshExplanationText ();
}
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
2013-01-12 22:48:38 -05:00
bool ScreenEditMenu :: MenuDown ( const InputEventPlus & )
2012-07-11 00:13:36 -05:00
{
if ( m_Selector . CanGoDown () )
{
m_Selector . Down ();
RefreshExplanationText ();
}
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
2013-01-12 22:48:38 -05:00
bool ScreenEditMenu :: MenuLeft ( const InputEventPlus & )
2012-07-11 00:13:36 -05:00
{
if ( m_Selector . CanGoLeft () )
{
m_Selector . Left ();
}
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
2013-01-12 22:48:38 -05:00
bool ScreenEditMenu :: MenuRight ( const InputEventPlus & )
2012-07-11 00:13:36 -05:00
{
if ( m_Selector . CanGoRight () )
{
m_Selector . Right ();
}
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
static RString GetCopyDescription ( const Steps * pSourceSteps )
{
RString s = pSourceSteps -> GetDescription ();
return s ;
}
static void SetCurrentStepsDescription ( const RString & s )
{
GAMESTATE -> m_pCurSteps [ 0 ] -> SetDescription ( s );
}
static void DeleteCurrentSteps ()
{
GAMESTATE -> m_pCurSong -> DeleteSteps ( GAMESTATE -> m_pCurSteps [ 0 ] );
GAMESTATE -> m_pCurSteps [ 0 ]. Set ( NULL );
}
static LocalizedString MISSING_MUSIC_FILE ( "ScreenEditMenu" , "This song is missing a music file and cannot be edited." );
static LocalizedString SONG_DIR_READ_ONLY ( "ScreenEditMenu" , "The song directory is read-only and cannot be edited." );
static LocalizedString DELETED_AUTOGEN_STEPS ( "ScreenEditMenu" , "These steps are produced by autogen. You do not need to delete them." );
static LocalizedString STEPS_WILL_BE_LOST ( "ScreenEditMenu" , "These steps will be lost permanently." );
static LocalizedString CONTINUE_WITH_DELETE ( "ScreenEditMenu" , "Continue with delete?" );
static LocalizedString ENTER_EDIT_DESCRIPTION ( "ScreenEditMenu" , "Enter a description for this edit." );
2014-12-24 02:27:46 -07:00
static LocalizedString INVALID_SELECTION ( "ScreenEditMenu" , "One of the selected things is invalid. Pick something valid instead." );
2012-12-27 00:00:28 -05:00
2013-01-12 22:48:38 -05:00
bool ScreenEditMenu :: MenuStart ( const InputEventPlus & )
2012-07-11 00:13:36 -05:00
{
if ( IsTransitioning () )
2013-01-12 22:48:38 -05:00
return false ;
2014-12-24 02:27:46 -07:00
if ( ! m_Selector . SafeToUse ())
{
return false ;
}
2012-07-11 00:13:36 -05:00
if ( m_Selector . CanGoDown () )
{
m_Selector . Down ();
RefreshExplanationText ();
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
Song * pSong = m_Selector . GetSelectedSong ();
StepsType st = m_Selector . GetSelectedStepsType ();
Difficulty dc = m_Selector . GetSelectedDifficulty ();
Steps * pSteps = m_Selector . GetSelectedSteps ();
// StepsType soureNT = m_Selector.GetSelectedSourceStepsType();
// Difficulty sourceDiff = m_Selector.GetSelectedSourceDifficulty();
Steps * pSourceSteps = m_Selector . GetSelectedSourceSteps ();
EditMenuAction action = m_Selector . GetSelectedAction ();
2014-12-24 02:27:46 -07:00
if ( st == StepsType_Invalid )
{
ScreenPrompt :: Prompt ( SM_None , INVALID_SELECTION );
return true ;
}
2012-07-11 00:13:36 -05:00
GAMESTATE -> m_pCurSong . Set ( pSong );
GAMESTATE -> m_pCurCourse . Set ( NULL );
2014-12-07 01:53:17 -07:00
GAMESTATE -> SetCurrentStyle ( GAMEMAN -> GetEditorStyleForStepsType ( st ), PLAYER_INVALID );
2012-07-11 00:13:36 -05:00
GAMESTATE -> m_pCurSteps [ PLAYER_1 ]. Set ( pSteps );
// handle error cases
if ( ! pSong -> HasMusic () )
{
ScreenPrompt :: Prompt ( SM_None , MISSING_MUSIC_FILE );
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
switch ( m_Selector . EDIT_MODE )
{
case EditMode_Full :
{
RString sDir = pSong -> GetSongDir ();
RString sTempFile = sDir + TEMP_FILE_NAME ;
RageFile file ;
if ( ! file . Open ( sTempFile , RageFile :: WRITE ) )
{
ScreenPrompt :: Prompt ( SM_None , SONG_DIR_READ_ONLY );
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
file . Close ();
FILEMAN -> Remove ( sTempFile );
break ;
}
default :
break ;
}
switch ( action )
{
case EditMenuAction_Delete :
{
2012-12-27 11:38:53 -05:00
ASSERT ( pSteps != NULL );
2012-07-11 00:13:36 -05:00
if ( pSteps -> IsAutogen () )
{
SCREENMAN -> PlayInvalidSound ();
SCREENMAN -> SystemMessage ( DELETED_AUTOGEN_STEPS . GetValue () );
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
}
default : break ;
}
// Do work
switch ( action )
{
case EditMenuAction_Edit :
case EditMenuAction_Practice :
break ;
case EditMenuAction_Delete :
2012-12-27 11:38:53 -05:00
ASSERT ( pSteps != NULL );
2012-07-11 00:13:36 -05:00
ScreenPrompt :: Prompt ( SM_None , STEPS_WILL_BE_LOST . GetValue () + " \n\n " + CONTINUE_WITH_DELETE . GetValue (),
PROMPT_YES_NO , ANSWER_NO );
break ;
2015-02-27 10:36:17 -07:00
case EditMenuAction_LoadAutosave :
if ( pSong )
{
FOREACH_PlayerNumber ( pn )
{
GAMESTATE -> m_pCurSteps [ pn ]. Set ( NULL );
}
pSong -> LoadAutosaveFile ();
SONGMAN -> Invalidate ( pSong );
SCREENMAN -> SendMessageToTopScreen ( SM_RefreshSelector );
}
break ;
2012-07-11 00:13:36 -05:00
case EditMenuAction_Create :
ASSERT ( ! pSteps );
{
pSteps = pSong -> CreateSteps ();
2012-12-27 16:59:35 -05:00
EditMode mode = m_Selector . EDIT_MODE ;
switch ( mode )
2012-07-11 00:13:36 -05:00
{
default :
2012-12-27 16:59:35 -05:00
FAIL_M ( ssprintf ( "Invalid EditMode: %i" , mode ));
2012-07-11 00:13:36 -05:00
case EditMode_Full :
break ;
case EditMode_Home :
pSteps -> SetLoadedFromProfile ( ProfileSlot_Machine );
break ;
case EditMode_Practice :
2012-12-27 16:59:35 -05:00
FAIL_M ( "Cannot create steps in EditMode_Practice" );
2012-07-11 00:13:36 -05:00
}
RString sEditName ;
if ( pSourceSteps )
{
pSteps -> CopyFrom ( pSourceSteps , st , pSong -> m_fMusicLengthSeconds );
sEditName = GetCopyDescription ( pSourceSteps );
}
else
{
pSteps -> CreateBlank ( st );
pSteps -> SetMeter ( 1 );
sEditName = "" ;
}
pSteps -> SetDifficulty ( dc ); // override difficulty with the user's choice
SongUtil :: MakeUniqueEditDescription ( pSong , st , sEditName );
pSteps -> SetDescription ( sEditName );
pSong -> AddSteps ( pSteps );
SCREENMAN -> PlayStartSound ();
GAMESTATE -> m_pCurSong . Set ( pSong );
GAMESTATE -> m_pCurSteps [ PLAYER_1 ]. Set ( pSteps );
GAMESTATE -> m_pCurCourse . Set ( NULL );
}
break ;
default :
2012-12-27 16:59:35 -05:00
FAIL_M ( ssprintf ( "Invalid edit menu action: %i" , action ));
2012-07-11 00:13:36 -05:00
}
// Go to the next screen.
switch ( action )
{
case EditMenuAction_Edit :
case EditMenuAction_Create :
case EditMenuAction_Practice :
{
// Prepare for ScreenEdit
2012-12-27 11:38:53 -05:00
ASSERT ( pSteps != NULL );
2012-07-11 00:13:36 -05:00
bool bPromptToNameSteps = ( action == EditMenuAction_Create && dc == Difficulty_Edit );
if ( bPromptToNameSteps )
{
ScreenTextEntry :: TextEntry (
SM_BackFromEditDescription ,
ENTER_EDIT_DESCRIPTION ,
GAMESTATE -> m_pCurSteps [ 0 ] -> GetDescription (),
MAX_STEPS_DESCRIPTION_LENGTH ,
SongUtil :: ValidateCurrentStepsDescription ,
SetCurrentStepsDescription ,
DeleteCurrentSteps );
}
else
{
SOUND -> StopMusic ();
SCREENMAN -> PlayStartSound ();
StartTransitioningScreen ( SM_GoToNextScreen );
}
}
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
case EditMenuAction_Delete :
2015-02-27 10:36:17 -07:00
case EditMenuAction_LoadAutosave :
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
default :
2012-12-27 16:59:35 -05:00
FAIL_M ( ssprintf ( "Invalid edit menu action: %i" , action ));
2012-07-11 00:13:36 -05:00
}
}
2013-01-12 22:48:38 -05:00
bool ScreenEditMenu :: MenuBack ( const InputEventPlus & input )
2012-07-11 00:13:36 -05:00
{
Cancel ( SM_GoToPrevScreen );
2013-01-12 22:48:38 -05:00
return true ;
2012-07-11 00:13:36 -05:00
}
void ScreenEditMenu :: RefreshExplanationText ()
{
m_textExplanation . SetText ( EXPLANATION_TEXT ( m_Selector . GetSelectedRow ()) );
m_textExplanation . StopTweening ();
ON_COMMAND ( m_textExplanation );
}
void ScreenEditMenu :: RefreshNumStepsLoadedFromProfile ()
{
RString s = ssprintf ( "edits used: %d" , SONGMAN -> GetNumStepsLoadedFromProfile () );
m_textNumStepsLoadedFromProfile . SetText ( s );
}
/*
* (c) 2002-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/