Added ArbSpeedMods function for a better way of setting speed modifiers. Added NotifyHandlerOfSelection to OptionRowHandler to support this. Changed exceptions thrown by OptionRowHandlerLua into log warnings because crashing out is not helpful to themers. Fixed SetEnabledForPlayers in OptionRowHandlerLua to correctly read the PlayerNumber enum. Removed silly git add Docs/Themerdocs/Examples/OptionRowHandlerLua.lua and second check for ExportOnChange.

This commit is contained in:
Kyzentun
2014-06-19 06:41:18 -06:00
parent 006fcd84a7
commit 045e9edcdd
9 changed files with 361 additions and 36 deletions
+30 -5
View File
@@ -148,7 +148,7 @@ void OptionRow::LoadExit()
ChoicesChanged( RowType_Exit );
}
void OptionRow::ChoicesChanged( RowType type )
void OptionRow::ChoicesChanged( RowType type, bool reset_focus )
{
ASSERT_M( !m_pHand->m_Def.m_vsChoices.empty(), m_pHand->m_Def.m_sName + " has no choices" );
@@ -181,9 +181,13 @@ void OptionRow::ChoicesChanged( RowType type )
InitText( type );
// When choices change, the old focus position is meaningless; reset it.
FOREACH_PlayerNumber( p )
SetChoiceInRowWithFocus( p, 0 );
// Lua can change the choices now, and when it does, we don't want to change focus.
if(reset_focus)
{
// When choices change, the old focus position is meaningless; reset it.
FOREACH_PlayerNumber( p )
SetChoiceInRowWithFocus( p, 0 );
}
m_textTitle->SetText( GetRowTitle() );
}
@@ -705,6 +709,7 @@ void OptionRow::SetOneSelection( PlayerNumber pn, int iChoice )
FOREACH( bool, vb, b )
*b = false;
vb[iChoice] = true;
NotifyHandlerOfSelection(pn, iChoice);
}
void OptionRow::SetOneSharedSelection( int iChoice )
@@ -788,11 +793,31 @@ OptionRowDefinition &OptionRow::GetRowDef()
return m_pHand->m_Def;
}
void OptionRow::SetSelected( PlayerNumber pn, int iChoice, bool b )
bool OptionRow::SetSelected( PlayerNumber pn, int iChoice, bool b )
{
if( m_pHand->m_Def.m_bOneChoiceForAllPlayers )
pn = PLAYER_1;
m_vbSelected[pn][iChoice] = b;
return NotifyHandlerOfSelection(pn, iChoice);
}
bool OptionRow::NotifyHandlerOfSelection(PlayerNumber pn, int choice)
{
bool changed= m_pHand->NotifyOfSelection(pn, choice);
if(changed)
{
ChoicesChanged(m_RowType, false);
vector<PlayerNumber> vpns;
FOREACH_HumanPlayer( p )
vpns.push_back( p );
ImportOptions(vpns);
FOREACH_PlayerNumber(p)
{
PositionUnderlines(p);
}
UpdateEnabledDisabled();
}
return changed;
}
void OptionRow::SetExitText( RString sExitText )
+5 -2
View File
@@ -76,7 +76,7 @@ public:
RString GetRowTitle() const;
void ChoicesChanged( RowType type );
void ChoicesChanged( RowType type, bool reset_focus= true );
void PositionUnderlines( PlayerNumber pn );
void PositionIcons( PlayerNumber pn );
void UpdateText( PlayerNumber pn );
@@ -96,7 +96,10 @@ public:
void ResetFocusFromSelection( PlayerNumber pn );
bool GetSelected( PlayerNumber pn, int iChoice ) const;
void SetSelected( PlayerNumber pn, int iChoice, bool b );
// SetSelected returns true if the choices changed because of setting.
bool SetSelected( PlayerNumber pn, int iChoice, bool b );
bool NotifyHandlerOfSelection(PlayerNumber pn, int choice);
const OptionRowDefinition &GetRowDef() const;
OptionRowDefinition &GetRowDef();
+86 -25
View File
@@ -834,7 +834,9 @@ public:
lua_call( L, 1, 1 ); // call function with 1 argument and 1 result
if( !lua_istable(L, -1) )
RageException::Throw( "\"EnabledForPlayers\" did not return a table." );
{
LOG->Warn("LUA_ERROR: \"EnabledForPlayers\" did not return a table." );
}
m_Def.m_vEnabledForPlayers.clear(); // and fill in with supplied PlayerNumbers below
@@ -842,7 +844,7 @@ public:
while( lua_next(L, -2) != 0 )
{
// `key' is at index -2 and `value' at index -1
PlayerNumber pn = (PlayerNumber)luaL_checkint( L, -1 );
PlayerNumber pn = Enum::Check<PlayerNumber>(L, -1);
m_Def.m_vEnabledForPlayers.insert( pn );
@@ -869,7 +871,9 @@ public:
m_pLuaTable->SetFromExpression( sLuaFunction );
if( m_pLuaTable->GetLuaType() != LUA_TTABLE )
RageException::Throw( "Result of \"%s\" is not a table.", sLuaFunction.c_str() );
{
LOG->Warn("LUA_ERROR: Result of \"%s\" is not a table.", sLuaFunction.c_str());
}
m_pLuaTable->PushSelf( L );
@@ -877,25 +881,29 @@ public:
lua_gettable( L, -2 );
const char *pStr = lua_tostring( L, -1 );
if( pStr == NULL )
RageException::Throw( "\"%s\" \"Name\" entry is not a string.", sLuaFunction.c_str() );
{
LOG->Warn("LUA_ERROR: \"%s\" \"Name\" entry is not a string.", sLuaFunction.c_str());
}
m_Def.m_sName = pStr;
lua_pop( L, 1 );
lua_pushstring( L, "OneChoiceForAllPlayers" );
lua_gettable( L, -2 );
m_Def.m_bOneChoiceForAllPlayers = !!lua_toboolean( L, -1 );
m_Def.m_bOneChoiceForAllPlayers = lua_toboolean( L, -1 );
lua_pop( L, 1 );
lua_pushstring( L, "ExportOnChange" );
lua_gettable( L, -2 );
m_Def.m_bExportOnChange = !!lua_toboolean( L, -1 );
m_Def.m_bExportOnChange = lua_toboolean( L, -1 );
lua_pop( L, 1 );
lua_pushstring( L, "LayoutType" );
lua_gettable( L, -2 );
pStr = lua_tostring( L, -1 );
if( pStr == NULL )
RageException::Throw( "\"%s\" \"LayoutType\" entry is not a string.", sLuaFunction.c_str() );
{
LOG->Warn("LUA_ERROR: \"%s\" \"LayoutType\" entry is not a string.", sLuaFunction.c_str());
}
m_Def.m_layoutType = StringToLayoutType( pStr );
ASSERT( m_Def.m_layoutType != LayoutType_Invalid );
lua_pop( L, 1 );
@@ -904,7 +912,9 @@ public:
lua_gettable( L, -2 );
pStr = lua_tostring( L, -1 );
if( pStr == NULL )
RageException::Throw( "\"%s\" \"SelectType\" entry is not a string.", sLuaFunction.c_str() );
{
LOG->Warn("LUA_ERROR: \"%s\" \"SelectType\" entry is not a string.", sLuaFunction.c_str());
}
m_Def.m_selectType = StringToSelectType( pStr );
ASSERT( m_Def.m_selectType != SelectType_Invalid );
lua_pop( L, 1 );
@@ -913,7 +923,9 @@ public:
lua_pushstring( L, "Choices" );
lua_gettable( L, -2 );
if( !lua_istable( L, -1 ) )
RageException::Throw( "\"%s\" \"Choices\" is not a table.", sLuaFunction.c_str() );
{
LOG->Warn("LUA_ERROR: \"%s\" \"Choices\" is not a table.", sLuaFunction.c_str());
}
lua_pushnil( L );
while( lua_next(L, -2) != 0 )
@@ -921,8 +933,10 @@ public:
// `key' is at index -2 and `value' at index -1
const char *pValue = lua_tostring( L, -1 );
if( pValue == NULL )
RageException::Throw( "\"%s\" Column entry is not a string.", sLuaFunction.c_str() );
// LOG->Trace( "'%s'", pValue);
{
LOG->Warn("LUA_ERROR: \"%s\" Column entry is not a string.", sLuaFunction.c_str());
}
//LOG->Trace( "choice: '%s'", pValue);
m_Def.m_vsChoices.push_back( pValue );
@@ -935,7 +949,9 @@ public:
lua_pushstring( L, "EnabledForPlayers" );
lua_gettable( L, -2 );
if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) )
RageException::Throw( "\"%s\" \"EnabledForPlayers\" is not a table.", sLuaFunction.c_str() );
{
LOG->Warn("LUA_ERROR: \"%s\" \"EnabledForPlayers\" is not a function.", sLuaFunction.c_str());
}
m_EnabledForPlayersFunc.SetFromStack( L );
SetEnabledForPlayers();
@@ -953,8 +969,10 @@ public:
// `key' is at index -2 and `value' at index -1
const char *pValue = lua_tostring( L, -1 );
if( pValue == NULL )
RageException::Throw( "\"%s\" Column entry is not a string.", sLuaFunction.c_str() );
LOG->Trace( "Found ReloadRowMessage '%s'", pValue);
{
LOG->Warn("LUA_ERROR: \"%s\" Column entry is not a string.", sLuaFunction.c_str());
}
//LOG->Trace( "Found ReloadRowMessage '%s'", pValue);
m_vsReloadRowMessages.push_back( pValue );
@@ -963,15 +981,6 @@ public:
}
lua_pop( L, 1 ); // pop ReloadRowMessages table
// Look for "ExportOnChange" value.
lua_pushstring( L, "ExportOnChange" );
lua_gettable( L, -2 );
if( !lua_isnil( L, -1 ) )
{
m_Def.m_bExportOnChange = !!MyLua_checkboolean( L, -1 );
}
lua_pop( L, 1 ); // pop ExportOnChange value
lua_pop( L, 1 ); // pop main table
ASSERT( lua_gettop(L) == 0 );
@@ -1013,7 +1022,9 @@ public:
lua_pushstring( L, "LoadSelections" );
lua_gettable( L, -2 );
if( !lua_isfunction( L, -1 ) )
RageException::Throw( "\"%s\" \"LoadSelections\" entry is not a function.", m_Def.m_sName.c_str() );
{
LOG->Warn("LUA_ERROR: \"%s\" \"LoadSelections\" entry is not a function.", m_Def.m_sName.c_str());
}
// Argument 1 (self):
m_pLuaTable->PushSelf( L );
@@ -1067,7 +1078,9 @@ public:
lua_pushstring( L, "SaveSelections" );
lua_gettable( L, -2 );
if( !lua_isfunction( L, -1 ) )
RageException::Throw( "\"%s\" \"SaveSelections\" entry is not a function.", m_Def.m_sName.c_str() );
{
LOG->Warn("LUA_ERROR: \"%s\" \"SaveSelections\" entry is not a function.", m_Def.m_sName.c_str());
}
// Argument 1 (self):
m_pLuaTable->PushSelf( L );
@@ -1094,6 +1107,54 @@ public:
// XXX: allow specifying the mask
return 0;
}
virtual bool NotifyOfSelection(PlayerNumber pn, int choice)
{
Lua *L= LUA->Get();
m_pLuaTable->PushSelf(L);
lua_pushstring(L, "NotifyOfSelection");
lua_gettable(L, -2);
bool changed= false;
if(lua_isfunction(L, -1))
{
m_pLuaTable->PushSelf(L);
LuaHelpers::Push(L, pn);
// Convert choice to a lua index so it matches up with the Choices table.
lua_pushinteger(L, choice+1);
lua_call(L, 3, 1);
if(lua_toboolean(L, -1))
{
lua_pop(L, 1);
changed= true;
m_Def.m_vsChoices.clear();
// Iterate over the "Choices" table.
lua_pushstring( L, "Choices" );
lua_gettable( L, -2 );
if(!lua_istable(L, -1))
{
LOG->Warn("\"%s\" \"Choices\" is not a table.", m_Def.m_sName.c_str());
}
lua_pushnil( L );
while( lua_next(L, -2) != 0 )
{
// `key' is at index -2 and `value' at index -1
const char *pValue = lua_tostring( L, -1 );
if(pValue == NULL)
{
LOG->Warn("\"%s\" Column entry is not a string.", m_Def.m_sName.c_str());
}
//LOG->Trace( "choice: '%s'", pValue);
m_Def.m_vsChoices.push_back( pValue );
lua_pop( L, 1 ); // removes `value'; keeps `key' for next iteration
}
}
}
lua_settop(L, 0); // Release has an assert that forces a clear stack.
LUA->Release(L);
return changed;
}
};
class OptionRowHandlerConfig : public OptionRowHandler
+2
View File
@@ -178,6 +178,8 @@ public:
virtual int ExportOption( const vector<PlayerNumber> &, const vector<bool> vbSelected[NUM_PLAYERS] ) const { return 0; }
virtual void GetIconTextAndGameCommand( int iFirstSelection, RString &sIconTextOut, GameCommand &gcOut ) const;
virtual RString GetScreen( int /* iChoice */ ) const { return RString(); }
// Exists so that a lua function can act on the selection. Returns true if the choices should be reloaded.
virtual bool NotifyOfSelection(PlayerNumber pn, int choice) { return false; }
};
/** @brief Utilities for the OptionRowHandlers. */
+5 -1
View File
@@ -895,7 +895,11 @@ void ScreenOptions::ProcessMenuStart( const InputEventPlus &input )
{
int iChoiceInRow = row.GetChoiceInRowWithFocus(pn);
bool bSelected = !row.GetSelected( pn, iChoiceInRow );
row.SetSelected( pn, iChoiceInRow, bSelected );
bool changed= row.SetSelected( pn, iChoiceInRow, bSelected );
if(changed)
{
AfterChangeValueOrRow(pn);
}
if( bSelected )
m_SoundToggleOn.Play();