Added RadioButton widget + RadioButtonGroup

This commit is contained in:
OmniaX-Dev 2026-04-22 17:05:25 +02:00
parent ffe9d7ca1a
commit 1c9d0b5ab9
14 changed files with 24834 additions and 9573 deletions

View file

@ -93,6 +93,7 @@ list(APPEND OGFX_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/CheckBox.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Scrollbar.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/Button.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/gui/widgets/RadioButton.cpp
# render
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/render/BasicRenderer.cpp
@ -101,7 +102,7 @@ list(APPEND OGFX_SOURCE_FILES
# resources
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/resources/Image.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/resources/UbuntuMonoRegularTTF.cpp
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/resources/UbuntuTTF.cpp
# utils
${CMAKE_CURRENT_LIST_DIR}/src/ogfx/utils/Animation.cpp

View file

@ -138,6 +138,35 @@ const $accentColorDark = #6B0A1DFF
% ====== RadioButton ======
(radioButton) {
innerCircleColor = $accentColorDark
outerCircleColor = $accentColor
outerCircleBorderWidth = 2
textColor = $textColor
fontSize = 20
showBackground = false
showBorder = false
padding = rect(15, 15, 15, 15)
margin = rect(0, 0, 0, 0)
}
(radioButton:hover) {
outerCircleColor = $accentColorLight
}
(radioButton:pressed) {
outerCircleColor = $accentColor
textColor = $accentColorDark
innerCircleColor = $accentColor
}
(radioButton:active) {
innerCircleColor = $accentColor
outerCircleColor = $accentColor
textColor = $accentColorDark
}
% =========================
% ====== Label ======
(label) {
textColor = $textColor

View file

@ -28,6 +28,7 @@ Add Dark Mode Default theme
FIX: Float values in stylesheet needing to have decimal point to be read as float
Make parsing of vec2 and rect in stylesheet, consistent with other value functions like gradients and animations
Add buttons to scroll tabs in TabPanel
Add Font class, to handle different font attributes
@ -43,8 +44,8 @@ Implement following widgets:
***Image/Icon
***Save/Open File Dialogs (and folder dialogs)
***Tooltips
Radio Button
Grouping
***Radio Button
***Grouping
Progressbar
Horizontal Slider
Vertical Slider

View file

@ -25,3 +25,4 @@
#include <ogfx/gui/widgets/CheckBox.hpp>
#include <ogfx/gui/widgets/Scrollbar.hpp>
#include <ogfx/gui/widgets/Button.hpp>
#include <ogfx/gui/widgets/RadioButton.hpp>

View file

@ -31,7 +31,7 @@ namespace ogfx
{
setText(text);
setPadding({ 5, 5, 5, 5 });
setTypeName("ogfx::gui::widgets::Label");
setTypeName("ogfx::gui::widgets::CheckBox");
disableChildren();
enableBackground(false);
setStylesheetCategoryName("checkbox");

View file

@ -0,0 +1,142 @@
/*
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 "RadioButton.hpp"
#include "../../render/BasicRenderer.hpp"
namespace ogfx
{
namespace gui
{
namespace widgets
{
RadioButton& RadioButton::create(RadioButtonGroup& group, const String& text)
{
m_radioGroup = &group;
setText(text);
setPadding({ 5, 5, 5, 5 });
setTypeName("ogfx::gui::widgets::RadioButton");
disableChildren();
enableBackground(false);
setStylesheetCategoryName("radioButton");
validate();
return *this;
}
void RadioButton::applyTheme(const ostd::Stylesheet& theme)
{
setInnerCircleColor(getThemeValue<Color>(theme, "innerCircleColor", m_innerCircleColor));
setOuterCircleColor(getThemeValue<Color>(theme, "outerCircleColor", m_outerCircleColor));
m_outerCircleBorderWidth = getThemeValue<i32>(theme, "outerCircleBorderWidth", m_outerCircleBorderWidth);
}
void RadioButton::onMouseReleased(const Event& event)
{
if (!isMouseInside())
return;
if (m_radioGroup == nullptr)
return;
m_radioGroup->set_selected(*this);
}
void RadioButton::onDraw(ogfx::BasicRenderer2D& gfx)
{
if (m_textChanged)
__update_size(gfx);
gfx.drawCircle({ getGlobalContentPosition() + Vec2 { 0, 4 }, m_circleSize }, getOuterCircleColor(), getOuterCircleBorderWidth());
if (isSelected())
gfx.fillCircle({ getGlobalContentPosition() + Vec2 { 3, 7 }, m_circleSize - 6 }, getInnerCircleColor());
gfx.drawString(getText(), getGlobalContentPosition() + Vec2 { m_circleSize.x + m_spacing, 0 }, getTextColor(), getFontSize());
}
void RadioButton::setText(const String& text)
{
m_text = text;
m_textChanged = true;
}
void RadioButton::__update_size(ogfx::BasicRenderer2D& gfx)
{
auto size = gfx.getStringDimensions(getText(), getFontSize());
m_circleSize = { cast<f32>(size.y - 6), cast<f32>(size.y - 6) };
size.x += m_spacing + m_circleSize.x;
size.x += getPadding().left();
size.x += getPadding().right();
size.y += getPadding().top();
size.y += getPadding().bottom();
setSize({ cast<f32>(size.x), cast<f32>(size.y) });
m_textChanged = false;
}
void RadioButton::__set_selected(bool selected)
{
if (m_selected == selected)
return;
m_selected = selected;
setThemeQualifier("active", m_selected);
}
RadioButtonGroup::RadioButtonGroup(void)
{
}
RadioButton& RadioButtonGroup::addButton(Widget& parent, const String& text, const Vec2& position)
{
m_buttons.push_back(std::unique_ptr<RadioButton>(
new RadioButton(parent.getWindow(), *this, text)
));
auto& btn = *m_buttons.back();
parent.addWidget(btn, position);
if (m_buttons.size() == 1)
set_selected(btn);
return btn;
}
void RadioButtonGroup::set_selected(RadioButton& sender)
{
if (is_button_present(sender))
{
unselect_all();
m_selected = &sender;
m_selected->__set_selected(true);
return;
}
}
bool RadioButtonGroup::is_button_present(RadioButton& button)
{
for (auto& btn : m_buttons)
if (btn.get() == &button)
return true;
return false;
}
void RadioButtonGroup::unselect_all(void)
{
for (auto& btn : m_buttons)
btn->__set_selected(false);
}
}
}
}

View file

@ -0,0 +1,83 @@
/*
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 RadioButtonGroup;
class RadioButton : public Widget
{
public:
void applyTheme(const ostd::Stylesheet& theme) override;
void onMouseReleased(const Event& event) override;
void onDraw(ogfx::BasicRenderer2D& gfx) override;
void setText(const String& text);
inline String getText(void) const { return m_text; }
inline bool isSelected(void) const { return m_selected; }
OSTD_PARAM_GETSET(i32, OuterCircleBorderWidth, m_outerCircleBorderWidth);
OSTD_PARAM_GETSET(Color, InnerCircleColor, m_innerCircleColor);
OSTD_PARAM_GETSET(Color, OuterCircleColor, m_outerCircleColor);
private:
inline RadioButton(WindowCore& window, RadioButtonGroup& group, const String& text) : Widget({ 0, 0, 0, 0 }, window) { create(group, text); }
RadioButton& create(RadioButtonGroup& group, const String& text);
void __update_size(ogfx::BasicRenderer2D& gfx);
void __set_selected(bool selected);
private:
RadioButtonGroup* m_radioGroup { nullptr };
Vec2 m_circleSize { 0, 0 };
bool m_selected { false };
String m_text { "" };
bool m_textChanged { false };
f32 m_spacing { 6 };
i32 m_outerCircleBorderWidth { 1 };
Color m_innerCircleColor { 255, 255, 255 };
Color m_outerCircleColor { 255, 255, 255 };
friend class RadioButtonGroup;
};
class RadioButtonGroup
{
public:
RadioButtonGroup(void);
RadioButton& addButton(Widget& parent, const String& text, const Vec2& position = { 0, 0 });
private:
void set_selected(RadioButton& sender);
bool is_button_present(RadioButton& button);
void unselect_all(void);
private:
stdvec<std::unique_ptr<RadioButton>> m_buttons;
RadioButton* m_selected { nullptr };
friend class RadioButton;
};
}
}
}

View file

@ -20,7 +20,7 @@
#include "BasicRenderer.hpp"
#include "../gui/Window.hpp"
#include "../resources/UbuntuMonoRegularTTF.hpp"
#include "../resources/UbuntuTTF.hpp"
#include "../gui/Window.hpp"
#define COLOR_CAST(ostd_color) std::bit_cast<SDL_FColor>(ostd_color.getNormalizedColor())
@ -152,11 +152,16 @@ namespace ogfx
SDL_SetRenderClipRect(m_window->getSDLRenderer(), &r);
}
i32 BasicRenderer2D::loadDefaultFont(i32 fontSize)
i32 BasicRenderer2D::loadDefaultMonoFont(i32 fontSize)
{
return openFont(ubuntu_mono_regular_ttf_data, ubuntu_mono_regular_ttf_size, fontSize);
}
i32 BasicRenderer2D::loadDefaultFont(i32 fontSize)
{
return openFont(ubuntu_regular_ttf_data, ubuntu_regular_ttf_size, fontSize);
}
void BasicRenderer2D::closeFont(void)
{
if (!m_initialized || !m_fontOpen) return;

View file

@ -63,6 +63,7 @@ namespace ogfx
void endFrame(void);
void pushClippingRect(const Rectangle& rect, bool additive = false);
void popClippingRect(void);
i32 loadDefaultMonoFont(i32 fontSize = 0);
i32 loadDefaultFont(i32 fontSize = 0);
void closeFont(void);
i32 openFont(const String& fontPath, i32 fontSize = 0);

File diff suppressed because it is too large Load diff

View file

@ -1,29 +0,0 @@
/*
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 <ostd/data/Types.hpp>
namespace ogfx
{
extern const u32 ubuntu_mono_regular_ttf_size;
extern const ostd::UByte ubuntu_mono_regular_ttf_data[];
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
/*
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 <ostd/data/Types.hpp>
namespace ogfx
{
// Ubuntu Mono Regular
extern const u32 ubuntu_mono_regular_ttf_size;
extern const ostd::UByte ubuntu_mono_regular_ttf_data[];
// Ubuntu Regular
extern const u32 ubuntu_regular_ttf_size;
extern const ostd::UByte ubuntu_regular_ttf_data[];
}

View file

@ -112,6 +112,9 @@ class Window : public ogfx::gui::Window
t3.addThemeOverride("@panel_tab.panel.backgroundColor", Colors::Orange);
t1.addWidget(m_check1, { 30, 30 });
m_radioGroup.addButton(t1, "Radio this out!", { 30, 80 });
m_radioGroup.addButton(t1, "Radio Opt. 2", { 30, 110 });
m_radioGroup.addButton(t1, "Radio 3", { 30, 140 });
t2.addWidget(m_panel2, { 500, 100 });
m_panel3.addWidget(m_label4);
@ -126,8 +129,6 @@ class Window : public ogfx::gui::Window
m_panel2.addWidget(m_btn1, { 0, 300 });
m_panel2.addWidget(m_img, { 20, 50 });
addWidget(m_tabs, { 0, 0 });
m_theme.loadFromFile("./DefaultTheme.oss", true, getDefaultStylesheetVariableList());
@ -166,6 +167,7 @@ class Window : public ogfx::gui::Window
Button m_btn1 { *this };
ImageLabel m_img { *this };
TabPanel m_tabs { *this };
RadioButtonGroup m_radioGroup;
ostd::Stylesheet m_theme;
};