--<<<- -- Public Protocol -- cancelAction self action -- catchUp self -- catchUpAll self -- scheduleAction self action -- scheduleImmediately self action -- Suppress compiler warnings. global rateChanged -- Class TimeLine is a player which allows dynamic control of scheduling actions. -- It is intended to be a runtime-editable version of the ScriptX ActionListPlayer. class TimeLine (Player) instance variables -- PUBLIC actions -- list of scheduled actions. slaves -- players which are slaved to the time loop. -- PRIVATE queuedActions -- actions to schedule at the next loop. _duration loopCallback: undefined end -- Method durationGetter returns the _duration instance variable. method get duration self {class TimeLine} -> ( return self._duration ) -- Method durationSetter sets the _duration instance variable. method set duration self {class TimeLine} value -> ( self._duration := value scheduleLoop self value ) method init self {class TimeLine} #rest args -> ( apply nextMethod self args self.actions := new Array self.slaves := new Array self.queuedActions := new Array self._duration := self.scale * 10 addRateCallback self rateChanged self #() false ) -- Method play schedules the loop callback, and calls nextMethod. method play self {class TimeLine} -> ( scheduleLoop self nextMethod self ) -- Method goToBegin is overridden to schedule all queued actions. method goToBegin self {class TimeLine} -> ( catchUpAll self nextMethod self ) -- Method rateChanged is called when the rate of the time line -- is changed (handled by a rate callback on self). method rateChanged self {class TimeLine} -> ( catchUp self ) -- Method addSlave adds a slave player to the time line. method addSlave self {class TimeLine} plyr -> ( plyr.masterClock := self appendNew self.slaves plyr updateToolsNamed theNavigator @timeline ) -- Method removeSlave removes the specified slave player from the time line. method removeSlave self {class TimeLine} plyr -> ( plyr.masterClock := undefined deleteAll self.slaves plyr updateToolsNamed theNavigator @timeline ) -- Method scheduleLoop schedules the callback to loop the time line. method scheduleLoop self {class TimeLine} -> ( if (self.loopCallback <> undefined) do ( cancel self.loopCallback ) self.loopCallback := addTimeCallback self (self -> goToBegin self) \ self #() self._duration false ) -- Method catchUp schedules queued actions which have a time later -- than the current time. This prevents actions from triggering -- automatically if they are scheduled BEFORE the current time. method catchUp self {class TimeLine} -> ( -- Schedule all actions threadCriticalUp() local deletionList := new Array forEach self.queuedActions (act ignore -> ( if (act.time > self.time) do ( append deletionList act scheduleImmediately self act ) )) undefined -- Delete the scheduled ones from the queue. for act in deletionList do ( deleteOne self.queuedActions act ) threadCriticalDown() ) -- Method catchUpAll schedules all of the queued actions immediately. method catchUpAll self {class TimeLine} -> ( -- Loop through the queued actions and schedule them. threadCriticalUp() forEach self.queuedActions (act ignore -> ( scheduleImmediately self act )) undefined emptyOut self.queuedActions threadCriticalDown() ) -- Method scheduleImmediately schedules the specified action by creating -- a time callback. The time callback invokes the trigger method on -- the action, using the same protocol as the core ScriptX Action -- classes. method scheduleImmediately self {class TimeLine} act -> ( -- Add a time callback to trigger the action. Use the built -- in trigger method (Action protocol). local perp := act.perpetrator local cb := addTimeCallback self trigger act \ #(perp, self) act.time false -- If this is a new action, add it to the list of actions. if (not isMember self.actions act) then ( append self.actions act ) else -- Otherwise, cancel the old callback. ( cancel act.callback ) act.callback := cb ) -- Method scheduleAction schedules the specified action depending on the -- action's time. If the time is after the current time, then the action -- is scheduled immediately. If the time is before the current time, the -- action is added to the action queue. method scheduleAction self {class TimeLine} action -> ( if (action.time > self.time) then ( -- If this action is in the queue, remove it. if (isMember self.queuedActions action) do ( deleteOne self.queuedActions action ) scheduleImmediately self action ) else ( -- It this action is already scheduled, cancel it... if (isMember self.actions action) do ( cancelAction self action ) -- and add it the queue for the next time around. append self.queuedActions action ) ) -- Method cancelAction cancels the specified action. method cancelAction self {class TimeLine} act -> ( cancel act.callback deleteOne self.actions act ) "Compiled timeline.sx" -->>>