[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:
+271
-8
@@ -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" );
|
||||
|
||||
Reference in New Issue
Block a user