Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/buildsystem2/src/ceguilua-0.6.1/ceguilua/CEGUILuaFunctor.cpp @ 2570

Last change on this file since 2570 was 2509, checked in by rgrieder, 16 years ago

Merged revisions 1875-2278 of the buildsystem branch to buildsystem2.

  • Property svn:eol-style set to native
File size: 9.1 KB
Line 
1/***********************************************************************
2    filename: CEGUILuaFunctor.cpp
3    created:  Thu Jan 26 2006
4    author:   Tomas Lindquist Olsen <tomas@famolsen.dk>
5
6    purpose:  Implementation for LuaFunctor class
7*************************************************************************/
8/***************************************************************************
9 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
10 *
11 *   Permission is hereby granted, free of charge, to any person obtaining
12 *   a copy of this software and associated documentation files (the
13 *   "Software"), to deal in the Software without restriction, including
14 *   without limitation the rights to use, copy, modify, merge, publish,
15 *   distribute, sublicense, and/or sell copies of the Software, and to
16 *   permit persons to whom the Software is furnished to do so, subject to
17 *   the following conditions:
18 *
19 *   The above copyright notice and this permission notice shall be
20 *   included in all copies or substantial portions of the Software.
21 *
22 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 *   OTHER DEALINGS IN THE SOFTWARE.
29 ***************************************************************************/
30#include "CEGUILuaFunctor.h"
31#include "CEGUILogger.h"
32#include "CEGUIExceptions.h"
33#include "CEGUIPropertyHelper.h"
34
35// include Lua libs and tolua++
36extern "C" {
37#include "lua.h"
38#include "lualib.h"
39#include "lauxlib.h"
40}
41
42#include "tolua++.h"
43
44// Start of CEGUI namespace section
45namespace CEGUI
46{
47
48/*************************************************************************
49    Constructor
50*************************************************************************/
51LuaFunctor::LuaFunctor(lua_State* state, int func, int selfIndex) :
52    L(state),
53    index(func),
54    self(selfIndex),
55    needs_lookup(false)
56{
57}
58
59/*************************************************************************
60    Constructor
61*************************************************************************/
62LuaFunctor::LuaFunctor(lua_State* state, const String& func, int selfIndex) :
63    L(state),
64    index(LUA_NOREF),
65    self(selfIndex),
66    needs_lookup(true),
67    function_name(func)
68{
69}
70
71/*************************************************************************
72    Constructor
73*************************************************************************/
74LuaFunctor::LuaFunctor(const LuaFunctor& cp) :
75    L(cp.L),
76    index(cp.index),
77    self(cp.self),
78    needs_lookup(cp.needs_lookup),
79    function_name(cp.function_name)
80{
81}
82
83/*************************************************************************
84    Destructor
85*************************************************************************/
86LuaFunctor::~LuaFunctor()
87{
88    if (self!=LUA_NOREF)
89    {
90        luaL_unref(L, LUA_REGISTRYINDEX, self);
91    }
92    if (index!=LUA_NOREF)
93    {
94        luaL_unref(L, LUA_REGISTRYINDEX, index);
95    }
96}
97
98/*************************************************************************
99    Call operator
100*************************************************************************/
101bool LuaFunctor::operator()(const EventArgs& args) const
102{
103    // is this a late binding?
104    if (needs_lookup)
105    {
106        pushNamedFunction(L, function_name);
107        // reference function
108        index = luaL_ref(L, LUA_REGISTRYINDEX);
109        needs_lookup = false;
110        CEGUI_LOGINSANE("Late binding of callback '"+function_name+"' performed");
111        function_name.clear();
112    } // if (needs_lookup)
113
114        ScriptWindowHelper* helper = 0;
115        //Set a global for this window
116        if(args.d_hasWindow)
117        {
118                WindowEventArgs& we = (WindowEventArgs&)args;
119                helper = new ScriptWindowHelper(we.window);
120                tolua_pushusertype(L,(void*)helper,"CEGUI::ScriptWindowHelper");
121                lua_setglobal(L,"this");
122        }
123
124    // retrieve function
125    lua_rawgeti(L, LUA_REGISTRYINDEX, index);
126
127    // possibly self as well?
128    int nargs = 1;
129    if (self != LUA_NOREF)
130    {
131        lua_rawgeti(L, LUA_REGISTRYINDEX, self);
132        ++nargs;
133    }
134
135    // push EventArgs  parameter
136    tolua_pushusertype(L, (void*)&args, "const CEGUI::EventArgs");
137
138    // call it
139    int error = lua_pcall(L, nargs, 0, 0);
140
141    // handle errors
142    if (error)
143    {
144        String errStr(lua_tostring(L, -1));
145        lua_pop(L, 1);
146                if(helper)
147                {
148                        delete helper;
149                        helper = 0;
150                }
151        throw ScriptException("Unable to call Lua event handler:\n\n"+errStr+"\n");
152    } // if (error)
153
154        if(helper)
155        {
156                delete helper;
157                helper = 0;
158        }
159
160    return true;
161}
162
163/*************************************************************************
164    do event subscription by reference instead of by name
165*************************************************************************/
166Event::Connection LuaFunctor::SubscribeEvent(EventSet* self, const String& event_name, int funcIndex, int selfIndex, lua_State* L)
167{
168    // should we pass a self to the callback?
169    int thisIndex = LUA_NOREF;
170    if (selfIndex != LUA_NOREF)
171    {
172        // reference self
173        thisIndex = luaL_ref(L, LUA_REGISTRYINDEX);
174    }
175
176    // do the real subscription
177    int type = lua_type(L,-1);
178    Event::Connection con;
179    if (type == LUA_TFUNCTION)
180    {
181        // reference function
182        int index = luaL_ref(L, LUA_REGISTRYINDEX);
183        LuaFunctor functor(L,index,thisIndex);
184        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
185        // make sure we don't release the reference(s) we just made when this call returns
186        functor.index = LUA_NOREF;
187        functor.self = LUA_NOREF;
188    }
189    else if (type == LUA_TSTRING)
190    {
191        const char* str = lua_tostring(L, -1);
192        LuaFunctor functor(L,String(str),thisIndex);
193        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
194        // make sure we don't release the reference we just (maybe) made when this call returns
195        functor.self = LUA_NOREF;
196    }
197    else
198    {
199        luaL_error(L,"bad function passed to subscribe function. must be a real function, or a string for late binding");
200    }
201
202    // return the event connection
203    return con;
204}
205
206/*************************************************************************
207    Pushes a named function on the stack
208*************************************************************************/
209void LuaFunctor::pushNamedFunction(lua_State* L, const String& handler_name)
210{
211    int top = lua_gettop(L);
212
213    // do we have any dots in the handler name? if so we grab the function as a table field
214    String::size_type i = handler_name.find_first_of((utf32)'.');
215    if (i!=String::npos)
216    {
217        // split the rest of the string up in parts seperated by '.'
218        // TODO: count the dots and size the vector accordingly from the beginning.
219        std::vector<String> parts;
220        String::size_type start = 0;
221        do
222        {
223            parts.push_back(handler_name.substr(start,i-start));
224            start = i+1;
225            i = handler_name.find_first_of((utf32)'.',start);
226        } while(i!=String::npos);
227
228        // add last part
229        parts.push_back(handler_name.substr(start));
230
231        // first part is the global
232        lua_getglobal(L, parts[0].c_str());
233        if (!lua_istable(L,-1))
234        {
235            lua_settop(L,top);
236            throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as first part is not a table");
237        }
238
239        // if there is more than two parts, we have more tables to go through
240        std::vector<String>::size_type visz = parts.size();
241        if (visz-- > 2) // avoid subtracting one later on
242        {
243            // go through all the remaining parts to (hopefully) have a valid Lua function in the end
244            std::vector<String>::size_type vi = 1;
245            while (vi<visz)
246            {
247                // push key, and get the next table
248                lua_pushstring(L,parts[vi].c_str());
249                lua_gettable(L,-2);
250                if (!lua_istable(L,-1))
251                {
252                    lua_settop(L,top);
253                    throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as part #"+PropertyHelper::uintToString(uint(vi+1))+" ("+parts[vi]+") is not a table");
254                }
255                // get rid of the last table and move on
256                lua_remove(L,-2);
257                vi++;
258            }
259        }
260
261        // now we are ready to get the function to call ... phew :)
262        lua_pushstring(L,parts[visz].c_str());
263        lua_gettable(L,-2);
264        lua_remove(L,-2); // get rid of the table
265    }
266    // just a regular global function
267    else
268    {
269        lua_getglobal(L, handler_name.c_str());
270    }
271
272    // is it a function
273    if (!lua_isfunction(L,-1))
274    {
275        lua_settop(L,top);
276        throw ScriptException("The Lua event handler: '"+handler_name+"' does not represent a Lua function");
277    }
278}
279
280} // namespace CEGUI
Note: See TracBrowser for help on using the repository browser.