From eb1090406941a243e710b5cae29b8625ca8bdbbd Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 24 May 2024 08:03:05 +0300 Subject: [PATCH] added tooltips --- src/graphics/ui/GUI.cpp | 40 +++++++++++++++++++++- src/graphics/ui/GUI.hpp | 10 ++++-- src/graphics/ui/elements/InventoryView.cpp | 14 +++++++- src/graphics/ui/elements/InventoryView.hpp | 1 + src/graphics/ui/elements/Label.cpp | 31 ++++++++++++++--- src/graphics/ui/elements/Label.hpp | 8 +++++ src/graphics/ui/elements/UINode.cpp | 26 +++++++++++++- src/graphics/ui/elements/UINode.hpp | 12 ++++++- src/graphics/ui/gui_xml.cpp | 7 ++++ src/logic/scripting/lua/libgui.cpp | 8 +++++ 10 files changed, 146 insertions(+), 11 deletions(-) diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index cdff6fc5..0fc17f8c 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -1,9 +1,14 @@ #include "GUI.hpp" + +#include "gui_util.hpp" + #include "elements/UINode.hpp" +#include "elements/Label.hpp" #include "elements/Menu.hpp" #include "../../assets/Assets.hpp" #include "../../frontend/UiDocument.hpp" +#include "../../frontend/locale.hpp" #include "../../graphics/core/Batch2D.hpp" #include "../../graphics/core/Shader.hpp" #include "../../graphics/core/DrawContext.hpp" @@ -27,6 +32,15 @@ GUI::GUI() { menu->setId("menu"); container->add(menu); container->setScrollable(false); + + tooltip = guiutil::create( + "" + "" + "" + ); + store("tooltip", tooltip); + store("tooltip.label", UINode::find(tooltip, "tooltip.label")); + container->add(tooltip); } GUI::~GUI() { @@ -45,10 +59,34 @@ void GUI::onAssetsLoad(Assets* assets) { ), "core:root"); } +void GUI::updateTooltip(float delta) { + float mouseDelta = glm::length(Events::delta); + if ((hover && mouseDelta < 1.0f) || + (hover && hover->isInside(Events::cursor) && tooltipTimer >= tooltipDelay)) { + if (tooltipTimer + delta >= tooltipDelay) { + auto label = std::dynamic_pointer_cast(get("tooltip.label")); + const auto& text = hover->getTooltip(); + if (label && !text.empty()) { + tooltip->setVisible(true); + tooltip->setPos(Events::cursor+glm::vec2(10.0f)); + label->setText(langs::get(text)); + tooltip->setSize(label->getSize()+glm::vec2(4.0f)); + } + } + tooltipTimer += delta; + } else { + tooltipTimer = 0.0f; + tooltip->setVisible(false); + } +} + /// @brief Mouse related input and logic handling void GUI::actMouse(float delta) { + updateTooltip(delta); + + float mouseDelta = glm::length(Events::delta); doubleClicked = false; - doubleClickTimer += delta + glm::length(Events::delta) * 0.1f; + doubleClickTimer += delta + mouseDelta * 0.1f; auto hover = container->getAt(Events::cursor, nullptr); if (this->hover && this->hover != hover) { diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index e88a3ea1..cb1dc4ff 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -54,21 +54,25 @@ namespace gui { /// @brief The main UI controller class GUI { std::shared_ptr container; - std::shared_ptr hover = nullptr; - std::shared_ptr pressed = nullptr; - std::shared_ptr focus = nullptr; + std::shared_ptr hover; + std::shared_ptr pressed; + std::shared_ptr focus; + std::shared_ptr tooltip; std::unordered_map> storage; std::unique_ptr uicamera; std::shared_ptr menu; std::queue postRunnables; + float tooltipTimer = 0.0f; + float tooltipDelay = 0.5f; float doubleClickTimer = 0.0f; float doubleClickDelay = 0.5f; bool doubleClicked = false; void actMouse(float delta); void actFocused(); + void updateTooltip(float delta); public: GUI(); ~GUI(); diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index 1ca82a72..7995a583 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -1,7 +1,9 @@ #include "InventoryView.hpp" + #include "../../../assets/Assets.hpp" #include "../../../content/Content.hpp" #include "../../../frontend/LevelFrontend.hpp" +#include "../../../frontend/locale.hpp" #include "../../../items/Inventories.hpp" #include "../../../items/Inventory.hpp" #include "../../../items/ItemDef.hpp" @@ -22,7 +24,6 @@ #include "../../render/BlocksPreview.hpp" #include "../GUI.hpp" -#include #include using namespace gui; @@ -270,6 +271,17 @@ void SlotView::onFocus(gui::GUI* gui) { clicked(gui, mousecode::BUTTON_1); } +const std::wstring SlotView::getTooltip() const { + const auto str = UINode::getTooltip(); + if (!str.empty() || bound->isEmpty()) { + return str; + } + auto def = content->getIndices()->getItemDef(bound->getItemId()); + return util::capitalized( + langs::get(util::str2wstr_utf8(def->caption)) + ); // TODO: cache +} + void SlotView::bind( int64_t inventoryid, ItemStack& stack, diff --git a/src/graphics/ui/elements/InventoryView.hpp b/src/graphics/ui/elements/InventoryView.hpp index 8e3006d7..5bb5629c 100644 --- a/src/graphics/ui/elements/InventoryView.hpp +++ b/src/graphics/ui/elements/InventoryView.hpp @@ -63,6 +63,7 @@ namespace gui { virtual void clicked(gui::GUI*, mousecode) override; virtual void onFocus(gui::GUI*) override; + virtual const std::wstring getTooltip() const override; void bind( int64_t inventoryid, diff --git a/src/graphics/ui/elements/Label.cpp b/src/graphics/ui/elements/Label.cpp index a7bb198d..f8e9fa07 100644 --- a/src/graphics/ui/elements/Label.cpp +++ b/src/graphics/ui/elements/Label.cpp @@ -64,12 +64,28 @@ Label::Label(std::wstring text, std::string fontName) cache.update(this->text, multiline, textWrap); } +glm::vec2 Label::calcSize() { + auto font = cache.font; + uint lineHeight = font->getLineHeight(); + if (cache.lines.size() > 1) { + lineHeight *= lineInterval; + } + return glm::vec2 ( + cache.font->calcWidth(text), + lineHeight * cache.lines.size() + font->getYOffset() + ); +} + void Label::setText(std::wstring text) { if (text == this->text && !cache.resetFlag) { return; } this->text = text; cache.update(this->text, multiline, textWrap); + + if (cache.font) { + setSize(calcSize()); + } } const std::wstring& Label::getText() const { @@ -156,10 +172,10 @@ void Label::draw(const DrawContext* pctx, Assets* assets) { lineHeight *= lineInterval; } glm::vec2 size = getSize(); - glm::vec2 newsize ( - font->calcWidth(text), - lineHeight * cache.lines.size() + font->getYOffset() - ); + glm::vec2 newsize = calcSize(); + if (autoresize) { + setSize(newsize); + } glm::vec2 pos = calcPos(); switch (align) { @@ -194,6 +210,13 @@ void Label::textSupplier(wstringsupplier supplier) { this->supplier = supplier; } +void Label::setAutoResize(bool flag) { + this->autoresize = flag; +} + +bool Label::isAutoResize() const { + return autoresize; +} void Label::setMultiline(bool multiline) { if (multiline != this->multiline) { diff --git a/src/graphics/ui/elements/Label.hpp b/src/graphics/ui/elements/Label.hpp index b7615ad5..87e82e72 100644 --- a/src/graphics/ui/elements/Label.hpp +++ b/src/graphics/ui/elements/Label.hpp @@ -24,6 +24,8 @@ namespace gui { class Label : public UINode { LabelCache cache; + + glm::vec2 calcSize(); protected: std::wstring text; std::string fontName; @@ -47,6 +49,9 @@ namespace gui { /// @brief Text line height multiplied by line interval int totalLineHeight = 1; + + /// @brief Auto resize label to fit text + bool autoresize = false; public: Label(std::string text, std::string fontName="normal"); Label(std::wstring text, std::string fontName="normal"); @@ -95,6 +100,9 @@ namespace gui { virtual void textSupplier(wstringsupplier supplier); + virtual void setAutoResize(bool flag); + virtual bool isAutoResize() const; + virtual void setMultiline(bool multiline); virtual bool isMultiline() const; diff --git a/src/graphics/ui/elements/UINode.cpp b/src/graphics/ui/elements/UINode.cpp index de1ced1c..be2cf9f8 100644 --- a/src/graphics/ui/elements/UINode.cpp +++ b/src/graphics/ui/elements/UINode.cpp @@ -129,6 +129,14 @@ bool UINode::isResizing() const { return resizing; } +void UINode::setTooltip(const std::wstring& text) { + this->tooltip = text; +} + +const std::wstring UINode::getTooltip() const { + return tooltip; +} + glm::vec2 UINode::calcPos() const { if (parent) { return pos + parent->calcPos() + parent->contentOffset(); @@ -316,7 +324,7 @@ void UINode::setGravity(Gravity gravity) { } void UINode::getIndices( - std::shared_ptr node, + const std::shared_ptr node, std::unordered_map>& map ) { const std::string& id = node->getId(); @@ -330,3 +338,19 @@ void UINode::getIndices( } } } +std::shared_ptr UINode::find( + const std::shared_ptr node, + const std::string& id +) { + if (node->getId() == id) { + return node; + } + if (auto container = std::dynamic_pointer_cast(node)) { + for (auto subnode : container->getNodes()) { + if (auto found = UINode::find(subnode, id)) { + return found; + } + } + } + return nullptr; +} diff --git a/src/graphics/ui/elements/UINode.hpp b/src/graphics/ui/elements/UINode.hpp index b4667acd..37a3b1b8 100644 --- a/src/graphics/ui/elements/UINode.hpp +++ b/src/graphics/ui/elements/UINode.hpp @@ -109,6 +109,8 @@ namespace gui { ActionsSet actions; /// @brief 'ondoubleclick' callbacks ActionsSet doubleClickCallbacks; + /// @brief element tooltip text + std::wstring tooltip; UINode(glm::vec2 size); public: @@ -197,6 +199,9 @@ namespace gui { virtual void setResizing(bool flag); virtual bool isResizing() const; + virtual void setTooltip(const std::wstring& text); + virtual const std::wstring getTooltip() const; + virtual glm::vec4 calcColor() const; /// @brief Get inner content offset. Used for scroll @@ -237,9 +242,14 @@ namespace gui { /// @brief collect all nodes having id static void getIndices( - std::shared_ptr node, + const std::shared_ptr node, std::unordered_map>& map ); + + static std::shared_ptr find( + const std::shared_ptr node, + const std::string& id + ); }; } diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index 50ba1bb2..cd3a9de7 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -143,6 +143,10 @@ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& no )); } + if (element->has("tooltip")) { + node.setTooltip(util::str2wstr_utf8(element->attr("tooltip").getText())); + } + if (auto onclick = create_action(reader, element, "onclick")) { node.listenAction(onclick); } @@ -245,6 +249,9 @@ static std::shared_ptr readLabel(UiXmlReader& reader, xml::xmlelement el reader.getFilename() )); } + if (element->has("autoresize")) { + label->setAutoResize(element->attr("autoresize").asBool()); + } if (element->has("multiline")) { label->setMultiline(element->attr("multiline").asBool()); if (!element->has("valign")) { diff --git a/src/logic/scripting/lua/libgui.cpp b/src/logic/scripting/lua/libgui.cpp index a72f91c7..de823455 100644 --- a/src/logic/scripting/lua/libgui.cpp +++ b/src/logic/scripting/lua/libgui.cpp @@ -264,6 +264,9 @@ static int p_get_hover_color(UINode* node) { static int p_get_pressed_color(UINode* node) { return lua::pushcolor_arr(state->getLua(), node->getPressedColor()); } +static int p_get_tooltip(UINode* node) { + return state->pushstring(util::wstr2str_utf8(node->getTooltip())); +} static int p_get_pos(UINode* node) { return lua::pushvec2_arr(state->getLua(), node->getPos()); } @@ -300,6 +303,7 @@ static int l_gui_getattr(lua_State* L) { {"color", p_get_color}, {"hoverColor", p_get_hover_color}, {"pressedColor", p_get_pressed_color}, + {"tooltip", p_get_tooltip}, {"pos", p_get_pos}, {"wpos", p_get_wpos}, {"size", p_get_size}, @@ -345,6 +349,9 @@ static void p_set_hover_color(UINode* node, int idx) { static void p_set_pressed_color(UINode* node, int idx) { node->setPressedColor(state->tocolor(idx)); } +static void p_set_tooltip(UINode* node, int idx) { + node->setTooltip(util::str2wstr_utf8(state->tostring(idx))); +} static void p_set_pos(UINode* node, int idx) { node->setPos(state->tovec2(idx)); } @@ -464,6 +471,7 @@ static int l_gui_setattr(lua_State* L) { {"color", p_set_color}, {"hoverColor", p_set_hover_color}, {"pressedColor", p_set_pressed_color}, + {"tooltip", p_set_tooltip}, {"pos", p_set_pos}, {"wpos", p_set_wpos}, {"size", p_set_size},