Skip to content

Commit

Permalink
animation: add CAnimationConfigTree (#29)
Browse files Browse the repository at this point in the history
Co-authored-by: Maximilian Seidler <[email protected]>
  • Loading branch information
PaideiaDilemma and PaideiaDilemma authored Jan 2, 2025
1 parent c42ce87 commit 6a26d08
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 32 deletions.
17 changes: 1 addition & 16 deletions include/hyprutils/animation/AnimatedVariable.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "AnimationConfig.hpp"
#include "../memory/WeakPtr.hpp"
#include "hyprutils/memory/SharedPtr.hpp"

Expand All @@ -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:
Expand Down
56 changes: 56 additions & 0 deletions include/hyprutils/animation/AnimationConfig.hpp
Original file line number Diff line number Diff line change
@@ -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;
};
}
}
70 changes: 70 additions & 0 deletions src/animation/AnimationConfig.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
94 changes: 78 additions & 16 deletions tests/animation.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <hyprutils/animation/AnimationConfig.hpp>
#include <hyprutils/animation/AnimationManager.hpp>
#include <hyprutils/animation/AnimatedVariable.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
Expand Down Expand Up @@ -37,7 +38,7 @@ struct SomeTestType {
}
};

std::unordered_map<std::string, SP<SAnimationPropertyConfig>> animationConfig;
CAnimationConfigTree animationTree;

class CMyAnimationManager : public CAnimationManager {
public:
Expand Down Expand Up @@ -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);
}

Expand All @@ -109,23 +110,86 @@ 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;
PANIMVAR<int> m_iB;
PANIMVAR<SomeTestType> m_iC;
};

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) {
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 ret = 0;
int ret = config();

animationTree.createNode("global");
animationTree.createNode("internal");

animationTree.createNode("default", "global");
animationTree.setConfigForNode("global", 1, 4.0, "default", "asdf");

Subject s(0, 0);

EXPECT(s.m_iA->value(), 0);
Expand Down Expand Up @@ -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);

Expand All @@ -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
//
Expand Down

0 comments on commit 6a26d08

Please sign in to comment.