Added Basic Panel widget

This commit is contained in:
OmniaX-Dev 2026-04-06 06:48:33 +02:00
parent c695c0ad85
commit 260c7054bc
19 changed files with 722 additions and 426 deletions

View file

@ -1,2 +1,3 @@
CompileFlags: CompileFlags:
CompilationDatabase: bin CompilationDatabase: bin
Add: ["--target=x86_64-w64-mingw32"]

View file

@ -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/RawTextInput.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/Window.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/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 # render
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp ${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp

View file

@ -21,9 +21,9 @@ window.backgroundColor = Color(rgba(120, 120, 120, 255))
(panel) { (panel) {
backgroundColor = Color(#AAAAAAFF) backgroundColor = Color(#AAAAAAFF)
borderColor = Color(#000000FF) borderColor = Color(#00FF00FF)
borderRadius = 8 borderRadius = 8
borderWidth = 2 borderWidth = 4
showBorder = true showBorder = true
padding = Rect(15, 15, 15, 15) padding = Rect(15, 15, 15, 15)
} }
@ -42,6 +42,11 @@ window.backgroundColor = Color(rgba(120, 120, 120, 255))
borderColor = Color(#208080FF) borderColor = Color(#208080FF)
} }
% (@testLabel2 label:pressed [mouseButton=left or mouseButton=right]) {
% ...
(@testLabel2 label:pressed) { (@testLabel2 label:pressed) {
showBackground = true showBackground = true
} }
@ -70,4 +75,13 @@ window.backgroundColor = Color(rgba(120, 120, 120, 255))
%borderColor = Color(#000000FF) %borderColor = Color(#000000FF)
} }
(@label3 label) {
textColor = $color2
backgroundColor = Color(#000000FF)
fontSize = 20
borderColor = Color(#FF0000FF)
borderWidth = 4
borderRadius = 15
}
% =================================================== % ===================================================

View file

@ -3,3 +3,30 @@
***Fix mouse detection currently using local coordinates ***Fix mouse detection currently using local coordinates
***implement file theme loading ***implement file theme loading
***Implemenmt MouseDragged callback ***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

View file

@ -1 +1 @@
2046 2049

View file

@ -58,11 +58,13 @@ cp -r ../src/ostd/vendor/nlohmann $RELEASE_DIR/include/ostd/vendor/
# OGFX # OGFX
mkdir -p $RELEASE_DIR/include/ogfx/vendor/sdl3_gfx mkdir -p $RELEASE_DIR/include/ogfx/vendor/sdl3_gfx
mkdir -p $RELEASE_DIR/include/ogfx/gui 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/render
mkdir -p $RELEASE_DIR/include/ogfx/resources mkdir -p $RELEASE_DIR/include/ogfx/resources
mkdir -p $RELEASE_DIR/include/ogfx/utils mkdir -p $RELEASE_DIR/include/ogfx/utils
find ../src/ogfx -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx \; 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 -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/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/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 \; find ../src/ogfx/utils -maxdepth 1 -name "*.h*" -exec cp {} $RELEASE_DIR/include/ogfx/utils \;

View file

@ -20,282 +20,5 @@
#pragma once #pragma once
#include "gui/Events.hpp" #include <ogfx/gui/widgets/Containers.hpp>
#include <ostd/data/BaseObject.hpp> #include <ogfx/gui/widgets/Label.hpp>
#include <ostd/math/Geometry.hpp>
#include <ostd/data/Color.hpp>
#include <ostd/io/Stylesheet.hpp>
#include <ostd/utils/Time.hpp>
#include <functional>
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<Widget*> 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<void(const Event&)>;
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<ostd::String>& 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<typename T>
inline T getThemeValue(const ostd::Stylesheet &theme, const ostd::String& key, const T& fallback)
{
return theme.get<T>(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<ostd::String> m_themeIDList;
ostd::Stylesheet::QualifierList m_qualifierList {
{ "disabled", false },
{ "pressed", false },
{ "hover", false },
{ "focused", false },
{ "active", false }
};
std::vector<ThemeOverride> 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 };
};
}
}
}

View file

@ -25,7 +25,7 @@
#include <ostd/utils/Time.hpp> #include <ostd/utils/Time.hpp>
#include <ostd/io/IOHandlers.hpp> #include <ostd/io/IOHandlers.hpp>
#include <ogfx/gui/Events.hpp> #include <ogfx/gui/Events.hpp>
#include <ogfx/gui/Widgets.hpp> #include <ogfx/gui/widgets/Widget.hpp>
#include <ogfx/render/BasicRenderer.hpp> #include <ogfx/render/BasicRenderer.hpp>
#include <ogfx/gui/WindowOutputHandler.hpp> #include <ogfx/gui/WindowOutputHandler.hpp>

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#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<ostd::Color>(theme, "panel.backgroundColor", ostd::Colors::Gray));
m_borderRadius = getThemeValue<int32_t>(theme, "panel.borderRadius", 8);
m_borderWidth = getThemeValue<int32_t>(theme, "panel.borderWidth", 2);
m_showBorder = getThemeValue<bool>(theme, "panel.showBorder", true);
m_borderColor = getThemeValue<ostd::Color>(theme, "panel.borderColor", ostd::Colors::Black);
setPadding(getThemeValue<ostd::Rectangle>(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);
}
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <ogfx/gui/widgets/Widget.hpp>
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 };
};
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#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<ostd::Color>(theme, "label.textColor", ostd::Colors::White));
setBackGroundColor(getThemeValue<ostd::Color>(theme, "label.backgroundColor", ostd::Colors::Transparent));
setFontSize(getThemeValue<int32_t>(theme, "label.fontSize", 20));
m_borderRadius = getThemeValue<int32_t>(theme, "label.borderRadius", 10);
m_borderWidth = getThemeValue<int32_t>(theme, "label.borderWidth", 2);
m_showBorder = getThemeValue<bool>(theme, "label.showBorder", false);
m_borderColor = getThemeValue<ostd::Color>(theme, "label.borderColor", ostd::Colors::White);
enableBackground(getThemeValue<bool>(theme, "label.showBackground", false));
setPadding(getThemeValue<ostd::Rectangle>(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<float>(size.x), static_cast<float>(size.y) });
m_textChanged = false;
}
}
}
}

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <ogfx/gui/widgets/Widget.hpp>
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:
};
}
}
}

