فهرست منبع

Fixed one of the leaks.

Fixed some more Lua errors that remained when I converted Python to Lua

Added a 'Shutdown' function for the plugin, so that all of the elements can be garbage collected from Lua before they get destroyed by the other plugins.

Fixed Log.Message

Created the functions for AddEventListener on both Context and Element.

Fixed the LuaEventListener lua function composition to actually compile AND run the string. It works now.
Nate Starkey 13 سال پیش
والد
کامیت
c615b0b190

+ 1 - 0
Include/Rocket/Core/Lua/Interpreter.h

@@ -26,6 +26,7 @@ public:
     static lua_State* GetLuaState();
 
     static void Initialise();
+	static void Shutdown();
     
     //From Plugin
     virtual int GetEventClasses();

+ 2 - 1
Samples/luainvaders/data/main_menu.rml

@@ -22,7 +22,8 @@ MainMenu = MainMenu or {}
 
 function MainMenu.CloseLogo(document)
 	if document.context then
-		document.context.documents['logo']:Close()
+		--context.documents seems to be empty
+		--document.context.documents['logo']:Close()
     end
 end
 		</script>

+ 6 - 6
Samples/luainvaders/data/options.rml

@@ -31,14 +31,14 @@ Options = Options or {}
 function Options.LoadOptions(document)
     local f = io.open('options.dat', 'r')
     --create the function below
-    local options = cPickle.loads(''.join(f:lines()))
+    local options = nil --cPickle.loads(''.join(f:lines()))
     
     document:GetElementById(options['graphics']).checked = true
     document:GetElementById('reverb').checked = options['reverb']
     document:GetElementById('3d').checked = options['3d']
 end
 
-function Options.SaveOptions(event, document):
+function Options.SaveOptions(event)
     if event.parameters['button'] == 'cancel' then
         return
     end
@@ -51,11 +51,11 @@ function Options.SaveOptions(event, document):
     
     local f = io.open('options.dat', 'w+')
     --need the below function
-    f:write(cPickle.dumps(options))
+    --f:write(cPickle.dumps(options))
     f:close()
 end
 		
-function Options.DisplayBadGraphics(document, display):
+function Options.DisplayBadGraphics(document, display)
 	if display then
 		document:GetElementById('bad_warning').style.display = 'block'
 	else
@@ -66,13 +66,13 @@ end
 	</script>
 	</head>
 	<body template="luawindow" onload="Window.OnWindowLoad(element) Options.LoadOptions(document)">
-		<form onsubmit="Options.SaveOptions(event, document) Window.LoadMenu('main_menu')">
+		<form onsubmit="Options.SaveOptions(event) Window.LoadMenu('main_menu',document)">
 			<div>
 				<p>
 					Graphics:<br />
 					<input id="good" type="radio" name="graphics" value="good"/> Good<br />
 					<input id="ok" type="radio" name="graphics" value="ok" checked="true"/> OK<br />
-					<input id="bad" type="radio" name="graphics" value="bad" onchange="DisplayBadGraphics(document, self.checked)" /> Bad<br />
+					<input id="bad" type="radio" name="graphics" value="bad" onchange="Options.DisplayBadGraphics(document, true)" /> Bad<br />
 				</p>
 				<p id="bad_warning" style="display: none;">Are you sure about this? Bad graphics are just plain <em>bad.</em></p>
 				<p>

+ 3 - 7
Samples/luainvaders/lua/start.lua

@@ -1,12 +1,8 @@
 
 function Startup()
-    local escape = rocket.key_identifier["ESCAPE"]
-    if escape ~= nil then
-        maincontext = rocket.contexts()["main"]
-        maincontext:LoadDocument("data/background.rml"):Show()
-        local doc = maincontext:LoadDocument("data/main_menu.rml")
-        doc:Show()
-    end
+	maincontext = rocket.contexts()["main"]
+	maincontext:LoadDocument("data/background.rml"):Show()
+	maincontext:LoadDocument("data/main_menu.rml"):Show()
 end
 
 Startup()

+ 1 - 0
Samples/luainvaders/src/main.cpp

@@ -133,6 +133,7 @@ int main(int, char**)
 	
 	// Shutdown Python before we shut down Rocket.
 	//PythonInterface::Shutdown();
+	Rocket::Core::Lua::Interpreter::Shutdown();
 
 	// Shut down the game singletons.
 	HighScores::Shutdown();

+ 38 - 1
Source/Core/Lua/Context.cpp

@@ -2,6 +2,8 @@
 #include "Context.h"
 #include <Rocket/Core/Context.h>
 #include <Rocket/Core/ElementDocument.h>
