Added Panel title

This commit is contained in:
OmniaX-Dev 2026-04-15 21:00:39 +02:00
parent e8d13b931e
commit 84c4c2eb88
10 changed files with 347 additions and 137 deletions

View file

@ -1,17 +1,17 @@
% ================== testTheme.txt ================== % ================== testTheme.txt ==================
% ---- Variables ---- % ---- Variables ----
$accentColor = Color(rgba(255, 0, 255, 255)) $accentColor = rgba(255, 0, 255, 255)
const $color2 = Color(#0000FFFF) const $color2 = #0000FFFF
% ------------------- % -------------------
window.backgroundColor = Color(rgba(160, 160, 160, 255)) window.backgroundColor = rgba(160, 160, 160, 255)
$accentColor = Color(rgb(255, 0, 0)) $accentColor = rgb(255, 0, 0)
(label) { (label) {
textColor = $accentColor textColor = $accentColor
backgroundColor = Color(#000000FF) backgroundColor = #000000FF
borderColor = $accentColor borderColor = $accentColor
fontSize = 20 fontSize = 20
borderRadius = 0 borderRadius = 0
@ -46,26 +46,30 @@ $accentColor = Color(rgb(255, 0, 0))
} }
(checkbox:active) { (checkbox:active) {
textColor = Color(#000050FF) textColor = #000050FF
} }
(panel) { (panel) {
backgroundColor = Color(#AAAAAAFF) backgroundColor = #AAAAAAFF
borderColor = Color(#000000FF) borderColor = color_black
borderRadius = 8 borderRadius = 10
borderWidth = 4 borderWidth = 2
showBorder = true showBorder = true
showBackground = true showBackground = true
padding = Rect(15, 15, 15, 15) padding = Rect(15, 15, 15, 15)
showTitle = true titleColor = #444444FF
titleColor = Color(#000000FF) titlebarColor = #999999FF
titlebarType = "full" titlebarBorderColor = #909090FF
titleHeight = 30 titlebarBorderWidth = 2
titlebarType = full
titlebarHeight = 18
titlebarFontSize = 18
titlebarTextAlign = text_left
} }
(@testLabel label) { (@testLabel label) {
textColor = $color2 textColor = $color2
backgroundColor = Color(#000000FF) backgroundColor = #000000FF
fontSize = 50 fontSize = 50
} }
@ -75,7 +79,7 @@ $accentColor = Color(rgb(255, 0, 0))
} }
(@testLabel2 label:hover) { (@testLabel2 label:hover) {
borderColor = Color(#208080FF) borderColor = #208080FF
} }
(@testLabel2 label:pressed) { (@testLabel2 label:pressed) {
@ -84,7 +88,7 @@ $accentColor = Color(rgb(255, 0, 0))
(label:hover) { (label:hover) {
textColor = color_green textColor = color_green
borderColor = Color(rgb(0, 255, 0)) borderColor = rgb(0, 255, 0)
} }
(label:pressed) { (label:pressed) {
@ -97,19 +101,19 @@ $accentColor = Color(rgb(255, 0, 0))
(@testLabel label:pressed) { (@testLabel label:pressed) {
backgroundColor = color_firebrick backgroundColor = color_firebrick
textColor = Color(#505050FF) textColor = #505050FF
} }
(label:disabled) { (label:disabled) {
backgroundColor = Color(#EEEEEEFF) backgroundColor = #EEEEEEFF
%textColor = Color(#505050FF) %textColor = #505050FF
%borderColor = Color(#000000FF) %borderColor = #000000FF
} }
(@label3 label) { (@label3 label) {
textColor = $color2 textColor = $color2
backgroundColor = Color(#000000FF) backgroundColor = #000000FF
borderColor = Color(#FF0000FF) borderColor = #FF0000FF
borderWidth = 4 borderWidth = 4
borderRadius = 15 borderRadius = 15
} }

View file

@ -16,10 +16,10 @@
***Implement wrappers in Renderer2D to take a center and size for rects ***Implement wrappers in Renderer2D to take a center and size for rects
***find a way to add fixed update to gui::Window ***find a way to add fixed update to gui::Window
***Add triangle drawing functions to BasicRenderer2D ***Add triangle drawing functions to BasicRenderer2D
***Implement Panel title
Add theme caching Add theme caching
Implement global scale (probably query desktop scale and adjust accordingly) Implement global scale (probably query desktop scale and adjust accordingly)
Implement show/hide functionality for widgets Implement show/hide functionality for widgets
Implement Panel title
Create reliable default stylesheet Create reliable default stylesheet
Implement cursors in Stylesheet Implement cursors in Stylesheet
@ -28,10 +28,10 @@ Implement cursors in Stylesheet
Implement following widgets: Implement following widgets:
***Label ***Label
***Checkbox ***Checkbox
***Panel / Container
***Title Label
Button Button
Image/Icon Image/Icon
Panel / Container
Title Label
Radio Button Radio Button
Grouping Grouping
Text Input Text Input

View file

@ -494,6 +494,10 @@ namespace ogfx
m_defaultStylesheetVariables["color_darkcyan"] = { "Color(" + Colors::DarkCyan.hexString(true, "#") + ")", true }; m_defaultStylesheetVariables["color_darkcyan"] = { "Color(" + Colors::DarkCyan.hexString(true, "#") + ")", true };
m_defaultStylesheetVariables["color_darkmagenta"] = { "Color(" + Colors::DarkMagenta.hexString(true, "#") + ")", true }; m_defaultStylesheetVariables["color_darkmagenta"] = { "Color(" + Colors::DarkMagenta.hexString(true, "#") + ")", true };
m_defaultStylesheetVariables["color_darkyellow"] = { "Color(" + Colors::DarkYellow.hexString(true, "#") + ")", true }; m_defaultStylesheetVariables["color_darkyellow"] = { "Color(" + Colors::DarkYellow.hexString(true, "#") + ")", true };
//Text Align
m_defaultStylesheetVariables["text_center"] = { String("").add(cast<i32>(eTextAlign::Center)), true };
m_defaultStylesheetVariables["text_left"] = { String("").add(cast<i32>(eTextAlign::Left)), true };
} }

View file

@ -59,6 +59,11 @@ namespace ogfx
Count Count
}; };
public: enum class eTextAlign : u8 {
Default = 0,
Center,
Left
};
public: public:
inline WindowCore(void) { } inline WindowCore(void) { }
virtual ~WindowCore(void); virtual ~WindowCore(void);

View file

@ -20,6 +20,7 @@
#include "Containers.hpp" #include "Containers.hpp"
#include "../../render/BasicRenderer.hpp" #include "../../render/BasicRenderer.hpp"
#include "../Window.hpp"
namespace ogfx namespace ogfx
{ {
@ -46,15 +47,85 @@ namespace ogfx
enableBorder(getThemeValue<bool>(theme, "panel.showBorder", true)); enableBorder(getThemeValue<bool>(theme, "panel.showBorder", true));
enableBackground(getThemeValue<bool>(theme, "panel.showBackground", true)); enableBackground(getThemeValue<bool>(theme, "panel.showBackground", true));
setBorderColor(getThemeValue<Color>(theme, "panel.borderColor", Colors::Black)); setBorderColor(getThemeValue<Color>(theme, "panel.borderColor", Colors::Black));
m_titleColor = getThemeValue<Color>(theme, "panel.titleColor", Colors::Black);
m_showTitle = getThemeValue<bool>(theme, "panel.showTitle", false);
m_titleHeight = getThemeValue<f32>(theme, "panel.titleHeight", 30);
m_titleType = getThemeValue<String>(theme, "panel.titlebarType", TitleBarTypes::None);
setPadding(getThemeValue<Rectangle>(theme, "panel.padding", { 15, 15, 15, 15 })); setPadding(getThemeValue<Rectangle>(theme, "panel.padding", { 15, 15, 15, 15 }));
m_basePadding = getPadding();
m_titleColor = getThemeValue<Color>(theme, "panel.titleColor", Colors::Black);
m_titlebarColor = getThemeValue<Color>(theme, "panel.titlebarColor", Colors::Transparent);
m_titlebarBorderColor = getThemeValue<Color>(theme, "panel.titlebarBorderColor", Colors::Black);
m_titlebarHeight = getThemeValue<f32>(theme, "panel.titlebarHeight", 30);
m_titlebarBorderWidth = getThemeValue<i32>(theme, "panel.titlebarBorderWidth", 1);
m_titlebarFontSize = getThemeValue<i32>(theme, "panel.titlebarFontSize", 26);
m_titleTextAlign = getThemeValue<i32>(theme, "panel.titlebarTextAlign", cast<i32>(WindowCore::eTextAlign::Left));
setTitlebarType(getThemeValue<String>(theme, "panel.titlebarType", TitleBarTypes::None));
} }
void Panel::onDraw(ogfx::BasicRenderer2D& gfx) void Panel::onDraw(ogfx::BasicRenderer2D& gfx)
{ {
draw_titlebar(gfx);
}
void Panel::setTitlebarType(const String& type)
{
String t = type.new_toLower().trim();
if (t == TitleBarTypes::None)
{
setPadding(m_basePadding);
m_titlebarType = TitleBarTypes::NoneValue;
}
else if (t == TitleBarTypes::Minimal)
{
setPadding(m_basePadding + Rectangle { 0, m_titlebarHeight, 0, 0 });
m_titlebarType = TitleBarTypes::MinimalValue;
}
else if (t == TitleBarTypes::Full)
{
setPadding(m_basePadding + Rectangle { 0, m_titlebarHeight, 0, 0 });
m_titlebarType = TitleBarTypes::FullValue;
}
}
String Panel::getTitlebarType(void) const
{
switch (m_titlebarType)
{
case TitleBarTypes::FullValue: return TitleBarTypes::Full;
case TitleBarTypes::MinimalValue: return TitleBarTypes::Minimal;
case TitleBarTypes::NoneValue: return TitleBarTypes::None;
default: return TitleBarTypes::None;
}
}
void Panel::draw_titlebar(BasicRenderer2D& gfx)
{
f32 br = cast<f32>(getBorderWidth());
br /= 2;
Rectangle titleBarBounds {
getGlobalPosition() + Vec2 { br, br },
Vec2 { getw(), m_titlebarHeight } - Vec2 { br * 2, br * 2 }
};
switch (m_titlebarType)
{
case TitleBarTypes::FullValue:
{
gfx.outlinedRoundRect(titleBarBounds, m_titlebarColor, m_titlebarColor, { cast<f32>(getBorderRadius()), cast<f32>(getBorderRadius()), 0, 0 }, getBorderWidth());
gfx.drawLine({ getGlobalPosition() + Vec2 { 0, m_titlebarHeight - 2 }, getGlobalPosition() + Vec2 { getGlobalBounds().w, m_titlebarHeight - 2 } }, m_titlebarBorderColor, m_titlebarBorderWidth);
if (m_titleTextAlign == cast<i32>(WindowCore::eTextAlign::Center))
gfx.drawCenteredString(m_title, titleBarBounds, m_titleColor, m_titlebarFontSize);
else
gfx.drawString(m_title, titleBarBounds.getPosition() + Vec2 { 10, 5 }, m_titleColor, m_titlebarFontSize);
break;
}
case TitleBarTypes::MinimalValue:
{
if (m_titleTextAlign == cast<i32>(WindowCore::eTextAlign::Center))
gfx.drawCenteredString(m_title, titleBarBounds, m_titleColor, m_titlebarFontSize);
else
gfx.drawString(m_title, titleBarBounds.getPosition() + Vec2 { 10, 5 }, m_titleColor, m_titlebarFontSize);
break;
}
case TitleBarTypes::NoneValue:
default: break;
}
} }
} }
} }

View file

@ -34,7 +34,11 @@ namespace ogfx
{ {
inline static const String None { "none" }; inline static const String None { "none" };
inline static const String Full { "full" }; inline static const String Full { "full" };
inline static const String Minimal { "monimal" }; inline static const String Minimal { "minimal" };
inline static constexpr i32 NoneValue = 0;
inline static constexpr i32 FullValue = 1;
inline static constexpr i32 MinimalValue = 2;
}; };
public: public:
inline Panel(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); } inline Panel(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); }
@ -42,15 +46,27 @@ namespace ogfx
void applyTheme(const ostd::Stylesheet& theme) override; void applyTheme(const ostd::Stylesheet& theme) override;
void onDraw(ogfx::BasicRenderer2D& gfx) override; void onDraw(ogfx::BasicRenderer2D& gfx) override;
void setTitlebarType(const String& type); void setTitlebarType(const String& type);
String getTitlebarType(void) const;
inline void setBackGroundColor(const Color& color) { m_backgroundColor = color; } inline void setBackGroundColor(const Color& color) { m_backgroundColor = color; }
inline Color getBackgroundColor(void) { return m_backgroundColor; } inline Color getBackgroundColor(void) { return m_backgroundColor; }
inline String getTitlebarType(void) const { return m_titleType; } inline String getTitle(void) const { return m_title; }
inline void setTitle(const String& title) { m_title = title; }
private: private:
Color m_titleColor { 0, 0, 0 }; void draw_titlebar(BasicRenderer2D& gfx);
bool m_showTitle { false };
String m_titleType = TitleBarTypes::None; private:
f32 m_titleHeight { 30 }; String m_title { "Panel" };
Color m_titleColor { Colors::Black };
i32 m_titlebarType = TitleBarTypes::NoneValue;
f32 m_titlebarHeight { 30 };
i32 m_titlebarBorderWidth { 1 };
i32 m_titlebarFontSize { 26 };
Color m_titlebarColor { Colors::Transparent };
Color m_titlebarBorderColor { Colors::Black };
Rectangle m_basePadding { 0, 0, 0, 0 };
i32 m_titleTextAlign { 0 };
}; };
} }
} }