View file

@ -18,12 +18,12 @@
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>. along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "Widgets.hpp" #include "Widget.hpp"
#include "gui/Events.hpp" #include "gui/Events.hpp"
#include "io/Memory.hpp" #include "io/Memory.hpp"
#include "utils/Keycodes.hpp" #include "utils/Keycodes.hpp"
#include <ogfx/render/BasicRenderer.hpp> #include "../..//render/BasicRenderer.hpp"
#include <ogfx/gui/Window.hpp> #include "../Window.hpp"
namespace ogfx namespace ogfx
{ {
@ -107,7 +107,9 @@ namespace ogfx
{ {
if (w == nullptr) continue; if (w == nullptr) continue;
if (w->isInvalid()) continue; if (w->isInvalid()) continue;
gfx.pushClippingRect({ w->getGlobalPosition(), w->getSize() }, true);
w->__draw(gfx); w->__draw(gfx);
gfx.popClippingRect();
} }
} }
@ -142,7 +144,7 @@ namespace ogfx
continue; continue;
w->__onMousePressed(event); w->__onMousePressed(event);
m_mousePressedOnWidget = w; m_mousePressedOnWidget = w;
if (event.isHandled()) if (event.isHandled() || w->m_stopEvents)
break; break;
} }
} }
@ -191,10 +193,22 @@ namespace ogfx
else else
w->__onMouseMoved(event); 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; break;
} }
} }
}
void WidgetManager::onMouseDragged(const Event& event) void WidgetManager::onMouseDragged(const Event& event)
{ {
@ -291,6 +305,7 @@ namespace ogfx
{ {
if (!m_allowChildren) if (!m_allowChildren)
return false; return false;
child.reloadTheme();
return m_widgets.addWidget(child); return m_widgets.addWidget(child);
} }
@ -298,10 +313,32 @@ namespace ogfx
{ {
ostd::Vec2 glob = getPosition(); ostd::Vec2 glob = getPosition();
if (!m_rootChild && m_parent != nullptr) if (!m_rootChild && m_parent != nullptr)
glob += m_parent->getGlobalPosition(); glob += m_parent->getGlobalPosition() + m_parent->getPadding().getPosition();
return glob; 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 bool Widget::contains(ostd::Vec2 p, bool includeBounds) const
{ {
return ostd::Rectangle(getGlobalPosition(), getSize()).contains(p, includeBounds); return ostd::Rectangle(getGlobalPosition(), getSize()).contains(p, includeBounds);
@ -594,94 +631,6 @@ namespace ogfx
{ {
gfx.fillRect({ 0, 0, static_cast<float>(getWindow().getWindowWidth()), static_cast<float>(getWindow().getWindowHeight()) }, m_color); gfx.fillRect({ 0, 0, static_cast<float>(getWindow().getWindowWidth()), static_cast<float>(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<ostd::Color>(theme, "label.textColor", ostd::Colors::White));
setBackGroundColor(getThemeValue<ostd::Color>(theme, "label.backgroundColor", ostd::Colors::Transparent));
setFontSize(getThemeValue<int32_t>(theme, "label.fontSize", 20));
m_borderRadius = getThemeValue<int32_t>(theme, "label.borderRadius", 10);
m_borderWidth = getThemeValue<int32_t>(theme, "label.borderWidth", 2);
m_showBorder = getThemeValue<bool>(theme, "label.showBorder", false);
m_borderColor = getThemeValue<ostd::Color>(theme, "label.borderColor", ostd::Colors::White);
enableBackground(getThemeValue<bool>(theme, "label.showBackground", false));
setPadding(getThemeValue<ostd::Rectangle>(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<float>(size.x), static_cast<float>(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<ostd::Color>(theme, "panel.backgroundColor", ostd::Colors::Gray));
m_borderRadius = getThemeValue<int32_t>(theme, "panel.borderRadius", 8);
m_borderWidth = getThemeValue<int32_t>(theme, "panel.borderWidth", 2);
m_showBorder = getThemeValue<bool>(theme, "panel.showBorder", true);
m_borderColor = getThemeValue<ostd::Color>(theme, "panel.borderColor", ostd::Colors::Black);
setPadding(getThemeValue<ostd::Rectangle>(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);
}
} }
} }
} }

View file

@ -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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <ogfx/gui/Events.hpp>
#include <ostd/data/BaseObject.hpp>
#include <ostd/math/Geometry.hpp>
#include <ostd/data/Color.hpp>
#include <ostd/io/Stylesheet.hpp>
#include <ostd/utils/Time.hpp>
#include <functional>
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<Widget*> 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<void(const Event&)>;
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<ostd::String>& 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<typename T>
inline T getThemeValue(const ostd::Stylesheet &theme, const ostd::String& key, const T& fallback)
{
return theme.get<T>(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<ostd::String> m_themeIDList;
ostd::Stylesheet::QualifierList m_qualifierList {
{ "disabled", false },
{ "pressed", false },
{ "hover", false },
{ "focused", false },
{ "active", false }
};
std::vector<ThemeOverride> 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 };
};
}
}
}

View file

@ -25,6 +25,7 @@
#include <ogfx/gui/RawTextInput.hpp> #include <ogfx/gui/RawTextInput.hpp>
#include <ogfx/gui/Window.hpp> #include <ogfx/gui/Window.hpp>
#include <ogfx/gui/WindowOutputHandler.hpp> #include <ogfx/gui/WindowOutputHandler.hpp>
#include <ogfx/gui/Widgets.hpp>
#include <ogfx/render/BasicRenderer.hpp> #include <ogfx/render/BasicRenderer.hpp>
#include <ogfx/render/PixelRenderer.hpp> #include <ogfx/render/PixelRenderer.hpp>

View file

@ -31,6 +31,50 @@ namespace ogfx
setDefaultFont(); 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) void BasicRenderer2D::setFont(const ostd::String& fontFilePath)
{ {
if (!m_initialized) return; 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); 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; if (!m_initialized) return;
fillRect(rect, fillColor); fillRect(rect, fillColor);
drawRect(rect, outlineColor, outlineThickness); float t = static_cast<float>(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; if (!m_initialized) return;
fillRoundRect(rect, fillColor, radius); fillRoundRect(rect, fillColor, radius);
drawRoundRect(rect, outlineColor, radius, outlineThickness); float t = static_cast<float>(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; if (!m_initialized) return;
fillCircle(center, radius, fillColor); fillCircle(center, radius, fillColor);
radius = (outlineInward ? radius : radius + outlineThickness);
drawCircle(center, radius, outlineColor, outlineThickness); drawCircle(center, radius, outlineColor, outlineThickness);
} }

View file

@ -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 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 WindowCore& getWindow(void) { return *m_window; }
inline bool isInitialized(void) { return m_initialized; } 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 setFont(const ostd::String& fontFilePath);
void setDefaultFont(void); void setDefaultFont(void);
void setFontSize(int32_t fontSize); 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 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 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 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); 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); 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: private:
TTFRenderer m_ttfr; TTFRenderer m_ttfr;
WindowCore* m_window { nullptr }; WindowCore* m_window { nullptr };
bool m_initialized { false }; bool m_initialized { false };
std::vector<ostd::Rectangle> m_clipStack;
}; };
} }

