Added Image/Animation to Button widget

This commit is contained in:
OmniaX-Dev 2026-04-21 12:36:35 +02:00
parent 32ed5099f1
commit 8c174fb863
6 changed files with 149 additions and 77 deletions

View file

@ -160,15 +160,17 @@ window.backgroundColor = rgba(160, 160, 160, 255)
useBackgroundGradient = true
padding = rect(15, 8, 15, 8)
margin = rect(0, 0, 0, 0)
showIcon = true
(icon) {
show = true
image = file("img.png")
path = file("img.png")
animation = anim(frameCount: 36, \
fps: 60, \
columns: 9, \
rows: 4, \
frameWidth: 256, \
frameHeight: 256)
size = vec2(32, 32)
animated = true
}
}
(button:hover) {

View file

@ -40,7 +40,7 @@ Implement following widgets:
***Image / Icon
***Tab Panel
***Button
Image/Icon
***Image/Icon
Radio Button
Grouping
Text Input

View file

@ -20,6 +20,8 @@
#include "Button.hpp"
#include "../../render/BasicRenderer.hpp"
#include "../../../ostd/io/FileSystem.hpp"
#include "../Window.hpp"
namespace ogfx
{
@ -41,24 +43,69 @@ namespace ogfx
void Button::onDraw(ogfx::BasicRenderer2D& gfx)
{
if (m_textChanged)
__update_size(gfx);
gfx.drawString(getText(), getGlobalContentPosition(), getTextColor(), getFontSize());
// if (m_textChanged)
__update_size();
if (isIconEnabled())
{
m_realIconSize = getIconSize().propy(getGlobalContentBounds().getSize().y);
if (isAnimatedEnabled())
gfx.drawAnimation(m_anim, getGlobalContentPosition(), m_realIconSize);
else
gfx.drawImage(m_icon, getGlobalContentPosition(), m_realIconSize);
}
gfx.drawString(getText(), getGlobalContentPosition() + Vec2 { m_realIconSize.x + m_iconSpacing, 0 }, getTextColor(), getFontSize());
}
void Button::onUpdate(void)
{
if (isAnimatedEnabled())
m_anim.update();
}
void Button::setText(const String& text)
{
m_text = text;
m_textChanged = true;
__update_size();
}
void Button::__update_size(ogfx::BasicRenderer2D& gfx)
void Button::setIcon(const String& filePath)
{
auto size = gfx.getStringDimensions(getText(), getFontSize());
disableIcon();
if (filePath == "") return;
if (!ostd::FileSystem::fileExists(filePath))
return;
m_icon.destroy();
m_icon.loadFromFile(filePath, getWindow().getGFX());
enableIcon();
}
void Button::applyTheme(const ostd::Stylesheet& theme)
{
enableIcon(getThemeValue<bool>(theme, "showIcon", m_showIcon));
enableAnimated(getThemeValue<bool>(theme, "icon.animated", m_animated));
setAnimationData(getThemeValue<AnimationData>(theme, "icon.animation", m_animData));
String filePath = getThemeValue<String>(theme, "icon.path", m_icon.getFilePath());
if (filePath != m_icon.getFilePath())
setIcon(filePath);
setIconSize(getThemeValue<Vec2>(theme, "icon.size", getSize()));
if (isAnimatedEnabled())
{
m_anim.create(m_animData);
m_anim.setSpriteSheet(m_icon);
}
__update_size();
}
void Button::__update_size(void)
{
auto size = getWindow().getGFX().getStringDimensions(getText(), getFontSize());
size.x += getPadding().left();
size.x += getPadding().right();
size.y += getPadding().top();
size.y += getPadding().bottom();
if (isIconEnabled())
size.x += m_iconSpacing + m_realIconSize.x;
setSize({ cast<f32>(size.x), cast<f32>(size.y) });
m_textChanged = false;
}

View file

@ -21,6 +21,8 @@
#pragma once
#include <ogfx/gui/widgets/Widget.hpp>
#include <ogfx/resources/Image.hpp>
#include <ogfx/utils/Animation.hpp>
namespace ogfx
{
@ -35,15 +37,32 @@ namespace ogfx
inline Button(WindowCore& window, const String& text) : Widget({ 0, 0, 0, 0 }, window) { create(text); }
Button& create(const String& text);
void onDraw(ogfx::BasicRenderer2D& gfx) override;
void onUpdate(void) override;
void setText(const String& text);
void setIcon(const String& filePath);
void applyTheme(const ostd::Stylesheet& theme) override;
OSTD_BOOL_PARAM_GETSET_E(Animated, m_animated);
inline String getText(void) const { return m_text; }
inline Image& getIcon(void) { return m_icon; }
OSTD_BOOL_PARAM_GETSET_E(Icon, m_showIcon);
OSTD_PARAM_GETSET(ostd::AnimationData, AnimationData, m_animData);
OSTD_PARAM_GETSET(Vec2, IconSize, m_iconSize);
private:
void __update_size(ogfx::BasicRenderer2D& gfx);
void __update_size(void);
private:
String m_text { "" };
bool m_textChanged { false };
bool m_textChanged { true };
Image m_icon;
Vec2 m_realIconSize { 0, 0 };
bool m_showIcon { false };
ostd::AnimationData m_animData;
Animation m_anim;
bool m_animated { false };
f32 m_iconSpacing { 10 };
Vec2 m_iconSize { 0, 0 };
};
}
}

