[ScreenTextEntry] Added Load(TextEntrySettings) Lua binding. [freem]

TextEntrySettings is implemented similar to the Attributes in BitmapText.

example settings and explanation:
local teSettings = {
	SendOnPop = "",					-- ScreenMessage to send on pop (optional, "SM_None" if omitted)
	Question = "",					-- The question to display
	InitialAnswer = "",				-- Initial answer text
	MaxInputLength = 0,				-- Maximum amount of characters
	Password = false,				-- Mask character input (optional)
	Validate = nil,					-- Validation function; function(answer, errorOut), must return boolean, string.
	OnOK = nil,						-- On OK; function(answer)
	OnCancel = nil,					-- On Cancel; function()
	ValidateAppend = nil,			-- Validate appending a character; function(answer,append), must return boolean
	FormatAnswerForDisplay = nil,	-- Format answer for display; function(answer), must return string
};
This commit is contained in:
AJ Kelly
2011-01-12 13:11:41 -06:00
parent 7827af4b2a
commit 17e557c396
3 changed files with 323 additions and 23 deletions
+271 -8
View File
@@ -11,6 +11,8 @@
#include "InputEventPlus.h"
#include "RageInput.h"
#include "LocalizedString.h"
#include "RageLog.h"
#include "LuaBinding.h"
static const char* g_szKeys[NUM_KeyboardRow][KEYS_PER_ROW] =
{
@@ -26,7 +28,7 @@ static const char* g_szKeys[NUM_KeyboardRow][KEYS_PER_ROW] =
RString ScreenTextEntry::s_sLastAnswer = "";
/* Settings: */
// Settings:
namespace
{
RString g_sQuestion;
@@ -38,6 +40,13 @@ namespace
bool g_bPassword;
bool (*g_pValidateAppend)(const RString &sAnswerBeforeChar, RString &sAppend);
RString (*g_pFormatAnswerForDisplay)(const RString &sAnswer);
// Lua bridge
LuaReference g_ValidateFunc;
LuaReference g_OnOKFunc;
LuaReference g_OnCancelFunc;
LuaReference g_ValidateAppendFunc;
LuaReference g_FormatAnswerForDisplayFunc;
};
void ScreenTextEntry::SetTextEntrySettings(
@@ -74,7 +83,7 @@ void ScreenTextEntry::TextEntry(
bool (*ValidateAppend)(const RString &sAnswerBeforeChar, RString &sAppend),
RString (*FormatAnswerForDisplay)(const RString &sAnswer)
)
{
{
g_sQuestion = sQuestion;
g_sInitialAnswer = sInitialAnswer;
g_iMaxInputLength = iMaxInputLength;
@@ -100,13 +109,11 @@ bool ScreenTextEntry::FloatValidate( const RString &sAnswer, RString &sErrorOut
bool ScreenTextEntry::s_bCancelledLast = false;
/*
* Handle UTF-8. Right now, we need to at least be able to backspace
* a whole UTF-8 character. Better would be to operate in wchar_t.
/* Handle UTF-8. Right now, we need to at least be able to backspace a whole
* UTF-8 character. Better would be to operate in wchar_t.
*
* XXX: Don't allow internal-use codepoints (above 0xFFFF); those are
* subject to change and shouldn't be written to disk.
*/
* XXX: Don't allow internal-use codepoints (above 0xFFFF); those are subject to
* change and shouldn't be written to disk. */
REGISTER_SCREEN_CLASS( ScreenTextEntry );
REGISTER_SCREEN_CLASS( ScreenTextEntryVisual );
@@ -297,6 +304,262 @@ void ScreenTextEntry::MenuBack( const InputEventPlus &input )
End( true );
}
void ScreenTextEntry::TextEntrySettings::FromStack( lua_State *L )
{
if( lua_type(L, 1) != LUA_TTABLE )
{
LOG->Trace("not a table");
return;
}
lua_pushvalue( L, 1 );
const int iTab = lua_gettop( L );
// Get ScreenMessage
lua_getfield( L, iTab, "SendOnPop" );
const char *pStr = lua_tostring( L, -1 );
if( pStr == NULL )
smSendOnPop = SM_None;
else
smSendOnPop = ScreenMessageHelpers::ToScreenMessage( pStr );
lua_settop( L, iTab );
// Get Question
lua_getfield( L, iTab, "Question" );
pStr = lua_tostring( L, -1 );
if( pStr == NULL )
RageException::Throw( "\"Question\" entry is not a string." );
sQuestion = pStr;
lua_settop( L, iTab );
// Get Initial Answer
lua_getfield( L, iTab, "InitialAnswer" );
pStr = lua_tostring( L, -1 );
if( pStr == NULL )
pStr = "";
sInitialAnswer = pStr;
lua_settop( L, iTab );
// Get Max Input Length
lua_getfield( L, iTab, "MaxInputLength" );
iMaxInputLength = lua_tointeger( L, -1 );
lua_settop( L, iTab );
// Get Password
lua_getfield( L, iTab, "Password" );
bPassword = !!lua_toboolean( L, -1 );
lua_settop( L, iTab );
// and now the hard part, the functions.
// Validate
lua_getfield( L, iTab, "Validate" );
if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) )
RageException::Throw( "\"Validate\" is not a function." );
Validate.SetFromStack( L );
lua_settop( L, iTab );
// OnOK
lua_getfield( L, iTab, "OnOK" );
if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) )
RageException::Throw( "\"OnOK\" is not a function." );
OnOK.SetFromStack( L );
lua_settop( L, iTab );
// OnCancel
lua_getfield( L, iTab, "OnCancel" );
if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) )
RageException::Throw( "\"OnCancel\" is not a function." );
OnCancel.SetFromStack( L );
lua_settop( L, iTab );
// ValidateAppend
lua_getfield( L, iTab, "ValidateAppend" );
if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) )
RageException::Throw( "\"ValidateAppend\" is not a function." );
ValidateAppend.SetFromStack( L );
lua_settop( L, iTab );
// FormatAnswerForDisplay
lua_getfield( L, iTab, "FormatAnswerForDisplay" );
if( !lua_isfunction( L, -1 ) && !lua_isnil( L, -1 ) )
RageException::Throw( "\"FormatAnswerForDisplay\" is not a function." );
FormatAnswerForDisplay.SetFromStack( L );
lua_settop( L, iTab );
}
// Lua bridges
static bool ValidateFromLua( const RString &sAnswer, RString &sErrorOut )
{
Lua *L = LUA->Get();
if( g_ValidateFunc.IsNil() )
{
LUA->Release(L);
return true;
}
g_ValidateFunc.PushSelf( L );
// Argument 1 (answer):
lua_pushstring( L, sAnswer );
// Argument 2 (error out):
lua_pushstring( L, sErrorOut );
lua_call( L, 2, 2 ); // call function with 2 arguments and 2 results
if( !lua_isstring(L, -1) )
RageException::Throw( "\"Validate\" did not return a string." );
if( !lua_isboolean(L, -2) )
RageException::Throw( "\"Validate\" did not return a boolean." );
RString sErrorFromLua;
LuaHelpers::Pop( L, sErrorFromLua );
if( !sErrorFromLua.empty() )
sErrorOut = sErrorFromLua;
bool bValidate;
LuaHelpers::Pop( L, bValidate );
LUA->Release(L);
return bValidate;
}
static void OnOKFromLua( const RString &sAnswer )
{
Lua *L = LUA->Get();
if( g_OnOKFunc.IsNil() )
{
LUA->Release(L);
return;
}
g_OnOKFunc.PushSelf( L );
// Argument 1 (answer):
lua_pushstring( L, sAnswer );
lua_call( L, 1, 0 ); // call function with 1 argument and 0 results
LUA->Release(L);
}
static void OnCancelFromLua()
{
Lua *L = LUA->Get();
if( g_OnCancelFunc.IsNil() )
{
LUA->Release(L);
return;
}
g_OnCancelFunc.PushSelf( L );
lua_call( L, 0, 0 ); // call function with 0 arguments and 0 results
LUA->Release(L);
}
static bool ValidateAppendFromLua( const RString &sAnswerBeforeChar, RString &sAppend )
{
Lua *L = LUA->Get();
if( g_ValidateAppendFunc.IsNil() )
{
LUA->Release(L);
return true;
}
g_ValidateAppendFunc.PushSelf( L );
// Argument 1 (AnswerBeforeChar):
lua_pushstring( L, sAnswerBeforeChar );
// Argument 2 (Append):
lua_pushstring( L, sAppend );
lua_call( L, 2, 1 ); // call function with 2 arguments and 1 result
if( !lua_isboolean(L, -1) )
RageException::Throw( "\"ValidateAppend\" did not return a boolean." );
bool bAppend;
LuaHelpers::Pop( L, bAppend );
LUA->Release(L);
return bAppend;
}
static RString FormatAnswerForDisplayFromLua( const RString &sAnswer )
{
Lua *L = LUA->Get();
if( g_FormatAnswerForDisplayFunc.IsNil() )
{
LUA->Release(L);
return sAnswer;
}
g_FormatAnswerForDisplayFunc.PushSelf( L );
// Argument 1 (Answer):
lua_pushstring( L, sAnswer );
lua_call( L, 1, 1 ); // call function with 1 argument and 1 result
if( !lua_isstring(L, -1) )
RageException::Throw( "\"FormatAnswerForDisplay\" did not return a string." );
RString sAnswerFromLua;
LuaHelpers::Pop( L, sAnswerFromLua );
LUA->Release(L);
return sAnswerFromLua;
}
void ScreenTextEntry::LoadFromTextEntrySettings( const TextEntrySettings &settings )
{
g_ValidateFunc = settings.Validate;
g_OnOKFunc = settings.OnOK;
g_OnCancelFunc = settings.OnCancel;
g_ValidateAppendFunc = settings.ValidateAppend;
g_FormatAnswerForDisplayFunc = settings.FormatAnswerForDisplay;
// set functions
SetTextEntrySettings(
settings.sQuestion,
settings.sInitialAnswer,
settings.iMaxInputLength,
ValidateFromLua, // Validate
OnOKFromLua, // OnOK
OnCancelFromLua, // OnCancel
settings.bPassword,
ValidateAppendFromLua, // ValidateAppend
FormatAnswerForDisplayFromLua // FormatAnswerForDisplay
);
// Hack: reload screen with new info
BeginScreen();
}
// lua start
class LunaScreenTextEntry: public Luna<ScreenTextEntry>
{
public:
static int Load( T* p, lua_State *L )
{
ScreenTextEntry::TextEntrySettings settings;
settings.FromStack( L );
p->LoadFromTextEntrySettings(settings);
return 0;
}
LunaScreenTextEntry()
{
ADD_METHOD( Load );
}
};
LUA_REGISTER_DERIVED_CLASS( ScreenTextEntry, ScreenWithMenuElements )
// lua end
// begin ScreenTextEntryVisual
void ScreenTextEntryVisual::Init()
{
ROW_START_X.Load( m_sName, "RowStartX" );