#pragma once #include #include #include #include "Vector2D.hpp" #include "Color.hpp" #include "../macros.hpp" #include "../debug/Log.hpp" enum ANIMATEDVARTYPE { AVARTYPE_INVALID = -1, AVARTYPE_FLOAT, AVARTYPE_VECTOR, AVARTYPE_COLOR }; enum AVARDAMAGEPOLICY { AVARDAMAGE_NONE = -1, AVARDAMAGE_ENTIRE = 0, AVARDAMAGE_BORDER, AVARDAMAGE_SHADOW }; class CAnimationManager; class CWorkspace; struct SLayerSurface; struct SAnimationPropertyConfig; class CHyprRenderer; class CAnimatedVariable { public: CAnimatedVariable(); // dummy var void create(ANIMATEDVARTYPE, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY); void create(ANIMATEDVARTYPE, std::any val, SAnimationPropertyConfig*, void* pWindow, AVARDAMAGEPOLICY); CAnimatedVariable(const CAnimatedVariable&) = delete; CAnimatedVariable(CAnimatedVariable&&) = delete; CAnimatedVariable& operator=(const CAnimatedVariable&) = delete; CAnimatedVariable& operator=(CAnimatedVariable&&) = delete; ~CAnimatedVariable(); void unregister(); void registerVar(); // gets the current vector value (real time) const Vector2D& vec() const { return m_vValue; } // gets the current float value (real time) const float& fl() const { return m_fValue; } // gets the current color value (real time) const CColor& col() const { return m_cValue; } // gets the goal vector value const Vector2D& goalv() const { return m_vGoal; } // gets the goal float value const float& goalf() const { return m_fGoal; } // gets the goal color value const CColor& goalc() const { return m_cGoal; } CAnimatedVariable& operator=(const Vector2D& v) { if (v == m_vGoal) return *this; m_vGoal = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; onAnimationBegin(); return *this; } CAnimatedVariable& operator=(const float& v) { if (v == m_fGoal) return *this; m_fGoal = v; animationBegin = std::chrono::system_clock::now(); m_fBegun = m_fValue; onAnimationBegin(); return *this; } CAnimatedVariable& operator=(const CColor& v) { if (v == m_cGoal) return *this; m_cGoal = v; animationBegin = std::chrono::system_clock::now(); m_cBegun = m_cValue; onAnimationBegin(); return *this; } // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const Vector2D& v) { if (v == m_vValue) return; m_vValue = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; onAnimationBegin(); } // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const float& v) { if (v == m_fValue) return; m_fValue = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; onAnimationBegin(); } // Sets the actual stored value, without affecting the goal, but resets the timer void setValue(const CColor& v) { if (v == m_cValue) return; m_cValue = v; animationBegin = std::chrono::system_clock::now(); m_vBegun = m_vValue; onAnimationBegin(); } // Sets the actual value and goal void setValueAndWarp(const Vector2D& v) { m_vGoal = v; warp(); } // Sets the actual value and goal void setValueAndWarp(const float& v) { m_fGoal = v; warp(); } // Sets the actual value and goal void setValueAndWarp(const CColor& v) { m_cGoal = v; warp(); } // checks if an animation is in progress inline bool isBeingAnimated() { return m_bIsBeingAnimated; } void warp(bool endCallback = true) { switch (m_eVarType) { case AVARTYPE_FLOAT: { m_fValue = m_fGoal; break; } case AVARTYPE_VECTOR: { m_vValue = m_vGoal; break; } case AVARTYPE_COLOR: { m_cValue = m_cGoal; break; } default: UNREACHABLE(); } m_bIsBeingAnimated = false; if (endCallback) onAnimationEnd(); } void setConfig(SAnimationPropertyConfig* pConfig) { m_pConfig = pConfig; } SAnimationPropertyConfig* getConfig() { return m_pConfig; } int getDurationLeftMs(); /* returns the spent (completion) % */ float getPercent(); /* returns the current curve value */ float getCurveValue(); /* sets a function to be ran when the animation finishes. if an animation is not running, runs instantly. if "remove" is set to true, will remove the callback when ran. */ void setCallbackOnEnd(std::function func, bool remove = true) { m_fEndCallback = func; m_bRemoveEndAfterRan = remove; if (!isBeingAnimated()) onAnimationEnd(); } /* sets a function to be ran when an animation is started. if "remove" is set to true, will remove the callback when ran. */ void setCallbackOnBegin(std::function func, bool remove = true) { m_fBeginCallback = func; m_bRemoveBeginAfterRan = remove; } /* Sets the update callback, called every time the value is animated and a step is done Warning: calling unregisterVar/registerVar in this handler will cause UB */ void setUpdateCallback(std::function func) { m_fUpdateCallback = func; } /* resets all callbacks. Does not call any. */ void resetAllCallbacks() { m_fBeginCallback = nullptr; m_fEndCallback = nullptr; m_fUpdateCallback = nullptr; m_bRemoveBeginAfterRan = false; m_bRemoveEndAfterRan = false; } private: Vector2D m_vValue = Vector2D(0, 0); float m_fValue = 0; CColor m_cValue; Vector2D m_vGoal = Vector2D(0, 0); float m_fGoal = 0; CColor m_cGoal; Vector2D m_vBegun = Vector2D(0, 0); float m_fBegun = 0; CColor m_cBegun; // owners void* m_pWindow = nullptr; void* m_pWorkspace = nullptr; void* m_pLayer = nullptr; SAnimationPropertyConfig* m_pConfig = nullptr; bool m_bDummy = true; bool m_bIsRegistered = false; bool m_bIsBeingAnimated = false; std::chrono::system_clock::time_point animationBegin; ANIMATEDVARTYPE m_eVarType = AVARTYPE_INVALID; AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE; bool m_bRemoveEndAfterRan = true; bool m_bRemoveBeginAfterRan = true; std::function m_fEndCallback; std::function m_fBeginCallback; std::function m_fUpdateCallback; bool m_bIsConnectedToActive = false; void connectToActive(); void disconnectFromActive(); // methods void onAnimationEnd() { m_bIsBeingAnimated = false; disconnectFromActive(); if (m_fEndCallback) { // loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false. auto removeEndCallback = m_bRemoveEndAfterRan; m_fEndCallback(this); if (removeEndCallback) m_fEndCallback = nullptr; // reset } } void onAnimationBegin() { m_bIsBeingAnimated = true; connectToActive(); if (m_fBeginCallback) { m_fBeginCallback(this); if (m_bRemoveBeginAfterRan) m_fBeginCallback = nullptr; // reset } } friend class CAnimationManager; friend class CWorkspace; friend struct SLayerSurface; friend class CHyprRenderer; };