onLoad and onDestroy events

This commit is contained in:
Eduardo Bart 2011-04-23 00:28:23 -03:00
parent 02ada0b82e
commit a98f1d67db
16 changed files with 210 additions and 31 deletions

View File

@ -3,8 +3,8 @@ window#enterGameWindow:
size: [236, 178] size: [236, 178]
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
onLoad: mainMenu:lock(self) onLoad: self:getParent():lock(self)
onDestroy: mainMenu:unlock() onDestroy: self:getParent():unlock()
label#accountNameLabel: label#accountNameLabel:
text: Account name text: Account name

View File

@ -3,8 +3,8 @@ window#infoWindow:
size: [244, 221] size: [244, 221]
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
onLoad: mainMenu:lock(self) onLoad: self:getParent():lock(self)
onDestroy: mainMenu:unlock() onDestroy: self:getParent():unlock()
panel#infoPanel: panel#infoPanel:
skin: flatPanel skin: flatPanel
@ -60,3 +60,4 @@ window#infoWindow:
anchors.top: parent.top anchors.top: parent.top
margin.top: 191 margin.top: 191
margin.left: 188 margin.left: 188
onClick: self:getParent():destroy()

View File

@ -3,8 +3,8 @@ window#optionsWindow:
size: [286, 262] size: [286, 262]
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
onLoad: mainMenu:lock(self) onLoad: self:getParent():lock(self)
onDestroy: mainMenu:unlock() onDestroy: self:getParent():unlock()
# general # general
button#generalButton: button#generalButton:

View File

@ -34,10 +34,10 @@ void Dispatcher::poll()
Task *task = m_taskList.top(); Task *task = m_taskList.top();
if(g_engine.getCurrentFrameTicks() < task->ticks) if(g_engine.getCurrentFrameTicks() < task->ticks)
break; break;
m_taskList.pop();
task->callback(); task->callback();
delete task; delete task;
m_taskList.pop();
} }
} }
@ -50,3 +50,41 @@ void Dispatcher::addTask(const SimpleCallback& callback)
{ {
m_taskList.push(new Task(callback)); m_taskList.push(new Task(callback));
} }
/*
* #include <prerequisites.h>
#include <core/dispatcher.h>
#include <core/engine.h>
#include <stack>
Dispatcher g_dispatcher;
void Dispatcher::poll()
{
if(!m_taskList.empty()) {
auto it = m_taskList.begin();
m_taskList.erase(it);
(*it)();
}
while(!m_scheduledTaskList.empty()) {
ScheduledTask *task = m_scheduledTaskList.top();
if(g_engine.getCurrentFrameTicks() < task->ticks)
break;
m_scheduledTaskList.pop();
task->callback();
delete task;
}
}
void Dispatcher::scheduleTask(const SimpleCallback& callback, int delay)
{
m_scheduledTaskList.push(new ScheduledTask(g_engine.getCurrentFrameTicks() + delay, callback));
}
void Dispatcher::addTask(const SimpleCallback& callback)
{
m_taskList.push_back(callback);
}
*/

View File

@ -61,4 +61,39 @@ private:
extern Dispatcher g_dispatcher; extern Dispatcher g_dispatcher;
/*
* class ScheduledTask {
public:
inline ScheduledTask(const SimpleCallback& _callback) : ticks(0), callback(_callback) { }
inline ScheduledTask(int _ticks, const SimpleCallback& _callback) : ticks(_ticks), callback(_callback) { }
inline bool operator<(const ScheduledTask& other) const { return ticks > other.ticks; }
int ticks;
SimpleCallback callback;
};
class lessScheduledTask : public std::binary_function<ScheduledTask*&, ScheduledTask*&, bool> {
public:
bool operator()(ScheduledTask*& t1,ScheduledTask*& t2) { return (*t1) < (*t2); }
};
class Dispatcher
{
public:
Dispatcher() { }
/// Execute scheduled events
void poll();
/// Add an event
void addTask(const SimpleCallback& callback);
/// Schedula an event
void scheduleTask(const SimpleCallback& callback, int delay);
private:
std::vector<SimpleCallback> m_taskList;
std::priority_queue<ScheduledTask*, std::vector<ScheduledTask*>, lessScheduledTask> m_scheduledTaskList;
};
extern Dispatcher g_dispatcher;*/
#endif // DISPATCHER_H #endif // DISPATCHER_H

