feat: add proper anim tokens to Tokens

This commit is contained in:
2 * r + 2 * t 2026-04-11 21:33:18 +10:00
parent b5dcd07ab8
commit 180120801a
5 changed files with 177 additions and 19 deletions

View file

@ -6,6 +6,7 @@ qml_module(caelestia-config
configscope.cpp
appearanceconfig.cpp
tokens.cpp
anim.cpp
monitorconfigmanager.cpp
backgroundconfig.hpp
barconfig.hpp

View file

@ -0,0 +1,62 @@
#include "anim.hpp"
#include "appearanceconfig.hpp"
#include "tokens.hpp"
#include <qpoint.h>
namespace caelestia::config {
AnimTokens::AnimTokens(QObject* parent)
: QObject(parent) {}
QEasingCurve AnimTokens::buildCurve(const QList<qreal>& points) {
QEasingCurve curve(QEasingCurve::BezierSpline);
// Points come in pairs of (x, y) forming cubic bezier segments.
// Each segment needs 3 control points: c1, c2, endPoint.
// So 6 values per segment: c1x, c1y, c2x, c2y, endX, endY.
for (int i = 0; i + 5 < points.size(); i += 6) {
QPointF c1(points[i], points[i + 1]);
QPointF c2(points[i + 2], points[i + 3]);
QPointF end(points[i + 4], points[i + 5]);
curve.addCubicBezierSegment(c1, c2, end);
}
return curve;
}
void AnimTokens::rebuildCurves() {
if (!m_curves)
return;
m_emphasized = buildCurve(m_curves->emphasized());
m_emphasizedAccel = buildCurve(m_curves->emphasizedAccel());
m_emphasizedDecel = buildCurve(m_curves->emphasizedDecel());
m_standard = buildCurve(m_curves->standard());
m_standardAccel = buildCurve(m_curves->standardAccel());
m_standardDecel = buildCurve(m_curves->standardDecel());
m_expressiveFastSpatial = buildCurve(m_curves->expressiveFastSpatial());
m_expressiveDefaultSpatial = buildCurve(m_curves->expressiveDefaultSpatial());
m_expressiveSlowSpatial = buildCurve(m_curves->expressiveSlowSpatial());
emit curvesChanged();
}
void AnimTokens::bindCurves(AnimCurves* curves) {
m_curves = curves;
// Rebuild when any curve control points change
connect(curves, &AnimCurves::propertiesChanged, this, &AnimTokens::rebuildCurves);
rebuildCurves();
}
void AnimTokens::bindDurations(AnimDurations* durations) {
if (m_durations == durations)
return;
m_durations = durations;
emit durationsChanged();
}
} // namespace caelestia::config

View file

@ -0,0 +1,78 @@
#pragma once
#include <qeasingcurve.h>
#include <qobject.h>
#include <qqmlintegration.h>
namespace caelestia::config {
class AnimCurves;
class AnimDurations;
class ConfigScope;
class AnimTokens : public QObject {
Q_OBJECT
Q_MOC_INCLUDE("appearanceconfig.hpp")
QML_ANONYMOUS
Q_PROPERTY(QEasingCurve emphasized READ emphasized NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve emphasizedAccel READ emphasizedAccel NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve emphasizedDecel READ emphasizedDecel NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve standard READ standard NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve standardAccel READ standardAccel NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve standardDecel READ standardDecel NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve expressiveFastSpatial READ expressiveFastSpatial NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve expressiveDefaultSpatial READ expressiveDefaultSpatial NOTIFY curvesChanged)
Q_PROPERTY(QEasingCurve expressiveSlowSpatial READ expressiveSlowSpatial NOTIFY curvesChanged)
Q_PROPERTY(caelestia::config::AnimDurations* durations READ durations NOTIFY durationsChanged)
public:
explicit AnimTokens(QObject* parent = nullptr);
void bindCurves(AnimCurves* curves);
void bindDurations(AnimDurations* durations);
[[nodiscard]] QEasingCurve emphasized() const { return m_emphasized; }
[[nodiscard]] QEasingCurve emphasizedAccel() const { return m_emphasizedAccel; }
[[nodiscard]] QEasingCurve emphasizedDecel() const { return m_emphasizedDecel; }
[[nodiscard]] QEasingCurve standard() const { return m_standard; }
[[nodiscard]] QEasingCurve standardAccel() const { return m_standardAccel; }
[[nodiscard]] QEasingCurve standardDecel() const { return m_standardDecel; }
[[nodiscard]] QEasingCurve expressiveFastSpatial() const { return m_expressiveFastSpatial; }
[[nodiscard]] QEasingCurve expressiveDefaultSpatial() const { return m_expressiveDefaultSpatial; }
[[nodiscard]] QEasingCurve expressiveSlowSpatial() const { return m_expressiveSlowSpatial; }
[[nodiscard]] AnimDurations* durations() const { return m_durations; }
signals:
void curvesChanged();
void durationsChanged();
private:
void rebuildCurves();
static QEasingCurve buildCurve(const QList<qreal>& points);
AnimCurves* m_curves = nullptr;
AnimDurations* m_durations = nullptr;
QEasingCurve m_emphasized;
QEasingCurve m_emphasizedAccel;
QEasingCurve m_emphasizedDecel;
QEasingCurve m_standard;
QEasingCurve m_standardAccel;
QEasingCurve m_standardDecel;
QEasingCurve m_expressiveFastSpatial;
QEasingCurve m_expressiveDefaultSpatial;
QEasingCurve m_expressiveSlowSpatial;
};
} // namespace caelestia::config

View file

@ -62,18 +62,6 @@ TokenConfig* TokenConfig::create(QQmlEngine* engine, QJSEngine*) {
// Tokens (attached type)
Tokens::Tokens(ConfigScope* scope, QObject* parent)
: QObject(parent)
, m_scope(scope) {
connectScope();
}
void Tokens::connectScope() {
if (!m_scope)
return;
connect(m_scope, &ConfigScope::configChanged, this, &Tokens::sourceChanged);
}
// Resolve appearance from per-monitor GlobalConfig overlay or global GlobalConfig
static const AppearanceConfig* resolveAppearance(ConfigScope* scope) {
if (scope && scope->config())
@ -82,6 +70,35 @@ static const AppearanceConfig* resolveAppearance(ConfigScope* scope) {
return global ? global->appearance() : nullptr;
}
Tokens::Tokens(ConfigScope* scope, QObject* parent)
: QObject(parent)
, m_scope(scope)
, m_anim(new AnimTokens(this)) {
connectScope();
bindAnim();
}
void Tokens::connectScope() {
if (!m_scope)
return;
connect(m_scope, &ConfigScope::configChanged, this, &Tokens::sourceChanged);
connect(m_scope, &ConfigScope::configChanged, this, &Tokens::bindAnim);
}
void Tokens::bindAnim() {
auto* appearance = resolveAppearance(m_scope);
if (!appearance)
return;
// Bind durations from resolved GlobalConfig appearance
m_anim->bindDurations(appearance->anim()->durations());
// Bind curves from TokenConfig
auto* tokens = TokenConfig::instance();
if (tokens)
m_anim->bindCurves(tokens->appearance()->curves());
}
const AppearanceRounding* Tokens::rounding() const {
auto* a = resolveAppearance(m_scope);
return a ? a->rounding() : nullptr;
@ -102,11 +119,6 @@ const AppearanceFont* Tokens::font() const {
return a ? a->font() : nullptr;
}
const AppearanceAnim* Tokens::anim() const {
auto* a = resolveAppearance(m_scope);
return a ? a->anim() : nullptr;
}
const AppearanceTransparency* Tokens::transparency() const {
auto* a = resolveAppearance(m_scope);
return a ? a->transparency() : nullptr;

View file

@ -1,5 +1,6 @@
#pragma once
#include "anim.hpp"
#include "appearanceconfig.hpp"
#include "configobject.hpp"
@ -356,9 +357,9 @@ class Tokens : public QObject {
Q_PROPERTY(const caelestia::config::AppearanceSpacing* spacing READ spacing NOTIFY sourceChanged)
Q_PROPERTY(const caelestia::config::AppearancePadding* padding READ padding NOTIFY sourceChanged)
Q_PROPERTY(const caelestia::config::AppearanceFont* font READ font NOTIFY sourceChanged)
Q_PROPERTY(const caelestia::config::AppearanceAnim* anim READ anim NOTIFY sourceChanged)
Q_PROPERTY(const caelestia::config::AppearanceTransparency* transparency READ transparency NOTIFY sourceChanged)
Q_PROPERTY(const caelestia::config::SizeTokens* sizes READ sizes NOTIFY sourceChanged)
Q_PROPERTY(const caelestia::config::AnimTokens* anim READ anim NOTIFY sourceChanged)
public:
explicit Tokens(ConfigScope* scope, QObject* parent = nullptr);
@ -367,10 +368,12 @@ public:
[[nodiscard]] const AppearanceSpacing* spacing() const;
[[nodiscard]] const AppearancePadding* padding() const;
[[nodiscard]] const AppearanceFont* font() const;
[[nodiscard]] const AppearanceAnim* anim() const;
[[nodiscard]] const AppearanceTransparency* transparency() const;
[[nodiscard]] const SizeTokens* sizes() const;
[[nodiscard]] const AnimTokens* anim() const { return m_anim; }
static Tokens* qmlAttachedProperties(QObject* object);
signals:
@ -378,8 +381,10 @@ signals:
private:
void connectScope();
void bindAnim();
ConfigScope* m_scope;
AnimTokens* m_anim = nullptr;
};
} // namespace caelestia::config