Added Panel title
This commit is contained in:
parent
e8d13b931e
commit
84c4c2eb88
10 changed files with 347 additions and 137 deletions
|
|
@ -1,17 +1,17 @@
|
|||
% ================== testTheme.txt ==================
|
||||
|
||||
% ---- Variables ----
|
||||
$accentColor = Color(rgba(255, 0, 255, 255))
|
||||
const $color2 = Color(#0000FFFF)
|
||||
$accentColor = rgba(255, 0, 255, 255)
|
||||
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) {
|
||||
textColor = $accentColor
|
||||
backgroundColor = Color(#000000FF)
|
||||
backgroundColor = #000000FF
|
||||
borderColor = $accentColor
|
||||
fontSize = 20
|
||||
borderRadius = 0
|
||||
|
|
@ -46,26 +46,30 @@ $accentColor = Color(rgb(255, 0, 0))
|
|||
}
|
||||
|
||||
(checkbox:active) {
|
||||
textColor = Color(#000050FF)
|
||||
textColor = #000050FF
|
||||
}
|
||||
|
||||
(panel) {
|
||||
backgroundColor = Color(#AAAAAAFF)
|
||||
borderColor = Color(#000000FF)
|
||||
borderRadius = 8
|
||||
borderWidth = 4
|
||||
backgroundColor = #AAAAAAFF
|
||||
borderColor = color_black
|
||||
borderRadius = 10
|
||||
borderWidth = 2
|
||||
showBorder = true
|
||||
showBackground = true
|
||||
padding = Rect(15, 15, 15, 15)
|
||||
showTitle = true
|
||||
titleColor = Color(#000000FF)
|
||||
titlebarType = "full"
|
||||
titleHeight = 30
|
||||
titleColor = #444444FF
|
||||
titlebarColor = #999999FF
|
||||
titlebarBorderColor = #909090FF
|
||||
titlebarBorderWidth = 2
|
||||
titlebarType = full
|
||||
titlebarHeight = 18
|
||||
titlebarFontSize = 18
|
||||
titlebarTextAlign = text_left
|
||||
}
|
||||
|
||||
(@testLabel label) {
|
||||
textColor = $color2
|
||||
backgroundColor = Color(#000000FF)
|
||||
backgroundColor = #000000FF
|
||||
fontSize = 50
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +79,7 @@ $accentColor = Color(rgb(255, 0, 0))
|
|||
}
|
||||
|
||||
(@testLabel2 label:hover) {
|
||||
borderColor = Color(#208080FF)
|
||||
borderColor = #208080FF
|
||||
}
|
||||
|
||||
(@testLabel2 label:pressed) {
|
||||
|
|
@ -84,7 +88,7 @@ $accentColor = Color(rgb(255, 0, 0))
|
|||
|
||||
(label:hover) {
|
||||
textColor = color_green
|
||||
borderColor = Color(rgb(0, 255, 0))
|
||||
borderColor = rgb(0, 255, 0)
|
||||
}
|
||||
|
||||
(label:pressed) {
|
||||
|
|
@ -97,19 +101,19 @@ $accentColor = Color(rgb(255, 0, 0))
|
|||
|
||||
(@testLabel label:pressed) {
|
||||
backgroundColor = color_firebrick
|
||||
textColor = Color(#505050FF)
|
||||
textColor = #505050FF
|
||||
}
|
||||
|
||||
(label:disabled) {
|
||||
backgroundColor = Color(#EEEEEEFF)
|
||||
%textColor = Color(#505050FF)
|
||||
%borderColor = Color(#000000FF)
|
||||
backgroundColor = #EEEEEEFF
|
||||
%textColor = #505050FF
|
||||
%borderColor = #000000FF
|
||||
}
|
||||
|
||||
(@label3 label) {
|
||||
textColor = $color2
|
||||
backgroundColor = Color(#000000FF)
|
||||
borderColor = Color(#FF0000FF)
|
||||
backgroundColor = #000000FF
|
||||
borderColor = #FF0000FF
|
||||
borderWidth = 4
|
||||
borderRadius = 15
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@
|
|||
***Implement wrappers in Renderer2D to take a center and size for rects
|
||||
***find a way to add fixed update to gui::Window
|
||||
***Add triangle drawing functions to BasicRenderer2D
|
||||
***Implement Panel title
|
||||
Add theme caching
|
||||
Implement global scale (probably query desktop scale and adjust accordingly)
|
||||
Implement show/hide functionality for widgets
|
||||
Implement Panel title
|
||||
Create reliable default stylesheet
|
||||
Implement cursors in Stylesheet
|
||||
|
||||
|
|
@ -28,10 +28,10 @@ Implement cursors in Stylesheet
|
|||
Implement following widgets:
|
||||
***Label
|
||||
***Checkbox
|
||||
***Panel / Container
|
||||
***Title Label
|
||||
Button
|
||||
Image/Icon
|
||||
Panel / Container
|
||||
Title Label
|
||||
Radio Button
|
||||
Grouping
|
||||
Text Input
|
||||
|
|
|
|||
|
|
@ -494,6 +494,10 @@ namespace ogfx
|
|||
m_defaultStylesheetVariables["color_darkcyan"] = { "Color(" + Colors::DarkCyan.hexString(true, "#") + ")", true };
|
||||
m_defaultStylesheetVariables["color_darkmagenta"] = { "Color(" + Colors::DarkMagenta.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 };
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ namespace ogfx
|
|||
|
||||
Count
|
||||
};
|
||||
public: enum class eTextAlign : u8 {
|
||||
Default = 0,
|
||||
Center,
|
||||
Left
|
||||
};
|
||||
public:
|
||||
inline WindowCore(void) { }
|
||||
virtual ~WindowCore(void);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "Containers.hpp"
|
||||
#include "../../render/BasicRenderer.hpp"
|
||||
#include "../Window.hpp"
|
||||
|
||||
namespace ogfx
|
||||
{
|
||||
|
|
@ -46,15 +47,85 @@ namespace ogfx
|
|||
enableBorder(getThemeValue<bool>(theme, "panel.showBorder", true));
|
||||
enableBackground(getThemeValue<bool>(theme, "panel.showBackground", true));
|
||||
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 }));
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,11 @@ namespace ogfx
|
|||
{
|
||||
inline static const String None { "none" };
|
||||
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:
|
||||
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 onDraw(ogfx::BasicRenderer2D& gfx) override;
|
||||
void setTitlebarType(const String& type);
|
||||
String getTitlebarType(void) const;
|
||||
inline void setBackGroundColor(const Color& color) { m_backgroundColor = color; }
|
||||
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:
|
||||
Color m_titleColor { 0, 0, 0 };
|
||||
bool m_showTitle { false };
|
||||
String m_titleType = TitleBarTypes::None;
|
||||
f32 m_titleHeight { 30 };
|
||||
void draw_titlebar(BasicRenderer2D& gfx);
|
||||
|
||||
private:
|
||||
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 };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ namespace ogfx
|
|||
{
|
||||
m_window = &window;
|
||||
if (m_initialized) return set_error_state(tErrors::NoError);
|
||||
SDL_SetRenderDrawBlendMode(m_window->getSDLRenderer(), SDL_BLENDMODE_BLEND);
|
||||
init_arrays();
|
||||
m_initialized = true;
|
||||
loadDefaultFont(20);
|
||||
|
|
@ -434,46 +435,52 @@ namespace ogfx
|
|||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
// Clamp radius so it never exceeds half the smallest dimension
|
||||
radius = std::max(0.0f, std::min(radius, std::min(rect.w, rect.h) * 0.5f));
|
||||
// radii: x=TL, y=TR, w=BR, h=BL
|
||||
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;
|
||||
|
||||
// Inset rectangle so the border stays INSIDE the given bounds
|
||||
f32 x1 = rect.x + half;
|
||||
f32 y1 = rect.y + half;
|
||||
f32 x2 = rect.x + rect.w - half;
|
||||
f32 y2 = rect.y + rect.h - half;
|
||||
|
||||
// Corner centers
|
||||
Vec2 TL { x1 + radius, y1 + radius };
|
||||
Vec2 TR { x2 - radius, y1 + radius };
|
||||
Vec2 BR { x2 - radius, y2 - radius };
|
||||
Vec2 BL { x1 + radius, y2 - radius };
|
||||
// Straight edges
|
||||
drawLine({ {x1 + rTL, y1}, {x2 - rTR, y1} }, color, thickness, false); // top
|
||||
drawLine({ {x2, y1 + rTR}, {x2, y2 - rBR} }, color, thickness, false); // right
|
||||
drawLine({ {x2 - rBR, y2}, {x1 + rBL, y2} }, color, thickness, false); // bottom
|
||||
drawLine({ {x1, y2 - rBL}, {x1, y1 + rTL} }, color, thickness, false); // left
|
||||
|
||||
// Straight edges (shortened to meet the arcs cleanly)
|
||||
drawLine({ {x1 + radius, y1}, {x2 - radius, y1} }, color, thickness, false); // top
|
||||
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
|
||||
// Corner arcs
|
||||
auto segments = [](f32 r) -> i32 { return std::max(6, i32(r * 0.75f)); };
|
||||
|
||||
// Number of segments for smooth arcs
|
||||
i32 segments = std::max(6, i32(radius * 0.75f));
|
||||
|
||||
// Quarter‑ellipse strokes (each is 90°)
|
||||
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);
|
||||
if (rTL > 0) generate_ellipse_stroke({ x1 + rTL, y1 + rTL }, rTL, rTL, thickness, M_PI, M_PI * 1.5f, color, segments(rTL));
|
||||
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));
|
||||
if (rBL > 0) generate_ellipse_stroke({ x1 + rBL, y2 - rBL }, rBL, rBL, thickness, M_PI * 0.5f, M_PI, color, segments(rBL));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!m_initialized || thickness <= 0)
|
||||
if (!m_initialized || thickness <= 0)
|
||||
return;
|
||||
|
||||
Vec2 center = { rect.x + rect.w*0.5f, rect.y + rect.h*0.5f };
|
||||
|
|
@ -526,9 +533,9 @@ namespace ogfx
|
|||
drawLine({ B, C }, color, thickness, false);
|
||||
drawLine({ C, A }, color, thickness, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BasicRenderer2D::fillRect(const Rectangle& rect, const Color& color)
|
||||
{
|
||||
|
|
@ -556,106 +563,172 @@ namespace ogfx
|
|||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
// Clamp radius
|
||||
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 x1 = rect.x;
|
||||
f32 y1 = rect.y;
|
||||
f32 x2 = rect.x + rect.w;
|
||||
f32 y2 = rect.y + rect.h;
|
||||
|
||||
f32 cx1 = x1 + radius;
|
||||
f32 cy1 = y1 + radius;
|
||||
f32 cx2 = x2 - radius;
|
||||
f32 cy2 = y2 - radius;
|
||||
// The largest corner radius on each side determines the inset for that side
|
||||
f32 topInset = std::max(rTL, rTR);
|
||||
f32 bottomInset = std::max(rBL, rBR);
|
||||
f32 leftInset = std::max(rTL, rBL);
|
||||
f32 rightInset = std::max(rTR, rBR);
|
||||
|
||||
// Number of segments for smooth corners
|
||||
i32 segments = std::max(6, i32(radius * 0.75f));
|
||||
|
||||
//
|
||||
// 1. Fill the center rectangle
|
||||
//
|
||||
// Center rectangle
|
||||
{
|
||||
Vec2 verts[4] = {
|
||||
{ cx1, cy1 },
|
||||
{ cx2, cy1 },
|
||||
{ cx2, cy2 },
|
||||
{ cx1, cy2 }
|
||||
{ x1 + leftInset, y1 + topInset },
|
||||
{ x2 - rightInset, y1 + topInset },
|
||||
{ x2 - rightInset, y2 - bottomInset },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
//
|
||||
// 2. Fill the four side rectangles
|
||||
//
|
||||
|
||||
// Top
|
||||
if (radius > 0)
|
||||
// Top strip
|
||||
{
|
||||
Vec2 verts[4] = {
|
||||
{ x1 + radius, y1 },
|
||||
{ x2 - radius, y1 },
|
||||
{ x2 - radius, y1 + radius },
|
||||
{ x1 + radius, y1 + radius }
|
||||
{ x1 + rTL, y1 },
|
||||
{ x2 - rTR, y1 },
|
||||
{ x2 - rTR, y1 + topInset },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
// Bottom
|
||||
// Bottom strip
|
||||
{
|
||||
Vec2 verts[4] = {
|
||||
{ x1 + radius, y2 - radius },
|
||||
{ x2 - radius, y2 - radius },
|
||||
{ x2 - radius, y2 },
|
||||
{ x1 + radius, y2 }
|
||||
{ x1 + rBL, y2 - bottomInset },
|
||||
{ x2 - rBR, y2 - bottomInset },
|
||||
{ x2 - rBR, 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);
|
||||
}
|
||||
|
||||
// Left
|
||||
// Left strip
|
||||
{
|
||||
Vec2 verts[4] = {
|
||||
{ x1, y1 + radius },
|
||||
{ x1 + radius, y1 + radius },
|
||||
{ x1 + radius, y2 - radius },
|
||||
{ x1, y2 - radius }
|
||||
{ x1, y1 + rTL },
|
||||
{ x1 + leftInset, y1 + rTL },
|
||||
{ x1 + leftInset, y2 - rBL },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
// Right
|
||||
// Right strip
|
||||
{
|
||||
Vec2 verts[4] = {
|
||||
{ x2 - radius, y1 + radius },
|
||||
{ x2, y1 + radius },
|
||||
{ x2, y2 - radius },
|
||||
{ x2 - radius, y2 - radius }
|
||||
{ x2 - rightInset, y1 + rTR },
|
||||
{ x2, y1 + rTR },
|
||||
{ x2, y2 - rBR },
|
||||
{ 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);
|
||||
}
|
||||
|
||||
//
|
||||
// 3. Fill the four rounded corners (quarter ellipses)
|
||||
//
|
||||
// Fill gaps between corners and strips when radii differ on the same side
|
||||
// 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
|
||||
generate_filled_ellipse_stroke({cx2, cy1}, radius, radius, 1.5f * M_PI, color, segments); // TR
|
||||
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
|
||||
}
|
||||
// Top-right gap
|
||||
if (rTR < topInset)
|
||||
{
|
||||
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)
|
||||
{
|
||||
fillRoundRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, radius);
|
||||
// Bottom-left gap
|
||||
if (rBL < bottomInset)
|
||||
{
|
||||
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)
|
||||
|
|
@ -714,9 +787,9 @@ namespace ogfx
|
|||
u32 inds[3] = { 0, 1, 2 };
|
||||
push_polygon(verts, texCoords, 3, inds, 3, color, nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BasicRenderer2D::outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness)
|
||||
{
|
||||
|
|
@ -733,15 +806,25 @@ namespace ogfx
|
|||
|
||||
void BasicRenderer2D::outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness)
|
||||
{
|
||||
if (!m_initialized) return;
|
||||
Rectangle offset = { 1, 1, -2, -2 };
|
||||
fillRoundRect(rect + offset, fillColor, radius);
|
||||
drawRoundRect(rect, outlineColor, radius, outlineThickness);
|
||||
outlinedRoundRect(rect, fillColor, outlineColor, { radius, radius, radius, radius }, 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)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@ namespace ogfx
|
|||
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 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 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 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 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 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 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 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 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);
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ custom_continue:
|
|||
{
|
||||
auto it = m_values.find(fullKey);
|
||||
// if (it != m_values.end())
|
||||
// std::cout << " GET: " << fullKey << "\n";
|
||||
// std::cout << " GET: " << fullKey << "\n";
|
||||
return it != m_values.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -231,6 +231,24 @@ custom_continue:
|
|||
if (key == "")
|
||||
return false;
|
||||
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.indexOf(" ") < 2)
|
||||
|
|
@ -249,10 +267,9 @@ custom_continue:
|
|||
valuePreserveCase.substr(1, value.len() - 1);
|
||||
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(value), themeID);
|
||||
set(key, Color(v), themeID);
|
||||
}
|
||||
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);
|
||||
}
|
||||
else if (exitCondition)
|
||||
{
|
||||
//Defaulting anything that isn't recognized as any value_type/variable to String type
|
||||
set(key, valuePreserveCase, themeID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exitCondition)
|
||||
|
|
|
|||
|
|
@ -153,8 +153,7 @@ class Window : public ogfx::gui::Window
|
|||
void onRedraw(ogfx::BasicRenderer2D& gfx) override
|
||||
{
|
||||
gfx.drawAnimation(m_anim, { 200, 200 });
|
||||
gfx.outlinedTriangle({ 30, 30 }, { 100, 50 }, { 60, 90 }, Colors::Crimson, Colors::DarkBlue, 5);
|
||||
gfx.endFrame();
|
||||
gfx.outlinedTriangle({ 30, 30 }, { 100, 50 }, { 60, 90 }, { 255, 0, 0, 80 }, Colors::DarkBlue, 5);
|
||||
}
|
||||
|
||||
void onFixedUpdate(void) override
|
||||
|
|
|
|||
Loading…
Reference in a new issue