diff --git a/stepmania/src/OptionRowHandler.cpp b/stepmania/src/OptionRowHandler.cpp index 8ebd844b81..e7c7f07f74 100644 --- a/stepmania/src/OptionRowHandler.cpp +++ b/stepmania/src/OptionRowHandler.cpp @@ -18,7 +18,6 @@ #include "Foreach.h" #define ENTRY(s) THEME->GetMetric ("ScreenOptionsMaster",s) -#define ENTRY_NAME(s) THEME->GetMetric ("OptionNames", s) #define ENTRY_MODE(s,i) THEME->GetMetric ("ScreenOptionsMaster",ssprintf("%s,%i",(s).c_str(),(i+1))) #define ENTRY_DEFAULT(s) THEME->GetMetric ("ScreenOptionsMaster",(s) + "Default") @@ -55,9 +54,143 @@ public: Default.Init(); m_bUseModNameForIcon = false; } - virtual void Load( OptionRowDefinition &defOut, CString sParam ); - virtual void ImportOption( const OptionRowDefinition &def, PlayerNumber pn, vector &vbSelectedOut ) const; - virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const; + virtual void Load( OptionRowDefinition &defOut, CString sParam ) + { + ASSERT( sParam.size() ); + + if( sParam.CompareNoCase("NoteSkins")==0 ) { FillNoteSkins( defOut, sParam ); return; } + else if( sParam.CompareNoCase("Steps")==0 ) { FillSteps( defOut, sParam ); return; } + else if( sParam.CompareNoCase("EditsAndNull")==0 ) { FillEditsAndNull( defOut, sParam ); return; } + else if( sParam.CompareNoCase("Characters")==0 ) { FillCharacters( defOut, sParam ); return; } + else if( sParam.CompareNoCase("Styles")==0 ) { FillStyles( defOut, sParam ); return; } + else if( sParam.CompareNoCase("Groups")==0 ) { FillGroups( defOut, sParam ); return; } + else if( sParam.CompareNoCase("Difficulties")==0 ) { FillDifficulties( defOut, sParam ); return; } + else if( sParam.CompareNoCase("SongsInCurrentSongGroup")==0 ) { FillSongsInCurrentSongGroup( defOut, sParam ); return; } + + Init(); + defOut.Init(); + + m_bUseModNameForIcon = true; + + defOut.name = sParam; + + Default.Load( -1, ParseCommands(ENTRY_DEFAULT(sParam)) ); + + /* Parse the basic configuration metric. */ + Commands cmds = ParseCommands( ENTRY(sParam) ); + if( cmds.v.size() < 1 ) + RageException::Throw( "Parse error in OptionRowHandlerUtilEntries::ListName%s", sParam.c_str() ); + + defOut.bOneChoiceForAllPlayers = false; + const int NumCols = atoi( cmds.v[0].m_vsArgs[0] ); + for( unsigned i=1; i= 0 && pn < NUM_PLAYERS ); + defOut.m_vEnabledForPlayers.insert( pn ); + } + } + else if( sName == "exportonchange" ) defOut.m_bExportOnChange = true; + else RageException::Throw( "Unkown row flag \"%s\"", sName.c_str() ); + } + + for( int col = 0; col < NumCols; ++col ) + { + GameCommand mc; + mc.Load( 0, ParseCommands(ENTRY_MODE(sParam, col)) ); + if( mc.m_sName == "" ) + RageException::Throw( "List \"%s\", col %i has no name", sParam.c_str(), col ); + + if( !mc.IsPlayable() ) + continue; + + ListEntries.push_back( mc ); + + CString sName = mc.m_sName; + CString sChoice = ENTRY_NAME(mc.m_sName); + defOut.choices.push_back( sChoice ); + } + } + void ImportOption( const OptionRowDefinition &def, PlayerNumber pn, vector &vbSelectedOut ) const + { + int FallbackOption = -1; + bool UseFallbackOption = true; + + for( unsigned e = 0; e < ListEntries.size(); ++e ) + { + const GameCommand &mc = ListEntries[e]; + + vbSelectedOut[e] = false; + + if( mc.IsZero() ) + { + /* The entry has no effect. This is usually a default "none of the + * above" entry. It will always return true for DescribesCurrentMode(). + * It's only the selected choice if nothing else matches. */ + if( def.selectType != SELECT_MULTIPLE ) + FallbackOption = e; + continue; + } + + if( def.bOneChoiceForAllPlayers ) + { + if( mc.DescribesCurrentModeForAllPlayers() ) + { + UseFallbackOption = false; + if( def.selectType != SELECT_MULTIPLE ) + SelectExactlyOne( e, vbSelectedOut ); + else + vbSelectedOut[e] = true; + } + } + else + { + if( mc.DescribesCurrentMode( pn) ) + { + UseFallbackOption = false; + if( def.selectType != SELECT_MULTIPLE ) + SelectExactlyOne( e, vbSelectedOut ); + else + vbSelectedOut[e] = true; + } + } + } + + if( def.selectType == SELECT_ONE && + UseFallbackOption && + FallbackOption != -1 ) + { + SelectExactlyOne( FallbackOption, vbSelectedOut ); + } + } + + int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const + { + Default.Apply( pn ); + for( unsigned i=0; iGetNoteSkinNames( arraySkinNames ); + for( unsigned skin=0; skinm_bEditing ) + { + defOut.choices.push_back( "" ); + ListEntries.push_back( GameCommand() ); + } + else if( GAMESTATE->IsCourseMode() ) // playing a course + { + defOut.bOneChoiceForAllPlayers = PREFSMAN->m_bLockCourseDifficulties; + + vector vTrails; + GAMESTATE->m_pCurCourse->GetTrails( vTrails, GAMESTATE->GetCurrentStyle()->m_StepsType ); + for( unsigned i=0; im_CourseDifficulty ); + defOut.choices.push_back( s ); + GameCommand mc; + mc.m_pTrail = pTrail; + ListEntries.push_back( mc ); + } + } + else // !GAMESTATE->IsCourseMode(), playing a song + { + vector vSteps; + GAMESTATE->m_pCurSong->GetSteps( vSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); + StepsUtil::SortNotesArrayByDifficulty( vSteps ); + for( unsigned i=0; iGetDifficulty() == DIFFICULTY_EDIT ) + s = pSteps->GetDescription(); + else + s = DifficultyToThemedString( pSteps->GetDifficulty() ); + s += ssprintf( " (%d)", pSteps->GetMeter() ); + + defOut.choices.push_back( s ); + GameCommand mc; + mc.m_pSteps = pSteps; + mc.m_dc = pSteps->GetDifficulty(); + ListEntries.push_back( mc ); + } + } + } + + void FillEditsAndNull( OptionRowDefinition &defOut, CString sParam ) + { + Init(); + defOut.Init(); + + ASSERT( sParam.size() ); + m_sName = sParam; + + defOut.name = "EditsAndNull"; + defOut.bOneChoiceForAllPlayers = true; + defOut.layoutType = LAYOUT_SHOW_ONE_IN_ROW; + defOut.m_bExportOnChange = true; + m_vsReloadRowMessages.push_back( MessageToString(MESSAGE_CURRENT_SONG_CHANGED) ); + + if( GAMESTATE->m_pCurSong != NULL ) + { + vector vSteps; + GAMESTATE->m_pCurSong->GetSteps( vSteps, GAMESTATE->m_stEdit, DIFFICULTY_EDIT ); + StepsUtil::SortNotesArrayByDifficulty( vSteps ); + FOREACH_CONST( Steps*, vSteps, p ) + { + CString s = (*p)->GetDescription(); + s += ssprintf( " (%d)", (*p)->GetMeter() ); + + defOut.choices.push_back( s ); + GameCommand mc; + mc.m_pSteps = *p; + ListEntries.push_back( mc ); + } + } + + // Add NULL entry for a new edit + { + defOut.choices.push_back( ENTRY_NAME("NewEdit") ); + GameCommand mc; + ListEntries.push_back( mc ); + } + } + + void FillCharacters( OptionRowDefinition &defOut, CString sParam ) + { + Init(); + defOut.Init(); + + ASSERT( sParam.size() ); + m_sName = sParam; + + defOut.bOneChoiceForAllPlayers = false; + defOut.name = "Characters"; + Default.m_pCharacter = GAMESTATE->GetDefaultCharacter(); + + { + defOut.choices.push_back( ENTRY_NAME("Off") ); + GameCommand mc; + mc.m_pCharacter = NULL; + ListEntries.push_back( mc ); + } + + vector apCharacters; + GAMESTATE->GetCharacters( apCharacters ); + for( unsigned i=0; im_sName; + s.MakeUpper(); + + defOut.choices.push_back( s ); + GameCommand mc; + mc.m_pCharacter = pCharacter; + ListEntries.push_back( mc ); + } + } + + void FillStyles( OptionRowDefinition &defOut, CString sParam ) + { + Init(); + defOut.Init(); + + ASSERT( sParam.size() ); + m_sName = sParam; + + defOut.bOneChoiceForAllPlayers = true; + defOut.name = "Style"; + defOut.bOneChoiceForAllPlayers = true; + + vector vStyles; + GAMEMAN->GetStylesForGame( GAMESTATE->m_pCurGame, vStyles ); + ASSERT( vStyles.size() ); + FOREACH_CONST( const Style*, vStyles, s ) + { + defOut.choices.push_back( GAMEMAN->StyleToThemedString(*s) ); + GameCommand mc; + mc.m_pStyle = *s; + ListEntries.push_back( mc ); + } + + Default.m_pStyle = vStyles[0]; + } + + void FillGroups( OptionRowDefinition &defOut, CString sParam ) + { + Init(); + defOut.Init(); + + ASSERT( sParam.size() ); + m_sName = sParam; + + defOut.bOneChoiceForAllPlayers = true; + defOut.name = "Group"; + Default.m_sSongGroup = GROUP_ALL_MUSIC; + + vector vGroups; + SONGMAN->GetGroupNames( vGroups ); + ASSERT( vGroups.size() ); + + { + defOut.choices.push_back( ENTRY_NAME("AllGroups") ); + GameCommand mc; + mc.m_sSongGroup = GROUP_ALL_MUSIC; + ListEntries.push_back( mc ); + } + + FOREACH_CONST( CString, vGroups, g ) + { + defOut.choices.push_back( *g ); + GameCommand mc; + mc.m_sSongGroup = *g; + ListEntries.push_back( mc ); + } + } + + void FillDifficulties( OptionRowDefinition &defOut, CString sParam ) + { + Init(); + defOut.Init(); + + ASSERT( sParam.size() ); + m_sName = sParam; + + set vDifficulties; + GAMESTATE->GetDifficultiesToShow( vDifficulties ); + + defOut.bOneChoiceForAllPlayers = true; + defOut.name = "Difficulty"; + Default.m_dc = DIFFICULTY_INVALID; + + { + defOut.choices.push_back( ENTRY_NAME("AllDifficulties") ); + GameCommand mc; + mc.m_dc = DIFFICULTY_INVALID; + ListEntries.push_back( mc ); + } + + FOREACHS_CONST( Difficulty, vDifficulties, d ) + { + CString s = DifficultyToThemedString( *d ); + + defOut.choices.push_back( s ); + GameCommand mc; + mc.m_dc = *d; + ListEntries.push_back( mc ); + } + } + + void FillSongsInCurrentSongGroup( OptionRowDefinition &defOut, CString sParam ) + { + Init(); + defOut.Init(); + + ASSERT( sParam.size() ); + m_sName = sParam; + + vector vpSongs; + SONGMAN->GetSongs( vpSongs, GAMESTATE->m_sPreferredSongGroup ); + + if( GAMESTATE->m_pCurSong == NULL ) + GAMESTATE->m_pCurSong.Set( vpSongs[0] ); + + defOut.name = "SongsInCurrentSongGroup"; + defOut.bOneChoiceForAllPlayers = true; + defOut.layoutType = LAYOUT_SHOW_ONE_IN_ROW; + defOut.m_bExportOnChange = true; + + FOREACH_CONST( Song*, vpSongs, p ) + { + defOut.choices.push_back( (*p)->GetFullTranslitTitle() ); + GameCommand mc; + mc.m_pSong = *p; + ListEntries.push_back( mc ); + } + } }; class OptionRowHandlerLua : public OptionRowHandler @@ -102,9 +501,238 @@ public: delete m_pLuaTable; m_pLuaTable = new LuaExpression; } - virtual void Load( OptionRowDefinition &defOut, CString sLuaFunction ); - virtual void ImportOption( const OptionRowDefinition &def, PlayerNumber pn, vector &vbSelectedOut ) const; - virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const; + virtual void Load( OptionRowDefinition &defOut, CString sLuaFunction ) + { + ASSERT( sLuaFunction.size() ); + + Init(); + defOut.Init(); + + m_sName = sLuaFunction; + // m_bUseModNameForIcon = true; + + /* Run the Lua expression. It should return a table. */ + m_pLuaTable->SetFromExpression( sLuaFunction ); + + if( m_pLuaTable->GetLuaType() != LUA_TTABLE ) + RageException::Throw( "Result of \"%s\" is not a table", sLuaFunction.c_str() ); + + { + m_pLuaTable->PushSelf( LUA->L ); + + lua_pushstring( LUA->L, "Name" ); + lua_gettable( LUA->L, -2 ); + const char *pStr = lua_tostring( LUA->L, -1 ); + if( pStr == NULL ) + RageException::Throw( "\"%s\" \"Name\" entry is not a string", sLuaFunction.c_str() ); + defOut.name = pStr; + lua_pop( LUA->L, 1 ); + + + lua_pushstring( LUA->L, "OneChoiceForAllPlayers" ); + lua_gettable( LUA->L, -2 ); + defOut.bOneChoiceForAllPlayers = !!lua_toboolean( LUA->L, -1 ); + lua_pop( LUA->L, 1 ); + + + lua_pushstring( LUA->L, "LayoutType" ); + lua_gettable( LUA->L, -2 ); + pStr = lua_tostring( LUA->L, -1 ); + if( pStr == NULL ) + RageException::Throw( "\"%s\" \"LayoutType\" entry is not a string", sLuaFunction.c_str() ); + defOut.layoutType = StringToLayoutType( pStr ); + ASSERT( defOut.layoutType != LAYOUT_INVALID ); + lua_pop( LUA->L, 1 ); + + + lua_pushstring( LUA->L, "SelectType" ); + lua_gettable( LUA->L, -2 ); + pStr = lua_tostring( LUA->L, -1 ); + if( pStr == NULL ) + RageException::Throw( "\"%s\" \"SelectType\" entry is not a string", sLuaFunction.c_str() ); + defOut.selectType = StringToSelectType( pStr ); + ASSERT( defOut.selectType != SELECT_INVALID ); + lua_pop( LUA->L, 1 ); + + + /* Iterate over the "Choices" table. */ + lua_pushstring( LUA->L, "Choices" ); + lua_gettable( LUA->L, -2 ); + if( !lua_istable( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"Choices\" is not a table", sLuaFunction.c_str() ); + + lua_pushnil( LUA->L ); + while( lua_next(LUA->L, -2) != 0 ) + { + /* `key' is at index -2 and `value' at index -1 */ + const char *pValue = lua_tostring( LUA->L, -1 ); + if( pValue == NULL ) + RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); + LOG->Trace( "'%s'", pValue); + + defOut.choices.push_back( pValue ); + + lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ + } + + lua_pop( LUA->L, 1 ); /* pop choices table */ + + + /* Iterate over the "EnabledForPlayers" table. */ + lua_pushstring( LUA->L, "EnabledForPlayers" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isnil( LUA->L, -1 ) ) + { + if( !lua_istable( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"EnabledForPlayers\" is not a table", sLuaFunction.c_str() ); + + defOut.m_vEnabledForPlayers.clear(); // and fill in with supplied PlayerNumbers below + + lua_pushnil( LUA->L ); + while( lua_next(LUA->L, -2) != 0 ) + { + /* `key' is at index -2 and `value' at index -1 */ + PlayerNumber pn = (PlayerNumber)luaL_checkint( LUA->L, -1 ); + + defOut.m_vEnabledForPlayers.insert( pn ); + + lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ + } + } + lua_pop( LUA->L, 1 ); /* pop EnabledForPlayers table */ + + + /* Look for "ExportOnChange" value. */ + lua_pushstring( LUA->L, "ExportOnChange" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isnil( LUA->L, -1 ) ) + { + defOut.m_bExportOnChange = !!MyLua_checkboolean( LUA->L, -1 ); + } + lua_pop( LUA->L, 1 ); /* pop ExportOnChange value */ + + + /* Iterate over the "ReloadRowMessages" table. */ + lua_pushstring( LUA->L, "ReloadRowMessages" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isnil( LUA->L, -1 ) ) + { + if( !lua_istable( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"ReloadRowMessages\" is not a table", sLuaFunction.c_str() ); + + m_vsReloadRowMessages.clear(); // and fill in with supplied PlayerNumbers below + + lua_pushnil( LUA->L ); + while( lua_next(LUA->L, -2) != 0 ) + { + /* `key' is at index -2 and `value' at index -1 */ + const char *pValue = lua_tostring( LUA->L, -1 ); + if( pValue == NULL ) + RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); + LOG->Trace( "'%s'", pValue); + + m_vsReloadRowMessages.push_back( pValue ); + + lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ + } + } + lua_pop( LUA->L, 1 ); /* pop ReloadRowMessages table */ + + + lua_pop( LUA->L, 1 ); /* pop main table */ + ASSERT( lua_gettop(LUA->L) == 0 ); + } + } + virtual void ImportOption( const OptionRowDefinition &def, PlayerNumber pn, vector &vbSelectedOut ) const + { + ASSERT( lua_gettop(LUA->L) == 0 ); + + /* Evaluate the LoadSelections(self,array,pn) function, where array is a table + * representing vbSelectedOut. */ + + /* All selections default to false. */ + for( unsigned i = 0; i < vbSelectedOut.size(); ++i ) + vbSelectedOut[i] = false; + + /* Create the vbSelectedOut table. */ + LUA->CreateTableFromArrayB( vbSelectedOut ); + ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ + + /* Get the function to call from m_LuaTable. */ + m_pLuaTable->PushSelf( LUA->L ); + ASSERT( lua_istable( LUA->L, -1 ) ); + + lua_pushstring( LUA->L, "LoadSelections" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isfunction( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"LoadSelections\" entry is not a function", def.name.c_str() ); + + /* Argument 1 (self): */ + m_pLuaTable->PushSelf( LUA->L ); + + /* Argument 2 (vbSelectedOut): */ + lua_pushvalue( LUA->L, 1 ); + + /* Argument 3 (pn): */ + LUA->PushStack( (int) pn ); + + ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ + + lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results + ASSERT( lua_gettop(LUA->L) == 2 ); + + lua_pop( LUA->L, 1 ); /* pop option table */ + + LUA->ReadArrayFromTableB( vbSelectedOut ); + + lua_pop( LUA->L, 1 ); /* pop vbSelectedOut table */ + + ASSERT( lua_gettop(LUA->L) == 0 ); + } + virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const + { + ASSERT( lua_gettop(LUA->L) == 0 ); + + /* Evaluate SaveSelections(self,array,pn) function, where array is a table + * representing vbSelectedOut. */ + + vector vbSelectedCopy = vbSelected; + + /* Create the vbSelectedOut table. */ + LUA->CreateTableFromArrayB( vbSelectedCopy ); + ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ + + /* Get the function to call. */ + m_pLuaTable->PushSelf( LUA->L ); + ASSERT( lua_istable( LUA->L, -1 ) ); + + lua_pushstring( LUA->L, "SaveSelections" ); + lua_gettable( LUA->L, -2 ); + if( !lua_isfunction( LUA->L, -1 ) ) + RageException::Throw( "\"%s\" \"SaveSelections\" entry is not a function", def.name.c_str() ); + + /* Argument 1 (self): */ + m_pLuaTable->PushSelf( LUA->L ); + + /* Argument 2 (vbSelectedOut): */ + lua_pushvalue( LUA->L, 1 ); + + /* Argument 3 (pn): */ + LUA->PushStack( (int) pn ); + + ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ + + lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results + ASSERT( lua_gettop(LUA->L) == 2 ); + + lua_pop( LUA->L, 1 ); /* pop option table */ + lua_pop( LUA->L, 1 ); /* pop vbSelected table */ + + ASSERT( lua_gettop(LUA->L) == 0 ); + + // XXX: allow specifying the mask + return 0; + } }; class OptionRowHandlerConfig : public OptionRowHandler @@ -118,15 +746,57 @@ public: OptionRowHandler::Init(); opt = NULL; } - virtual void Load( OptionRowDefinition &defOut, CString sParam ); - virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const; - virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const; + virtual void Load( OptionRowDefinition &defOut, CString sParam ) + { + ASSERT( sParam.size() ); + + Init(); + defOut.Init(); + + /* Configuration values are never per-player. */ + defOut.bOneChoiceForAllPlayers = true; + + ConfOption *pConfOption = ConfOption::Find( sParam ); + if( pConfOption == NULL ) + RageException::Throw( "Invalid Conf type \"%s\"", sParam.c_str() ); + + pConfOption->UpdateAvailableOptions(); + + opt = pConfOption; + opt->MakeOptionsList( defOut.choices ); + + defOut.name = opt->name; + } + virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const + { + int iSelection = opt->Get(); + SelectExactlyOne( iSelection, vbSelectedOut ); + } + virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const + { + int sel = GetOneSelection(vbSelected); + + /* Get the original choice. */ + int Original = opt->Get(); + + /* Apply. */ + opt->Put( sel ); + + /* Get the new choice. */ + int New = opt->Get(); + + /* If it didn't change, don't return any side-effects. */ + if( Original == New ) + return 0; + + return opt->GetEffects(); + } }; class OptionRowHandlerStepsType : public OptionRowHandler { public: - StepsType *m_pstToFill; + BroadcastOnChange *m_pstToFill; vector m_vStepsTypesToShow; OptionRowHandlerStepsType::OptionRowHandlerStepsType() { Init(); } @@ -139,6 +809,8 @@ public: virtual void Load( OptionRowDefinition &defOut, CString sParam ) { + ASSERT( sParam.size() ); + Init(); defOut.Init(); @@ -179,7 +851,7 @@ public: } if( *m_pstToFill == STEPS_TYPE_INVALID ) - *m_pstToFill = m_vStepsTypesToShow[0]; + m_pstToFill->Set( m_vStepsTypesToShow[0] ); } virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const { @@ -199,7 +871,7 @@ public: virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const { int index = GetOneSelection( vbSelected ); - *m_pstToFill = m_vStepsTypesToShow[index]; + m_pstToFill->Set( m_vStepsTypesToShow[index] ); return 0; } }; @@ -208,7 +880,7 @@ public: class OptionRowHandlerSteps : public OptionRowHandler { public: - Steps **m_ppStepsToFill; + BroadcastOnChangePtr *m_ppStepsToFill; vector m_vSteps; OptionRowHandlerSteps::OptionRowHandlerSteps() { Init(); } @@ -221,11 +893,13 @@ public: virtual void Load( OptionRowDefinition &defOut, CString sParam ) { + ASSERT( sParam.size() ); + Init(); defOut.Init(); if( sParam == "EditSourceSteps" ) - m_ppStepsToFill = &GAMESTATE->m_pStepsEditSource; + m_ppStepsToFill = &GAMESTATE->m_pEditSourceSteps; else RageException::Throw( "invalid StepsType param \"%s\"", sParam.c_str() ); @@ -234,27 +908,30 @@ public: defOut.bOneChoiceForAllPlayers = true; defOut.layoutType = LAYOUT_SHOW_ONE_IN_ROW; defOut.m_bExportOnChange = true; - m_vsReloadRowMessages.push_back( MessageToString(MESSAGE_CURRENT_SONG_CHANGED) ); + m_vsReloadRowMessages.push_back( MessageToString(MESSAGE_EDIT_SOURCE_STEPS_TYPE_CHANGED) ); - GAMESTATE->m_pCurSong->GetSteps( m_vSteps, GAMESTATE->m_stEditSource ); - StepsUtil::SortNotesArrayByDifficulty( m_vSteps ); - for( unsigned i=0; im_pCurSong ) { - Steps* pSteps = m_vSteps[i]; + GAMESTATE->m_pCurSong->GetSteps( m_vSteps, GAMESTATE->m_stEditSource ); + StepsUtil::SortNotesArrayByDifficulty( m_vSteps ); + for( unsigned i=0; iGetDifficulty() == DIFFICULTY_EDIT ) - s = pSteps->GetDescription(); - else - s = DifficultyToThemedString( pSteps->GetDifficulty() ); - s += ssprintf( " (%d)", pSteps->GetMeter() ); + CString s; + if( pSteps->GetDifficulty() == DIFFICULTY_EDIT ) + s = pSteps->GetDescription(); + else + s = DifficultyToThemedString( pSteps->GetDifficulty() ); + s += ssprintf( " (%d)", pSteps->GetMeter() ); - defOut.choices.push_back( s ); + defOut.choices.push_back( s ); + } } } virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const { - vector::const_iterator iter = find( m_vSteps.begin(), m_vSteps.end(), *m_ppStepsToFill ); + vector::const_iterator iter = find( m_vSteps.begin(), m_vSteps.end(), m_ppStepsToFill->Get() ); if( iter != m_vSteps.end() ) { unsigned i = iter - m_vSteps.begin(); @@ -266,691 +943,84 @@ public: virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const { int index = GetOneSelection( vbSelected ); - *m_ppStepsToFill = m_vSteps[index]; + m_ppStepsToFill->Set( m_vSteps[index] ); return 0; } }; - -void OptionRowHandlerList::ImportOption( const OptionRowDefinition &def, PlayerNumber pn, vector &vbSelectedOut ) const +class OptionRowHandlerEditMenuAction : public OptionRowHandler { - int FallbackOption = -1; - bool UseFallbackOption = true; +public: + vector m_vEditMenuActions; - for( unsigned e = 0; e < ListEntries.size(); ++e ) + OptionRowHandlerEditMenuAction::OptionRowHandlerEditMenuAction() { Init(); } + void Init() { - const GameCommand &mc = ListEntries[e]; - - vbSelectedOut[e] = false; - - if( mc.IsZero() ) - { - /* The entry has no effect. This is usually a default "none of the - * above" entry. It will always return true for DescribesCurrentMode(). - * It's only the selected choice if nothing else matches. */ - if( def.selectType != SELECT_MULTIPLE ) - FallbackOption = e; - continue; - } - - if( def.bOneChoiceForAllPlayers ) - { - if( mc.DescribesCurrentModeForAllPlayers() ) - { - UseFallbackOption = false; - if( def.selectType != SELECT_MULTIPLE ) - SelectExactlyOne( e, vbSelectedOut ); - else - vbSelectedOut[e] = true; - } - } - else - { - if( mc.DescribesCurrentMode( pn) ) - { - UseFallbackOption = false; - if( def.selectType != SELECT_MULTIPLE ) - SelectExactlyOne( e, vbSelectedOut ); - else - vbSelectedOut[e] = true; - } - } + OptionRowHandler::Init(); + m_vEditMenuActions.clear(); } - if( def.selectType == SELECT_ONE && - UseFallbackOption && - FallbackOption != -1 ) + virtual void Load( OptionRowDefinition &defOut, CString sParam ) { - SelectExactlyOne( FallbackOption, vbSelectedOut ); + ASSERT( sParam.size() ); + + Init(); + defOut.Init(); + + m_sName = sParam; + defOut.name = sParam; + defOut.bOneChoiceForAllPlayers = true; + defOut.layoutType = LAYOUT_SHOW_ONE_IN_ROW; + m_vsReloadRowMessages.push_back( MessageToString(MESSAGE_CURRENT_STEPS_P1_CHANGED) ); + m_vsReloadRowMessages.push_back( MessageToString(MESSAGE_EDIT_SOURCE_STEPS_CHANGED) ); + + bool bHasSteps = GAMESTATE->m_pCurSteps[0] != NULL; + FOREACH_EditMenuAction( ema ) + { + switch( ema ) + { + case EDIT_MENU_ACTION_EDIT: + case EDIT_MENU_ACTION_DELETE: + if( !bHasSteps ) + continue; // skip + break; + case EDIT_MENU_ACTION_COPY: + case EDIT_MENU_ACTION_AUTOGEN: + case EDIT_MENU_ACTION_BLANK: + if( bHasSteps ) + continue; // skip + break; + default: + ASSERT(0); + } + + m_vEditMenuActions.push_back( ema ); + CString s = EditMenuActionToThemedString( ema ); + defOut.choices.push_back( s ); + } } -} - -int OptionRowHandlerList::ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const -{ - Default.Apply( pn ); - for( unsigned i=0; i &vbSelectedOut ) const -{ - ASSERT( lua_gettop(LUA->L) == 0 ); - - /* Evaluate the LoadSelections(self,array,pn) function, where array is a table - * representing vbSelectedOut. */ - - /* All selections default to false. */ - for( unsigned i = 0; i < vbSelectedOut.size(); ++i ) - vbSelectedOut[i] = false; - - /* Create the vbSelectedOut table. */ - LUA->CreateTableFromArrayB( vbSelectedOut ); - ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ - - /* Get the function to call from m_LuaTable. */ - m_pLuaTable->PushSelf( LUA->L ); - ASSERT( lua_istable( LUA->L, -1 ) ); - - lua_pushstring( LUA->L, "LoadSelections" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isfunction( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"LoadSelections\" entry is not a function", def.name.c_str() ); - - /* Argument 1 (self): */ - m_pLuaTable->PushSelf( LUA->L ); - - /* Argument 2 (vbSelectedOut): */ - lua_pushvalue( LUA->L, 1 ); - - /* Argument 3 (pn): */ - LUA->PushStack( (int) pn ); - - ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ - - lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results - ASSERT( lua_gettop(LUA->L) == 2 ); - - lua_pop( LUA->L, 1 ); /* pop option table */ - - LUA->ReadArrayFromTableB( vbSelectedOut ); - - lua_pop( LUA->L, 1 ); /* pop vbSelectedOut table */ - - ASSERT( lua_gettop(LUA->L) == 0 ); -} - -int OptionRowHandlerLua::ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const -{ - ASSERT( lua_gettop(LUA->L) == 0 ); - - /* Evaluate SaveSelections(self,array,pn) function, where array is a table - * representing vbSelectedOut. */ - - vector vbSelectedCopy = vbSelected; - - /* Create the vbSelectedOut table. */ - LUA->CreateTableFromArrayB( vbSelectedCopy ); - ASSERT( lua_gettop(LUA->L) == 1 ); /* vbSelectedOut table */ - - /* Get the function to call. */ - m_pLuaTable->PushSelf( LUA->L ); - ASSERT( lua_istable( LUA->L, -1 ) ); - - lua_pushstring( LUA->L, "SaveSelections" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isfunction( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"SaveSelections\" entry is not a function", def.name.c_str() ); - - /* Argument 1 (self): */ - m_pLuaTable->PushSelf( LUA->L ); - - /* Argument 2 (vbSelectedOut): */ - lua_pushvalue( LUA->L, 1 ); - - /* Argument 3 (pn): */ - LUA->PushStack( (int) pn ); - - ASSERT( lua_gettop(LUA->L) == 6 ); /* vbSelectedOut, m_iLuaTable, function, self, arg, arg */ - - lua_call( LUA->L, 3, 0 ); // call function with 3 arguments and 0 results - ASSERT( lua_gettop(LUA->L) == 2 ); - - lua_pop( LUA->L, 1 ); /* pop option table */ - lua_pop( LUA->L, 1 ); /* pop vbSelected table */ - - ASSERT( lua_gettop(LUA->L) == 0 ); - - // XXX: allow specifying the mask - return 0; -} - - -void OptionRowHandlerConfig::ImportOption( const OptionRowDefinition &def, PlayerNumber pn, vector &vbSelectedOut ) const -{ - int iSelection = opt->Get(); - SelectExactlyOne( iSelection, vbSelectedOut ); -} - -int OptionRowHandlerConfig::ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const -{ - int sel = GetOneSelection(vbSelected); - - /* Get the original choice. */ - int Original = opt->Get(); - - /* Apply. */ - opt->Put( sel ); - - /* Get the new choice. */ - int New = opt->Get(); - - /* If it didn't change, don't return any side-effects. */ - if( Original == New ) + virtual void ImportOption( const OptionRowDefinition &row, PlayerNumber pn, vector &vbSelectedOut ) const + { + vbSelectedOut[0] = true; + } + virtual int ExportOption( const OptionRowDefinition &def, PlayerNumber pn, const vector &vbSelected ) const + { + // TODO: Do actions. return 0; + } + virtual CString GetAndEraseScreen( int iChoice ) + { + if( m_vEditMenuActions[iChoice] == EDIT_MENU_ACTION_EDIT ) + return "ScreenEdit"; + else + return ""; + } +}; - return opt->GetEffects(); -} /////////////////////////////////////////////////////////////////////////////////// -/* Add the list named "ListName" to the given row/handler. */ -void OptionRowHandlerList::Load( OptionRowDefinition &defOut, CString sListName ) -{ - m_sName = sListName; - - if( m_sName.CompareNoCase("NoteSkins")==0 ) { FillNoteSkins( defOut ); return; } - else if( m_sName.CompareNoCase("Steps")==0 ) { FillSteps( defOut ); return; } - else if( m_sName.CompareNoCase("EditsAndNull")==0 ) { FillEditsAndNull( defOut ); return; } - else if( m_sName.CompareNoCase("Characters")==0 ) { FillCharacters( defOut ); return; } - else if( m_sName.CompareNoCase("Styles")==0 ) { FillStyles( defOut ); return; } - else if( m_sName.CompareNoCase("Groups")==0 ) { FillGroups( defOut ); return; } - else if( m_sName.CompareNoCase("Difficulties")==0 ) { FillDifficulties( defOut ); return; } - else if( m_sName.CompareNoCase("SongsInCurrentSongGroup")==0 ) { FillSongsInCurrentSongGroup( defOut ); return; } - - Init(); - defOut.Init(); - - m_bUseModNameForIcon = true; - - defOut.name = sListName; - - Default.Load( -1, ParseCommands(ENTRY_DEFAULT(sListName)) ); - - /* Parse the basic configuration metric. */ - Commands cmds = ParseCommands( ENTRY(sListName) ); - if( cmds.v.size() < 1 ) - RageException::Throw( "Parse error in OptionRowHandlerUtilEntries::ListName%s", sListName.c_str() ); - - defOut.bOneChoiceForAllPlayers = false; - const int NumCols = atoi( cmds.v[0].m_vsArgs[0] ); - for( unsigned i=1; i= 0 && pn < NUM_PLAYERS ); - defOut.m_vEnabledForPlayers.insert( pn ); - } - } - else if( sName == "exportonchange" ) defOut.m_bExportOnChange = true; - else RageException::Throw( "Unkown row flag \"%s\"", sName.c_str() ); - } - - for( int col = 0; col < NumCols; ++col ) - { - GameCommand mc; - mc.Load( 0, ParseCommands(ENTRY_MODE(sListName, col)) ); - if( mc.m_sName == "" ) - RageException::Throw( "List \"%s\", col %i has no name", sListName.c_str(), col ); - - if( !mc.IsPlayable() ) - continue; - - ListEntries.push_back( mc ); - - CString sName = mc.m_sName; - CString sChoice = ENTRY_NAME(mc.m_sName); - defOut.choices.push_back( sChoice ); - } -} - -void OptionRowHandlerLua::Load( OptionRowDefinition &defOut, CString sLuaFunction ) -{ - Init(); - defOut.Init(); - - m_sName = sLuaFunction; -// m_bUseModNameForIcon = true; - - /* Run the Lua expression. It should return a table. */ - m_pLuaTable->SetFromExpression( sLuaFunction ); - - if( m_pLuaTable->GetLuaType() != LUA_TTABLE ) - RageException::Throw( "Result of \"%s\" is not a table", sLuaFunction.c_str() ); - - { - m_pLuaTable->PushSelf( LUA->L ); - - lua_pushstring( LUA->L, "Name" ); - lua_gettable( LUA->L, -2 ); - const char *pStr = lua_tostring( LUA->L, -1 ); - if( pStr == NULL ) - RageException::Throw( "\"%s\" \"Name\" entry is not a string", sLuaFunction.c_str() ); - defOut.name = pStr; - lua_pop( LUA->L, 1 ); - - - lua_pushstring( LUA->L, "OneChoiceForAllPlayers" ); - lua_gettable( LUA->L, -2 ); - defOut.bOneChoiceForAllPlayers = !!lua_toboolean( LUA->L, -1 ); - lua_pop( LUA->L, 1 ); - - - lua_pushstring( LUA->L, "LayoutType" ); - lua_gettable( LUA->L, -2 ); - pStr = lua_tostring( LUA->L, -1 ); - if( pStr == NULL ) - RageException::Throw( "\"%s\" \"LayoutType\" entry is not a string", sLuaFunction.c_str() ); - defOut.layoutType = StringToLayoutType( pStr ); - ASSERT( defOut.layoutType != LAYOUT_INVALID ); - lua_pop( LUA->L, 1 ); - - - lua_pushstring( LUA->L, "SelectType" ); - lua_gettable( LUA->L, -2 ); - pStr = lua_tostring( LUA->L, -1 ); - if( pStr == NULL ) - RageException::Throw( "\"%s\" \"SelectType\" entry is not a string", sLuaFunction.c_str() ); - defOut.selectType = StringToSelectType( pStr ); - ASSERT( defOut.selectType != SELECT_INVALID ); - lua_pop( LUA->L, 1 ); - - - /* Iterate over the "Choices" table. */ - lua_pushstring( LUA->L, "Choices" ); - lua_gettable( LUA->L, -2 ); - if( !lua_istable( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"Choices\" is not a table", sLuaFunction.c_str() ); - - lua_pushnil( LUA->L ); - while( lua_next(LUA->L, -2) != 0 ) - { - /* `key' is at index -2 and `value' at index -1 */ - const char *pValue = lua_tostring( LUA->L, -1 ); - if( pValue == NULL ) - RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); - LOG->Trace( "'%s'", pValue); - - defOut.choices.push_back( pValue ); - - lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ - } - - lua_pop( LUA->L, 1 ); /* pop choices table */ - - - /* Iterate over the "EnabledForPlayers" table. */ - lua_pushstring( LUA->L, "EnabledForPlayers" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isnil( LUA->L, -1 ) ) - { - if( !lua_istable( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"EnabledForPlayers\" is not a table", sLuaFunction.c_str() ); - - defOut.m_vEnabledForPlayers.clear(); // and fill in with supplied PlayerNumbers below - - lua_pushnil( LUA->L ); - while( lua_next(LUA->L, -2) != 0 ) - { - /* `key' is at index -2 and `value' at index -1 */ - PlayerNumber pn = (PlayerNumber)luaL_checkint( LUA->L, -1 ); - - defOut.m_vEnabledForPlayers.insert( pn ); - - lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ - } - } - lua_pop( LUA->L, 1 ); /* pop EnabledForPlayers table */ - - - /* Look for "ExportOnChange" value. */ - lua_pushstring( LUA->L, "ExportOnChange" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isnil( LUA->L, -1 ) ) - { - defOut.m_bExportOnChange = !!MyLua_checkboolean( LUA->L, -1 ); - } - lua_pop( LUA->L, 1 ); /* pop ExportOnChange value */ - - - /* Iterate over the "ReloadRowMessages" table. */ - lua_pushstring( LUA->L, "ReloadRowMessages" ); - lua_gettable( LUA->L, -2 ); - if( !lua_isnil( LUA->L, -1 ) ) - { - if( !lua_istable( LUA->L, -1 ) ) - RageException::Throw( "\"%s\" \"ReloadRowMessages\" is not a table", sLuaFunction.c_str() ); - - m_vsReloadRowMessages.clear(); // and fill in with supplied PlayerNumbers below - - lua_pushnil( LUA->L ); - while( lua_next(LUA->L, -2) != 0 ) - { - /* `key' is at index -2 and `value' at index -1 */ - const char *pValue = lua_tostring( LUA->L, -1 ); - if( pValue == NULL ) - RageException::Throw( "\"%s\" Column entry is not a string", sLuaFunction.c_str() ); - LOG->Trace( "'%s'", pValue); - - m_vsReloadRowMessages.push_back( pValue ); - - lua_pop( LUA->L, 1 ); /* removes `value'; keeps `key' for next iteration */ - } - } - lua_pop( LUA->L, 1 ); /* pop ReloadRowMessages table */ - - - lua_pop( LUA->L, 1 ); /* pop main table */ - ASSERT( lua_gettop(LUA->L) == 0 ); - } -} - -void OptionRowHandlerList::FillNoteSkins( OptionRowDefinition &defOut ) -{ - Init(); - defOut.Init(); - - defOut.name = "NoteSkins"; - defOut.bOneChoiceForAllPlayers = false; - - CStringArray arraySkinNames; - NOTESKIN->GetNoteSkinNames( arraySkinNames ); - for( unsigned skin=0; skinm_bEditing ) - { - defOut.choices.push_back( "" ); - ListEntries.push_back( GameCommand() ); - } - else if( GAMESTATE->IsCourseMode() ) // playing a course - { - defOut.bOneChoiceForAllPlayers = PREFSMAN->m_bLockCourseDifficulties; - - vector vTrails; - GAMESTATE->m_pCurCourse->GetTrails( vTrails, GAMESTATE->GetCurrentStyle()->m_StepsType ); - for( unsigned i=0; im_CourseDifficulty ); - defOut.choices.push_back( s ); - GameCommand mc; - mc.m_pTrail = pTrail; - ListEntries.push_back( mc ); - } - } - else // !GAMESTATE->IsCourseMode(), playing a song - { - vector vSteps; - GAMESTATE->m_pCurSong->GetSteps( vSteps, GAMESTATE->GetCurrentStyle()->m_StepsType ); - StepsUtil::SortNotesArrayByDifficulty( vSteps ); - for( unsigned i=0; iGetDifficulty() == DIFFICULTY_EDIT ) - s = pSteps->GetDescription(); - else - s = DifficultyToThemedString( pSteps->GetDifficulty() ); - s += ssprintf( " (%d)", pSteps->GetMeter() ); - - defOut.choices.push_back( s ); - GameCommand mc; - mc.m_pSteps = pSteps; - mc.m_dc = pSteps->GetDifficulty(); - ListEntries.push_back( mc ); - } - } -} - -void OptionRowHandlerList::FillEditsAndNull( OptionRowDefinition &defOut ) -{ - Init(); - defOut.Init(); - - defOut.name = "EditsAndNull"; - defOut.bOneChoiceForAllPlayers = true; - defOut.layoutType = LAYOUT_SHOW_ONE_IN_ROW; - defOut.m_bExportOnChange = true; - m_vsReloadRowMessages.push_back( MessageToString(MESSAGE_CURRENT_SONG_CHANGED) ); - - vector vSteps; - GAMESTATE->m_pCurSong->GetSteps( vSteps, GAMESTATE->m_stEdit, DIFFICULTY_EDIT ); - StepsUtil::SortNotesArrayByDifficulty( vSteps ); - FOREACH_CONST( Steps*, vSteps, p ) - { - CString s = (*p)->GetDescription(); - s += ssprintf( " (%d)", (*p)->GetMeter() ); - - defOut.choices.push_back( s ); - GameCommand mc; - mc.m_pSteps = *p; - ListEntries.push_back( mc ); - } - - // Add NULL entry for a new edit - { - defOut.choices.push_back( ENTRY_NAME("NewEdit") ); - GameCommand mc; - ListEntries.push_back( mc ); - } -} - - -/* Add the given configuration value to the given row/handler. */ -void OptionRowHandlerConfig::Load( OptionRowDefinition &defOut, CString param ) -{ - Init(); - defOut.Init(); - - /* Configuration values are never per-player. */ - defOut.bOneChoiceForAllPlayers = true; - - ConfOption *pConfOption = ConfOption::Find( param ); - if( pConfOption == NULL ) - RageException::Throw( "Invalid Conf type \"%s\"", param.c_str() ); - - pConfOption->UpdateAvailableOptions(); - - opt = pConfOption; - opt->MakeOptionsList( defOut.choices ); - - defOut.name = opt->name; -} - -/* Add a list of available characters to the given row/handler. */ -void OptionRowHandlerList::FillCharacters( OptionRowDefinition &defOut ) -{ - Init(); - defOut.Init(); - - defOut.bOneChoiceForAllPlayers = false; - defOut.name = "Characters"; - Default.m_pCharacter = GAMESTATE->GetDefaultCharacter(); - - { - defOut.choices.push_back( ENTRY_NAME("Off") ); - GameCommand mc; - mc.m_pCharacter = NULL; - ListEntries.push_back( mc ); - } - - vector apCharacters; - GAMESTATE->GetCharacters( apCharacters ); - for( unsigned i=0; im_sName; - s.MakeUpper(); - - defOut.choices.push_back( s ); - GameCommand mc; - mc.m_pCharacter = pCharacter; - ListEntries.push_back( mc ); - } -} - -/* Add a list of available styles to the given row/handler. */ -void OptionRowHandlerList::FillStyles( OptionRowDefinition &defOut ) -{ - Init(); - defOut.Init(); - - defOut.bOneChoiceForAllPlayers = true; - defOut.name = "Style"; - defOut.bOneChoiceForAllPlayers = true; - - vector vStyles; - GAMEMAN->GetStylesForGame( GAMESTATE->m_pCurGame, vStyles ); - ASSERT( vStyles.size() ); - FOREACH_CONST( const Style*, vStyles, s ) - { - defOut.choices.push_back( GAMEMAN->StyleToThemedString(*s) ); - GameCommand mc; - mc.m_pStyle = *s; - ListEntries.push_back( mc ); - } - - Default.m_pStyle = vStyles[0]; -} - -/* Add a list of available song groups to the given row/handler. */ -void OptionRowHandlerList::FillGroups( OptionRowDefinition &defOut ) -{ - Init(); - defOut.Init(); - - defOut.bOneChoiceForAllPlayers = true; - defOut.name = "Group"; - Default.m_sSongGroup = GROUP_ALL_MUSIC; - - vector vGroups; - SONGMAN->GetGroupNames( vGroups ); - ASSERT( vGroups.size() ); - - { - defOut.choices.push_back( ENTRY_NAME("AllGroups") ); - GameCommand mc; - mc.m_sSongGroup = GROUP_ALL_MUSIC; - ListEntries.push_back( mc ); - } - - FOREACH_CONST( CString, vGroups, g ) - { - defOut.choices.push_back( *g ); - GameCommand mc; - mc.m_sSongGroup = *g; - ListEntries.push_back( mc ); - } -} - -/* Add a list of available difficulties to the given row/handler. */ -void OptionRowHandlerList::FillDifficulties( OptionRowDefinition &defOut ) -{ - Init(); - defOut.Init(); - - set vDifficulties; - GAMESTATE->GetDifficultiesToShow( vDifficulties ); - - defOut.bOneChoiceForAllPlayers = true; - defOut.name = "Difficulty"; - Default.m_dc = DIFFICULTY_INVALID; - - { - defOut.choices.push_back( ENTRY_NAME("AllDifficulties") ); - GameCommand mc; - mc.m_dc = DIFFICULTY_INVALID; - ListEntries.push_back( mc ); - } - - FOREACHS_CONST( Difficulty, vDifficulties, d ) - { - CString s = DifficultyToThemedString( *d ); - - defOut.choices.push_back( s ); - GameCommand mc; - mc.m_dc = *d; - ListEntries.push_back( mc ); - } -} - -void OptionRowHandlerList::FillSongsInCurrentSongGroup( OptionRowDefinition &defOut ) -{ - Init(); - defOut.Init(); - - vector vpSongs; - SONGMAN->GetSongs( vpSongs, GAMESTATE->m_sPreferredSongGroup ); - - if( GAMESTATE->m_pCurSong == NULL ) - GAMESTATE->m_pCurSong.Set( vpSongs[0] ); - - defOut.name = "SongsInCurrentSongGroup"; - defOut.bOneChoiceForAllPlayers = true; - defOut.layoutType = LAYOUT_SHOW_ONE_IN_ROW; - defOut.m_bExportOnChange = true; - - FOREACH_CONST( Song*, vpSongs, p ) - { - defOut.choices.push_back( (*p)->GetFullTranslitTitle() ); - GameCommand mc; - mc.m_pSong = *p; - ListEntries.push_back( mc ); - } -} - - OptionRowHandler* OptionRowHandlerUtil::Make( const Command &command, OptionRowDefinition &defOut ) { OptionRowHandler* pHand = NULL; @@ -966,6 +1036,7 @@ OptionRowHandler* OptionRowHandlerUtil::Make( const Command &command, OptionRowD else if( name == "conf" ) MAKE( OptionRowHandlerConfig ) else if( name == "stepstype" ) MAKE( OptionRowHandlerStepsType ) else if( name == "steps" ) MAKE( OptionRowHandlerSteps ) + else if( name == "editmenuaction" ) MAKE( OptionRowHandlerEditMenuAction ) EndHandleArgs; diff --git a/stepmania/src/OptionRowHandler.h b/stepmania/src/OptionRowHandler.h index ea4a82b87e..da36fad2c7 100644 --- a/stepmania/src/OptionRowHandler.h +++ b/stepmania/src/OptionRowHandler.h @@ -9,6 +9,8 @@ struct ConfOption; +#define ENTRY_NAME(s) THEME->GetMetric ("OptionNames", s) + class OptionRowHandler { public: