From ffe9d7ca1aad9c95b3569e9d3d89bca1c62b3def Mon Sep 17 00:00:00 2001 From: OmniaX-Dev Date: Wed, 22 Apr 2026 05:34:59 +0200 Subject: [PATCH] Added tooltips --- extra/DefaultTheme.oss | 11 ++++++++- other/TODO.txt | 2 +- src/ogfx/gui/Window.cpp | 10 ++++++++ src/ogfx/gui/Window.hpp | 10 ++++++++ src/ogfx/gui/widgets/RootWidget.cpp | 8 +++++-- src/ogfx/gui/widgets/RootWidget.hpp | 37 ++++++++++++++++++----------- src/ogfx/gui/widgets/Widget.cpp | 6 +++++ src/ogfx/gui/widgets/Widget.hpp | 5 ++++ src/test/GuiTest.cpp | 7 +++--- 9 files changed, 75 insertions(+), 21 deletions(-) diff --git a/extra/DefaultTheme.oss b/extra/DefaultTheme.oss index 3156614..d53436a 100644 --- a/extra/DefaultTheme.oss +++ b/extra/DefaultTheme.oss @@ -10,7 +10,16 @@ const $accentColorDark = #6B0A1DFF % ====== Root Widget ====== -window.backgroundColor = rgba(160, 160, 160, 255) +(window) { + backgroundColor = rgba(160, 160, 160, 255) + (tooltip) { + backgroundColor = #FFF7D6FF + borderColor = rgb(30, 30, 30) + textColor = rgb(30, 30, 30) + borderWidth = 1 + fontSize = 20 + } +} % ========================= diff --git a/other/TODO.txt b/other/TODO.txt index f651c63..e0ea796 100644 --- a/other/TODO.txt +++ b/other/TODO.txt @@ -42,6 +42,7 @@ Implement following widgets: ***Button ***Image/Icon ***Save/Open File Dialogs (and folder dialogs) + ***Tooltips Radio Button Grouping Progressbar @@ -49,7 +50,6 @@ Implement following widgets: Vertical Slider ListBox ComboBox - Tooltips Context Menu Menu Bar Layouts diff --git a/src/ogfx/gui/Window.cpp b/src/ogfx/gui/Window.cpp index 2de6311..68a672d 100644 --- a/src/ogfx/gui/Window.cpp +++ b/src/ogfx/gui/Window.cpp @@ -583,6 +583,7 @@ namespace ogfx else if (event.type == SDL_EVENT_MOUSE_MOTION) { MouseEventData mmd = get_mouse_state(event); + m_mousePosition = { mmd.position_x, mmd.position_y }; ostd::SignalHandler::emitSignal(ostd::BuiltinSignals::MouseMoved, ostd::Signal::Priority::RealTime, mmd); } else if (event.type == SDL_EVENT_MOUSE_WHEEL) @@ -876,6 +877,15 @@ namespace ogfx m_rootWidget.__update(); m_rootWidget.__draw(m_gfx); onRedraw(m_gfx); + + if (isTooltipShown()) + { + auto textSize = m_gfx.getStringDimensions(getTooltipText(), m_rootWidget.getTooltipFontSize()); + Rectangle textBounds = { getMousePosition(), textSize }; + textBounds += Rectangle { 0, 0, 30, 10 }; + m_gfx.outlinedRect(textBounds, m_rootWidget.getTooltipBackgroundColor(), m_rootWidget.getTooltipBorderColor(), m_rootWidget.getTooltipBorderWidth()); + m_gfx.drawCenteredString(getTooltipText(), textBounds, m_rootWidget.getTooltipTextColor(), m_rootWidget.getTooltipFontSize()); + } m_gfx.endFrame(); after_render(); } diff --git a/src/ogfx/gui/Window.hpp b/src/ogfx/gui/Window.hpp index a151020..a3a83ea 100644 --- a/src/ogfx/gui/Window.hpp +++ b/src/ogfx/gui/Window.hpp @@ -135,6 +135,13 @@ namespace ogfx inline GraphicsWindowOutputHandler& wout(void) { return m_wout; } inline f32 getScaleFactor(void) const { return m_systemScale * m_userScale; } inline void updateScalleFactor(void) { setUserScale(m_userScale); } + inline Vec2 getMousePosition(void) const { return m_mousePosition; } + inline void startTooltipTimer(const String& text) { m_tooltipText = text; m_tooltipTimer.startCount(ostd::eTimeUnits::Seconds); } + inline void stopTooltipTimer(void) { m_tooltipText = ""; m_tooltipTimer.endCount(); } + inline void restartTooltipTimer(void) { m_tooltipTimer.restart(ostd::eTimeUnits::Seconds); } + inline u64 readTooltipTimer(void) { return m_tooltipTimer.read(); } + inline bool isTooltipShown(void) { return m_tooltipText.new_trim() != "" && m_tooltipTimer.read() >= 2; } + inline String getTooltipText(void) const { return m_tooltipText; } protected: MouseEventData get_mouse_state(SDL_Event& event); @@ -170,6 +177,9 @@ namespace ogfx i32 m_windowHeight { 0 }; String m_title { "" }; i32 m_blockingEventsDelay { 33 }; + Vec2 m_mousePosition { 0, 0 }; + ostd::Timer m_tooltipTimer; + String m_tooltipText { "" }; bool m_running { false }; bool m_initialized { false }; diff --git a/src/ogfx/gui/widgets/RootWidget.cpp b/src/ogfx/gui/widgets/RootWidget.cpp index 48ba104..660ba8b 100644 --- a/src/ogfx/gui/widgets/RootWidget.cpp +++ b/src/ogfx/gui/widgets/RootWidget.cpp @@ -43,12 +43,16 @@ namespace ogfx void RootWidget::applyTheme(const ostd::Stylesheet& theme) { - m_color = getThemeValue(theme, "backgroundColor", getWindow().getClearColor()); + setTooltipBackgroundColor(getThemeValue(theme, "tooltip.backgroundColor", getTooltipBackgroundColor())); + setTooltipBorderColor(getThemeValue(theme, "tooltip.borderColor", getTooltipBorderColor())); + setTooltipTextColor(getThemeValue(theme, "tooltip.textColor", getTooltipTextColor())); + setTooltipBorderWidth(getThemeValue(theme, "tooltip.borderWidth", getTooltipBorderWidth())); + setTooltipFontSize(getThemeValue(theme, "tooltip.fontSize", getTooltipFontSize())); } void RootWidget::onDraw(ogfx::BasicRenderer2D& gfx) { - gfx.fillRect({ 0, 0, cast(getWindow().getWindowWidth()), cast(getWindow().getWindowHeight()) }, m_color); + gfx.fillRect({ 0, 0, cast(getWindow().getWindowWidth()), cast(getWindow().getWindowHeight()) }, getBackgroundColor()); } } } diff --git a/src/ogfx/gui/widgets/RootWidget.hpp b/src/ogfx/gui/widgets/RootWidget.hpp index 6adb1d4..29843cf 100644 --- a/src/ogfx/gui/widgets/RootWidget.hpp +++ b/src/ogfx/gui/widgets/RootWidget.hpp @@ -1,21 +1,21 @@ /* - OmniaFramework - A collection of useful functionality - Copyright (C) 2025 OmniaX-Dev + OmniaFramework - A collection of useful functionality + Copyright (C) 2025 OmniaX-Dev - This file is part of OmniaFramework. + This file is part of OmniaFramework. - OmniaFramework is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + OmniaFramework is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - OmniaFramework is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + OmniaFramework is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with OmniaFramework. If not, see . + You should have received a copy of the GNU General Public License + along with OmniaFramework. If not, see . */ #pragma once @@ -35,9 +35,18 @@ namespace ogfx void onWindowResized(const Event& event) override; void applyTheme(const ostd::Stylesheet& theme) override; void onDraw(ogfx::BasicRenderer2D& gfx) override; + OSTD_PARAM_GETSET(Color, TooltipBackgroundColor, m_tooltipBackgroundColor); + OSTD_PARAM_GETSET(Color, TooltipBorderColor, m_tooltipBorderColor); + OSTD_PARAM_GETSET(Color, TooltipTextColor, m_tooltipTextColor); + OSTD_PARAM_GETSET(i32, TooltipBorderWidth, m_tooltipBorderWidth); + OSTD_PARAM_GETSET(i32, TooltipFontSize, m_tooltipFontSize); private: - Color m_color { Colors::Transparent }; + Color m_tooltipBackgroundColor { "#FFF7D6FF" }; + Color m_tooltipBorderColor { 50, 50, 50 }; + Color m_tooltipTextColor { 50, 50, 50 }; + i32 m_tooltipBorderWidth { 1 }; + i32 m_tooltipFontSize { 20 }; }; } } diff --git a/src/ogfx/gui/widgets/Widget.cpp b/src/ogfx/gui/widgets/Widget.cpp index 3549ac7..b3d3e88 100644 --- a/src/ogfx/gui/widgets/Widget.cpp +++ b/src/ogfx/gui/widgets/Widget.cpp @@ -320,6 +320,8 @@ namespace ogfx callback_onMouseMoved(event); onMouseMoved(event); } + if (isTooltipEnabled() && isMouseInside()) + getWindow().restartTooltipTimer(); } void Widget::__onMouseScrolled(const Event& event) @@ -340,6 +342,8 @@ namespace ogfx if (callback_onMouseEntered) callback_onMouseEntered(event); onMouseEntered(event); + if (isTooltipEnabled()) + getWindow().startTooltipTimer(getTooltipText()); } void Widget::__onMouseExited(const Event& event) @@ -348,6 +352,8 @@ namespace ogfx if (callback_onMouseExited) callback_onMouseExited(event); onMouseExited(event); + if (isTooltipEnabled()) + getWindow().stopTooltipTimer(); } void Widget::__onMouseDragged(const Event& event) diff --git a/src/ogfx/gui/widgets/Widget.hpp b/src/ogfx/gui/widgets/Widget.hpp index fb21329..0e856ed 100644 --- a/src/ogfx/gui/widgets/Widget.hpp +++ b/src/ogfx/gui/widgets/Widget.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace ogfx @@ -141,6 +142,7 @@ namespace ogfx OSTD_PARAM_GETSET(Rectangle, Margin, m_margin); OSTD_PARAM_GETSET(i32, TabIndex, m_tabIndex); OSTD_PARAM_GETSET(Vec2, ContentOffset, m_contentOffset); + OSTD_PARAM_GETSET(String, TooltipText, m_tooltipText); // BOOL PARAMETERS inline bool isVisible(void) const { return m_visible; } @@ -167,6 +169,7 @@ namespace ogfx OSTD_BOOL_PARAM_GETSET_E(HScroll, m_vScrollEnabled); OSTD_BOOL_PARAM_GETSET_E(BackgroundGradient, m_useBackgroundGradient); OSTD_BOOL_PARAM_GETSET_E(Theming, m_enableTheming); + OSTD_BOOL_PARAM_GETSET_E(Tooltip, m_enableTooltip); // ========================================================================== protected: @@ -185,6 +188,7 @@ namespace ogfx bool m_focused { false }; i32 m_tabIndex { -1 }; i32 m_zIndex { -1 }; + String m_tooltipText { "" }; MouseEventData::eButton m_pressedButton { MouseEventData::eButton::None }; // ==================== @@ -205,6 +209,7 @@ namespace ogfx bool m_vScrollEnabled { false }; bool m_hScrollEnabled { false }; bool m_enableTheming { true }; + bool m_enableTooltip { false }; // ==================== diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp index 51d00e5..eeefbe0 100644 --- a/src/test/GuiTest.cpp +++ b/src/test/GuiTest.cpp @@ -52,7 +52,6 @@ class Window : public ogfx::gui::Window m_label1.setText("Show Panel2"); m_label1.setCallback(ogfx::gui::Widget::eCallback::MousePressed, [&](const ogfx::gui::Event& event) -> void { m_check1.setChecked(!m_check1.isChecked()); - m_label1.addy(10); }); m_label1.disableTheming(); m_label1.addThemeOverride("@.label.showBackground", true); @@ -81,6 +80,8 @@ class Window : public ogfx::gui::Window m_btn1.setIcon("./img.png"); m_btn1.setIconSize({ 64, 64 }); m_btn1.enableAnimated(); + m_btn1.enableTooltip(); + m_btn1.setTooltipText("Test tooltip"); m_label2.setText("Label2"); m_label3.setText("Label3"); @@ -99,13 +100,13 @@ class Window : public ogfx::gui::Window m_panel2.setSize(600, 400); m_panel2.setTitle("Panel 2"); + m_panel2.enableTooltip(); + m_panel2.setTooltipText("PANEL tooltip"); m_tabs.setSize(900, 700); auto& t1 = m_tabs.addTab("Tab1"); auto& t2 = m_tabs.addTab("Tab2 Test"); auto& t3 = m_tabs.addTab("Long Tab Test"); - for (i32 i = 3; i < 15; i++) - m_tabs.addTab(String("Tab").add(i)); t2.addThemeOverride("@panel_tab.panel.backgroundColor", Colors::SkyBlue); t3.addThemeOverride("@panel_tab.panel.backgroundColor", Colors::Orange);