View File

@ -52,11 +52,11 @@ void Engine::poll()
// poll platform events // poll platform events
Platform::poll(); Platform::poll();
// poll network events
Connection::poll();
// poll diaptcher tasks // poll diaptcher tasks
g_dispatcher.poll(); g_dispatcher.poll();
// poll network events
Connection::poll();
} }
void Engine::run() void Engine::run()

View File

@ -43,6 +43,8 @@ void LuaScript::registerFunctions()
registerClass("UIContainer", "UIElement"); registerClass("UIContainer", "UIElement");
registerClass("UIWindow", "UIContainer"); registerClass("UIWindow", "UIContainer");
registerMemberFunction("UIElement", "setOnLoad", &LuaScript::lua_UIElement_setOnLoad);
registerMemberFunction("UIElement", "setOnDestroy", &LuaScript::lua_UIElement_setOnDestroy);
registerMemberFunction("UIElement", "getParent", &LuaScript::lua_UIElement_getParent); registerMemberFunction("UIElement", "getParent", &LuaScript::lua_UIElement_getParent);
registerMemberFunction("UIElement", "destroy", &LuaScript::lua_UIElement_destroy); registerMemberFunction("UIElement", "destroy", &LuaScript::lua_UIElement_destroy);
registerMemberFunction("UIContainer", "getChildByID", &LuaScript::lua_UIContainer_getChildByID); registerMemberFunction("UIContainer", "getChildByID", &LuaScript::lua_UIContainer_getChildByID);
@ -95,6 +97,40 @@ int LuaScript::lua_setOnApplicationClose()
return 1; return 1;
} }
int LuaScript::lua_UIElement_setOnLoad()
{
moveTop(-2);
UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(popClassInstance());
if(element) {
int funcRef = popFunction();
element->setOnLoad([this, funcRef](UIElementPtr element) {
pushFunction(funcRef);
setLocal(element, "self");
callFunction();
});
} else {
pop();
}
return 1;
}
int LuaScript::lua_UIElement_setOnDestroy()
{
moveTop(-2);
UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(popClassInstance());
if(element) {
int funcRef = popFunction();
element->setOnDestroy([this, funcRef](UIElementPtr element) {
pushFunction(funcRef);
setLocal(element, "self");
callFunction();
});
} else {
pop();
}
return 1;
}
int LuaScript::lua_UIElement_destroy() int LuaScript::lua_UIElement_destroy()
{ {
UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(popClassInstance()); UIElementPtr element = boost::dynamic_pointer_cast<UIElement>(popClassInstance());
@ -121,7 +157,7 @@ int LuaScript::lua_UIButton_setOnClick()
UIButtonPtr button = boost::dynamic_pointer_cast<UIButton>(popClassInstance()); UIButtonPtr button = boost::dynamic_pointer_cast<UIButton>(popClassInstance());
if(button) { if(button) {
int funcRef = popFunction(); int funcRef = popFunction();
button->setOnClick([this, funcRef](UIButtonPtr button) { button->setOnClick([this, funcRef](UIElementPtr button) {
pushFunction(funcRef); pushFunction(funcRef);
setLocal(button, "self"); setLocal(button, "self");
callFunction(); callFunction();

View File

@ -84,10 +84,13 @@ public:
void registerFunctions(); void registerFunctions();
int lua_UIButton_setOnClick(); int lua_UIElement_setOnLoad();
int lua_UIElement_setOnDestroy();
int lua_UIElement_getParent(); int lua_UIElement_getParent();
int lua_UIElement_destroy(); int lua_UIElement_destroy();
int lua_UIButton_setOnClick();
// container functions // container functions
int lua_UIContainer_getChildByID(); int lua_UIContainer_getChildByID();
int lua_UIContainer_lock(); int lua_UIContainer_lock();

View File

@ -33,9 +33,8 @@ void UIButton::onInputEvent(const InputEvent& event)
} else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) { } else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) {
m_state = UI::ButtonUp; m_state = UI::ButtonUp;
if(getRect().contains(event.mousePos)) { if(getRect().contains(event.mousePos)) {
if(m_onClickCallback) { if(m_onClickCallback)
g_dispatcher.addTask(boost::bind(m_onClickCallback, boost::static_pointer_cast<UIButton>(shared_from_this()))); g_dispatcher.addTask(boost::bind(m_onClickCallback, asUIElement()));
}
} }
} }
} }

View File

@ -34,8 +34,6 @@ typedef boost::shared_ptr<UIButton> UIButtonPtr;
class UIButton : public UIElement class UIButton : public UIElement
{ {
typedef boost::function<void(UIButtonPtr)> OnClick;
public: public:
UIButton() : UIButton() :
UIElement(UI::Button), UIElement(UI::Button),
@ -48,14 +46,14 @@ public:
UI::EButtonState getState() { return m_state; } UI::EButtonState getState() { return m_state; }
void setOnClick(const OnClick& callback) { m_onClickCallback = callback; } void setOnClick(const UIElementCallback& callback) { m_onClickCallback = callback; }
virtual const char *getScriptableName() const { return "UIButton"; } virtual const char *getScriptableName() const { return "UIButton"; }
private: private:
std::string m_text; std::string m_text;
UI::EButtonState m_state; UI::EButtonState m_state;
OnClick m_onClickCallback; UIElementCallback m_onClickCallback;
}; };
#endif // UIBUTTON_H #endif // UIBUTTON_H

View File

@ -27,10 +27,27 @@
#include <ui/uicontainer.h> #include <ui/uicontainer.h>
#include <core/dispatcher.h> #include <core/dispatcher.h>
UIContainerPtr rootContainer(new UIContainer); void UIContainer::internalOnDestroy()
{
// destroy children
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
(*it)->setParent(UIContainerPtr());
(*it)->destroy();
}
m_children.clear();
// root container must not call internalDestroy
if(asUIContainer() != getRootContainer())
UIElement::internalOnDestroy();
}
UIContainerPtr& UIContainer::getRootContainer() UIContainerPtr& UIContainer::getRootContainer()
{ {
static UIContainerPtr rootContainer;
if(!rootContainer) {
rootContainer = UIContainerPtr(new UIContainer);
rootContainer->setId("root");
}
return rootContainer; return rootContainer;
} }
@ -118,6 +135,13 @@ void UIContainer::pushChildToTop(const UIElementPtr& child)
} }
} }
void UIContainer::onLoad()
{
for(auto it = m_children.begin(); it != m_children.end(); ++it)
(*it)->onLoad();
UIElement::onLoad();
}
void UIContainer::render() void UIContainer::render()
{ {
UIElement::render(); UIElement::render();

View File

@ -35,6 +35,7 @@ public:
UIElement(type) { } UIElement(type) { }
virtual ~UIContainer() { } virtual ~UIContainer() { }
virtual void onLoad();
virtual void render(); virtual void render();
virtual void onInputEvent(const InputEvent& event); virtual void onInputEvent(const InputEvent& event);
@ -73,6 +74,9 @@ public:
/// Get root container (the container that contains everything) /// Get root container (the container that contains everything)
static UIContainerPtr& getRootContainer(); static UIContainerPtr& getRootContainer();
protected:
virtual void internalOnDestroy();
private: private:
std::list<UIElementPtr> m_children; std::list<UIElementPtr> m_children;
UIElementPtr m_focusedElement; UIElementPtr m_focusedElement;

View File

@ -42,20 +42,20 @@ UIElement::UIElement(UI::EElementType type) :
void UIElement::destroy() void UIElement::destroy()
{ {
setVisible(false); if(m_onDestroyCallback)
setEnabled(false); g_dispatcher.addTask(boost::bind(m_onDestroyCallback, asUIElement()));
g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIElement()));
if(getParent()) { if(getParent()) {
// schedule removal from parent // schedule removal from parent
g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIElement())); g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIElement()));
} }
// schedule internal destroy (used to check for leaks) // schedule internal destroy
g_dispatcher.addTask(boost::bind(&UIElement::internalDestroy, asUIElement())); g_dispatcher.addTask(boost::bind(&UIElement::internalOnDestroy, asUIElement()));
} }
void UIElement::internalDestroy() void UIElement::internalOnDestroy()
{ {
setVisible(false);
setEnabled(false);
// check for leaks, the number of references must be always 2 here // check for leaks, the number of references must be always 2 here
assert(asUIElement().use_count() == 2); assert(asUIElement().use_count() == 2);
} }
@ -67,6 +67,12 @@ void UIElement::setSkin(const UIElementSkinPtr& skin)
skin->apply(this); skin->apply(this);
} }
void UIElement::onLoad()
{
if(m_onLoadCallback)
g_dispatcher.addTask(boost::bind(m_onLoadCallback, asUIElement()));
}
void UIElement::render() void UIElement::render()
{ {
if(m_skin) if(m_skin)

View File

@ -41,6 +41,8 @@ class UIElement;
typedef boost::shared_ptr<UIElement> UIElementPtr; typedef boost::shared_ptr<UIElement> UIElementPtr;
typedef boost::weak_ptr<UIElement> UIElementWeakPtr; typedef boost::weak_ptr<UIElement> UIElementWeakPtr;
typedef boost::function<void(UIElementPtr)> UIElementCallback;
class UIElement : public UILayout class UIElement : public UILayout
{ {
public: public:
@ -54,6 +56,7 @@ public:
virtual void render(); virtual void render();
// events // events
virtual void onLoad();
virtual void onInputEvent(const InputEvent& event) { } virtual void onInputEvent(const InputEvent& event) { }
virtual void onFocusChange() { } virtual void onFocusChange() { }
@ -86,11 +89,13 @@ public:
virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); } virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); }
virtual const char *getScriptableName() const { return "UIElement"; } virtual const char *getScriptableName() const { return "UIElement"; }
void setOnDestroy( void setOnDestroy(const UIElementCallback& onDestroyCallback) { m_onDestroyCallback = onDestroyCallback; }
friend class UIContainer; void setOnLoad(const UIElementCallback& onLoadCallback) { m_onLoadCallback = onLoadCallback; }
protected:
virtual void internalOnDestroy();
private: private:
void internalDestroy();
UI::EElementType m_type; UI::EElementType m_type;
UIContainerWeakPtr m_parent; UIContainerWeakPtr m_parent;
@ -99,6 +104,8 @@ private:
bool m_visible; bool m_visible;
bool m_enabled; bool m_enabled;
bool m_focused; bool m_focused;
UIElementCallback m_onLoadCallback;
UIElementCallback m_onDestroyCallback;
}; };
#endif // UIELEMENT_H #endif // UIELEMENT_H

