Started work on TabPanel

This commit is contained in:
OmniaX-Dev 2026-04-20 14:45:40 +02:00
parent 27feac8fb7
commit 5491e5d4b3
9 changed files with 208 additions and 73 deletions

View file

@ -39,6 +39,33 @@ window.backgroundColor = rgba(160, 160, 160, 255)
% ====== Panel ======
(tabPanel) {
backgroundColor = #AAAAAAFF
borderColor = #909090FF
borderRadius = 0
borderWidth = 2
showBorder = true
showBackground = true
padding = rect(0, 0, 0, 0)
margin = rect(0, 0, 0, 0)
textColor = $textColor
(tabBar) {
height = 35.0
fontSize = 18
backgroundColor = #999999FF
borderColor = #909090FF
borderWidth = 2
}
}
(@panel_tab panel) {
backgroundColor = color_crimson
}
% ===================
% ====== Scrollbar ======
(scrollbar) {
(thumb) {
@ -156,20 +183,9 @@ window.backgroundColor = rgba(160, 160, 160, 255)
}
% ====================
% ====== Image ======
(image) {
path = file("img.png")
animated = true
animation = anim(frameCount: 36, \
fps: 60, \
columns: 9, \
rows: 4, \
frameWidth: 256, \
frameHeight: 256)
useBackgroundGradient = true
backgroundGradient = gradientV(color_crimson - $accentColorDark)
showBorder = true
borderWidth = 1
borderColor = $accentColorDark
borderRadius = 0
padding = rect(15, 15, 15, 15)
}
% ===================

View file

@ -1 +1 @@
2072
2073

View file

@ -136,13 +136,23 @@ namespace ogfx
disableFocus();
enableStopEvents();
setStylesheetCategoryName("tabPanel");
enableBackground();
enableBorder();
setTabBarHeight(m_tabBarHeight);
validate();
return *this;
}
void TabPanel::applyTheme(const ostd::Stylesheet& theme)
{
setTabBarHeight(getThemeValue<f32>(theme, "tabBar.height", m_tabBarHeight));
for (auto& tab : m_tabs)
{
if (tab == nullptr)
continue;
tab->setBackgroundColor(getBackgroundColor());
}
}
void TabPanel::onMouseReleased(const Event& event)
@ -152,13 +162,19 @@ namespace ogfx
void TabPanel::onDraw(ogfx::BasicRenderer2D& gfx)
{
gfx.outlinedRoundRect({ getGlobalPosition(), { getw(), m_tabBarHeight } }, m_tabBarBackgroundColor, m_tabBarBorderColor, m_tabBarBorderRadii, getBorderWidth());
draw_tabs(gfx);
}
Panel& TabPanel::addTab(const String& title)
{
m_tabs.push_back(std::make_unique<Panel>(getWindow()));
auto& tab = *m_tabs.back();
tab.setTitle(title);
tab.setTitlebarType(Panel::TitleBarTypes::None);
if (m_currentTab == nullptr && m_tabs.size() == 2)
setCurrentTab(tab);
tab.addThemeID("panel_tab");
// Initialization code here
return tab;
}
@ -211,6 +227,15 @@ namespace ogfx
return true;
}
void TabPanel::setTabBarHeight(f32 height)
{
if (height == m_tabBarHeight)
return;
m_tabBarHeight = height;
m_tabBarBorderRadii = { cast<f32>(getBorderRadius()), cast<f32>(getBorderRadius()), 0, 0 };
setContentOffset({ 0, m_tabBarHeight });
}
void TabPanel::prepare_for_current_tab_removal(void)
{
if (m_currentTab == nullptr)
@ -230,6 +255,38 @@ namespace ogfx
else
m_currentTab = (it + 1)->get(); // first tab being removed, go right
}
void TabPanel::draw_tabs(ogfx::BasicRenderer2D& gfx)
{
f32 nextTabX = 2;
for (const auto& _tab : m_tabs)
{
if (_tab == nullptr) continue;
const auto& tab = *_tab;
auto titleBounds = gfx.getStringDimensions(tab.getTitle(), getFontSize());
auto glob = getGlobalPosition();
Rectangle tabBounds { glob + Vec2 { nextTabX, 2}, { titleBounds.x + (m_tabSidePadding * 2), m_tabBarHeight - 3 } };
if (m_currentTab == _tab.get())
{
gfx.outlinedRect(tabBounds, tab.getBackgroundColor(), Colors::Black, 1, true, true, false, true);
}
else
{
gfx.drawRect(tabBounds, Colors::Black, 1, true, true, false, true);
}
gfx.drawCenteredString(tab.getTitle(), tabBounds, getTextColor(), getFontSize());
nextTabX += titleBounds.x + (m_tabSidePadding * 2);
// f32 titleY = (m_tabBarHeight / 2.0f) - (titleBounds.y / 2.0f);
// if (m_currentTab == _tab.get())
// {
// gfx.fillRect({ getGlobalPosition() + Vec2 { nextTabX, 0 }, { (titleBounds.x * 2), m_tabBarHeight } }, tab.getBackgroundColor());
// }
// gfx.drawString(tab.getTitle(), getGlobalPosition() + Vec2 { nextTabX + m_tabSidePadding, titleY }, getTextColor(), getFontSize());
// nextTabX += titleBounds.x + (m_tabSidePadding * 2);
// gfx.drawLine({ getGlobalPosition() + Vec2 { nextTabX, 0 }, getGlobalPosition() + Vec2 { nextTabX, m_tabBarHeight - 3 } }, Colors::Black, 2);
}
}
}
}
}

View file

@ -82,15 +82,21 @@ namespace ogfx
bool removeTab(const String& title);
bool setCurrentTab(Panel& tab);
bool setCurrentTab(i32 index);
void setTabBarHeight(f32 height);
private:
void prepare_for_current_tab_removal(void);
void draw_tabs(ogfx::BasicRenderer2D& gfx);
private:
stdvec<std::unique_ptr<Panel>> m_tabs;
Panel* m_currentTab { nullptr };
Rectangle m_tabBarBorderRadii { 0, 0, 0, 0 };
f32 m_tabBarHeight { 30 };
f32 m_tabBarHeight { 35 };
Color m_tabBarBackgroundColor { 120, 120, 120 };
Color m_tabBarBorderColor { 170, 170, 170 };
f32 m_tabSidePadding { 20 };
};
}
}

View file

@ -477,7 +477,7 @@ namespace ogfx
generate_half_circle(p2, dir, half, segments, color, true);
}
void BasicRenderer2D::drawRect(const Rectangle& rect, const Color& color, i32 thickness)
void BasicRenderer2D::drawRect(const Rectangle& rect, const Color& color, i32 thickness, bool topEdge, bool rightEdge, bool bottomEdge, bool leftEdge)
{
if (!m_initialized || thickness <= 0)
return;
@ -491,21 +491,25 @@ namespace ogfx
f32 y2 = rect.y + rect.h - half;
// Top
drawLine({ {x1, y1}, {x2, y1} }, color, thickness, false);
if (topEdge)
drawLine({ {x1, y1}, {x2, y1} }, color, thickness, false);
// Right
drawLine({ {x2, y1 - half}, {x2, y2 + half} }, color, thickness, false);
if (rightEdge)
drawLine({ {x2, y1 - half}, {x2, y2 + half} }, color, thickness, false);
// Bottom
drawLine({ {x2, y2}, {x1, y2} }, color, thickness, false);
if (bottomEdge)
drawLine({ {x2, y2}, {x1, y2} }, color, thickness, false);
// Left
drawLine({ {x1, y2 + half}, {x1, y1 - half} }, color, thickness, false);
if (leftEdge)
drawLine({ {x1, y2 + half}, {x1, y1 - half} }, color, thickness, false);
}
void BasicRenderer2D::drawRect(const Vec2& center, const Vec2& size, const Color& color, i32 thickness)
void BasicRenderer2D::drawRect(const Vec2& center, const Vec2& size, const Color& color, i32 thickness, bool topEdge, bool rightEdge, bool bottomEdge, bool leftEdge)
{
drawRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, thickness);
drawRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, color, thickness, topEdge, rightEdge, bottomEdge, leftEdge);
}
void BasicRenderer2D::drawRoundRect(const Rectangle& rect, const Color& color, f32 radius, i32 thickness)
@ -864,17 +868,17 @@ namespace ogfx
void BasicRenderer2D::outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness)
void BasicRenderer2D::outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness, bool topEdge, bool rightEdge, bool bottomEdge, bool leftEdge)
{
if (!m_initialized) return;
Rectangle offset = { 1, 1, -2, -2 };
fillRect(rect + offset, fillColor);
drawRect(rect, outlineColor, outlineThickness);
drawRect(rect, outlineColor, outlineThickness, topEdge, rightEdge, bottomEdge, leftEdge);
}
void BasicRenderer2D::outlinedRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, i32 outlineThickness)
void BasicRenderer2D::outlinedRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, i32 outlineThickness, bool topEdge, bool rightEdge, bool bottomEdge, bool leftEdge)
{
outlinedRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, fillColor, outlineColor, outlineThickness);
outlinedRect({ center.x - size.x * 0.5f, center.y - size.y * 0.5f, size.x, size.y }, fillColor, outlineColor, outlineThickness, topEdge, rightEdge, bottomEdge, leftEdge);
}
void BasicRenderer2D::outlinedRoundRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, f32 radius, i32 outlineThickness)

View file

@ -88,8 +88,8 @@ namespace ogfx
void drawCenteredString(const String& str, const Rectangle& bounds, const Color& color, i32 fontSize = 0, f32 scale = 1.0f);
void drawLine(const FLine& line, const Color& color, i32 thickness = 1, bool rounded = true);
void drawRect(const Rectangle& rect, const Color& color, i32 thickness = 1);
void drawRect(const Vec2& center, const Vec2& size, const Color& color, i32 thickness = 1);
void drawRect(const Rectangle& rect, const Color& color, i32 thickness = 1, bool topEdge = true, bool rightEdge = true, bool bottomEdge = true, bool leftEdge = true);
void drawRect(const Vec2& center, const Vec2& size, const Color& color, i32 thickness = 1, bool topEdge = true, bool rightEdge = true, bool bottomEdge = true, bool leftEdge = true);
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);
@ -112,8 +112,8 @@ namespace ogfx
void fillTriangle(const Triangle& tri, const Color& color);
void fillTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Color& color);
void outlinedRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1);
void outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1);
void outlinedRect(const Vec2& center, const Vec2& size, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1, bool topEdge = true, bool rightEdge = true, bool bottomEdge = true, bool leftEdge = true);
void outlinedRect(const Rectangle& rect, const Color& fillColor, const Color& outlineColor, i32 outlineThickness = 1, bool topEdge = true, bool rightEdge = true, bool bottomEdge = true, bool leftEdge = true);
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);

View file

@ -208,15 +208,40 @@ namespace ostd
{
if (m_dirty)
{
m_cachedFloat = {
r.value * (1.0f / 255.0f),
g.value * (1.0f / 255.0f),
b.value * (1.0f / 255.0f),
a.value * (1.0f / 255.0f)
};
m_dirty = false;
}
return m_cachedFloat;
m_cachedFloat = {
r.value * (1.0f / 255.0f),
g.value * (1.0f / 255.0f),
b.value * (1.0f / 255.0f),
a.value * (1.0f / 255.0f)
};
m_dirty = false;
}
return m_cachedFloat;
}
Color Color::darkened(f32 amount) const
{
f32 h, s, v;
RGBtoHSV(r.value / 255.0f, g.value / 255.0f, b.value / 255.0f, h, s, v);
v = std::clamp(v - amount, 0.0f, 1.0f);
f32 nr, ng, nb;
HSVtoRGB(h, s, v, nr, ng, nb);
return {
cast<u8>(nr * 255),
cast<u8>(ng * 255),
cast<u8>(nb * 255),
cast<u8>(a.value)
};
}
Color Color::scaled(f32 factor) const
{
return {
cast<u8>(std::clamp(r.value * factor, 0.0f, 255.0f)),
cast<u8>(std::clamp(g.value * factor, 0.0f, 255.0f)),
cast<u8>(std::clamp(b.value * factor, 0.0f, 255.0f)),
cast<u8>(a.value)
};
}
String Color::toString(void) const
@ -237,45 +262,45 @@ namespace ostd
void Color::RGBtoHSV(f32 r, f32 g, f32 b, f32& h, f32& s, f32& v)
{
f32 max = std::max({r, g, b});
f32 min = std::min({r, g, b});
f32 d = max - min;
f32 max = std::max({r, g, b});
f32 min = std::min({r, g, b});
f32 d = max - min;
v = max;
v = max;
if (max == 0)
{
s = 0;
h = 0;
return;
}
if (max == 0)
{
s = 0;
h = 0;
return;
}
s = d / max;
s = d / max;
if (max == r) h = std::fmod((g - b) / d + 6.0f, 6.0f);
else if (max == g) h = (b - r) / d + 2.0f;
else h = (r - g) / d + 4.0f;
if (max == r) h = std::fmod((g - b) / d + 6.0f, 6.0f);
else if (max == g) h = (b - r) / d + 2.0f;
else h = (r - g) / d + 4.0f;
h /= 6.0f;
h /= 6.0f;
}
void Color::HSVtoRGB(f32 h, f32 s, f32 v, f32& r, f32& g, f32& b)
{
i32 i = cast<i32>(h * 6);
f32 f = h * 6 - i;
f32 p = v * (1 - s);
f32 q = v * (1 - f * s);
f32 t = v * (1 - (1 - f) * s);
i32 i = cast<i32>(h * 6);
f32 f = h * 6 - i;
f32 p = v * (1 - s);
f32 q = v * (1 - f * s);
f32 t = v * (1 - (1 - f) * s);
switch (i % 6)
{
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
switch (i % 6)
{
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
}
}

View file

@ -79,6 +79,13 @@ namespace ostd
u32 asInteger(eColorFormat format = eColorFormat::RGBA) const;
FloatCol getNormalizedColor(void) const;
inline Color& darken(f32 amount) { Color c = darkened(amount); set(c.r, c.g, c.b, c.a); return *this; }
inline Color& lighten(f32 amount) { Color c = lightened(amount); set(c.r, c.g, c.b, c.a); return *this; }
inline Color& scale(f32 amount) { Color c = scaled(amount); set(c.r, c.g, c.b, c.a); return *this; }
inline Color lightened(f32 amount) const { return darkened(amount); }
Color darkened(f32 amount) const;
Color scaled(f32 factor) const;
String toString(void) const override;
void print(bool newLine = true, OutputHandlerBase* __destination = nullptr) const override;
inline void invalidate(void) override { }

View file

@ -32,6 +32,18 @@ class Window : public ogfx::gui::Window
inline Window(void) { }
inline void onInitialize(void) override
{
ogfx::AnimationData ad;
ad.frameCount = 36;
ad.fps = 60;
ad.columns = 9;
ad.rows = 4;
ad.frameWidth = 256;
ad.frameHeight = 256;
m_img.setAnimationData(ad);
m_img.setImage("./img.png");
m_img.enableAnimated();
m_img.setSize(256, 256);
m_label1.setText("Show Panel2");
m_label1.setCallback(ogfx::gui::Widget::eCallback::MousePressed, [&](const ogfx::gui::Event& event) -> void {
m_check1.setChecked(!m_check1.isChecked());
@ -78,6 +90,11 @@ class Window : public ogfx::gui::Window
m_panel2.setSize(600, 400);
m_panel2.setTitle("Panel 2");
m_tabs.setSize(400, 400);
m_tabs.addTab("Tab1");
m_tabs.addTab("Tab2 Test");
m_tabs.addTab("Long Tab Test");
m_panel3.addWidget(m_label4);
m_panel1.addWidget(m_label2);
@ -88,10 +105,11 @@ class Window : public ogfx::gui::Window
m_panel2.addWidget(m_panel1, { 400, 50 });
m_panel2.addWidget(m_label1, { 0, 500 });
m_panel2.addWidget(m_btn1, { 0, 300 });
m_panel2.addWidget(m_img, { 20, 150 });
m_panel2.addWidget(m_img, { 20, 50 });
addWidget(m_check1, { 30, 30 });
addWidget(m_panel2, { 500, 100 });
addWidget(m_tabs, { 20, 120 });
m_theme.loadFromFile("./DefaultTheme.oss", true, getDefaultStylesheetVariableList());
setTheme(m_theme);
@ -109,6 +127,7 @@ class Window : public ogfx::gui::Window
void onRedraw(ogfx::BasicRenderer2D& gfx) override
{
gfx.fillRect(m_tabs.getGlobalPureContentBounds(), { 0, 255, 0, 100 });
}
void onFixedUpdate(void) override
@ -127,6 +146,7 @@ class Window : public ogfx::gui::Window
CheckBox m_check1 { *this };
Button m_btn1 { *this };
ImageLabel m_img { *this };
TabPanel m_tabs { *this };
ostd::Stylesheet m_theme;
};
@ -138,7 +158,7 @@ i32 main(i32 argc, char** argv)
window.initialize(1200, 800, "OmniaFramework - Test Window");
window.setClearColor({ 0, 0, 0 });
window.setPosition({ 50, 50 });
window.setWindowState(ogfx::WindowCore::eWindowState::Maximized);
// window.setWindowState(ogfx::WindowCore::eWindowState::Maximized);
window.mainLoop();
return 0;
}