Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/ceguilua-0.5.0b/ceguilua/CEGUILuaFunctor.cpp @ 2698

Last change on this file since 2698 was 1810, checked in by rgrieder, 16 years ago

merged ceguilua branch back to trunk

  • Property svn:eol-style set to native
File size: 8.6 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++
36#include "lua/lua.hpp"
37#include "tolua/tolua++.h"
38
39// Start of CEGUI namespace section
40namespace CEGUI
41{
42
43/*************************************************************************
44    Constructor
45*************************************************************************/
46LuaFunctor::LuaFunctor(lua_State* state, int func, int selfIndex) :
47    L(state),
48    index(func),
49    self(selfIndex),
50    needs_lookup(false)
51{
52}
53
54/*************************************************************************
55    Constructor
56*************************************************************************/
57LuaFunctor::LuaFunctor(lua_State* state, const String& func, int selfIndex) :
58    L(state),
59    index(LUA_NOREF),
60    self(selfIndex),
61    needs_lookup(true),
62    function_name(func)
63{
64}
65
66/*************************************************************************
67    Constructor
68*************************************************************************/
69LuaFunctor::LuaFunctor(const LuaFunctor& cp) :
70    L(cp.L),
71    index(cp.index),
72    self(cp.self),
73    needs_lookup(cp.needs_lookup),
74    function_name(cp.function_name)
75{
76}
77
78/*************************************************************************
79    Destructor
80*************************************************************************/
81LuaFunctor::~LuaFunctor()
82{
83    if (self!=LUA_NOREF)
84    {
85        luaL_unref(L, LUA_REGISTRYINDEX, self);
86    }
87    if (index!=LUA_NOREF)
88    {
89        luaL_unref(L, LUA_REGISTRYINDEX, index);
90    }
91}
92
93/*************************************************************************
94    Call operator
95*************************************************************************/
96bool LuaFunctor::operator()(const EventArgs& args) const
97{
98    // is this a late binding?
99    if (needs_lookup)
100    {
101        pushNamedFunction(L, function_name);
102        // reference function
103        index = luaL_ref(L, LUA_REGISTRYINDEX);
104        needs_lookup = false;
105        CEGUI_LOGINSANE("Late binding of callback '"+function_name+"' performed");
106        function_name.clear();
107    }
108
109    // retrieve function
110    lua_rawgeti(L, LUA_REGISTRYINDEX, index);
111
112    // possibly self as well?
113    int nargs = 1;
114    if (self != LUA_NOREF)
115    {
116        lua_rawgeti(L, LUA_REGISTRYINDEX, self);
117        ++nargs;
118    }
119
120    // push EventArgs  parameter
121    tolua_pushusertype(L, (void*)&args, "const CEGUI::EventArgs");
122
123    // call it
124    int error = lua_pcall(L, nargs, 0, 0);
125
126    // handle errors
127    if (error)
128    {
129        String errStr(lua_tostring(L, -1));
130        lua_pop(L, 1);
131        throw ScriptException("Unable to call Lua event handler:\n\n"+errStr+"\n");
132    }
133
134    return true;
135}
136
137/*************************************************************************
138    do event subscription by reference instead of by name
139*************************************************************************/
140Event::Connection LuaFunctor::SubscribeEvent(EventSet* self, const String& event_name, int funcIndex, int selfIndex, lua_State* L)
141{
142    // should we pass a self to the callback?
143    int thisIndex = LUA_NOREF;
144    if (selfIndex != LUA_NOREF)
145    {
146        // reference self
147        thisIndex = luaL_ref(L, LUA_REGISTRYINDEX);
148    }
149
150    // do the real subscription
151    int type = lua_type(L,-1);
152    Event::Connection con;
153    if (type == LUA_TFUNCTION)
154    {
155        // reference function
156        int index = luaL_ref(L, LUA_REGISTRYINDEX);
157        LuaFunctor functor(L,index,thisIndex);
158        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
159        // make sure we don't release the reference(s) we just made when this call returns
160        functor.index = LUA_NOREF;
161        functor.self = LUA_NOREF;
162    }
163    else if (type == LUA_TSTRING)
164    {
165        const char* str = lua_tostring(L, -1);
166        LuaFunctor functor(L,String(str),thisIndex);
167        con = self->subscribeEvent(String(event_name), Event::Subscriber(functor));
168        // make sure we don't release the reference we just (maybe) made when this call returns
169        functor.self = LUA_NOREF;
170    }
171    else
172    {
173        luaL_error(L,"bad function passed to subscribe function. must be a real function, or a string for late binding");
174    }
175
176    // return the event connection
177    return con;
178}
179
180/*************************************************************************
181    Pushes a named function on the stack
182*************************************************************************/
183void LuaFunctor::pushNamedFunction(lua_State* L, const String& handler_name)
184{
185    int top = lua_gettop(L);
186
187    // do we have any dots in the handler name? if so we grab the function as a table field
188    String::size_type i = handler_name.find_first_of((utf32)'.');
189    if (i!=String::npos)
190    {
191        // split the rest of the string up in parts seperated by '.'
192        // TODO: count the dots and size the vector accordingly from the beginning.
193        std::vector<String> parts;
194        String::size_type start = 0;
195        do
196        {
197            parts.push_back(handler_name.substr(start,i-start));
198            start = i+1;
199            i = handler_name.find_first_of((utf32)'.',start);
200        } while(i!=String::npos);
201
202        // add last part
203        parts.push_back(handler_name.substr(start));
204
205        // first part is the global
206        lua_getglobal(L, parts[0].c_str());
207        if (!lua_istable(L,-1))
208        {
209            lua_settop(L,top);
210            throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as first part is not a table");
211        }
212
213        // if there is more than two parts, we have more tables to go through
214        std::vector<String>::size_type visz = parts.size();
215        if (visz-- > 2) // avoid subtracting one later on
216        {
217            // go through all the remaining parts to (hopefully) have a valid Lua function in the end
218            std::vector<String>::size_type vi = 1;
219            while (vi<visz)
220            {
221                // push key, and get the next table
222                lua_pushstring(L,parts[vi].c_str());
223                lua_gettable(L,-2);
224                if (!lua_istable(L,-1))
225                {
226                    lua_settop(L,top);
227                    throw ScriptException("Unable to get the Lua event handler: '"+handler_name+"' as part #"+PropertyHelper::uintToString(uint(vi+1))+" ("+parts[vi]+") is not a table");
228                }
229                // get rid of the last table and move on
230                lua_remove(L,-2);
231                vi++;
232            }
233        }
234
235        // now we are ready to get the function to call ... phew :)
236        lua_pushstring(L,parts[visz].c_str());
237        lua_gettable(L,-2);
238        lua_remove(L,-2); // get rid of the table
239    }
240    // just a regular global function
241    else
242    {
243        lua_getglobal(L, handler_name.c_str());
244    }
245
246    // is it a function
247    if (!lua_isfunction(L,-1))
248    {
249        lua_settop(L,top);
250        throw ScriptException("The Lua event handler: '"+handler_name+"' does not represent a Lua function");
251    }
252}
253
254} // namespace CEGUI
Note: See TracBrowser for help on using the repository browser.