View file

@ -207,6 +207,7 @@ namespace ogfx
if (m_currentTab == nullptr && m_tabs.size() == 1)
setCurrentTab(tab);
tab.addThemeID("panel_tab");
tab.reloadTheme(true);
return tab;
}

View file

@ -47,8 +47,8 @@ namespace ostd
struct Vec2 : public __i_stringeable
{
//======================== Data ========================
f32 x;
f32 y;
f32 x { 0.0f };
f32 y { 0.0f };
//======================================================
@ -75,13 +75,14 @@ namespace ostd
//===================== Operations =====================
inline f32 mag(void) const { return std::sqrt((x * x) + (y * y)); }
inline Vec2 add(Vec2 v2) const { return { x + v2.x, y + v2.y }; }
inline Vec2 add(f32 x2, f32 y2) const { return { x + x2, y + y2 }; }
inline Vec2 sub(Vec2 v2) const { return { x - v2.x, y - v2.y }; }
inline Vec2 sub(f32 x2, f32 y2) const { return { x - x2, y - y2 }; }
inline Vec2 mul(f32 scalar) const { return { x * scalar, y * scalar }; }
inline Vec2 div(f32 scalar) const { return { x / scalar, y / scalar }; }
inline Vec2 propx(f32 new_x) const { return { new_x, new_x * (y / x) }; }
inline Vec2 propy(f32 new_y) const { return { new_y * (x / y), new_y }; }
inline Vec2 normalize(void) const { f32 m = _zp(mag()); return { x / m, y / m }; }
inline f32 dist(Vec2 v2) const { return std::sqrt((f32)((v2.x - x) * (v2.x - x)) + ((v2.y - y) * (v2.y - y))); }
@ -99,6 +100,8 @@ namespace ostd
inline Vec2& subm(const f32& x2, const f32& y2) { x -= x2; y -= y2; return *this; }
inline Vec2& mulm(const f32& scalar) { x *= scalar; y *= scalar; return *this; }
inline Vec2& divm(const f32& scalar) { x /= scalar; y /= scalar; return *this; }
inline Vec2& propxm(const f32& new_x) { x = new_x; y = new_x * (y / x); return *this; }
inline Vec2& propym(const f32& new_y) { x = new_y * (x / y); y = new_y; return *this; }
inline Vec2& normalizem(void) { f32 m = _zp(mag()); x /= m; y /= m; return *this; }
inline Vec2& setMag(const f32& mag) { return normalizem().mulm(mag); }
@ -109,19 +112,19 @@ namespace ostd
//===================== Operators ======================
inline bool operator==(const Vec2& op2 ) const { return (x == op2.x && y == op2.y); }
inline bool operator!=(const Vec2& op2 ) const { return (x != op2.x || y != op2.y); }
inline bool operator==(const Vec2& op2) const { return (x == op2.x && y == op2.y); }
inline bool operator!=(const Vec2& op2) const { return (x != op2.x || y != op2.y); }
inline Vec2 operator-() const { return { -x, -y }; }
inline Vec2 operator+ (const Vec2& op2 ) const { return add(op2); }
inline Vec2 operator- (const Vec2& op2 ) const { return sub(op2); }
inline Vec2 operator+ (const Vec2& op2) const { return add(op2); }
inline Vec2 operator- (const Vec2& op2) const { return sub(op2); }
inline Vec2 operator+ (const f32& op2) const { return add(op2, op2); }
inline Vec2 operator- (const f32& op2) const { return sub(op2, op2); }
inline Vec2 operator* (const f32& op2) const { return mul(op2); }
inline Vec2 operator/ (const f32& op2) const { return div(op2); }
inline Vec2& operator= (const Vec2& val ) { return set(val); }
inline Vec2& operator= (const Vec2& val) { return set(val); }
inline Vec2& operator= (const f32& val) { return set(val, val); }
inline Vec2& operator+=(const Vec2& op2 ) { return addm(op2); }
inline Vec2& operator-=(const Vec2& op2 ) { return subm(op2); }
inline Vec2& operator+=(const Vec2& op2) { return addm(op2); }
inline Vec2& operator-=(const Vec2& op2) { return subm(op2); }
inline Vec2& operator+=(const f32& op2) { return addm(op2, op2); }
inline Vec2& operator-=(const f32& op2) { return subm(op2, op2); }
inline Vec2& operator*=(const f32& op2) { return mulm(op2); }