View File

@ -99,6 +99,8 @@ UIElementPtr UILoader::loadFile(const std::string& file, const UIContainerPtr& p
// now do the real load // now do the real load
loadElements(element, doc.begin().second()); loadElements(element, doc.begin().second());
// report onLoad events
element->onLoad();
return element; return element;
} catch (YAML::Exception& e) { } catch (YAML::Exception& e) {
flogError("ERROR: Failed to load ui file \"%s\":\n %s", file.c_str() % e.what()); flogError("ERROR: Failed to load ui file \"%s\":\n %s", file.c_str() % e.what());
@ -224,6 +226,29 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
if(node.FindValue("anchors.verticalCenter")) if(node.FindValue("anchors.verticalCenter"))
loadElementAnchor(element, ANCHOR_VERTICAL_CENTER, node["anchors.verticalCenter"]); loadElementAnchor(element, ANCHOR_VERTICAL_CENTER, node["anchors.verticalCenter"]);
// load events
if(node.FindValue("onLoad")) {
const YAML::Node& cnode = node["onLoad"];
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>());
if(funcRef != LUA_REFNIL) {
g_lua.pushClassInstance(element);
g_lua.pushFunction(funcRef);
g_lua.lua_UIElement_setOnLoad();
} else
throw YAML::Exception(cnode.GetMark(), "failed to parse lua script");
}
if(node.FindValue("onDestroy")) {
const YAML::Node& cnode = node["onDestroy"];
int funcRef = g_lua.loadBufferAsFunction(cnode.Read<std::string>());
if(funcRef != LUA_REFNIL) {
g_lua.pushClassInstance(element);
g_lua.pushFunction(funcRef);
g_lua.lua_UIElement_setOnDestroy();
} else
throw YAML::Exception(cnode.GetMark(), "failed to parse lua script");
}
} }
void UILoader::loadElementAnchor(const UIElementPtr& element, EAnchorType type, const YAML::Node& node) void UILoader::loadElementAnchor(const UIElementPtr& element, EAnchorType type, const YAML::Node& node)

View File

@ -129,6 +129,9 @@ int main(int argc, const char *argv[])
// main loop, run everything // main loop, run everything
g_engine.run(); g_engine.run();
// destroy root ui
UIContainer::getRootContainer()->destroy();
// poll remaning events // poll remaning events
g_engine.poll(); g_engine.poll();