Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / gui / lua_ihm.cpp
blob229cd1f0f80238e1b2c9bf60d4a4ac64b62ba396
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2019-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
23 #include "nel/gui/lua_helper.h"
24 #include "nel/gui/interface_group.h"
26 #include <algorithm>
28 // to get rid of you_must_not_use_assert___use_nl_assert___read_debug_h_file messages
29 #include <cassert>
30 #ifdef assert
31 #undef assert
32 #endif
34 #ifdef NL_OS_WINDOWS
35 #include <Windows.h>
36 #endif
38 // Warning: cannot use namespace std, when using luabind
39 #ifdef NL_OS_WINDOWS
40 # ifndef NL_EXTENDED_FOR_SCOPE
41 # undef for
42 # endif
43 #endif
45 #ifdef NL_DEBUG
46 # define assert(x) nlassert(x)
47 #else
48 # define assert(x)
49 #endif
51 // Always use unique_ptr with ValyriaTear/luabind on Ubuntu 20,
52 // since the setting is not stored in build_information.hpp
53 #ifndef LUABIND_USE_CXX11
54 #define LUABIND_USE_CXX11
55 #endif
57 #include <luabind/luabind.hpp>
58 // in luabind > 0.6, LUABIND_MAX_ARITY is set to 10
59 #if LUABIND_MAX_ARITY == 10
60 # include <luabind/operator.hpp>
61 // only luabind > 0.7 have version.hpp (file checked with build system)
62 # ifdef HAVE_LUABIND_VERSION
63 # include <luabind/version.hpp>
64 # endif
65 # ifndef LUABIND_VERSION
66 // luabind 0.7 doesn't define LUABIND_VERSION
67 # define LUABIND_VERSION 700
68 # endif
69 // luabind 0.6 doesn't define LUABIND_VERSION but LUABIND_MAX_ARITY is set to 5
70 #elif LUABIND_MAX_ARITY == 5
71 # define LUABIND_VERSION 600
72 #else
73 # pragma error("luabind version not recognized")
74 #endif
77 #include "nel/gui/lua_ihm.h"
78 #include "nel/gui/reflect.h"
79 #include "nel/misc/algo.h"
80 #include "nel/misc/file.h"
81 #include "nel/misc/i18n.h"
82 #include "nel/misc/time_nl.h"
83 #include "nel/misc/path.h"
84 #include "nel/misc/sstring.h"
85 #include "nel/misc/command.h"
86 #include "nel/gui/lua_object.h"
87 #include "nel/misc/polygon.h"
88 #include "nel/gui/lua_manager.h"
89 #include "nel/gui/widget_manager.h"
90 #include "nel/gui/action_handler.h"
91 #include "nel/gui/view_renderer.h"
92 #include "nel/gui/interface_expr.h"
93 #include "nel/misc/debug.h"
95 // ***************************************************************************
97 IMPORTANT NOTE: we do this heavy double registration in this file because we DON'T want
98 to include luabind.hpp in every file.
99 Compilation is VERY SLOW
101 // ***************************************************************************
103 using namespace NLMISC;
105 #ifdef DEBUG_NEW
106 #define new DEBUG_NEW
107 #endif
109 #ifdef RYZOM_LUA_UCSTRING
110 // declare ostream << operator for ucstring -> registration of ucstring iin luabind will build a 'tostring' function from it
111 std::ostream &operator<<(std::ostream &str, const ucstring &value)
113 return str << value.toString();
115 #endif
117 namespace NLGUI
120 struct CMiscFunctions
122 static std::string fileLookup(const std::string &fileName)
124 return NLMISC::CPath::lookup(fileName, false);
126 static void shellExecute(const std::string &operation, const std::string &fileName, const std::string &parameters)
128 #if !FINAL_VERSION
129 #ifdef NL_OS_WINDOWS
130 ShellExecuteW(NULL, nlUtf8ToWide(operation), nlUtf8ToWide(fileName), nlUtf8ToWide(parameters), NULL, SW_SHOWDEFAULT);
131 #endif
132 #endif
137 // ***************************************************************************
138 bool CLuaIHM::pop(CLuaState &ls, NLMISC::CRGBA &dest)
140 //H_AUTO(Lua_CLuaIHM_pop)
143 if (ls.isNil(-1)) return false;
144 #if LUABIND_VERSION > 600
145 luabind::object obj(luabind::from_stack(ls.getStatePointer(), -1));
146 ls.pop();
147 #else
148 luabind::object obj(ls.getStatePointer());
149 obj.set();
150 #endif
151 dest = luabind::object_cast<NLMISC::CRGBA>(obj);
153 catch(const luabind::cast_failed &)
155 return false;
157 return true;
160 // ***************************************************************************
161 bool CLuaIHM::pop(CLuaState &ls,NLMISC::CVector2f &dest)
163 //H_AUTO(Lua_CLuaIHM_pop)
166 if (ls.isNil(-1)) return false;
167 #if LUABIND_VERSION > 600
168 luabind::object obj(luabind::from_stack(ls.getStatePointer(), -1));
169 ls.pop();
170 #else
171 luabind::object obj(ls.getStatePointer());
172 obj.set();
173 #endif
174 dest = luabind::object_cast<NLMISC::CVector2f>(obj);
176 catch(const luabind::cast_failed &)
178 return false;
180 return true;
183 #ifdef RYZOM_LUA_UCSTRING
184 // ***************************************************************************
185 bool CLuaIHM::pop(CLuaState &ls, ucstring &dest)
187 //H_AUTO(Lua_CLuaIHM_pop)
190 if (ls.isNil(-1)) return false;
191 #if LUABIND_VERSION > 600
192 luabind::object obj(luabind::from_stack(ls.getStatePointer(), -1));
193 ls.pop();
194 #else
195 luabind::object obj(ls.getStatePointer());
196 obj.set();
197 #endif
198 dest = luabind::object_cast<ucstring>(obj);
200 catch(const luabind::cast_failed &)
202 return false;
204 return true;
207 // ***************************************************************************
208 bool CLuaIHM::isUCStringOnStack(CLuaState &ls, sint index)
210 //H_AUTO(Lua_CLuaIHM_isUCStringOnStack)
211 ls.pushValue(index);
212 ucstring dummy;
213 return pop(ls, dummy);
216 // ***************************************************************************
217 bool CLuaIHM::getUCStringOnStack(CLuaState &ls, sint index, ucstring &dest)
219 //H_AUTO(Lua_CLuaIHM_getUCStringOnStack)
220 ls.pushValue(index);
221 return pop(ls, dest);
225 // ***************************************************************************
226 void CLuaIHM::push(CLuaState &ls, const ucstring &value)
228 //H_AUTO(Lua_CLuaIHM_push)
229 #if defined(LUABIND_STACK_HPP_INCLUDED)
230 luabind::push(ls.getStatePointer(), value);
231 #elif (LUABIND_VERSION > 600)
232 luabind::detail::push(ls.getStatePointer(), value);
233 #else
234 luabind::object obj(ls.getStatePointer(), value);
235 obj.pushvalue();
236 #endif
238 #endif
240 // ***************************************************************************
241 // ***************************************************************************
242 // CInterface To LUA Registry
243 // ***************************************************************************
244 // ***************************************************************************
247 CLuaState * ELuaIHMException::getLuaState()
249 return CLuaManager::getInstance().getLuaState();
254 // ***************************************************************************
255 #define LUA_REGISTER_BASIC(_type_) \
256 luabind::detail::yes_t is_user_defined(luabind::detail::by_value<_type_>); \
257 _type_ convert_lua_to_cpp(lua_State* L, luabind::detail::by_value<_type_>, int index) \
259 return (_type_)lua_tointeger(L, index); \
261 int match_lua_to_cpp(lua_State* L, luabind::detail::by_value<_type_>, int index) \
263 return lua_isnumber(L, index) ? 0:-1; \
265 void convert_cpp_to_lua(lua_State* L, const _type_& v) \
267 lua_pushinteger(L, (lua_Integer)v); \
270 // Basic LUA types
271 namespace luabind
273 namespace converters
275 LUA_REGISTER_BASIC(sint8)
276 LUA_REGISTER_BASIC(uint8)
277 LUA_REGISTER_BASIC(sint16)
278 LUA_REGISTER_BASIC(uint16)
279 LUA_REGISTER_BASIC(sint32)
280 LUA_REGISTER_BASIC(uint32)
284 namespace NLGUI
286 static CLuaString lstr_Env("Env");
287 static CLuaString lstr_isNil("isNil");
289 // ***************************************************************************
290 int CLuaIHM::luaUIIndex(CLuaState &ls)
292 //H_AUTO(Lua_CLuaIHM_luaUIIndex)
293 nlassert(ls.getTop()==2);
294 // get the userdata and key
295 CReflectableLuaRef *pRefElm = (CReflectableLuaRef *) ls.toUserData(1);
297 const char *propName = ls.toString(2);
298 CReflectableRefPtrTarget *pRPT= (CReflectableRefPtrTarget*)(pRefElm->Ptr);
299 // ** try to get the Env Table (interface group only)
300 if(propName==lstr_isNil)
302 ls.push(pRPT==NULL);
303 return 1;
306 // Check the object is not NULL or freed
307 if(pRPT==NULL)
309 return 0;
312 // ** try to get the Env Table (interface group only)
313 if(propName==lstr_Env)
315 // Env can be bound to a CInterfaceGroup only
316 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(pRPT);
317 if(group==NULL)
319 ls.pushNil();
320 return 1;
322 else
324 group->pushLUAEnvTable();
325 return 1;
329 // ** try to get the property
330 const CReflectedProperty *prop = pRefElm->getProp(propName);
331 if (prop)
333 CLuaIHM::luaValueFromReflectedProperty(ls, *pRPT, *prop);
334 return 1;
337 // ** try to get a UI relative
338 CInterfaceElement *uiRelative= getUIRelative(dynamic_cast<CInterfaceElement *>(pRPT), propName);
339 if(uiRelative)
341 // push the UI onto the stack
342 pushUIOnStack(ls, uiRelative);
343 return 1;
347 // Fail to find any Attributes or elements
348 // Yoyo: don't write any message or warning because this may be a feature (if user want to test that something exit in the ui)
349 ls.pushNil();
350 return 1;
353 // ***************************************************************************
354 int CLuaIHM::luaUINewIndex(CLuaState &ls)
356 //H_AUTO(Lua_CLuaIHM_luaUINewIndex)
357 nlassert(ls.getTop()==3);
358 // get the userdata and key
359 CReflectableLuaRef *pRefElm = (CReflectableLuaRef *) ls.toUserData(1);
360 nlassert(pRefElm);
361 CReflectableRefPtrTarget *pRPT= (CReflectableRefPtrTarget*)(pRefElm->Ptr);
362 // Check the UI is not NULL or freed
363 if(pRPT == NULL)
365 return 0;
368 const char *propName = ls.toString(2);
369 // ** try to set the Env Table (interface group only)
370 if(propName == lstr_Env)
372 CInterfaceElement *pIE = dynamic_cast<CInterfaceElement *>(pRPT);
373 std::string name ;
374 if (pIE)
376 name = pIE->getId();
378 else
380 name = "<reflectable element>";
382 // Exception!!! not allowed
383 throw ELuaIHMException("You cannot change the Env Table of '%s'", name.c_str());
387 // ** try to set the property
388 const CReflectedProperty *prop = pRefElm->getProp(propName);
389 if (prop)
391 CLuaIHM::luaValueToReflectedProperty(ls, 3, *pRPT, *prop);
392 return 0;
395 CInterfaceElement *pIE = dynamic_cast<CInterfaceElement *>(pRPT);
396 // ** try to get another UI (child or parent)
397 CInterfaceElement *uiRelative= getUIRelative(pIE, propName);
398 if(uiRelative)
400 // Exception!!! not allowed
401 throw ELuaIHMException("You cannot write into the UI '%s' of '%s'", propName, pIE->getId().c_str());
404 // ** Prop Not Found
405 throw ELuaIHMException("Property '%s' not found in '%s' of type %s", propName, pIE ? pIE->getId().c_str() : "<reflectable element>", typeid(*pRPT).name());
407 // Fail to find any Attributes or elements
408 return 0;
411 // ***************************************************************************
412 int CLuaIHM::luaUIEq(CLuaState &ls)
414 //H_AUTO(Lua_CLuaIHM_luaUIEq)
415 nlassert(ls.getTop() == 2);
416 // read lhs & rhs
417 // get the userdata and key
418 CReflectableLuaRef *lhs = (CReflectableLuaRef *) ls.toUserData(1);
419 CReflectableLuaRef *rhs = (CReflectableLuaRef *) ls.toUserData(2);
420 nlassert(lhs);
421 nlassert(rhs);
422 ls.push(lhs->Ptr == rhs->Ptr);
423 return 1;
427 // ***************************************************************************
428 int CLuaIHM::luaUIDtor(CLuaState &ls)
430 //H_AUTO(Lua_CLuaIHM_luaUIDtor)
431 nlassert(ls.getTop()==1);
432 // get the userdata
433 CReflectableLuaRef *pRefElm = (CReflectableLuaRef *) ls.toUserData(1);
434 nlassert(pRefElm);
436 // call dtor
437 pRefElm->~CReflectableLuaRef();
439 return 0;
442 // ***************************************************************************
443 int CLuaIHM::luaUINext(CLuaState &ls)
445 //H_AUTO(Lua_CLuaIHM_luaUINext)
446 // Code below allow enumeration of properties of a reflectable object
447 // From lua standpoint, the object is seen as a table with (key, value) pairs
448 // If object is a CInterfaceGroup, iteration is also done on sons (groups, controls & view).
450 if (ls.getTop() != 2)
452 CLuaIHM::fails(ls, "__next metamethod require 2 arguments (table & key)");
454 CLuaIHM::check(ls, CLuaIHM::isReflectableOnStack(ls, 1), "__next : require ui element as first arg");
455 CReflectableRefPtrTarget *reflectedObject = CLuaIHM::getReflectableOnStack(ls, 1);
456 // To traverse all properties / field of the object, we must be able to determine the next key from a previous key
457 // (keys are ordered)
458 // We use the 'TValueType' enum to know which kind of property we are traversing, and an index in this group of properties
459 // The key which uniquely identify an element / property in the reflectable object
460 struct CKey
462 enum TValueType
464 VTGroup = 0, // children groups (If the object is a CInterfaceGroup)
465 VTView, // children views (If the object is a CInterfaceView)
466 VTCtrl, // children controls (If the object is a CInterfaceCtrl)
467 VTProp // List of exported proeprties (For all relfectable objects)
469 TValueType ValueType;
470 sint Index;
471 const CClassInfo *ClassInfo; // if ValueType is "VTProp" -> give the class for which property are currently enumerated
473 static int tostring(CLuaState &ls) // '__print' metamathod
475 CLuaIHM::checkArgCount(ls, "reflected object metatable:__print", 1);
476 CKey key;
477 key.pop(ls);
478 switch(key.ValueType)
480 case VTGroup: ls.push(toString("_Group %d", key.Index)); break;
481 case VTView: ls.push(toString("_View %d", key.Index)); break;
482 case VTCtrl: ls.push(toString("_Ctrl %d", key.Index)); break;
483 case VTProp: ls.push(key.ClassInfo->Properties[key.Index].Name); break;
485 return 1;
487 // push the key on the lua stack
488 void push(CLuaState &ls)
490 void *ud = ls.newUserData(sizeof(*this));
491 *(CKey *) ud = *this;
492 getMetaTable(ls).push();
493 ls.setMetaTable(-2);
495 // pop the key from the lua stack
496 void pop(CLuaState &ls)
498 CLuaStackChecker lsc(&ls, -1);
499 if (!ls.isUserData(-1))
501 CLuaIHM::fails(ls, "Can't pop object, not a user data");
503 // check that metatable is good (it is share between all keys)
504 ls.getMetaTable(-1);
505 getMetaTable(ls).push();
506 if (!ls.rawEqual(-1, -2))
508 CLuaIHM::fails(ls, "Bad metatable for reflectable object key");
510 ls.pop(2);
511 // retrieve key
512 *this = *(CKey *) ls.toUserData(-1);
513 ls.pop();
515 // get the metatable for a CKey
516 CLuaObject &getMetaTable(CLuaState &ls)
518 static CLuaObject metatable;
519 if (!metatable.isValid())
521 // first build
522 CLuaStackChecker lsc(&ls);
523 ls.newTable();
524 ls.push("__tostring");
525 ls.push(CKey::tostring);
526 ls.setTable(-3);
527 metatable.pop(ls);
529 return metatable;
532 // Pop the current key to continue enumeration
533 CKey key;
534 if (ls.isNil(2))
536 // no key -> start of table
537 key.ValueType = CKey::VTGroup;
538 key.Index = -1;
540 else
542 key.pop(ls);
545 CInterfaceGroup *group = dynamic_cast<CInterfaceGroup *>(reflectedObject);
546 bool enumerate = true;
547 while (enumerate)
549 switch(key.ValueType)
551 case CKey::VTGroup:
552 if (!group || (key.Index + 1) == (sint) group->getGroups().size())
554 key.Index = -1;
555 key.ValueType = CKey::VTView; // continue enumeration with views
557 else
559 ++ key.Index;
560 key.push(ls);
561 pushUIOnStack(ls, group->getGroups()[key.Index]);
562 return 2;
564 break;
565 case CKey::VTView:
566 if (!group || (key.Index + 1) == (sint) group->getViews().size())
568 key.Index = -1;
569 key.ValueType = CKey::VTCtrl; // continue enumeration with controls
571 else
573 ++ key.Index;
574 key.push(ls);
575 pushUIOnStack(ls, group->getViews()[key.Index]);
576 return 2;
578 break;
579 case CKey::VTCtrl:
580 if (!group || (key.Index + 1) == (sint) group->getControls().size())
582 key.Index = -1;
583 key.ValueType = CKey::VTProp; // continue enumeration with properties
584 key.ClassInfo = reflectedObject->getClassInfo();
586 else
588 ++ key.Index;
589 key.push(ls);
590 pushUIOnStack(ls, group->getControls()[key.Index]);
591 return 2;
593 break;
594 case CKey::VTProp:
595 if (!key.ClassInfo)
597 enumerate = false;
598 break;
600 if ((sint) key.ClassInfo->Properties.size() == (key.Index + 1))
602 key.ClassInfo = key.ClassInfo->ParentClass; // continue enumeration in parent class
603 key.Index = -1;
605 else
607 ++ key.Index;
608 key.push(ls);
609 CLuaIHM::luaValueFromReflectedProperty(ls, *reflectedObject, key.ClassInfo->Properties[key.Index]);
610 return 2;
612 break;
613 default:
614 nlassert(0);
615 break;
618 ls.pushNil();
619 return 0;
622 // ***************************************************************************
623 void CLuaIHM::pushUIOnStack(CLuaState &ls, CInterfaceElement *pIE)
625 //H_AUTO(Lua_CLuaIHM_pushUIOnStack)
626 CLuaIHM::pushReflectableOnStack(ls, pIE);
629 // ***************************************************************************
630 bool CLuaIHM::isUIOnStack(CLuaState &ls, sint index)
632 //H_AUTO(Lua_CLuaIHM_isUIOnStack)
633 return getUIOnStack(ls, index) != NULL;
636 // ***************************************************************************
637 CInterfaceElement *CLuaIHM::getUIOnStack(CLuaState &ls, sint index)
639 //H_AUTO(Lua_CLuaIHM_getUIOnStack)
640 return dynamic_cast<CInterfaceElement *>(CLuaIHM::getReflectableOnStack(ls, index));
643 // ***************************************************************************
644 void CLuaIHM::checkArgTypeUIElement(CLuaState &ls, const char *funcName, uint index)
646 //H_AUTO(Lua_CLuaIHM_checkArgTypeUIElement)
647 nlassert(index > 0);
648 if (ls.getTop() < (int) index)
650 CLuaIHM::fails(ls, "%s : argument %d of expected type ui element was not defined", funcName, index);
652 if (!isUIOnStack(ls, index))
654 CLuaIHM::fails(ls, "%s : argument %d of expected type ui element has bad type : %s", funcName, index, ls.getTypename(ls.type(index)), ls.type(index));
659 // ***************************************************************************
660 CInterfaceElement *CLuaIHM::getUIRelative(CInterfaceElement *pIE, const std::string &propName)
662 //H_AUTO(Lua_CLuaIHM_getUIRelative)
663 if (pIE == NULL) return NULL;
664 // If the prop is "parent", then return the parent of the ui
665 if(propName=="parent")
667 return pIE->getParent();
669 // else try to get a child (if group/exist)
670 else
672 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(pIE);
673 if(group)
675 return group->getElement(group->getId()+":"+propName);
679 return NULL;
683 // ***************************************************************************
684 void CLuaIHM::registerBasics(CLuaState &ls)
686 //H_AUTO(Lua_CLuaIHM_registerBasics)
687 using namespace luabind;
688 lua_State *L= ls.getStatePointer();
690 // RGBA
691 module(L)
693 class_<NLMISC::CRGBA>("CRGBA")
694 .def(constructor<>())
695 .def(constructor<const NLMISC::CRGBA &>())
696 .def(constructor<uint8, uint8, uint8>())
697 .def(constructor<uint8, uint8, uint8, uint8>())
698 .def_readwrite("R", &NLMISC::CRGBA::R)
699 .def_readwrite("G", &NLMISC::CRGBA::G)
700 .def_readwrite("B", &NLMISC::CRGBA::B)
701 .def_readwrite("A", &NLMISC::CRGBA::A)
704 #ifdef RYZOM_LUA_UCSTRING
705 // ucstring
706 module(L)
708 class_<ucstring>("ucstring")
709 .def(constructor<>())
710 .def(constructor<const ucstring &>())
711 .def(constructor<const std::string &>())
712 .def(const_self + other<const std::string>())
713 .def(other<const std::string>() + const_self)
714 // NB nico : luabind crash not solved here -> use concatUCString as a replacement
715 // .def(const_self + other<const ucstring &>())
716 .def(const_self < other<const ucstring&>())
717 .def(const_self == other<const ucstring&>())
718 .def("toUtf8", &ucstring::toUtf8)
719 .def("fromUtf8", &ucstring::fromUtf8)
720 .def("substr", &ucstring::luabind_substr)
721 .def(luabind::tostring(const_self)) // __string metamethod
722 .def("toString", (std::string(ucstring::*)()const)&ucstring::toString)
723 //.def(self + other<ucstring>())
725 #endif
727 // CVector2f
728 module(L)
730 class_<NLMISC::CVector2f>("CVector2f")
731 .def(constructor<float ,float>())
732 .def_readwrite("x", &NLMISC::CVector2f::x)
733 .def_readwrite("y", &NLMISC::CVector2f::y)
739 // ***************************************************************************
740 int CLuaIHM::luaMethodCall(lua_State *ls)
742 //H_AUTO(Lua_CLuaIHM_luaMethodCall)
743 nlassert(ls);
744 const CReflectedProperty *prop = (const CReflectedProperty *) lua_touserdata(ls, lua_upvalueindex(1));
745 CLuaState *state = (CLuaState *) lua_touserdata(ls, lua_upvalueindex(2));
746 nlassert(prop);
747 nlassert(prop->Type == CReflectedProperty::LuaMethod);
748 nlassert(state);
749 if (state->empty())
751 state->push(NLMISC::toString("Error while calling lua method %s:%s : no 'self' reference provided, did you you function call '.' instead of method call ':' ?",
752 prop->ParentClass->ClassName.c_str(), prop->Name.c_str())
754 lua_error(ls);
756 // because this is a method, first parameter is the 'this'
757 CReflectableRefPtrTarget *pRPT = getReflectableOnStack(*state, 1);
758 if (!pRPT)
760 state->push(NLMISC::toString("Error while calling lua method %s:%s : 'self' pointer is nil or of bad type, can't make the call.",
761 prop->ParentClass->ClassName.c_str(), prop->Name.c_str())
763 lua_error(ls);
766 state->remove(1); // remove 'self' reference from parameters stack
768 sint numResults = 0;
769 if (pRPT)
771 sint initialStackSize = state->getTop();
774 // call the actual method
775 numResults = (pRPT->*(prop->GetMethod.GetLuaMethod))(*state);
777 catch (const std::exception & e)
779 // restore stack to its initial size
780 state->setTop(initialStackSize);
781 lua_pushstring(ls, e.what());
782 // TODO : see if this is safe to call lua error there" ... (it does a long jump)
783 lua_error(ls);
786 return numResults;
791 // ***************************************************************************
792 int CLuaIHM::setOnDraw(CLuaState &ls)
794 //H_AUTO(Lua_CLuaIHM_setOnDraw)
795 CLuaStackChecker lsc(&ls, 0);
797 // params: CInterfaceGroup*, "script".
798 // return: none
799 CLuaIHM::checkArgCount(ls, "setOnDraw", 2);
800 CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "setOnDraw() requires a UI object in param 1");
801 CLuaIHM::check(ls, ls.isString(2), "setOnDraw() requires a string in param 2");
803 // retrieve args
804 CInterfaceElement *pIE= CLuaIHM::getUIOnStack(ls, 1);
805 std::string script;
806 ls.toString(2, script);
807 nlassert(pIE);
809 // must be a group
810 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(pIE);
811 if(!group)
812 throw ELuaIHMException("setOnDraw(): '%s' is not a group", pIE->getId().c_str());
813 // Set the script to be executed at each draw
814 group->setLuaScriptOnDraw(script);
816 return 0;
819 // ***************************************************************************
820 int CLuaIHM::getOnDraw(CLuaState &ls)
822 //H_AUTO(Lua_CLuaIHM_getOnDraw
823 CLuaStackChecker lsc(&ls, 1);
825 // params: CInterfaceElement*.
826 // return: "script" (nil if empty)
827 CLuaIHM::checkArgCount(ls, "getOnDraw", 1);
828 CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "getOnDraw() requires a UI object in param 1");
830 // retrieve arguments
831 CInterfaceElement *pIE = CLuaIHM::getUIOnStack(ls, 1);
832 if (pIE)
834 // must be a group
835 CInterfaceGroup *group = dynamic_cast<CInterfaceGroup*>(pIE);
836 if (group)
838 if (!group->getLuaScriptOnDraw().empty()) {
839 ls.push(group->getLuaScriptOnDraw());
840 return 1;
844 ls.pushNil();
845 return 1;
848 // ***************************************************************************
849 int CLuaIHM::addOnDbChange(CLuaState &ls)
851 //H_AUTO(Lua_CLuaIHM_addOnDbChange)
852 CLuaStackChecker lsc(&ls, 0);
854 // params: CInterfaceGroup*, "dblist", "script".
855 // return: none
856 CLuaIHM::checkArgCount(ls, "addOnDbChange", 3);
857 CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "addOnDbChange() requires a UI object in param 1");
858 CLuaIHM::check(ls, ls.isString(2), "addOnDbChange() requires a string in param 2");
859 CLuaIHM::check(ls, ls.isString(3), "addOnDbChange() requires a string in param 3");
861 // retrieve args
862 CInterfaceElement *pIE= CLuaIHM::getUIOnStack(ls, 1);
863 std::string dbList, script;
864 ls.toString(2, dbList);
865 ls.toString(3, script);
866 nlassert(pIE);
868 // must be a group
869 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(pIE);
870 if(!group)
871 throw ELuaIHMException("addOnDbChange(): '%s' is not a group", pIE->getId().c_str());
872 // Set the script to be executed when the given DB change
873 group->addLuaScriptOnDBChange(dbList, script);
875 return 0;
879 // ***************************************************************************
880 int CLuaIHM::removeOnDbChange(CLuaState &ls)
882 //H_AUTO(Lua_CLuaIHM_removeOnDbChange)
883 CLuaStackChecker lsc(&ls, 0);
885 // params: CInterfaceGroup*, "dbList"
886 // return: none
887 CLuaIHM::checkArgCount(ls, "removeOnDbChange", 2);
888 CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "removeOnDbChange() requires a UI object in param 1");
889 CLuaIHM::check(ls, ls.isString(2), "removeOnDbChange() requires a string in param 2");
891 // retrieve args
892 CInterfaceElement *pIE= CLuaIHM::getUIOnStack(ls, 1);
893 std::string dbList;
894 ls.toString(2, dbList);
895 nlassert(pIE);
897 // must be a group
898 CInterfaceGroup *group= dynamic_cast<CInterfaceGroup*>(pIE);
899 if(!group)
900 throw ELuaIHMException("removeOnDbChange(): '%s' is not a group", pIE->getId().c_str());
901 // Remove the script to be executed when the given DB change
902 group->removeLuaScriptOnDBChange(dbList);
904 return 0;
909 // ***************************************************************************
910 int CLuaIHM::setCaptureKeyboard(CLuaState &ls)
912 //H_AUTO(Lua_CLuaIHM_setCaptureKeyboard)
913 const char *funcName = "setCaptureKeyboard";
914 CLuaIHM::checkArgCount(ls, funcName, 1);
915 CLuaIHM::checkArgTypeUIElement(ls, funcName, 1);
916 CCtrlBase *ctrl = dynamic_cast<CCtrlBase *>( CLuaIHM::getUIOnStack(ls, 1));
917 if (!ctrl)
919 CLuaIHM::fails(ls, "%s waits a ui control as arg 1", funcName);
921 CWidgetManager::getInstance()->setCaptureKeyboard(ctrl);
922 return 0;
925 // ***************************************************************************
926 int CLuaIHM::resetCaptureKeyboard(CLuaState &ls)
928 //H_AUTO(Lua_CLuaIHM_resetCaptureKeyboard)
929 const char *funcName = "resetCaptureKeyboard";
930 CLuaIHM::checkArgCount(ls, funcName, 0);
931 CWidgetManager::getInstance()->resetCaptureKeyboard();
932 return 0;
935 // ***************************************************************************
936 int CLuaIHM::getUIId(CLuaState &ls)
938 //H_AUTO(Lua_CLuaIHM_getUIId)
939 CLuaStackChecker lsc(&ls, 1);
941 // params: CInterfaceElement*
942 // return: "ui:interface:...". (empty if error)
943 CLuaIHM::checkArgCount(ls, "getUIId", 1);
944 CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "getUIId() requires a UI object in param 1");
946 // retrieve args
947 CInterfaceElement *pIE= CLuaIHM::getUIOnStack(ls, 1);
949 // convert to id
950 if(pIE)
951 ls.push(pIE->getId());
952 else
953 ls.push("");
955 return 1;
960 // ***************************************************************************
961 int CLuaIHM::runAH(CLuaState &ls)
963 //H_AUTO(Lua_CLuaIHM_runAH)
964 CLuaStackChecker lsc(&ls, 0);
966 // params: CInterfaceElement *, "ah", "params".
967 // return: none
968 CLuaIHM::checkArgCount(ls, "runAH", 3);
969 CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1) || ls.isNil(1), "runAH() requires a UI object in param 1 (or Nil)");
970 CLuaIHM::check(ls, ls.isString(2), "runAH() requires a string in param 2");
971 CLuaIHM::check(ls, ls.isString(3), "runAH() requires a string in param 3");
973 // retrieve args
974 CInterfaceElement *pIE= CLuaIHM::getUIOnStack(ls, 1);
975 std::string ah, params;
976 ls.toString(2, ah);
977 ls.toString(3, params);
979 // run AH
980 // The element must be ctrl (or NULL)
981 CCtrlBase *ctrl= NULL;
982 if(pIE)
984 ctrl= dynamic_cast<CCtrlBase*>(pIE);
985 if(!ctrl)
986 throw ELuaIHMException("runAH(): '%s' is not a ctrl", pIE->getId().c_str());
988 CAHManager::getInstance()->runActionHandler(ah, ctrl, params);
990 return 0;
993 // ***************************************************************************
994 int CLuaIHM::getWindowSize(CLuaState &ls)
996 //H_AUTO(Lua_CLuaIHM_getWindowSize)
997 CLuaIHM::checkArgCount(ls, "getWindowSize", 0);
998 uint32 w, h;
999 CViewRenderer::getInstance()->getScreenSize(w, h);
1000 ls.push(w);
1001 ls.push(h);
1002 return 2;
1005 // ***************************************************************************
1006 int CLuaIHM::setTopWindow(CLuaState &ls)
1008 //H_AUTO(Lua_CLuaIHM_setTopWindow)
1009 const char *funcName = "setTopWindow";
1010 CLuaIHM::checkArgCount(ls, funcName, 1);
1011 CInterfaceGroup *wnd = dynamic_cast<CInterfaceGroup *>( CLuaIHM::getUIOnStack(ls, 1));
1012 if (!wnd)
1014 CLuaIHM::fails(ls, "%s : interface group expected as arg 1", funcName);
1016 CWidgetManager::getInstance()->setTopWindow(wnd);
1017 return 0;
1020 int CLuaIHM::getTextureSize(CLuaState &ls)
1022 //H_AUTO(Lua_CLuaIHM_getTextureSize)
1023 const char *funcName = "getTextureSize";
1024 CLuaIHM::checkArgCount(ls, funcName, 1);
1025 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
1026 std::string textureName = ls.toString(1);
1028 CBitmap bitmap;
1029 CIFile fs(CPath::lookup(textureName).c_str());
1030 bitmap.load(fs);
1032 ls.push(bitmap.getWidth());
1033 ls.push(bitmap.getHeight());
1035 return 2;
1040 // ***************************************************************************
1041 int CLuaIHM::disableModalWindow(CLuaState &ls)
1043 //H_AUTO(Lua_CLuaIHM_disableModalWindow)
1044 CLuaIHM::checkArgCount(ls, "disableModalWindow", 0);
1045 CWidgetManager::getInstance()->disableModalWindow();
1046 return 0;
1049 // ***************************************************************************
1050 int CLuaIHM::deleteUI(CLuaState &ls)
1052 //H_AUTO(Lua_CLuaIHM_deleteUI)
1053 CLuaStackChecker lsc(&ls, 0);
1055 // params: CInterfaceElement *
1056 // return: none
1057 CLuaIHM::checkArgCount(ls, "deleteUI", 1);
1058 CLuaIHM::check(ls, CLuaIHM::isUIOnStack(ls, 1), "deleteUI() requires a UI object in param 1");
1060 // retrieve args
1061 CInterfaceElement *pIE= CLuaIHM::getUIOnStack(ls, 1);
1062 if(!pIE)
1063 return 0;
1065 // has a parent?
1066 CInterfaceGroup *parent= pIE->getParent();
1067 if(parent)
1069 // correctly remove from parent
1070 parent->delElement(pIE);
1072 else
1074 // just delete
1075 delete pIE;
1078 return 0;
1081 // ***************************************************************************
1082 int CLuaIHM::deleteReflectable(CLuaState &ls)
1084 //H_AUTO(Lua_CLuaIHM_deleteReflectable)
1085 CLuaStackChecker lsc(&ls, 0);
1087 // params: CInterfaceElement *
1088 // return: none
1089 CLuaIHM::checkArgCount(ls, "deleteReflectable", 1);
1090 CLuaIHM::check(ls, CLuaIHM::isReflectableOnStack(ls, 1), "deleteReflectable() requires a reflectable C++ object in param 1");
1092 // retrieve args
1093 CReflectableRefPtrTarget *pRPT= CLuaIHM::getReflectableOnStack(ls, 1);
1094 if(!pRPT)
1095 return 0;
1098 CInterfaceElement *pIE = dynamic_cast<CInterfaceElement *>(pRPT);
1100 if (pIE)
1102 // has a parent?
1103 CInterfaceGroup *parent= pIE->getParent();
1104 if(parent)
1106 // correctly remove from parent
1107 parent->delElement(pIE);
1111 // just delete
1112 delete pIE;
1114 return 0;
1118 int CLuaIHM::getCurrentWindowUnder(CLuaState &ls)
1120 //H_AUTO(Lua_CLuaIHM_getCurrentWindowUnder)
1121 CLuaStackChecker lsc(&ls, 1);
1122 CInterfaceElement *pIE= CWidgetManager::getInstance()->getCurrentWindowUnder();
1123 if(!pIE)
1125 ls.pushNil();
1126 nlerror("getCurrentWindowUnder(): No UICaller found. return Nil");
1128 else
1130 CLuaIHM::pushUIOnStack(ls, pIE);
1132 return 1;
1135 // ***************************************************************************
1136 bool CLuaIHM::fileExists(const std::string &fileName)
1138 //H_AUTO(Lua_CLuaIHM_fileExists)
1139 return CPath::exists(fileName);
1142 // ***************************************************************************
1143 int CLuaIHM::runExprAndPushResult(CLuaState &ls, const std::string &expr)
1145 //H_AUTO(Lua_CLuaIHM_runExprAndPushResult)
1146 // Execute expression
1147 CInterfaceExprValue value;
1148 if (CInterfaceExpr::eval(expr, value, NULL))
1150 switch(value.getType())
1152 case CInterfaceExprValue::Boolean:
1153 ls.push(value.getBool());
1154 break;
1155 case CInterfaceExprValue::Integer:
1156 ls.push(value.getInteger());
1157 break;
1158 case CInterfaceExprValue::Double:
1159 ls.push(value.getDouble());
1160 break;
1161 case CInterfaceExprValue::String:
1162 ls.push(value.getString());
1163 break;
1164 case CInterfaceExprValue::RGBA:
1166 CRGBA color = value.getRGBA();
1167 #if defined(LUABIND_STACK_HPP_INCLUDED)
1168 luabind::push(ls.getStatePointer(), color);
1169 #elif (LUABIND_VERSION > 600)
1170 luabind::detail::push(ls.getStatePointer(), color);
1171 #else
1172 luabind::object obj(ls.getStatePointer(), color);
1173 obj.pushvalue();
1174 #endif
1175 break;
1177 break;
1178 case CInterfaceExprValue::UserType: // Yoyo: don't care UserType...
1179 default:
1180 ls.pushNil();
1181 break;
1184 else
1185 ls.pushNil();
1187 return 1;
1190 // ***************************************************************************
1191 int CLuaIHM::runExpr(CLuaState &ls)
1193 //H_AUTO(Lua_CLuaIHM_runExpr)
1194 CLuaStackChecker lsc(&ls, 1);
1196 // params: "expr".
1197 // return: any of: nil, bool, string, number, RGBA, UCString
1198 CLuaIHM::checkArgCount(ls, "runExpr", 1);
1199 CLuaIHM::check(ls, ls.isString(1), "runExpr() requires a string in param 1");
1201 // retrieve args
1202 std::string expr;
1203 ls.toString(1, expr);
1205 // run expression and push result
1206 return runExprAndPushResult(ls, expr);
1209 // ***************************************************************************
1210 int CLuaIHM::runFct(CLuaState &ls)
1212 //H_AUTO(Lua_CLuaIHM_runFct)
1213 CLuaStackChecker lsc(&ls, 1);
1215 // params: "expr", param1, param2...
1216 // return: any of: nil, bool, string, number, RGBA, UCString
1217 CLuaIHM::checkArgMin(ls, "runFct", 1);
1218 CLuaIHM::check(ls, ls.isString(1), "runExpr() requires a string in param 1");
1220 // retrieve fct
1221 std::string expr;
1222 ls.toString(1, expr);
1223 expr+= "(";
1225 // retrieve params
1226 uint top= ls.getTop();
1227 for(uint i=2;i<=top;i++)
1229 if(i>2)
1230 expr+= ", ";
1232 // If it is a number
1233 if(ls.type(i)==LUA_TNUMBER)
1235 std::string paramValue;
1236 ls.toString(i, paramValue); // nb: transformed to a string in the stack
1237 expr+= paramValue;
1239 // else suppose a string
1240 else
1242 // must enclose with "'"
1243 std::string paramValue;
1244 ls.toString(i, paramValue);
1245 expr+= std::string("'") + paramValue + std::string("'") ;
1249 // end fct call
1250 expr+= ")";
1253 // run expression and push result
1254 return runExprAndPushResult(ls, expr);
1257 // ***************************************************************************
1258 int CLuaIHM::runCommand(CLuaState &ls)
1260 //H_AUTO(Lua_CLuaIHM_runCommand)
1261 CLuaStackChecker lsc(&ls, 1);
1262 if (ls.empty())
1264 nlwarning("'runCommand' : Command name expected");
1265 ls.push(false);
1266 return 1;
1268 const char *commandName = ls.toString(1);
1269 if (!commandName)
1271 nlwarning("'runCommand' : Bad command name");
1272 ls.push(false);
1273 return 1;
1275 if (!NLMISC::ICommand::LocalCommands || !NLMISC::ICommand::LocalCommands->count(ls.toString(1)))
1277 nlwarning("'runCommand' : Command %s not found", ls.toString(1));
1278 ls.push(false);
1279 return 1;
1281 std::string rawCommandString = ls.toString(1);
1282 NLMISC::ICommand *command = (*NLMISC::ICommand::LocalCommands)[ls.toString(1)];
1283 nlassert(command);
1284 std::vector<std::string> args(ls.getTop() - 1);
1285 for(uint k = 2; k <= (uint) ls.getTop(); ++k)
1287 if (ls.toString(k))
1289 args[k - 2] = ls.toString(k);
1290 rawCommandString += " " + std::string(ls.toString(k));
1294 ls.push(command->execute(rawCommandString, args, NLMISC::ErrorLog(), false, true));
1295 return 1;
1298 #ifdef RYZOM_LUA_UCSTRING
1299 // ***************************************************************************
1300 int CLuaIHM::isUCString(CLuaState &ls)
1302 //H_AUTO(Lua_CLuaIHM_isUCString)
1303 const char *funcName = "isUCString";
1304 CLuaIHM::checkArgCount(ls, funcName, 1);
1305 ls.push(CLuaIHM::isUCStringOnStack(ls, 1));
1306 return 1;
1309 // ***************************************************************************
1310 int CLuaIHM::concatUCString(CLuaState &ls)
1312 //H_AUTO(Lua_CLuaIHM_concatUCString)
1313 const char *funcName = "concatUCString";
1314 ucstring result;
1315 for (uint k = 1; k <= (uint) ls.getTop(); ++k)
1317 //nlwarning("arg %d = %s", k, ls.getTypename(ls.type(k)));
1318 ucstring part;
1319 if (ls.isString(k))
1321 part.fromUtf8(ls.toString(k));
1323 else
1325 CLuaIHM::checkArgTypeUCString(ls, funcName, k);
1326 nlverify(CLuaIHM::getUCStringOnStack(ls, k, part));
1328 result += part;
1330 CLuaIHM::push(ls, result);
1331 return 1;
1333 #endif
1335 // ***************************************************************************
1336 int CLuaIHM::concatString(CLuaState &ls)
1338 //H_AUTO(Lua_CLuaIHM_concatUCString)
1339 const char *funcName = "concatString";
1340 std::string result;
1341 uint stackSize = ls.getTop();
1342 for (uint k = 1; k <= stackSize; ++k)
1344 CLuaIHM::checkArgType(ls, funcName, k, LUA_TSTRING);
1345 result += ls.toString(k);
1347 ls.push(result);
1348 return 1;
1351 // ***************************************************************************
1352 int CLuaIHM::tableToString(CLuaState &ls)
1354 const char *funcName = "tableToString";
1355 CLuaIHM::checkArgCount(ls, funcName, 1);
1356 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TTABLE);
1357 uint length = 0;
1358 // compute size
1359 ls.pushNil();
1360 while (ls.next(-2))
1362 ls.toString(-1);
1363 length += (uint)ls.strlen(-1);
1364 ls.pop(2);
1366 std::string result;
1367 result.resize(length);
1368 char *dest = &result[0];
1369 // concatenate
1370 ls.pushNil();
1371 while (ls.next(-2))
1373 uint length = (uint)ls.strlen(-1);
1374 if (length)
1376 memcpy(dest, ls.toString(-1), length);
1378 dest += length;
1379 ls.pop(2);
1381 ls.push(result);
1382 return 1;
1386 int CLuaIHM::getPathContent(CLuaState &ls)
1388 //H_AUTO(Lua_CLuaIHM_getPathContent)
1389 const char *funcName = "getPathContent";
1390 CLuaIHM::checkArgCount(ls, funcName, 1);
1391 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
1392 std::vector<std::string> files;
1393 NLMISC::CPath::getPathContent(ls.toString(1), false, false, true, files);
1394 ls.newTable();
1395 for(uint k = 0; k < files.size(); ++k)
1397 ls.push(k);
1398 ls.push(files[k]);
1399 ls.setTable(-3);
1401 return 1;
1407 // ***************************************************************************
1408 void CLuaIHM::luaValueFromReflectedProperty(CLuaState &ls, CReflectable &reflectedObject, const CReflectedProperty &property)
1410 //H_AUTO(Lua_CLuaIHM_luaValueFromReflectedProperty)
1411 switch(property.Type)
1413 case CReflectedProperty::Boolean:
1414 ls.push( (reflectedObject.*(property.GetMethod.GetBool))() );
1415 break;
1416 case CReflectedProperty::SInt32:
1417 ls.push( (reflectedObject.*(property.GetMethod.GetSInt32))() );
1418 break;
1419 case CReflectedProperty::Float:
1420 ls.push( (reflectedObject.*(property.GetMethod.GetFloat))() );
1421 break;
1422 case CReflectedProperty::String:
1423 ls.push( (reflectedObject.*(property.GetMethod.GetString))() );
1424 break;
1425 #ifdef RYZOM_LUA_UCSTRING
1426 case CReflectedProperty::UCString:
1428 ucstring str = (reflectedObject.*(property.GetMethod.GetUCString))();
1429 #if defined(LUABIND_STACK_HPP_INCLUDED)
1430 luabind::push(ls.getStatePointer(), str);
1431 #elif (LUABIND_VERSION > 600)
1432 luabind::detail::push(ls.getStatePointer(), str);
1433 #else
1434 luabind::object obj(ls.getStatePointer(), str);
1435 obj.pushvalue();
1436 #endif
1438 break;
1439 case CReflectedProperty::UCStringRef:
1441 ucstring str = (reflectedObject.*(property.GetMethod.GetUCStringRef))();
1442 #if defined(LUABIND_STACK_HPP_INCLUDED)
1443 luabind::push(ls.getStatePointer(), str);
1444 #elif (LUABIND_VERSION > 600)
1445 luabind::detail::push(ls.getStatePointer(), str);
1446 #else
1447 luabind::object obj(ls.getStatePointer(), str);
1448 obj.pushvalue();
1449 #endif
1451 break;
1452 #endif
1453 case CReflectedProperty::StringRef:
1454 ls.push( (reflectedObject.*(property.GetMethod.GetStringRef))() );
1455 break;
1456 case CReflectedProperty::RGBA:
1458 CRGBA color = (reflectedObject.*(property.GetMethod.GetRGBA))();
1459 #if defined(LUABIND_STACK_HPP_INCLUDED)
1460 luabind::push(ls.getStatePointer(), color);
1461 #elif (LUABIND_VERSION > 600)
1462 luabind::detail::push(ls.getStatePointer(), color);
1463 #else
1464 luabind::object obj(ls.getStatePointer(), color);
1465 obj.pushvalue();
1466 #endif
1468 break;
1469 case CReflectedProperty::LuaMethod:
1471 // must create a closure that will forward the call to the real method
1472 if (!property.LuaMethodRef.isValid())
1474 ls.pushLightUserData((void *) &property);
1475 ls.pushLightUserData((void *) &ls);
1476 ls.pushCClosure(luaMethodCall, 2);
1477 property.LuaMethodRef.pop(ls);
1479 nlassert(property.LuaMethodRef.getLuaState() == &ls); // only one single lua state supported for now
1480 property.LuaMethodRef.push();
1482 break;
1483 default:
1484 nlstop;
1485 break;
1489 // ***************************************************************************
1490 void CLuaIHM::luaValueToReflectedProperty(CLuaState &ls, int stackIndex, CReflectable &target, const CReflectedProperty &property)
1492 //H_AUTO(Lua_property_throw)
1493 if(ls.isNil(stackIndex))
1494 throw ELuaIHMException("Trying to set nil to UI property '%s'", property.Name.c_str());
1495 switch(property.Type)
1497 case CReflectedProperty::Boolean:
1499 bool val= ls.toBoolean(stackIndex);
1500 (target.*(property.SetMethod.SetBool))(val);
1501 return;
1503 case CReflectedProperty::SInt32:
1505 sint32 val= (sint32)ls.toInteger(stackIndex);
1506 (target.*(property.SetMethod.SetSInt32))(val);
1507 return;
1509 case CReflectedProperty::UInt32:
1511 uint32 val= (uint32)ls.toInteger(stackIndex);
1512 (target.*(property.SetMethod.SetUInt32))(val);
1513 return;
1515 case CReflectedProperty::Float:
1517 float val= (float)ls.toNumber(stackIndex);
1518 (target.*(property.SetMethod.SetFloat))(val);
1519 return;
1521 case CReflectedProperty::String:
1522 case CReflectedProperty::StringRef:
1524 std::string val;
1525 ls.toString(stackIndex, val);
1526 (target.*(property.SetMethod.SetString))(val);
1527 return;
1529 #ifdef RYZOM_LUA_UCSTRING
1530 case CReflectedProperty::UCString:
1531 case CReflectedProperty::UCStringRef:
1533 ucstring val;
1534 // Additionaly return of CInterfaceExpr may be std::string... test std string too
1535 if(ls.isString() || ls.isNumber() || ls.isInteger())
1537 std::string str;
1538 ls.toString(stackIndex, str);
1539 val= str;
1541 #ifdef RYZOM_LUA_UCSTRING
1542 else
1544 // else this should be a ucstring
1545 if (!pop(ls, val))
1547 throw ELuaIHMException("You must set a string, number or ucstring to UI property '%s'", property.Name.c_str());
1550 #endif
1551 (target.*(property.SetMethod.SetUCString))(val);
1552 return;
1554 #endif
1555 case CReflectedProperty::RGBA:
1557 CRGBA color;
1558 if (pop(ls, color))
1560 (target.*(property.SetMethod.SetRGBA))(color);
1562 else
1564 throw ELuaIHMException("You must set a CRGBA to UI property '%s'", property.Name.c_str());
1566 return;
1568 default:
1569 nlstop;
1574 // ***************************************************************************
1575 void CLuaIHM::createLuaEnumTable(CLuaState &ls, const std::string &str)
1577 //H_AUTO(Lua_CLuaIHM_createLuaEnumTable)
1578 std::string path = "", script, p;
1579 CSString s = str;
1580 // Create table recursively (ex: 'game.TPVPClan' will check/create the table 'game' and 'game.TPVPClan')
1581 p = s.splitTo('.', true);
1582 while (!p.empty())
1584 if (path.empty() )
1585 path = p;
1586 else
1587 path += "." + p;
1588 script = "if (" + path + " == nil) then " + path + " = {}; end";
1589 ls.executeScript(script);
1590 p = s.splitTo('.', true);
1594 #define LUABIND_ENUM(__enum__, __name__, __num__, __toStringFunc__) \
1595 createLuaEnumTable(ls, __name__); \
1596 for (uint e=0 ; e<__num__ ; e++) \
1598 std::string str = __toStringFunc__((__enum__)e); \
1599 std::string temp = __name__ + toString(".") + __toStringFunc__((__enum__)e) + " = " + toString("%u;", e); \
1600 ls.executeScript(temp); \
1603 // ***************************************************************************
1604 #define LUABIND_FUNC(__func__) luabind::def(#__func__, &__func__)
1606 void CLuaIHM::registerIHM(CLuaState &ls)
1608 //H_AUTO(Lua_CLuaIHM_registerIHM)
1609 CLuaStackChecker lsc(&ls);
1611 // *** Register a Table for ui env.
1612 ls.push(IHM_LUA_ENVTABLE); // "__ui_envtable"
1613 ls.newTable(); // "__ui_envtable" {}
1614 ls.setTable(LUA_REGISTRYINDEX);
1617 // *** Register the MetaTable for UI userdata
1618 ls.push(IHM_LUA_METATABLE); // "__ui_metatable"
1619 ls.newTable(); // "__ui_metatable" {}
1620 // set the '__index' method
1621 ls.push("__index");
1622 ls.push(luaUIIndex);
1623 nlassert(ls.isCFunction());
1624 ls.setTable(-3); // "__ui_metatable" {"__index"= CFunc_luaUIIndex}
1625 // set the '__newindex' method
1626 ls.push("__newindex");
1627 ls.push(luaUINewIndex);
1628 nlassert(ls.isCFunction());
1629 ls.setTable(-3);
1630 // set the '__newindex' method
1631 ls.push("__gc");
1632 ls.push(luaUIDtor);
1633 nlassert(ls.isCFunction());
1634 ls.setTable(-3);
1635 // set the '__eq' method
1636 ls.push("__eq");
1637 ls.push(luaUIEq);
1638 nlassert(ls.isCFunction());
1639 ls.setTable(-3);
1640 // set the custom '__next' method
1641 ls.push("__next");
1642 ls.push(luaUINext);
1643 nlassert(ls.isCFunction());
1644 ls.setTable(-3);
1645 // set registry
1646 ls.setTable(LUA_REGISTRYINDEX);
1649 // *** Register Functions
1650 ls.registerFunc("setOnDraw", setOnDraw);
1651 ls.registerFunc("getOnDraw", getOnDraw);
1652 ls.registerFunc("setCaptureKeyboard", setCaptureKeyboard);
1653 ls.registerFunc("resetCaptureKeyboard", resetCaptureKeyboard);
1654 ls.registerFunc("setTopWindow", setTopWindow);
1655 ls.registerFunc("addOnDbChange", addOnDbChange);
1656 ls.registerFunc("removeOnDbChange", removeOnDbChange);
1657 ls.registerFunc("getUIId", getUIId);
1658 ls.registerFunc("runAH", runAH);
1659 ls.registerFunc("deleteUI", deleteUI);
1660 ls.registerFunc("deleteReflectable", deleteReflectable);
1661 ls.registerFunc("getWindowSize", getWindowSize);
1662 ls.registerFunc("getTextureSize", getTextureSize);
1663 ls.registerFunc("disableModalWindow", disableModalWindow);
1664 #ifdef RYZOM_LUA_UCSTRING
1665 ls.registerFunc("isUCString", isUCString);
1666 ls.registerFunc("concatUCString", concatUCString);
1667 #endif
1668 ls.registerFunc("concatString", concatString);
1669 ls.registerFunc("tableToString", tableToString);
1670 ls.registerFunc("getCurrentWindowUnder", getCurrentWindowUnder);
1671 ls.registerFunc("runExpr", runExpr);
1672 ls.registerFunc("runFct", runFct);
1673 ls.registerFunc("runCommand", runCommand);
1674 ls.registerFunc("getPathContent", getPathContent);
1676 // Through LUABind API
1677 lua_State *L= ls.getStatePointer();
1679 luabind::module(L)
1681 luabind::def("findReplaceAll", (std::string(*)(const std::string &, const std::string &, const std::string &)) &findReplaceAll),
1682 luabind::def("findReplaceAll", (ucstring(*)(const ucstring &, const ucstring &, const ucstring &)) &findReplaceAll),
1683 luabind::def("findReplaceAll", (ucstring(*)(const ucstring &, const std::string &, const std::string &)) &findReplaceAll),
1684 luabind::def("findReplaceAll", (ucstring(*)(const ucstring &, const ucstring &, const std::string &)) &findReplaceAll),
1685 luabind::def("findReplaceAll", (ucstring(*)(const ucstring &, const std::string &, const ucstring &)) &findReplaceAll),
1687 #if !FINAL_VERSION
1688 LUABIND_FUNC(openDoc),
1689 LUABIND_FUNC(launchProgram),
1690 #endif
1692 luabind::def("fileLookup", CMiscFunctions::fileLookup),
1693 luabind::def("shellExecute", CMiscFunctions::shellExecute),
1694 LUABIND_FUNC(fileExists)
1697 // inside i18n table
1698 luabind::module(L, "i18n")
1700 #ifdef RYZOM_LUA_UCSTRING
1701 luabind::def("get", &CI18N::getAsUtf16), // Compatibility
1702 #else
1703 luabind::def("get", &CI18N::get),
1704 #endif
1705 luabind::def("hasTranslation", &CI18N::hasTranslation)
1707 // inside 'nlfile' table
1708 luabind::module(L, "nlfile")
1710 luabind::def("getFilename", NLMISC::CFile::getFilename),
1711 luabind::def("getExtension", NLMISC::CFile::getExtension),
1712 luabind::def("getFilenameWithoutExtension", NLMISC::CFile::getFilenameWithoutExtension)
1714 // inside 'nltime' table
1715 luabind::module(L, "nltime")
1717 luabind::def("getPreciseLocalTime", getPreciseLocalTime),
1718 luabind::def("getSecondsSince1970", NLMISC::CTime::getSecondsSince1970),
1719 luabind::def("getLocalTime", getLocalTime) // NB : use CLuaIHM::getLocalTime instead of NLMISC::CTime::getLocalTime, because the NLMISC
1720 // version returns a uint64, which can't be casted into lua numbers (doubles ...)
1725 // ***************************************************************************
1726 double CLuaIHM::getPreciseLocalTime()
1728 //H_AUTO(Lua_CLuaIHM_getPreciseLocalTime)
1729 // don't export these 2 function to lua directly here, because all uint64 can't be represented with lua 'numbers'
1730 return NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime());
1733 // ***************************************************************************
1734 void CLuaIHM::registerAll(CLuaState &ls)
1736 //H_AUTO(Lua_CLuaIHM_registerAll)
1737 registerBasics(ls);
1738 registerIHM(ls);
1743 //#define CHECK_REFLECTABLE_MT
1746 // ***************************************************************************
1747 void CLuaIHM::pushReflectableOnStack(CLuaState &ls, class CReflectableRefPtrTarget *pRPT)
1749 //H_AUTO(Lua_CLuaIHM_pushReflectableOnStack)
1750 nlassert(pRPT);
1751 CLuaStackChecker lsc(&ls, 1);
1753 if (!pRPT)
1755 ls.pushNil();
1756 return;
1759 //ls.dumpStack();
1760 /** if there's already a ref ptr for this object in the registry, then use it,
1761 * else create a new one to avoid costly allocations
1763 ls.pushLightUserData(pRPT);
1764 ls.getTable(LUA_REGISTRYINDEX);
1765 //ls.dumpStack();
1766 if (ls.isNil())
1768 ls.pop(1);
1769 //ls.dumpStack();
1770 // allocate the user data where to put the ref ptr
1771 void *ptr= ls.newUserData(sizeof(CReflectableLuaRef));
1772 nlassert(ptr);
1773 //ls.dumpStack();
1775 // disable memory leaks detection for placement new
1776 #ifdef new
1777 #undef new
1778 #endif
1780 // initialize it, and copy the given element
1781 new (ptr) CReflectableLuaRef(pRPT);
1783 // reenable memory leaks detection for placement new
1784 #ifdef DEBUG_NEW
1785 #define new DEBUG_NEW
1786 #endif
1788 // Assign to this user data the __ui_metatable
1789 //ls.dumpStack();
1790 ls.push(IHM_LUA_METATABLE); // userdata "__ui_metatable"
1791 //ls.dumpStack();
1792 ls.getTable(LUA_REGISTRYINDEX); // userdata __ui_metatable
1793 //ls.dumpStack();
1794 nlverify(ls.setMetaTable(-2)); // userdata
1795 //ls.dumpStack();
1797 // cache in registry
1798 ls.pushLightUserData(pRPT);
1799 ls.pushValue(-2); // copy for table insertion
1800 //ls.dumpStack();
1801 ls.setTable(LUA_REGISTRYINDEX);
1802 //ls.dumpStack();
1805 // Check that the metatable is correct
1806 #ifdef CHECK_REFLECTABLE_MT
1807 nlverify(ls.getMetaTable(-1)); // userdata __ui_metatable
1808 ls.push("__index");
1809 ls.getTable(-2);
1810 ls.push("__newindex");
1811 ls.getTable(-3);
1812 ls.push("__gc");
1813 ls.getTable(-4);
1814 nlassert(ls.isCFunction(-1));
1815 nlassert(ls.isCFunction(-2));
1816 nlassert(ls.isCFunction(-3));
1817 ls.pop(4);
1818 #endif
1819 //ls.dumpStack();
1822 // ***************************************************************************
1823 bool CLuaIHM::isReflectableOnStack(CLuaState &ls, sint index)
1825 //H_AUTO(Lua_CLuaIHM_isReflectableOnStack)
1826 CLuaStackChecker lsc(&ls);
1828 if(!ls.isUserData(index))
1829 return false;
1830 // verify that it is a UI with its metatable
1831 if(!ls.getMetaTable(index)) // ??? object_metatable
1832 return false;
1833 ls.push(IHM_LUA_METATABLE); // ??? object_metatable "__ui_metatable"
1834 ls.getTable(LUA_REGISTRYINDEX); // ??? object_metatable __ui_metatable
1835 // equal test
1836 bool ok= ls.rawEqual(-2, -1);
1837 // Also must not be nil (maybe nil in case of LuaIHM still not registered)
1838 ok= ok && !ls.isNil(-1);
1839 ls.pop();
1840 ls.pop();
1842 return ok;
1845 // ***************************************************************************
1846 CReflectableRefPtrTarget *CLuaIHM::getReflectableOnStack(CLuaState &ls, sint index)
1848 //H_AUTO(Lua_CLuaIHM_getReflectableOnStack)
1849 if(!isReflectableOnStack(ls, index))
1850 return NULL;
1852 CReflectableLuaRef *p= (CReflectableLuaRef *) ls.toUserData(index);
1853 nlassert(p->Ptr);
1854 return p->Ptr;
1858 // ***************************************************************************
1859 // ***************************************************************************
1860 // LUA IHM Functions
1861 // ***************************************************************************
1862 // ***************************************************************************
1865 // ***************************************************************************
1866 uint32 CLuaIHM::getLocalTime()
1868 //H_AUTO(Lua_CLuaIHM_getLocalTime)
1869 return (uint32) NLMISC::CTime::getLocalTime();
1873 // ***************************************************************************
1874 std::string CLuaIHM::findReplaceAll(const std::string &str, const std::string &search, const std::string &replace)
1876 //H_AUTO(Lua_CLuaIHM_findReplaceAll)
1877 std::string ret= str;
1878 while(strFindReplace(ret, search, replace));
1879 return ret;
1882 #ifdef RYZOM_LUA_UCSTRING
1883 // ***************************************************************************
1884 ucstring CLuaIHM::findReplaceAll(const ucstring &str, const ucstring &search, const ucstring &replace)
1886 //H_AUTO(Lua_CLuaIHM_findReplaceAll)
1887 return strFindReplaceAll(str, search, replace);
1890 // ***************************************************************************
1891 ucstring CLuaIHM::findReplaceAll(const ucstring &str, const std::string &search, const std::string &replace)
1893 //H_AUTO(Lua_CLuaIHM_findReplaceAll)
1894 return findReplaceAll(str, ucstring::makeFromUtf8(search), ucstring::makeFromUtf8(replace));
1897 // ***************************************************************************
1898 ucstring CLuaIHM::findReplaceAll(const ucstring &str, const std::string &search, const ucstring &replace)
1900 //H_AUTO(Lua_CLuaIHM_findReplaceAll)
1901 return findReplaceAll(str, ucstring::makeFromUtf8(search), replace);
1904 // ***************************************************************************
1905 ucstring CLuaIHM::findReplaceAll(const ucstring &str, const ucstring &search, const std::string &replace)
1907 //H_AUTO(Lua_CLuaIHM_findReplaceAll)
1908 return findReplaceAll(str, search, ucstring::makeFromUtf8(replace));
1910 #endif
1912 // ***************************************************************************
1913 void CLuaIHM::fails(CLuaState &ls, const char *format, ...)
1915 //H_AUTO(Lua_CLuaIHM_fails)
1916 std::string reason;
1917 NLMISC_CONVERT_VARGS (reason, format, NLMISC::MaxCStringSize);
1918 std::string stack;
1919 ls.getStackAsString(stack);
1920 // use a std::exception, to avoid Nel Exception warning
1921 throw ELuaIHMException("%s. Lua stack = \n %s", reason.c_str(), stack.c_str());
1925 // ***************************************************************************
1926 void CLuaIHM::checkArgCount(CLuaState &ls, const char* funcName, uint nArgs)
1928 //H_AUTO(Lua_CLuaIHM_checkArgCount)
1929 if(ls.getTop()!=(sint)nArgs)
1931 fails(ls, "%s() need exactly %d arguments (tips : check between method & function call)", funcName, nArgs);
1935 // ***************************************************************************
1936 void CLuaIHM::checkArgMin(CLuaState &ls, const char* funcName, uint nArgs)
1938 //H_AUTO(Lua_CLuaIHM_checkArgMin)
1939 if(ls.getTop()<(sint)nArgs)
1941 fails(ls, "%s() need at least %d arguments (tips : check between method & function call)", funcName, nArgs);
1945 // ***************************************************************************
1946 void CLuaIHM::checkArgMax(CLuaState &ls,const char* funcName,uint nArgs)
1948 //H_AUTO(Lua_CLuaIHM_checkArgMax)
1949 if(ls.getTop()>(sint)nArgs)
1951 fails(ls, "%s() need at most %d arguments.", funcName, nArgs);
1955 // ***************************************************************************
1956 void CLuaIHM::check(CLuaState &ls, bool ok, const std::string &failReason)
1958 //H_AUTO(Lua_CLuaIHM_check)
1959 if(!ok)
1961 fails(ls, failReason.c_str());
1965 // ***************************************************************************
1966 void CLuaIHM::checkArgType(CLuaState &ls, const char *funcName, uint index, int argType)
1968 //H_AUTO(Lua_CLuaIHM_checkArgType)
1969 nlassert(index > 0);
1970 if (ls.getTop() < (int) index)
1972 fails(ls, "%s : argument %d of expected type %s was not defined", funcName, index, ls.getTypename(argType));
1974 if (ls.type(index) != argType)
1976 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));
1980 // ***************************************************************************
1981 void CLuaIHM::checkArgTypeRGBA(CLuaState &ls, const char *funcName, uint index)
1983 //H_AUTO(Lua_CLuaIHM_checkArgTypeRGBA)
1984 nlassert(index > 0);
1985 if (ls.getTop() < (int) index)
1987 fails(ls, "%s : argument %d of expected type RGBA was not defined", funcName, index);
1989 ls.pushValue(index);
1990 CRGBA dummy;
1991 if (!pop(ls, dummy))
1993 fails(ls, "%s : argument %d of expected type RGBA has bad type : %s", funcName, index, ls.getTypename(ls.type(index)), ls.type(index));
1997 #ifdef RYZOM_LUA_UCSTRING
1998 // ***************************************************************************
1999 void CLuaIHM::checkArgTypeUCString(CLuaState &ls, const char *funcName, uint index)
2001 //H_AUTO(Lua_CLuaIHM_checkArgTypeUCString)
2002 nlassert(index > 0);
2003 if (ls.getTop() < (int) index)
2005 fails(ls, "%s : argument %d of expected type ucstring was not defined", funcName, index);
2007 ls.pushValue(index);
2008 ucstring dummy;
2009 if (!pop(ls, dummy))
2011 fails(ls, "%s : argument %d of expected type ucstring has bad type : %s", funcName, index, ls.getTypename(ls.type(index)), ls.type(index));
2014 #endif
2017 // ***************************************************************************
2018 bool CLuaIHM::popString(CLuaState &ls, std::string & dest)
2020 //H_AUTO(Lua_CLuaIHM_popString)
2023 #if LUABIND_VERSION > 600
2024 luabind::object obj(luabind::from_stack(ls.getStatePointer(), -1));
2025 ls.pop();
2026 #else
2027 luabind::object obj(ls.getStatePointer());
2028 obj.set();
2029 #endif
2030 dest = luabind::object_cast<std::string>(obj);
2032 catch(const luabind::cast_failed &)
2034 return false;
2036 return true;
2039 // ***************************************************************************
2040 bool CLuaIHM::popSINT32(CLuaState &ls, sint32 & dest)
2042 //H_AUTO(Lua_CLuaIHM_popSINT32)
2045 #if LUABIND_VERSION > 600
2046 luabind::object obj(luabind::from_stack(ls.getStatePointer(), -1));
2047 ls.pop();
2048 #else
2049 luabind::object obj(ls.getStatePointer());
2050 obj.set();
2051 #endif
2052 dest = luabind::object_cast<sint32>(obj);
2054 catch(const luabind::cast_failed &)
2056 return false;
2058 return true;
2061 // ***************************************************************************
2062 void CLuaIHM::getPoly2DOnStack(CLuaState &ls, sint index, NLMISC::CPolygon2D &dest)
2064 //H_AUTO(Lua_CLuaIHM_getPoly2DOnStack)
2065 ls.pushValue(index);
2066 CLuaObject poly;
2067 poly.pop(ls);
2068 dest.Vertices.clear();
2069 ENUM_LUA_TABLE(poly, it)
2071 it.nextValue().push();
2072 NLMISC::CVector2f pos;
2073 if (!pop(ls, pos))
2075 fails(ls, "2D polygon expects CVector2f for poly coordinates");
2077 dest.Vertices.push_back(pos);