View file

@ -60,6 +60,7 @@ namespace ogfx
{ {
m_window = &window; m_window = &window;
if (m_initialized) return set_error_state(tErrors::NoError); if (m_initialized) return set_error_state(tErrors::NoError);
SDL_SetRenderDrawBlendMode(m_window->getSDLRenderer(), SDL_BLENDMODE_BLEND);
init_arrays(); init_arrays();
m_initialized = true; m_initialized = true;
loadDefaultFont(20); loadDefaultFont(20);
@ -434,46 +435,52 @@ namespace ogfx
} }
void BasicRenderer2D::drawRoundRect(const Rectangle& rect, const Color& color, f32 radius, i32 thickness) void BasicRenderer2D::drawRoundRect(const Rectangle& rect, const Color& color, f32 radius, i32 thickness)
{
drawRoundRect(rect, color, { radius, radius, radius, radius }, thickness);
}
void BasicRenderer2D::drawRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius, i32 thickness)
{
drawRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, { radius, radius, radius, radius }, thickness);
}
void BasicRenderer2D::drawRoundRect(const Vec2& center, const Vec2& size, const Color& color, const Rectangle& radii, i32 thickness)
{
drawRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, radii, thickness);
}
void BasicRenderer2D::drawRoundRect(const Rectangle& rect, const Color& color, const Rectangle& radii, i32 thickness)
{ {
if (!m_initialized || thickness <= 0) if (!m_initialized || thickness <= 0)
return; return;
// Clamp radius so it never exceeds half the smallest dimension // radii: x=TL, y=TR, w=BR, h=BL
radius = std::max(0.0f, std::min(radius, std::min(rect.w, rect.h) * 0.5f)); f32 maxR = std::min(rect.w, rect.h) * 0.5f;
f32 rTL = std::max(0.0f, std::min(radii.x, maxR));
f32 rTR = std::max(0.0f, std::min(radii.y, maxR));
f32 rBR = std::max(0.0f, std::min(radii.w, maxR));
f32 rBL = std::max(0.0f, std::min(radii.h, maxR));
f32 half = thickness * 0.5f; f32 half = thickness * 0.5f;
// Inset rectangle so the border stays INSIDE the given bounds
f32 x1 = rect.x + half; f32 x1 = rect.x + half;
f32 y1 = rect.y + half; f32 y1 = rect.y + half;
f32 x2 = rect.x + rect.w - half; f32 x2 = rect.x + rect.w - half;
f32 y2 = rect.y + rect.h - half; f32 y2 = rect.y + rect.h - half;
// Corner centers // Straight edges
Vec2 TL { x1 + radius, y1 + radius }; drawLine({ {x1 + rTL, y1}, {x2 - rTR, y1} }, color, thickness, false); // top
Vec2 TR { x2 - radius, y1 + radius }; drawLine({ {x2, y1 + rTR}, {x2, y2 - rBR} }, color, thickness, false); // right
Vec2 BR { x2 - radius, y2 - radius }; drawLine({ {x2 - rBR, y2}, {x1 + rBL, y2} }, color, thickness, false); // bottom
Vec2 BL { x1 + radius, y2 - radius }; drawLine({ {x1, y2 - rBL}, {x1, y1 + rTL} }, color, thickness, false); // left
// Straight edges (shortened to meet the arcs cleanly) // Corner arcs
drawLine({ {x1 + radius, y1}, {x2 - radius, y1} }, color, thickness, false); // top auto segments = [](f32 r) -> i32 { return std::max(6, i32(r * 0.75f)); };
drawLine({ {x2, y1 + radius}, {x2, y2 - radius} }, color, thickness, false); // right
drawLine({ {x2 - radius, y2}, {x1 + radius, y2} }, color, thickness, false); // bottom
drawLine({ {x1, y2 - radius}, {x1, y1 + radius} }, color, thickness, false); // left
// Number of segments for smooth arcs if (rTL > 0) generate_ellipse_stroke({ x1 + rTL, y1 + rTL }, rTL, rTL, thickness, M_PI, M_PI * 1.5f, color, segments(rTL));
i32 segments = std::max(6, i32(radius * 0.75f)); if (rTR > 0) generate_ellipse_stroke({ x2 - rTR, y1 + rTR }, rTR, rTR, thickness, M_PI * 1.5f, M_PI * 2.0f, color, segments(rTR));
if (rBR > 0) generate_ellipse_stroke({ x2 - rBR, y2 - rBR }, rBR, rBR, thickness, 0.0f, M_PI * 0.5f, color, segments(rBR));
// Quarterellipse strokes (each is 90°) if (rBL > 0) generate_ellipse_stroke({ x1 + rBL, y2 - rBL }, rBL, rBL, thickness, M_PI * 0.5f, M_PI, color, segments(rBL));
generate_ellipse_stroke(TL, radius, radius, thickness, M_PI, M_PI + M_PI * 0.5f, color, segments); // TL
generate_ellipse_stroke(TR, radius, radius, thickness, 1.5f * M_PI, 2.0f * M_PI, color, segments); // TR
generate_ellipse_stroke(BR, radius, radius, thickness, 0.0f, M_PI * 0.5f, color, segments); // BR
generate_ellipse_stroke(BL, radius, radius, thickness, M_PI * 0.5f, M_PI, color, segments); // BL
}
void BasicRenderer2D::drawRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius, i32 thickness)
{
drawRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, radius, thickness);
} }
void BasicRenderer2D::drawCircle(const Vec2& center, f32 radius, const Color& color, i32 thickness) void BasicRenderer2D::drawCircle(const Vec2& center, f32 radius, const Color& color, i32 thickness)
@ -500,7 +507,7 @@ namespace ogfx
void BasicRenderer2D::drawEllipse(const Rectangle& rect, const Color& color, i32 thickness) void BasicRenderer2D::drawEllipse(const Rectangle& rect, const Color& color, i32 thickness)
{ {
if (!m_initialized || thickness <= 0) if (!m_initialized || thickness <= 0)
return; return;
Vec2 center = { rect.x + rect.w*0.5f, rect.y + rect.h*0.5f }; Vec2 center = { rect.x + rect.w*0.5f, rect.y + rect.h*0.5f };
@ -556,106 +563,172 @@ namespace ogfx
} }
void BasicRenderer2D::fillRoundRect(const Rectangle& rect, const Color& color, f32 radius) void BasicRenderer2D::fillRoundRect(const Rectangle& rect, const Color& color, f32 radius)
{
fillRoundRect(rect, color, { radius, radius, radius, radius });
}
void BasicRenderer2D::fillRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius)
{
fillRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, { radius, radius, radius, radius });
}
void BasicRenderer2D::fillRoundRect(const Vec2& center, const Vec2& size, const Color& color, const Rectangle& radii)
{
fillRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, radii);
}
void BasicRenderer2D::fillRoundRect(const Rectangle& rect, const Color& color, const Rectangle& radii)
{ {
if (!m_initialized) if (!m_initialized)
return; return;
// Clamp radius f32 maxR = std::min(rect.w, rect.h) * 0.5f;
radius = std::max(0.0f, std::min(radius, std::min(rect.w, rect.h) * 0.5f)); f32 rTL = std::max(0.0f, std::min(radii.x, maxR));
f32 rTR = std::max(0.0f, std::min(radii.y, maxR));
f32 rBR = std::max(0.0f, std::min(radii.w, maxR));
f32 rBL = std::max(0.0f, std::min(radii.h, maxR));
f32 x1 = rect.x; f32 x1 = rect.x;
f32 y1 = rect.y; f32 y1 = rect.y;
f32 x2 = rect.x + rect.w; f32 x2 = rect.x + rect.w;
f32 y2 = rect.y + rect.h; f32 y2 = rect.y + rect.h;
f32 cx1 = x1 + radius; // The largest corner radius on each side determines the inset for that side
f32 cy1 = y1 + radius; f32 topInset = std::max(rTL, rTR);
f32 cx2 = x2 - radius; f32 bottomInset = std::max(rBL, rBR);
f32 cy2 = y2 - radius; f32 leftInset = std::max(rTL, rBL);
f32 rightInset = std::max(rTR, rBR);
// Number of segments for smooth corners // Center rectangle
i32 segments = std::max(6, i32(radius * 0.75f));
//
// 1. Fill the center rectangle
//
{ {
Vec2 verts[4] = { Vec2 verts[4] = {
{ cx1, cy1 }, { x1 + leftInset, y1 + topInset },
{ cx2, cy1 }, { x2 - rightInset, y1 + topInset },
{ cx2, cy2 }, { x2 - rightInset, y2 - bottomInset },
{ cx1, cy2 } { x1 + leftInset, y2 - bottomInset }
}; };
u32 inds[6] = { 0,1,2, 2,3,0 }; u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
} }
// // Top strip
// 2. Fill the four side rectangles
//
// Top
if (radius > 0)
{ {
Vec2 verts[4] = { Vec2 verts[4] = {
{ x1 + radius, y1 }, { x1 + rTL, y1 },
{ x2 - radius, y1 }, { x2 - rTR, y1 },
{ x2 - radius, y1 + radius }, { x2 - rTR, y1 + topInset },
{ x1 + radius, y1 + radius } { x1 + rTL, y1 + topInset }
}; };
u32 inds[6] = { 0,1,2, 2,3,0 }; u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
} }
// Bottom // Bottom strip
{ {
Vec2 verts[4] = { Vec2 verts[4] = {
{ x1 + radius, y2 - radius }, { x1 + rBL, y2 - bottomInset },
{ x2 - radius, y2 - radius }, { x2 - rBR, y2 - bottomInset },
{ x2 - radius, y2 }, { x2 - rBR, y2 },
{ x1 + radius, y2 } { x1 + rBL, y2 }
}; };
u32 inds[6] = { 0,1,2, 2,3,0 }; u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
} }
// Left // Left strip
{ {
Vec2 verts[4] = { Vec2 verts[4] = {
{ x1, y1 + radius }, { x1, y1 + rTL },
{ x1 + radius, y1 + radius }, { x1 + leftInset, y1 + rTL },
{ x1 + radius, y2 - radius }, { x1 + leftInset, y2 - rBL },
{ x1, y2 - radius } { x1, y2 - rBL }
}; };
u32 inds[6] = { 0,1,2, 2,3,0 }; u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
} }
// Right // Right strip
{ {
Vec2 verts[4] = { Vec2 verts[4] = {
{ x2 - radius, y1 + radius }, { x2 - rightInset, y1 + rTR },
{ x2, y1 + radius }, { x2, y1 + rTR },
{ x2, y2 - radius }, { x2, y2 - rBR },
{ x2 - radius, y2 - radius } { x2 - rightInset, y2 - rBR }
}; };
u32 inds[6] = { 0,1,2, 2,3,0 }; u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr); push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
} }
// // Fill gaps between corners and strips when radii differ on the same side
// 3. Fill the four rounded corners (quarter ellipses) // Top-left gap (if rTL < topInset, there's a rectangular gap below the TL corner)
// if (rTL < topInset)
{
Vec2 verts[4] = {
{ x1, y1 + rTL },
{ x1 + leftInset, y1 + rTL },
{ x1 + leftInset, y1 + topInset },
{ x1, y1 + topInset }
};
u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
}
generate_filled_ellipse_stroke({cx1, cy1}, radius, radius, M_PI, color, segments); // TL // Top-right gap
generate_filled_ellipse_stroke({cx2, cy1}, radius, radius, 1.5f * M_PI, color, segments); // TR if (rTR < topInset)
generate_filled_ellipse_stroke({cx2, cy2}, radius, radius, 0.0f, color, segments); // BR {
generate_filled_ellipse_stroke({cx1, cy2}, radius, radius, 0.5f * M_PI, color, segments); // BL Vec2 verts[4] = {
} { x2 - rightInset, y1 + rTR },
{ x2, y1 + rTR },
{ x2, y1 + topInset },
{ x2 - rightInset, y1 + topInset }
};
u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
}
void BasicRenderer2D::fillRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius) // Bottom-left gap
{ if (rBL < bottomInset)
fillRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, radius); {
Vec2 verts[4] = {
{ x1, y2 - bottomInset },
{ x1 + leftInset, y2 - bottomInset },
{ x1 + leftInset, y2 - rBL },
{ x1, y2 - rBL }
};
u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
}
// Bottom-right gap
if (rBR < bottomInset)
{
Vec2 verts[4] = {
{ x2 - rightInset, y2 - bottomInset },
{ x2, y2 - bottomInset },
{ x2, y2 - rBR },
{ x2 - rightInset, y2 - rBR }
};
u32 inds[6] = QUAD_INDICES_ARR;
push_polygon(verts, nullptr, 4, inds, 6, color, nullptr);
}
// Left-side gap (if rTL != rBL, leftInset is the max, smaller one needs a gap)
if (rTL < leftInset && rTL < topInset)
{
// Already covered by TL gap above
}
if (rBL < leftInset && rBL < bottomInset)
{
// Already covered by BL gap above
}
// Corner fills
auto segments = [](f32 r) -> i32 { return std::max(6, i32(r * 0.75f)); };
if (rTL > 0) generate_filled_ellipse_stroke({ x1 + rTL, y1 + rTL }, rTL, rTL, M_PI, color, segments(rTL));
if (rTR > 0) generate_filled_ellipse_stroke({ x2 - rTR, y1 + rTR }, rTR, rTR, M_PI * 1.5f, color, segments(rTR));
if (rBR > 0) generate_filled_ellipse_stroke({ x2 - rBR, y2 - rBR }, rBR, rBR, 0.0f, color, segments(rBR));
if (rBL > 0) generate_filled_ellipse_stroke({ x1 + rBL, y2 - rBL }, rBL, rBL, M_PI * 0.5f, color, segments(rBL));
} }
void BasicRenderer2D::fillCircle(const Vec2& center, f32 radius, const Color& color) void BasicRenderer2D::fillCircle(const Vec2& center, f32 radius, const Color& color)
@ -733,15 +806,25 @@ namespace ogfx
void BasicRenderer2D::outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness) void BasicRenderer2D::outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness)
{ {
if (!m_initialized) return; outlinedRoundRect(rect, fillColor, outlineColor, { radius, radius, radius, radius }, outlineThickness);
Rectangle offset = { 1, 1, -2, -2 };
fillRoundRect(rect + offset, fillColor, radius);
drawRoundRect(rect, outlineColor, radius, outlineThickness);
} }
void BasicRenderer2D::outlinedRoundRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness) void BasicRenderer2D::outlinedRoundRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness)
{ {
outlinedRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, fillColor, outlineColor, radius, outlineThickness); outlinedRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, fillColor, outlineColor, { radius, radius, radius, radius }, outlineThickness);
}
void BasicRenderer2D::outlinedRoundRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, const Rectangle& radii, i32 outlineThickness)
{
outlinedRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, fillColor, outlineColor, radii, outlineThickness);
}
void BasicRenderer2D::outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, const Rectangle& radii, i32 outlineThickness)
{
if (!m_initialized) return;
Rectangle offset = { 1, 1, -2, -2 };
fillRoundRect(rect + offset, fillColor, radii);
drawRoundRect(rect, outlineColor, radii, outlineThickness);
} }
void BasicRenderer2D::outlinedCircle(const Vec2& center, f32 radius, const Color& fillColor, const Color& outlineColor, i32 outlineThickness) void BasicRenderer2D::outlinedCircle(const Vec2& center, f32 radius, const Color& fillColor, const Color& outlineColor, i32 outlineThickness)

