mirror of
https://github.com/edubart/otclient.git
synced 2025-10-19 05:53:26 +02:00
onLoad and onDestroy events
This commit is contained in:
@@ -33,9 +33,8 @@ void UIButton::onInputEvent(const InputEvent& event)
|
||||
} else if(event.type == EV_MOUSE_LUP && m_state == UI::ButtonDown) {
|
||||
m_state = UI::ButtonUp;
|
||||
if(getRect().contains(event.mousePos)) {
|
||||
if(m_onClickCallback) {
|
||||
g_dispatcher.addTask(boost::bind(m_onClickCallback, boost::static_pointer_cast<UIButton>(shared_from_this())));
|
||||
}
|
||||
if(m_onClickCallback)
|
||||
g_dispatcher.addTask(boost::bind(m_onClickCallback, asUIElement()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,8 +34,6 @@ typedef boost::shared_ptr<UIButton> UIButtonPtr;
|
||||
|
||||
class UIButton : public UIElement
|
||||
{
|
||||
typedef boost::function<void(UIButtonPtr)> OnClick;
|
||||
|
||||
public:
|
||||
UIButton() :
|
||||
UIElement(UI::Button),
|
||||
@@ -48,14 +46,14 @@ public:
|
||||
|
||||
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"; }
|
||||
|
||||
private:
|
||||
std::string m_text;
|
||||
UI::EButtonState m_state;
|
||||
OnClick m_onClickCallback;
|
||||
UIElementCallback m_onClickCallback;
|
||||
};
|
||||
|
||||
#endif // UIBUTTON_H
|
||||
|
@@ -27,10 +27,27 @@
|
||||
#include <ui/uicontainer.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()
|
||||
{
|
||||
static UIContainerPtr rootContainer;
|
||||
if(!rootContainer) {
|
||||
rootContainer = UIContainerPtr(new UIContainer);
|
||||
rootContainer->setId("root");
|
||||
}
|
||||
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()
|
||||
{
|
||||
UIElement::render();
|
||||
|
@@ -35,6 +35,7 @@ public:
|
||||
UIElement(type) { }
|
||||
virtual ~UIContainer() { }
|
||||
|
||||
virtual void onLoad();
|
||||
virtual void render();
|
||||
virtual void onInputEvent(const InputEvent& event);
|
||||
|
||||
@@ -73,6 +74,9 @@ public:
|
||||
/// Get root container (the container that contains everything)
|
||||
static UIContainerPtr& getRootContainer();
|
||||
|
||||
protected:
|
||||
virtual void internalOnDestroy();
|
||||
|
||||
private:
|
||||
std::list<UIElementPtr> m_children;
|
||||
UIElementPtr m_focusedElement;
|
||||
|
@@ -42,20 +42,20 @@ UIElement::UIElement(UI::EElementType type) :
|
||||
|
||||
void UIElement::destroy()
|
||||
{
|
||||
setVisible(false);
|
||||
setEnabled(false);
|
||||
|
||||
g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIElement()));
|
||||
if(m_onDestroyCallback)
|
||||
g_dispatcher.addTask(boost::bind(m_onDestroyCallback, asUIElement()));
|
||||
if(getParent()) {
|
||||
// schedule removal from parent
|
||||
g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIElement()));
|
||||
}
|
||||
// schedule internal destroy (used to check for leaks)
|
||||
g_dispatcher.addTask(boost::bind(&UIElement::internalDestroy, asUIElement()));
|
||||
// schedule internal destroy
|
||||
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
|
||||
assert(asUIElement().use_count() == 2);
|
||||
}
|
||||
@@ -67,6 +67,12 @@ void UIElement::setSkin(const UIElementSkinPtr& skin)
|
||||
skin->apply(this);
|
||||
}
|
||||
|
||||
void UIElement::onLoad()
|
||||
{
|
||||
if(m_onLoadCallback)
|
||||
g_dispatcher.addTask(boost::bind(m_onLoadCallback, asUIElement()));
|
||||
}
|
||||
|
||||
void UIElement::render()
|
||||
{
|
||||
if(m_skin)
|
||||
|
@@ -41,6 +41,8 @@ class UIElement;
|
||||
typedef boost::shared_ptr<UIElement> UIElementPtr;
|
||||
typedef boost::weak_ptr<UIElement> UIElementWeakPtr;
|
||||
|
||||
typedef boost::function<void(UIElementPtr)> UIElementCallback;
|
||||
|
||||
class UIElement : public UILayout
|
||||
{
|
||||
public:
|
||||
@@ -54,6 +56,7 @@ public:
|
||||
virtual void render();
|
||||
|
||||
// events
|
||||
virtual void onLoad();
|
||||
virtual void onInputEvent(const InputEvent& event) { }
|
||||
virtual void onFocusChange() { }
|
||||
|
||||
@@ -86,11 +89,13 @@ public:
|
||||
virtual UIContainerPtr asUIContainer() { return UIContainerPtr(); }
|
||||
virtual const char *getScriptableName() const { return "UIElement"; }
|
||||
|
||||
void setOnDestroy(
|
||||
friend class UIContainer;
|
||||
void setOnDestroy(const UIElementCallback& onDestroyCallback) { m_onDestroyCallback = onDestroyCallback; }
|
||||
void setOnLoad(const UIElementCallback& onLoadCallback) { m_onLoadCallback = onLoadCallback; }
|
||||
|
||||
protected:
|
||||
virtual void internalOnDestroy();
|
||||
|
||||
private:
|
||||
void internalDestroy();
|
||||
|
||||
UI::EElementType m_type;
|
||||
UIContainerWeakPtr m_parent;
|
||||
@@ -99,6 +104,8 @@ private:
|
||||
bool m_visible;
|
||||
bool m_enabled;
|
||||
bool m_focused;
|
||||
UIElementCallback m_onLoadCallback;
|
||||
UIElementCallback m_onDestroyCallback;
|
||||
};
|
||||
|
||||
#endif // UIELEMENT_H
|
||||
|
@@ -99,6 +99,8 @@ UIElementPtr UILoader::loadFile(const std::string& file, const UIContainerPtr& p
|
||||
// now do the real load
|
||||
loadElements(element, doc.begin().second());
|
||||
|
||||
// report onLoad events
|
||||
element->onLoad();
|
||||
return element;
|
||||
} catch (YAML::Exception& e) {
|
||||
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"))
|
||||
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)
|
||||
|
Reference in New Issue
Block a user