+#include <Rocket/Core/Factory.h>
+#include "LuaEventListener.h"
 
 namespace Rocket {
 namespace Core {
@@ -12,6 +14,38 @@ typedef Rocket::Core::ElementDocument Document;
 int ContextAddEventListener(lua_State* L, Context* obj)
 {
    //need to make an EventListener for Lua before I can do anything else
+	LUACHECKOBJ(obj);
+	const char* evt = luaL_checkstring(L,1); //event
+	Element* element = NULL;
+	bool capturephase = false;
+	//get the rest of the stuff needed to construct the listener
+	if(lua_gettop(L) > 2)
+	{
+		if(!lua_isnoneornil(L,3))
+			element = LuaType<Element>::check(L,3);
+		if(!lua_isnoneornil(L,4))
+			capturephase = CHECK_BOOL(L,4);
+
+	}
+	int type = lua_type(L,2);
+	if(type == LUA_TFUNCTION)
+	{
+		if(element)
+			element->AddEventListener(evt, new LuaEventListener(L,2,element), capturephase);
+		else
+			obj->AddEventListener(evt, new LuaEventListener(L,2,NULL), capturephase);
+	}
+	else if(type == LUA_TSTRING)
+	{
+		if(element)
+			element->AddEventListener(evt, new LuaEventListener(luaL_checkstring(L,2),element), capturephase);
+		else
+			obj->AddEventListener(evt, new LuaEventListener(luaL_checkstring(L,2),NULL), capturephase);
+	}
+	else
+	{
+		Log::Message(Log::LT_WARNING, "Lua Context:AddEventLisener's 2nd argument can only be a Lua function or a string, you passed in a %s", lua_typename(L,type));
+	}
     return 0;
 }
 
@@ -31,6 +65,8 @@ int ContextCreateDocument(lua_State* L, Context* obj)
         tag = luaL_checkstring(L,1);
     Document* doc = obj->CreateDocument(tag);
     LuaType<Document>::push(L,doc,true);
+	//for debugging
+	int count = doc->GetReferenceCount();
     return 1;
 }
 
@@ -38,7 +74,8 @@ int ContextLoadDocument(lua_State* L, Context* obj)
 {
     const char* path = luaL_checkstring(L,1);
     Document* doc = obj->LoadDocument(path);
-    LuaType<Document>::push(L,doc,true);
+    LuaType<Document>::push(L,doc,false);
+	doc->RemoveReference();
     return 1;
 }
 

+ 10 - 2
Source/Core/Lua/Context.h

@@ -3,12 +3,12 @@
     This defines a Context type in the Lua global namespace
 
     //methods
-    Context:AddEventListener --NYI
+    noreturn Context:AddEventListener(string event, function | string listener, [Element element, bool capture]) --see note at the bottom
     noreturn Context:AddMouseCursor(Document cursor_document)
     Document Context:CreateDocument([string tag]) --tag defaults to "body"
     Document Context:LoadDocument(string path)
     Document Context:LoadMouseCursor(string path)
-    bool Context:Render
+    bool Context:Render()
     noreturn Context:ShowMouseCursor(bool show)
     noreturn Context:UnloadAllDocuments()
     noreturn Context:UnloadAllMouseCursors()
@@ -27,6 +27,14 @@
     //setters
     Context.dimensions = Vector2i
 
+	--note 1
+	--[[
+	Context:AddEventListener has 2 'unusuals'. The first is that the 2nd argument can be either a string or a function;
+	see footnote 1 in Element.h for more info
+	The second is the optional parameters. If you pass in an element (anything not nil), then it will actually call 
+	element->AddEventListener and will call context->AddEventListener otherwise. capture will default to false
+	]]
+
 */
 #include "LuaType.h"
 #include "lua.hpp"

+ 8 - 6
Source/Core/Lua/Element.cpp

@@ -13,10 +13,10 @@ typedef ElementDocument Document;
 int ElementAddEventListener(lua_State* L, Element* obj)
 {
     int top = lua_gettop(L);
-    bool capture;
+    bool capture = false;
     //default false if they didn't pass it in
-    if (top < 3) capture = false;
-    else capture = CHECK_BOOL(L,3);
+    if (top > 3)
+		capture = CHECK_BOOL(L,3);
 
     const char* event = luaL_checkstring(L,1);
 
@@ -24,15 +24,17 @@ int ElementAddEventListener(lua_State* L, Element* obj)
     int type = lua_type(L,2);
     if(type == LUA_TFUNCTION)
     {
-        lua_pushvalue(L,2);
-        int ref = lua_ref(L,true);
-        listener = new LuaEventListener(ref,obj);
+        listener = new LuaEventListener(L,2,obj);
     }
     else if(type == LUA_TSTRING)
     {
         const char* code = luaL_checkstring(L,2);
         listener = new LuaEventListener(code,obj);
     }
+	else
+	{
+		Log::Message(Log::LT_WARNING, "Lua Context:AddEventLisener's 2nd argument can only be a Lua function or a string, you passed in a %s", lua_typename(L,type));
+	}
 
     if(listener != NULL)
     {

+ 7 - 1
Source/Core/Lua/Interpreter.cpp

@@ -163,7 +163,8 @@ void Interpreter::OnInitialise()
 
 void Interpreter::OnShutdown()
 {
-    lua_close(_L);
+	//causing crashes
+    //lua_close(_L);
 }
 
 void Interpreter::Initialise()
@@ -171,6 +172,11 @@ void Interpreter::Initialise()
     Rocket::Core::RegisterPlugin(new Interpreter());
 }
 
+void Interpreter::Shutdown()
+{
+	lua_close(_L);
+}
+
 }
 }
 }