View file

@ -93,6 +93,8 @@ namespace ogfx
void drawRect(const Vec2& center, const Vec2& size, const Color& color, i32 thickness = 1); void drawRect(const Vec2& center, const Vec2& size, const Color& color, i32 thickness = 1);
void drawRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius, i32 thickness = 1); void drawRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius, i32 thickness = 1);
void drawRoundRect(const Rectangle& rect, const Color& color, f32 radius, i32 thickness = 1); void drawRoundRect(const Rectangle& rect, const Color& color, f32 radius, i32 thickness = 1);
void drawRoundRect(const Rectangle& rect, const Color& color, const Rectangle& radii, i32 thickness = 1);
void drawRoundRect(const Vec2& center, const Vec2& size, const Color& color, const Rectangle& radii, i32 thickness = 1);
void drawCircle(const Vec2& center, f32 radius, const Color& color, i32 thickness = 1); void drawCircle(const Vec2& center, f32 radius, const Color& color, i32 thickness = 1);
void drawCircle(const Rectangle& rect, const Color& color, i32 thickness = 1); void drawCircle(const Rectangle& rect, const Color& color, i32 thickness = 1);
void drawEllipse(const Rectangle& rect, const Color& color, i32 thickness = 1); void drawEllipse(const Rectangle& rect, const Color& color, i32 thickness = 1);
@ -103,6 +105,8 @@ namespace ogfx
void fillRect(const Vec2& center, const Vec2& size, const Color& color); void fillRect(const Vec2& center, const Vec2& size, const Color& color);
void fillRoundRect(const Rectangle& rect, const Color& color, f32 radius); void fillRoundRect(const Rectangle& rect, const Color& color, f32 radius);
void fillRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius); void fillRoundRect(const Vec2& center, const Vec2& size, const Color& color, f32 radius);
void fillRoundRect(const Rectangle& rect, const Color& color, const Rectangle& radii);
void fillRoundRect(const Vec2& center, const Vec2& size, const Color& color, const Rectangle& radii);
void fillCircle(const Vec2& center, f32 radius, const Color& color); void fillCircle(const Vec2& center, f32 radius, const Color& color);
void fillCircle(const Rectangle& rect, const Color& color); void fillCircle(const Rectangle& rect, const Color& color);
void fillEllipse(const Rectangle& rect, const Color& color); void fillEllipse(const Rectangle& rect, const Color& color);
@ -113,6 +117,8 @@ namespace ogfx
void outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); void outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1);
void outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness = 1); void outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness = 1);
void outlinedRoundRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness = 1); void outlinedRoundRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness = 1);
void outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, const Rectangle& radii, i32 outlineThickness = 1);
void outlinedRoundRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, const Rectangle& radii, i32 outlineThickness = 1);
void outlinedCircle(const Vec2& center, f32 radius, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); void outlinedCircle(const Vec2& center, f32 radius, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1);
void outlinedCircle(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); void outlinedCircle(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1);
void outlinedEllipse(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1); void outlinedEllipse(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1);

