From f769f6fb0cb942b768073bc59479e16811502a34 Mon Sep 17 00:00:00 2001 From: dfighter1985 Date: Wed, 23 May 2012 19:40:41 +0200 Subject: [PATCH] CHANGED: #1471 Moved the stuff I moved to NELGUI library, under the NLGUI namespace. --HG-- branch : gui-refactoring --- code/nel/include/nel/gui/lua_ihm.h | 204 +-- code/nel/include/nel/gui/lua_manager.h | 60 +- code/nel/include/nel/gui/lua_object.h | 516 +++--- code/nel/include/nel/gui/reflect.h | 659 ++++--- code/nel/src/gui/lua_ihm.cpp | 1611 +++++++++-------- code/nel/src/gui/lua_manager.cpp | 27 +- code/nel/src/gui/lua_object.cpp | 1157 ++++++------ code/nel/src/gui/reflect.cpp | 285 +-- code/ryzom/client/src/decal_anim.h | 8 +- .../src/interface_v3/interface_element.h | 2 + .../client/src/interface_v3/interface_link.h | 10 +- .../client/src/interface_v3/lua_ihm_ryzom.h | 4 +- code/ryzom/client/src/r2/displayer_base.h | 6 +- .../client/src/r2/entity_custom_select_box.h | 7 +- .../ryzom/client/src/r2/lua_event_forwarder.h | 4 +- code/ryzom/client/src/r2/prim_render.h | 6 +- code/ryzom/client/src/r2/tool.h | 3 +- code/ryzom/client/src/r2/tool_choose_pos.h | 6 +- .../ryzom/client/src/r2/tool_choose_pos_lua.h | 5 +- code/ryzom/client/src/r2/tool_create_entity.h | 6 +- code/ryzom/client/src/r2/tool_draw_prim.h | 6 +- 21 files changed, 2318 insertions(+), 2274 deletions(-) diff --git a/code/nel/include/nel/gui/lua_ihm.h b/code/nel/include/nel/gui/lua_ihm.h index 8eecb2da5..bd7b5627a 100644 --- a/code/nel/include/nel/gui/lua_ihm.h +++ b/code/nel/include/nel/gui/lua_ihm.h @@ -19,8 +19,9 @@ #include "nel/misc/types_nl.h" #include "nel/gui/lua_helper.h" -using namespace NLGUI; +#define IHM_LUA_METATABLE "__ui_metatable" +#define IHM_LUA_ENVTABLE "__ui_envtable" namespace NLMISC { @@ -29,133 +30,122 @@ namespace NLMISC class CRGBA; } -class CReflectable; -class CReflectedProperty; - -// *************************************************************************** -/* Use this Exception for all LUA Error (eg: scripted passes bad number of paramters). - * Does not herit from Exception because avoid nlinfo, because sent twice (catch then resent) - * This is special to lua and IHM since it works with CLuaStackChecker, and also append to the error msg - * the FileName/LineNumber - */ -class ELuaIHMException : public ELuaWrappedFunctionException +namespace NLGUI { -private: - static CLuaState *getLuaState(); -public: - ELuaIHMException() : ELuaWrappedFunctionException(getLuaState()) + + class CReflectable; + class CReflectedProperty; + + // *************************************************************************** + /* Use this Exception for all LUA Error (eg: scripted passes bad number of paramters). + * Does not herit from Exception because avoid nlinfo, because sent twice (catch then resent) + * This is special to lua and IHM since it works with CLuaStackChecker, and also append to the error msg + * the FileName/LineNumber + */ + class ELuaIHMException : public ELuaWrappedFunctionException { - } - ELuaIHMException(const std::string &reason) : ELuaWrappedFunctionException(getLuaState(), reason) + private: + static CLuaState *getLuaState(); + public: + ELuaIHMException() : ELuaWrappedFunctionException(getLuaState()) + { + } + ELuaIHMException(const std::string &reason) : ELuaWrappedFunctionException(getLuaState(), reason) + { + } + ELuaIHMException(const char *format, ...) : ELuaWrappedFunctionException(getLuaState()) + { + std::string reason; + NLMISC_CONVERT_VARGS (reason, format, NLMISC::MaxCStringSize); + init(getLuaState(), reason); + } + }; + + // *************************************************************************** + /** + * Define Functions to export from C to LUA + * \author Lionel Berenguier + * \author Nevrax France + * \date 2004 + */ + class CLuaIHM { - } - ELuaIHMException(const char *format, ...) : ELuaWrappedFunctionException(getLuaState()) - { - std::string reason; - NLMISC_CONVERT_VARGS (reason, format, NLMISC::MaxCStringSize); - init(getLuaState(), reason); - } -}; + public: + static void registerAll(CLuaState &ls); + + /** CReflectableInterfaceElement management on stack, stored by a CRefPtr. + * May be called as well for ui element, because they derive from CReflectableRefPtrTarget + */ + static void pushReflectableOnStack(CLuaState &ls, class CReflectableRefPtrTarget *pRPT); + static bool isReflectableOnStack(CLuaState &ls, sint index); + static CReflectableRefPtrTarget *getReflectableOnStack(CLuaState &ls, sint index); -// *************************************************************************** -#define IHM_LUA_METATABLE "__ui_metatable" -#define IHM_LUA_ENVTABLE "__ui_envtable" + // ucstring + static bool pop(CLuaState &ls, ucstring &dest); + static void push(CLuaState &ls, const ucstring &value); + static bool isUCStringOnStack(CLuaState &ls, sint index); + static bool getUCStringOnStack(CLuaState &ls, sint index, ucstring &dest); -// *************************************************************************** -/** - * Define Functions to export from C to LUA - * \author Lionel Berenguier - * \author Nevrax France - * \date 2004 - */ -class CLuaIHM -{ -public: - static void registerAll(CLuaState &ls); + // RGBA + static bool pop(CLuaState &ls, NLMISC::CRGBA &dest); - /** CReflectableInterfaceElement management on stack, stored by a CRefPtr. - * May be called as well for ui element, because they derive from CReflectableRefPtrTarget - */ - static void pushReflectableOnStack(CLuaState &ls, class CReflectableRefPtrTarget *pRPT); - static bool isReflectableOnStack(CLuaState &ls, sint index); - static CReflectableRefPtrTarget *getReflectableOnStack(CLuaState &ls, sint index); + // CVector2f + static bool pop(CLuaState &ls, NLMISC::CVector2f &dest); + // helper : get a 2D poly (a table of cvector2f) from a lua table (throw on fail) + static void getPoly2DOnStack(CLuaState &ls, sint index, NLMISC::CPolygon2D &dest); - // ucstring - static bool pop(CLuaState &ls, ucstring &dest); - static void push(CLuaState &ls, const ucstring &value); - static bool isUCStringOnStack(CLuaState &ls, sint index); - static bool getUCStringOnStack(CLuaState &ls, sint index, ucstring &dest); + // argument checkin helpers + static void checkArgCount(CLuaState &ls, const char* funcName, uint nArgs); // check that number of argument is exactly the one required + static void checkArgMin(CLuaState &ls, const char* funcName, uint nArgs); // check that number of argument is at least the one required + static void checkArgMax(CLuaState &ls, const char* funcName, uint nArgs); // check that number of argument is at most the one required + static void check(CLuaState &ls, bool ok, const std::string &failReason); + static void checkArgType(CLuaState &ls, const char *funcName, uint index, int argType); + static void checkArgTypeRGBA(CLuaState &ls, const char *funcName, uint index); + static void checkArgTypeUCString(CLuaState &ls, const char *funcName, uint index); + /** throw a lua expection (inside a C function called from lua) with the given reason, and the current call stack + * The various check... function call this function when their test fails + */ + static void fails(CLuaState &ls, const char *format, ...); + // pop a sint32 from a lua stack, throw an exception on fail + static bool popSINT32(CLuaState &ls, sint32 & dest); + bool popString(CLuaState &ls, std::string & dest); - // RGBA - static bool pop(CLuaState &ls, NLMISC::CRGBA &dest); + /** read/write between values on a lua stack & a property exported from a 'CReflectable' derived object + * (throws on error) + */ + static void luaValueToReflectedProperty(CLuaState &ls, int stackIndex, CReflectable &target, const CReflectedProperty &property) throw(ELuaIHMException); - // CVector2f - static bool pop(CLuaState &ls, NLMISC::CVector2f &dest); - - // helper : get a 2D poly (a table of cvector2f) from a lua table (throw on fail) - static void getPoly2DOnStack(CLuaState &ls, sint index, NLMISC::CPolygon2D &dest); - - // argument checkin helpers - static void checkArgCount(CLuaState &ls, const char* funcName, uint nArgs); // check that number of argument is exactly the one required - static void checkArgMin(CLuaState &ls, const char* funcName, uint nArgs); // check that number of argument is at least the one required - static void checkArgMax(CLuaState &ls, const char* funcName, uint nArgs); // check that number of argument is at most the one required - static void check(CLuaState &ls, bool ok, const std::string &failReason); - static void checkArgType(CLuaState &ls, const char *funcName, uint index, int argType); - static void checkArgTypeRGBA(CLuaState &ls, const char *funcName, uint index); - static void checkArgTypeUCString(CLuaState &ls, const char *funcName, uint index); - /** throw a lua expection (inside a C function called from lua) with the given reason, and the current call stack - * The various check... function call this function when their test fails - */ - static void fails(CLuaState &ls, const char *format, ...); - - // pop a sint32 from a lua stack, throw an exception on fail - static bool popSINT32(CLuaState &ls, sint32 & dest); - bool popString(CLuaState &ls, std::string & dest); - - /** read/write between values on a lua stack & a property exported from a 'CReflectable' derived object - * (throws on error) - */ - static void luaValueToReflectedProperty(CLuaState &ls, int stackIndex, CReflectable &target, const CReflectedProperty &property) throw(ELuaIHMException); - - // push a reflected property on the stack - // NB : no check is done that 'property' is part of the class info of 'reflectedObject' - static void luaValueFromReflectedProperty(CLuaState &ls, CReflectable &reflectedObject, const CReflectedProperty &property); + // push a reflected property on the stack + // NB : no check is done that 'property' is part of the class info of 'reflectedObject' + static void luaValueFromReflectedProperty(CLuaState &ls, CReflectable &reflectedObject, const CReflectedProperty &property); -private: + private: + static void registerBasics(CLuaState &ls); + static void registerIHM(CLuaState &ls); + static void createLuaEnumTable(CLuaState &ls, const std::string &str); + //////////////////////////////////////////// Exported functions ////////////////////////////////////////////////////// + static uint32 getLocalTime(); + static double getPreciseLocalTime(); + static std::string findReplaceAll(const std::string &str, const std::string &search, const std::string &replace); + static ucstring findReplaceAll(const ucstring &str, const ucstring &search, const ucstring &replace); + static ucstring findReplaceAll(const ucstring &str, const std::string &search, const std::string &replace); + static ucstring findReplaceAll(const ucstring &str, const std::string &search, const ucstring &replace); + static ucstring findReplaceAll(const ucstring &str, const ucstring &search, const std::string &replace); - static void registerBasics(CLuaState &ls); - static void registerIHM(CLuaState &ls); - static void createLuaEnumTable(CLuaState &ls, const std::string &str); + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// \name Exported Functions - // @{ - - // LUA exported Functions with luabind - static uint32 getLocalTime(); - static double getPreciseLocalTime(); - - static std::string findReplaceAll(const std::string &str, const std::string &search, const std::string &replace); - static ucstring findReplaceAll(const ucstring &str, const ucstring &search, const ucstring &replace); - // just for ease of use - static ucstring findReplaceAll(const ucstring &str, const std::string &search, const std::string &replace); - static ucstring findReplaceAll(const ucstring &str, const std::string &search, const ucstring &replace); - static ucstring findReplaceAll(const ucstring &str, const ucstring &search, const std::string &replace); - - // @} - - // Function export tools - // Function to forward lua call to C++ to a 'lua method' exported from a reflected object - static int luaMethodCall(lua_State *ls); -}; + static int luaMethodCall(lua_State *ls); + }; +} #endif // NL_LUA_IHM_H diff --git a/code/nel/include/nel/gui/lua_manager.h b/code/nel/include/nel/gui/lua_manager.h index 246e7bbd6..def6ab472 100644 --- a/code/nel/include/nel/gui/lua_manager.h +++ b/code/nel/include/nel/gui/lua_manager.h @@ -22,36 +22,36 @@ namespace NLGUI { class CLuaState; + + /// Provides a single global access point to the Lua state, and related stuff. :( + class CLuaManager + { + public: + ~CLuaManager(); + + static CLuaManager& getInstance() + { + if( instance == NULL ) + { + instance = new CLuaManager(); + } + return *instance; + } + + /// Enables attaching the Lua debugger in the CLuaState instance, only matters on startup. + static void enableLuaDebugging(){ debugLua = true; } + + NLGUI::CLuaState* getLuaState() const{ return luaState; } + + private: + CLuaManager(); + + static CLuaManager *instance; + static bool debugLua; + + NLMISC::CSmartPtr< NLGUI::CLuaState > luaState; + }; + } -/// Provides a single global access point to the Lua state, and related stuff. :( -class CLuaManager -{ -public: - ~CLuaManager(); - - static CLuaManager& getInstance() - { - if( instance == NULL ) - { - instance = new CLuaManager(); - } - return *instance; - } - - /// Enables attaching the Lua debugger in the CLuaState instance, only matters on startup. - static void enableLuaDebugging(){ debugLua = true; } - - NLGUI::CLuaState* getLuaState() const{ return luaState; } - -private: - CLuaManager(); - - static CLuaManager *instance; - static bool debugLua; - - NLMISC::CSmartPtr< NLGUI::CLuaState > luaState; -}; - - #endif diff --git a/code/nel/include/nel/gui/lua_object.h b/code/nel/include/nel/gui/lua_object.h index 7e2d19370..d188018ee 100644 --- a/code/nel/include/nel/gui/lua_object.h +++ b/code/nel/include/nel/gui/lua_object.h @@ -20,282 +20,284 @@ #include "nel/misc/smart_ptr.h" #include "nel/misc/rgba.h" -// #include "nel/gui/lua_helper.h" -using namespace NLGUI; - - -class CLuaEnumeration; - -/** - * Wrapper to a lua value - * - * Useful to navigate through lua tables without having to deal with the stack. - * - * The following types are tracked by reference : - * - lua table - * - lua user data - * - lua functions - * - * The following types are kept by value : - * - * - lua numbers - * - lua strings ? - * - lua boolean - * - lua light user datas - * - lua 'pointers' - * - * Each reference object has an id giving its path in order to track bugs more easily - */ -class CLuaObject +namespace NLGUI { -public: - CLuaObject() {} - ~CLuaObject(); - // Build this object by popping it from the given lua state - CLuaObject(CLuaState &state, const char *id =""); - CLuaObject(CLuaState &state, const std::string &id); - // Build this object from another object - CLuaObject(const CLuaObject &other); - // Copy refrence to another lua object - CLuaObject &operator=(const CLuaObject &other); - // Get id for that object - const std::string &getId() const { return _Id; } - // Set id for that object - void setId(const std::string &id) { _Id = id; } - // See if the obj - bool isValid() const; - // Pop a new value for this lua object from the top of the stack. The stack must not be empty - void pop(CLuaState &luaState, const char *id =""); - // Push the object that is being referenced on the stack - // An assertion is raised if 'pop' hasn't been called or - // if the lua state has been destroyed - void push() const; - // Get the lua state in which the object resides. - CLuaState *getLuaState() const; - // Release the object. 'pop' must be called to make the object valid again - void release(); - // type queries - int type() const; - const char *getTypename() const; - bool isNil() const; - bool isNumber() const; - bool isBoolean() const; - bool isString() const; - bool isFunction() const; - bool isCFunction() const; - bool isTable() const; - bool isUserData() const; - bool isLightUserData() const; - bool isRGBA() const; - // equality - bool rawEqual(const CLuaObject &other) const; - // conversions (no throw) : the actual value of object is not modified!! - NLMISC::CRGBA toRGBA() const; // default to black if not a crgba - bool toBoolean() const; - lua_Number toNumber() const; - std::string toString() const; - lua_CFunction toCFunction() const; - void *toUserData() const; - const void *toPointer() const; - // implicit conversions (no throw) - operator bool() const; - operator float() const; - operator double() const; - operator std::string() const; - /** create a sub table for this object, with a string as a key - * This object must be a table or an exception if thrown - */ - CLuaObject newTable(const char *tableName) throw(ELuaNotATable); + class CLuaEnumeration; - /** Set a value in a table. - * If this object is not a table then an exception is thrown - * NB : value should came from the same lua environment - * \TODO other type of keys + /** + * Wrapper to a lua value + * + * Useful to navigate through lua tables without having to deal with the stack. + * + * The following types are tracked by reference : + * - lua table + * - lua user data + * - lua functions + * + * The following types are kept by value : + * + * - lua numbers + * - lua strings ? + * - lua boolean + * - lua light user datas + * - lua 'pointers' + * + * Each reference object has an id giving its path in order to track bugs more easily */ - void setValue(const char *key, const CLuaObject &value) throw(ELuaNotATable); - void setValue(const std::string &key, const CLuaObject &value) throw(ELuaNotATable) { setValue(key.c_str(), value); } - void setValue(const char *key, const std::string &value) throw(ELuaNotATable); - void setValue(const char *key, const char *value) throw(ELuaNotATable); - void setValue(const char *key, bool value) throw(ELuaNotATable); - void setValue(const char *key, TLuaWrappedFunction value) throw(ELuaNotATable); - void setValue(const char *key, double value) throw(ELuaNotATable); - void setValue(const std::string &key, const std::string &value) throw(ELuaNotATable) { setValue(key.c_str(), value); } - void setNil(const char *key) throw(ELuaNotATable); - void setNil(const std::string &key) throw(ELuaNotATable) { setNil(key.c_str()); } - /** Erase a value in a table by its key. - * If this object is not a table then an exception is thrown. - * \TODO other type of keys - */ - void eraseValue(const char *key) throw(ELuaNotATable); - void eraseValue(const std::string &key) throw(ELuaNotATable) { eraseValue(key.c_str()); } - // test is this object is enumerable - bool isEnumerable() const; - // Enumeration of a table. If the object is not a table, an exception is thrown. - CLuaEnumeration enumerate() throw(ELuaNotATable); - // retrieve metatable of an object (or nil if object has no metatable) - CLuaObject getMetaTable() const; - // set metatable for this object - bool setMetaTable(CLuaObject &metatable); - /** Access to a sub element of a table (no throw). - * if the element is not a table, then 'nil' is returned - * TODO nico : add other key types if needed - * TODO nico : version that takes destination object as a reference in its parameter to avoid an object copy - */ - CLuaObject operator[](double key) const; - CLuaObject operator[](const char *key) const; - CLuaObject operator[](const std::string &key) const { return operator[](key.c_str()); } - /** Checked access to a sub element of a table. An exception is thrown is the element is not a table. - */ - CLuaObject at(const char *key) const throw (ELuaNotATable); - CLuaObject at(const std::string &key) const { return at(key.c_str()); } - - // Test is that table has the given key. The object must be a table or an exception is thrown - bool hasKey(const char *key) const; - - /** debug : recursively get value (useful for table) - * \param maxDepth (0 for no limit) - * \param alreadySeen pointer to lua tables that have already been displayed by the command (to avoid infinite recursion when a cycluic graph is encountered) - */ - std::string toStringRecurse(uint depth = 0, uint maxDepth = 20, std::set *alreadySeen = NULL) const; - - /** dump the value in the log (includes tables) - * \param alreadySeen pointer to lua tables that have already been displayed by the command (to avoid infinite recursion when a cycluic graph is encountered) - */ - void dump(uint maxDepth = 20, std::set *alreadySeen = NULL) const; - // concatenate identifiers, adding a dot between them if necessary. If right is a number then brackets are added - static std::string concatId(const std::string &left, const std::string &right); - // If this object is a function, then call it and return true on success - bool callNoThrow(int numArgs, int numRet); - // Call a method of this table by name (no throw version) - bool callMethodByNameNoThrow(const char *name, int numArgs, int numRet); -private: - NLMISC::CRefPtr _LuaState; - std::string _Id; -}; - - -/** enumeration of the content of a lua table - * - * Example of use : - * - *\code - CLuaObject table; - table.pop(luaState); // retrieve table from the top of a lua stack - CLuaEnumeration enueration = table.enumerate(); - while (enumeration.hasNext()) + class CLuaObject { - nlinfo('key = %s", enumeration.nextKey().toString().c_str()); - nlinfo('value = %s", enumeration.nextValue().toString().c_str()); - enumeration.next(); + public: + CLuaObject() {} + ~CLuaObject(); + // Build this object by popping it from the given lua state + CLuaObject(CLuaState &state, const char *id =""); + CLuaObject(CLuaState &state, const std::string &id); + // Build this object from another object + CLuaObject(const CLuaObject &other); + // Copy refrence to another lua object + CLuaObject &operator=(const CLuaObject &other); + // Get id for that object + const std::string &getId() const { return _Id; } + // Set id for that object + void setId(const std::string &id) { _Id = id; } + // See if the obj + bool isValid() const; + // Pop a new value for this lua object from the top of the stack. The stack must not be empty + void pop(CLuaState &luaState, const char *id =""); + // Push the object that is being referenced on the stack + // An assertion is raised if 'pop' hasn't been called or + // if the lua state has been destroyed + void push() const; + // Get the lua state in which the object resides. + CLuaState *getLuaState() const; + // Release the object. 'pop' must be called to make the object valid again + void release(); + // type queries + int type() const; + const char *getTypename() const; + bool isNil() const; + bool isNumber() const; + bool isBoolean() const; + bool isString() const; + bool isFunction() const; + bool isCFunction() const; + bool isTable() const; + bool isUserData() const; + bool isLightUserData() const; + bool isRGBA() const; + // equality + bool rawEqual(const CLuaObject &other) const; + // conversions (no throw) : the actual value of object is not modified!! + NLMISC::CRGBA toRGBA() const; // default to black if not a crgba + bool toBoolean() const; + lua_Number toNumber() const; + std::string toString() const; + lua_CFunction toCFunction() const; + void *toUserData() const; + const void *toPointer() const; + // implicit conversions (no throw) + operator bool() const; + operator float() const; + operator double() const; + operator std::string() const; + /** create a sub table for this object, with a string as a key + * This object must be a table or an exception if thrown + */ + CLuaObject newTable(const char *tableName) throw(ELuaNotATable); + + + /** Set a value in a table. + * If this object is not a table then an exception is thrown + * NB : value should came from the same lua environment + * \TODO other type of keys + */ + void setValue(const char *key, const CLuaObject &value) throw(ELuaNotATable); + void setValue(const std::string &key, const CLuaObject &value) throw(ELuaNotATable) { setValue(key.c_str(), value); } + void setValue(const char *key, const std::string &value) throw(ELuaNotATable); + void setValue(const char *key, const char *value) throw(ELuaNotATable); + void setValue(const char *key, bool value) throw(ELuaNotATable); + void setValue(const char *key, TLuaWrappedFunction value) throw(ELuaNotATable); + void setValue(const char *key, double value) throw(ELuaNotATable); + void setValue(const std::string &key, const std::string &value) throw(ELuaNotATable) { setValue(key.c_str(), value); } + void setNil(const char *key) throw(ELuaNotATable); + void setNil(const std::string &key) throw(ELuaNotATable) { setNil(key.c_str()); } + /** Erase a value in a table by its key. + * If this object is not a table then an exception is thrown. + * \TODO other type of keys + */ + void eraseValue(const char *key) throw(ELuaNotATable); + void eraseValue(const std::string &key) throw(ELuaNotATable) { eraseValue(key.c_str()); } + // test is this object is enumerable + bool isEnumerable() const; + // Enumeration of a table. If the object is not a table, an exception is thrown. + CLuaEnumeration enumerate() throw(ELuaNotATable); + // retrieve metatable of an object (or nil if object has no metatable) + CLuaObject getMetaTable() const; + // set metatable for this object + bool setMetaTable(CLuaObject &metatable); + /** Access to a sub element of a table (no throw). + * if the element is not a table, then 'nil' is returned + * TODO nico : add other key types if needed + * TODO nico : version that takes destination object as a reference in its parameter to avoid an object copy + */ + CLuaObject operator[](double key) const; + CLuaObject operator[](const char *key) const; + CLuaObject operator[](const std::string &key) const { return operator[](key.c_str()); } + /** Checked access to a sub element of a table. An exception is thrown is the element is not a table. + */ + CLuaObject at(const char *key) const throw (ELuaNotATable); + CLuaObject at(const std::string &key) const { return at(key.c_str()); } + + // Test is that table has the given key. The object must be a table or an exception is thrown + bool hasKey(const char *key) const; + + /** debug : recursively get value (useful for table) + * \param maxDepth (0 for no limit) + * \param alreadySeen pointer to lua tables that have already been displayed by the command (to avoid infinite recursion when a cycluic graph is encountered) + */ + std::string toStringRecurse(uint depth = 0, uint maxDepth = 20, std::set *alreadySeen = NULL) const; + + /** dump the value in the log (includes tables) + * \param alreadySeen pointer to lua tables that have already been displayed by the command (to avoid infinite recursion when a cycluic graph is encountered) + */ + void dump(uint maxDepth = 20, std::set *alreadySeen = NULL) const; + // concatenate identifiers, adding a dot between them if necessary. If right is a number then brackets are added + static std::string concatId(const std::string &left, const std::string &right); + // If this object is a function, then call it and return true on success + bool callNoThrow(int numArgs, int numRet); + // Call a method of this table by name (no throw version) + bool callMethodByNameNoThrow(const char *name, int numArgs, int numRet); + private: + NLMISC::CRefPtr _LuaState; + std::string _Id; }; - \endcode - * - * There is a macro called 'ENUM_LUA_TABLE' to automate that process. - * Previous code would then be written as follow : - * - * - *\code - CLuaObject table; - table.pop(luaState); // retrieve table from the top of a lua stack - ENUM_LUA_TABLE(table, enumeration); + + + /** enumeration of the content of a lua table + * + * Example of use : + * + *\code + CLuaObject table; + table.pop(luaState); // retrieve table from the top of a lua stack + CLuaEnumeration enueration = table.enumerate(); + while (enumeration.hasNext()) + { + nlinfo('key = %s", enumeration.nextKey().toString().c_str()); + nlinfo('value = %s", enumeration.nextValue().toString().c_str()); + enumeration.next(); + }; + \endcode + * + * There is a macro called 'ENUM_LUA_TABLE' to automate that process. + * Previous code would then be written as follow : + * + * + *\code + CLuaObject table; + table.pop(luaState); // retrieve table from the top of a lua stack + ENUM_LUA_TABLE(table, enumeration); + { + nlinfo('key = %s", enumeration.nextKey().toString().c_str()); + nlinfo('value = %s", enumeration.nextValue().toString().c_str()); + }; + \endcode + * + */ + class CLuaEnumeration { - nlinfo('key = %s", enumeration.nextKey().toString().c_str()); - nlinfo('value = %s", enumeration.nextValue().toString().c_str()); + public: + // is there a next key,value pair in the table + bool hasNext() { return _HasNext; } + // Return next key. Assertion if 'hasNext' is false + const CLuaObject &nextKey() const; + // Return next value. Assertion if 'hasNext' is false + CLuaObject &nextValue(); + // Go to the next value. Assertion if there's no such value + void next(); + private: + friend class CLuaObject; + // current value & key + CLuaObject _Table; + CLuaObject _Key; + CLuaObject _Value; + CLuaObject _NextFunction; // pointer to the global 'next' function + bool _HasNext; + // construction from a table on the stack + CLuaEnumeration(CLuaObject &table); }; - \endcode - * - */ -class CLuaEnumeration -{ -public: - // is there a next key,value pair in the table - bool hasNext() { return _HasNext; } - // Return next key. Assertion if 'hasNext' is false - const CLuaObject &nextKey() const; - // Return next value. Assertion if 'hasNext' is false - CLuaObject &nextValue(); - // Go to the next value. Assertion if there's no such value - void next(); -private: - friend class CLuaObject; - // current value & key - CLuaObject _Table; - CLuaObject _Key; - CLuaObject _Value; - CLuaObject _NextFunction; // pointer to the global 'next' function - bool _HasNext; - // construction from a table on the stack - CLuaEnumeration(CLuaObject &table); -}; -/** macro to ease lua table enumeration - * \param object A CLuaObject which must be a table, and on which enumeration is done. An exception will be thrown as 'CLuaObject::enumerate' is - * called if this is not the case - * \param enumerator The enumerator object - */ -#define ENUM_LUA_TABLE(object, enumerator) for(CLuaEnumeration enumerator = (object).enumerate(); enumerator.hasNext(); enumerator.next()) + /** macro to ease lua table enumeration + * \param object A CLuaObject which must be a table, and on which enumeration is done. An exception will be thrown as 'CLuaObject::enumerate' is + * called if this is not the case + * \param enumerator The enumerator object + */ + #define ENUM_LUA_TABLE(object, enumerator) for(CLuaEnumeration enumerator = (object).enumerate(); enumerator.hasNext(); enumerator.next()) -//opitmized lua string for fast comparison -class CLuaString -{ -public: - explicit CLuaString(const char *value = "") + //opitmized lua string for fast comparison + class CLuaString { - nlassert( value != NULL ); - _Str = value; + public: + explicit CLuaString(const char *value = "") + { + nlassert( value != NULL ); + _Str = value; + } + const std::string& getStr() const{ return _Str; } + private: + std::string _Str; + mutable CLuaState::TRefPtr _LuaState; // ref ptr so that statics get rebuilt on lua restart + mutable CLuaObject _InLua; + }; + + inline bool operator==(const char* lh, const CLuaString& rh) + { + return std::string(lh) == rh.getStr(); } - const std::string& getStr() const{ return _Str; } -private: - std::string _Str; - mutable CLuaState::TRefPtr _LuaState; // ref ptr so that statics get rebuilt on lua restart - mutable CLuaObject _InLua; -}; -inline bool operator==(const char* lh, const CLuaString& rh) -{ - return std::string(lh) == rh.getStr(); + inline bool operator==( const CLuaString& lh, const CLuaString& rh) + { + return lh.getStr() == rh.getStr(); + } + + inline bool operator==(const CLuaString& lh, const char* rh) + { + return std::string(rh) == lh.getStr(); + } + + inline bool operator==( const CLuaString& lh, const std::string& rh) + { + return lh.getStr() == rh; + } + + inline bool operator==(const std::string& lh, const CLuaString& rh) + { + return lh == rh.getStr(); + } + + class CLuaHashMapTraits + { + public: + static const size_t bucket_size = 4; + static const size_t min_buckets = 8; + CLuaHashMapTraits() + {} + + // hasher for lua string -> they are unique pointers for each string, so just hash a pointer instead of a string... + size_t operator()(const char *value) const { return ((size_t) value) >> 3; } + + // equality for lua string for hash_map -> they are unique pointer -> compare pointers instead of string content + bool operator()(const char *lhs, const char *rhs) const { return lhs < rhs; } + }; + + } -inline bool operator==( const CLuaString& lh, const CLuaString& rh) -{ - return lh.getStr() == rh.getStr(); -} - -inline bool operator==(const CLuaString& lh, const char* rh) -{ - return std::string(rh) == lh.getStr(); -} - -inline bool operator==( const CLuaString& lh, const std::string& rh) -{ - return lh.getStr() == rh; -} - -inline bool operator==(const std::string& lh, const CLuaString& rh) -{ - return lh == rh.getStr(); -} - -class CLuaHashMapTraits -{ -public: - static const size_t bucket_size = 4; - static const size_t min_buckets = 8; - CLuaHashMapTraits() - {} - - // hasher for lua string -> they are unique pointers for each string, so just hash a pointer instead of a string... - size_t operator()(const char *value) const { return ((size_t) value) >> 3; } - - // equality for lua string for hash_map -> they are unique pointer -> compare pointers instead of string content - bool operator()(const char *lhs, const char *rhs) const { return lhs < rhs; } -}; - #endif diff --git a/code/nel/include/nel/gui/reflect.h b/code/nel/include/nel/gui/reflect.h index 64dbb5e2e..435c74799 100644 --- a/code/nel/include/nel/gui/reflect.h +++ b/code/nel/include/nel/gui/reflect.h @@ -14,358 +14,355 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . - - - #ifndef CL_REFLECT_H #define CL_REFLECT_H #include "nel/misc/rgba.h" #include "nel/gui/lua_object.h" -// #include -class CReflectable; namespace NLGUI { + class CReflectable; class CLuaState; -} -struct CClassInfo; + struct CClassInfo; -/** A property of a reflectable object - * NB: multiple inheritance not supported - */ -class CReflectedProperty -{ -public: - enum TType { Boolean = 0, - SInt32, - UInt32, - Float, - String, - UCString, - RGBA, - LuaMethod - }; // other types will be added when needed - // define some pointer-to-member types - typedef bool (CReflectable::* TGetBool) () const; - typedef sint32 (CReflectable::* TGetSInt32) () const; - typedef uint32 (CReflectable::* TGetUInt32) () const; - typedef float (CReflectable::* TGetFloat) () const; - typedef std::string (CReflectable::* TGetString) () const; - typedef ucstring (CReflectable::* TGetUCString) () const; - typedef NLMISC::CRGBA (CReflectable::* TGetRGBA) () const; - // - typedef void (CReflectable::* TSetBool) (bool); - typedef void (CReflectable::* TSetSInt32) (sint32); - typedef void (CReflectable::* TSetUInt32) (uint32); - typedef void (CReflectable::* TSetFloat) (float); - typedef void (CReflectable::* TSetString) (const std::string &); - typedef void (CReflectable::* TSetUCString) (const ucstring &); - typedef void (CReflectable::* TSetRGBA) (NLMISC::CRGBA col); - // - typedef int (CReflectable:: *TLuaMethod) (CLuaState &luaState); - -public: - TType Type; - // In each union we have method pointers to retrieve / set the data of the desired type (as told in 'Type') - union - { - TGetBool GetBool; - TGetSInt32 GetSInt32; - TGetUInt32 GetUInt32; - TGetFloat GetFloat; - TGetString GetString; - TGetUCString GetUCString; - TGetRGBA GetRGBA; - TLuaMethod GetLuaMethod; // lua method can only be obtained, not written ... - } GetMethod; - union - { - TSetBool SetBool; - TSetSInt32 SetSInt32; - TSetUInt32 SetUInt32; - TSetFloat SetFloat; - TSetString SetString; - TSetUCString SetUCString; - TSetRGBA SetRGBA; - } SetMethod; - // name of the property - std::string Name; - mutable CLuaObject LuaMethodRef; // cache pointer to function call if type == LuaMethod - const CClassInfo *ParentClass; // filled when 'registerClass' is called -}; - -// a vector of reflected properties -typedef std::vector TReflectedProperties; - - -struct CClassInfo; - -/** Base class for a reflectable object - * NB: multiple inheritance not supported - */ -class CReflectable -{ -public: - virtual ~CReflectable() {} - virtual const char *getReflectedClassName() const { return "CReflectable"; } - virtual const char *getRflectedParentClassName() const { return ""; } - - /** When registering classes, the reflect system will call this function on each class - * to know which properties they exports. - * To defines which properties are exported use the REFLECT_EXPORT_** macros. - * By doing so, a new 'getReflectedProperties' function will be defined + /** A property of a reflectable object + * NB: multiple inheritance not supported */ - static void getReflectedProperties(TReflectedProperties &/* props */) + class CReflectedProperty { + public: + enum TType { Boolean = 0, + SInt32, + UInt32, + Float, + String, + UCString, + RGBA, + LuaMethod + }; // other types will be added when needed + // define some pointer-to-member types + typedef bool (CReflectable::* TGetBool) () const; + typedef sint32 (CReflectable::* TGetSInt32) () const; + typedef uint32 (CReflectable::* TGetUInt32) () const; + typedef float (CReflectable::* TGetFloat) () const; + typedef std::string (CReflectable::* TGetString) () const; + typedef ucstring (CReflectable::* TGetUCString) () const; + typedef NLMISC::CRGBA (CReflectable::* TGetRGBA) () const; + // + typedef void (CReflectable::* TSetBool) (bool); + typedef void (CReflectable::* TSetSInt32) (sint32); + typedef void (CReflectable::* TSetUInt32) (uint32); + typedef void (CReflectable::* TSetFloat) (float); + typedef void (CReflectable::* TSetString) (const std::string &); + typedef void (CReflectable::* TSetUCString) (const ucstring &); + typedef void (CReflectable::* TSetRGBA) (NLMISC::CRGBA col); + // + typedef int (CReflectable:: *TLuaMethod) (CLuaState &luaState); + + public: + TType Type; + // In each union we have method pointers to retrieve / set the data of the desired type (as told in 'Type') + union + { + TGetBool GetBool; + TGetSInt32 GetSInt32; + TGetUInt32 GetUInt32; + TGetFloat GetFloat; + TGetString GetString; + TGetUCString GetUCString; + TGetRGBA GetRGBA; + TLuaMethod GetLuaMethod; // lua method can only be obtained, not written ... + } GetMethod; + union + { + TSetBool SetBool; + TSetSInt32 SetSInt32; + TSetUInt32 SetUInt32; + TSetFloat SetFloat; + TSetString SetString; + TSetUCString SetUCString; + TSetRGBA SetRGBA; + } SetMethod; + // name of the property + std::string Name; + mutable CLuaObject LuaMethodRef; // cache pointer to function call if type == LuaMethod + const CClassInfo *ParentClass; // filled when 'registerClass' is called + }; + + // a vector of reflected properties + typedef std::vector TReflectedProperties; + + + struct CClassInfo; + + /** Base class for a reflectable object + * NB: multiple inheritance not supported + */ + class CReflectable + { + public: + virtual ~CReflectable() {} + virtual const char *getReflectedClassName() const { return "CReflectable"; } + virtual const char *getRflectedParentClassName() const { return ""; } + + /** When registering classes, the reflect system will call this function on each class + * to know which properties they exports. + * To defines which properties are exported use the REFLECT_EXPORT_** macros. + * By doing so, a new 'getReflectedProperties' function will be defined + */ + static void getReflectedProperties(TReflectedProperties &/* props */) + { + } + // get class infos for this reflectable object + const CClassInfo *getClassInfo(); + + /** get a property from this object by name + * TODO nico : optimized version for lua string (found in CLuaIHM) would maybe fit better here ... + */ + const CReflectedProperty *getReflectedProperty(const std::string &propertyName, bool dspWarning= true) const; + }; + + struct CLuaIndexedProperty + { + const CReflectedProperty *Prop; + CLuaString Id; // must keep id here, so that we are sure the string is not gc in lua and its pointer remains valid + }; + + + struct CClassInfo + { + TReflectedProperties Properties; // the properties exported by this class + const CClassInfo *ParentClass; // pointer to infos of the parent class, or NULL if it is a root class + std::string ClassName; + /** For lua speedup (used by CLuaIHM) : because lua string are unique, we can use them to access property directly. + */ + typedef CHashMap TLuaStrToPropMap; + mutable TLuaStrToPropMap LuaStrToProp; + }; + + /** Simple reflection system. + * Used by the GUI and some other objects. + * It is used to export some properties so that we can easily manipulate them in the GUI scripts (either lua or with CInterfaceExpr). + * NB: multiple inheritance not supported + * + * Example of use : a class exporting a boolean + * + * class CTestClass : public CReflectable + * { + * public: + * void setValue(bool value) { _Value = value; } + * bool getValue() const { return _Value; } + * \\ export the bool value + * REFLECT_EXPORT_START(CTestClass, CReflectable) + * REFLECT_BOOL("myValue", setValue, getValue) + * REFLECT_EXPORT_END + * private: + * bool _Value; + * }; + * + * The class must then be registered with : + * + * REGISTER_REFLECTABLE_CLASS(CTestClass, CReflectable) + * + * NB: It should be registered after its parents + * + * + * \author Nicolas Vizerie + * \author Nevrax France + * \date 2002 + */ + class CReflectSystem + { + public: + + typedef std::map TClassMap; + + public: + // release memory + static void release(); + + /** register a class and its properties + * NB : class should be registered after their parent have been, or an assertion will be raised + */ + static void registerClass(const std::string &className, const std::string &parentName, const TReflectedProperties properties); + + // retrieve a property of a reflectable class, or NULL if unknown + static const CReflectedProperty *getProperty(const std::string &className, const std::string &propertyName, bool dspWarning= true); + + // get the list of class for debug or read purpose (NULL if no register has been called) + static const TClassMap *getClassMap() {return _ClassMap;} + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private: + static TClassMap *_ClassMap; // each class and its infos + }; + + + /** Helper macros to export properties of a reflectable class + */ + + /** Start a declaration of a reflectable class exports + * Should be placed inside the class + */ + #define REFLECT_EXPORT_START(className, parentName) \ + virtual const char *getReflectedClassName() const { return #className; } \ + virtual const char *getReflectedParentClassName() const { return #parentName; } \ + static void getReflectedProperties(TReflectedProperties &props) \ + { \ + typedef className A; \ + typedef bool (className::* TGetBoola) () const; \ + typedef sint32 (className::* TGetSInt32a) () const; \ + typedef uint32 (className::* TGetUInt32a) () const; \ + typedef float (className::* TGetFloata) () const; \ + typedef std::string (className::* TGetStringa) () const; \ + typedef ucstring (className::* TGetUCStringa) () const; \ + typedef NLMISC::CRGBA (className::* TGetRGBAa) () const; \ + typedef void (className::* TSetBoola) (bool); \ + typedef void (className::* TSetSInt32a) (sint32); \ + typedef void (className::* TSetUInt32a) (uint32); \ + typedef void (className::* TSetFloata) (float); \ + typedef void (className::* TSetStringa) (const std::string &); \ + typedef void (className::* TSetUCStringa) (const ucstring &); \ + typedef void (className::* TSetRGBAa) (NLMISC::CRGBA col); \ + typedef int (className:: *TLuaMethoda) (CLuaState &luaState); \ + nlunreferenced(props); + + + // export a boolean value, by giving the name of the get and the set method + #define REFLECT_BOOL(exportName, getMethod, setMethod) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::Boolean; \ + prop.GetMethod.GetBool = (CReflectedProperty::TGetBool) (TGetBoola) &A::getMethod; \ + prop.SetMethod.SetBool = (CReflectedProperty::TSetBool) (TSetBoola) &A::setMethod; \ + props.push_back(prop); \ } - // get class infos for this reflectable object - const CClassInfo *getClassInfo(); - /** get a property from this object by name - * TODO nico : optimized version for lua string (found in CLuaIHM) would maybe fit better here ... + // export a sint32 value, by giving the name of the get and the set method + #define REFLECT_SINT32(exportName, getMethod, setMethod) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::SInt32; \ + prop.GetMethod.GetSInt32 = (CReflectedProperty::TGetSInt32) (TGetSInt32a) &A::getMethod; \ + prop.SetMethod.SetSInt32 = (CReflectedProperty::TSetSInt32) (TSetSInt32a) &A::setMethod; \ + props.push_back(prop); \ + } + + // export a sint32 value, by giving the name of the get and the set method + #define REFLECT_UINT32(exportName, getMethod, setMethod) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::UInt32; \ + prop.GetMethod.GetUInt32 = (CReflectedProperty::TGetUInt32) (TGetUInt32a) &A::getMethod; \ + prop.SetMethod.SetUInt32 = (CReflectedProperty::TSetUInt32) (TSetUInt32a) &A::setMethod; \ + props.push_back(prop); \ + } + + // export a float value, by giving the name of the get and the set method + #define REFLECT_FLOAT(exportName, getMethod, setMethod) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::Float; \ + prop.GetMethod.GetFloat = (CReflectedProperty::TGetFloat) (TGetFloata) &A::getMethod; \ + prop.SetMethod.SetFloat = (CReflectedProperty::TSetFloat) (TSetFloata) &A::setMethod; \ + props.push_back(prop); \ + } + + // export a string value, by giving the name of the get and the set method + #define REFLECT_STRING(exportName, getMethod, setMethod) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::String; \ + prop.GetMethod.GetString = (CReflectedProperty::TGetString) (TGetStringa) &A::getMethod; \ + prop.SetMethod.SetString = (CReflectedProperty::TSetString) (TSetStringa) &A::setMethod; \ + props.push_back(prop); \ + } + + // export a unicode string value, by giving the name of the get and the set method + #define REFLECT_UCSTRING(exportName, getMethod, setMethod) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::UCString; \ + prop.GetMethod.GetUCString = (CReflectedProperty::TGetUCString) (TGetUCStringa) &A::getMethod; \ + prop.SetMethod.SetUCString = (CReflectedProperty::TSetUCString) (TSetUCStringa) &A::setMethod; \ + props.push_back(prop); \ + } + + + // export a color value, by giving the name of the get and the set method + #define REFLECT_RGBA(exportName, getMethod, setMethod) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::RGBA; \ + prop.GetMethod.GetRGBA = (CReflectedProperty::TGetRGBA) (TGetRGBAa) &A::getMethod; \ + prop.SetMethod.SetRGBA = (CReflectedProperty::TSetRGBA) (TSetRGBAa) &A::setMethod; \ + props.push_back(prop); \ + } + + // export a lua method + #define REFLECT_LUA_METHOD(exportName, method) \ + { \ + CReflectedProperty prop; \ + prop.Name = exportName; \ + prop.Type = CReflectedProperty::LuaMethod; \ + prop.GetMethod.GetLuaMethod = (CReflectedProperty::TLuaMethod) (TLuaMethoda) &A::method; \ + props.push_back(prop); \ + } + + + + // ends an export declaration + #define REFLECT_EXPORT_END } + + + // This macro registers a reflectable class to the manager + #define REGISTER_REFLECTABLE_CLASS(className, parentName) \ + { \ + TReflectedProperties props; \ + className::getReflectedProperties(props); \ + CReflectSystem::registerClass(#className, #parentName, props); \ + } + + + + /** Reflectable refcounted object + * NB nico : added this intermediate class so that the binding from lua to the reflection + * system that are found in CLuaIHM can be reused for other objects as well + * NOTE: The class is named 'CReflectableRefPtrTarget' and not 'CReflectableRefCount' + * because the refcount part is only used for ref pointing in the ui */ - const CReflectedProperty *getReflectedProperty(const std::string &propertyName, bool dspWarning= true) const; -}; - -struct CLuaIndexedProperty -{ - const CReflectedProperty *Prop; - CLuaString Id; // must keep id here, so that we are sure the string is not gc in lua and its pointer remains valid -}; + class CReflectableRefPtrTarget : public CReflectable, public NLMISC::CRefCount + { + public: + virtual ~CReflectableRefPtrTarget(); + }; -struct CClassInfo -{ - TReflectedProperties Properties; // the properties exported by this class - const CClassInfo *ParentClass; // pointer to infos of the parent class, or NULL if it is a root class - std::string ClassName; - /** For lua speedup (used by CLuaIHM) : because lua string are unique, we can use them to access property directly. - */ - typedef CHashMap TLuaStrToPropMap; - mutable TLuaStrToPropMap LuaStrToProp; -}; - -/** Simple reflection system. - * Used by the GUI and some other objects. - * It is used to export some properties so that we can easily manipulate them in the GUI scripts (either lua or with CInterfaceExpr). - * NB: multiple inheritance not supported - * - * Example of use : a class exporting a boolean - * - * class CTestClass : public CReflectable - * { - * public: - * void setValue(bool value) { _Value = value; } - * bool getValue() const { return _Value; } - * \\ export the bool value - * REFLECT_EXPORT_START(CTestClass, CReflectable) - * REFLECT_BOOL("myValue", setValue, getValue) - * REFLECT_EXPORT_END - * private: - * bool _Value; - * }; - * - * The class must then be registered with : - * - * REGISTER_REFLECTABLE_CLASS(CTestClass, CReflectable) - * - * NB: It should be registered after its parents - * - * - * \author Nicolas Vizerie - * \author Nevrax France - * \date 2002 - */ -class CReflectSystem -{ -public: - - typedef std::map TClassMap; - -public: - // release memory - static void release(); - - /** register a class and its properties - * NB : class should be registered after their parent have been, or an assertion will be raised - */ - static void registerClass(const std::string &className, const std::string &parentName, const TReflectedProperties properties); - - // retrieve a property of a reflectable class, or NULL if unknown - static const CReflectedProperty *getProperty(const std::string &className, const std::string &propertyName, bool dspWarning= true); - - // get the list of class for debug or read purpose (NULL if no register has been called) - static const TClassMap *getClassMap() {return _ClassMap;} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -private: - static TClassMap *_ClassMap; // each class and its infos -}; + class CReflectableLuaRef + { + public: + CReflectableLuaRef(CReflectableRefPtrTarget *ptr = NULL) : Ptr(ptr), _ClassInfo(NULL) {} + NLMISC::CRefPtr Ptr; + const CClassInfo &getClassInfo() const; + // IMPORTANT : luaStringPtr should have been obtained from lua, see remark in CClassInfo + const CReflectedProperty *getProp(const char *luaStringPtr) const; + private: + // cache to class definition of the pointee object (once a CReflectableLuaRef created in lua, it remains a *const* pointer) + mutable const CClassInfo *_ClassInfo; + }; -/** Helper macros to export properties of a reflectable class - */ - -/** Start a declaration of a reflectable class exports - * Should be placed inside the class - */ -#define REFLECT_EXPORT_START(className, parentName) \ - virtual const char *getReflectedClassName() const { return #className; } \ - virtual const char *getReflectedParentClassName() const { return #parentName; } \ - static void getReflectedProperties(TReflectedProperties &props) \ - { \ - typedef className A; \ - typedef bool (className::* TGetBoola) () const; \ - typedef sint32 (className::* TGetSInt32a) () const; \ - typedef uint32 (className::* TGetUInt32a) () const; \ - typedef float (className::* TGetFloata) () const; \ - typedef std::string (className::* TGetStringa) () const; \ - typedef ucstring (className::* TGetUCStringa) () const; \ - typedef NLMISC::CRGBA (className::* TGetRGBAa) () const; \ - typedef void (className::* TSetBoola) (bool); \ - typedef void (className::* TSetSInt32a) (sint32); \ - typedef void (className::* TSetUInt32a) (uint32); \ - typedef void (className::* TSetFloata) (float); \ - typedef void (className::* TSetStringa) (const std::string &); \ - typedef void (className::* TSetUCStringa) (const ucstring &); \ - typedef void (className::* TSetRGBAa) (NLMISC::CRGBA col); \ - typedef int (className:: *TLuaMethoda) (CLuaState &luaState); \ - nlunreferenced(props); - - -// export a boolean value, by giving the name of the get and the set method -#define REFLECT_BOOL(exportName, getMethod, setMethod) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::Boolean; \ - prop.GetMethod.GetBool = (CReflectedProperty::TGetBool) (TGetBoola) &A::getMethod; \ - prop.SetMethod.SetBool = (CReflectedProperty::TSetBool) (TSetBoola) &A::setMethod; \ - props.push_back(prop); \ } -// export a sint32 value, by giving the name of the get and the set method -#define REFLECT_SINT32(exportName, getMethod, setMethod) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::SInt32; \ - prop.GetMethod.GetSInt32 = (CReflectedProperty::TGetSInt32) (TGetSInt32a) &A::getMethod; \ - prop.SetMethod.SetSInt32 = (CReflectedProperty::TSetSInt32) (TSetSInt32a) &A::setMethod; \ - props.push_back(prop); \ -} - -// export a sint32 value, by giving the name of the get and the set method -#define REFLECT_UINT32(exportName, getMethod, setMethod) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::UInt32; \ - prop.GetMethod.GetUInt32 = (CReflectedProperty::TGetUInt32) (TGetUInt32a) &A::getMethod; \ - prop.SetMethod.SetUInt32 = (CReflectedProperty::TSetUInt32) (TSetUInt32a) &A::setMethod; \ - props.push_back(prop); \ -} - -// export a float value, by giving the name of the get and the set method -#define REFLECT_FLOAT(exportName, getMethod, setMethod) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::Float; \ - prop.GetMethod.GetFloat = (CReflectedProperty::TGetFloat) (TGetFloata) &A::getMethod; \ - prop.SetMethod.SetFloat = (CReflectedProperty::TSetFloat) (TSetFloata) &A::setMethod; \ - props.push_back(prop); \ -} - -// export a string value, by giving the name of the get and the set method -#define REFLECT_STRING(exportName, getMethod, setMethod) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::String; \ - prop.GetMethod.GetString = (CReflectedProperty::TGetString) (TGetStringa) &A::getMethod; \ - prop.SetMethod.SetString = (CReflectedProperty::TSetString) (TSetStringa) &A::setMethod; \ - props.push_back(prop); \ -} - -// export a unicode string value, by giving the name of the get and the set method -#define REFLECT_UCSTRING(exportName, getMethod, setMethod) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::UCString; \ - prop.GetMethod.GetUCString = (CReflectedProperty::TGetUCString) (TGetUCStringa) &A::getMethod; \ - prop.SetMethod.SetUCString = (CReflectedProperty::TSetUCString) (TSetUCStringa) &A::setMethod; \ - props.push_back(prop); \ -} - - -// export a color value, by giving the name of the get and the set method -#define REFLECT_RGBA(exportName, getMethod, setMethod) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::RGBA; \ - prop.GetMethod.GetRGBA = (CReflectedProperty::TGetRGBA) (TGetRGBAa) &A::getMethod; \ - prop.SetMethod.SetRGBA = (CReflectedProperty::TSetRGBA) (TSetRGBAa) &A::setMethod; \ - props.push_back(prop); \ -} - -// export a lua method -#define REFLECT_LUA_METHOD(exportName, method) \ -{ \ - CReflectedProperty prop; \ - prop.Name = exportName; \ - prop.Type = CReflectedProperty::LuaMethod; \ - prop.GetMethod.GetLuaMethod = (CReflectedProperty::TLuaMethod) (TLuaMethoda) &A::method; \ - props.push_back(prop); \ -} - - - -// ends an export declaration -#define REFLECT_EXPORT_END } - - -// This macro registers a reflectable class to the manager -#define REGISTER_REFLECTABLE_CLASS(className, parentName) \ -{ \ - TReflectedProperties props; \ - className::getReflectedProperties(props); \ - CReflectSystem::registerClass(#className, #parentName, props); \ -} - - - -/** Reflectable refcounted object - * NB nico : added this intermediate class so that the binding from lua to the reflection - * system that are found in CLuaIHM can be reused for other objects as well - * NOTE: The class is named 'CReflectableRefPtrTarget' and not 'CReflectableRefCount' - * because the refcount part is only used for ref pointing in the ui - */ -class CReflectableRefPtrTarget : public CReflectable, public NLMISC::CRefCount -{ -public: - virtual ~CReflectableRefPtrTarget(); -}; - - -class CReflectableLuaRef -{ -public: - CReflectableLuaRef(CReflectableRefPtrTarget *ptr = NULL) : Ptr(ptr), _ClassInfo(NULL) {} - NLMISC::CRefPtr Ptr; - const CClassInfo &getClassInfo() const; - // IMPORTANT : luaStringPtr should have been obtained from lua, see remark in CClassInfo - const CReflectedProperty *getProp(const char *luaStringPtr) const; -private: - // cache to class definition of the pointee object (once a CReflectableLuaRef created in lua, it remains a *const* pointer) - mutable const CClassInfo *_ClassInfo; -}; - - #endif diff --git a/code/nel/src/gui/lua_ihm.cpp b/code/nel/src/gui/lua_ihm.cpp index 7ec02ee8a..8cd1ea463 100644 --- a/code/nel/src/gui/lua_ihm.cpp +++ b/code/nel/src/gui/lua_ihm.cpp @@ -16,7 +16,6 @@ #include "nel/gui/lua_helper.h" -using namespace NLGUI; #include @@ -92,840 +91,848 @@ std::ostream &operator<<(std::ostream &str, const ucstring &value) return str << value.toString(); } -struct CMiscFunctions +namespace NLGUI { - static std::string fileLookup(const std::string &fileName) + + struct CMiscFunctions { - 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); + 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(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(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(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 + // *************************************************************************** + // *************************************************************************** -// *************************************************************************** -bool CLuaIHM::pop(CLuaState &ls, NLMISC::CRGBA &dest) -{ - //H_AUTO(Lua_CLuaIHM_pop) - try + CLuaState * ELuaIHMException::getLuaState() { - 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(obj); + return CLuaManager::getInstance().getLuaState(); } - 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(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(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) - } -} - -// *************************************************************************** -void CLuaIHM::registerBasics(CLuaState &ls) -{ - //H_AUTO(Lua_CLuaIHM_registerBasics) - using namespace luabind; - lua_State *L= ls.getStatePointer(); - - // RGBA - module(L) - [ - class_("CRGBA") - .def(constructor<>()) - .def(constructor()) - .def(constructor()) - .def(constructor()) - .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") - .def(constructor<>()) - .def(constructor()) - .def(constructor()) - .def(const_self + other()) - .def(other() + const_self) - // NB nico : luabind crash not solved here -> use concatUCString as a replacement -// .def(const_self + other()) - .def(const_self < other()) - .def(const_self == other()) - .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()) - ]; - - // CVector2f - module(L) - [ - class_("CVector2f") - .def(constructor()) - .def_readwrite("x", &NLMISC::CVector2f::x) - .def_readwrite("y", &NLMISC::CVector2f::y) - ]; } + // *************************************************************************** + #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); \ + } -// *************************************************************************** -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()) + // Basic LUA types + namespace luabind { - 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; -} - -// *************************************************************************** -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: + namespace converters { - 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 + 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) } - 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; } -} -static CLuaString lstr_Env("Env"); -static CLuaString lstr_isNil("isNil"); - -// *************************************************************************** -void CLuaIHM::luaValueToReflectedProperty(CLuaState &ls, int stackIndex, CReflectable &target, const CReflectedProperty &property) throw(ELuaIHMException) +namespace NLGUI { - //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) + + // *************************************************************************** + void CLuaIHM::registerBasics(CLuaState &ls) { - case CReflectedProperty::Boolean: + //H_AUTO(Lua_CLuaIHM_registerBasics) + using namespace luabind; + lua_State *L= ls.getStatePointer(); + + // RGBA + module(L) + [ + class_("CRGBA") + .def(constructor<>()) + .def(constructor()) + .def(constructor()) + .def(constructor()) + .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") + .def(constructor<>()) + .def(constructor()) + .def(constructor()) + .def(const_self + other()) + .def(other() + const_self) + // NB nico : luabind crash not solved here -> use concatUCString as a replacement + // .def(const_self + other()) + .def(const_self < other()) + .def(const_self == other()) + .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()) + ]; + + // CVector2f + module(L) + [ + class_("CVector2f") + .def(constructor()) + .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; + } + + // *************************************************************************** + 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: { - bool val= ls.toBoolean(stackIndex); - (target.*(property.SetMethod.SetBool))(val); - return; + 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 } - case CReflectedProperty::SInt32: + break; + case CReflectedProperty::RGBA: { - sint32 val= (sint32)ls.toNumber(stackIndex); - (target.*(property.SetMethod.SetSInt32))(val); - return; + 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 } - case CReflectedProperty::UInt32: + break; + case CReflectedProperty::LuaMethod: { - 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()) + // must create a closure that will forward the call to the real method + if (!property.LuaMethodRef.isValid()) { - std::string str; - ls.toString(stackIndex, str); - val= str; + ls.pushLightUserData((void *) &property); + ls.pushLightUserData((void *) &ls); + ls.pushCClosure(luaMethodCall, 2); + property.LuaMethodRef.pop(ls); } - else + nlassert(property.LuaMethodRef.getLuaState() == &ls); // only one single lua state supported for now + property.LuaMethodRef.push(); + } + break; + default: + nlstop; + break; + } + } + + static CLuaString lstr_Env("Env"); + static CLuaString lstr_isNil("isNil"); + + // *************************************************************************** + 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: { - // else this should be a ucstring - if (!pop(ls, val)) + 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()) { - throw ELuaIHMException("You must set a string, number or ucstring to UI property '%s'", property.Name.c_str()); + 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; } - (target.*(property.SetMethod.SetUCString))(val); - return; - } - case CReflectedProperty::RGBA: - { - CRGBA color; - if (pop(ls, color)) + case CReflectedProperty::RGBA: { - (target.*(property.SetMethod.SetRGBA))(color); + 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; } - 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 == "") - 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 Functions - - // 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) - ]; - - // 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(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(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"); + default: + nlstop; } - dest.Vertices.push_back(pos); } + + + // *************************************************************************** + 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 == "") + 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 Functions + + // 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) + ]; + + // 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(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(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); + } + } + } - - diff --git a/code/nel/src/gui/lua_manager.cpp b/code/nel/src/gui/lua_manager.cpp index f7606ec2b..5e9ef7761 100644 --- a/code/nel/src/gui/lua_manager.cpp +++ b/code/nel/src/gui/lua_manager.cpp @@ -18,17 +18,22 @@ #include "nel/gui/lua_manager.h" #include "nel/gui/lua_helper.h" -bool CLuaManager::debugLua = false; -CLuaManager* CLuaManager::instance = NULL; - -CLuaManager::CLuaManager() +namespace NLGUI { - luaState = new NLGUI::CLuaState( debugLua ); + + bool CLuaManager::debugLua = false; + CLuaManager* CLuaManager::instance = NULL; + + CLuaManager::CLuaManager() + { + luaState = new NLGUI::CLuaState( debugLua ); + } + + CLuaManager::~CLuaManager() + { + luaState = NULL; + } + + } -CLuaManager::~CLuaManager() -{ - luaState = NULL; -} - - diff --git a/code/nel/src/gui/lua_object.cpp b/code/nel/src/gui/lua_object.cpp index 432e3c607..b11705f5b 100644 --- a/code/nel/src/gui/lua_object.cpp +++ b/code/nel/src/gui/lua_object.cpp @@ -14,643 +14,638 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -//#include "stdpch.h" #include "nel/gui/lua_object.h" #include "nel/gui/lua_ihm.h" -//#include "lua_ihm_ryzom.h" #include "nel/gui/lua_helper.h" -using namespace NLGUI; -// -//#include "interface_manager.h" -//////////////// -// CLuaObject // -//////////////// - -// ************************************************* -CLuaObject::CLuaObject(CLuaState &state, const char *id) +namespace NLGUI { - pop(state, id); -} -// ************************************************* -CLuaObject::CLuaObject(CLuaState &state, const std::string &id) -{ - pop(state, id.c_str()); -} - - -// ************************************************* -bool CLuaObject::isValid() const -{ - return getLuaState() != NULL; -} - -// ************************************************* -CLuaState *CLuaObject::getLuaState() const -{ - return _LuaState; -} - -// ************************************************* -CLuaObject::CLuaObject(const CLuaObject &other) -{ - if (other.isValid()) + // ************************************************* + CLuaObject::CLuaObject(CLuaState &state, const char *id) { + pop(state, id); + } + + // ************************************************* + CLuaObject::CLuaObject(CLuaState &state, const std::string &id) + { + pop(state, id.c_str()); + } + + + // ************************************************* + bool CLuaObject::isValid() const + { + return getLuaState() != NULL; + } + + // ************************************************* + CLuaState *CLuaObject::getLuaState() const + { + return _LuaState; + } + + // ************************************************* + CLuaObject::CLuaObject(const CLuaObject &other) + { + if (other.isValid()) + { + other.push(); + nlassert(other.getLuaState()); + pop(*other.getLuaState()); + _Id = other._Id; + } + // else ... copy of an invalid CLuaObject( is an invalid CLuaObject + } + + // ************************************************* + CLuaObject &CLuaObject::operator=(const CLuaObject &other) + { + if (!other.isValid()) + { + release(); + return *this; + } other.push(); - nlassert(other.getLuaState()); pop(*other.getLuaState()); _Id = other._Id; - } - // else ... copy of an invalid CLuaObject( is an invalid CLuaObject -} - -// ************************************************* -CLuaObject &CLuaObject::operator=(const CLuaObject &other) -{ - if (!other.isValid()) - { - release(); return *this; } - other.push(); - pop(*other.getLuaState()); - _Id = other._Id; - return *this; -} -// ************************************************* -bool CLuaObject::rawEqual(const CLuaObject &other) const -{ - nlassert(other.getLuaState() == getLuaState()); - push(); - other.push(); - bool equal = other.getLuaState()->rawEqual(-1, -2); - getLuaState()->pop(2); - return equal; -} - -// ************************************************* -CLuaObject::~CLuaObject() -{ - release(); -} - -// ************************************************* -void CLuaObject::release() -{ - if (_LuaState) + // ************************************************* + bool CLuaObject::rawEqual(const CLuaObject &other) const { - CLuaStackChecker lsc(_LuaState); + nlassert(other.getLuaState() == getLuaState()); + push(); + other.push(); + bool equal = other.getLuaState()->rawEqual(-1, -2); + getLuaState()->pop(2); + return equal; + } + + // ************************************************* + CLuaObject::~CLuaObject() + { + release(); + } + + // ************************************************* + void CLuaObject::release() + { + if (_LuaState) + { + CLuaStackChecker lsc(_LuaState); + _LuaState->pushLightUserData((void *) this); + _LuaState->pushNil(); + _LuaState->setTable(LUA_REGISTRYINDEX); + _LuaState = NULL; + } + } + + // ************************************************* + void CLuaObject::pop(CLuaState &luaState, const char *id) + { + release(); + nlassert(luaState.getTop() >= 1); + { + CLuaStackChecker lsc(&luaState); + luaState.pushLightUserData((void *) this); + luaState.pushValue(-2); // copy original object + luaState.setTable(LUA_REGISTRYINDEX); + } + luaState.pop(); + _LuaState = &luaState; + _Id = id; + } + + // ************************************************* + void CLuaObject::push() const + { + nlassert(isValid()); _LuaState->pushLightUserData((void *) this); - _LuaState->pushNil(); - _LuaState->setTable(LUA_REGISTRYINDEX); - _LuaState = NULL; + _LuaState->getTable(LUA_REGISTRYINDEX); } -} -// ************************************************* -void CLuaObject::pop(CLuaState &luaState, const char *id) -{ - release(); - nlassert(luaState.getTop() >= 1); + // ************************************************* + int CLuaObject::type() const { - CLuaStackChecker lsc(&luaState); - luaState.pushLightUserData((void *) this); - luaState.pushValue(-2); // copy original object - luaState.setTable(LUA_REGISTRYINDEX); + push(); + int type = _LuaState->type(); + _LuaState->pop(); + return type; } - luaState.pop(); - _LuaState = &luaState; - _Id = id; -} -// ************************************************* -void CLuaObject::push() const -{ - nlassert(isValid()); - _LuaState->pushLightUserData((void *) this); - _LuaState->getTable(LUA_REGISTRYINDEX); -} - -// ************************************************* -int CLuaObject::type() const -{ - push(); - int type = _LuaState->type(); - _LuaState->pop(); - return type; -} - -// ************************************************* -const char *CLuaObject::getTypename() const -{ - push(); - const char *typeName = _LuaState->getTypename(-1); - _LuaState->pop(); - return typeName; -} - -// ************************************************* -bool CLuaObject::isNil() const { push(); bool result = _LuaState->isNil(); _LuaState->pop(); return result; } -bool CLuaObject::isNumber() const { push(); bool result = _LuaState->isNumber(); _LuaState->pop(); return result; } -bool CLuaObject::isBoolean() const { push(); bool result = _LuaState->isBoolean(); _LuaState->pop(); return result; } -bool CLuaObject::isString() const { push(); bool result = _LuaState->isString(); _LuaState->pop(); return result; } -bool CLuaObject::isFunction() const { push(); bool result = _LuaState->isFunction(); _LuaState->pop(); return result; } -bool CLuaObject::isCFunction() const { push(); bool result = _LuaState->isCFunction(); _LuaState->pop(); return result; } -bool CLuaObject::isTable() const { push(); bool result = _LuaState->isTable(); _LuaState->pop(); return result; } -bool CLuaObject::isUserData() const { push(); bool result = _LuaState->isUserData(); _LuaState->pop(); return result; } -bool CLuaObject::isLightUserData() const { push(); bool result = _LuaState->isLightUserData(); _LuaState->pop(); return result; } -bool CLuaObject::isRGBA() const -{ - if (!isUserData()) return false; - push(); - NLMISC::CRGBA dummy; - return CLuaIHM::pop(*_LuaState, dummy); -} - -// ************************************************* -bool CLuaObject::toBoolean() const { push(); bool result = _LuaState->toBoolean(); _LuaState->pop(); return result; } -lua_Number CLuaObject::toNumber() const { push(); lua_Number result = _LuaState->toNumber(); _LuaState->pop(); return result; } -std::string CLuaObject::toString() const -{ - push(); - const char *str = _LuaState->toString(); - std::string result = str ? str : ""; - _LuaState->pop(); - return result; -} -lua_CFunction CLuaObject::toCFunction() const { push(); lua_CFunction result = _LuaState->toCFunction(); _LuaState->pop(); return result; } -void *CLuaObject::toUserData() const { push(); void *result = _LuaState->toUserData(); _LuaState->pop(); return result; } -const void *CLuaObject::toPointer() const { push(); const void *result = _LuaState->toPointer(); _LuaState->pop(); return result; } -NLMISC::CRGBA CLuaObject::toRGBA() const -{ - NLMISC::CRGBA result; - push(); - if (CLuaIHM::pop(*_LuaState, result)) + // ************************************************* + const char *CLuaObject::getTypename() const { + push(); + const char *typeName = _LuaState->getTypename(-1); + _LuaState->pop(); + return typeName; + } + + // ************************************************* + bool CLuaObject::isNil() const { push(); bool result = _LuaState->isNil(); _LuaState->pop(); return result; } + bool CLuaObject::isNumber() const { push(); bool result = _LuaState->isNumber(); _LuaState->pop(); return result; } + bool CLuaObject::isBoolean() const { push(); bool result = _LuaState->isBoolean(); _LuaState->pop(); return result; } + bool CLuaObject::isString() const { push(); bool result = _LuaState->isString(); _LuaState->pop(); return result; } + bool CLuaObject::isFunction() const { push(); bool result = _LuaState->isFunction(); _LuaState->pop(); return result; } + bool CLuaObject::isCFunction() const { push(); bool result = _LuaState->isCFunction(); _LuaState->pop(); return result; } + bool CLuaObject::isTable() const { push(); bool result = _LuaState->isTable(); _LuaState->pop(); return result; } + bool CLuaObject::isUserData() const { push(); bool result = _LuaState->isUserData(); _LuaState->pop(); return result; } + bool CLuaObject::isLightUserData() const { push(); bool result = _LuaState->isLightUserData(); _LuaState->pop(); return result; } + bool CLuaObject::isRGBA() const + { + if (!isUserData()) return false; + push(); + NLMISC::CRGBA dummy; + return CLuaIHM::pop(*_LuaState, dummy); + } + + // ************************************************* + bool CLuaObject::toBoolean() const { push(); bool result = _LuaState->toBoolean(); _LuaState->pop(); return result; } + lua_Number CLuaObject::toNumber() const { push(); lua_Number result = _LuaState->toNumber(); _LuaState->pop(); return result; } + std::string CLuaObject::toString() const + { + push(); + const char *str = _LuaState->toString(); + std::string result = str ? str : ""; + _LuaState->pop(); return result; } - return NLMISC::CRGBA::Black; -} - -// ************************************************* -CLuaObject::operator bool() const { return toBoolean(); } -CLuaObject::operator float() const { return (float) toNumber(); } -CLuaObject::operator double() const { return (double) toNumber(); } -CLuaObject::operator std::string() const { return toString(); } - - -// ************************************************* -bool CLuaObject::isEnumerable() const -{ - if (isTable()) return true; - CLuaStackRestorer lsr(_LuaState, _LuaState->getTop()); - push(); - if (_LuaState->getMetaTable(-1)) + lua_CFunction CLuaObject::toCFunction() const { push(); lua_CFunction result = _LuaState->toCFunction(); _LuaState->pop(); return result; } + void *CLuaObject::toUserData() const { push(); void *result = _LuaState->toUserData(); _LuaState->pop(); return result; } + const void *CLuaObject::toPointer() const { push(); const void *result = _LuaState->toPointer(); _LuaState->pop(); return result; } + NLMISC::CRGBA CLuaObject::toRGBA() const { - _LuaState->remove(-2); - _LuaState->push("__next"); - _LuaState->getTable(-2); - return _LuaState->isFunction(); + NLMISC::CRGBA result; + push(); + if (CLuaIHM::pop(*_LuaState, result)) + { + return result; + } + return NLMISC::CRGBA::Black; } - return false; -} -// ************************************************* -CLuaEnumeration CLuaObject::enumerate() throw(ELuaNotATable) -{ - if (!isEnumerable()) - { - throw ELuaNotATable(NLMISC::toString("Called CLuaObject::enumerate on an object that has no enumeration (not a table or no '__next' method in the metatable). Object is '%s' with type '%s'", getId().c_str(), getTypename()).c_str()); - } - return CLuaEnumeration(*this); -} - -// ************************************************* -CLuaObject CLuaObject::operator[](const char *key) const -{ - nlassert(key); - nlassert(isValid()); - if (!isEnumerable()) - { - _LuaState->pushNil(); - CLuaObject result(*_LuaState); - return result; - } - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->getTable(-2); - CLuaObject subObject(*_LuaState, concatId(getId(), key)); - _LuaState->pop(); // pop the sub object - return subObject; -} - -// ************************************************* -CLuaObject CLuaObject::operator[](double key) const -{ - nlassert(isValid()); - if (!isEnumerable()) - { - _LuaState->pushNil(); - CLuaObject result(*_LuaState); - return result; - } - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->getTable(-2); - CLuaObject subObject(*_LuaState, concatId(getId(), NLMISC::toString(key))); - _LuaState->pop(); // pop the sub object - return subObject; -} - -// ************************************************* -CLuaObject CLuaObject::at(const char *key) const throw(ELuaNotATable) -{ - if (!isEnumerable()) throw ELuaNotATable(NLMISC::toString("Can't get key '%s' in object '%s' because type is '%s', it is not a table.", key, getId().c_str(), getTypename()).c_str()); - return operator[](key); -} - -// ************************************************* -bool CLuaObject::hasKey(const char *key) const -{ - if (!isEnumerable()) throw ELuaNotATable(NLMISC::toString("Trying to access key '%s' on object '%s' of type %s.", key, getId().c_str(), getTypename()).c_str()); - CLuaObject value = operator[](key); - return (!value.isNil()); -} - -// ************************************************* -CLuaObject CLuaObject::newTable(const char *tableName) throw(ELuaNotATable) -{ - nlassert(tableName); - nlassert(isValid()); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to create a subtable '%s' on object '%s' of type %s (not a table).", tableName, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(tableName); - _LuaState->newTable(); - _LuaState->setTable(-3); - _LuaState->pop(); - return at(tableName); //\TODO nico double copy here ... -} - -// ************************************************* -void CLuaObject::setValue(const char *key, const CLuaObject &value) throw(ELuaNotATable) -{ - nlassert(key); - nlassert(isValid()); - nlassert(value.isValid()); - nlassert(getLuaState() == value.getLuaState()); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%s' on object '%s' of type %s (not a table).", key, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - value.push(); - _LuaState->setTable(-3); - _LuaState->pop(); -} - -// ************************************************* -void CLuaObject::setNil(const char *key) throw(ELuaNotATable) -{ - nlassert(key); - nlassert(isValid()); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value 'nil' at key %s on object '%s' of type %s (not a table).", key, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->pushNil(); - _LuaState->setTable(-3); - _LuaState->pop(); -} - -// ************************************************* -void CLuaObject::setValue(const char *key, const char *value) throw(ELuaNotATable) -{ - nlassert(value); - nlassert(key); - nlassert(isValid()); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%s' at key %s on object '%s' of type %s (not a table).", value, key, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->push(value); - _LuaState->setTable(-3); - _LuaState->pop(); -} - -// ************************************************* -void CLuaObject::setValue(const char *key, const std::string &value) throw(ELuaNotATable) -{ - setValue(key, value.c_str()); -} - -// ************************************************* -void CLuaObject::setValue(const char *key, bool value) throw(ELuaNotATable) -{ - nlassert(key); - nlassert(isValid()); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%s' at key %s on object '%s' of type %s (not a table).", value ? "true" : "false", key, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->push(value); - _LuaState->setTable(-3); - _LuaState->pop(); -} - -// ************************************************* -void CLuaObject::setValue(const char *key, TLuaWrappedFunction value) throw(ELuaNotATable) -{ - nlassert(key); - nlassert(isValid()); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a function value '%p' at key %s on object '%s' of type %s (not a table).", value, key, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->push(value); - _LuaState->setTable(-3); - _LuaState->pop(); -} - -// ************************************************* -void CLuaObject::setValue(const char *key, double value) throw(ELuaNotATable) -{ - nlassert(key); - nlassert(isValid()); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%lf' at key %s on object '%s' of type %s (not a table).", value, key, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->push(value); - _LuaState->setTable(-3); - _LuaState->pop(); -} - -// ************************************************* -void CLuaObject::eraseValue(const char *key) throw(ELuaNotATable) -{ - nlassert(isValid()); - nlassert(key); - if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to erase a value with key '%s' on object '%s' of type %s (not a table).", key, getId().c_str(), getTypename())); - CLuaStackChecker lsc(_LuaState); - push(); - _LuaState->push(key); - _LuaState->pushNil(); - _LuaState->setTable(-3); - _LuaState->pop(); -} - -// ************************************************* -bool CLuaObject::callNoThrow(int numArgs, int numRet) -{ - nlassert(isValid()); - if (!isFunction()) - { - nlwarning("Calling a non function object (id = %s, type = %s)", getId().c_str(), getTypename()); - _LuaState->pop(numArgs); - return false; - } - // TMP TMP - static volatile bool dumpFunction = false; - if (dumpFunction) + // ************************************************* + CLuaObject::operator bool() const { return toBoolean(); } + CLuaObject::operator float() const { return (float) toNumber(); } + CLuaObject::operator double() const { return (double) toNumber(); } + CLuaObject::operator std::string() const { return toString(); } + + + // ************************************************* + bool CLuaObject::isEnumerable() const { + if (isTable()) return true; CLuaStackRestorer lsr(_LuaState, _LuaState->getTop()); push(); - lua_Debug ar; - lua_getinfo (_LuaState->getStatePointer(), ">lS", &ar); - nlwarning((std::string(ar.what) + ", at line " + NLMISC::toString(ar.linedefined) + " in " + std::string(ar.source)).c_str()); + if (_LuaState->getMetaTable(-1)) + { + _LuaState->remove(-2); + _LuaState->push("__next"); + _LuaState->getTable(-2); + return _LuaState->isFunction(); + } + return false; } - push(); - _LuaState->insert(-1 - numArgs); // put the function before its arguments - int result = _LuaState->pcall(numArgs, numRet); - switch (result) - { - case LUA_ERRRUN: - case LUA_ERRMEM: - case LUA_ERRERR: - nlwarning(_LuaState->toString(-1)); - _LuaState->pop(); - return false; - break; - case 0: - return true; - break; - default: - nlassert(0); - break; - } - return false; -} -// ************************************************* -bool CLuaObject::callMethodByNameNoThrow(const char *name, int numArgs, int numRet) -{ - nlassert(isValid()); - int initialStackSize = _LuaState->getTop(); - if (!isTable() && !isUserData()) + // ************************************************* + CLuaEnumeration CLuaObject::enumerate() throw(ELuaNotATable) { - nlwarning("Can't call method : object is not a table (id = %s)", getId().c_str()); + if (!isEnumerable()) + { + throw ELuaNotATable(NLMISC::toString("Called CLuaObject::enumerate on an object that has no enumeration (not a table or no '__next' method in the metatable). Object is '%s' with type '%s'", getId().c_str(), getTypename()).c_str()); + } + return CLuaEnumeration(*this); + } + + // ************************************************* + CLuaObject CLuaObject::operator[](const char *key) const + { + nlassert(key); + nlassert(isValid()); + if (!isEnumerable()) + { + _LuaState->pushNil(); + CLuaObject result(*_LuaState); + return result; + } + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->getTable(-2); + CLuaObject subObject(*_LuaState, concatId(getId(), key)); + _LuaState->pop(); // pop the sub object + return subObject; + } + + // ************************************************* + CLuaObject CLuaObject::operator[](double key) const + { + nlassert(isValid()); + if (!isEnumerable()) + { + _LuaState->pushNil(); + CLuaObject result(*_LuaState); + return result; + } + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->getTable(-2); + CLuaObject subObject(*_LuaState, concatId(getId(), NLMISC::toString(key))); + _LuaState->pop(); // pop the sub object + return subObject; + } + + // ************************************************* + CLuaObject CLuaObject::at(const char *key) const throw(ELuaNotATable) + { + if (!isEnumerable()) throw ELuaNotATable(NLMISC::toString("Can't get key '%s' in object '%s' because type is '%s', it is not a table.", key, getId().c_str(), getTypename()).c_str()); + return operator[](key); + } + + // ************************************************* + bool CLuaObject::hasKey(const char *key) const + { + if (!isEnumerable()) throw ELuaNotATable(NLMISC::toString("Trying to access key '%s' on object '%s' of type %s.", key, getId().c_str(), getTypename()).c_str()); + CLuaObject value = operator[](key); + return (!value.isNil()); + } + + // ************************************************* + CLuaObject CLuaObject::newTable(const char *tableName) throw(ELuaNotATable) + { + nlassert(tableName); + nlassert(isValid()); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to create a subtable '%s' on object '%s' of type %s (not a table).", tableName, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(tableName); + _LuaState->newTable(); + _LuaState->setTable(-3); + _LuaState->pop(); + return at(tableName); //\TODO nico double copy here ... + } + + // ************************************************* + void CLuaObject::setValue(const char *key, const CLuaObject &value) throw(ELuaNotATable) + { + nlassert(key); + nlassert(isValid()); + nlassert(value.isValid()); + nlassert(getLuaState() == value.getLuaState()); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%s' on object '%s' of type %s (not a table).", key, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + value.push(); + _LuaState->setTable(-3); + _LuaState->pop(); + } + + // ************************************************* + void CLuaObject::setNil(const char *key) throw(ELuaNotATable) + { + nlassert(key); + nlassert(isValid()); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value 'nil' at key %s on object '%s' of type %s (not a table).", key, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->pushNil(); + _LuaState->setTable(-3); + _LuaState->pop(); + } + + // ************************************************* + void CLuaObject::setValue(const char *key, const char *value) throw(ELuaNotATable) + { + nlassert(value); + nlassert(key); + nlassert(isValid()); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%s' at key %s on object '%s' of type %s (not a table).", value, key, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->push(value); + _LuaState->setTable(-3); + _LuaState->pop(); + } + + // ************************************************* + void CLuaObject::setValue(const char *key, const std::string &value) throw(ELuaNotATable) + { + setValue(key, value.c_str()); + } + + // ************************************************* + void CLuaObject::setValue(const char *key, bool value) throw(ELuaNotATable) + { + nlassert(key); + nlassert(isValid()); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%s' at key %s on object '%s' of type %s (not a table).", value ? "true" : "false", key, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->push(value); + _LuaState->setTable(-3); + _LuaState->pop(); + } + + // ************************************************* + void CLuaObject::setValue(const char *key, TLuaWrappedFunction value) throw(ELuaNotATable) + { + nlassert(key); + nlassert(isValid()); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a function value '%p' at key %s on object '%s' of type %s (not a table).", value, key, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->push(value); + _LuaState->setTable(-3); + _LuaState->pop(); + } + + // ************************************************* + void CLuaObject::setValue(const char *key, double value) throw(ELuaNotATable) + { + nlassert(key); + nlassert(isValid()); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to set a value '%lf' at key %s on object '%s' of type %s (not a table).", value, key, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->push(value); + _LuaState->setTable(-3); + _LuaState->pop(); + } + + // ************************************************* + void CLuaObject::eraseValue(const char *key) throw(ELuaNotATable) + { + nlassert(isValid()); + nlassert(key); + if (!isTable()) throw ELuaNotATable(NLMISC::toString("Trying to erase a value with key '%s' on object '%s' of type %s (not a table).", key, getId().c_str(), getTypename())); + CLuaStackChecker lsc(_LuaState); + push(); + _LuaState->push(key); + _LuaState->pushNil(); + _LuaState->setTable(-3); + _LuaState->pop(); + } + + // ************************************************* + bool CLuaObject::callNoThrow(int numArgs, int numRet) + { + nlassert(isValid()); + if (!isFunction()) + { + nlwarning("Calling a non function object (id = %s, type = %s)", getId().c_str(), getTypename()); + _LuaState->pop(numArgs); + return false; + } + // TMP TMP + static volatile bool dumpFunction = false; + if (dumpFunction) + { + CLuaStackRestorer lsr(_LuaState, _LuaState->getTop()); + push(); + lua_Debug ar; + lua_getinfo (_LuaState->getStatePointer(), ">lS", &ar); + nlwarning((std::string(ar.what) + ", at line " + NLMISC::toString(ar.linedefined) + " in " + std::string(ar.source)).c_str()); + } + push(); + _LuaState->insert(-1 - numArgs); // put the function before its arguments + int result = _LuaState->pcall(numArgs, numRet); + switch (result) + { + case LUA_ERRRUN: + case LUA_ERRMEM: + case LUA_ERRERR: + nlwarning(_LuaState->toString(-1)); + _LuaState->pop(); + return false; + break; + case 0: + return true; + break; + default: + nlassert(0); + break; + } + return false; + } + + // ************************************************* + bool CLuaObject::callMethodByNameNoThrow(const char *name, int numArgs, int numRet) + { + nlassert(isValid()); + int initialStackSize = _LuaState->getTop(); + if (!isTable() && !isUserData()) + { + nlwarning("Can't call method : object is not a table (id = %s)", getId().c_str()); + _LuaState->setTop(std::max(0, initialStackSize - numArgs)); + return false; + } + CLuaObject method = (*this)[name]; + push(); // the 'self' parameter + _LuaState->insert(-1 - numArgs); // put 'self' before the arguments + if (method.callNoThrow(numArgs + 1, numRet)) + { + return true; + } _LuaState->setTop(std::max(0, initialStackSize - numArgs)); return false; } - CLuaObject method = (*this)[name]; - push(); // the 'self' parameter - _LuaState->insert(-1 - numArgs); // put 'self' before the arguments - if (method.callNoThrow(numArgs + 1, numRet)) - { - return true; - } - _LuaState->setTop(std::max(0, initialStackSize - numArgs)); - return false; -} -///////////////////// -// CLuaEnumeration // -///////////////////// + ///////////////////// + // CLuaEnumeration // + ///////////////////// -// ************************************************* -CLuaEnumeration::CLuaEnumeration(CLuaObject &table) -{ - nlassert(table.isEnumerable()); - CLuaState *luaState = table.getLuaState(); - CLuaStackChecker lsc(luaState); - // get pointer to the 'next' function - luaState->pushValue(LUA_GLOBALSINDEX); - _NextFunction = CLuaObject(*luaState)["next"]; - // - nlassert(luaState); - table.push(); - luaState->pushNil(); - _HasNext = false; - if (_NextFunction.callNoThrow(2, 2)) + // ************************************************* + CLuaEnumeration::CLuaEnumeration(CLuaObject &table) { - _Value.pop(*luaState); - _Key.pop(*luaState); - _HasNext = !_Key.isNil(); - _Value.setId(CLuaObject::concatId(table.getId(), _Key.toString())); - _Table = table; + nlassert(table.isEnumerable()); + CLuaState *luaState = table.getLuaState(); + CLuaStackChecker lsc(luaState); + // get pointer to the 'next' function + luaState->pushValue(LUA_GLOBALSINDEX); + _NextFunction = CLuaObject(*luaState)["next"]; + // + nlassert(luaState); + table.push(); + luaState->pushNil(); + _HasNext = false; + if (_NextFunction.callNoThrow(2, 2)) + { + _Value.pop(*luaState); + _Key.pop(*luaState); + _HasNext = !_Key.isNil(); + _Value.setId(CLuaObject::concatId(table.getId(), _Key.toString())); + _Table = table; + } + } -} - -// ************************************************* -const CLuaObject &CLuaEnumeration::nextKey() const -{ - nlassert(_HasNext); - return _Key; -} - -// ************************************************* -CLuaObject &CLuaEnumeration::nextValue() -{ - nlassert(_HasNext); - return _Value; -} - -// ************************************************* -CLuaObject CLuaObject::getMetaTable() const -{ - nlassert(isValid()); - CLuaStackChecker lsc(_LuaState); - push(); - if (_LuaState->getMetaTable(-1)) + // ************************************************* + const CLuaObject &CLuaEnumeration::nextKey() const { - _LuaState->remove(-2); + nlassert(_HasNext); + return _Key; + } + + // ************************************************* + CLuaObject &CLuaEnumeration::nextValue() + { + nlassert(_HasNext); + return _Value; + } + + // ************************************************* + CLuaObject CLuaObject::getMetaTable() const + { + nlassert(isValid()); + CLuaStackChecker lsc(_LuaState); + push(); + if (_LuaState->getMetaTable(-1)) + { + _LuaState->remove(-2); + return CLuaObject(*_LuaState); + } + _LuaState->pop(); + _LuaState->pushNil(); return CLuaObject(*_LuaState); } - _LuaState->pop(); - _LuaState->pushNil(); - return CLuaObject(*_LuaState); -} -// ************************************************* -bool CLuaObject::setMetaTable(CLuaObject &metatable) -{ - nlassert(isValid()); - nlassert(metatable.isValid()); - nlassert(this->getLuaState() == metatable.getLuaState()); - CLuaStackChecker lsc(_LuaState); - push(); - metatable.push(); - bool ok = _LuaState->setMetaTable(-2); - _LuaState->pop(1); - return ok; -} - -// ************************************************* -std::string CLuaObject::toStringRecurse(uint depth /*=0*/, uint maxDepth /*= 20*/, std::set *alreadySeen /*= NULL */) const -{ - if (maxDepth != 0 && depth > maxDepth) return ""; - const uint INDENT_NUM_BLANK = 2; - std::string indentStr(depth * INDENT_NUM_BLANK, ' '); - nlassert(_LuaState); - if (isEnumerable()) // is enumeration possible on that object ? + // ************************************************* + bool CLuaObject::setMetaTable(CLuaObject &metatable) { - std::string result; - if (alreadySeen) + nlassert(isValid()); + nlassert(metatable.isValid()); + nlassert(this->getLuaState() == metatable.getLuaState()); + CLuaStackChecker lsc(_LuaState); + push(); + metatable.push(); + bool ok = _LuaState->setMetaTable(-2); + _LuaState->pop(1); + return ok; + } + + // ************************************************* + std::string CLuaObject::toStringRecurse(uint depth /*=0*/, uint maxDepth /*= 20*/, std::set *alreadySeen /*= NULL */) const + { + if (maxDepth != 0 && depth > maxDepth) return ""; + const uint INDENT_NUM_BLANK = 2; + std::string indentStr(depth * INDENT_NUM_BLANK, ' '); + nlassert(_LuaState); + if (isEnumerable()) // is enumeration possible on that object ? { - if (alreadySeen->count(toPointer())) // avoid cyclic graph (infinite recursion else) + std::string result; + if (alreadySeen) { - result += indentStr +""; - return result; + if (alreadySeen->count(toPointer())) // avoid cyclic graph (infinite recursion else) + { + result += indentStr +""; + return result; + } + alreadySeen->insert(toPointer()); } - alreadySeen->insert(toPointer()); + result += indentStr + "{\n"; + CLuaObject *table = const_cast(this); + uint numElem = 0; + ENUM_LUA_TABLE(*table, it) + { + //nlwarning("entering table %s", it.nextKey().toString().c_str()); + result += std::string((depth + 1) * INDENT_NUM_BLANK, ' ') + it.nextKey().toString() + " = "; + if (it.nextValue().isEnumerable()) + { + result += "\n" + it.nextValue().toStringRecurse(depth + 1, maxDepth, alreadySeen); + } + else + { + result += it.nextValue().toStringRecurse(); + } + result += ",\n"; + ++ numElem; + if (numElem > 4000) + { + throw NLMISC::Exception("possible infinite loop, aborting enumeration"); + } + } + result += indentStr + "}"; + return result; } - result += indentStr + "{\n"; - CLuaObject *table = const_cast(this); - uint numElem = 0; - ENUM_LUA_TABLE(*table, it) + else if (isNil()) { - //nlwarning("entering table %s", it.nextKey().toString().c_str()); - result += std::string((depth + 1) * INDENT_NUM_BLANK, ' ') + it.nextKey().toString() + " = "; - if (it.nextValue().isEnumerable()) - { - result += "\n" + it.nextValue().toStringRecurse(depth + 1, maxDepth, alreadySeen); - } - else - { - result += it.nextValue().toStringRecurse(); - } - result += ",\n"; - ++ numElem; - if (numElem > 4000) - { - throw NLMISC::Exception("possible infinite loop, aborting enumeration"); - } + return (indentStr + "nil").c_str(); } - result += indentStr + "}"; - return result; - } - else if (isNil()) - { - return (indentStr + "nil").c_str(); - } - else if (isString()) - { - return (indentStr + "\"" + toString() + "\"").c_str(); - } - else if (isFunction()) - { - return (indentStr + "").c_str(); - } - else - { - return ((indentStr + toString()).c_str()); - } -} - -// ************************************************* -void CLuaObject::dump(uint maxDepth /*= 20*/, std::set *alreadySeen /*= NULL */) const -{ - try - { - std::string str = toStringRecurse(0, maxDepth, alreadySeen); - std::vector res; - NLMISC::explode(str, std::string("\n"), res); - for(uint k = 0; k < res.size(); ++k) + else if (isString()) { - NLMISC::InfoLog->forceDisplayRaw((res[k] + "\n") .c_str()); + return (indentStr + "\"" + toString() + "\"").c_str(); + } + else if (isFunction()) + { + return (indentStr + "").c_str(); + } + else + { + return ((indentStr + toString()).c_str()); } } - catch(const std::exception &e) - { - //CLuaIHMRyzom::dumpCallStack(); - nlwarning(e.what()); - } -} -// ************************************************* -std::string CLuaObject::concatId(const std::string &left,const std::string &right) -{ - if (!right.empty() && isdigit(right[0])) + // ************************************************* + void CLuaObject::dump(uint maxDepth /*= 20*/, std::set *alreadySeen /*= NULL */) const { - if (left.empty()) return "[" + right + "]"; - return left + "[" + right + "]"; + try + { + std::string str = toStringRecurse(0, maxDepth, alreadySeen); + std::vector res; + NLMISC::explode(str, std::string("\n"), res); + for(uint k = 0; k < res.size(); ++k) + { + NLMISC::InfoLog->forceDisplayRaw((res[k] + "\n") .c_str()); + } + } + catch(const std::exception &e) + { + //CLuaIHMRyzom::dumpCallStack(); + nlwarning(e.what()); + } + } + + // ************************************************* + std::string CLuaObject::concatId(const std::string &left,const std::string &right) + { + if (!right.empty() && isdigit(right[0])) + { + if (left.empty()) return "[" + right + "]"; + return left + "[" + right + "]"; + } + if (left.empty()) return right; + return left + "." + right; + + } + + // ************************************************* + void CLuaEnumeration::next() + { + nlassert(_HasNext); + CLuaState *luaState = _Table.getLuaState(); + nlassert(luaState); + CLuaStackChecker lsc(luaState); + _Table.push(); + _Key.push(); + _HasNext = false; + if (_NextFunction.callNoThrow(2, 2)) + { + _Value.pop(*luaState); + _Key.pop(*luaState); + _HasNext = !_Key.isNil(); + _Value.setId(_Table.getId() + "." + _Key.toString()); + } } - if (left.empty()) return right; - return left + "." + right; } - -// ************************************************* -void CLuaEnumeration::next() -{ - nlassert(_HasNext); - CLuaState *luaState = _Table.getLuaState(); - nlassert(luaState); - CLuaStackChecker lsc(luaState); - _Table.push(); - _Key.push(); - _HasNext = false; - if (_NextFunction.callNoThrow(2, 2)) - { - _Value.pop(*luaState); - _Key.pop(*luaState); - _HasNext = !_Key.isNil(); - _Value.setId(_Table.getId() + "." + _Key.toString()); - } -} - diff --git a/code/nel/src/gui/reflect.cpp b/code/nel/src/gui/reflect.cpp index 078fa3ef6..5058ba232 100644 --- a/code/nel/src/gui/reflect.cpp +++ b/code/nel/src/gui/reflect.cpp @@ -17,175 +17,182 @@ #include "nel/gui/reflect.h" -// Yoyo: Act like a singleton, else registerClass may crash. -CReflectSystem::TClassMap *CReflectSystem::_ClassMap= NULL; - -// hack to register the root class at startup -static const struct CRootReflectableClassRegister +namespace NLGUI { - CRootReflectableClassRegister() + // Yoyo: Act like a singleton, else registerClass may crash. + CReflectSystem::TClassMap *CReflectSystem::_ClassMap= NULL; + + // hack to register the root class at startup + static const struct CRootReflectableClassRegister { - TReflectedProperties props; - CReflectSystem::registerClass("CReflectable", "", props); - } -} _RootReflectableClassRegisterInstance; + CRootReflectableClassRegister() + { + TReflectedProperties props; + CReflectSystem::registerClass("CReflectable", "", props); + } + } _RootReflectableClassRegisterInstance; -//=================================================================================== -// release memory -void CReflectSystem::release() -{ - delete _ClassMap; - _ClassMap = NULL; -} + //=================================================================================== + // release memory + void CReflectSystem::release() + { + delete _ClassMap; + _ClassMap = NULL; + } -//=================================================================================== -void CReflectSystem::registerClass(const std::string &className, const std::string &parentName, const TReflectedProperties properties) -{ - if(!_ClassMap) _ClassMap= new TClassMap; + //=================================================================================== + void CReflectSystem::registerClass(const std::string &className, const std::string &parentName, const TReflectedProperties properties) + { + if(!_ClassMap) _ClassMap= new TClassMap; - TClassMap::const_iterator it = _ClassMap->find(className); - if (it != _ClassMap->end()) - { - nlerror("CReflectSystem::registerClass : Class registered twice : %s!", className.c_str()); + TClassMap::const_iterator it = _ClassMap->find(className); + if (it != _ClassMap->end()) + { + nlerror("CReflectSystem::registerClass : Class registered twice : %s!", className.c_str()); + } + CClassInfo &ci = (*_ClassMap)[className]; + ci.Properties = properties; + ci.ClassName = className; + for(uint k = 0; k < ci.Properties.size(); ++k) + { + ci.Properties[k].ParentClass = &ci; + } + if (parentName.empty()) + { + ci.ParentClass = NULL; + } + else + { + it = _ClassMap->find(parentName); + if (it == _ClassMap->end()) + { + nlerror("CReflectSystem::registerClass : Parent class %s not found", parentName.c_str()); + } + ci.ParentClass = &(it->second); + } } - CClassInfo &ci = (*_ClassMap)[className]; - ci.Properties = properties; - ci.ClassName = className; - for(uint k = 0; k < ci.Properties.size(); ++k) + + //=================================================================================== + const CReflectedProperty *CReflectSystem::getProperty(const std::string &className, const std::string &propertyName, bool dspWarning) { - ci.Properties[k].ParentClass = &ci; - } - if (parentName.empty()) - { - ci.ParentClass = NULL; - } - else - { - it = _ClassMap->find(parentName); + if(!_ClassMap) _ClassMap= new TClassMap; + + TClassMap::const_iterator it = _ClassMap->find(className); if (it == _ClassMap->end()) { - nlerror("CReflectSystem::registerClass : Parent class %s not found", parentName.c_str()); + nlwarning("CReflectSystem::getProperty : Unkwown class : %s", className.c_str()); + return NULL; } - ci.ParentClass = &(it->second); - } -} - -//=================================================================================== -const CReflectedProperty *CReflectSystem::getProperty(const std::string &className, const std::string &propertyName, bool dspWarning) -{ - if(!_ClassMap) _ClassMap= new TClassMap; - - TClassMap::const_iterator it = _ClassMap->find(className); - if (it == _ClassMap->end()) - { - nlwarning("CReflectSystem::getProperty : Unkwown class : %s", className.c_str()); - return NULL; - } - const CClassInfo *ci = &it->second; - while (ci) - { - // Linear search should suffice for now - for(uint k = 0; k < ci->Properties.size(); ++k) + const CClassInfo *ci = &it->second; + while (ci) { - if (ci->Properties[k].Name == propertyName) + // Linear search should suffice for now + for(uint k = 0; k < ci->Properties.size(); ++k) { - return &(ci->Properties[k]); + if (ci->Properties[k].Name == propertyName) + { + return &(ci->Properties[k]); + } } + // search in parent + ci = ci->ParentClass; } - // search in parent - ci = ci->ParentClass; - } - //\ TODO nico : possible optimization : instead of going up in the parents when - // searching for a property, it would be simpler to concatenate properties - // from parent class at registration. - // All that would be left at the end would be a hash_map of properties ... + //\ TODO nico : possible optimization : instead of going up in the parents when + // searching for a property, it would be simpler to concatenate properties + // from parent class at registration. + // All that would be left at the end would be a hash_map of properties ... - if(dspWarning) - nlwarning("CReflectSystem::getProperty : %s is not a property of class : %s", propertyName.c_str(), className.c_str()); - return NULL; -} - - -//=================================================================================== -const CClassInfo *CReflectable::getClassInfo() -{ - if (!CReflectSystem::getClassMap()) return NULL; - // TODO nico : a possible optimization would be to use the address of the static function - // 'getReflectedProperties' as a key into the CClassInfo map. This pointer uniquely identify - // classes that export properties - CReflectSystem::TClassMap::const_iterator it = CReflectSystem::getClassMap()->find(this->getReflectedClassName()); - if (it == CReflectSystem::getClassMap()->end()) - { + if(dspWarning) + nlwarning("CReflectSystem::getProperty : %s is not a property of class : %s", propertyName.c_str(), className.c_str()); return NULL; } - return &(it->second); -} -//=================================================================================== -const CReflectedProperty *CReflectable::getReflectedProperty(const std::string &propertyName, bool dspWarning) const -{ - return CReflectSystem::getProperty(this->getReflectedClassName(), propertyName, dspWarning); -} + //=================================================================================== + const CClassInfo *CReflectable::getClassInfo() + { + if (!CReflectSystem::getClassMap()) return NULL; + // TODO nico : a possible optimization would be to use the address of the static function + // 'getReflectedProperties' as a key into the CClassInfo map. This pointer uniquely identify + // classes that export properties + CReflectSystem::TClassMap::const_iterator it = CReflectSystem::getClassMap()->find(this->getReflectedClassName()); + if (it == CReflectSystem::getClassMap()->end()) + { + return NULL; + } + return &(it->second); + } + + //=================================================================================== + const CReflectedProperty *CReflectable::getReflectedProperty(const std::string &propertyName, bool dspWarning) const + { + return CReflectSystem::getProperty(this->getReflectedClassName(), propertyName, dspWarning); + } + +} #include "nel/gui/lua_manager.h" -CReflectableRefPtrTarget::~CReflectableRefPtrTarget() +namespace NLGUI { - CLuaState *lua= CLuaManager::getInstance().getLuaState(); - if(!lua) - return; - CLuaStackChecker lsc(lua); - // remove from the lua registry if i'm in - lua->pushLightUserData((void *) this); - lua->getTable(LUA_REGISTRYINDEX); - if (!lua->isNil(-1)) + CReflectableRefPtrTarget::~CReflectableRefPtrTarget() { - lua->pop(); + CLuaState *lua= CLuaManager::getInstance().getLuaState(); + if(!lua) + return; + CLuaStackChecker lsc(lua); + // remove from the lua registry if i'm in lua->pushLightUserData((void *) this); - lua->pushNil(); - lua->setTable(LUA_REGISTRYINDEX); + lua->getTable(LUA_REGISTRYINDEX); + if (!lua->isNil(-1)) + { + lua->pop(); + lua->pushLightUserData((void *) this); + lua->pushNil(); + lua->setTable(LUA_REGISTRYINDEX); + } + else + { + lua->pop(); + } } - else + + /** + * Data structure pushed in lua (a userdata) to access CReflectableRefPtrTarget derived objects + * These includes element of the GUI. + * if holds a pointer to the reflectable object, and + * a cache to its CClassInfo for fast access to exported properties + * \see reflect.h + */ + + // + + inline const CClassInfo &CReflectableLuaRef::getClassInfo() const { - lua->pop(); + nlassert(Ptr); // class info should not be accessed for a null ptr + if (_ClassInfo) return *_ClassInfo; + _ClassInfo = Ptr->getClassInfo(); + return *_ClassInfo; } -} -/** - * Data structure pushed in lua (a userdata) to access CReflectableRefPtrTarget derived objects - * These includes element of the GUI. - * if holds a pointer to the reflectable object, and - * a cache to its CClassInfo for fast access to exported properties - * \see reflect.h - */ - -// - -inline const CClassInfo &CReflectableLuaRef::getClassInfo() const -{ - nlassert(Ptr); // class info should not be accessed for a null ptr - if (_ClassInfo) return *_ClassInfo; - _ClassInfo = Ptr->getClassInfo(); - return *_ClassInfo; -} - -const CReflectedProperty *CReflectableLuaRef::getProp(const char *luaStringPtr) const -{ - const CClassInfo &ci = getClassInfo(); - CClassInfo::TLuaStrToPropMap::const_iterator it = ci.LuaStrToProp.find(luaStringPtr); - if (it != ci.LuaStrToProp.end()) + const CReflectedProperty *CReflectableLuaRef::getProp(const char *luaStringPtr) const { - return it->second.Prop; + const CClassInfo &ci = getClassInfo(); + CClassInfo::TLuaStrToPropMap::const_iterator it = ci.LuaStrToProp.find(luaStringPtr); + if (it != ci.LuaStrToProp.end()) + { + return it->second.Prop; + } + // slowly retrieve property, and store in cache + // NB nico : this could also be done at startup... + const CReflectedProperty *prop = CReflectSystem::getProperty(ci.ClassName, luaStringPtr, false); + if (!prop) return NULL; + CLuaIndexedProperty lip; + lip.Id = CLuaString(luaStringPtr); // keep a ref on the lua string to ensure that its pointer always remains valid + lip.Prop = prop; + ci.LuaStrToProp[luaStringPtr] = lip; + return prop; } - // slowly retrieve property, and store in cache - // NB nico : this could also be done at startup... - const CReflectedProperty *prop = CReflectSystem::getProperty(ci.ClassName, luaStringPtr, false); - if (!prop) return NULL; - CLuaIndexedProperty lip; - lip.Id = CLuaString(luaStringPtr); // keep a ref on the lua string to ensure that its pointer always remains valid - lip.Prop = prop; - ci.LuaStrToProp[luaStringPtr] = lip; - return prop; + } diff --git a/code/ryzom/client/src/decal_anim.h b/code/ryzom/client/src/decal_anim.h index 9dde03b9e..50ae61d66 100644 --- a/code/ryzom/client/src/decal_anim.h +++ b/code/ryzom/client/src/decal_anim.h @@ -23,7 +23,13 @@ namespace NLMISC class CVector2f; } -class CLuaObject; +namespace NLGUI +{ + class CLuaObject; +} + +using namespace NLGUI; + class CDecal; // TODO nico : this would fit nicely in the particle system animation system (would be more flexible) diff --git a/code/ryzom/client/src/interface_v3/interface_element.h b/code/ryzom/client/src/interface_v3/interface_element.h index 27d6e4656..3b5a878cb 100644 --- a/code/ryzom/client/src/interface_v3/interface_element.h +++ b/code/ryzom/client/src/interface_v3/interface_element.h @@ -25,6 +25,8 @@ #include "interface_property.h" #include "nel/gui/reflect.h" +using namespace NLGUI; + // ---------------------------------------------------------------------------- class CInterfaceGroup; diff --git a/code/ryzom/client/src/interface_v3/interface_link.h b/code/ryzom/client/src/interface_v3/interface_link.h index c83ef5034..ae88849dd 100644 --- a/code/ryzom/client/src/interface_v3/interface_link.h +++ b/code/ryzom/client/src/interface_v3/interface_link.h @@ -22,12 +22,20 @@ #include "nel/misc/cdb_branch.h" #include "nel/misc/cdb_branch_observing_handler.h" +namespace NLGUI +{ + class CReflectedProperty; +} + + class CInterfaceElement; -class CReflectedProperty; class CInterfaceExprValue; class CInterfaceGroup; class CInterfaceExprNode; +using namespace NLGUI; + + /** A link in an interface. * A link is an object that can read one or several values from the database, that can evaluate an expression * on these database entries (simple computation, using the CInterfaceExpr class), and that can affect the result to diff --git a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h index ba9089186..71fe3f398 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h +++ b/code/ryzom/client/src/interface_v3/lua_ihm_ryzom.h @@ -3,10 +3,12 @@ #include "nel/gui/lua_ihm.h" +using namespace NLGUI; + class CLuaIHMRyzom { public: - static void RegisterRyzomFunctions( NLGUI::CLuaState &ls ); + static void RegisterRyzomFunctions( CLuaState &ls ); private: static void createLuaEnumTable(CLuaState &ls, const std::string &str); diff --git a/code/ryzom/client/src/r2/displayer_base.h b/code/ryzom/client/src/r2/displayer_base.h index 26e61e0d7..40f077af2 100644 --- a/code/ryzom/client/src/r2/displayer_base.h +++ b/code/ryzom/client/src/r2/displayer_base.h @@ -21,8 +21,10 @@ #include "nel/misc/class_registry.h" #include "../interface_v3/interface_element.h" -class CLuaObject; - +namespace NLGUI +{ + class CLuaObject; +} namespace R2 { diff --git a/code/ryzom/client/src/r2/entity_custom_select_box.h b/code/ryzom/client/src/r2/entity_custom_select_box.h index f16d6f5f8..5bd923806 100644 --- a/code/ryzom/client/src/r2/entity_custom_select_box.h +++ b/code/ryzom/client/src/r2/entity_custom_select_box.h @@ -21,7 +21,12 @@ #include "nel/gui/lua_object.h" #include -class CLuaObject; +namespace NLGUI +{ + class CLuaObject; +} + +using namespace NLGUI; namespace R2 { diff --git a/code/ryzom/client/src/r2/lua_event_forwarder.h b/code/ryzom/client/src/r2/lua_event_forwarder.h index bd16cd57c..41343b127 100644 --- a/code/ryzom/client/src/r2/lua_event_forwarder.h +++ b/code/ryzom/client/src/r2/lua_event_forwarder.h @@ -20,8 +20,10 @@ namespace NLGUI { class CLuaState; + class CLuaString; } -class CLuaString; + +using namespace NLGUI; namespace R2 { diff --git a/code/ryzom/client/src/r2/prim_render.h b/code/ryzom/client/src/r2/prim_render.h index 025da5862..bab97d5f6 100644 --- a/code/ryzom/client/src/r2/prim_render.h +++ b/code/ryzom/client/src/r2/prim_render.h @@ -24,8 +24,12 @@ #include "../interface_v3/group_map.h" +namespace NLGUI +{ + class CLuaObject; +} + class CEntityCL; -class CLuaObject; class CCtrlPolygon; namespace R2 diff --git a/code/ryzom/client/src/r2/tool.h b/code/ryzom/client/src/r2/tool.h index 4e5613c55..e10e5002e 100644 --- a/code/ryzom/client/src/r2/tool.h +++ b/code/ryzom/client/src/r2/tool.h @@ -29,8 +29,9 @@ class CInterfaceManager; namespace NLGUI { class CEventDescriptor; + class CLuaObject; } -class CLuaObject; + class CGroupMap; namespace NLMISC diff --git a/code/ryzom/client/src/r2/tool_choose_pos.h b/code/ryzom/client/src/r2/tool_choose_pos.h index 9eddb3fd6..98940a8b9 100644 --- a/code/ryzom/client/src/r2/tool_choose_pos.h +++ b/code/ryzom/client/src/r2/tool_choose_pos.h @@ -25,8 +25,10 @@ class CEntity; class CEntityCL; -class CLuaObject; - +namespace NLGUI +{ + class CLuaObject; +} namespace R2 { diff --git a/code/ryzom/client/src/r2/tool_choose_pos_lua.h b/code/ryzom/client/src/r2/tool_choose_pos_lua.h index 697eb34e6..867cb98b4 100644 --- a/code/ryzom/client/src/r2/tool_choose_pos_lua.h +++ b/code/ryzom/client/src/r2/tool_choose_pos_lua.h @@ -22,8 +22,11 @@ #include "nel/gui/lua_object.h" class CEntity; -class CLuaObject; +namespace NLGUI +{ + class CLuaObject; +} namespace R2 { diff --git a/code/ryzom/client/src/r2/tool_create_entity.h b/code/ryzom/client/src/r2/tool_create_entity.h index f906bc5e3..c80475b55 100644 --- a/code/ryzom/client/src/r2/tool_create_entity.h +++ b/code/ryzom/client/src/r2/tool_create_entity.h @@ -25,8 +25,10 @@ #include "displayer_visual_entity.h" class CEntity; -class CLuaObject; - +namespace NLGUI +{ + class CLuaObject; +} namespace R2 { diff --git a/code/ryzom/client/src/r2/tool_draw_prim.h b/code/ryzom/client/src/r2/tool_draw_prim.h index fd85bd498..32f5f682e 100644 --- a/code/ryzom/client/src/r2/tool_draw_prim.h +++ b/code/ryzom/client/src/r2/tool_draw_prim.h @@ -25,8 +25,10 @@ class CEntity; -class CLuaObject; - +namespace NLGUI +{ + class CLuaObject; +} namespace R2 {