diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md index 6a739d168..c238d24f6 100644 --- a/doc/en/xml-ui-layouts.md +++ b/doc/en/xml-ui-layouts.md @@ -42,8 +42,11 @@ Examples: - `ondoubleclick` - lua function called when you double click on an element. - `onfocus` - lua function called when focusing on an element. - `ondefocus` - lua function called when the element loses focus. -- `onmouseover` - lua function called when the cursor enters an element. -- `onmouseover` - lua function called when the cursor exits an element. +- `onmouseenter` - lua function called when the cursor enters an element. +- `onmouseleave` - lua function called when the cursor leaves an element. +- `onmouseover` - lua function called when the cursor hovers over an element. +- `onmouseout` - lua function called when the cursor exits an element. + onmouseenter and onmouseleave do not respect the elements hierarchy. - `tooltip` - tooltip text - `tooltip-delay` - tooltip show-up delay - `gravity` - automatic positioning of the element in the container. (Does not work in automatic containers like panel). Values: *top-left, top-center, top-right, center-left, center-center, center-right, bottom-left, bottom-center, bottom-right*. diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md index 3c5d1acc1..d1255007c 100644 --- a/doc/ru/xml-ui-layouts.md +++ b/doc/ru/xml-ui-layouts.md @@ -46,8 +46,11 @@ - `ondoubleclick` - lua функция вызываемая при двойном нажатии на элемент. - `onfocus` - lua функция вызываемая при фокусировке на элемент. - `ondefocus` - lua функция вызываемая при потере фокуса элеметом. -- `onmouseover` - lua функция вызываемая при входе курсора в элемент. -- `onmouseover` - lua функция вызываемая при выходе курсора из элемента. +- `onmouseenter` - lua функция вызываемая при входе курсора в элемент. +- `onmouseleave` - lua функция вызываемая при выходе курсора из элемента. +- `onmouseover` - lua функция вызываемая при наведении курсора на элемент. +- `onmouseout` - lua функция вызываемая при выходе курсора из элемента. + onmouseenter и onmouseleave не учитывают иерархию элементов. - `tooltip` - текст всплывающей подсказки - `tooltip-delay` - задержка появления всплывающей подсказки - `gravity` - автоматическое позиционирование элемента в контейнере. (Не работает в автоматических контейнерах, как panel). Значения: *top-left, top-center, top-right, center-left, center-center, center-right, bottom-left, bottom-center, bottom-right*. diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index 22ae5b908..5fa617bda 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -133,10 +133,10 @@ void GUI::actMouse(float delta, const CursorState& cursor) { auto hover = container->getAt(cursor.pos); if (this->hover && this->hover != hover) { - this->hover->setHover(false); + this->hover->setMouseEnter(false); } - if (hover) { - hover->setHover(true); + if (hover && hover != this->hover) { + hover->setMouseEnter(true); int scroll = input.getScroll(); if (scroll) { @@ -144,6 +144,28 @@ void GUI::actMouse(float delta, const CursorState& cursor) { } } this->hover = hover; + auto node = hover; + while (node) { + if (mouseOver.find(hover) != mouseOver.end()) { + break; + } + mouseOver.insert(node); + node->setMouseOver(true); + auto parent = node->getParent(); + if (parent) { + node = parent->shared_from_this(); + } + } + + for (auto it = mouseOver.begin(); it != mouseOver.end(); ) { + auto node = *it; + if (node->isInside(cursor.pos)) { + ++it; + continue; + } + node->setMouseOver(false); + it = mouseOver.erase(it); + } if (input.jclicked(Mousecode::BUTTON_1)) { if (pressed == nullptr && this->hover) { @@ -219,7 +241,7 @@ void GUI::act(float delta, const glm::uvec2& vp) { actMouse(delta, cursor); } else { if (hover) { - hover->setHover(false); + hover->setMouseEnter(false); hover = nullptr; } } diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index 16d8e358c..8a12c3cd4 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -2,6 +2,7 @@ #include "delegates.hpp" +#include #include #include #include @@ -80,6 +81,7 @@ namespace gui { std::unique_ptr uicamera; std::shared_ptr menu; std::queue postRunnables; + std::set> mouseOver; PageLoaderFunc pagesLoader; diff --git a/src/graphics/ui/elements/UINode.cpp b/src/graphics/ui/elements/UINode.cpp index cbcb1c909..465ff26e4 100644 --- a/src/graphics/ui/elements/UINode.cpp +++ b/src/graphics/ui/elements/UINode.cpp @@ -47,10 +47,11 @@ void UINode::setAlign(Align align) { this->align = align; } -void UINode::setHover(bool flag) { - if (hover == flag) { - return; - } +void UINode::setMouseEnter(bool flag) { + actions.notify(flag ? UIAction::MOUSE_ENTER : UIAction::MOUSE_LEAVE, gui); +} + +void UINode::setMouseOver(bool flag) { hover = flag; actions.notify(flag ? UIAction::MOUSE_OVER : UIAction::MOUSE_OUT, gui); } diff --git a/src/graphics/ui/elements/UINode.hpp b/src/graphics/ui/elements/UINode.hpp index cbd43b380..fb699a737 100644 --- a/src/graphics/ui/elements/UINode.hpp +++ b/src/graphics/ui/elements/UINode.hpp @@ -59,7 +59,9 @@ namespace gui { DEFOCUS, RIGHT_CLICK, MOUSE_OVER, - MOUSE_OUT + MOUSE_OUT, + MOUSE_ENTER, + MOUSE_LEAVE, }; using ActionsSet = TaggedCallbacksSet; @@ -167,11 +169,14 @@ namespace gui { virtual void setAlign(Align align); Align getAlign() const; - virtual void setHover(bool flag); + virtual void setMouseEnter(bool flag); bool isHover() const; + void setMouseOver(bool flag); + virtual void setParent(UINode* node); UINode* getParent() const; + std::shared_ptr getParentShared() const; /// @brief Set element color (doesn't affect inner elements). /// Also replaces hover color to avoid adding extra properties diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index 6011373fb..967fd6bca 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -186,6 +186,8 @@ static void read_uinode( register_action(node, reader, element, "ondoubleclick", UIAction::DOUBLE_CLICK); register_action(node, reader, element, "onmouseover", UIAction::MOUSE_OVER); register_action(node, reader, element, "onmouseout", UIAction::MOUSE_OUT); + register_action(node, reader, element, "onmouseenter", UIAction::MOUSE_ENTER); + register_action(node, reader, element, "onmouseleave", UIAction::MOUSE_LEAVE); } static void read_container_impl(