View file

@ -217,7 +217,7 @@ custom_continue:
{ {
auto it = m_values.find(fullKey); auto it = m_values.find(fullKey);
// if (it != m_values.end()) // if (it != m_values.end())
// std::cout << " GET: " << fullKey << "\n"; // std::cout << " GET: " << fullKey << "\n";
return it != m_values.end() ? &it->second : nullptr; return it != m_values.end() ? &it->second : nullptr;
} }
@ -231,6 +231,24 @@ custom_continue:
if (key == "") if (key == "")
return false; return false;
String themeID = ""; String themeID = "";
auto l_parseColor = [this](const String& _value) -> String {
String value = _value.new_toLower().trim();
if (value.startsWith("color(") && value.endsWith(")"))
{
value.substr(6, value.len() - 1).trim();
return value;
}
else if ((value.startsWith("#") && (value.len() == 7 || value.len() == 9)) ||
(value.startsWith("rgb(") && value.endsWith(")")) ||
(value.startsWith("rgba(") && value.endsWith(")")))
{
return value;
}
return "";
};
if (key.startsWith("@")) if (key.startsWith("@"))
{ {
if (key.indexOf(" ") < 2) if (key.indexOf(" ") < 2)
@ -249,10 +267,9 @@ custom_continue:
valuePreserveCase.substr(1, value.len() - 1); valuePreserveCase.substr(1, value.len() - 1);
set(key, valuePreserveCase, themeID); set(key, valuePreserveCase, themeID);
} }
else if (value.startsWith("color(") && value.endsWith(")")) else if (String v = l_parseColor(value); v != "")
{ {
value.substr(6, value.len() - 1).trim(); set(key, Color(v), themeID);
set(key, Color(value), themeID);
} }
else if (value.startsWith("vec2(") && value.endsWith(")")) else if (value.startsWith("vec2(") && value.endsWith(")"))
{ {
@ -284,6 +301,11 @@ custom_continue:
} }
set(key, Rectangle(vec[0], vec[1], vec[2], vec[3]), themeID); set(key, Rectangle(vec[0], vec[1], vec[2], vec[3]), themeID);
} }
else if (exitCondition)
{
//Defaulting anything that isn't recognized as any value_type/variable to String type
set(key, valuePreserveCase, themeID);
}
else else
{ {
if (exitCondition) if (exitCondition)

View file

@ -153,8 +153,7 @@ class Window : public ogfx::gui::Window
void onRedraw(ogfx::BasicRenderer2D& gfx) override void onRedraw(ogfx::BasicRenderer2D& gfx) override
{ {
gfx.drawAnimation(m_anim, { 200, 200 }); gfx.drawAnimation(m_anim, { 200, 200 });
gfx.outlinedTriangle({ 30, 30 }, { 100, 50 }, { 60, 90 }, Colors::Crimson, Colors::DarkBlue, 5); gfx.outlinedTriangle({ 30, 30 }, { 100, 50 }, { 60, 90 }, { 255, 0, 0, 80 }, Colors::DarkBlue, 5);
gfx.endFrame();
} }
void onFixedUpdate(void) override void onFixedUpdate(void) override