+ 1 - 0
Source/Core/Lua/Interpreter.h

@@ -26,6 +26,7 @@ public:
     static lua_State* GetLuaState();
 
     static void Initialise();
+	static void Shutdown();
     
     //From Plugin
     virtual int GetEventClasses();

+ 27 - 15
Source/Core/Lua/LuaEventListener.cpp

@@ -35,16 +35,32 @@ LuaEventListener::LuaEventListener(const String& code, Element* element) : Event
     lua_pop(L,1); //pop the EVENTLISTENERFUNCTIONS table
 
     attached = element;
-    parent = element->GetOwnerDocument();
+	if(element)
+		parent = element->GetOwnerDocument();
+	else
+		parent = NULL;
     strFunc = function;
 }
 
-//if it is created from a Lua Element
-LuaEventListener::LuaEventListener(int ref, Element* element)
+//if it is passed in a Lua function
+LuaEventListener::LuaEventListener(lua_State* L, int narg, Element* element)
 {
-    luaFuncRef = ref;
-    attached = element;
-    parent = element->GetOwnerDocument();
+    lua_getglobal(L,"EVENTLISTENERFUNCTIONS");
+	if(lua_isnoneornil(L,-1))
+	{
+		lua_newtable(L);
+		lua_setglobal(L,"EVENTLISTENERFUNCTIONS");
+		lua_pop(L,1); //pop the unsucessful getglobal
+		lua_getglobal(L,"EVENTLISTENERFUNCTIONS");
+	}
+	lua_pushvalue(L,narg);
+	luaFuncRef = luaL_ref(L,-2); //put the funtion as a ref in to that table
+	lua_pop(L,1); //pop the EVENTLISTENERFUNCTIONS table
+	attached = element;
+	if(element)
+		parent = element->GetOwnerDocument();
+	else
+		parent = NULL;
 }
 
 LuaEventListener::~LuaEventListener()
@@ -61,19 +77,15 @@ void LuaEventListener::ProcessEvent(Event& event)
     //not sure if this is the right place to do this, but if the element we are attached to isn't a document, then
     //the 'parent' variable will be NULL, because element->ower_document hasn't been set on the construction. We should
     //correct that
-    if(!parent) parent = attached->GetOwnerDocument();
+    if(!parent && attached) parent = attached->GetOwnerDocument();
     lua_State* L = Interpreter::GetLuaState();
-    String strtype;
     int top = lua_gettop(L); 
     //push the arguments
     lua_getglobal(L,"EVENTLISTENERFUNCTIONS");
-    int table = lua_gettop(L); //needed for lua_remove
-    strtype = lua_typename(L,lua_type(L,table));
-    lua_rawgeti(L,table,luaFuncRef);
-    strtype = lua_typename(L,lua_type(L,-1));
-    strtype = lua_typename(L,lua_type(L,LuaType<Event>::push(L,&event,false)));
-    strtype = lua_typename(L,lua_type(L,LuaType<Element>::push(L,attached,false)));
-    strtype = lua_typename(L,lua_type(L,LuaType<Document>::push(L,parent,false)));
+    lua_rawgeti(L,-1,luaFuncRef);
+    LuaType<Event>::push(L,&event,false);
+	LuaType<Element>::push(L,attached,false);
+    LuaType<Document>::push(L,parent,false);
     
     Interpreter::ExecuteCall(3,0); //call the function at the top of the stack with 3 arguments
 

+ 2 - 1
Source/Core/Lua/LuaEventListener.h

@@ -17,7 +17,8 @@ public:
     //This is called from a Lua Element if in element:AddEventListener it passes a function in as the 2nd
     //parameter rather than a string. We don't wrap the function in an anonymous function, so the user
     //should take care to have the proper order. The order is event,element,document.
-    LuaEventListener(int ref, Element* element);
+	//narg is the position on the stack
+    LuaEventListener(lua_State* L, int narg, Element* element);
 
     virtual ~LuaEventListener();
 

+ 1 - 1
Source/Core/Lua/LuaTypeTemplateSpec.inl

@@ -293,7 +293,7 @@ template<> void LuaType<Log>::extra_init(lua_State* L, int metatable_index)
     int method_index = metatable_index - 1;
 
     lua_pushcfunction(L,LogMessage);
-    lua_setfield(L,metatable_index, "Message");
+    lua_setfield(L,method_index, "Message");
 
     //construct the "logtype" table, so that we can use the Rocket::Core::Log::Type enum like Log.logtype.always in Lua for Log::LT_ALWAYS
     lua_newtable(L);