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 useBackgroundGradient = true
padding = rect(15, 8, 15, 8) padding = rect(15, 8, 15, 8)
margin = rect(0, 0, 0, 0) margin = rect(0, 0, 0, 0)
showIcon = true
(icon) { (icon) {
show = true path = file("img.png")
image = file("img.png")
animation = anim(frameCount: 36, \ animation = anim(frameCount: 36, \
fps: 60, \ fps: 60, \
columns: 9, \ columns: 9, \
rows: 4, \ rows: 4, \
frameWidth: 256, \ frameWidth: 256, \
frameHeight: 256) frameHeight: 256)
size = vec2(32, 32)
animated = true
} }
} }
(button:hover) { (button:hover) {

View file

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

View file

@ -20,6 +20,8 @@
#include "Button.hpp" #include "Button.hpp"
#include "../../render/BasicRenderer.hpp" #include "../../render/BasicRenderer.hpp"
#include "../../../ostd/io/FileSystem.hpp"
#include "../Window.hpp"
namespace ogfx namespace ogfx
{ {
@ -41,24 +43,69 @@ namespace ogfx
void Button::onDraw(ogfx::BasicRenderer2D& gfx) void Button::onDraw(ogfx::BasicRenderer2D& gfx)
{ {
if (m_textChanged) // if (m_textChanged)
__update_size(gfx); __update_size();
gfx.drawString(getText(), getGlobalContentPosition(), getTextColor(), getFontSize()); 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) void Button::setText(const String& text)
{ {
m_text = 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().left();
size.x += getPadding().right(); size.x += getPadding().right();
size.y += getPadding().top(); size.y += getPadding().top();
size.y += getPadding().bottom(); size.y += getPadding().bottom();
if (isIconEnabled())
size.x += m_iconSpacing + m_realIconSize.x;
setSize({ cast<f32>(size.x), cast<f32>(size.y) }); setSize({ cast<f32>(size.x), cast<f32>(size.y) });
m_textChanged = false; m_textChanged = false;
} }

View file

@ -21,6 +21,8 @@
#pragma once #pragma once
#include <ogfx/gui/widgets/Widget.hpp> #include <ogfx/gui/widgets/Widget.hpp>
#include <ogfx/resources/Image.hpp>
#include <ogfx/utils/Animation.hpp>
namespace ogfx namespace ogfx
{ {
@ -35,15 +37,32 @@ namespace ogfx
inline Button(WindowCore& window, const String& text) : Widget({ 0, 0, 0, 0 }, window) { create(text); } inline Button(WindowCore& window, const String& text) : Widget({ 0, 0, 0, 0 }, window) { create(text); }
Button& create(const String& text); Button& create(const String& text);
void onDraw(ogfx::BasicRenderer2D& gfx) override; void onDraw(ogfx::BasicRenderer2D& gfx) override;
void onUpdate(void) override;
void setText(const String& text); 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 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: private:
void __update_size(ogfx::BasicRenderer2D& gfx); void __update_size(void);
private: private:
String m_text { "" }; 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) if (m_currentTab == nullptr && m_tabs.size() == 1)
setCurrentTab(tab); setCurrentTab(tab);
tab.addThemeID("panel_tab"); tab.addThemeID("panel_tab");
tab.reloadTheme(true);
return tab; return tab;
} }

View file

@ -47,85 +47,88 @@ namespace ostd
struct Vec2 : public __i_stringeable struct Vec2 : public __i_stringeable
{ {
//======================== Data ======================== //======================== Data ========================
f32 x; f32 x { 0.0f };
f32 y; f32 y { 0.0f };
//====================================================== //======================================================
//==================== Construction ==================== //==================== Construction ====================
inline Vec2(f32 xx = 0, f32 yy = 0) : x(xx), y(yy) { } inline Vec2(f32 xx = 0, f32 yy = 0) : x(xx), y(yy) { }
inline Vec2(const Vec2& v2) { set(v2); } inline Vec2(const Vec2& v2) { set(v2); }
inline Vec2& set(const Vec2& v2) { x = v2.x; y = v2.y; return *this; } inline Vec2& set(const Vec2& v2) { x = v2.x; y = v2.y; return *this; }
inline Vec2& set(f32 xx, f32 yy) { x = xx; y = yy; return *this; } inline Vec2& set(f32 xx, f32 yy) { x = xx; y = yy; return *this; }
//====================================================== //======================================================
//================== Static Functions ================== //================== Static Functions ==================
inline static Vec2 fromAngle(f32 angle) { return Vec2(std::cos(angle), std::sin(angle)); } inline static Vec2 fromAngle(f32 angle) { return Vec2(std::cos(angle), std::sin(angle)); }
inline static f32 angleBetween(const Vec2& v1, const Vec2& v2) { return std::acos(v1.dot(v2) / (v1.mag() * v2.mag())); } inline static f32 angleBetween(const Vec2& v1, const Vec2& v2) { return std::acos(v1.dot(v2) / (v1.mag() * v2.mag())); }
//====================================================== //======================================================
//===================== Conversion ===================== //===================== Conversion =====================
inline Vec2 toIsometric(void) const { return Vec2(x - y, (x + y) / 2.0f); } inline Vec2 toIsometric(void) const { return Vec2(x - y, (x + y) / 2.0f); }
inline Vec2 toCartesian(void) const { return Vec2((2 * y + x) / 2.0f, (2 * y - x) / 2.0f); } inline Vec2 toCartesian(void) const { return Vec2((2 * y + x) / 2.0f, (2 * y - x) / 2.0f); }
inline String toString(void) const override { return String("{ ").add(x).add(", ").add(y).add(" }"); } inline String toString(void) const override { return String("{ ").add(x).add(", ").add(y).add(" }"); }
//====================================================== //======================================================
//===================== Operations ===================== //===================== Operations =====================
inline f32 mag(void) const { return std::sqrt((x * x) + (y * y)); } 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 add(Vec2 v2) const { return { x + v2.x, y + v2.y }; } inline Vec2 normalize(void) const { f32 m = _zp(mag()); return { x / m, y / m }; }
inline Vec2 add(f32 x2, f32 y2) const { return { x + x2, y + y2 }; } inline f32 dist(Vec2 v2) const { return std::sqrt((f32)((v2.x - x) * (v2.x - x)) + ((v2.y - y) * (v2.y - y))); }
inline Vec2 sub(Vec2 v2) const { return { x - v2.x, y - v2.y }; } inline f32 heading(void) const { return std::atan2(y, x); }
inline Vec2 sub(f32 x2, f32 y2) const { return { x - x2, y - y2 }; } inline Vec2 rotate(f32 angle) const { return Vec2(*this).rotate(angle); }
inline Vec2 mul(f32 scalar) const { return { x * scalar, y * scalar }; } inline f32 dot(const Vec2& v2) const { return (x * v2.x) + (y * v2.y); }
inline Vec2 div(f32 scalar) const { return { x / scalar, y / scalar }; } inline f32 cross(const Vec2& v2) const { return (x * v2.y) - (v2.x * 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))); }
inline f32 heading(void) const { return std::atan2(y, x); }
inline Vec2 rotate(f32 angle) const { return Vec2(*this).rotate(angle); }
inline f32 dot(const Vec2& v2) const { return (x * v2.x) + (y * v2.y); }
inline f32 cross(const Vec2& v2) const { return (x * v2.y) - (v2.x * y); }
//====================================================== //======================================================
//===================== Modifiers ====================== //===================== Modifiers ======================
inline Vec2& addm(const Vec2& v2) { x += v2.x; y += v2.y; return *this; } inline Vec2& addm(const Vec2& v2) { x += v2.x; y += v2.y; return *this; }
inline Vec2& addm(const f32& x2, const f32& y2) { x += x2; y += y2; return *this; } inline Vec2& addm(const f32& x2, const f32& y2) { x += x2; y += y2; return *this; }
inline Vec2& subm(const Vec2& v2) { x -= v2.x; y -= v2.y; return *this; } inline Vec2& subm(const Vec2& v2) { x -= v2.x; y -= v2.y; return *this; }
inline Vec2& subm(const f32& x2, const f32& y2) { x -= x2; y -= y2; return *this; } 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& mulm(const f32& scalar) { x *= scalar; y *= scalar; return *this; }
inline Vec2& divm(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& normalizem(void) { f32 m = _zp(mag()); x /= m; y /= m; return *this; }
inline Vec2& setMag(const f32& mag) { return normalizem().mulm(mag); } inline Vec2& setMag(const f32& mag) { return normalizem().mulm(mag); }
inline Vec2& setHeading(const f32& angle) { f32 m = mag(); set(m * std::cos(angle), m * std::sin(angle)); return *this; } inline Vec2& setHeading(const f32& angle) { f32 m = mag(); set(m * std::cos(angle), m * std::sin(angle)); return *this; }
inline Vec2& rotate(const f32& angle) { return setHeading(heading() + angle); } inline Vec2& rotate(const f32& angle) { return setHeading(heading() + angle); }
inline Vec2& limit(const f32& max) { f32 msq = mag(); msq *= msq; if (msq > (max * max)) divm(std::sqrt(msq)).mulm(max); return *this; } inline Vec2& limit(const f32& max) { f32 msq = mag(); msq *= msq; if (msq > (max * max)) divm(std::sqrt(msq)).mulm(max); return *this; }
//====================================================== //======================================================
//===================== Operators ====================== //===================== 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 { return { -x, -y }; }
inline Vec2 operator+ (const Vec2& op2 ) const { return add(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 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 add(op2, op2); }
inline Vec2 operator- (const f32& op2) const { return sub(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 mul(op2); }
inline Vec2 operator/ (const f32& op2) const { return div(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 f32& val) { return set(val, val); }
inline Vec2& operator+=(const Vec2& op2 ) { return addm(op2); } 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 subm(op2); }
inline Vec2& operator+=(const f32& op2) { return addm(op2, 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 subm(op2, op2); }
inline Vec2& operator*=(const f32& op2) { return mulm(op2); } inline Vec2& operator*=(const f32& op2) { return mulm(op2); }
inline Vec2& operator/=(const f32& op2) { return divm(op2); } inline Vec2& operator/=(const f32& op2) { return divm(op2); }
//====================================================== //======================================================
private: private:
@ -141,30 +144,30 @@ namespace ostd
T y; T y;
public: public:
inline Point(void) : x(0), y(0) { } inline Point(void) : x(0), y(0) { }
inline Point(T xx, T yy) : x(xx), y(yy) {} inline Point(T xx, T yy) : x(xx), y(yy) {}
inline Point(const Vec2& vec) { x = vec.x; y = vec.y; } inline Point(const Vec2& vec) { x = vec.x; y = vec.y; }
inline Point<T>& set(const Point<T>& v2) { x = v2.x; y = v2.y; return *this; } inline Point<T>& set(const Point<T>& v2) { x = v2.x; y = v2.y; return *this; }
inline Point<T>& set(f32 xx, f32 yy) { x = xx; y = yy; return *this; } inline Point<T>& set(f32 xx, f32 yy) { x = xx; y = yy; return *this; }
//===================== Operators ====================== //===================== Operators ======================
inline bool operator==(const Point<T>& op2 ) const { return (x == op2.x && y == op2.y); } inline bool operator==(const Point<T>& op2 ) const { return (x == op2.x && y == op2.y); }
inline bool operator!=(const Point<T>& op2 ) const { return (x != op2.x || y != op2.y); } inline bool operator!=(const Point<T>& op2 ) const { return (x != op2.x || y != op2.y); }
inline operator Vec2() const { return { cast<f32>(x), cast<f32>(y) }; } inline operator Vec2() const { return { cast<f32>(x), cast<f32>(y) }; }
inline Point<T> operator+ (const Point<T>& op2 ) const { return { x + op2.x, y + op2.y }; } inline Point<T> operator+ (const Point<T>& op2 ) const { return { x + op2.x, y + op2.y }; }
inline Point<T> operator- (const Point<T>& op2 ) const { return { x - op2.x, y - op2.y }; } inline Point<T> operator- (const Point<T>& op2 ) const { return { x - op2.x, y - op2.y }; }
inline Point<T> operator+ (const T& op2) const { return { x + op2, y + op2 }; } inline Point<T> operator+ (const T& op2) const { return { x + op2, y + op2 }; }
inline Point<T> operator- (const T& op2) const { return { x + op2, y + op2 }; } inline Point<T> operator- (const T& op2) const { return { x + op2, y + op2 }; }
inline Point<T> operator* (const T& op2) const { return { x * op2, y * op2 }; } inline Point<T> operator* (const T& op2) const { return { x * op2, y * op2 }; }
inline Point<T> operator/ (const T& op2) const { return { x / op2, y / op2 }; } inline Point<T> operator/ (const T& op2) const { return { x / op2, y / op2 }; }
inline Point<T>& operator= (const Point<T>& val ) { return set(val); } inline Point<T>& operator= (const Point<T>& val ) { return set(val); }
inline Point<T>& operator= (const T& val) { return set(val, val); } inline Point<T>& operator= (const T& val) { return set(val, val); }
inline Point<T>& operator+=(const Point<T>& op2 ) { x += op2.x; y += op2.y; return *this; } inline Point<T>& operator+=(const Point<T>& op2 ) { x += op2.x; y += op2.y; return *this; }
inline Point<T>& operator-=(const Point<T>& op2 ) { x -= op2.x; y -= op2.y; return *this; } inline Point<T>& operator-=(const Point<T>& op2 ) { x -= op2.x; y -= op2.y; return *this; }
inline Point<T>& operator+=(const T& op2) { x += op2; y += op2; return *this;; } inline Point<T>& operator+=(const T& op2) { x += op2; y += op2; return *this;; }
inline Point<T>& operator-=(const T& op2) { x -= op2; y -= op2; return *this; } inline Point<T>& operator-=(const T& op2) { x -= op2; y -= op2; return *this; }
inline Point<T>& operator*=(const T& op2) { return x *= op2; y *= op2; return *this; } inline Point<T>& operator*=(const T& op2) { return x *= op2; y *= op2; return *this; }
inline Point<T>& operator/=(const T& op2) { return x /= op2; y /= op2; return *this; } inline Point<T>& operator/=(const T& op2) { return x /= op2; y /= op2; return *this; }
//====================================================== //======================================================
template <class T2> inline Point(Point<T2> copy) template <class T2> inline Point(Point<T2> copy)