Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
PhosphorEasing.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 fuddlesworth
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#pragma once
5
7#include <PhosphorAnimation/phosphoranimation_export.h>
8
9#include <QtCore/QObject>
10#include <QtCore/QString>
11#include <QtCore/QtGlobal>
12#include <QtQml/qqmlregistration.h>
13
14#include <cmath>
15
16namespace PhosphorAnimation {
17
37class PHOSPHORANIMATION_EXPORT PhosphorEasing
38{
39 Q_GADGET
40 QML_VALUE_TYPE(phosphorEasing)
41 QML_STRUCTURED_VALUE
42
43 Q_PROPERTY(Type type READ type WRITE setType)
44 Q_PROPERTY(qreal x1 READ x1 WRITE setX1)
45 Q_PROPERTY(qreal y1 READ y1 WRITE setY1)
46 Q_PROPERTY(qreal x2 READ x2 WRITE setX2)
47 Q_PROPERTY(qreal y2 READ y2 WRITE setY2)
48 Q_PROPERTY(qreal amplitude READ amplitude WRITE setAmplitude)
49 Q_PROPERTY(qreal period READ period WRITE setPeriod)
50 Q_PROPERTY(int bounces READ bounces WRITE setBounces)
51
52public:
53 // Parallel to `PhosphorAnimation::Easing::Type` so QML enum references
54 // work without the caller having to know about the nested C++ enum.
55 // Integer values kept identical for `static_cast` round-trip.
56 enum class Type : int {
57 CubicBezier = int(Easing::Type::CubicBezier),
58 ElasticIn = int(Easing::Type::ElasticIn),
59 ElasticOut = int(Easing::Type::ElasticOut),
60 ElasticInOut = int(Easing::Type::ElasticInOut),
61 BounceIn = int(Easing::Type::BounceIn),
62 BounceOut = int(Easing::Type::BounceOut),
63 BounceInOut = int(Easing::Type::BounceInOut),
64 };
65 Q_ENUM(Type)
66
67 PhosphorEasing() = default;
70 explicit PhosphorEasing(const Easing& value)
71 : m_value(value)
72 {
73 }
74
80 const Easing& value() const
81 {
82 return m_value;
83 }
84
85 // ─── Property delegates ───
86 //
87 // Setters mirror the bounds enforced by `Easing::fromString`'s
88 // qBound clamps: x ∈ [0, 1], y ∈ [-1, 2], period ∈ [0.1, 1],
89 // bounces ∈ [1, 8]. Amplitude routes through `Easing::clampAmplitude`,
90 // whose range depends on BOTH the type and the period (elastic's
91 // amplitude is its peak, floored by what the period can reach;
92 // bounce's is a height scale over [0.5, 3]) — so `setType` and
93 // `setPeriod` re-clamp it, and property order does not matter.
94 // NaN/inf are silently dropped (the previous value is preserved).
95 // Direct field writes would otherwise let a settings UI sneak
96 // pathological values past the parse-path clamp.
97
98 Type type() const
99 {
100 return static_cast<Type>(static_cast<int>(m_value.type));
101 }
102 void setType(Type t)
103 {
104 m_value.type = static_cast<Easing::Type>(static_cast<int>(t));
105 // Amplitude's admitted range depends on the type (elastic and bounce
106 // share the field, not its bounds), and a QML declaration may well set
107 // `amplitude` before `type`. Re-clamp so the pair is coherent whichever
108 // order the two properties are written in.
109 m_value.amplitude = Easing::clampAmplitude(m_value.type, m_value.amplitude, m_value.period);
110 }
111
112 qreal x1() const
113 {
114 return m_value.x1;
115 }
116 void setX1(qreal v)
117 {
118 if (!std::isfinite(v)) {
119 return;
120 }
121 m_value.x1 = qBound(0.0, v, 1.0);
122 }
123 qreal y1() const
124 {
125 return m_value.y1;
126 }
127 void setY1(qreal v)
128 {
129 if (!std::isfinite(v)) {
130 return;
131 }
132 m_value.y1 = qBound(-1.0, v, 2.0);
133 }
134 qreal x2() const
135 {
136 return m_value.x2;
137 }
138 void setX2(qreal v)
139 {
140 if (!std::isfinite(v)) {
141 return;
142 }
143 m_value.x2 = qBound(0.0, v, 1.0);
144 }
145 qreal y2() const
146 {
147 return m_value.y2;
148 }
149 void setY2(qreal v)
150 {
151 if (!std::isfinite(v)) {
152 return;
153 }
154 m_value.y2 = qBound(-1.0, v, 2.0);
155 }
156
157 qreal amplitude() const
158 {
159 return m_value.amplitude;
160 }
161 void setAmplitude(qreal v)
162 {
163 if (!std::isfinite(v)) {
164 return;
165 }
166 m_value.amplitude = Easing::clampAmplitude(m_value.type, v, m_value.period);
167 }
168 qreal period() const
169 {
170 return m_value.period;
171 }
172 void setPeriod(qreal v)
173 {
174 if (!std::isfinite(v)) {
175 return;
176 }
177 m_value.period = qBound(Easing::MinElasticPeriod, v, Easing::MaxElasticPeriod);
178 // Elastic's amplitude is its peak, and the gentlest peak it can reach moves
179 // with the period. Dropping the period can therefore strand the amplitude
180 // below what the curve can now produce, so re-clamp against the new floor.
181 m_value.amplitude = Easing::clampAmplitude(m_value.type, m_value.amplitude, m_value.period);
182 }
183 int bounces() const
184 {
185 return m_value.bounces;
186 }
187 void setBounces(int v)
188 {
189 m_value.bounces = qBound(1, v, 8);
190 }
191
192 // ─── Serialization ───
193
195 Q_INVOKABLE QString toString() const
196 {
197 return m_value.toString();
198 }
199
203 Q_INVOKABLE static PhosphorEasing fromString(const QString& str)
204 {
205 return PhosphorEasing(Easing::fromString(str));
206 }
207
208 // ─── Equality ───
209
210 bool operator==(const PhosphorEasing& other) const
211 {
212 return m_value == other.m_value;
213 }
214 bool operator!=(const PhosphorEasing& other) const
215 {
216 return !(*this == other);
217 }
218
219private:
220 Easing m_value;
221};
222
223} // namespace PhosphorAnimation
224
225Q_DECLARE_METATYPE(PhosphorAnimation::PhosphorEasing)
Parametric easing curve: cubic bezier, elastic, or bounce.
Definition Easing.h:18
Type
Definition Easing.h:20
QML value-type wrapper around PhosphorAnimation::Easing.
Definition PhosphorEasing.h:38
QString toString() const
Canonical wire format from PhosphorAnimation::Easing::toString.
Definition PhosphorEasing.h:195
Type
Definition PhosphorEasing.h:56
void setX1(qreal v)
Definition PhosphorEasing.h:116
void setType(Type t)
Definition PhosphorEasing.h:102
qreal amplitude() const
Definition PhosphorEasing.h:157
bool operator==(const PhosphorEasing &other) const
Definition PhosphorEasing.h:210
int bounces() const
Definition PhosphorEasing.h:183
bool operator!=(const PhosphorEasing &other) const
Definition PhosphorEasing.h:214
void setBounces(int v)
Definition PhosphorEasing.h:187
qreal y2() const
Definition PhosphorEasing.h:145
qreal x1() const
Definition PhosphorEasing.h:112
qreal y1() const
Definition PhosphorEasing.h:123
static PhosphorEasing fromString(const QString &str)
Parse the same wire format.
Definition PhosphorEasing.h:203
const Easing & value() const
Read-only access to the underlying value.
Definition PhosphorEasing.h:80
qreal x2() const
Definition PhosphorEasing.h:134
void setY2(qreal v)
Definition PhosphorEasing.h:149
void setX2(qreal v)
Definition PhosphorEasing.h:138
void setY1(qreal v)
Definition PhosphorEasing.h:127
void setAmplitude(qreal v)
Definition PhosphorEasing.h:161
qreal period() const
Definition PhosphorEasing.h:168
void setPeriod(qreal v)
Definition PhosphorEasing.h:172
Type type() const
Definition PhosphorEasing.h:98
Definition AnimatedValue.h:32