mirror of
https://github.com/edubart/otclient.git
synced 2025-10-19 05:53:26 +02:00
remove game state classes
scripting improvements
This commit is contained in:
@@ -33,8 +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_buttonClickCallback) {
|
||||
g_dispatcher.addTask(m_buttonClickCallback);
|
||||
if(m_onClickCallback) {
|
||||
g_dispatcher.addTask(boost::bind(m_onClickCallback, boost::static_pointer_cast<UIButton>(shared_from_this())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,8 +29,13 @@
|
||||
#include <ui/uielement.h>
|
||||
#include <graphics/borderedimage.h>
|
||||
|
||||
class UIButton;
|
||||
typedef boost::shared_ptr<UIButton> UIButtonPtr;
|
||||
|
||||
class UIButton : public UIElement
|
||||
{
|
||||
typedef boost::function<void(UIButtonPtr)> OnClick;
|
||||
|
||||
public:
|
||||
UIButton() :
|
||||
UIElement(UI::Button),
|
||||
@@ -43,16 +48,14 @@ public:
|
||||
|
||||
UI::EButtonState getState() { return m_state; }
|
||||
|
||||
void setOnClick(const Callback& callback) { m_buttonClickCallback = callback; }
|
||||
void setOnClick(const OnClick& callback) { m_onClickCallback = callback; }
|
||||
|
||||
virtual const char *getScriptableName() const { return "UIButton"; }
|
||||
|
||||
private:
|
||||
std::string m_text;
|
||||
UI::EButtonState m_state;
|
||||
Callback m_buttonClickCallback;
|
||||
OnClick m_onClickCallback;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<UIButton> UIButtonPtr;
|
||||
|
||||
#endif // UIBUTTON_H
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <prerequisites.h>
|
||||
#include <core/resources.h>
|
||||
#include <ui/uicontainer.h>
|
||||
#include <core/dispatcher.h>
|
||||
|
||||
UIContainerPtr rootContainer(new UIContainer);
|
||||
|
||||
@@ -71,6 +72,15 @@ UIElementPtr UIContainer::getChildById(const std::string& id)
|
||||
return UIElementPtr();
|
||||
}
|
||||
|
||||
UIElementPtr UIContainer::getChildByPos(const Point& pos)
|
||||
{
|
||||
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
||||
if((*it)->getRect().contains(pos))
|
||||
return (*it);
|
||||
}
|
||||
return UIElementPtr();
|
||||
}
|
||||
|
||||
UIElementPtr UIContainer::recursiveGetChildById(const std::string& id)
|
||||
{
|
||||
if(getId() == id)
|
||||
@@ -93,6 +103,21 @@ UIElementPtr UIContainer::recursiveGetChildById(const std::string& id)
|
||||
return UIElementPtr();
|
||||
}
|
||||
|
||||
void UIContainer::pushChildToTop(const UIElementPtr& child)
|
||||
{
|
||||
bool removed = false;
|
||||
for(auto it = m_children.begin(); it != m_children.end(); ++it) {
|
||||
if((*it) == child) {
|
||||
removed = true;
|
||||
m_children.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(removed) {
|
||||
m_children.push_back(child);
|
||||
}
|
||||
}
|
||||
|
||||
void UIContainer::render()
|
||||
{
|
||||
UIElement::render();
|
||||
@@ -119,9 +144,10 @@ void UIContainer::onInputEvent(const InputEvent& event)
|
||||
}
|
||||
// mouse events
|
||||
} else if(event.type & EV_MOUSE) {
|
||||
// mouse down and wheel events only go to elements that contains the mouse position and are not containers
|
||||
if((event.type & EV_DOWN || event.type & EV_MOUSE_WHEEL) && !child->asUIContainer()) {
|
||||
if(child->getRect().contains(event.mousePos)) {
|
||||
// mouse down and wheel events only go to elements that contains the mouse position
|
||||
if(event.type & EV_DOWN || event.type & EV_MOUSE_WHEEL) {
|
||||
// the child must contains the mouse position and be on top
|
||||
if(child->getRect().contains(event.mousePos) && child == getChildByPos(event.mousePos)) {
|
||||
// focus it
|
||||
if(event.type == EV_MOUSE_LDOWN && child->isFocusable())
|
||||
setFocusedElement(child);
|
||||
@@ -171,9 +197,17 @@ void UIContainer::setFocusedElement(UIElementPtr focusedElement)
|
||||
m_focusedElement->setFocused(false);
|
||||
m_focusedElement->onFocusChange();
|
||||
}
|
||||
|
||||
m_focusedElement = focusedElement;
|
||||
m_focusedElement->setFocused(true);
|
||||
m_focusedElement->onFocusChange();
|
||||
if(m_focusedElement) {
|
||||
m_focusedElement->setFocused(true);
|
||||
m_focusedElement->onFocusChange();
|
||||
}
|
||||
}
|
||||
|
||||
// when containers are focused they go to the top
|
||||
if(focusedElement && focusedElement->asUIContainer()) {
|
||||
g_dispatcher.addTask(boost::bind(&UIContainer::pushChildToTop, asUIContainer(), m_focusedElement));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -44,8 +44,14 @@ public:
|
||||
void removeChild(UIElementPtr child);
|
||||
/// Find an element in this container by id
|
||||
UIElementPtr getChildById(const std::string& id);
|
||||
/// Find an element by position
|
||||
UIElementPtr getChildByPos(const Point& pos);
|
||||
/// Find an element in this container and in its children by id
|
||||
UIElementPtr recursiveGetChildById(const std::string& id);
|
||||
/// Pushs a child to the top
|
||||
void pushChildToTop(const UIElementPtr& child);
|
||||
|
||||
int getChildCount() const { return m_children.size(); }
|
||||
|
||||
/// Disable all children except the specified element
|
||||
bool lockElement(UIElementPtr element);
|
||||
|
@@ -42,12 +42,21 @@ UIElement::UIElement(UI::EElementType type) :
|
||||
|
||||
void UIElement::destroy()
|
||||
{
|
||||
// we must always have a parent when destroying
|
||||
assert(getParent());
|
||||
// we cant delete now, as this call maybe in a event loop
|
||||
g_dispatcher.addTask(boost::bind(&UIContainer::removeChild, getParent(), asUIContainer()));
|
||||
// shared ptr must have 4 refs, (this + removeChild callback + parent + use_count call)
|
||||
assert(asUIElement().use_count() == 4);
|
||||
setVisible(false);
|
||||
setEnabled(false);
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
void UIElement::internalDestroy()
|
||||
{
|
||||
// check for leaks, the number of references must be always 2 here
|
||||
assert(asUIElement().use_count() == 2);
|
||||
}
|
||||
|
||||
void UIElement::setSkin(const UIElementSkinPtr& skin)
|
||||
|
@@ -89,6 +89,8 @@ public:
|
||||
friend class UIContainer;
|
||||
|
||||
private:
|
||||
void internalDestroy();
|
||||
|
||||
UI::EElementType m_type;
|
||||
UIContainerWeakPtr m_parent;
|
||||
UIElementSkinPtr m_skin;
|
||||
|
@@ -50,6 +50,8 @@ void UIElementSkin::draw(UIElement *element)
|
||||
ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
|
||||
{
|
||||
ImagePtr image;
|
||||
TexturePtr texture;
|
||||
|
||||
if(node.FindValue("bordered image")) {
|
||||
const YAML::Node& child = node["bordered image"];
|
||||
Rect left, right, top, bottom, topLeft, topRight, bottomLeft, bottomRight, center;
|
||||
@@ -72,7 +74,6 @@ ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
|
||||
if(child.FindValue("center"))
|
||||
child["center"] >> center;
|
||||
|
||||
TexturePtr texture;
|
||||
if(child.FindValue("image")) {
|
||||
std::string textureName;
|
||||
child["image"] >> textureName;
|
||||
@@ -81,17 +82,34 @@ ImagePtr UIElementSkin::loadImage(const YAML::Node& node)
|
||||
texture = g_uiSkins.getDefaultTexture();
|
||||
}
|
||||
|
||||
image = ImagePtr(new BorderedImage(texture,
|
||||
left,
|
||||
right,
|
||||
top,
|
||||
bottom,
|
||||
topLeft,
|
||||
topRight,
|
||||
bottomLeft,
|
||||
bottomRight,
|
||||
center));
|
||||
if(texture) {
|
||||
image = ImagePtr(new BorderedImage(texture,
|
||||
left,
|
||||
right,
|
||||
top,
|
||||
bottom,
|
||||
topLeft,
|
||||
topRight,
|
||||
bottomLeft,
|
||||
bottomRight,
|
||||
center));
|
||||
}
|
||||
} else if(node.FindValue("image")) {
|
||||
std::string textureName;
|
||||
node["image"] >> textureName;
|
||||
texture = g_textures.get(textureName);
|
||||
if(texture) {
|
||||
image = ImagePtr(new Image(texture));
|
||||
}
|
||||
}
|
||||
|
||||
if(texture && node.FindValue("antialised")){
|
||||
bool antialised;
|
||||
node["antialised"] >> antialised;
|
||||
if(antialised)
|
||||
texture->enableBilinearFilter();
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,7 @@ public:
|
||||
UIElementSkin(const std::string& name, UI::EElementType elementType) :
|
||||
m_name(name),
|
||||
m_elementType(elementType) { }
|
||||
UIElementSkin() : m_elementType(UI::Element) { }
|
||||
virtual ~UIElementSkin() { }
|
||||
|
||||
/// Load the skin from a YAML node
|
||||
|
@@ -133,8 +133,8 @@ void UILayout::recalculateLayout()
|
||||
m_rect.moveVerticalCenter(m_anchors[ANCHOR_VERTICAL_CENTER].getPos() + m_marginTop - m_marginBottom);
|
||||
} else {
|
||||
if(m_anchors[ANCHOR_TOP].isValid() && m_anchors[ANCHOR_BOTTOM].isValid()) {
|
||||
m_rect.setLeft(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
|
||||
m_rect.setRight(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom);
|
||||
m_rect.setTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
|
||||
m_rect.setBottom(m_anchors[ANCHOR_BOTTOM].getPos() - m_marginBottom);
|
||||
} else if(m_anchors[ANCHOR_TOP].isValid()) {
|
||||
m_rect.moveTop(m_anchors[ANCHOR_TOP].getPos() + m_marginTop);
|
||||
} else if(m_anchors[ANCHOR_BOTTOM].isValid()) {
|
||||
|
@@ -67,7 +67,7 @@ UIElementPtr UILoader::loadFile(const std::string& file, const UIContainerPtr& p
|
||||
{
|
||||
std::string fileContents = g_resources.loadTextFile(file);
|
||||
if(!fileContents.size()) {
|
||||
logFatal("Could not load ui file \"%s", file.c_str());
|
||||
logError("Could not load ui file \"%s", file.c_str());
|
||||
return UIElementPtr();
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ UIElementPtr UILoader::loadFile(const std::string& file, const UIContainerPtr& p
|
||||
|
||||
return element;
|
||||
} catch (YAML::Exception& e) {
|
||||
logFatal("Failed to load ui file \"%s\":\n %s", file.c_str(), e.what());
|
||||
logError("Failed to load ui file \"%s\":\n %s", file.c_str(), e.what());
|
||||
}
|
||||
|
||||
return UIElementPtr();
|
||||
@@ -168,9 +168,15 @@ void UILoader::loadElement(const UIElementPtr& element, const YAML::Node& node)
|
||||
}
|
||||
|
||||
// set element skin
|
||||
if(node.FindValue("skin"))
|
||||
element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), node["skin"]));
|
||||
else // apply default skin
|
||||
if(node.FindValue("skin")) {
|
||||
if(node["skin"].GetType() == YAML::CT_SCALAR) {
|
||||
element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), node["skin"]));
|
||||
} else {
|
||||
UIElementSkinPtr skin = UIElementSkinPtr(new UIElementSkin());
|
||||
skin->load(node["skin"]);
|
||||
element->setSkin(skin);
|
||||
}
|
||||
} else // apply default skin
|
||||
element->setSkin(g_uiSkins.getElementSkin(element->getElementType(), "default"));
|
||||
|
||||
// load elements common proprieties
|
||||
@@ -252,6 +258,8 @@ void UILoader::loadElementAnchor(const UIElementPtr& element, EAnchorType type,
|
||||
UILayoutPtr relativeElement;
|
||||
if(relativeElementId == "parent" && element->getParent()) {
|
||||
relativeElement = element->getParent()->asUILayout();
|
||||
} else if(relativeElementId == "root") {
|
||||
relativeElement = UIContainer::getRootContainer();
|
||||
} else {
|
||||
UIElementPtr tmp = element->backwardsGetElementById(relativeElementId);
|
||||
if(tmp)
|
||||
@@ -277,6 +285,8 @@ void UILoader::loadButton(const UIButtonPtr& button, const YAML::Node& node)
|
||||
g_lua.pushClassInstance(button);
|
||||
g_lua.pushFunction(funcRef);
|
||||
g_lua.lua_UIButton_setOnClick();
|
||||
} else {
|
||||
throw YAML::Exception(node["onClick"].GetMark(), "failed to parse lua script");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -42,6 +42,8 @@ public:
|
||||
|
||||
virtual const char *getScriptableName() const { return "UIWindow"; }
|
||||
|
||||
virtual bool isFocusable() const { return true; }
|
||||
|
||||
private:
|
||||
std::string m_title;
|
||||
bool m_moving;
|
||||
|
Reference in New Issue
Block a user