Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/buildsystem2/src/ceguilua-0.5.0/ceguilua/CEGUILuaFunctor.cpp @ 2601

Last change on this file since 2601 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: 8.7 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    }
113
114    // retrieve function
115    lua_rawgeti(L, LUA_REGISTRYINDEX, index);
116
117    // possibly self as well?
118    int nargs = 1;
119    if (self != LUA_NOREF)
120    {
121        lua_rawgeti(L, LUA_REGISTRYINDEX, self);
122        ++nargs;
123    }
124
125    // push EventArgs  parameter
126    tolua_pushusertype(L, (void*)&args, "const CEGUI::EventArgs");
127
128    // call it
129    int error = lua_pcall(L, nargs, 0, 0);
130
131    // handle errors
132    if (error)
133    {
134        String errStr(lua_tostring(L, -1));
135        lua_pop(L, 1);
136        throw ScriptException("Unable to call Lua event handler:\n\n"+errStr+"\n");
137    }
138
139    return true;
140}
141
142/*************************************************************************
143    do event subscription by reference instead of by name
144*************************************************************************/
145Event::Connection LuaFunctor::SubscribeEvent(EventSet* self, const String& event_name, int funcIndex, int selfIndex, lua_State* L)
146{
147    // should we pass a self to the callback?
148    int thisIndex = LUA_NOREF;
149    if (selfIndex != LUA_NOREF)
150    {
151        // reference self
152        thisIndex = luaL_ref(L, LUA_REGISTRYINDEX);
153    }
154
155    // do the real subscription
156    int type = lua_type(L,-1);
157    Event::Connection con;
158    if (type == LUA_TFUNCTION)
159    {
160        // reference function
161        int index = luaL_ref(L, LUA_REGISTRYINDEX);
162        LuaFunctor functor(L,index,thisIndex);
163        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
164        // make sure we don't release the reference(s) we just made when this call returns
165        functor.index = LUA_NOREF;
166        functor.self = LUA_NOREF;
167    }
168    else if (type == LUA_TSTRING)
169    {
170        const char* str = lua_tostring(L, -1);
171        LuaFunctor functor(L,String(str),thisIndex);
172        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
173        // make sure we don't release the reference we just (maybe) made when this call returns
174        functor.self = LUA_NOREF;
175    }
176    else
177    {
178        luaL_error(L,"bad function passed to subscribe function. must be a real function, or a string for late binding");
179    }
180
181    // return the event connection
182    return con;
183}
184
185/*************************************************************************
186    Pushes a named function on the stack
187*************************************************************************/
188void LuaFunctor::pushNamedFunction(lua_State* L, const String& handler_name)
189{
190    int top = lua_gettop(L);
191
192    // do we have any dots in the handler name? if so we grab the function as a table field
193    String::size_type i = handler_name.find_first_of((utf32)'.');
194    if (i!=String::npos)
195    {
196        // split the rest of the string up in parts seperated by '.'
197        // TODO: count the dots and size the vector accordingly from the beginning.
198        std::vector<String> parts;
199        String::size_type start = 0;
200        do
201        {
202            parts.push_back(handler_name.substr(start,i-start));
203            start = i+1;
204            i = handler_name.find_first_of((utf32)'.',start);
205        } while(i!=String::npos);
206
207        // add last part
208        parts.push_back(handler_name.substr(start));
209
210        // first part is the global
211        lua_getglobal(L, parts[0].c_str());
212        if (!lua_istable(L,-1))
213        {
214            lua_settop(L,top);
215            throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as first part is not a table");
216        }
217
218        // if there is more than two parts, we have more tables to go through
219        std::vector<String>::size_type visz = parts.size();
220        if (visz-- > 2) // avoid subtracting one later on
221        {
222            // go through all the remaining parts to (hopefully) have a valid Lua function in the end
223            std::vector<String>::size_type vi = 1;
224            while (vi<visz)
225            {
226                // push key, and get the next table
227                lua_pushstring(L,parts[vi].c_str());
228                lua_gettable(L,-2);
229                if (!lua_istable(L,-1))
230                {
231                    lua_settop(L,top);
232                    throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as part #"+PropertyHelper::uintToString(uint(vi+1))+" ("+parts[vi]+") is not a table");
233                }
234                // get rid of the last table and move on
235                lua_remove(L,-2);
236                vi++;
237            }
238        }
239
240        // now we are ready to get the function to call ... phew :)
241        lua_pushstring(L,parts[visz].c_str());
242        lua_gettable(L,-2);
243        lua_remove(L,-2); // get rid of the table
244    }
245    // just a regular global function
246    else
247    {
248        lua_getglobal(L, handler_name.c_str());
249    }
250
251    // is it a function
252    if (!lua_isfunction(L,-1))
253    {
254        lua_settop(L,top);
255        throw ScriptException("The Lua event handler: '"+handler_name+"' does not represent a Lua function");
256    }
257}
258
259} // namespace CEGUI
Note: See TracBrowser for help on using the repository browser.