package flare.animate { import flare.util.Maths; import flare.util.Vectors; /** * Transition that runs multiple transitions one after the other in * sequence. By default, the total duration of the sequence is the sum of * the durations and delays of the sub-transitions. If the duration * of the sequence is set explicitly, the duration and delay for * sub-transitions will be uniformly scaled to fit within in the new * time span. */ public class Sequence extends Transition { // -- Properties ------------------------------------------------------ /** Array of sequential transitions */ protected var _trans:Vector. = new Vector.(); /** @private */ protected var _fracs:Vector. = new Vector.(); /** @private */ protected var _autodur:Boolean = true; /** @private */ protected var _dirty:Boolean = false; /** @private */ protected var _idx:int = 0; /** * If true, the duration of this sequence is automatically determined * by the durations of each sub-transition. This is the default behavior. */ public function get autoDuration():Boolean { return _autodur; } public function set autoDuration(b:Boolean):void { _autodur = b; computeDuration(); } /** @inheritDoc */ public override function get duration():Number { if (_dirty) computeDuration(); return super.duration; } public override function set duration(dur:Number):void { _autodur = false; super.duration = dur; _dirty = true; } // -- Methods --------------------------------------------------------- /** * Creates a new Sequence transition. * @param transitions an ordered list of sub-transitions */ public function Sequence(...transitions) { easing = Easing.none; for each (var t:Transition in transitions) { _trans.push(t); } _dirty = true; } /** * Adds a new transition to the end of this sequence. * @param t the transition to add */ public function add(t:Transition):void { if (running) throw new Error("Transition is running!"); _trans.push(t); _dirty = true; } /** * Removes a sub-transition from this sequence. * @param t the transition to remove * @return true if the transition was found and removed, false * otherwise */ public function remove(t:Transition):Boolean { if (running) throw new Error("Transition is running!"); var rem:Boolean = Vectors.remove(_trans, t) >= 0; if (rem) _dirty = true; return rem; } /** * Computes the duration of this sequence transition. */ protected function computeDuration():void { var d:Number = 0; _fracs.length = 0; _fracs.push(0); // collect durations and compute sum for each (var t:Transition in _trans) _fracs.push(d += t.totalDuration); // normalize durations to create progress fractions for (var i:int=1; i<=_trans.length; ++i) _fracs[i] = (d==0 ? 0 : (_fracs[i] as Number) / d); // set duration and scale if (_autodur) super.duration = d; _dirty = false; } /** @inheritDoc */ public override function dispose():void { while (_trans.length > 0) { _trans.pop().dispose(); } } // -- Transition Handlers --------------------------------------------- /** @inheritDoc */ public override function play(reverse:Boolean=false):void { if (_dirty) computeDuration(); super.play(reverse); } /** * Sets up each sub-transition. */ protected override function setup():void { // initialize each transition in proper sequence for each (var t:Transition in _trans) { t.doSetup(); t.step(1.0); } } /** * Starts this sequence transition, starting the first sub-transition * to be played. */ protected override function start():void { if (_reverse) { // init for reverse playback for (_idx=0; _idx<_trans.length; ++_idx) _trans[_idx].step(1); _idx -= 1; } else { // init for forward playback for (_idx=_trans.length; --_idx>=0;) _trans[_idx].step(0); _idx += 1; } if (_trans.length > 0) _trans[_idx].doStart(_reverse); } /** * Steps this sequence transition, ensuring that any sub-transitions * between the previous and current progress fraction are properly * invoked. * @param ef the current progress fraction. */ internal override function step(ef:Number):void { // find the right sub-transition var t:Transition, f0:Number, f1:Number, i:int, inc:int; f0 = _fracs[_idx] as Number; f1 = _fracs[_idx+1] as Number; inc = (ef<=f0 ? -1 : 1); for (i = _idx; i>=0 && i<_trans.length; i+=inc) { // get transition and progress fractions t = _trans[i] as Transition; f0 = _fracs[i] as Number; f1 = _fracs[i+1] as Number; // hand-off to new transition if (i != _idx) t.doStart(_reverse); if ((inc<0 && ef >= f0) || (inc>0 && ef <= f1)) break; t.doStep(inc<0 ? 0 : 1); t.doEnd(); } _idx = i; // set the transition index if (_idx >= 0 && _idx < _trans.length) { // run transition with mapped fraction t.doStep(Maths.invLinearInterp(ef, f0, f1)); } } /** * Ends this sequence transition, ending the last transition to be * played in the sequence as necessary. */ protected override function end():void { if (_idx >= 0 && _idx < _trans.length) { _trans[_idx].doStep(_reverse ? 0 : 1); _trans[_idx].doEnd(); } } } // end of class Sequence }