diff --git a/CMakeLists.txt b/CMakeLists.txt index 129e27f..4f80d52 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ list(APPEND OGFX_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/RootWidget.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/CheckBox.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Scrollbar.cpp + ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Button.cpp # render ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp diff --git a/other/TODO.txt b/other/TODO.txt index c4e692e..5319a81 100644 --- a/other/TODO.txt +++ b/other/TODO.txt @@ -19,8 +19,8 @@ ***Implement Panel title ***Implement show/hide functionality for widgets ***Create reliable default stylesheet +***Implement global scale (probably query desktop scale and adjust accordingly) Add theme caching -Implement global scale (probably query desktop scale and adjust accordingly) Implement cursors in Stylesheet diff --git a/src/ogfx/gui/WidgetManager.cpp b/src/ogfx/gui/WidgetManager.cpp index 7599b63..bba2d96 100644 --- a/src/ogfx/gui/WidgetManager.cpp +++ b/src/ogfx/gui/WidgetManager.cpp @@ -22,6 +22,7 @@ #include "widgets/Widget.hpp" #include "../render/BasicRenderer.hpp" #include "../utils/Keycodes.hpp" +#include "../../ostd/io/Memory.hpp" namespace ogfx { @@ -68,12 +69,20 @@ namespace ogfx if (hasWidget(widget)) return false; widget.m_parent = &m_owner; m_widgetList.push_back(&widget); + if (widget.m_topMost) + return true; std::ranges::sort(m_widgetList, {}, [](Widget* w) { return w->m_zIndex; }); return true; } + bool WidgetManager::removeWidget(Widget& widget) + { + STDVEC_REMOVE(m_widgetList, &widget); + return true; + } + Widget* WidgetManager::focusNext(void) { if (m_widgetList.empty()) @@ -107,6 +116,7 @@ namespace ogfx if (w == nullptr) continue; if (w->isInvalid()) continue; if (!w->isVisible()) continue; + if (w->isManualDrawEnabled()) continue; gfx.pushClippingRect({ w->getGlobalPosition(), w->getSize() }, true); w->__draw(gfx); gfx.popClippingRect(); diff --git a/src/ogfx/gui/WidgetManager.hpp b/src/ogfx/gui/WidgetManager.hpp index 81429a9..465ba40 100644 --- a/src/ogfx/gui/WidgetManager.hpp +++ b/src/ogfx/gui/WidgetManager.hpp @@ -41,6 +41,7 @@ namespace ogfx bool hasWidget(Widget& widget); bool requestFocus(Widget& widget); bool addWidget(Widget& widget); + bool removeWidget(Widget& widget); Widget* focusNext(void); void draw(ogfx::BasicRenderer2D& gfx); diff --git a/src/ogfx/gui/widgets/Button.cpp b/src/ogfx/gui/widgets/Button.cpp new file mode 100644 index 0000000..fea4188 --- /dev/null +++ b/src/ogfx/gui/widgets/Button.cpp @@ -0,0 +1,32 @@ +/* + OmniaFramework - A collection of useful functionality + Copyright (C) 2025 OmniaX-Dev + + 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 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 . +*/ + +#include "Button.hpp" +#include "../../render/BasicRenderer.hpp" + +namespace ogfx +{ + namespace gui + { + namespace widgets + { + } + } +} diff --git a/src/ogfx/gui/widgets/Button.hpp b/src/ogfx/gui/widgets/Button.hpp new file mode 100644 index 0000000..a29db42 --- /dev/null +++ b/src/ogfx/gui/widgets/Button.hpp @@ -0,0 +1,33 @@ +/* + OmniaFramework - A collection of useful functionality + Copyright (C) 2025 OmniaX-Dev + + 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 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 . +*/ + +#pragma once + +#include + +namespace ogfx +{ + namespace gui + { + namespace widgets + { + } + } +} diff --git a/src/ogfx/gui/widgets/Containers.cpp b/src/ogfx/gui/widgets/Containers.cpp index 69551a4..9f39d40 100644 --- a/src/ogfx/gui/widgets/Containers.cpp +++ b/src/ogfx/gui/widgets/Containers.cpp @@ -36,6 +36,9 @@ namespace ogfx disableFocus(); enableStopEvents(); allowScroll(true); + m_scrollbar.setMargin({ 0, getTitlebarHeight(), 0, 0 }); + m_scrollbar.enableManualDraw(true); + addWidget(m_scrollbar); validate(); return *this; } @@ -71,6 +74,7 @@ namespace ogfx void Panel::afterDraw(ogfx::BasicRenderer2D& gfx) { draw_titlebar(gfx); + m_scrollbar.__draw(gfx); } void Panel::onMouseScrolled(const Event& event) @@ -143,7 +147,13 @@ namespace ogfx bool Panel::needsScroll(void) const { - return getContentExtents().h > getContentBounds().h; + return isScrollAllowed() && getContentExtents().h > getContentBounds().h; + } + + void Panel::onWidgetAdded(Widget& child) + { + removeWidget(m_scrollbar); + addWidget(m_scrollbar, { 0, 0 }, true); } void Panel::draw_titlebar(BasicRenderer2D& gfx) diff --git a/src/ogfx/gui/widgets/Containers.hpp b/src/ogfx/gui/widgets/Containers.hpp index 1cdf96a..3d5e6f5 100644 --- a/src/ogfx/gui/widgets/Containers.hpp +++ b/src/ogfx/gui/widgets/Containers.hpp @@ -21,6 +21,7 @@ #pragma once #include +#include namespace ogfx { @@ -52,6 +53,7 @@ namespace ogfx void setScrollOffset(const Vec2& offset) override; void addScrollOffset(const Vec2& offset) override; bool needsScroll(void) const override; + void onWidgetAdded(Widget& child) override; inline void setBackGroundColor(const Color& color) { m_backgroundColor = color; } inline Color getBackgroundColor(void) { return m_backgroundColor; } inline String getTitle(void) const { return m_title; } @@ -65,6 +67,7 @@ namespace ogfx private: String m_title { "Panel" }; Vec2 m_scrollOffset { 0, 0 }; + VerticalScrollBar m_scrollbar { getWindow() }; Color m_titleColor { Colors::Black }; i32 m_titlebarType = TitleBarTypes::NoneValue; diff --git a/src/ogfx/gui/widgets/Label.hpp b/src/ogfx/gui/widgets/Label.hpp index e51e71a..171d489 100644 --- a/src/ogfx/gui/widgets/Label.hpp +++ b/src/ogfx/gui/widgets/Label.hpp @@ -28,7 +28,6 @@ namespace ogfx { namespace widgets { - class Label : public Widget { public: diff --git a/src/ogfx/gui/widgets/Scrollbar.cpp b/src/ogfx/gui/widgets/Scrollbar.cpp index b8c4eb5..7d22e53 100644 --- a/src/ogfx/gui/widgets/Scrollbar.cpp +++ b/src/ogfx/gui/widgets/Scrollbar.cpp @@ -36,6 +36,7 @@ namespace ogfx disableChildren(); enableBackground(true); enableBorder(false); + enableTopMost(true); allowIgnoreScroll(true); validate(); return *this; diff --git a/src/ogfx/gui/widgets/Widget.cpp b/src/ogfx/gui/widgets/Widget.cpp index 7ba7d9f..d460c71 100644 --- a/src/ogfx/gui/widgets/Widget.cpp +++ b/src/ogfx/gui/widgets/Widget.cpp @@ -36,14 +36,23 @@ namespace ogfx m_window = &window; } - bool Widget::addWidget(Widget& child, const Vec2& position) + bool Widget::addWidget(Widget& child, const Vec2& position, bool __skip_callback) { if (!m_allowChildren) return false; if (position.x != 0 || position.y != 0) child.setPosition(position); child.reloadTheme(); - return m_widgets.addWidget(child); + bool result = m_widgets.addWidget(child); + if (!result) return false; + if (!__skip_callback) + onWidgetAdded(child); + return result; + } + + bool Widget::removeWidget(Widget& child) + { + return m_widgets.removeWidget(child); } Vec2 Widget::getGlobalPosition(void) const diff --git a/src/ogfx/gui/widgets/Widget.hpp b/src/ogfx/gui/widgets/Widget.hpp index 82d855c..008ff3a 100644 --- a/src/ogfx/gui/widgets/Widget.hpp +++ b/src/ogfx/gui/widgets/Widget.hpp @@ -41,7 +41,8 @@ namespace ogfx public: using EventCallback = std::function; public: Widget(const Rectangle& bounds, WindowCore& window); - bool addWidget(Widget& child, const Vec2& position = { 0, 0 }); + bool addWidget(Widget& child, const Vec2& position = { 0, 0 }, bool __skip_callback = false); + bool removeWidget(Widget& child); virtual Vec2 getGlobalPosition(void) const; virtual Vec2 getGlobalContentPosition(void) const; virtual Rectangle getGlobalBounds(void) const; @@ -68,6 +69,7 @@ namespace ogfx inline virtual void onDraw(ogfx::BasicRenderer2D& gfx) { } inline virtual void afterDraw(ogfx::BasicRenderer2D& gfx) { } inline virtual void onUpdate(void) { } + inline virtual void onWidgetAdded(Widget& child) { } inline virtual void onMousePressed(const Event& event) { } inline virtual void onMouseReleased(const Event& event) { } @@ -155,6 +157,10 @@ namespace ogfx inline Color getBorderColor(void) { return m_borderColor; } inline void enableBorder(bool enable = true) { m_showBorder = enable; } inline bool isBorderEnabled(void) const { return m_showBorder; } + inline void enableManualDraw(bool enable = true) { m_manualDraw = enable; } + inline bool isManualDrawEnabled(void) const { return m_manualDraw; } + inline void enableTopMost(bool enable = true) { m_topMost = enable; } + inline bool isTopMostEnabled(void) const { return m_topMost; } inline void setBorderRadius(i32 br) { m_borderRadius = br; } inline i32 getBorderRadius(void) const { return m_borderRadius; } inline void setBorderWidth(i32 bw) { m_borderWidth = bw; } @@ -227,6 +233,8 @@ namespace ogfx bool m_visible { true }; bool m_allowScroll { false }; bool m_ignoreScroll { false}; + bool m_manualDraw { false }; + bool m_topMost { false }; MouseEventData::eButton m_pressedButton { MouseEventData::eButton::None }; stdvec m_themeIDList; diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp index c3f5172..f476e18 100644 --- a/src/test/GuiTest.cpp +++ b/src/test/GuiTest.cpp @@ -75,14 +75,11 @@ class Window : public ogfx::gui::Window m_panel2.setSize(600, 400); - m_scroll.setMargin({ 0, m_panel2.getTitlebarHeight(), 0, 0 }); - m_panel1.addWidget(m_label2); m_panel2.addWidget(m_label3); - m_panel2.addWidget(m_panel1, { 0, 50 }); + m_panel2.addWidget(m_panel1, { 400, 50 }); m_panel2.addWidget(m_label1, { 0, 500 }); - m_panel2.addWidget(m_scroll); addWidget(m_check1, { 30, 30 }); addWidget(m_panel2, { 30, 100 }); @@ -118,7 +115,6 @@ class Window : public ogfx::gui::Window ogfx::gui::widgets::Panel m_panel1 { *this }; ogfx::gui::widgets::Panel m_panel2 { *this }; ogfx::gui::widgets::CheckBox m_check1 { *this }; - ogfx::gui::widgets::VerticalScrollBar m_scroll { *this }; ostd::Stylesheet m_theme; ogfx::Animation m_anim;