diff --git a/CMakeLists.txt b/CMakeLists.txt index acd06ea..b69ae79 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,9 +148,6 @@ if (WIN32) "${MSYS2_UCRT64}/include/c++/13.2.0/x86_64-w64-mingw32" ) - file(WRITE ${CMAKE_CURRENT_LIST_DIR}/.clangd "CompileFlags:\n CompilationDatabase: bin\n Add: [\"--target=x86_64-w64-mingw32\"]\nDiagnostics:\n MissingIncludes: None") -else() - file(WRITE ${CMAKE_CURRENT_LIST_DIR}/.clangd "CompileFlags:\n CompilationDatabase: bin\nDiagnostics:\n MissingIncludes: None") endif() if(CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/extra/DefaultTheme.oss b/extra/DefaultTheme.oss index 81d0ba7..682e61d 100644 --- a/extra/DefaultTheme.oss +++ b/extra/DefaultTheme.oss @@ -332,4 +332,13 @@ const $accentColorDark = #6B0A1DFF showBorder = true borderColor = color_black showIcon = true + (icon) { + tint = color_crimson + } +} +(@tool_button button:hover) { + borderColor = color_white + (icon) { + tint = color_white + } } diff --git a/extra/icons.png b/extra/icons.png new file mode 100644 index 0000000..43768d4 Binary files /dev/null and b/extra/icons.png differ diff --git a/other/TODO.txt b/other/TODO.txt index 8591493..ae2bd69 100644 --- a/other/TODO.txt +++ b/other/TODO.txt @@ -37,6 +37,8 @@ Add icons to ListView FIX: Limit FPS even when continuous events happen Add gradient to listbox selection Add gradient to menubar background and selection +Add cursor stack +Add MacOS global menu integration @@ -61,7 +63,7 @@ Implement following widgets: ***ListBox ***Context Menu ***MenuBar - Toolbar + ***Toolbar StatusBar ComboBox TreeView diff --git a/src/ogfx/gui/widgets/Button.cpp b/src/ogfx/gui/widgets/Button.cpp index 6de202d..385c148 100644 --- a/src/ogfx/gui/widgets/Button.cpp +++ b/src/ogfx/gui/widgets/Button.cpp @@ -54,9 +54,9 @@ namespace ogfx { const Vec2 iconPos = contentTL + m_drawIconOffset; if (isAnimatedEnabled()) - gfx.drawAnimation(m_anim, iconPos, m_drawIconSize); + gfx.drawAnimation(m_anim, iconPos, m_drawIconSize, getIconTintColor()); else - gfx.drawImage(m_icon, iconPos, m_drawIconSize); + gfx.drawImage(m_icon, iconPos, m_drawIconSize, getIconTintColor()); } // --- Text --- @@ -110,6 +110,7 @@ namespace ogfx enableAutoSize(getThemeValue(theme, "autoSize", m_autoSize)); enableAnimated(getThemeValue(theme, "icon.animated", m_animated)); setAnimationData(getThemeValue(theme, "icon.animation", m_animData)); + setIconTintColor(getThemeValue(theme, "icon.tint", getIconTintColor())); String filePath = getThemeValue(theme, "icon.path", m_icon.getFilePath()); if (filePath != m_icon.getFilePath()) setIcon(filePath); diff --git a/src/ogfx/gui/widgets/Button.hpp b/src/ogfx/gui/widgets/Button.hpp index c2c414b..015738d 100644 --- a/src/ogfx/gui/widgets/Button.hpp +++ b/src/ogfx/gui/widgets/Button.hpp @@ -62,6 +62,7 @@ namespace ogfx OSTD_PARAM_GETSET(ostd::AnimationData, AnimationData, m_animData); OSTD_PARAM_GETSET(Vec2, IconSize, m_iconSize); OSTD_PARAM_GETSET(f32, IconSpacing, m_iconSpacing); + OSTD_PARAM_GETSET(Color, IconTintColor, m_iconTint); private: // Force a layout recompute on the next draw. @@ -85,6 +86,7 @@ namespace ogfx Animation m_anim; Vec2 m_iconSize { 0, 0 }; f32 m_iconSpacing { 10 }; + Color m_iconTint { Colors::White }; // Computed layout state (refreshed by recompute_layout). bool m_layoutDirty { true }; diff --git a/src/ogfx/render/BasicRenderer.cpp b/src/ogfx/render/BasicRenderer.cpp index bacb400..fcefac5 100644 --- a/src/ogfx/render/BasicRenderer.cpp +++ b/src/ogfx/render/BasicRenderer.cpp @@ -262,7 +262,7 @@ namespace ogfx // ===================================================== SPECIALIZED ===================================================== - void BasicRenderer2D::drawImage(const ogfx::Image& image, const Vec2& position, const Vec2& size, const Rectangle& srcRect) + void BasicRenderer2D::drawImage(const ogfx::Image& image, const Vec2& position, const Vec2& size, const Color& tint, const Rectangle& srcRect) { if (!m_initialized || !image.isLoaded()) return; @@ -319,16 +319,16 @@ namespace ogfx // 5. Push quad u32 inds[6] = QUAD_INDICES_ARR; - push_polygon(verts, uvs, 4, inds, 6, Colors::White, tex, false); + push_polygon(verts, uvs, 4, inds, 6, tint, tex, false); } - void BasicRenderer2D::drawAnimation(const Animation& anim, const Vec2& position, const Vec2& size) + void BasicRenderer2D::drawAnimation(const Animation& anim, const Vec2& position, const Vec2& size, const Color& tint) { if (!m_initialized) return; if (!anim.hasImage()) return; const Image& img = anim.getSpriteSheet(); if (!img.isLoaded() || !img.isValid()) return; - drawImage(img, position, size, anim.getFrameRect()); + drawImage(img, position, size, tint, anim.getFrameRect()); } void BasicRenderer2D::fillGradientRect(const Rectangle& rect, ColorGradient& gradient) diff --git a/src/ogfx/render/BasicRenderer.hpp b/src/ogfx/render/BasicRenderer.hpp index 9cdc177..78b6f91 100644 --- a/src/ogfx/render/BasicRenderer.hpp +++ b/src/ogfx/render/BasicRenderer.hpp @@ -81,8 +81,8 @@ namespace ogfx inline bool isInitialized(void) { return m_initialized; } inline FontGlyphAtlas& getFontGlyphAtlas(void) { return m_fontGlyphAtlas; } - void drawImage(const ogfx::Image& image, const Vec2& position, const Vec2& size = { 0, 0 }, const Rectangle& srcRect = { 0, 0, 0, 0 }); - void drawAnimation(const Animation& anim, const Vec2& position, const Vec2& size = { 0, 0 }); + void drawImage(const ogfx::Image& image, const Vec2& position, const Vec2& size = { 0, 0 }, const Color& tint = Colors::White, const Rectangle& srcRect = { 0, 0, 0, 0 }); + void drawAnimation(const Animation& anim, const Vec2& position, const Vec2& size = { 0, 0 }, const Color& tint = Colors::White); void fillGradientRect(const Rectangle& rect, ColorGradient& gradient); void drawString(const String& str, const Vec2& position, const Color& color, i32 fontSize = 0, f32 scale = 1.0f); void drawCenteredString(const String& str, const Vec2& center, const Color& color, i32 fontSize = 0, f32 scale = 1.0f); diff --git a/src/ogfx/utils/Animation.cpp b/src/ogfx/utils/Animation.cpp index 8b35022..40701be 100644 --- a/src/ogfx/utils/Animation.cpp +++ b/src/ogfx/utils/Animation.cpp @@ -30,6 +30,7 @@ namespace ogfx m_timer.create(m_animData.fps, [&](f64 dt) -> void { update_animation(); }); + update_animation(); return *this; } @@ -76,10 +77,15 @@ namespace ogfx else m_currentFrame = 0; } - i32 x = m_animData.pixelOffsetX + (((m_currentFrame % m_animData.columns) + m_animData.columnOffset) * m_animData.frameWidth); - i32 y = m_animData.pixelOffsetY + (m_animData.rowOffset * m_animData.frameHeight); - if (m_animData.rows > 1) - y = m_animData.pixelOffsetY + ((cast(m_currentFrame / m_animData.columns) + m_animData.rowOffset) * m_animData.frameHeight); + i32 col = m_currentFrame % m_animData.columns; + i32 row = (m_animData.rows > 1) ? cast(m_currentFrame / m_animData.columns) : 0; + + i32 x = m_animData.pixelOffsetX + + ((col + m_animData.columnOffset) * (m_animData.frameWidth + m_animData.spacingX)); + + i32 y = m_animData.pixelOffsetY + + ((row + m_animData.rowOffset) * (m_animData.frameHeight + m_animData.spacingY)); + m_frameRect = { cast(x), cast(y), m_animData.frameWidth, m_animData.frameHeight }; } } diff --git a/src/ogfx/utils/Animation.hpp b/src/ogfx/utils/Animation.hpp index c019dca..11f4f13 100644 --- a/src/ogfx/utils/Animation.hpp +++ b/src/ogfx/utils/Animation.hpp @@ -45,6 +45,8 @@ namespace ogfx inline void setRowOffset(i32 o) { m_animData.rowOffset = o; } inline void setPixelOffsetX(f32 o) { m_animData.pixelOffsetX = o; } inline void setPixelOffsetY(f32 o) { m_animData.pixelOffsetY = o; } + inline void setSpacingX(f32 s) { m_animData.spacingX = s; } + inline void setSpacingY(f32 s) { m_animData.spacingY = s; } inline void setNRows(i32 n) { m_animData.rows = n; } inline void setNColumns(i32 n) { m_animData.columns = n; } inline void setFrameWidth(i32 f) { m_animData.frameWidth = f; } @@ -60,6 +62,8 @@ namespace ogfx inline i32 getRowOffset(void) { return m_animData.rowOffset; } inline f32 getPixelOffsetX(void) { return m_animData.pixelOffsetX; } inline f32 getPixelOffsetY(void) { return m_animData.pixelOffsetY; } + inline f32 getSpacingX(void) { return m_animData.spacingX; } + inline f32 getSpacingY(void) { return m_animData.spacingY; } inline i32 getNRows(void) { return m_animData.rows; } inline i32 getNColumns(void) { return m_animData.columns; } inline i32 getFrameWidth(void) { return m_animData.frameWidth; } diff --git a/src/ostd/data/AnimationData.hpp b/src/ostd/data/AnimationData.hpp index a075d92..bdbbdae 100644 --- a/src/ostd/data/AnimationData.hpp +++ b/src/ostd/data/AnimationData.hpp @@ -34,6 +34,8 @@ namespace ostd i32 columnOffset { 0 }; f32 pixelOffsetX { 0.0f }; f32 pixelOffsetY { 0.0f }; + f32 spacingX { 0.0f };; + f32 spacingY { 0.0f };; i32 rows { 1 }; i32 columns { 1 }; f32 frameWidth{ 32 }; @@ -53,6 +55,8 @@ namespace ostd str.add(" ").add("columnOffset: ").add(columnOffset).add(",\n"); str.add(" ").add("pixelOffsetX: ").add(pixelOffsetX, 2).add(",\n"); str.add(" ").add("pixelOffsetY: ").add(pixelOffsetY, 2).add(",\n"); + str.add(" ").add("spacingX: ").add(spacingX, 2).add(",\n"); + str.add(" ").add("CpacingY: ").add(spacingY, 2).add(",\n"); str.add(" ").add("rows: ").add(rows).add(",\n"); str.add(" ").add("columns: ").add(columns).add(",\n"); str.add(" ").add("frameWidth: ").add(frameWidth, 2).add(",\n"); diff --git a/src/ostd/io/Stylesheet.cpp b/src/ostd/io/Stylesheet.cpp index 8b43b9d..42fab78 100644 --- a/src/ostd/io/Stylesheet.cpp +++ b/src/ostd/io/Stylesheet.cpp @@ -593,6 +593,18 @@ namespace ostd return l_error(true); ad.pixelOffsetY = val.toFloat(); } + else if (prop == "spacingx") + { + if (!val.isNumeric(true)) + return l_error(true); + ad.spacingX = val.toFloat(); + } + else if (prop == "spacingy") + { + if (!val.isNumeric(true)) + return l_error(true); + ad.spacingY = val.toFloat(); + } else if (prop == "rows") { if (!val.isInt()) diff --git a/src/test/GuiTest.cpp b/src/test/GuiTest.cpp index 20b72d2..08ad85a 100644 --- a/src/test/GuiTest.cpp +++ b/src/test/GuiTest.cpp @@ -52,6 +52,17 @@ class Window : public ogfx::gui::Window getToolBar().setHeight(30); + ogfx::AnimationData iconsAD; + iconsAD.frameCount = 1; + iconsAD.fps = 1; + iconsAD.columns = 8; + iconsAD.rows = 5; + iconsAD.frameWidth = 64; + iconsAD.frameHeight = 64; + iconsAD.spacingX = 50; + iconsAD.spacingY = 48; + iconsAD.still = true; + 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()); @@ -136,9 +147,15 @@ class Window : public ogfx::gui::Window for (i32 i = 0; i < 20; i++) { - auto& btn = getToolBar().addButton("./img.png"); - btn.setAnimationData(ad); + iconsAD.columnOffset = ostd::Random::getui32(0, 7); + iconsAD.rowOffset = ostd::Random::getui32(0, 4); + + if (iconsAD.rowOffset == 3) + iconsAD.columnOffset = ostd::Random::getui32(0, 4); + + auto& btn = getToolBar().addButton("./icons.png"); btn.enableAnimated(); + btn.setAnimationData(iconsAD); } m_tabs.setSize(900, 700);