animation: add CAnimationConfigTree (#29)

Co-authored-by: Maximilian Seidler <paideia_dilemma@losfuzzys.net>
This commit is contained in:
Maximilian Seidler 2025-01-02 14:02:21 +00:00 committed by GitHub
parent c42ce87eb3
commit 6a26d08bac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 205 additions and 32 deletions

View file

@ -1,5 +1,6 @@
#pragma once
#include "AnimationConfig.hpp"
#include "../memory/WeakPtr.hpp"
#include "hyprutils/memory/SharedPtr.hpp"
@ -10,22 +11,6 @@ namespace Hyprutils {
namespace Animation {
class CAnimationManager;
/*
Structure for animation properties.
Config properties need to have a static lifetime to allow for config reload.
*/
struct SAnimationPropertyConfig {
bool overridden = true;
std::string internalBezier = "";
std::string internalStyle = "";
float internalSpeed = 0.f;
int internalEnabled = -1;
Memory::CWeakPointer<SAnimationPropertyConfig> pValues;
Memory::CWeakPointer<SAnimationPropertyConfig> pParentAnimation;
};
/* A base class for animated variables. */
class CBaseAnimatedVariable {
public:

View file

@ -0,0 +1,56 @@
#pragma once
#include "../memory/WeakPtr.hpp"
#include "hyprutils/memory/WeakPtr.hpp"
#include <unordered_map>
namespace Hyprutils {
namespace Animation {
/*
Structure for animation properties.
Config properties need to have a static lifetime to allow for config reload.
*/
struct SAnimationPropertyConfig {
bool overridden = false;
std::string internalBezier = "";
std::string internalStyle = "";
float internalSpeed = 0.f;
int internalEnabled = -1;
Memory::CWeakPointer<SAnimationPropertyConfig> pValues;
Memory::CWeakPointer<SAnimationPropertyConfig> pParentAnimation;
};
/* A class to manage SAnimationPropertyConfig objects in a tree structure */
class CAnimationConfigTree {
public:
CAnimationConfigTree() = default;
~CAnimationConfigTree() = default;
/* Add a new animation node inheriting from a parent.
If parent is empty, a root node will be created that references it's own values.
Make sure the parent node has already been created through this interface. */
void createNode(const std::string& nodeName, const std::string& parent = "");
/* check if a node name has been created using createNode */
bool nodeExists(const std::string& nodeName) const;
/* Override the values of a node. The root node can also be overriden. */
void setConfigForNode(const std::string& nodeName, int enabled, float speed, const std::string& bezier, const std::string& style = "");
Memory::CSharedPointer<SAnimationPropertyConfig> getConfig(const std::string& name) const;
const std::unordered_map<std::string, Memory::CSharedPointer<SAnimationPropertyConfig>>& getFullConfig() const;
CAnimationConfigTree(const CAnimationConfigTree&) = delete;
CAnimationConfigTree(CAnimationConfigTree&&) = delete;
CAnimationConfigTree& operator=(const CAnimationConfigTree&) = delete;
CAnimationConfigTree& operator=(CAnimationConfigTree&&) = delete;
private:
void setAnimForChildren(Memory::CSharedPointer<SAnimationPropertyConfig> PANIM);
std::unordered_map<std::string, Memory::CSharedPointer<SAnimationPropertyConfig>> m_mAnimationConfig;
};
}
}

View file

@ -0,0 +1,70 @@
#include <hyprutils/animation/AnimationConfig.hpp>
using namespace Hyprutils::Animation;
using namespace Hyprutils::Memory;
#define SP CSharedPointer
#define WP CWeakPointer
void CAnimationConfigTree::createNode(const std::string& nodeName, const std::string& parent) {
auto pConfig = m_mAnimationConfig[nodeName];
if (!pConfig)
pConfig = makeShared<SAnimationPropertyConfig>();
WP<SAnimationPropertyConfig> parentRef;
if (!parent.empty() && m_mAnimationConfig.find(parent) != m_mAnimationConfig.end())
parentRef = m_mAnimationConfig[parent];
*pConfig = {
.overridden = false,
.internalBezier = "",
.internalStyle = "",
.internalSpeed = 0.f,
.internalEnabled = -1,
.pValues = (parentRef) ? parentRef->pValues : pConfig,
.pParentAnimation = (parentRef) ? parentRef : pConfig,
};
m_mAnimationConfig[nodeName] = pConfig;
}
bool CAnimationConfigTree::nodeExists(const std::string& nodeName) const {
return m_mAnimationConfig.find(nodeName) != m_mAnimationConfig.end();
}
void CAnimationConfigTree::setConfigForNode(const std::string& nodeName, int enabled, float speed, const std::string& bezier, const std::string& style) {
auto pConfig = m_mAnimationConfig[nodeName];
if (!pConfig)
return;
*pConfig = {
.overridden = true,
.internalBezier = bezier,
.internalStyle = style,
.internalSpeed = speed,
.internalEnabled = enabled,
.pValues = pConfig,
.pParentAnimation = pConfig->pParentAnimation, // keep the parent!
};
setAnimForChildren(pConfig);
}
SP<SAnimationPropertyConfig> CAnimationConfigTree::getConfig(const std::string& name) const {
return m_mAnimationConfig.at(name);
}
const std::unordered_map<std::string, SP<SAnimationPropertyConfig>>& CAnimationConfigTree::getFullConfig() const {
return m_mAnimationConfig;
}
void CAnimationConfigTree::setAnimForChildren(SP<SAnimationPropertyConfig> PANIM) {
for (auto& [name, anim] : m_mAnimationConfig) {
if (anim->pParentAnimation == PANIM && !anim->overridden) {
// if a child isnt overridden, set the values of the parent
anim->pValues = PANIM->pValues;
setAnimForChildren(anim);
}
}
}

View file

@ -1,3 +1,4 @@
#include <hyprutils/animation/AnimationConfig.hpp>
#include <hyprutils/animation/AnimationManager.hpp>
#include <hyprutils/animation/AnimatedVariable.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
@ -37,7 +38,7 @@ struct SomeTestType {
}
};
std::unordered_map<std::string, SP<SAnimationPropertyConfig>> animationConfig;
CAnimationConfigTree animationTree;
class CMyAnimationManager : public CAnimationManager {
public:
@ -90,7 +91,7 @@ class CMyAnimationManager : public CAnimationManager {
const auto PAV = makeShared<CGenericAnimatedVariable<VarType, EmtpyContext>>();
PAV->create(EAVTYPE, static_cast<CAnimationManager*>(this), PAV, v);
PAV->setConfig(animationConfig[animationConfigName]);
PAV->setConfig(animationTree.getConfig(animationConfigName));
av = std::move(PAV);
}
@ -109,7 +110,7 @@ class Subject {
public:
Subject(const int& a, const int& b) {
gAnimationManager.createAnimation(a, m_iA, "default");
gAnimationManager.createAnimation(b, m_iB, "default");
gAnimationManager.createAnimation(b, m_iB, "internal");
gAnimationManager.createAnimation({}, m_iC, "default");
}
PANIMVAR<int> m_iA;
@ -117,15 +118,78 @@ class Subject {
PANIMVAR<SomeTestType> m_iC;
};
int main(int argc, char** argv, char** envp) {
animationConfig["default"] = makeShared<SAnimationPropertyConfig>();
animationConfig["default"]->internalBezier = "default";
animationConfig["default"]->internalSpeed = 1.0;
animationConfig["default"]->internalStyle = "asdf";
animationConfig["default"]->internalEnabled = 1;
animationConfig["default"]->pValues = animationConfig["default"];
int config() {
int ret = 0;
animationTree.createNode("global");
animationTree.createNode("internal");
animationTree.createNode("foo", "internal");
animationTree.createNode("default", "global");
animationTree.createNode("bar", "default");
/*
internal
foo
global
default
bar
*/
auto barCfg = animationTree.getConfig("bar");
auto internalCfg = animationTree.getConfig("internal");
// internal is a root node and should point to itself
EXPECT(internalCfg->pParentAnimation.get(), internalCfg.get());
EXPECT(internalCfg->pValues.get(), internalCfg.get());
animationTree.setConfigForNode("global", 1, 4.0, "default", "asdf");
EXPECT(barCfg->internalEnabled, -1);
{
const auto PVALUES = barCfg->pValues.lock();
EXPECT(PVALUES->internalEnabled, 1);
EXPECT(PVALUES->internalBezier, "default");
EXPECT(PVALUES->internalStyle, "asdf");
EXPECT(PVALUES->internalSpeed, 4.0);
}
EXPECT(barCfg->pParentAnimation.get(), animationTree.getConfig("default").get());
// Overwrite our own values
animationTree.setConfigForNode("bar", 1, 4.2, "test", "qwer");
{
const auto PVALUES = barCfg->pValues.lock();
EXPECT(PVALUES->internalEnabled, 1);
EXPECT(PVALUES->internalBezier, "test");
EXPECT(PVALUES->internalStyle, "qwer");
EXPECT(PVALUES->internalSpeed, 4.2f);
}
// Now overwrite the parent
animationTree.setConfigForNode("default", 0, 0.0, "zxcv", "foo");
{
// Expecting no change
const auto PVALUES = barCfg->pValues.lock();
EXPECT(PVALUES->internalEnabled, 1);
EXPECT(PVALUES->internalBezier, "test");
EXPECT(PVALUES->internalStyle, "qwer");
EXPECT(PVALUES->internalSpeed, 4.2f);
}
return ret;
}
int main(int argc, char** argv, char** envp) {
int ret = config();
animationTree.createNode("global");
animationTree.createNode("internal");
animationTree.createNode("default", "global");
animationTree.setConfigForNode("global", 1, 4.0, "default", "asdf");
int ret = 0;
Subject s(0, 0);
EXPECT(s.m_iA->value(), 0);
@ -172,7 +236,7 @@ int main(int argc, char** argv, char** envp) {
EXPECT(s.m_iA->getStyle(), "asdf");
EXPECT(s.m_iA->enabled(), true);
animationConfig["default"]->internalEnabled = 0;
animationTree.getConfig("global")->internalEnabled = 0;
EXPECT(s.m_iA->enabled(), false);
@ -181,16 +245,14 @@ int main(int argc, char** argv, char** envp) {
EXPECT(s.m_iA->value(), 50);
// Test missing pValues
animationConfig["default"]->internalEnabled = 1;
animationConfig["default"]->pValues.reset();
animationTree.getConfig("global")->internalEnabled = 0;
animationTree.getConfig("default")->pValues.reset();
EXPECT(s.m_iA->enabled(), false);
EXPECT(s.m_iA->getBezierName(), "default");
EXPECT(s.m_iA->getStyle(), "");
EXPECT(s.m_iA->getPercent(), 1.f);
animationConfig["default"]->pValues = animationConfig["default"];
//
// Test callbacks
//