package flare.animate { import flash.display.Shape; import flash.events.Event; import flash.events.TimerEvent; import flash.utils.Timer; /** * Scheduler that oversees animation and time-based processing. Uses an * internal timer to regularly invoke the current set of scheduled * objects. Typically, interaction with the scheduler is automatically * handled by Transition classes. However, custom implmentations of * the ISchedulable interface will need to be scheduled. Use the * Scheduler.instance property, and not the constructor, to get * a reference to the active scheduler. * *

By default, the Scheduler issues updates to all scheduled items each * time the Flash Player advances to the next frame, as reported by the * Event.ENTER_FRAME event. To instead set the update interval * manually, see the timerInterval property.

*/ public class Scheduler { private static const _instance:Scheduler = new Scheduler(_Lock); /** The default Scheduler instance. */ public static function get instance():Scheduler { return _instance; } private var _scheduled:Vector. = new Vector.(0); // list of all currently scheduled items private var _ids:Object; // map of all named items private var _timer:Timer; // timer for interval-based scheduling private var _obj:Shape; // shape for getting ENTER_FRAME events /** * Sets the timer interval (in milliseconds) at which the scheduler * should process events. If this value is greater than zero, a * Timer instance will be used to trigger scheduler * updates at the given interval. If this value is less than or equal * to zero (the default), scheduler updates will be issued with each * time the Flash Player advances to the next frame according to the * Event.ENTER_FRAME event. */ public function get timerInterval():Number { return _timer.delay; } public function set timerInterval(t:Number):void { pause(); _timer.delay = (t>0 ? t : 0); play(); } /** * Creates a new Scheduler--this constructor should be not used; * instead use the instance property. * @param lock a lock object to emulate a private constructor */ public function Scheduler(lock:Class) { if (lock == _Lock) { _scheduled.length = 0; _ids = {}; _obj = new Shape(); _timer = new Timer(0); _timer.addEventListener(TimerEvent.TIMER, tick); } else { throw new Error("Invalid constructor. Use Scheduler.instance."); } } /** * Plays the scheduler, allowing it to process events. */ private function play():void { if (timerInterval <= 0) { if (!_obj.hasEventListener(Event.ENTER_FRAME)) _obj.addEventListener(Event.ENTER_FRAME, tick); } else if (!_timer.running) { _timer.start(); } } /** * Pauses the scheduler, so that events are not processed. */ private function pause():void { if (timerInterval <= 0) { _obj.removeEventListener(Event.ENTER_FRAME, tick); } else { _timer.stop(); } } /** * Adds an object to the scheduling list. * @param item a schedulable object to add */ public function add(item:ISchedulable) : void { if (item.id && _ids[item.id] != item) { cancel(item.id); _ids[item.id] = item; } _scheduled.push(item); play(); } /** * Removes an object from the scheduling list. * @param item the object to remove * @return true if the object was found and removed, false otherwise */ public function remove(item:ISchedulable) : Boolean { var idx:int = _scheduled.indexOf(item); if (idx >= 0) { _scheduled.splice(idx,1); if (item.id && _ids[item.id] == item) { if (_scheduled.indexOf(item) < 0) delete _ids[item.id]; } } return (idx >= 0); } /** * Indicates if an object with the given id is currently in the * scheduler queue. * @param id the id to check for * @return true if an object with that id is currently scheduled, * false otherwise */ public function isScheduled(id:String) : Boolean { return _ids[id] != undefined; } /** * Looks up the scheduled object indicated by the given id, if any. * @param id the id to lookup * @return the scheduled object with matching id, of null if none */ public function lookup(id:String) : ISchedulable { return id==null ? null : _ids[id]; } /** * Cancels any scheduled object with a matching id. * @param id the id to cancel * @return true if an object was found and cancelled, false otherwise */ public function cancel(id:String) : Boolean { var s:ISchedulable = _ids[id]; if (s != null) { remove(s); s.cancelled(); return true; } else { return false; } } /** * Frame/timer callback that invokes each scheduled object. * @param event the event that triggered the callback */ public function tick(event:Event) : void { // all events will see the same timestamp var time:Number = new Date().time; for each (var s:ISchedulable in _scheduled) { if (s.evaluate(time)) remove(s); } if (_scheduled.length == 0) { pause(); } } } // end of class Scheduler } // scheduler lock class to enforce singleton pattern class _Lock { }