View file

@ -268,6 +268,23 @@ namespace ostd
inline Rectangle(Vec2 position, Vec2 size) { x = position.x; y = position.y; w = size.x; h = size.y; } inline Rectangle(Vec2 position, Vec2 size) { x = position.x; y = position.y; w = size.x; h = size.y; }
virtual ~Rectangle(void) = default; 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 getx(void) const { return x; }
inline virtual float gety(void) const { return y; } inline virtual float gety(void) const { return y; }
inline virtual float getw(void) const { return w; } inline virtual float getw(void) const { return w; }

View file

@ -18,26 +18,6 @@
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>. along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/ */
/*
* --- 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 <ogfx/utils/Keycodes.hpp> #include <ogfx/utils/Keycodes.hpp>
#include <ogfx/ogfx.hpp> #include <ogfx/ogfx.hpp>
@ -60,6 +40,10 @@ class Window : public ogfx::gui::Window
pos = pos2; pos = pos2;
}); });
m_panel2.setSize(300, 140);
m_panel2.setPosition(130, 200);
m_label1.setPosition(100, 200); m_label1.setPosition(100, 200);
m_label1.setText("Hello World!"); m_label1.setText("Hello World!");
m_label1.setMousePressedCallback([&](const ogfx::gui::Event& event) -> void { m_label1.setMousePressedCallback([&](const ogfx::gui::Event& event) -> void {
@ -67,9 +51,9 @@ class Window : public ogfx::gui::Window
}); });
addWidget(m_label1); addWidget(m_label1);
addWidget(m_panel1); 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.setText("Ciccia Bella!");
m_label2.addThemeID("testLabel"); m_label2.addThemeID("testLabel");
m_label2.addThemeID("testLabel2"); m_label2.addThemeID("testLabel2");
@ -78,14 +62,16 @@ class Window : public ogfx::gui::Window
m_label1.addThemeOverride("@:pressed.label.textColor", ostd::Colors::Crimson); m_label1.addThemeOverride("@:pressed.label.textColor", ostd::Colors::Crimson);
m_theme.loadFromFile("./testTheme.txt"); m_theme.loadFromFile("./testTheme.txt");
setTheme(m_theme);
m_label2.addThemeOverride("@:hover.label.showBackground", true); m_label2.addThemeOverride("@:hover.label.showBackground", true);
m_label2.addThemeOverride("@:hover.label.backgroundColor", ostd::Colors::DarkGreen); 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 inline void onSignal(ostd::Signal& signal) override
@ -106,7 +92,9 @@ class Window : public ogfx::gui::Window
private: private:
ogfx::gui::widgets::Label m_label1 { *this }; ogfx::gui::widgets::Label m_label1 { *this };
ogfx::gui::widgets::Label m_label2 { *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_panel1 { *this };
ogfx::gui::widgets::Panel m_panel2 { *this };
ostd::Stylesheet m_theme; ostd::Stylesheet m_theme;
ostd::Vec2 pos { 0, 0 }; ostd::Vec2 pos { 0, 0 };
}; };