Hyprland/src/helpers/AnimatedVariable.hpp

310 lines
9.3 KiB
C++
Raw Normal View History

2022-04-23 14:16:02 +02:00
#pragma once
2023-08-07 13:35:19 +02:00
#include <functional>
2022-04-23 14:16:02 +02:00
#include <any>
2023-08-07 13:35:19 +02:00
#include <chrono>
#include <type_traits>
2023-08-07 13:35:19 +02:00
#include "Vector2D.hpp"
#include "Color.hpp"
#include "../macros.hpp"
#include "../debug/Log.hpp"
#include "../desktop/DesktopTypes.hpp"
2022-04-23 14:16:02 +02:00
enum ANIMATEDVARTYPE {
2022-04-23 14:16:02 +02:00
AVARTYPE_INVALID = -1,
AVARTYPE_FLOAT,
AVARTYPE_VECTOR,
AVARTYPE_COLOR
};
// Utility to bind a type with its corresponding ANIMATEDVARTYPE
template <class T>
struct typeToANIMATEDVARTYPE_t {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_INVALID;
};
template <>
struct typeToANIMATEDVARTYPE_t<float> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_FLOAT;
};
template <>
struct typeToANIMATEDVARTYPE_t<Vector2D> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_VECTOR;
};
template <>
struct typeToANIMATEDVARTYPE_t<CColor> {
static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR;
};
template <class T>
inline constexpr ANIMATEDVARTYPE typeToANIMATEDVARTYPE = typeToANIMATEDVARTYPE_t<T>::value;
enum AVARDAMAGEPOLICY {
2023-01-20 20:48:07 +01:00
AVARDAMAGE_NONE = -1,
AVARDAMAGE_ENTIRE = 0,
AVARDAMAGE_BORDER,
AVARDAMAGE_SHADOW
};
2022-04-23 14:16:02 +02:00
class CAnimationManager;
struct SLayerSurface;
2022-07-28 13:28:43 +02:00
struct SAnimationPropertyConfig;
2022-11-06 18:52:09 +01:00
class CHyprRenderer;
class CWindow;
class CWorkspace;
2022-04-23 14:16:02 +02:00
// Utility to define a concept as a list of possible type
template <class T, class... U>
concept OneOf = (... or std::same_as<T, U>);
2022-04-23 14:16:02 +02:00
// Concept to describe which type can be placed into CAnimatedVariable
// This is mainly to get better errors if we put a type that's not supported
// Otherwise template errors are ugly
template <class T>
concept Animable = OneOf<T, Vector2D, float, CColor>;
2022-04-23 14:16:02 +02:00
class CBaseAnimatedVariable {
public:
CBaseAnimatedVariable(ANIMATEDVARTYPE type);
void create(SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, SLayerSurface* pLayer, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy);
void create(SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy);
2022-04-23 14:16:02 +02:00
CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete;
CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete;
CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete;
2022-05-12 11:27:31 +02:00
virtual ~CBaseAnimatedVariable();
2022-11-06 18:52:09 +01:00
void unregister();
void registerVar();
2023-07-19 22:40:03 +02:00
virtual void warp(bool endCallback = true) = 0;
2022-04-23 14:16:02 +02:00
//
2022-07-28 13:28:43 +02:00
void setConfig(SAnimationPropertyConfig* pConfig) {
m_pConfig = pConfig;
}
SAnimationPropertyConfig* getConfig() {
return m_pConfig;
}
int getDurationLeftMs();
2022-11-06 18:52:09 +01:00
/* returns the spent (completion) % */
float getPercent();
2022-12-29 12:30:43 +01:00
/* returns the current curve value */
float getCurveValue();
// checks if an animation is in progress
inline bool isBeingAnimated() {
return m_bIsBeingAnimated;
}
/* sets a function to be ran when the animation finishes.
if an animation is not running, runs instantly.
2022-11-06 18:52:09 +01:00
if "remove" is set to true, will remove the callback when ran. */
void setCallbackOnEnd(std::function<void(void* thisptr)> func, bool remove = true) {
m_fEndCallback = func;
2022-11-06 18:52:09 +01:00
m_bRemoveEndAfterRan = remove;
if (!isBeingAnimated())
onAnimationEnd();
}
2022-11-06 18:52:09 +01:00
/* 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<void(void* thisptr)> func, bool remove = true) {
m_fBeginCallback = func;
2022-11-06 18:52:09 +01:00
m_bRemoveBeginAfterRan = remove;
}
2023-05-15 18:11:51 +02:00
/* 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<void(void* thisptr)> func) {
m_fUpdateCallback = func;
}
2022-11-18 14:53:54 +01:00
/* resets all callbacks. Does not call any. */
void resetAllCallbacks() {
m_fBeginCallback = nullptr;
m_fEndCallback = nullptr;
2023-05-15 18:11:51 +02:00
m_fUpdateCallback = nullptr;
2022-11-18 14:53:54 +01:00
m_bRemoveBeginAfterRan = false;
m_bRemoveEndAfterRan = false;
2022-11-18 14:53:54 +01:00
}
CWindow* getWindow() {
return (CWindow*)m_pWindow;
}
protected:
void* m_pWindow = nullptr;
std::weak_ptr<CWorkspace> m_pWorkspace;
void* m_pLayer = nullptr;
SAnimationPropertyConfig* m_pConfig = nullptr;
2022-04-23 14:16:02 +02:00
2023-07-19 22:40:03 +02:00
bool m_bDummy = true;
bool m_bIsRegistered = false;
bool m_bIsBeingAnimated = false;
2022-04-23 14:16:02 +02:00
2022-04-23 21:47:16 +02:00
std::chrono::system_clock::time_point animationBegin;
2023-01-20 20:48:07 +01:00
AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE;
ANIMATEDVARTYPE m_Type;
2022-04-23 14:16:02 +02:00
bool m_bRemoveEndAfterRan = true;
bool m_bRemoveBeginAfterRan = true;
std::function<void(void* thisptr)> m_fEndCallback;
std::function<void(void* thisptr)> m_fBeginCallback;
2023-05-15 18:11:51 +02:00
std::function<void(void* thisptr)> m_fUpdateCallback;
bool m_bIsConnectedToActive = false;
void connectToActive();
void disconnectFromActive();
// methods
void onAnimationEnd() {
2023-07-19 22:40:03 +02:00
m_bIsBeingAnimated = false;
disconnectFromActive();
2023-07-19 22:40:03 +02:00
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
2022-11-06 18:52:09 +01:00
}
}
void onAnimationBegin() {
2023-07-19 22:40:03 +02:00
m_bIsBeingAnimated = true;
connectToActive();
2023-07-19 22:40:03 +02:00
2022-11-06 18:52:09 +01:00
if (m_fBeginCallback) {
m_fBeginCallback(this);
if (m_bRemoveBeginAfterRan)
m_fBeginCallback = nullptr; // reset
}
}
2022-04-23 14:16:02 +02:00
friend class CAnimationManager;
2022-05-12 11:27:31 +02:00
friend class CWorkspace;
friend struct SLayerSurface;
2022-11-06 18:52:09 +01:00
friend class CHyprRenderer;
2022-09-25 20:07:48 +02:00
};
template <Animable VarType>
class CAnimatedVariable : public CBaseAnimatedVariable {
public:
CAnimatedVariable() : CBaseAnimatedVariable(typeToANIMATEDVARTYPE<VarType>) {} // dummy var
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, CWindow* pWindow, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWindow, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, SLayerSurface* pLayer, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pLayer, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, pWorkspace, policy);
m_Value = value;
m_Goal = value;
}
void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, AVARDAMAGEPOLICY policy) {
create(pAnimConfig, policy);
m_Value = value;
m_Goal = value;
}
using CBaseAnimatedVariable::create;
CAnimatedVariable(const CAnimatedVariable&) = delete;
CAnimatedVariable(CAnimatedVariable&&) = delete;
CAnimatedVariable& operator=(const CAnimatedVariable&) = delete;
CAnimatedVariable& operator=(CAnimatedVariable&&) = delete;
~CAnimatedVariable() = default;
// gets the current vector value (real time)
const VarType& value() const {
return m_Value;
}
// gets the goal vector value
const VarType& goal() const {
return m_Goal;
}
CAnimatedVariable& operator=(const VarType& v) {
if (v == m_Goal)
return *this;
m_Goal = v;
animationBegin = std::chrono::system_clock::now();
m_Begun = m_Value;
onAnimationBegin();
return *this;
}
// Sets the actual stored value, without affecting the goal, but resets the timer
void setValue(const VarType& v) {
if (v == m_Value)
return;
m_Value = v;
animationBegin = std::chrono::system_clock::now();
m_Begun = m_Value;
onAnimationBegin();
}
// Sets the actual value and goal
void setValueAndWarp(const VarType& v) {
2024-03-31 22:43:08 +02:00
m_Goal = v;
m_bIsBeingAnimated = true;
warp();
}
void warp(bool endCallback = true) override {
if (!m_bIsBeingAnimated)
return;
m_Value = m_Goal;
m_bIsBeingAnimated = false;
if (m_fUpdateCallback)
m_fUpdateCallback(this);
2024-03-31 22:43:08 +02:00
if (endCallback)
onAnimationEnd();
}
private:
VarType m_Value{};
VarType m_Goal{};
VarType m_Begun{};
// owners
friend class CAnimationManager;
friend class CWorkspace;
friend struct SLayerSurface;
friend class CHyprRenderer;
};