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

@ -1,301 +1,24 @@
/* /*
OmniaFramework - A collection of useful functionality OmniaFramework - A collection of useful functionality
Copyright (C) 2025 OmniaX-Dev 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 OmniaFramework is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
OmniaFramework is distributed in the hope that it will be useful, OmniaFramework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>. along with OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
*/ */
#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,8 +193,20 @@ 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;
}
} }
} }
@ -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 };
}; };