diff --git a/.clangd b/.clangd
index 122ab09..32169b9 100644
--- a/.clangd
+++ b/.clangd
@@ -1,2 +1,3 @@
CompileFlags:
- CompilationDatabase: bin
\ No newline at end of file
+ CompilationDatabase: bin
+ Add: ["--target=x86_64-w64-mingw32"]
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac8ecb2..d5075b2 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -89,7 +89,11 @@ list(APPEND OGFX_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/RawTextInput.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/Window.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/WindowOutputHandler.cpp
- ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/Widgets.cpp
+
+ # gui/widgets
+ ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Widget.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Containers.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Label.cpp
# render
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp
diff --git a/extra/testTheme.txt b/extra/testTheme.txt
index a2d78c1..a5f6f74 100644
--- a/extra/testTheme.txt
+++ b/extra/testTheme.txt
@@ -21,9 +21,9 @@ window.backgroundColor = Color(rgba(120, 120, 120, 255))
(panel) {
backgroundColor = Color(#AAAAAAFF)
- borderColor = Color(#000000FF)
+ borderColor = Color(#00FF00FF)
borderRadius = 8
- borderWidth = 2
+ borderWidth = 4
showBorder = true
padding = Rect(15, 15, 15, 15)
}
@@ -42,6 +42,11 @@ window.backgroundColor = Color(rgba(120, 120, 120, 255))
borderColor = Color(#208080FF)
}
+
+% (@testLabel2 label:pressed [mouseButton=left or mouseButton=right]) {
+% ...
+
+
(@testLabel2 label:pressed) {
showBackground = true
}
@@ -70,4 +75,13 @@ window.backgroundColor = Color(rgba(120, 120, 120, 255))
%borderColor = Color(#000000FF)
}
+(@label3 label) {
+ textColor = $color2
+ backgroundColor = Color(#000000FF)
+ fontSize = 20
+ borderColor = Color(#FF0000FF)
+ borderWidth = 4
+ borderRadius = 15
+}
+
% ===================================================
diff --git a/other/TODO.txt b/other/TODO.txt
index f6c4ea1..17d8377 100644
--- a/other/TODO.txt
+++ b/other/TODO.txt
@@ -3,3 +3,30 @@
***Fix mouse detection currently using local coordinates
***implement file theme loading
***Implemenmt MouseDragged callback
+***Add scissoring to only draw inside the bounds of containers
+Add theme caching
+Implement mouse scroll callback
+Implement a way to determine on what widget (in the hierarchy chain) and event must stop
+Implement margin for widgets
+Implement conditional statements for stylesheet rules
+
+
+Implement following widgets:
+ ***Label
+ Button
+ Image/Icon
+ Panel / Container
+ Title Label
+ Checkbox
+ Radio Button
+ Grouping
+ Text Input
+ Horizontal Slider
+ Vertical Slider
+ Image / Icon
+ ScrollView
+ ListBox
+ ComboBox
+ TreeView
+ Save/Open File Dialogs (and folder dialogs)
+ Tab Panel
diff --git a/other/build.nr b/other/build.nr
index e83bd43..a9a6e2f 100644
--- a/other/build.nr
+++ b/other/build.nr
@@ -1 +1 @@
-2046
+2049
diff --git a/other/create_release.sh b/other/create_release.sh
index 1cb7819..0a0aa33 100755
--- a/other/create_release.sh
+++ b/other/create_release.sh
@@ -58,11 +58,13 @@ cp -r ../src/ostd/vendor/nlohmann $RELEASE_DIR/include/ostd/vendor/
# OGFX
mkdir -p $RELEASE_DIR/include/ogfx/vendor/sdl3_gfx
mkdir -p $RELEASE_DIR/include/ogfx/gui
+mkdir -p $RELEASE_DIR/include/ogfx/gui/widgets
mkdir -p $RELEASE_DIR/include/ogfx/render
mkdir -p $RELEASE_DIR/include/ogfx/resources
mkdir -p $RELEASE_DIR/include/ogfx/utils
find ../src/ogfx -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx \;
find ../src/ogfx/gui -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx/gui \;
+find ../src/ogfx/gui/widgets -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx/gui/widgets \;
find ../src/ogfx/render -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx/render \;
find ../src/ogfx/resources -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx/resources \;
find ../src/ogfx/utils -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx/utils \;
diff --git a/src/ogfx/gui/Widgets.hpp b/src/ogfx/gui/Widgets.hpp
index bf10646..d0912eb 100644
--- a/src/ogfx/gui/Widgets.hpp
+++ b/src/ogfx/gui/Widgets.hpp
@@ -1,301 +1,24 @@
/*
- 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
-#include "gui/Events.hpp"
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace ogfx
-{
- class BasicRenderer2D;
- class WindowCore;
- namespace gui
- {
- class Event;
- class Widget;
- class WidgetManager
- {
- public:
- WidgetManager(WindowCore& window, Widget& owner);
- bool hasWidget(Widget& widget);
- bool requestFocus(Widget& widget);
- bool addWidget(Widget& widget);
- Widget* focusNext(void);
-
- void draw(ogfx::BasicRenderer2D& gfx);
- void update(void);
- void onThemeApplied(const ostd::Stylesheet& theme);
- void onMousePressed(const Event& event);
- void onMouseReleased(const Event& event);
- void onMouseMoved(const Event& event);
- void onMouseDragged(const Event& event);
- void onKeyPressed(const Event& event);
- void onKeyReleased(const Event& event);
- void onTextEntered(const Event& event);
- void onWindowClosed(const Event& event);
- void onWindowResized(const Event& event);
- void onWindowFocused(const Event& event);
- void onWindowFocusLost(const Event& event);
-
- inline int32_t widgetCount(void) const { return m_widgetList.size(); }
- inline WindowCore& getWindow(void) { return m_window; }
-
- private:
- WindowCore& m_window;
- Widget& m_owner;
- std::vector m_widgetList;
- Widget* m_focused { nullptr };
- bool m_tabNavigationEnabled { true };
- Widget* m_mousePressedOnWidget { nullptr };
- };
- class Widget : public ostd::BaseObject, public ostd::Rectangle
- {
- private: struct ThemeOverride
- {
- ostd::String fullKey;
- ostd::Stylesheet::TypeVariant value;
- bool propagate;
- };
- public: using EventCallback = std::function;
- public:
- Widget(const ostd::Rectangle& bounds, WindowCore& window);
- bool addChild(Widget& child);
- ostd::Vec2 getGlobalPosition(void) const;
- using ostd::Rectangle::contains;
- bool contains(ostd::Vec2 p, bool includeBounds = false) const override;
- void enable(bool enable = true);
- virtual void applyTheme(const ostd::Stylesheet& theme) = 0;
- void addThemeOverride(const ostd::String& fullKey, ostd::Stylesheet::TypeVariant value, bool propagate = true);
- void reloadTheme(void);
- void setThemeQualifier(const ostd::String& qualifier, bool value = true);
- bool getThemeQualifier(const ostd::String& qualifier);
- bool addThemeID(const ostd::String& id);
- bool removeThemeID(const ostd::String& id);
- inline const ostd::Stylesheet::QualifierList& getThemeQualifierList(void) const { return m_qualifierList; }
-
- inline virtual void onDraw(ogfx::BasicRenderer2D& gfx) { }
- inline virtual void onUpdate(void) { }
-
- inline virtual void onMousePressed(const Event& event) { }
- inline virtual void onMouseReleased(const Event& event) { }
- inline virtual void onMouseMoved(const Event& event) { }
- inline virtual void onMouseEntered(const Event& event) { }
- inline virtual void onMouseExited(const Event& event) { }
- inline virtual void onMouseDragged(const Event& event) { }
- inline virtual void onKeyPressed(const Event& event) { }
- inline virtual void onKeyReleased(const Event& event) { }
- inline virtual void onTextEntered(const Event& event) { }
- inline virtual void onFocusGained(const Event& event) { }
- inline virtual void onFocusLost(const Event& event) { }
- inline virtual void onWindowClosed(const Event& event) { }
- inline virtual void onWindowResized(const Event& event) { }
- inline virtual void onWindowFocused(const Event& event) { }
- inline virtual void onWindowFocusLost(const Event& event) { }
-
- void __draw(ogfx::BasicRenderer2D& gfx);
- void __update(void);
- void __onMousePressed(const Event& event);
- void __onMouseReleased(const Event& event);
- void __onMouseMoved(const Event& event);
- void __onMouseEntered(const Event& event);
- void __onMouseExited(const Event& event);
- void __onMouseDragged(const Event& event);
- void __onKeyPressed(const Event& event);
- void __onKeyReleased(const Event& event);
- void __onTextEntered(const Event& event);
- void __onWindowClosed(const Event& event);
- void __onWindowResized(const Event& event);
- void __onWIndowFocused(const Event& event);
- void __onWindowFocusLost(const Event& event);
- void __applyTheme(const ostd::Stylesheet& theme, bool propagate);
-
- inline virtual void setMousePressedCallback(EventCallback callback) { callback_onMousePressed = callback; }
- inline virtual void setMouseReleasedCallback(EventCallback callback) { callback_onMouseReleased = callback; }
- inline virtual void setMouseMovedCallback(EventCallback callback) { callback_onMouseMoved = callback; }
- inline virtual void setMouseEnteredCallback(EventCallback callback) { callback_onMouseEntered = callback; }
- inline virtual void setMouseExitedCallback(EventCallback callback) { callback_onMouseExited = callback; }
- inline virtual void setMouseDraggedCallback(EventCallback callback) { callback_onMouseDragged = callback; }
- inline virtual void setKeyPressedCallback(EventCallback callback) { callback_onKeyPressed = callback; }
- inline virtual void setKeyReleasedCallback(EventCallback callback) { callback_onKeyReleased = callback; }
- inline virtual void setTextEnteredCallback(EventCallback callback) { callback_onTextEntered = callback; }
- inline virtual void setWindowClosedCallback(EventCallback callback) { callback_onWindowClosed = callback; }
- inline virtual void setWindowResizedCallback(EventCallback callback) { callback_onWindowResized = callback; }
- inline virtual void setWIndowFocusedCallback(EventCallback callback) { callback_onWindowFocused = callback; }
- inline virtual void setWindowFocusLostCallback(EventCallback callback) { callback_onWindowFocusLost = callback; }
-
- inline bool hasChildren(void) const { return m_allowChildren && m_widgets.widgetCount() > 0; }
- inline virtual bool isInvalid(void) const override { return ostd::BaseObject::isInvalid() || (m_parent == nullptr && !m_rootChild); }
- inline void setTabIndex(int32_t tabIndex) { m_tabIndex = tabIndex; }
- inline int32_t getTabIndex(void) const { return m_tabIndex; }
- inline bool isFocused(void) const { return m_focused; }
- inline WindowCore& getWindow(void) { return *m_window; }
- inline Widget* getParent(void) { return m_parent; }
- inline int32_t getZIndex(void) const { return m_zIndex; }
- inline bool isChildrenEnabled(void) const { return m_allowChildren; }
- inline void setPadding(const ostd::Rectangle& pad) { m_padding = pad; }
- inline Rectangle getPadding(void) { return m_padding; }
- inline bool isMouseInside(void) const { return m_mouseInside; }
- inline ogfx::MouseEventData::eButton getPressedMouseButton(void) const { return m_pressedButton; }
- inline const std::vector& getThemeIDList(void) const { return m_themeIDList; }
- inline bool isEnabled(void) const { return m_enabled; }
- inline bool isFocusEnabled(void) const { return m_allowFocus; }
- inline void enableFocus(bool enable = true) { m_allowFocus = enable; }
- inline void disableFocus(void) { enableFocus(false); }
- inline void disabble(void) { enable(false); }
- inline void enableStopEvents(bool enable = true) { m_stopEvents = enable; }
-
- template
- inline T getThemeValue(const ostd::Stylesheet &theme, const ostd::String& key, const T& fallback)
- {
- return theme.get(key, fallback, getThemeIDList(), getThemeQualifierList());
- }
-
- protected:
- inline void disableChildren(void) { m_allowChildren = false; }
- inline void disableDrawBox(void) { m_drawBox = false; }
- inline void enableDrawBox(void) { m_drawBox = true; }
- inline bool isDrawBoxEnabled(void) const { return m_drawBox; }
- inline void setDrawBoxColor(const ostd::Color& color) { m_drawBoxColor = color; }
- inline ostd::Color getDrawBoxColor(void) { return m_drawBoxColor; }
-
- protected:
- bool m_rootChild { false };
-
- EventCallback callback_onMousePressed { nullptr };
- EventCallback callback_onMouseReleased { nullptr };
- EventCallback callback_onMouseMoved { nullptr };
- EventCallback callback_onMouseEntered { nullptr };
- EventCallback callback_onMouseExited { nullptr };
- EventCallback callback_onMouseDragged { nullptr };
- EventCallback callback_onKeyPressed { nullptr };
- EventCallback callback_onKeyReleased { nullptr };
- EventCallback callback_onTextEntered { nullptr };
- EventCallback callback_onWindowClosed { nullptr };
- EventCallback callback_onWindowResized { nullptr };
- EventCallback callback_onWindowFocused { nullptr };
- EventCallback callback_onWindowFocusLost { nullptr };
-
- private:
- WindowCore* m_window { nullptr };
- Widget* m_parent { nullptr };
- bool m_focused { false };
- int32_t m_tabIndex { -1 };
- int32_t m_zIndex { -1 };
- WidgetManager m_widgets;
- bool m_allowChildren { true };
- bool m_mouseInside { false };
- bool m_allowFocus { true };
- bool m_enabled { true };
- bool m_stopEvents { false };
- MouseEventData::eButton m_pressedButton { MouseEventData::eButton::None };
-
- std::vector m_themeIDList;
- ostd::Stylesheet::QualifierList m_qualifierList {
- { "disabled", false },
- { "pressed", false },
- { "hover", false },
- { "focused", false },
- { "active", false }
- };
- std::vector m_themeOverrides;
-
- bool m_drawBox { true };
- ostd::Color m_drawBoxColor { 255, 0, 0 };
-
- ostd::Rectangle m_padding { 0, 0, 0, 0 };
-
- friend class WidgetManager;
- };
- namespace widgets
- {
- class RootWidget : public Widget
- {
- public:
- RootWidget(WindowCore& window);
- void onWindowResized(const Event& event) override;
- void applyTheme(const ostd::Stylesheet& theme) override;
- void onDraw(ogfx::BasicRenderer2D& gfx) override;
-
- private:
- ostd::Color m_color { ostd::Colors::Transparent };
- };
- class Label : public Widget
- {
- public:
- inline Label(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(""); }
- inline Label(WindowCore& window, const ostd::String& text) : Widget({ 0, 0, 0, 0 }, window) { create(text); }
- Label& create(const ostd::String& text);
- void applyTheme(const ostd::Stylesheet& theme) override;
- void onDraw(ogfx::BasicRenderer2D& gfx) override;
- void setText(const ostd::String& text);
- inline ostd::String getText(void) const { return m_text; }
- inline ostd::Color getColor(void) const { return m_color; }
- inline void setColor(const ostd::Color& color) { m_color = color; }
- inline int32_t getFontSize(void) const { return m_fontSize; }
- inline void setFontSize(int32_t fontSize) { m_fontSize = fontSize; }
- inline void setBackGroundColor(const ostd::Color& color) { m_backgroundColor = color; }
- inline ostd::Color getBackgroundColor(void) { return m_backgroundColor; }
- inline void enableBackground(bool enable = true) { m_showBackground = enable; }
- inline bool isBackgoundEnabled(void) const { return m_showBackground; }
-
- private:
- void __update_size(ogfx::BasicRenderer2D& gfx);
-
- private:
- ostd::String m_text { "" };
- bool m_textChanged { false };
- int32_t m_fontSize { 20 };
- ostd::Color m_color { 255, 255, 255 };
- int32_t m_borderRadius { 10 };
- int32_t m_borderWidth { 2 };
- bool m_showBorder { false };
- bool m_showBackground { false };
- ostd::Color m_backgroundColor { ostd::Colors::Transparent };
- ostd::Color m_borderColor { 255, 255, 255 };
-
- private:
- };
- class Panel : public Widget
- {
- public:
- inline Panel(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); }
- Panel& create(void);
- void applyTheme(const ostd::Stylesheet& theme) override;
- void onDraw(ogfx::BasicRenderer2D& gfx) override;
- inline void setBackGroundColor(const ostd::Color& color) { m_backgroundColor = color; }
- inline ostd::Color getBackgroundColor(void) { return m_backgroundColor; }
-
- private:
- ostd::Color m_backgroundColor { 150, 150, 150 };
- ostd::Color m_borderColor { 0, 0, 0 };
- int32_t m_borderRadius { 10 };
- int32_t m_borderWidth { 2 };
- bool m_showBorder { false };
-
- };
- }
- }
-}
+#include
+#include
diff --git a/src/ogfx/gui/Window.hpp b/src/ogfx/gui/Window.hpp
index b01524f..24212dd 100644
--- a/src/ogfx/gui/Window.hpp
+++ b/src/ogfx/gui/Window.hpp
@@ -25,7 +25,7 @@
#include
#include
#include
-#include
+#include
#include
#include
diff --git a/src/ogfx/gui/widgets/Containers.cpp b/src/ogfx/gui/widgets/Containers.cpp
new file mode 100644
index 0000000..5f729c9
--- /dev/null
+++ b/src/ogfx/gui/widgets/Containers.cpp
@@ -0,0 +1,61 @@
+/*
+ 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 "Containers.hpp"
+#include "../../render/BasicRenderer.hpp"
+
+namespace ogfx
+{
+ namespace gui
+ {
+ namespace widgets
+ {
+ Panel& Panel::create(void)
+ {
+ setPadding({ 5, 5, 5, 5 });
+ setTypeName("ogfx::gui::widgets::Panel");
+ disableDrawBox();
+ disableFocus();
+ enableStopEvents();
+ validate();
+ return *this;
+ }
+
+ void Panel::applyTheme(const ostd::Stylesheet& theme)
+ {
+ setBackGroundColor(getThemeValue(theme, "panel.backgroundColor", ostd::Colors::Gray));
+ m_borderRadius = getThemeValue(theme, "panel.borderRadius", 8);
+ m_borderWidth = getThemeValue(theme, "panel.borderWidth", 2);
+ m_showBorder = getThemeValue(theme, "panel.showBorder", true);
+ m_borderColor = getThemeValue(theme, "panel.borderColor", ostd::Colors::Black);
+ setPadding(getThemeValue(theme, "panel.padding", { 15, 15, 15, 15 }));
+ }
+
+ void Panel::onDraw(ogfx::BasicRenderer2D& gfx)
+ {
+ if (m_showBorder)
+ gfx.outlinedRoundRect({ getGlobalPosition(), getSize() }, getBackgroundColor(), m_borderColor, m_borderRadius, m_borderWidth);
+ else
+ gfx.fillRoundRect({ getGlobalPosition(), getSize() }, getBackgroundColor(), m_borderRadius);
+ gfx.drawRect(getGlobalContentBounds(), ostd::Colors::Aquamarine, 6);
+ }
+ }
+ }
+}
diff --git a/src/ogfx/gui/widgets/Containers.hpp b/src/ogfx/gui/widgets/Containers.hpp
new file mode 100644
index 0000000..de68bbe
--- /dev/null
+++ b/src/ogfx/gui/widgets/Containers.hpp
@@ -0,0 +1,47 @@
+/*
+ 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
+ {
+ class Panel : public Widget
+ {
+ public:
+ inline Panel(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); }
+ Panel& create(void);
+ void applyTheme(const ostd::Stylesheet& theme) override;
+ void onDraw(ogfx::BasicRenderer2D& gfx) override;
+ inline void setBackGroundColor(const ostd::Color& color) { m_backgroundColor = color; }
+ inline ostd::Color getBackgroundColor(void) { return m_backgroundColor; }
+
+ private:
+ ostd::Color m_backgroundColor { 150, 150, 150 };
+
+ };
+ }
+ }
+}
diff --git a/src/ogfx/gui/widgets/Label.cpp b/src/ogfx/gui/widgets/Label.cpp
new file mode 100644
index 0000000..b52399d
--- /dev/null
+++ b/src/ogfx/gui/widgets/Label.cpp
@@ -0,0 +1,84 @@
+/*
+ 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 "Label.hpp"
+#include "../../render/BasicRenderer.hpp"
+
+namespace ogfx
+{
+ namespace gui
+ {
+ namespace widgets
+ {
+ Label& Label::create(const ostd::String& text)
+ {
+ setText(text);
+ setPadding({ 5, 5, 5, 5 });
+ setTypeName("ogfx::gui::widgets::Label");
+ disableDrawBox();
+ disableChildren();
+ enableBackground(false);
+ validate();
+ return *this;
+ }
+
+ void Label::applyTheme(const ostd::Stylesheet& theme)
+ {
+ setColor(getThemeValue(theme, "label.textColor", ostd::Colors::White));
+ setBackGroundColor(getThemeValue(theme, "label.backgroundColor", ostd::Colors::Transparent));
+ setFontSize(getThemeValue(theme, "label.fontSize", 20));
+ m_borderRadius = getThemeValue(theme, "label.borderRadius", 10);
+ m_borderWidth = getThemeValue(theme, "label.borderWidth", 2);
+ m_showBorder = getThemeValue(theme, "label.showBorder", false);
+ m_borderColor = getThemeValue(theme, "label.borderColor", ostd::Colors::White);
+ enableBackground(getThemeValue(theme, "label.showBackground", false));
+ setPadding(getThemeValue(theme, "label.padding", { 5, 5, 5, 5 }));
+ }
+
+ void Label::onDraw(ogfx::BasicRenderer2D& gfx)
+ {
+ if (m_textChanged)
+ __update_size(gfx);
+ if (m_showBackground)
+ gfx.fillRoundRect({ getGlobalPosition(), getSize() }, m_backgroundColor, m_borderRadius);
+ if (m_showBorder)
+ gfx.drawRoundRect({ getGlobalPosition(), getSize() }, m_borderColor, m_borderRadius, m_borderWidth);
+ gfx.drawString(getText(), getGlobalPosition() + ostd::Vec2 { getPadding().left(), getPadding().top() }, getColor(), getFontSize());
+ }
+
+ void Label::setText(const ostd::String& text)
+ {
+ m_text = text;
+ m_textChanged = true;
+ }
+
+ void Label::__update_size(ogfx::BasicRenderer2D& gfx)
+ {
+ auto size = gfx.getStringSize(getText(), getFontSize());
+ size.x += getPadding().left();
+ size.x += getPadding().right();
+ size.y += getPadding().top();
+ size.y += getPadding().bottom();
+ setSize({ static_cast(size.x), static_cast(size.y) });
+ m_textChanged = false;
+ }
+ }
+ }
+}
diff --git a/src/ogfx/gui/widgets/Label.hpp b/src/ogfx/gui/widgets/Label.hpp
new file mode 100644
index 0000000..f240b4c
--- /dev/null
+++ b/src/ogfx/gui/widgets/Label.hpp
@@ -0,0 +1,66 @@
+/*
+ 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
+ {
+
+ class Label : public Widget
+ {
+ public:
+ inline Label(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(""); }
+ inline Label(WindowCore& window, const ostd::String& text) : Widget({ 0, 0, 0, 0 }, window) { create(text); }
+ Label& create(const ostd::String& text);
+ void applyTheme(const ostd::Stylesheet& theme) override;
+ void onDraw(ogfx::BasicRenderer2D& gfx) override;
+ void setText(const ostd::String& text);
+ inline ostd::String getText(void) const { return m_text; }
+ inline ostd::Color getColor(void) const { return m_color; }
+ inline void setColor(const ostd::Color& color) { m_color = color; }
+ inline int32_t getFontSize(void) const { return m_fontSize; }
+ inline void setFontSize(int32_t fontSize) { m_fontSize = fontSize; }
+ inline void setBackGroundColor(const ostd::Color& color) { m_backgroundColor = color; }
+ inline ostd::Color getBackgroundColor(void) { return m_backgroundColor; }
+ inline void enableBackground(bool enable = true) { m_showBackground = enable; }
+ inline bool isBackgoundEnabled(void) const { return m_showBackground; }
+
+ private:
+ void __update_size(ogfx::BasicRenderer2D& gfx);
+
+ private:
+ ostd::String m_text { "" };
+ bool m_textChanged { false };
+ int32_t m_fontSize { 20 };
+ ostd::Color m_color { 255, 255, 255 };
+ bool m_showBackground { false };
+ ostd::Color m_backgroundColor { ostd::Colors::Transparent };
+
+ private:
+ };
+ }
+ }
+}
diff --git a/src/ogfx/gui/Widgets.cpp b/src/ogfx/gui/widgets/Widget.cpp
similarity index 80%
rename from src/ogfx/gui/Widgets.cpp
rename to src/ogfx/gui/widgets/Widget.cpp
index a2e12df..1a4c790 100644
--- a/src/ogfx/gui/Widgets.cpp
+++ b/src/ogfx/gui/widgets/Widget.cpp
@@ -18,12 +18,12 @@
along with OmniaFramework. If not, see .
*/
-#include "Widgets.hpp"
+#include "Widget.hpp"
#include "gui/Events.hpp"
#include "io/Memory.hpp"
#include "utils/Keycodes.hpp"
-#include
-#include
+#include "../..//render/BasicRenderer.hpp"
+#include "../Window.hpp"
namespace ogfx
{
@@ -107,7 +107,9 @@ namespace ogfx
{
if (w == nullptr) continue;
if (w->isInvalid()) continue;
+ gfx.pushClippingRect({ w->getGlobalPosition(), w->getSize() }, true);
w->__draw(gfx);
+ gfx.popClippingRect();
}
}
@@ -142,7 +144,7 @@ namespace ogfx
continue;
w->__onMousePressed(event);
m_mousePressedOnWidget = w;
- if (event.isHandled())
+ if (event.isHandled() || w->m_stopEvents)
break;
}
}
@@ -191,8 +193,20 @@ namespace ogfx
else
w->__onMouseMoved(event);
}
- if (event.isHandled())
+ if (event.isHandled() || w->m_stopEvents)
+ {
+ bool mouseOut = false;
+ for (int32_t j = i - 1; j >= 0; j--)
+ {
+ Widget* ww = m_widgetList[j];
+ if (ww->m_mouseInside)
+ {
+ ww->m_mouseInside = false;
+ ww->__onMouseExited(event);
+ }
+ }
break;
+ }
}
}
@@ -291,6 +305,7 @@ namespace ogfx
{
if (!m_allowChildren)
return false;
+ child.reloadTheme();
return m_widgets.addWidget(child);
}
@@ -298,10 +313,32 @@ namespace ogfx
{
ostd::Vec2 glob = getPosition();
if (!m_rootChild && m_parent != nullptr)
- glob += m_parent->getGlobalPosition();
+ glob += m_parent->getGlobalPosition() + m_parent->getPadding().getPosition();
return glob;
}
+ ostd::Vec2 Widget::getGlobalContentPosition(void) const
+ {
+ return getGlobalPosition() + getContentBounds().getPosition();
+ }
+
+ ostd::Rectangle Widget::getGlobalBounds(void) const
+ {
+ return { getGlobalPosition(), getSize() };
+ }
+
+ ostd::Rectangle Widget::getContentBounds(void) const
+ {
+ auto pad = getPadding();
+ return { pad.getPosition(), (getSize() - (pad.getSize() * 2)) };
+ }
+
+ ostd::Rectangle Widget::getGlobalContentBounds(void) const
+ {
+ auto pad = getPadding();
+ return { getGlobalContentPosition(), getContentBounds().getSize() };
+ }
+
bool Widget::contains(ostd::Vec2 p, bool includeBounds) const
{
return ostd::Rectangle(getGlobalPosition(), getSize()).contains(p, includeBounds);
@@ -594,94 +631,6 @@ namespace ogfx
{
gfx.fillRect({ 0, 0, static_cast(getWindow().getWindowWidth()), static_cast(getWindow().getWindowHeight()) }, m_color);
}
-
-
-
-
- Label& Label::create(const ostd::String& text)
- {
- setText(text);
- setPadding({ 5, 5, 5, 5 });
- setTypeName("ogfx::gui::widgets::Label");
- disableDrawBox();
- disableChildren();
- enableBackground(false);
- validate();
- return *this;
- }
-
- void Label::applyTheme(const ostd::Stylesheet& theme)
- {
- setColor(getThemeValue(theme, "label.textColor", ostd::Colors::White));
- setBackGroundColor(getThemeValue(theme, "label.backgroundColor", ostd::Colors::Transparent));
- setFontSize(getThemeValue(theme, "label.fontSize", 20));
- m_borderRadius = getThemeValue(theme, "label.borderRadius", 10);
- m_borderWidth = getThemeValue(theme, "label.borderWidth", 2);
- m_showBorder = getThemeValue(theme, "label.showBorder", false);
- m_borderColor = getThemeValue(theme, "label.borderColor", ostd::Colors::White);
- enableBackground(getThemeValue(theme, "label.showBackground", false));
- setPadding(getThemeValue(theme, "label.padding", { 5, 5, 5, 5 }));
- }
-
- void Label::onDraw(ogfx::BasicRenderer2D& gfx)
- {
- if (m_textChanged)
- __update_size(gfx);
- if (m_showBackground)
- gfx.fillRoundRect({ getGlobalPosition(), getSize() }, m_backgroundColor, m_borderRadius);
- if (m_showBorder)
- gfx.drawRoundRect({ getGlobalPosition(), getSize() }, m_borderColor, m_borderRadius, m_borderWidth);
- gfx.drawString(getText(), getGlobalPosition() + ostd::Vec2 { getPadding().left(), getPadding().top() }, getColor(), getFontSize());
- }
-
- void Label::setText(const ostd::String& text)
- {
- m_text = text;
- m_textChanged = true;
- }
-
- void Label::__update_size(ogfx::BasicRenderer2D& gfx)
- {
- auto size = gfx.getStringSize(getText(), getFontSize());
- size.x += getPadding().left();
- size.x += getPadding().right();
- size.y += getPadding().top();
- size.y += getPadding().bottom();
- setSize({ static_cast(size.x), static_cast(size.y) });
- m_textChanged = false;
- }
-
-
-
-
- Panel& Panel::create(void)
- {
- setPadding({ 5, 5, 5, 5 });
- setTypeName("ogfx::gui::widgets::Panel");
- disableDrawBox();
- disableFocus();
- enableStopEvents();
- validate();
- return *this;
- }
-
- void Panel::applyTheme(const ostd::Stylesheet& theme)
- {
- setBackGroundColor(getThemeValue(theme, "panel.backgroundColor", ostd::Colors::Gray));
- m_borderRadius = getThemeValue(theme, "panel.borderRadius", 8);
- m_borderWidth = getThemeValue(theme, "panel.borderWidth", 2);
- m_showBorder = getThemeValue(theme, "panel.showBorder", true);
- m_borderColor = getThemeValue(theme, "panel.borderColor", ostd::Colors::Black);
- setPadding(getThemeValue(theme, "panel.padding", { 15, 15, 15, 15 }));
- }
-
- void Panel::onDraw(ogfx::BasicRenderer2D& gfx)
- {
- if (m_showBorder)
- gfx.outlinedRoundRect({ getGlobalPosition(), getSize() }, getBackgroundColor(), m_borderColor, m_borderRadius, m_borderWidth);
- else
- gfx.fillRoundRect({ getGlobalPosition(), getSize() }, getBackgroundColor(), m_borderRadius);
- }
}
}
}
diff --git a/src/ogfx/gui/widgets/Widget.hpp b/src/ogfx/gui/widgets/Widget.hpp
new file mode 100644
index 0000000..1454752
--- /dev/null
+++ b/src/ogfx/gui/widgets/Widget.hpp
@@ -0,0 +1,256 @@
+/*
+ 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
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ogfx
+{
+ class BasicRenderer2D;
+ class WindowCore;
+ namespace gui
+ {
+ class Event;
+ class Widget;
+ class WidgetManager
+ {
+ public:
+ WidgetManager(WindowCore& window, Widget& owner);
+ bool hasWidget(Widget& widget);
+ bool requestFocus(Widget& widget);
+ bool addWidget(Widget& widget);
+ Widget* focusNext(void);
+
+ void draw(ogfx::BasicRenderer2D& gfx);
+ void update(void);
+ void onThemeApplied(const ostd::Stylesheet& theme);
+ void onMousePressed(const Event& event);
+ void onMouseReleased(const Event& event);
+ void onMouseMoved(const Event& event);
+ void onMouseDragged(const Event& event);
+ void onKeyPressed(const Event& event);
+ void onKeyReleased(const Event& event);
+ void onTextEntered(const Event& event);
+ void onWindowClosed(const Event& event);
+ void onWindowResized(const Event& event);
+ void onWindowFocused(const Event& event);
+ void onWindowFocusLost(const Event& event);
+
+ inline int32_t widgetCount(void) const { return m_widgetList.size(); }
+ inline WindowCore& getWindow(void) { return m_window; }
+
+ private:
+ WindowCore& m_window;
+ Widget& m_owner;
+ std::vector m_widgetList;
+ Widget* m_focused { nullptr };
+ bool m_tabNavigationEnabled { true };
+ Widget* m_mousePressedOnWidget { nullptr };
+ };
+ class Widget : public ostd::BaseObject, public ostd::Rectangle
+ {
+ private: struct ThemeOverride
+ {
+ ostd::String fullKey;
+ ostd::Stylesheet::TypeVariant value;
+ bool propagate;
+ };
+ public: using EventCallback = std::function;
+ public:
+ Widget(const ostd::Rectangle& bounds, WindowCore& window);
+ bool addChild(Widget& child);
+ ostd::Vec2 getGlobalPosition(void) const;
+ ostd::Vec2 getGlobalContentPosition(void) const;
+ ostd::Rectangle getGlobalBounds(void) const;
+ ostd::Rectangle getContentBounds(void) const;
+ ostd::Rectangle getGlobalContentBounds(void) const;
+ using ostd::Rectangle::contains;
+ bool contains(ostd::Vec2 p, bool includeBounds = false) const override;
+ void enable(bool enable = true);
+ virtual void applyTheme(const ostd::Stylesheet& theme) = 0;
+ void addThemeOverride(const ostd::String& fullKey, ostd::Stylesheet::TypeVariant value, bool propagate = true);
+ void reloadTheme(void);
+ void setThemeQualifier(const ostd::String& qualifier, bool value = true);
+ bool getThemeQualifier(const ostd::String& qualifier);
+ bool addThemeID(const ostd::String& id);
+ bool removeThemeID(const ostd::String& id);
+ inline const ostd::Stylesheet::QualifierList& getThemeQualifierList(void) const { return m_qualifierList; }
+
+ inline virtual void onDraw(ogfx::BasicRenderer2D& gfx) { }
+ inline virtual void onUpdate(void) { }
+
+ inline virtual void onMousePressed(const Event& event) { }
+ inline virtual void onMouseReleased(const Event& event) { }
+ inline virtual void onMouseMoved(const Event& event) { }
+ inline virtual void onMouseEntered(const Event& event) { }
+ inline virtual void onMouseExited(const Event& event) { }
+ inline virtual void onMouseDragged(const Event& event) { }
+ inline virtual void onKeyPressed(const Event& event) { }
+ inline virtual void onKeyReleased(const Event& event) { }
+ inline virtual void onTextEntered(const Event& event) { }
+ inline virtual void onFocusGained(const Event& event) { }
+ inline virtual void onFocusLost(const Event& event) { }
+ inline virtual void onWindowClosed(const Event& event) { }
+ inline virtual void onWindowResized(const Event& event) { }
+ inline virtual void onWindowFocused(const Event& event) { }
+ inline virtual void onWindowFocusLost(const Event& event) { }
+
+ void __draw(ogfx::BasicRenderer2D& gfx);
+ void __update(void);
+ void __onMousePressed(const Event& event);
+ void __onMouseReleased(const Event& event);
+ void __onMouseMoved(const Event& event);
+ void __onMouseEntered(const Event& event);
+ void __onMouseExited(const Event& event);
+ void __onMouseDragged(const Event& event);
+ void __onKeyPressed(const Event& event);
+ void __onKeyReleased(const Event& event);
+ void __onTextEntered(const Event& event);
+ void __onWindowClosed(const Event& event);
+ void __onWindowResized(const Event& event);
+ void __onWIndowFocused(const Event& event);
+ void __onWindowFocusLost(const Event& event);
+ void __applyTheme(const ostd::Stylesheet& theme, bool propagate);
+
+ inline virtual void setMousePressedCallback(EventCallback callback) { callback_onMousePressed = callback; }
+ inline virtual void setMouseReleasedCallback(EventCallback callback) { callback_onMouseReleased = callback; }
+ inline virtual void setMouseMovedCallback(EventCallback callback) { callback_onMouseMoved = callback; }
+ inline virtual void setMouseEnteredCallback(EventCallback callback) { callback_onMouseEntered = callback; }
+ inline virtual void setMouseExitedCallback(EventCallback callback) { callback_onMouseExited = callback; }
+ inline virtual void setMouseDraggedCallback(EventCallback callback) { callback_onMouseDragged = callback; }
+ inline virtual void setKeyPressedCallback(EventCallback callback) { callback_onKeyPressed = callback; }
+ inline virtual void setKeyReleasedCallback(EventCallback callback) { callback_onKeyReleased = callback; }
+ inline virtual void setTextEnteredCallback(EventCallback callback) { callback_onTextEntered = callback; }
+ inline virtual void setWindowClosedCallback(EventCallback callback) { callback_onWindowClosed = callback; }
+ inline virtual void setWindowResizedCallback(EventCallback callback) { callback_onWindowResized = callback; }
+ inline virtual void setWIndowFocusedCallback(EventCallback callback) { callback_onWindowFocused = callback; }
+ inline virtual void setWindowFocusLostCallback(EventCallback callback) { callback_onWindowFocusLost = callback; }
+
+ inline bool hasChildren(void) const { return m_allowChildren && m_widgets.widgetCount() > 0; }
+ inline virtual bool isInvalid(void) const override { return ostd::BaseObject::isInvalid() || (m_parent == nullptr && !m_rootChild); }
+ inline void setTabIndex(int32_t tabIndex) { m_tabIndex = tabIndex; }
+ inline int32_t getTabIndex(void) const { return m_tabIndex; }
+ inline bool isFocused(void) const { return m_focused; }
+ inline WindowCore& getWindow(void) { return *m_window; }
+ inline Widget* getParent(void) { return m_parent; }
+ inline int32_t getZIndex(void) const { return m_zIndex; }
+ inline bool isChildrenEnabled(void) const { return m_allowChildren; }
+ inline void setPadding(const ostd::Rectangle& pad) { m_padding = pad; }
+ inline Rectangle getPadding(void) const { return m_padding; }
+ inline bool isMouseInside(void) const { return m_mouseInside; }
+ inline ogfx::MouseEventData::eButton getPressedMouseButton(void) const { return m_pressedButton; }
+ inline const std::vector& getThemeIDList(void) const { return m_themeIDList; }
+ inline bool isEnabled(void) const { return m_enabled; }
+ inline bool isFocusEnabled(void) const { return m_allowFocus; }
+ inline void enableFocus(bool enable = true) { m_allowFocus = enable; }
+ inline void disableFocus(void) { enableFocus(false); }
+ inline void disabble(void) { enable(false); }
+ inline void enableStopEvents(bool enable = true) { m_stopEvents = enable; }
+
+ template
+ inline T getThemeValue(const ostd::Stylesheet &theme, const ostd::String& key, const T& fallback)
+ {
+ return theme.get(key, fallback, getThemeIDList(), getThemeQualifierList());
+ }
+
+ protected:
+ inline void disableChildren(void) { m_allowChildren = false; }
+ inline void disableDrawBox(void) { m_drawBox = false; }
+ inline void enableDrawBox(void) { m_drawBox = true; }
+ inline bool isDrawBoxEnabled(void) const { return m_drawBox; }
+ inline void setDrawBoxColor(const ostd::Color& color) { m_drawBoxColor = color; }
+ inline ostd::Color getDrawBoxColor(void) { return m_drawBoxColor; }
+
+ protected:
+ bool m_rootChild { false };
+ int32_t m_borderRadius { 10 };
+ int32_t m_borderWidth { 2 };
+ ostd::Color m_borderColor { 255, 255, 255 };
+ bool m_showBorder { false };
+
+ EventCallback callback_onMousePressed { nullptr };
+ EventCallback callback_onMouseReleased { nullptr };
+ EventCallback callback_onMouseMoved { nullptr };
+ EventCallback callback_onMouseEntered { nullptr };
+ EventCallback callback_onMouseExited { nullptr };
+ EventCallback callback_onMouseDragged { nullptr };
+ EventCallback callback_onKeyPressed { nullptr };
+ EventCallback callback_onKeyReleased { nullptr };
+ EventCallback callback_onTextEntered { nullptr };
+ EventCallback callback_onWindowClosed { nullptr };
+ EventCallback callback_onWindowResized { nullptr };
+ EventCallback callback_onWindowFocused { nullptr };
+ EventCallback callback_onWindowFocusLost { nullptr };
+
+ private:
+ WindowCore* m_window { nullptr };
+ Widget* m_parent { nullptr };
+ bool m_focused { false };
+ int32_t m_tabIndex { -1 };
+ int32_t m_zIndex { -1 };
+ WidgetManager m_widgets;
+ bool m_allowChildren { true };
+ bool m_mouseInside { false };
+ bool m_allowFocus { true };
+ bool m_enabled { true };
+ bool m_stopEvents { true };
+ bool m_clipContents { true };
+ MouseEventData::eButton m_pressedButton { MouseEventData::eButton::None };
+
+ std::vector m_themeIDList;
+ ostd::Stylesheet::QualifierList m_qualifierList {
+ { "disabled", false },
+ { "pressed", false },
+ { "hover", false },
+ { "focused", false },
+ { "active", false }
+ };
+ std::vector m_themeOverrides;
+
+ bool m_drawBox { true };
+ ostd::Color m_drawBoxColor { 255, 0, 0 };
+
+ ostd::Rectangle m_padding { 0, 0, 0, 0 };
+
+ friend class WidgetManager;
+ };
+ namespace widgets
+ {
+ class RootWidget : public Widget
+ {
+ public:
+ RootWidget(WindowCore& window);
+ void onWindowResized(const Event& event) override;
+ void applyTheme(const ostd::Stylesheet& theme) override;
+ void onDraw(ogfx::BasicRenderer2D& gfx) override;
+
+ private:
+ ostd::Color m_color { ostd::Colors::Transparent };
+ };
+ }
+ }
+}
diff --git a/src/ogfx/ogfx.hpp b/src/ogfx/ogfx.hpp
index d6d6612..f483be8 100644
--- a/src/ogfx/ogfx.hpp
+++ b/src/ogfx/ogfx.hpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/src/ogfx/render/BasicRenderer.cpp b/src/ogfx/render/BasicRenderer.cpp
index b78077f..508ece1 100644
--- a/src/ogfx/render/BasicRenderer.cpp
+++ b/src/ogfx/render/BasicRenderer.cpp
@@ -31,6 +31,50 @@ namespace ogfx
setDefaultFont();
}
+ void BasicRenderer2D::pushClippingRect(const ostd::Rectangle& rect, bool additive)
+ {
+ if (!m_initialized) return;
+
+ ostd::Rectangle finalRect = rect;
+
+ if (additive && !m_clipStack.empty())
+ finalRect = m_clipStack.back().getIntersection(rect, false);
+
+ m_clipStack.push_back(finalRect);
+
+ SDL_Rect r;
+ r.x = (int)std::round(finalRect.x);
+ r.y = (int)std::round(finalRect.y);
+ r.w = (int)std::round(finalRect.w);
+ r.h = (int)std::round(finalRect.h);
+
+ SDL_SetRenderClipRect(m_window->getSDLRenderer(), &r);
+ }
+
+ void BasicRenderer2D::popClippingRect(void)
+ {
+ if (!m_initialized) return;
+ if (m_clipStack.empty()) return;
+
+ m_clipStack.pop_back();
+
+ if (m_clipStack.empty())
+ {
+ SDL_SetRenderClipRect(m_window->getSDLRenderer(), nullptr);
+ return;
+ }
+
+ const auto& rect = m_clipStack.back();
+
+ SDL_Rect r;
+ r.x = (int)std::round(rect.x);
+ r.y = (int)std::round(rect.y);
+ r.w = (int)std::round(rect.w);
+ r.h = (int)std::round(rect.h);
+
+ SDL_SetRenderClipRect(m_window->getSDLRenderer(), &r);
+ }
+
void BasicRenderer2D::setFont(const ostd::String& fontFilePath)
{
if (!m_initialized) return;
@@ -172,24 +216,33 @@ namespace ogfx
filledCircleRGBA(m_window->getSDLRenderer(), (int32_t)std::round(center.x), (int32_t)std::round(center.y), radius, color.r, color.g, color.b, color.a);
}
- void BasicRenderer2D::outlinedRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness)
+ void BasicRenderer2D::outlinedRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness, bool outlineInward)
{
if (!m_initialized) return;
fillRect(rect, fillColor);
- drawRect(rect, outlineColor, outlineThickness);
+ float t = static_cast(outlineThickness);
+ ostd::Rectangle offset = { 0, 0, 0, 0 };
+ if (!outlineInward)
+ offset = { -t, -t, t * 2, t * 2 };
+ drawRect(rect + offset , outlineColor, outlineThickness);
}
- void BasicRenderer2D::outlinedRoundRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t radius, int32_t outlineThickness)
+ void BasicRenderer2D::outlinedRoundRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t radius, int32_t outlineThickness, bool outlineInward)
{
if (!m_initialized) return;
fillRoundRect(rect, fillColor, radius);
- drawRoundRect(rect, outlineColor, radius, outlineThickness);
+ float t = static_cast(outlineThickness);
+ ostd::Rectangle offset = { 0, 0, 0, 0 };
+ if (!outlineInward)
+ offset = { -t, -t, t * 2, t * 2 };
+ drawRoundRect(rect + offset, outlineColor, radius, outlineThickness);
}
- void BasicRenderer2D::outlinedCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness)
+ void BasicRenderer2D::outlinedCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness, bool outlineInward)
{
if (!m_initialized) return;
fillCircle(center, radius, fillColor);
+ radius = (outlineInward ? radius : radius + outlineThickness);
drawCircle(center, radius, outlineColor, outlineThickness);
}
diff --git a/src/ogfx/render/BasicRenderer.hpp b/src/ogfx/render/BasicRenderer.hpp
index 297c64f..ceb381f 100644
--- a/src/ogfx/render/BasicRenderer.hpp
+++ b/src/ogfx/render/BasicRenderer.hpp
@@ -38,6 +38,8 @@ namespace ogfx
inline ostd::IPoint getStringSize(const ostd::String str, int32_t fontSize = 0) { return m_ttfr.getStringDimensions(str, fontSize); }
inline WindowCore& getWindow(void) { return *m_window; }
inline bool isInitialized(void) { return m_initialized; }
+ void pushClippingRect(const ostd::Rectangle& rect, bool additive = false);
+ void popClippingRect(void);
void setFont(const ostd::String& fontFilePath);
void setDefaultFont(void);
void setFontSize(int32_t fontSize);
@@ -58,13 +60,14 @@ namespace ogfx
void fillRoundRect(const ostd::Rectangle& rect, const ostd::Color& color, int32_t radius);
void fillCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& color);
- void outlinedRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1);
- void outlinedRoundRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t radius, int32_t outlineThickness = 1);
- void outlinedCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1);
+ void outlinedRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1, bool outlineInward = true);
+ void outlinedRoundRect(const ostd::Rectangle& rect, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t radius, int32_t outlineThickness = 1, bool outlineInward = true);
+ void outlinedCircle(const ostd::Vec2& center, int32_t radius, const ostd::Color& fillColor, const ostd::Color& outlineColor, int32_t outlineThickness = 1, bool outlineInward = true);
private:
TTFRenderer m_ttfr;
WindowCore* m_window { nullptr };
bool m_initialized { false };
+ std::vector m_clipStack;
};
}
diff --git a/src/ostd/math/Geometry.hpp b/src/ostd/math/Geometry.hpp
index 8519cf2..3e9640e 100755
--- a/src/ostd/math/Geometry.hpp
+++ b/src/ostd/math/Geometry.hpp
@@ -268,6 +268,23 @@ namespace ostd
inline Rectangle(Vec2 position, Vec2 size) { x = position.x; y = position.y; w = size.x; h = size.y; }
virtual ~Rectangle(void) = default;
+ inline bool operator==(const Rectangle& op2) const { return x == op2.x && y == op2.y && w == op2.w && h == op2.h; }
+ inline bool operator!=(const Rectangle& op2) const { return !(*this == op2); }
+ inline Rectangle operator+(const Rectangle& op2) const { return { x + op2.x, y + op2.y, w + op2.w, h + op2.h }; }
+ inline Rectangle operator-(const Rectangle& op2) const { return { x - op2.x, y - op2.y, w - op2.w, h - op2.h }; }
+ inline Rectangle operator+(float s) const { return { x + s, y + s, w + s, h + s }; }
+ inline Rectangle operator-(float s) const { return { x - s, y - s, w - s, h - s }; }
+ inline Rectangle operator*(float s) const { return { x * s, y * s, w * s, h * s }; }
+ inline Rectangle operator/(float s) const { return { x / s, y / s, w / s, h / s }; }
+ inline Rectangle& operator=(const Rectangle& r) { x = r.x; y = r.y; w = r.w; h = r.h; return *this; }
+ inline Rectangle& operator=(float s) { x = s; y = s; w = s; h = s; return *this; }
+ inline Rectangle& operator+=(const Rectangle& op2) { x += op2.x; y += op2.y; w += op2.w; h += op2.h; return *this; }
+ inline Rectangle& operator-=(const Rectangle& op2) { x -= op2.x; y -= op2.y; w -= op2.w; h -= op2.h; return *this; }
+ inline Rectangle& operator+=(float s) { x += s; y += s; w += s; h += s; return *this; }
+ inline Rectangle& operator-=(float s) { x -= s; y -= s; w -= s; h -= s; return *this; }
+ inline Rectangle& operator*=(float s) { x *= s; y *= s; w *= s; h *= s; return *this; }
+ inline Rectangle& operator/=(float s) { x /= s; y /= s; w /= s; h /= s; return *this; }
+
inline virtual float getx(void) const { return x; }
inline virtual float gety(void) const { return y; }
inline virtual float getw(void) const { return w; }
diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp
index 0f529de..4e9fd5a 100644
--- a/src/test/GuiTest.cpp
+++ b/src/test/GuiTest.cpp
@@ -18,26 +18,6 @@
along with OmniaFramework. If not, see .
*/
-
-
-
-/*
- * --- Label
- * Button
- * Panel / Container
- * Checkbox
- * Radio Button (Group)
- * Text Input
- * Horizontal Slider
- * Image / Icon
- * ScrollView
- * ListBox
- * ComboBox
- * TreeView
- * Save/Open File Dialogs (and folder dialogs)
- * Tab Panel
- */
-
#include
#include
@@ -60,6 +40,10 @@ class Window : public ogfx::gui::Window
pos = pos2;
});
+
+ m_panel2.setSize(300, 140);
+ m_panel2.setPosition(130, 200);
+
m_label1.setPosition(100, 200);
m_label1.setText("Hello World!");
m_label1.setMousePressedCallback([&](const ogfx::gui::Event& event) -> void {
@@ -67,9 +51,9 @@ class Window : public ogfx::gui::Window
});
addWidget(m_label1);
addWidget(m_panel1);
- // m_label1.setThemeQualifier("disabled");
+ addWidget(m_panel2);
- m_label2.setPosition(10, 10);
+ m_label2.setPosition(0, 0);
m_label2.setText("Ciccia Bella!");
m_label2.addThemeID("testLabel");
m_label2.addThemeID("testLabel2");
@@ -78,14 +62,16 @@ class Window : public ogfx::gui::Window
m_label1.addThemeOverride("@:pressed.label.textColor", ostd::Colors::Crimson);
m_theme.loadFromFile("./testTheme.txt");
- setTheme(m_theme);
m_label2.addThemeOverride("@:hover.label.showBackground", true);
m_label2.addThemeOverride("@:hover.label.backgroundColor", ostd::Colors::DarkGreen);
- m_theme.debugPrint();
- m_label2.reloadTheme();
- m_theme.debugPrint();
+ m_label3.setPosition(0, 30);
+ m_label3.setText("Bella!");
+ m_label3.addThemeID("label3");
+ m_panel1.addChild(m_label3);
+
+ setTheme(m_theme);
}
inline void onSignal(ostd::Signal& signal) override
@@ -106,7 +92,9 @@ class Window : public ogfx::gui::Window
private:
ogfx::gui::widgets::Label m_label1 { *this };
ogfx::gui::widgets::Label m_label2 { *this };
+ ogfx::gui::widgets::Label m_label3 { *this };
ogfx::gui::widgets::Panel m_panel1 { *this };
+ ogfx::gui::widgets::Panel m_panel2 { *this };
ostd::Stylesheet m_theme;
ostd::Vec2 pos { 0, 0 };
};