///|
/// Lifecycle state for a serial composition of scalar tweens.
pub(all) enum SequenceState {
Before
Active
Gap
After
} derive(Eq, Debug)
///|
/// A sample from a TweenSequence, including the active segment index.
pub(all) struct SequenceSample {
time : Double
value : Double
index : Int
progress : Double
state : SequenceState
} derive(Debug)
///|
pub fn SequenceSample::time(self : SequenceSample) -> Double {
self.time
}
///|
pub fn SequenceSample::value(self : SequenceSample) -> Double {
self.value
}
///|
pub fn SequenceSample::index(self : SequenceSample) -> Int {
self.index
}
///|
pub fn SequenceSample::progress(self : SequenceSample) -> Double {
self.progress
}
///|
pub fn SequenceSample::state(self : SequenceSample) -> SequenceState {
self.state
}
///|
/// A serial composition of Tweens with optional gaps between segments.
pub struct TweenSequence {
tweens : Array[Tween]
gap : Double
} derive(Debug)
///|
pub fn TweenSequence::new(
tweens : Array[Tween],
gap? : Double = 0.0,
) -> TweenSequence raise MotionError {
if tweens.length() == 0 {
raise MotionError::EmptyTrack
}
ensure_finite(gap)
if gap < 0.0 {
raise MotionError::InvalidDuration(gap)
}
{ tweens: tweens.copy(), gap }
}
///|
pub fn TweenSequence::tweens(self : TweenSequence) -> Array[Tween] {
self.tweens.copy()
}
///|
pub fn TweenSequence::length(self : TweenSequence) -> Int {
self.tweens.length()
}
///|
pub fn TweenSequence::gap(self : TweenSequence) -> Double {
self.gap
}
///|
pub fn TweenSequence::duration(self : TweenSequence) -> Double {
let mut total = 0.0
for index in 0.. Double {
let mut start = 0.0
for cursor in 0.. SequenceSample {
let first = self.tweens[0].sample(0.0)
{ time, value: first.value(), index: 0, progress: 0.0, state: Before }
}
///|
fn TweenSequence::sample_after(
self : TweenSequence,
time : Double,
) -> SequenceSample {
let last_index = self.tweens.length() - 1
let last = self.tweens[last_index]
let sample = last.sample(last.total_duration())
{
time,
value: sample.value(),
index: last_index,
progress: 1.0,
state: After,
}
}
///|
/// Sample the sequence in wall-clock time. A gap holds the previous value.
pub fn TweenSequence::sample(
self : TweenSequence,
time : Double,
) -> SequenceSample {
if time < 0.0 {
return self.sample_before(time)
}
if time >= self.duration() {
return self.sample_after(time)
}
for index in 0.. Double {
self.sample(time).value()
}
///|
pub fn TweenSequence::sample_many(
self : TweenSequence,
count : Int,
) -> Array[SequenceSample] raise MotionError {
if count < 2 {
raise MotionError::InvalidSampleCount(count)
}
let values : Array[SequenceSample] = []
let duration = self.duration()
for index in 0.. SequenceBuilder {
{ tweens: [], gap }
}
///|
pub fn SequenceBuilder::add(self : SequenceBuilder, tween : Tween) -> Unit {
self.tweens.push(tween)
}
///|
pub fn SequenceBuilder::remove_at(
self : SequenceBuilder,
index : Int,
) -> Tween? {
if index < 0 || index >= self.tweens.length() {
None
} else {
Some(self.tweens.remove(index))
}
}
///|
pub fn SequenceBuilder::build(
self : SequenceBuilder,
) -> TweenSequence raise MotionError {
TweenSequence::new(self.tweens, gap=self.gap)
}