2013-02-14 15:53:06 +00:00
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2013-03-24 19:16:23 +00:00
# include "stdpch.h"
2013-02-14 15:53:06 +00:00
# include "nel/gui/lua_helper.h"
# include "nel/gui/interface_group.h"
# include <algorithm>
// to get rid of you_must_not_use_assert___use_nl_assert___read_debug_h_file messages
# include <cassert>
# ifdef assert
# undef assert
# endif
# ifdef NL_OS_WINDOWS
# include <Windows.h>
# endif
// Warning: cannot use namespace std, when using luabind
# ifdef NL_OS_WINDOWS
# ifndef NL_EXTENDED_FOR_SCOPE
# undef for
# endif
# endif
# ifdef NL_DEBUG
# define assert(x) nlassert(x)
# else
# define assert(x)
# endif
# include <luabind/luabind.hpp>
// in luabind > 0.6, LUABIND_MAX_ARITY is set to 10
# if LUABIND_MAX_ARITY == 10
# include <luabind / operator.hpp>
// only luabind > 0.7 have version.hpp (file checked with build system)
# ifdef HAVE_LUABIND_VERSION
# include <luabind / version.hpp>
# endif
# ifndef LUABIND_VERSION
// luabind 0.7 doesn't define LUABIND_VERSION
# define LUABIND_VERSION 700
# endif
// luabind 0.6 doesn't define LUABIND_VERSION but LUABIND_MAX_ARITY is set to 5
# elif LUABIND_MAX_ARITY == 5
# define LUABIND_VERSION 600
# else
# pragma error("luabind version not recognized")
# endif
# include "nel/gui/lua_ihm.h"
# include "nel/gui/reflect.h"
# include "nel/misc/algo.h"
# include "nel/misc/file.h"
# include "nel/misc/i18n.h"
# include "nel/misc/time_nl.h"
# include "nel/misc/path.h"
# include "nel/misc/sstring.h"
# include "nel/misc/command.h"
# include "nel/gui/lua_object.h"
# include "nel/misc/polygon.h"
# include "nel/gui/lua_manager.h"
# include "nel/gui/widget_manager.h"
# include "nel/gui/action_handler.h"
# include "nel/gui/view_renderer.h"
# include "nel/gui/interface_expr.h"
# include "nel/misc/debug.h"
// ***************************************************************************
/*
IMPORTANT NOTE : we do this heavy double registration in this file because we DON ' T want
to include luabind . hpp in every file .
Compilation is VERY SLOW
*/
// ***************************************************************************
using namespace NLMISC ;
// declare ostream << operator for ucstring -> registration of ucstring iin luabind will build a 'tostring' function from it
std : : ostream & operator < < ( std : : ostream & str , const ucstring & value )
{
return str < < value . toString ( ) ;
}
namespace NLGUI
{
struct CMiscFunctions
{
static std : : string fileLookup ( const std : : string & fileName )
{
return NLMISC : : CPath : : lookup ( fileName , false ) ;
}
static void shellExecute ( const char * operation , const char * fileName , const char * parameters )
{
# if !FINAL_VERSION
# ifdef NL_OS_WINDOWS
ShellExecute ( NULL , operation , fileName , parameters , NULL , SW_SHOWDEFAULT ) ;
# endif
# endif
}
} ;
// ***************************************************************************
bool CLuaIHM : : pop ( CLuaState & ls , NLMISC : : CRGBA & dest )
{
//H_AUTO(Lua_CLuaIHM_pop)
try
{
if ( ls . isNil ( - 1 ) ) return false ;
# if LUABIND_VERSION > 600
luabind : : object obj ( luabind : : from_stack ( ls . getStatePointer ( ) , - 1 ) ) ;
ls . pop ( ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) ) ;
obj . set ( ) ;
# endif
dest = luabind : : object_cast < NLMISC : : CRGBA > ( obj ) ;
}
catch ( const luabind : : cast_failed & )
{
return false ;
}
return true ;
}
// ***************************************************************************
bool CLuaIHM : : pop ( CLuaState & ls , NLMISC : : CVector2f & dest )
{
//H_AUTO(Lua_CLuaIHM_pop)
try
{
if ( ls . isNil ( - 1 ) ) return false ;
# if LUABIND_VERSION > 600
luabind : : object obj ( luabind : : from_stack ( ls . getStatePointer ( ) , - 1 ) ) ;
ls . pop ( ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) ) ;
obj . set ( ) ;
# endif
dest = luabind : : object_cast < NLMISC : : CVector2f > ( obj ) ;
}
catch ( const luabind : : cast_failed & )
{
return false ;
}
return true ;
}
// ***************************************************************************
bool CLuaIHM : : pop ( CLuaState & ls , ucstring & dest )
{
//H_AUTO(Lua_CLuaIHM_pop)
try
{
if ( ls . isNil ( - 1 ) ) return false ;
# if LUABIND_VERSION > 600
luabind : : object obj ( luabind : : from_stack ( ls . getStatePointer ( ) , - 1 ) ) ;
ls . pop ( ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) ) ;
obj . set ( ) ;
# endif
dest = luabind : : object_cast < ucstring > ( obj ) ;
}
catch ( const luabind : : cast_failed & )
{
return false ;
}
return true ;
}
// ***************************************************************************
bool CLuaIHM : : isUCStringOnStack ( CLuaState & ls , sint index )
{
//H_AUTO(Lua_CLuaIHM_isUCStringOnStack)
ls . pushValue ( index ) ;
ucstring dummy ;
return pop ( ls , dummy ) ;
}
// ***************************************************************************
bool CLuaIHM : : getUCStringOnStack ( CLuaState & ls , sint index , ucstring & dest )
{
//H_AUTO(Lua_CLuaIHM_getUCStringOnStack)
ls . pushValue ( index ) ;
return pop ( ls , dest ) ;
}
// ***************************************************************************
void CLuaIHM : : push ( CLuaState & ls , const ucstring & value )
{
//H_AUTO(Lua_CLuaIHM_push)
# if LUABIND_VERSION > 600
luabind : : detail : : push ( ls . getStatePointer ( ) , value ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) , value ) ;
obj . pushvalue ( ) ;
# endif
}
// ***************************************************************************
// ***************************************************************************
// CInterface To LUA Registry
// ***************************************************************************
// ***************************************************************************
CLuaState * ELuaIHMException : : getLuaState ( )
{
return CLuaManager : : getInstance ( ) . getLuaState ( ) ;
}
}
// ***************************************************************************
# define LUA_REGISTER_BASIC(_type_) \
luabind : : detail : : yes_t is_user_defined ( luabind : : detail : : by_value < _type_ > ) ; \
_type_ convert_lua_to_cpp ( lua_State * L , luabind : : detail : : by_value < _type_ > , int index ) \
{ \
return ( _type_ ) lua_tonumber ( L , index ) ; \
} \
int match_lua_to_cpp ( lua_State * L , luabind : : detail : : by_value < _type_ > , int index ) \
{ \
if ( lua_isnumber ( L , index ) ) return 0 ; else return - 1 ; \
} \
void convert_cpp_to_lua ( lua_State * L , const _type_ & v ) \
{ \
lua_pushnumber ( L , ( double ) v ) ; \
}
// Basic LUA types
namespace luabind
{
namespace converters
{
LUA_REGISTER_BASIC ( sint8 )
LUA_REGISTER_BASIC ( uint8 )
LUA_REGISTER_BASIC ( sint16 )
LUA_REGISTER_BASIC ( uint16 )
LUA_REGISTER_BASIC ( sint32 )
LUA_REGISTER_BASIC ( uint32 )
// LUA_REGISTER_BASIC(sint)
// LUA_REGISTER_BASIC(uint)
}
}
namespace NLGUI
{
static CLuaString lstr_Env ( " Env " ) ;
static CLuaString lstr_isNil ( " isNil " ) ;
// ***************************************************************************
int CLuaIHM : : luaUIIndex ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_luaUIIndex)
nlassert ( ls . getTop ( ) = = 2 ) ;
// get the userdata and key
CReflectableLuaRef * pRefElm = ( CReflectableLuaRef * ) ls . toUserData ( 1 ) ;
const char * propName = ls . toString ( 2 ) ;
CReflectableRefPtrTarget * pRPT = ( CReflectableRefPtrTarget * ) ( pRefElm - > Ptr ) ;
// ** try to get the Env Table (interface group only)
if ( propName = = lstr_isNil )
{
ls . push ( pRPT = = NULL ) ;
return 1 ;
}
// Check the object is not NULL or freed
if ( pRPT = = NULL )
{
return 0 ;
}
// ** try to get the Env Table (interface group only)
if ( propName = = lstr_Env )
{
// Env can be bound to a CInterfaceGroup only
CInterfaceGroup * group = dynamic_cast < CInterfaceGroup * > ( pRPT ) ;
if ( group = = NULL )
{
ls . pushNil ( ) ;
return 1 ;
}
else
{
group - > pushLUAEnvTable ( ) ;
return 1 ;
}
}
// ** try to get the property
const CReflectedProperty * prop = pRefElm - > getProp ( propName ) ;
if ( prop )
{
CLuaIHM : : luaValueFromReflectedProperty ( ls , * pRPT , * prop ) ;
return 1 ;
}
// ** try to get a UI relative
CInterfaceElement * uiRelative = getUIRelative ( dynamic_cast < CInterfaceElement * > ( pRPT ) , propName ) ;
if ( uiRelative )
{
// push the UI onto the stack
pushUIOnStack ( ls , uiRelative ) ;
return 1 ;
}
// Fail to find any Attributes or elements
// Yoyo: don't write any message or warning because this may be a feature (if user want to test that something exit in the ui)
ls . pushNil ( ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : luaUINewIndex ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_luaUINewIndex)
nlassert ( ls . getTop ( ) = = 3 ) ;
// get the userdata and key
CReflectableLuaRef * pRefElm = ( CReflectableLuaRef * ) ls . toUserData ( 1 ) ;
nlassert ( pRefElm ) ;
CReflectableRefPtrTarget * pRPT = ( CReflectableRefPtrTarget * ) ( pRefElm - > Ptr ) ;
// Check the UI is not NULL or freed
if ( pRPT = = NULL )
{
return 0 ;
}
const char * propName = ls . toString ( 2 ) ;
// ** try to set the Env Table (interface group only)
if ( propName = = lstr_Env )
{
CInterfaceElement * pIE = dynamic_cast < CInterfaceElement * > ( pRPT ) ;
std : : string name ;
if ( pIE )
{
name = pIE - > getId ( ) ;
}
else
{
name = " <reflectable element> " ;
}
// Exception!!! not allowed
throw ELuaIHMException ( " You cannot change the Env Table of '%s' " , name . c_str ( ) ) ;
}
// ** try to set the property
const CReflectedProperty * prop = pRefElm - > getProp ( propName ) ;
if ( prop )
{
CLuaIHM : : luaValueToReflectedProperty ( ls , 3 , * pRPT , * prop ) ;
return 0 ;
}
CInterfaceElement * pIE = dynamic_cast < CInterfaceElement * > ( pRPT ) ;
// ** try to get another UI (child or parent)
CInterfaceElement * uiRelative = getUIRelative ( pIE , propName ) ;
if ( uiRelative )
{
// Exception!!! not allowed
throw ELuaIHMException ( " You cannot write into the UI '%s' of '%s' " , propName , pIE - > getId ( ) . c_str ( ) ) ;
}
// ** Prop Not Found
throw ELuaIHMException ( " Property '%s' not found in '%s' of type %s " , propName , pIE ? pIE - > getId ( ) . c_str ( ) : " <reflectable element> " , typeid ( * pRPT ) . name ( ) ) ;
// Fail to find any Attributes or elements
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : luaUIEq ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_luaUIEq)
nlassert ( ls . getTop ( ) = = 2 ) ;
// read lhs & rhs
// get the userdata and key
CReflectableLuaRef * lhs = ( CReflectableLuaRef * ) ls . toUserData ( 1 ) ;
CReflectableLuaRef * rhs = ( CReflectableLuaRef * ) ls . toUserData ( 2 ) ;
nlassert ( lhs ) ;
nlassert ( rhs ) ;
ls . push ( lhs - > Ptr = = rhs - > Ptr ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : luaUIDtor ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_luaUIDtor)
nlassert ( ls . getTop ( ) = = 1 ) ;
// get the userdata
CReflectableLuaRef * pRefElm = ( CReflectableLuaRef * ) ls . toUserData ( 1 ) ;
nlassert ( pRefElm ) ;
// call dtor
pRefElm - > ~ CReflectableLuaRef ( ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : luaUINext ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_luaUINext)
// Code below allow enumeration of properties of a reflectable object
// From lua standpoint, the object is seen as a table with (key, value) pairs
// If object is a CInterfaceGroup, iteration is also done on sons (groups, controls & view).
if ( ls . getTop ( ) ! = 2 )
{
CLuaIHM : : fails ( ls , " __next metamethod require 2 arguments (table & key) " ) ;
}
CLuaIHM : : check ( ls , CLuaIHM : : isReflectableOnStack ( ls , 1 ) , " __next : require ui element as first arg " ) ;
CReflectableRefPtrTarget * reflectedObject = CLuaIHM : : getReflectableOnStack ( ls , 1 ) ;
// To traverse all properties / field of the object, we must be able to determine the next key from a previous key
// (keys are ordered)
// We use the 'TValueType' enum to know which kind of property we are traversing, and an index in this group of properties
// The key which uniquely identify an element / property in the reflectable object
struct CKey
{
enum TValueType
{
VTGroup = 0 , // children groups (If the object is a CInterfaceGroup)
VTView , // children views (If the object is a CInterfaceView)
VTCtrl , // children controls (If the object is a CInterfaceCtrl)
VTProp // List of exported proeprties (For all relfectable objects)
} ;
TValueType ValueType ;
sint Index ;
const CClassInfo * ClassInfo ; // if ValueType is "VTProp" -> give the class for which property are currently enumerated
//
static int tostring ( CLuaState & ls ) // '__print' metamathod
{
CLuaIHM : : checkArgCount ( ls , " reflected object metatable:__print " , 1 ) ;
CKey key ;
key . pop ( ls ) ;
switch ( key . ValueType )
{
case VTGroup : ls . push ( toString ( " _Group %d " , key . Index ) ) ; break ;
case VTView : ls . push ( toString ( " _View %d " , key . Index ) ) ; break ;
case VTCtrl : ls . push ( toString ( " _Ctrl %d " , key . Index ) ) ; break ;
case VTProp : ls . push ( key . ClassInfo - > Properties [ key . Index ] . Name ) ; break ;
}
return 1 ;
}
// push the key on the lua stack
void push ( CLuaState & ls )
{
void * ud = ls . newUserData ( sizeof ( * this ) ) ;
* ( CKey * ) ud = * this ;
getMetaTable ( ls ) . push ( ) ;
ls . setMetaTable ( - 2 ) ;
}
// pop the key from the lua stack
void pop ( CLuaState & ls )
{
CLuaStackChecker lsc ( & ls , - 1 ) ;
if ( ! ls . isUserData ( - 1 ) )
{
CLuaIHM : : fails ( ls , " Can't pop object, not a user data " ) ;
}
// check that metatable is good (it is share between all keys)
ls . getMetaTable ( - 1 ) ;
getMetaTable ( ls ) . push ( ) ;
if ( ! ls . rawEqual ( - 1 , - 2 ) )
{
CLuaIHM : : fails ( ls , " Bad metatable for reflectable object key " ) ;
}
ls . pop ( 2 ) ;
// retrieve key
* this = * ( CKey * ) ls . toUserData ( - 1 ) ;
ls . pop ( ) ;
}
// get the metatable for a CKey
CLuaObject & getMetaTable ( CLuaState & ls )
{
static CLuaObject metatable ;
if ( ! metatable . isValid ( ) )
{
// first build
CLuaStackChecker lsc ( & ls ) ;
ls . newTable ( ) ;
ls . push ( " __tostring " ) ;
ls . push ( CKey : : tostring ) ;
ls . setTable ( - 3 ) ;
metatable . pop ( ls ) ;
}
return metatable ;
}
} ;
// Pop the current key to continue enumeration
CKey key ;
if ( ls . isNil ( 2 ) )
{
// no key -> start of table
key . ValueType = CKey : : VTGroup ;
key . Index = - 1 ;
}
else
{
key . pop ( ls ) ;
}
//
CInterfaceGroup * group = dynamic_cast < CInterfaceGroup * > ( reflectedObject ) ;
bool enumerate = true ;
while ( enumerate )
{
switch ( key . ValueType )
{
case CKey : : VTGroup :
if ( ! group | | ( key . Index + 1 ) = = ( sint ) group - > getGroups ( ) . size ( ) )
{
key . Index = - 1 ;
key . ValueType = CKey : : VTView ; // continue enumeration with views
}
else
{
+ + key . Index ;
key . push ( ls ) ;
pushUIOnStack ( ls , group - > getGroups ( ) [ key . Index ] ) ;
return 2 ;
}
break ;
case CKey : : VTView :
if ( ! group | | ( key . Index + 1 ) = = ( sint ) group - > getViews ( ) . size ( ) )
{
key . Index = - 1 ;
key . ValueType = CKey : : VTCtrl ; // continue enumeration with controls
}
else
{
+ + key . Index ;
key . push ( ls ) ;
pushUIOnStack ( ls , group - > getViews ( ) [ key . Index ] ) ;
return 2 ;
}
break ;
case CKey : : VTCtrl :
if ( ! group | | ( key . Index + 1 ) = = ( sint ) group - > getControls ( ) . size ( ) )
{
key . Index = - 1 ;
key . ValueType = CKey : : VTProp ; // continue enumeration with properties
key . ClassInfo = reflectedObject - > getClassInfo ( ) ;
}
else
{
+ + key . Index ;
key . push ( ls ) ;
pushUIOnStack ( ls , group - > getControls ( ) [ key . Index ] ) ;
return 2 ;
}
break ;
case CKey : : VTProp :
if ( ! key . ClassInfo )
{
enumerate = false ;
break ;
}
if ( ( sint ) key . ClassInfo - > Properties . size ( ) = = ( key . Index + 1 ) )
{
key . ClassInfo = key . ClassInfo - > ParentClass ; // continue enumeration in parent class
key . Index = - 1 ;
}
else
{
+ + key . Index ;
key . push ( ls ) ;
CLuaIHM : : luaValueFromReflectedProperty ( ls , * reflectedObject , key . ClassInfo - > Properties [ key . Index ] ) ;
return 2 ;
}
break ;
default :
nlassert ( 0 ) ;
break ;
}
}
ls . pushNil ( ) ;
return 0 ;
}
// ***************************************************************************
void CLuaIHM : : pushUIOnStack ( CLuaState & ls , CInterfaceElement * pIE )
{
//H_AUTO(Lua_CLuaIHM_pushUIOnStack)
CLuaIHM : : pushReflectableOnStack ( ls , pIE ) ;
}
// ***************************************************************************
bool CLuaIHM : : isUIOnStack ( CLuaState & ls , sint index )
{
//H_AUTO(Lua_CLuaIHM_isUIOnStack)
return getUIOnStack ( ls , index ) ! = NULL ;
}
// ***************************************************************************
CInterfaceElement * CLuaIHM : : getUIOnStack ( CLuaState & ls , sint index )
{
//H_AUTO(Lua_CLuaIHM_getUIOnStack)
return dynamic_cast < CInterfaceElement * > ( CLuaIHM : : getReflectableOnStack ( ls , index ) ) ;
}
// ***************************************************************************
void CLuaIHM : : checkArgTypeUIElement ( CLuaState & ls , const char * funcName , uint index )
{
//H_AUTO(Lua_CLuaIHM_checkArgTypeUIElement)
nlassert ( index > 0 ) ;
if ( ls . getTop ( ) < ( int ) index )
{
CLuaIHM : : fails ( ls , " %s : argument %d of expected type ui element was not defined " , funcName , index ) ;
}
if ( ! isUIOnStack ( ls , index ) )
{
CLuaIHM : : fails ( ls , " %s : argument %d of expected type ui element has bad type : %s " , funcName , index , ls . getTypename ( ls . type ( index ) ) , ls . type ( index ) ) ;
}
}
// ***************************************************************************
CInterfaceElement * CLuaIHM : : getUIRelative ( CInterfaceElement * pIE , const std : : string & propName )
{
//H_AUTO(Lua_CLuaIHM_getUIRelative)
if ( pIE = = NULL ) return NULL ;
// If the prop is "parent", then return the parent of the ui
if ( propName = = " parent " )
{
return pIE - > getParent ( ) ;
}
// else try to get a child (if group/exist)
else
{
CInterfaceGroup * group = dynamic_cast < CInterfaceGroup * > ( pIE ) ;
if ( group )
{
return group - > getElement ( group - > getId ( ) + " : " + propName ) ;
}
}
return NULL ;
}
// ***************************************************************************
void CLuaIHM : : registerBasics ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_registerBasics)
using namespace luabind ;
lua_State * L = ls . getStatePointer ( ) ;
// RGBA
module ( L )
[
class_ < NLMISC : : CRGBA > ( " CRGBA " )
. def ( constructor < > ( ) )
. def ( constructor < const NLMISC : : CRGBA & > ( ) )
. def ( constructor < uint8 , uint8 , uint8 > ( ) )
. def ( constructor < uint8 , uint8 , uint8 , uint8 > ( ) )
. def_readwrite ( " R " , & NLMISC : : CRGBA : : R )
. def_readwrite ( " G " , & NLMISC : : CRGBA : : G )
. def_readwrite ( " B " , & NLMISC : : CRGBA : : B )
. def_readwrite ( " A " , & NLMISC : : CRGBA : : A )
] ;
// ucstring
module ( L )
[
class_ < ucstring > ( " ucstring " )
. def ( constructor < > ( ) )
. def ( constructor < const ucstring & > ( ) )
. def ( constructor < const std : : string & > ( ) )
. def ( const_self + other < const std : : string > ( ) )
. def ( other < const std : : string > ( ) + const_self )
// NB nico : luabind crash not solved here -> use concatUCString as a replacement
// .def(const_self + other<const ucstring &>())
. def ( const_self < other < const ucstring & > ( ) )
. def ( const_self = = other < const ucstring & > ( ) )
. def ( " toUtf8 " , & ucstring : : toUtf8 )
. def ( " fromUtf8 " , & ucstring : : fromUtf8 )
. def ( " substr " , & ucstring : : luabind_substr )
. def ( luabind : : tostring ( const_self ) ) // __string metamethod
. def ( " toString " , ( std : : string ( ucstring : : * ) ( ) const ) & ucstring : : toString )
//.def(self + other<ucstring>())
] ;
// CVector2f
module ( L )
[
class_ < NLMISC : : CVector2f > ( " CVector2f " )
. def ( constructor < float , float > ( ) )
. def_readwrite ( " x " , & NLMISC : : CVector2f : : x )
. def_readwrite ( " y " , & NLMISC : : CVector2f : : y )
] ;
}
// ***************************************************************************
int CLuaIHM : : luaMethodCall ( lua_State * ls )
{
//H_AUTO(Lua_CLuaIHM_luaMethodCall)
nlassert ( ls ) ;
const CReflectedProperty * prop = ( const CReflectedProperty * ) lua_touserdata ( ls , lua_upvalueindex ( 1 ) ) ;
CLuaState * state = ( CLuaState * ) lua_touserdata ( ls , lua_upvalueindex ( 2 ) ) ;
nlassert ( prop ) ;
nlassert ( prop - > Type = = CReflectedProperty : : LuaMethod ) ;
nlassert ( state ) ;
if ( state - > empty ( ) )
{
state - > push ( NLMISC : : toString ( " Error while calling lua method %s:%s : no 'self' reference provided, did you you function call '.' instead of method call ':' ? " ,
prop - > ParentClass - > ClassName . c_str ( ) , prop - > Name . c_str ( ) )
) ;
lua_error ( ls ) ;
}
// because this is a method, first parameter is the 'this'
CReflectableRefPtrTarget * pRPT = getReflectableOnStack ( * state , 1 ) ;
if ( pRPT = = NULL )
{
state - > push ( NLMISC : : toString ( " Error while calling lua method %s:%s : 'self' pointer is nil or of bad type, can't make the call. " ,
prop - > ParentClass - > ClassName . c_str ( ) , prop - > Name . c_str ( ) )
) ;
lua_error ( ls ) ;
}
//
state - > remove ( 1 ) ; // remove 'self' reference from parameters stack
//
sint numResults = 0 ;
sint initialStackSize = state - > getTop ( ) ;
try
{
// call the actual method
numResults = ( pRPT - > * ( prop - > GetMethod . GetLuaMethod ) ) ( * state ) ;
}
catch ( const std : : exception & e )
{
// restore stack to its initial size
state - > setTop ( initialStackSize ) ;
lua_pushstring ( ls , e . what ( ) ) ;
// TODO : see if this is safe to call lua error there" ... (it does a long jump)
lua_error ( ls ) ;
}
return numResults ;
}
// ***************************************************************************
int CLuaIHM : : setOnDraw ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_setOnDraw)
CLuaStackChecker lsc ( & ls , 0 ) ;
// params: CInterfaceGroup*, "script".
// return: none
CLuaIHM : : checkArgCount ( ls , " setOnDraw " , 2 ) ;
CLuaIHM : : check ( ls , CLuaIHM : : isUIOnStack ( ls , 1 ) , " setOnDraw() requires a UI object in param 1 " ) ;
CLuaIHM : : check ( ls , ls . isString ( 2 ) , " setOnDraw() requires a string in param 2 " ) ;
// retrieve args
CInterfaceElement * pIE = CLuaIHM : : getUIOnStack ( ls , 1 ) ;
std : : string script ;
ls . toString ( 2 , script ) ;
// must be a group
CInterfaceGroup * group = dynamic_cast < CInterfaceGroup * > ( pIE ) ;
if ( ! group )
throw ELuaIHMException ( " setOnDraw() : ' % s ' is not a group " , pIE->getId().c_str()) ;
// Set the script to be executed at each draw
group - > setLuaScriptOnDraw ( script ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : addOnDbChange ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_addOnDbChange)
CLuaStackChecker lsc ( & ls , 0 ) ;
// params: CInterfaceGroup*, "dblist", "script".
// return: none
CLuaIHM : : checkArgCount ( ls , " addOnDbChange " , 3 ) ;
CLuaIHM : : check ( ls , CLuaIHM : : isUIOnStack ( ls , 1 ) , " addOnDbChange() requires a UI object in param 1 " ) ;
CLuaIHM : : check ( ls , ls . isString ( 2 ) , " addOnDbChange() requires a string in param 2 " ) ;
CLuaIHM : : check ( ls , ls . isString ( 3 ) , " addOnDbChange() requires a string in param 3 " ) ;
// retrieve args
CInterfaceElement * pIE = CLuaIHM : : getUIOnStack ( ls , 1 ) ;
std : : string dbList , script ;
ls . toString ( 2 , dbList ) ;
ls . toString ( 3 , script ) ;
// must be a group
CInterfaceGroup * group = dynamic_cast < CInterfaceGroup * > ( pIE ) ;
if ( ! group )
throw ELuaIHMException ( " addOnDbChange() : ' % s ' is not a group " , pIE->getId().c_str()) ;
// Set the script to be executed when the given DB change
group - > addLuaScriptOnDBChange ( dbList , script ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : removeOnDbChange ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_removeOnDbChange)
CLuaStackChecker lsc ( & ls , 0 ) ;
// params: CInterfaceGroup*, "dbList"
// return: none
CLuaIHM : : checkArgCount ( ls , " removeOnDbChange " , 2 ) ;
CLuaIHM : : check ( ls , CLuaIHM : : isUIOnStack ( ls , 1 ) , " removeOnDbChange() requires a UI object in param 1 " ) ;
CLuaIHM : : check ( ls , ls . isString ( 2 ) , " removeOnDbChange() requires a string in param 2 " ) ;
// retrieve args
CInterfaceElement * pIE = CLuaIHM : : getUIOnStack ( ls , 1 ) ;
std : : string dbList ;
ls . toString ( 2 , dbList ) ;
// must be a group
CInterfaceGroup * group = dynamic_cast < CInterfaceGroup * > ( pIE ) ;
if ( ! group )
throw ELuaIHMException ( " removeOnDbChange() : ' % s ' is not a group " , pIE->getId().c_str()) ;
// Remove the script to be executed when the given DB change
group - > removeLuaScriptOnDBChange ( dbList ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : setCaptureKeyboard ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_setCaptureKeyboard)
const char * funcName = " setCaptureKeyboard " ;
CLuaIHM : : checkArgCount ( ls , funcName , 1 ) ;
CLuaIHM : : checkArgTypeUIElement ( ls , funcName , 1 ) ;
CCtrlBase * ctrl = dynamic_cast < CCtrlBase * > ( CLuaIHM : : getUIOnStack ( ls , 1 ) ) ;
if ( ! ctrl )
{
CLuaIHM : : fails ( ls , " %s waits a ui control as arg 1 " , funcName ) ;
}
CWidgetManager : : getInstance ( ) - > setCaptureKeyboard ( ctrl ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : resetCaptureKeyboard ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_resetCaptureKeyboard)
const char * funcName = " resetCaptureKeyboard " ;
CLuaIHM : : checkArgCount ( ls , funcName , 0 ) ;
CWidgetManager : : getInstance ( ) - > resetCaptureKeyboard ( ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : getUIId ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_getUIId)
CLuaStackChecker lsc ( & ls , 1 ) ;
// params: CInterfaceElement*
// return: "ui:interface:...". (empty if error)
CLuaIHM : : checkArgCount ( ls , " getUIId " , 1 ) ;
CLuaIHM : : check ( ls , CLuaIHM : : isUIOnStack ( ls , 1 ) , " getUIId() requires a UI object in param 1 " ) ;
// retrieve args
CInterfaceElement * pIE = CLuaIHM : : getUIOnStack ( ls , 1 ) ;
// convert to id
if ( pIE )
ls . push ( pIE - > getId ( ) ) ;
else
ls . push ( " " ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : runAH ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_runAH)
CLuaStackChecker lsc ( & ls , 0 ) ;
// params: CInterfaceElement *, "ah", "params".
// return: none
CLuaIHM : : checkArgCount ( ls , " runAH " , 3 ) ;
CLuaIHM : : check ( ls , CLuaIHM : : isUIOnStack ( ls , 1 ) | | ls . isNil ( 1 ) , " runAH() requires a UI object in param 1 (or Nil) " ) ;
CLuaIHM : : check ( ls , ls . isString ( 2 ) , " runAH() requires a string in param 2 " ) ;
CLuaIHM : : check ( ls , ls . isString ( 3 ) , " runAH() requires a string in param 3 " ) ;
// retrieve args
CInterfaceElement * pIE = CLuaIHM : : getUIOnStack ( ls , 1 ) ;
std : : string ah , params ;
ls . toString ( 2 , ah ) ;
ls . toString ( 3 , params ) ;
// run AH
// The element must be ctrl (or NULL)
CCtrlBase * ctrl = NULL ;
if ( pIE )
{
ctrl = dynamic_cast < CCtrlBase * > ( pIE ) ;
if ( ! ctrl )
throw ELuaIHMException ( " runAH() : ' % s ' is not a ctrl " , pIE->getId().c_str()) ;
}
CAHManager : : getInstance ( ) - > runActionHandler ( ah , ctrl , params ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : getWindowSize ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_getWindowSize)
CLuaIHM : : checkArgCount ( ls , " getWindowSize " , 0 ) ;
uint32 w , h ;
CViewRenderer : : getInstance ( ) - > getScreenSize ( w , h ) ;
ls . push ( ( double ) w ) ;
ls . push ( ( double ) h ) ;
return 2 ;
}
// ***************************************************************************
int CLuaIHM : : setTopWindow ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_setTopWindow)
const char * funcName = " setTopWindow " ;
CLuaIHM : : checkArgCount ( ls , funcName , 1 ) ;
CInterfaceGroup * wnd = dynamic_cast < CInterfaceGroup * > ( CLuaIHM : : getUIOnStack ( ls , 1 ) ) ;
if ( ! wnd )
{
CLuaIHM : : fails ( ls , " %s : interface group expected as arg 1 " , funcName ) ;
}
CWidgetManager : : getInstance ( ) - > setTopWindow ( wnd ) ;
return 0 ;
}
int CLuaIHM : : getTextureSize ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_getTextureSize)
const char * funcName = " getTextureSize " ;
CLuaIHM : : checkArgCount ( ls , funcName , 1 ) ;
CLuaIHM : : checkArgType ( ls , funcName , 1 , LUA_TSTRING ) ;
std : : string textureName = ls . toString ( 1 ) ;
CBitmap bitmap ;
CIFile fs ( CPath : : lookup ( textureName ) . c_str ( ) ) ;
bitmap . load ( fs ) ;
ls . push ( ( double ) bitmap . getWidth ( ) ) ;
ls . push ( ( double ) bitmap . getHeight ( ) ) ;
return 2 ;
}
// ***************************************************************************
int CLuaIHM : : disableModalWindow ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_disableModalWindow)
CLuaIHM : : checkArgCount ( ls , " disableModalWindow " , 0 ) ;
CWidgetManager : : getInstance ( ) - > disableModalWindow ( ) ;
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : deleteUI ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_deleteUI)
CLuaStackChecker lsc ( & ls , 0 ) ;
// params: CInterfaceElement *
// return: none
CLuaIHM : : checkArgCount ( ls , " deleteUI " , 1 ) ;
CLuaIHM : : check ( ls , CLuaIHM : : isUIOnStack ( ls , 1 ) , " deleteUI() requires a UI object in param 1 " ) ;
// retrieve args
CInterfaceElement * pIE = CLuaIHM : : getUIOnStack ( ls , 1 ) ;
if ( ! pIE )
return 0 ;
// has a parent?
CInterfaceGroup * parent = pIE - > getParent ( ) ;
if ( parent )
{
// correctly remove from parent
parent - > delElement ( pIE ) ;
}
else
{
// just delete
delete pIE ;
}
return 0 ;
}
// ***************************************************************************
int CLuaIHM : : deleteReflectable ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_deleteReflectable)
CLuaStackChecker lsc ( & ls , 0 ) ;
// params: CInterfaceElement *
// return: none
CLuaIHM : : checkArgCount ( ls , " deleteReflectable " , 1 ) ;
CLuaIHM : : check ( ls , CLuaIHM : : isReflectableOnStack ( ls , 1 ) , " deleteReflectable() requires a reflectable C++ object in param 1 " ) ;
// retrieve args
CReflectableRefPtrTarget * pRPT = CLuaIHM : : getReflectableOnStack ( ls , 1 ) ;
if ( ! pRPT )
return 0 ;
CInterfaceElement * pIE = dynamic_cast < CInterfaceElement * > ( pRPT ) ;
if ( pIE )
{
// has a parent?
CInterfaceGroup * parent = pIE - > getParent ( ) ;
if ( parent )
{
// correctly remove from parent
parent - > delElement ( pIE ) ;
}
}
// just delete
delete pIE ;
return 0 ;
}
int CLuaIHM : : getCurrentWindowUnder ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_getCurrentWindowUnder)
CLuaStackChecker lsc ( & ls , 1 ) ;
CInterfaceElement * pIE = CWidgetManager : : getInstance ( ) - > getCurrentWindowUnder ( ) ;
if ( ! pIE )
{
ls . pushNil ( ) ;
nlerror ( " getCurrentWindowUnder(): No UICaller found. return Nil " ) ;
}
else
{
CLuaIHM : : pushUIOnStack ( ls , pIE ) ;
}
return 1 ;
}
// ***************************************************************************
bool CLuaIHM : : fileExists ( const std : : string & fileName )
{
//H_AUTO(Lua_CLuaIHM_fileExists)
return CPath : : exists ( fileName ) ;
}
// ***************************************************************************
int CLuaIHM : : runExprAndPushResult ( CLuaState & ls , const std : : string & expr )
{
//H_AUTO(Lua_CLuaIHM_runExprAndPushResult)
// Execute expression
CInterfaceExprValue value ;
if ( CInterfaceExpr : : eval ( expr , value , NULL ) )
{
switch ( value . getType ( ) )
{
case CInterfaceExprValue : : Boolean :
ls . push ( value . getBool ( ) ) ;
break ;
case CInterfaceExprValue : : Integer :
ls . push ( ( double ) value . getInteger ( ) ) ;
break ;
case CInterfaceExprValue : : Double :
ls . push ( value . getDouble ( ) ) ;
break ;
case CInterfaceExprValue : : String :
{
ucstring ucstr = value . getUCString ( ) ;
// Yoyo: dynamically decide whether must return a string or a ucstring
bool mustUseUCString = false ;
for ( uint i = 0 ; i < ucstr . size ( ) ; i + + )
{
if ( ucstr [ i ] > 255 )
{
mustUseUCString = true ;
break ;
}
}
// push a ucstring?
if ( mustUseUCString )
{
# if LUABIND_VERSION > 600
luabind : : detail : : push ( ls . getStatePointer ( ) , ucstr ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) , ucstr ) ;
obj . pushvalue ( ) ;
# endif
}
else
{
ls . push ( ucstr . toString ( ) ) ;
}
break ;
}
case CInterfaceExprValue : : RGBA :
{
CRGBA color = value . getRGBA ( ) ;
# if LUABIND_VERSION > 600
luabind : : detail : : push ( ls . getStatePointer ( ) , color ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) , color ) ;
obj . pushvalue ( ) ;
# endif
break ;
}
break ;
case CInterfaceExprValue : : UserType : // Yoyo: don't care UserType...
default :
ls . pushNil ( ) ;
break ;
}
}
else
ls . pushNil ( ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : runExpr ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_runExpr)
CLuaStackChecker lsc ( & ls , 1 ) ;
// params: "expr".
// return: any of: nil, bool, string, number, RGBA, UCString
CLuaIHM : : checkArgCount ( ls , " runExpr " , 1 ) ;
CLuaIHM : : check ( ls , ls . isString ( 1 ) , " runExpr() requires a string in param 1 " ) ;
// retrieve args
std : : string expr ;
ls . toString ( 1 , expr ) ;
// run expression and push result
return runExprAndPushResult ( ls , expr ) ;
}
// ***************************************************************************
int CLuaIHM : : runFct ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_runFct)
CLuaStackChecker lsc ( & ls , 1 ) ;
// params: "expr", param1, param2...
// return: any of: nil, bool, string, number, RGBA, UCString
CLuaIHM : : checkArgMin ( ls , " runFct " , 1 ) ;
CLuaIHM : : check ( ls , ls . isString ( 1 ) , " runExpr() requires a string in param 1 " ) ;
// retrieve fct
std : : string expr ;
ls . toString ( 1 , expr ) ;
expr + = " ( " ;
// retrieve params
uint top = ls . getTop ( ) ;
for ( uint i = 2 ; i < = top ; i + + )
{
if ( i > 2 )
expr + = " , " ;
// If it is a number
if ( ls . type ( i ) = = LUA_TNUMBER )
{
std : : string paramValue ;
ls . toString ( i , paramValue ) ; // nb: transformed to a string in the stack
expr + = paramValue ;
}
// else suppose a string
else
{
// must enclose with "'"
std : : string paramValue ;
ls . toString ( i , paramValue ) ;
expr + = std : : string ( " ' " ) + paramValue + std : : string ( " ' " ) ;
}
}
// end fct call
expr + = " ) " ;
// run expression and push result
return runExprAndPushResult ( ls , expr ) ;
}
// ***************************************************************************
int CLuaIHM : : runCommand ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_runCommand)
CLuaStackChecker lsc ( & ls , 1 ) ;
if ( ls . empty ( ) )
{
nlwarning ( " 'runCommand' : Command name expected " ) ;
ls . push ( false ) ;
return 1 ;
}
const char * commandName = ls . toString ( 1 ) ;
if ( ! commandName )
{
nlwarning ( " 'runCommand' : Bad command name " ) ;
ls . push ( false ) ;
return 1 ;
}
if ( ! NLMISC : : ICommand : : LocalCommands | | ! NLMISC : : ICommand : : LocalCommands - > count ( ls . toString ( 1 ) ) )
{
nlwarning ( " 'runCommand' : Command %s not found " , ls . toString ( 1 ) ) ;
ls . push ( false ) ;
return 1 ;
}
std : : string rawCommandString = ls . toString ( 1 ) ;
NLMISC : : ICommand * command = ( * NLMISC : : ICommand : : LocalCommands ) [ ls . toString ( 1 ) ] ;
nlassert ( command ) ;
std : : vector < std : : string > args ( ls . getTop ( ) - 1 ) ;
for ( uint k = 2 ; k < = ( uint ) ls . getTop ( ) ; + + k )
{
if ( ls . toString ( k ) )
{
args [ k - 2 ] = ls . toString ( k ) ;
rawCommandString + = " " + std : : string ( ls . toString ( k ) ) ;
}
}
ls . push ( command - > execute ( rawCommandString , args , NLMISC : : ErrorLog ( ) , false , true ) ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : isUCString ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_isUCString)
const char * funcName = " isUCString " ;
CLuaIHM : : checkArgCount ( ls , funcName , 1 ) ;
ls . push ( CLuaIHM : : isUCStringOnStack ( ls , 1 ) ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : concatUCString ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_concatUCString)
const char * funcName = " concatUCString " ;
ucstring result ;
for ( uint k = 1 ; k < = ( uint ) ls . getTop ( ) ; + + k )
{
//nlwarning("arg %d = %s", k, ls.getTypename(ls.type(k)));
ucstring part ;
if ( ls . isString ( k ) )
{
part . fromUtf8 ( ls . toString ( k ) ) ;
}
else
{
CLuaIHM : : checkArgTypeUCString ( ls , funcName , k ) ;
nlverify ( CLuaIHM : : getUCStringOnStack ( ls , k , part ) ) ;
}
result + = part ;
}
CLuaIHM : : push ( ls , result ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : concatString ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_concatUCString)
const char * funcName = " concatString " ;
std : : string result ;
uint stackSize = ls . getTop ( ) ;
for ( uint k = 1 ; k < = stackSize ; + + k )
{
CLuaIHM : : checkArgType ( ls , funcName , k , LUA_TSTRING ) ;
result + = ls . toString ( k ) ;
}
ls . push ( result ) ;
return 1 ;
}
// ***************************************************************************
int CLuaIHM : : tableToString ( CLuaState & ls )
{
const char * funcName = " tableToString " ;
CLuaIHM : : checkArgCount ( ls , funcName , 1 ) ;
CLuaIHM : : checkArgType ( ls , funcName , 1 , LUA_TTABLE ) ;
uint length = 0 ;
// compute size
ls . pushNil ( ) ;
while ( ls . next ( - 2 ) )
{
ls . toString ( - 1 ) ;
length + = ( uint ) ls . strlen ( - 1 ) ;
ls . pop ( 2 ) ;
}
std : : string result ;
result . resize ( length ) ;
char * dest = & result [ 0 ] ;
// concatenate
ls . pushNil ( ) ;
while ( ls . next ( - 2 ) )
{
uint length = ( uint ) ls . strlen ( - 1 ) ;
if ( length )
{
memcpy ( dest , ls . toString ( - 1 ) , length ) ;
}
dest + = length ;
ls . pop ( 2 ) ;
}
ls . push ( result ) ;
return 1 ;
}
int CLuaIHM : : getPathContent ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_getPathContent)
const char * funcName = " getPathContent " ;
CLuaIHM : : checkArgCount ( ls , funcName , 1 ) ;
CLuaIHM : : checkArgType ( ls , funcName , 1 , LUA_TSTRING ) ;
std : : vector < std : : string > files ;
NLMISC : : CPath : : getPathContent ( ls . toString ( 1 ) , false , false , true , files ) ;
ls . newTable ( ) ;
for ( uint k = 0 ; k < files . size ( ) ; + + k )
{
ls . push ( ( double ) k ) ;
ls . push ( files [ k ] ) ;
ls . setTable ( - 3 ) ;
}
return 1 ;
}
// ***************************************************************************
void CLuaIHM : : luaValueFromReflectedProperty ( CLuaState & ls , CReflectable & reflectedObject , const CReflectedProperty & property )
{
//H_AUTO(Lua_CLuaIHM_luaValueFromReflectedProperty)
switch ( property . Type )
{
case CReflectedProperty : : Boolean :
ls . push ( ( reflectedObject . * ( property . GetMethod . GetBool ) ) ( ) ) ;
break ;
case CReflectedProperty : : SInt32 :
ls . push ( ( lua_Number ) ( reflectedObject . * ( property . GetMethod . GetSInt32 ) ) ( ) ) ;
break ;
case CReflectedProperty : : Float :
ls . push ( ( lua_Number ) ( reflectedObject . * ( property . GetMethod . GetFloat ) ) ( ) ) ;
break ;
case CReflectedProperty : : String :
ls . push ( ( reflectedObject . * ( property . GetMethod . GetString ) ) ( ) ) ;
break ;
case CReflectedProperty : : UCString :
{
ucstring str = ( reflectedObject . * ( property . GetMethod . GetUCString ) ) ( ) ;
# if LUABIND_VERSION > 600
luabind : : detail : : push ( ls . getStatePointer ( ) , str ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) , str ) ;
obj . pushvalue ( ) ;
# endif
}
break ;
case CReflectedProperty : : RGBA :
{
CRGBA color = ( reflectedObject . * ( property . GetMethod . GetRGBA ) ) ( ) ;
# if LUABIND_VERSION > 600
luabind : : detail : : push ( ls . getStatePointer ( ) , color ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) , color ) ;
obj . pushvalue ( ) ;
# endif
}
break ;
case CReflectedProperty : : LuaMethod :
{
// must create a closure that will forward the call to the real method
if ( ! property . LuaMethodRef . isValid ( ) )
{
ls . pushLightUserData ( ( void * ) & property ) ;
ls . pushLightUserData ( ( void * ) & ls ) ;
ls . pushCClosure ( luaMethodCall , 2 ) ;
property . LuaMethodRef . pop ( ls ) ;
}
nlassert ( property . LuaMethodRef . getLuaState ( ) = = & ls ) ; // only one single lua state supported for now
property . LuaMethodRef . push ( ) ;
}
break ;
default :
nlstop ;
break ;
}
}
// ***************************************************************************
void CLuaIHM : : luaValueToReflectedProperty ( CLuaState & ls , int stackIndex , CReflectable & target , const CReflectedProperty & property ) throw ( ELuaIHMException )
{
//H_AUTO(Lua_property_throw)
if ( ls . isNil ( stackIndex ) )
throw ELuaIHMException ( " Trying to set nil to UI property '%s' " , property . Name . c_str ( ) ) ;
switch ( property . Type )
{
case CReflectedProperty : : Boolean :
{
bool val = ls . toBoolean ( stackIndex ) ;
( target . * ( property . SetMethod . SetBool ) ) ( val ) ;
return ;
}
case CReflectedProperty : : SInt32 :
{
sint32 val = ( sint32 ) ls . toNumber ( stackIndex ) ;
( target . * ( property . SetMethod . SetSInt32 ) ) ( val ) ;
return ;
}
case CReflectedProperty : : UInt32 :
{
uint32 val = ( uint32 ) ls . toNumber ( stackIndex ) ;
( target . * ( property . SetMethod . SetUInt32 ) ) ( val ) ;
return ;
}
case CReflectedProperty : : Float :
{
float val = ( float ) ls . toNumber ( stackIndex ) ;
( target . * ( property . SetMethod . SetFloat ) ) ( val ) ;
return ;
}
case CReflectedProperty : : String :
{
std : : string val ;
ls . toString ( stackIndex , val ) ;
( target . * ( property . SetMethod . SetString ) ) ( val ) ;
return ;
}
case CReflectedProperty : : UCString :
{
ucstring val ;
// Additionaly return of CInterfaceExpr may be std::string... test std string too
if ( ls . isString ( ) | | ls . isNumber ( ) )
{
std : : string str ;
ls . toString ( stackIndex , str ) ;
val = str ;
}
else
{
// else this should be a ucstring
if ( ! pop ( ls , val ) )
{
throw ELuaIHMException ( " You must set a string, number or ucstring to UI property '%s' " , property . Name . c_str ( ) ) ;
}
}
( target . * ( property . SetMethod . SetUCString ) ) ( val ) ;
return ;
}
case CReflectedProperty : : RGBA :
{
CRGBA color ;
if ( pop ( ls , color ) )
{
( target . * ( property . SetMethod . SetRGBA ) ) ( color ) ;
}
else
{
throw ELuaIHMException ( " You must set a CRGBA to UI property '%s' " , property . Name . c_str ( ) ) ;
}
return ;
}
default :
nlstop ;
}
}
// ***************************************************************************
void CLuaIHM : : createLuaEnumTable ( CLuaState & ls , const std : : string & str )
{
//H_AUTO(Lua_CLuaIHM_createLuaEnumTable)
std : : string path = " " , script , p ;
CSString s = str ;
// Create table recursively (ex: 'game.TPVPClan' will check/create the table 'game' and 'game.TPVPClan')
p = s . splitTo ( ' . ' , true ) ;
while ( p . size ( ) > 0 )
{
if ( path . empty ( ) )
path = p ;
else
path + = " . " + p ;
script = " if ( " + path + " == nil) then " + path + " = {}; end " ;
ls . executeScript ( script ) ;
p = s . splitTo ( ' . ' , true ) ;
}
}
# define LUABIND_ENUM(__enum__, __name__, __num__, __toStringFunc__) \
createLuaEnumTable ( ls , __name__ ) ; \
for ( uint e = 0 ; e < __num__ ; e + + ) \
{ \
std : : string str = __toStringFunc__ ( ( __enum__ ) e ) ; \
std : : string temp = __name__ + toString ( " . " ) + __toStringFunc__ ( ( __enum__ ) e ) + " = " + toString ( " %d; " , e ) ; \
ls . executeScript ( temp ) ; \
} \
// ***************************************************************************
# define LUABIND_FUNC(__func__) luabind::def(#__func__, &__func__)
void CLuaIHM : : registerIHM ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_registerIHM)
CLuaStackChecker lsc ( & ls ) ;
// *** Register a Table for ui env.
ls . push ( IHM_LUA_ENVTABLE ) ; // "__ui_envtable"
ls . newTable ( ) ; // "__ui_envtable" {}
ls . setTable ( LUA_REGISTRYINDEX ) ;
// *** Register the MetaTable for UI userdata
ls . push ( IHM_LUA_METATABLE ) ; // "__ui_metatable"
ls . newTable ( ) ; // "__ui_metatable" {}
// set the '__index' method
ls . push ( " __index " ) ;
ls . push ( luaUIIndex ) ;
nlassert ( ls . isCFunction ( ) ) ;
ls . setTable ( - 3 ) ; // "__ui_metatable" {"__index"= CFunc_luaUIIndex}
// set the '__newindex' method
ls . push ( " __newindex " ) ;
ls . push ( luaUINewIndex ) ;
nlassert ( ls . isCFunction ( ) ) ;
ls . setTable ( - 3 ) ;
// set the '__newindex' method
ls . push ( " __gc " ) ;
ls . push ( luaUIDtor ) ;
nlassert ( ls . isCFunction ( ) ) ;
ls . setTable ( - 3 ) ;
// set the '__eq' method
ls . push ( " __eq " ) ;
ls . push ( luaUIEq ) ;
nlassert ( ls . isCFunction ( ) ) ;
ls . setTable ( - 3 ) ;
// set the custom '__next' method
ls . push ( " __next " ) ;
ls . push ( luaUINext ) ;
nlassert ( ls . isCFunction ( ) ) ;
ls . setTable ( - 3 ) ;
// set registry
ls . setTable ( LUA_REGISTRYINDEX ) ;
// *** Register Functions
ls . registerFunc ( " setOnDraw " , setOnDraw ) ;
ls . registerFunc ( " setCaptureKeyboard " , setCaptureKeyboard ) ;
ls . registerFunc ( " resetCaptureKeyboard " , resetCaptureKeyboard ) ;
ls . registerFunc ( " setTopWindow " , setTopWindow ) ;
ls . registerFunc ( " addOnDbChange " , addOnDbChange ) ;
ls . registerFunc ( " removeOnDbChange " , removeOnDbChange ) ;
ls . registerFunc ( " getUIId " , getUIId ) ;
ls . registerFunc ( " runAH " , runAH ) ;
ls . registerFunc ( " deleteUI " , deleteUI ) ;
ls . registerFunc ( " deleteReflectable " , deleteReflectable ) ;
ls . registerFunc ( " getWindowSize " , getWindowSize ) ;
ls . registerFunc ( " getTextureSize " , getTextureSize ) ;
ls . registerFunc ( " disableModalWindow " , disableModalWindow ) ;
ls . registerFunc ( " isUCString " , isUCString ) ;
ls . registerFunc ( " concatUCString " , concatUCString ) ;
ls . registerFunc ( " concatString " , concatString ) ;
ls . registerFunc ( " tableToString " , tableToString ) ;
ls . registerFunc ( " getCurrentWindowUnder " , getCurrentWindowUnder ) ;
ls . registerFunc ( " runExpr " , runExpr ) ;
ls . registerFunc ( " runFct " , runFct ) ;
ls . registerFunc ( " runCommand " , runCommand ) ;
ls . registerFunc ( " getPathContent " , getPathContent ) ;
// Through LUABind API
lua_State * L = ls . getStatePointer ( ) ;
luabind : : module ( L )
[
luabind : : def ( " findReplaceAll " , ( std : : string ( * ) ( const std : : string & , const std : : string & , const std : : string & ) ) & findReplaceAll ) ,
luabind : : def ( " findReplaceAll " , ( ucstring ( * ) ( const ucstring & , const ucstring & , const ucstring & ) ) & findReplaceAll ) ,
luabind : : def ( " findReplaceAll " , ( ucstring ( * ) ( const ucstring & , const std : : string & , const std : : string & ) ) & findReplaceAll ) ,
luabind : : def ( " findReplaceAll " , ( ucstring ( * ) ( const ucstring & , const ucstring & , const std : : string & ) ) & findReplaceAll ) ,
luabind : : def ( " findReplaceAll " , ( ucstring ( * ) ( const ucstring & , const std : : string & , const ucstring & ) ) & findReplaceAll ) ,
# if !FINAL_VERSION
LUABIND_FUNC ( openDoc ) ,
LUABIND_FUNC ( launchProgram ) ,
# endif
luabind : : def ( " fileLookup " , CMiscFunctions : : fileLookup ) ,
luabind : : def ( " shellExecute " , CMiscFunctions : : shellExecute ) ,
LUABIND_FUNC ( fileExists )
] ;
// inside i18n table
luabind : : module ( L , " i18n " )
[
luabind : : def ( " get " , & CI18N : : get ) ,
luabind : : def ( " hasTranslation " , & CI18N : : hasTranslation )
] ;
// inside 'nlfile' table
luabind : : module ( L , " nlfile " )
[
luabind : : def ( " getFilename " , NLMISC : : CFile : : getFilename ) ,
luabind : : def ( " getExtension " , NLMISC : : CFile : : getExtension ) ,
luabind : : def ( " getFilenameWithoutExtension " , NLMISC : : CFile : : getFilenameWithoutExtension )
] ;
// inside 'nltime' table
luabind : : module ( L , " nltime " )
[
luabind : : def ( " getPreciseLocalTime " , getPreciseLocalTime ) ,
luabind : : def ( " getSecondsSince1970 " , NLMISC : : CTime : : getSecondsSince1970 ) ,
luabind : : def ( " getLocalTime " , getLocalTime ) // NB : use CLuaIHM::getLocalTime instead of NLMISC::CTime::getLocalTime, because the NLMISC
// version returns a uint64, which can't be casted into lua numbers (doubles ...)
] ;
}
// ***************************************************************************
double CLuaIHM : : getPreciseLocalTime ( )
{
//H_AUTO(Lua_CLuaIHM_getPreciseLocalTime)
// don't export these 2 function to lua directly here, because all uint64 can't be represented with lua 'numbers'
return NLMISC : : CTime : : ticksToSecond ( NLMISC : : CTime : : getPerformanceTime ( ) ) ;
}
// ***************************************************************************
void CLuaIHM : : registerAll ( CLuaState & ls )
{
//H_AUTO(Lua_CLuaIHM_registerAll)
registerBasics ( ls ) ;
registerIHM ( ls ) ;
}
//#define CHECK_REFLECTABLE_MT
// ***************************************************************************
void CLuaIHM : : pushReflectableOnStack ( CLuaState & ls , class CReflectableRefPtrTarget * pRPT )
{
//H_AUTO(Lua_CLuaIHM_pushReflectableOnStack)
nlassert ( pRPT ) ;
CLuaStackChecker lsc ( & ls , 1 ) ;
if ( ! pRPT )
{
ls . pushNil ( ) ;
return ;
}
//ls.dumpStack();
/** if there's already a ref ptr for this object in the registry, then use it,
* else create a new one to avoid costly allocations
*/
ls . pushLightUserData ( pRPT ) ;
ls . getTable ( LUA_REGISTRYINDEX ) ;
//ls.dumpStack();
if ( ls . isNil ( ) )
{
ls . pop ( 1 ) ;
//ls.dumpStack();
// allocate the user data where to put the ref ptr
void * ptr = ls . newUserData ( sizeof ( CReflectableLuaRef ) ) ;
nlassert ( ptr ) ;
//ls.dumpStack();
// initialize it, and copy the given element
new ( ptr ) CReflectableLuaRef ( pRPT ) ;
// Assign to this user data the __ui_metatable
//ls.dumpStack();
ls . push ( IHM_LUA_METATABLE ) ; // userdata "__ui_metatable"
//ls.dumpStack();
ls . getTable ( LUA_REGISTRYINDEX ) ; // userdata __ui_metatable
//ls.dumpStack();
nlverify ( ls . setMetaTable ( - 2 ) ) ; // userdata
//ls.dumpStack();
// cache in registry
ls . pushLightUserData ( pRPT ) ;
ls . pushValue ( - 2 ) ; // copy for table insertion
//ls.dumpStack();
ls . setTable ( LUA_REGISTRYINDEX ) ;
//ls.dumpStack();
}
// Check that the metatable is correct
# ifdef CHECK_REFLECTABLE_MT
nlverify ( ls . getMetaTable ( - 1 ) ) ; // userdata __ui_metatable
ls . push ( " __index " ) ;
ls . getTable ( - 2 ) ;
ls . push ( " __newindex " ) ;
ls . getTable ( - 3 ) ;
ls . push ( " __gc " ) ;
ls . getTable ( - 4 ) ;
nlassert ( ls . isCFunction ( - 1 ) ) ;
nlassert ( ls . isCFunction ( - 2 ) ) ;
nlassert ( ls . isCFunction ( - 3 ) ) ;
ls . pop ( 4 ) ;
# endif
//ls.dumpStack();
}
// ***************************************************************************
bool CLuaIHM : : isReflectableOnStack ( CLuaState & ls , sint index )
{
//H_AUTO(Lua_CLuaIHM_isReflectableOnStack)
CLuaStackChecker lsc ( & ls ) ;
if ( ! ls . isUserData ( index ) )
return false ;
// verify that it is a UI with its metatable
if ( ! ls . getMetaTable ( index ) ) // ??? object_metatable
return false ;
ls . push ( IHM_LUA_METATABLE ) ; // ??? object_metatable "__ui_metatable"
ls . getTable ( LUA_REGISTRYINDEX ) ; // ??? object_metatable __ui_metatable
// equal test
bool ok = ls . rawEqual ( - 2 , - 1 ) ;
// Also must not be nil (maybe nil in case of LuaIHM still not registered)
ok = ok & & ! ls . isNil ( - 1 ) ;
ls . pop ( ) ;
ls . pop ( ) ;
return ok ;
}
// ***************************************************************************
CReflectableRefPtrTarget * CLuaIHM : : getReflectableOnStack ( CLuaState & ls , sint index )
{
//H_AUTO(Lua_CLuaIHM_getReflectableOnStack)
if ( ! isReflectableOnStack ( ls , index ) )
return NULL ;
CReflectableLuaRef * p = ( CReflectableLuaRef * ) ls . toUserData ( index ) ;
nlassert ( p - > Ptr ) ;
return p - > Ptr ;
}
// ***************************************************************************
// ***************************************************************************
// LUA IHM Functions
// ***************************************************************************
// ***************************************************************************
// ***************************************************************************
uint32 CLuaIHM : : getLocalTime ( )
{
//H_AUTO(Lua_CLuaIHM_getLocalTime)
return ( uint32 ) NLMISC : : CTime : : getLocalTime ( ) ;
}
// ***************************************************************************
std : : string CLuaIHM : : findReplaceAll ( const std : : string & str , const std : : string & search , const std : : string & replace )
{
//H_AUTO(Lua_CLuaIHM_findReplaceAll)
std : : string ret = str ;
while ( strFindReplace ( ret , search , replace ) ) ;
return ret ;
}
// ***************************************************************************
ucstring CLuaIHM : : findReplaceAll ( const ucstring & str , const ucstring & search , const ucstring & replace )
{
//H_AUTO(Lua_CLuaIHM_findReplaceAll)
ucstring ret = str ;
while ( strFindReplace ( ret , search , replace ) ) ;
return ret ;
}
// ***************************************************************************
ucstring CLuaIHM : : findReplaceAll ( const ucstring & str , const std : : string & search , const std : : string & replace )
{
//H_AUTO(Lua_CLuaIHM_findReplaceAll)
return findReplaceAll ( str , ucstring ( search ) , ucstring ( replace ) ) ;
}
// ***************************************************************************
ucstring CLuaIHM : : findReplaceAll ( const ucstring & str , const std : : string & search , const ucstring & replace )
{
//H_AUTO(Lua_CLuaIHM_findReplaceAll)
return findReplaceAll ( str , ucstring ( search ) , ucstring ( replace ) ) ;
}
// ***************************************************************************
ucstring CLuaIHM : : findReplaceAll ( const ucstring & str , const ucstring & search , const std : : string & replace )
{
//H_AUTO(Lua_CLuaIHM_findReplaceAll)
return findReplaceAll ( str , ucstring ( search ) , ucstring ( replace ) ) ;
}
// ***************************************************************************
void CLuaIHM : : fails ( CLuaState & ls , const char * format , . . . )
{
//H_AUTO(Lua_CLuaIHM_fails)
std : : string reason ;
NLMISC_CONVERT_VARGS ( reason , format , NLMISC : : MaxCStringSize ) ;
std : : string stack ;
ls . getStackAsString ( stack ) ;
// use a std::exception, to avoid Nel Exception warning
throw ELuaIHMException ( " %s. Lua stack = \n %s " , reason . c_str ( ) , stack . c_str ( ) ) ;
}
// ***************************************************************************
void CLuaIHM : : checkArgCount ( CLuaState & ls , const char * funcName , uint nArgs )
{
//H_AUTO(Lua_CLuaIHM_checkArgCount)
if ( ls . getTop ( ) ! = ( sint ) nArgs )
{
fails ( ls , " %s() need exactly %d arguments (tips : check between method & function call) " , funcName , nArgs ) ;
}
}
// ***************************************************************************
void CLuaIHM : : checkArgMin ( CLuaState & ls , const char * funcName , uint nArgs )
{
//H_AUTO(Lua_CLuaIHM_checkArgMin)
if ( ls . getTop ( ) < ( sint ) nArgs )
{
fails ( ls , " %s() need at least %d arguments (tips : check between method & function call) " , funcName , nArgs ) ;
}
}
// ***************************************************************************
void CLuaIHM : : checkArgMax ( CLuaState & ls , const char * funcName , uint nArgs )
{
//H_AUTO(Lua_CLuaIHM_checkArgMax)
if ( ls . getTop ( ) > ( sint ) nArgs )
{
fails ( ls , " %s() need at most %d arguments. " , funcName , nArgs ) ;
}
}
// ***************************************************************************
void CLuaIHM : : check ( CLuaState & ls , bool ok , const std : : string & failReason )
{
//H_AUTO(Lua_CLuaIHM_check)
if ( ! ok )
{
fails ( ls , failReason . c_str ( ) ) ;
}
}
// ***************************************************************************
void CLuaIHM : : checkArgType ( CLuaState & ls , const char * funcName , uint index , int argType )
{
//H_AUTO(Lua_CLuaIHM_checkArgType)
nlassert ( index > 0 ) ;
if ( ls . getTop ( ) < ( int ) index )
{
fails ( ls , " %s : argument %d of expected type %s was not defined " , funcName , index , ls . getTypename ( argType ) ) ;
}
if ( ls . type ( index ) ! = argType )
{
fails ( ls , " %s : argument %d of expected type %s has bad type : %s " , funcName , index , ls . getTypename ( argType ) , ls . getTypename ( ls . type ( index ) ) , ls . type ( index ) ) ;
}
}
// ***************************************************************************
void CLuaIHM : : checkArgTypeRGBA ( CLuaState & ls , const char * funcName , uint index )
{
//H_AUTO(Lua_CLuaIHM_checkArgTypeRGBA)
nlassert ( index > 0 ) ;
if ( ls . getTop ( ) < ( int ) index )
{
fails ( ls , " %s : argument %d of expected type RGBA was not defined " , funcName , index ) ;
}
ls . pushValue ( index ) ;
CRGBA dummy ;
if ( ! pop ( ls , dummy ) )
{
fails ( ls , " %s : argument %d of expected type RGBA has bad type : %s " , funcName , index , ls . getTypename ( ls . type ( index ) ) , ls . type ( index ) ) ;
}
}
// ***************************************************************************
void CLuaIHM : : checkArgTypeUCString ( CLuaState & ls , const char * funcName , uint index )
{
//H_AUTO(Lua_CLuaIHM_checkArgTypeUCString)
nlassert ( index > 0 ) ;
if ( ls . getTop ( ) < ( int ) index )
{
fails ( ls , " %s : argument %d of expected type ucstring was not defined " , funcName , index ) ;
}
ls . pushValue ( index ) ;
ucstring dummy ;
if ( ! pop ( ls , dummy ) )
{
fails ( ls , " %s : argument %d of expected type ucstring has bad type : %s " , funcName , index , ls . getTypename ( ls . type ( index ) ) , ls . type ( index ) ) ;
}
}
// ***************************************************************************
bool CLuaIHM : : popString ( CLuaState & ls , std : : string & dest )
{
//H_AUTO(Lua_CLuaIHM_popString)
try
{
# if LUABIND_VERSION > 600
luabind : : object obj ( luabind : : from_stack ( ls . getStatePointer ( ) , - 1 ) ) ;
ls . pop ( ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) ) ;
obj . set ( ) ;
# endif
dest = luabind : : object_cast < std : : string > ( obj ) ;
}
catch ( const luabind : : cast_failed & )
{
return false ;
}
return true ;
}
// ***************************************************************************
bool CLuaIHM : : popSINT32 ( CLuaState & ls , sint32 & dest )
{
//H_AUTO(Lua_CLuaIHM_popSINT32)
try
{
# if LUABIND_VERSION > 600
luabind : : object obj ( luabind : : from_stack ( ls . getStatePointer ( ) , - 1 ) ) ;
ls . pop ( ) ;
# else
luabind : : object obj ( ls . getStatePointer ( ) ) ;
obj . set ( ) ;
# endif
dest = luabind : : object_cast < sint32 > ( obj ) ;
}
catch ( const luabind : : cast_failed & )
{
return false ;
}
return true ;
}
// ***************************************************************************
void CLuaIHM : : getPoly2DOnStack ( CLuaState & ls , sint index , NLMISC : : CPolygon2D & dest )
{
//H_AUTO(Lua_CLuaIHM_getPoly2DOnStack)
ls . pushValue ( index ) ;
CLuaObject poly ;
poly . pop ( ls ) ;
dest . Vertices . clear ( ) ;
ENUM_LUA_TABLE ( poly , it )
{
it . nextValue ( ) . push ( ) ;
NLMISC : : CVector2f pos ;
if ( ! pop ( ls , pos ) )
{
fails ( ls , " 2D polygon expects CVector2f for poly coordinates " ) ;
}
dest . Vertices . push_back ( pos ) ;
}
}
}