[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:
@@ -16,6 +16,20 @@ sm-ssc v1.2.1 | 20110???
|
||||
20110112
|
||||
--------
|
||||
* [NetworkSyncManager] Added CloseConnection() Lua binding. [freem]
|
||||
* [ScreenTextEntry] Added Load(TextEntrySettings) Lua binding. [freem]
|
||||
TextEntrySettings is implemented similar to the Attributes in BitmapText.
|
||||
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
|
||||
};
|
||||
|
||||
20110111
|
||||
--------
|
||||
|
||||
+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" );
|
||||
|
||||
+38
-15
@@ -58,6 +58,26 @@ public:
|
||||
TextEntry( smSendOnPop, sQuestion, "", 255, NULL, OnOK, OnCancel, true );
|
||||
}
|
||||
|
||||
struct TextEntrySettings {
|
||||
TextEntrySettings() { }
|
||||
ScreenMessage smSendOnPop;
|
||||
RString sQuestion;
|
||||
RString sInitialAnswer;
|
||||
int iMaxInputLength;
|
||||
bool bPassword; // (optional)
|
||||
LuaReference Validate; // (RString sAnswer, RString sErrorOut; optional)
|
||||
LuaReference OnOK; // (RString sAnswer; optional)
|
||||
LuaReference OnCancel; // (optional)
|
||||
LuaReference ValidateAppend; // (RString sAnswerBeforeChar, RString sAppend; optional)
|
||||
LuaReference FormatAnswerForDisplay; // (RString sAnswer; optional)
|
||||
|
||||
// see BitmapText.cpp Attribute::FromStack() and
|
||||
// OptionRowHandler.cpp LoadInternal() for ideas on how to implement the
|
||||
// main part, and ImportOption() from OptionRowHandler.cpp for functions.
|
||||
void FromStack( lua_State *L );
|
||||
};
|
||||
void LoadFromTextEntrySettings( const TextEntrySettings &settings );
|
||||
|
||||
static bool FloatValidate( const RString &sAnswer, RString &sErrorOut );
|
||||
|
||||
virtual void Init();
|
||||
@@ -69,6 +89,9 @@ public:
|
||||
static RString s_sLastAnswer;
|
||||
static bool s_bCancelledLast;
|
||||
|
||||
// Lua
|
||||
virtual void PushSelf( lua_State *L );
|
||||
|
||||
protected:
|
||||
void TryAppendToAnswer( RString s );
|
||||
void BackspaceInAnswer();
|
||||
@@ -81,16 +104,16 @@ private:
|
||||
|
||||
void UpdateAnswerText();
|
||||
|
||||
wstring m_sAnswer;
|
||||
bool m_bShowAnswerCaret;
|
||||
wstring m_sAnswer;
|
||||
bool m_bShowAnswerCaret;
|
||||
|
||||
BitmapText m_textQuestion;
|
||||
BitmapText m_textAnswer;
|
||||
BitmapText m_textQuestion;
|
||||
BitmapText m_textAnswer;
|
||||
|
||||
RageSound m_sndType;
|
||||
RageSound m_sndBackspace;
|
||||
RageSound m_sndType;
|
||||
RageSound m_sndBackspace;
|
||||
|
||||
RageTimer m_timerToggleCursor;
|
||||
RageTimer m_timerToggleCursor;
|
||||
};
|
||||
|
||||
class ScreenTextEntryVisual: public ScreenTextEntry
|
||||
@@ -107,20 +130,20 @@ protected:
|
||||
|
||||
virtual void TextEnteredDirectly();
|
||||
|
||||
virtual void MenuLeft( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(-1); }
|
||||
virtual void MenuRight( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(+1); }
|
||||
virtual void MenuUp( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(-1); }
|
||||
virtual void MenuDown( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(+1); }
|
||||
virtual void MenuLeft( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(-1); }
|
||||
virtual void MenuRight( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveX(+1); }
|
||||
virtual void MenuUp( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(-1); }
|
||||
virtual void MenuDown( const InputEventPlus &input ) { if(input.type==IET_FIRST_PRESS) MoveY(+1); }
|
||||
|
||||
virtual void MenuStart( const InputEventPlus &input );
|
||||
|
||||
int m_iFocusX;
|
||||
KeyboardRow m_iFocusY;
|
||||
KeyboardRow m_iFocusY;
|
||||
|
||||
AutoActor m_sprCursor;
|
||||
BitmapText *m_ptextKeys[NUM_KeyboardRow][KEYS_PER_ROW];
|
||||
AutoActor m_sprCursor;
|
||||
BitmapText *m_ptextKeys[NUM_KeyboardRow][KEYS_PER_ROW];
|
||||
|
||||
RageSound m_sndChange;
|
||||
RageSound m_sndChange;
|
||||
|
||||
ThemeMetric<float> ROW_START_X;
|
||||
ThemeMetric<float> ROW_START_Y;
|
||||
|
||||
Reference in New Issue
Block a user