[Golist] [goasap commit] r60 - Fixes the initial commit so it works! I've now lightly tested the updates to SequenceCA and...
codesite-noreply at google.com
codesite-noreply at google.com
Tue Mar 17 16:39:59 PDT 2009
Author: mosesoak
Date: Tue Mar 17 16:22:37 2009
New Revision: 60
Modified:
branches/goasap0.5.2/src_go/org/goasap/utils/PlayableGroup.as
branches/goasap0.5.2/src_go/org/goasap/utils/SequenceCA.as
Log:
Fixes the initial commit so it works! I've now lightly tested the updates
to SequenceCA and the new ImmediateAdvance class, both of which seem to
work.
Modified: branches/goasap0.5.2/src_go/org/goasap/utils/PlayableGroup.as
==============================================================================
--- branches/goasap0.5.2/src_go/org/goasap/utils/PlayableGroup.as (original)
+++ branches/goasap0.5.2/src_go/org/goasap/utils/PlayableGroup.as Tue Mar
17 16:22:37 2009
@@ -1 +1 @@
-/**
* Copyright (c) 2007 Moses Gunesch
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the "Software"), to
deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.goasap.utils {
import org.goasap.PlayStates;
import org.goasap.PlayableBase;
import org.goasap.events.GoEvent;
import org.goasap.interfaces.IPlayable;
import org.goasap.managers.Repeater;
import flash.utils.Dictionary;
/**
* Dispatched when the group starts.
* @eventType org.goasap.events.START
*/
[Event(name="START", type="org.goasap.events.GoEvent")]
/**
* Dispatched when the group is paused successfully.
* @eventType org.goasap.events.PAUSE
*/
[Event(name="PAUSE", type="org.goasap.events.GoEvent")]
/**
* Dispatched when the group is resumed successfully.
* @eventType org.goasap.events.RESUME
*/
[Event(name="RESUME", type="org.goasap.events.GoEvent")]
/**
* Dispatched at the end the group if <code>repeater.cycles</code> is set
to
* a value other than one, just before the group starts its next play
cycle.
* @eventType org.goasap.events.CYCLE
*/
[Event(name="CYCLE", type="org.goasap.events.GoEvent")]
/**
* Dispatched if the group is manually stopped.
* @eventType org.goasap.events.STOP
*/
[Event(name="STOP", type="org.goasap.events.GoEvent")]
/**
* Dispatched after all children have dispatched a STOP or COMPLETE event.
* @eventType org.goasap.events.COMPLETE
*/
[Event(name="COMPLETE", type="org.goasap.events.GoEvent")]
/**
* Batch-play a set of items and receive an event when all of them have
finished.
*
* <p>PlayableGroup accepts any IPlayable for its children, which can
include
* tweens, other groups, sequences and so forth. The group listens for both
* GoEvent.STOP and GoEvent.COMPLETE events from its children, either of
which
* are counted toward group completion.</p>
*
* <p>The <code>repeater</code> property of PlayableGroup allows you to
loop play
* any number of times, or indefinitely by setting its cycles to
Repeater.INFINITE.
* GoEvent.CYCLE is dispatched on each loop and GoEvent.COMPLETE when
finished.
* Other events dispatched include the GoEvent types START, STOP, PAUSE,
and RESUME.</p>
*
* @author Moses Gunesch
*/
public class PlayableGroup extends PlayableBase implements IPlayable {
// -== Public Properties ==-
/**
* Get or set the children array. Only IPlayable items are stored. Note
that
* unlike the methods <code>addChild</code> and <code>removeChild</code>,
* setting this property will stop any group play currently in progress.
*/
public function get children():Array {
var a:Array = [];
for (var item:Object in _children)
a.push(item);
return a;
}
public function set children(a:Array):void {
if (_listeners > 0)
stop();
for each (var item:Object in a)
if (item is IPlayable)
addChild(item as IPlayable);
}
/**
* The groups's Repeater instance, which may be used to make
* it loop and play more than one time.
*
* <p>The Repeater's cycles property can be set to an integer, or
* to Repeater.INFINITE or 0 to repeat indefinitely.</p>
*
* <pre>
* var group:PlayableGroup = new PlayableGroup(tween1, tween2, tween3);
* group.repeater.cycles = 2;
* group.start();
* trace(group.repeater.currentCycle); // output: 0
* </pre>
*/
public function get repeater(): Repeater {
return _repeater;
}
/**
* Determines the number of children currently being monitored
* for completion by the group.
*/
public function get listenerCount() : uint {
return _listeners;
}
// -== Protected Properties ==-
/** @private */
protected var _children: Dictionary = new Dictionary();
/** @private */
protected var _listeners: uint = 0;
/** @private */
protected var _repeater: Repeater;
// -== Public Methods ==-
/**
* Constructor.
*
* @param items Any number of IPlayable items as separate arguments,
* or a single array of them.
*/
public function PlayableGroup(...items) {
super();
if (items.length > 0)
this.children = ((items[ 0 ] is Array) ? items[ 0 ] : items);
_repeater = new Repeater();
_repeater.setParent(this);
}
/**
* Searches for a child with the specified playableID.
*
* @param playableID The item playableID to search for. (The item must
have a
* property called <code>playableID</code> which is a general
* GoASAP convention established in PlayableBase.)
* @param deepSearch If child is not found in the group, this option runs
a
* recursive search on any children that are PlayableGroup.
* @return The SequenceStep with the matching playableID.
*/
public function getChildByID(playableID:*,
deepSearch:Boolean=true):IPlayable {
for (var item:Object in _children)
if (item.hasOwnProperty("playableID") &&
item["playableID"]===playableID)
return (item as IPlayable);
if (deepSearch) {
for (item in _children) {
if (item is PlayableGroup) {
var match:IPlayable = ((item as
PlayableGroup).getChildByID(playableID, true));
if (match) { return (match as IPlayable); }
}
}
}
return null;
}
/**
* Adds a single IPlayable to the children array (duplicates are
rejected) and
* syncs up the group and child play-states based on various conditions.
*
* <p>Normally this method is called when both the group and the child
item are
* not playing. However in some cases either the group or the child might
be
* playing or paused, in which case calling this method will attempt to
sync
* the child state with the group's state. If syncing fails the child is
not added
* and false is returned.</p>
*
* @param item Any instance that implements IPlayable and uses
PlayState constants.
* @return The item added, or null if the item was already in the
group or
* a mismatched child state was not syncable to the group's state.
*/
public function addChild(item:IPlayable): IPlayable {
var itemState:String = item.state;
if (_children[ item ]!=null) {
return null; // child already added!
}
_children[ item ] = false;
if (_state==PlayStates.STOPPED && itemState!=PlayStates.STOPPED) {
item.stop();
}
if (itemState==_state) {
return item; // states match: no further action is needed. this is most
common.
}
// Group is active: attempt syncing of child state to group state.
var success:Boolean = true;
listenTo(item);
if (_state==PlayStates.PLAYING || _state==PlayStates.PLAYING_DELAY) {
if (itemState==PlayStates.PAUSED) {
success = item.resume();
}
else if (itemState==PlayStates.STOPPED) {
success = item.start();
}
else {
return item; // Item is already playing and only delay states
mismatch: Success.
}
}
else if (_state==PlayStates.PAUSED) {
if (itemState==PlayStates.STOPPED) {
item.start();
}
success = item.pause();
}
if (!success) {
unListenTo(item);
delete _children[ item ];
return null;
}
return item;
}
/**
* Removes a single IPlayable from the children array.
*
* <p>Note that if play is in progress when a child is added it does not
* interrupt play and the child is monitored for completion along with
* others.</p>
*
* @param item Any instance that implements IPlayable and uses PlayState
constants.
* @return The item removed, or null if the call failed.
*/
public function removeChild(item:IPlayable): IPlayable {
var v:* = _children[ item ];
if (v===null)
return null;
if (v===true)
unListenTo( item );
delete _children[ item ];
return item;
}
/**
* Enables already-playing items to be added to a group seamlessly by
presetting
* the group's state to PLAYING instead of interrupting the child item.
*
* @param item Any instance that implements IPlayable and uses PlayState
constants.
* @return The item added, or null if the call failed.
*/
public function addPlayingChildAndStart(item:IPlayable): IPlayable {
_state = PlayStates.PLAYING;
item = addChild(item); // Item will start if stopped and resume if
paused.
if (_listeners > 0) {
dispatchEvent(new GoEvent( GoEvent.START));
_playRetainer[ this ] = 1; // Developers - Important! Look up
_playRetainer.
}
else {
_state = PlayStates.STOPPED;
}
return item;
}
/**
* Test whether any child has a particular PlayState.
*
* <pre>
* // Example: resume a paused group
* if ( myGroup.anyChildHasState(PlayStates.PlayStates.PAUSED) ) {
* myGroup.resume();
* }
* </pre>
* @see org.goasap.PlayStates PlayStates
*/
public function anyChildHasState(state:String): Boolean {
for (var item:Object in _children)
if ((item as IPlayable).state==state)
return true;
return false;
}
// -== IPlayable implementation ==-
/**
* Calls start on all children.
*
* <p>If the group is active when this method is called, a
<code>stop</code> call
* is automated which will result in a GoEVent.STOP event being
dispatched.</p>
*
* @return Returns true if any child in the group starts successfully.
*/
public function start() : Boolean {
stop();
var r:Boolean = false;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
listenTo(item); // first in case of immediate STOP/COMPLETE.
var started:Boolean = item.start();
if (!started) {
unListenTo(item);
}
r = (started || r);
}
if (!r) return false; // all starts failed
_state = PlayStates.PLAYING;
dispatchEvent(new GoEvent( GoEvent.START));
_playRetainer[ this ] = 1; // Developers - Important! Look up
_playRetainer.
return true;
}
/**
* If the group is active, this method stops all child items and
* dispatches a GoEvent.STOP event.
*
* @return Returns true only if all children in the group stop
successfully.
*/
public function stop() : Boolean {
if (_state == PlayStates.STOPPED)
return false;
_state = PlayStates.STOPPED;
_repeater.reset();
delete _playRetainer[ this ]; // Developers - Important! Look up
_playRetainer.
if (_listeners==0) {
dispatchEvent(new GoEvent( GoEvent.COMPLETE ));
return true;
}
var r:Boolean = true;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
unListenTo(item);
r = (item.stop() && r);
}
dispatchEvent(new GoEvent( GoEvent.STOP ));
return r;
}
/**
* Calls <code>pause</code> on all children.
*
* @return Returns true only if all playing children in the group paused
successfully
* and at least one child was paused.
*/
public function pause() : Boolean {
if (_state!= PlayStates.PLAYING)
return false;
var r:Boolean = true;
var n:uint = 0;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
var success:Boolean = item.pause();
if (success) n++;
r = (r && success);
}
if (n>0) {
_state = PlayStates.PAUSED; // state should reflect that at least one
item was paused,
// while return value may indicate that not all pause calls
succeeded.
dispatchEvent(new GoEvent( GoEvent.PAUSE ));
}
return (n>0 && r);
}
/**
* Calls <code>resume</code> on all children.
*
* @return Returns true only if all paused children in the group resumed
successfully
* and at least one child was resumed.
*/
public function resume() : Boolean {
if (_state!= PlayStates.PAUSED)
return false;
var r:Boolean = true;
var n:uint = 0;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
var success:Boolean = item.resume();
if (success) n++;
r = (r && success);
}
if (n>0) {
_state = PlayStates.PLAYING; // state should reflect that at least one
item was resumed,
// while return value may indicate that not all resume calls
succeeded.
dispatchEvent(new GoEvent( GoEvent.RESUME ));
}
return (n>0 && r);
}
/**
* Calls <code>skipTo</code> on all children.
*
* @return Returns true only if all children in the group skipTo the
position successfully
* and at least one child was affected.
*/
public function skipTo(position : Number) : Boolean {
var r:Boolean = true;
var n:uint = 0;
position = _repeater.skipTo(_repeater.cycles, position); // TODO: TEST
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
listenTo(item); // first in case of immediate STOP/COMPLETE.
var started:Boolean = item.skipTo(position);
if (!started || item.state==PlayStates.STOPPED) {
unListenTo(item);
started = false;
}
else { n++; }
r = (started && r);
}
_state = (r ? PlayStates.PLAYING : PlayStates.STOPPED);
return (n>0 && r);
}
// -== Protected Methods ==-
/**
* @private
* Internal handler for item completion.
* @param event GoEvent dispatched by child item.
*/
protected function onItemEnd(event:GoEvent) : void {
unListenTo(event.target as IPlayable);
if (_listeners==0) {
complete();
}
}
/**
* @private
* Internal handler for group completion.
*/
protected function complete() : void {
if (_repeater.next()) {
dispatchEvent(new GoEvent( GoEvent.CYCLE ));
var c:Array = this.children; // array is used because cycling
Dictionary and setting entries can result in duplicates (Dictionary bug,
apparently.)
for each (var item:IPlayable in c) {
listenTo(item); // first in case of immediate STOP/COMPLETE.
var started:Boolean = (item).start();
if (!started || item.state==PlayStates.STOPPED)
unListenTo(item);
}
}
else {
stop();
}
}
/**
* @private
* Internal. Listen for item completion, keeping tight track of listeners.
* @param item Any instance that extends IPlayable (IPlayable itself
should not be used directly).
*/
protected function listenTo(item:IPlayable) : void {
if (_children[ item ] === false) {
item.addEventListener(GoEvent.STOP, onItemEnd, false, 0, true);
item.addEventListener(GoEvent.COMPLETE, onItemEnd, false, 0, true);
_children[ item ] = true;
_listeners++;
}
}
/**
* @private
* Internal. Stop listening for item completion.
* @param item Any instance that extends IPlayable (IPlayable itself
should not be used directly).
* @return Number of completion listeners remaining.
*/
protected function unListenTo(item:IPlayable) : void {
if (_children[ item ] === true) {
item.removeEventListener(GoEvent.STOP, onItemEnd);
item.removeEventListener(GoEvent.COMPLETE, onItemEnd);
_children[ item ] = false;
_listeners--;
}
}
}
}
\ No newline at end of file
+/**
* Copyright (c) 2007 Moses Gunesch
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the "Software"), to
deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.goasap.utils {
import org.goasap.PlayStates;
import org.goasap.PlayableBase;
import org.goasap.events.GoEvent;
import org.goasap.interfaces.IPlayable;
import org.goasap.managers.Repeater;
import flash.utils.Dictionary;
/**
* Dispatched when the group starts.
* @eventType org.goasap.events.START
*/
[Event(name="START", type="org.goasap.events.GoEvent")]
/**
* Dispatched when the group is paused successfully.
* @eventType org.goasap.events.PAUSE
*/
[Event(name="PAUSE", type="org.goasap.events.GoEvent")]
/**
* Dispatched when the group is resumed successfully.
* @eventType org.goasap.events.RESUME
*/
[Event(name="RESUME", type="org.goasap.events.GoEvent")]
/**
* Dispatched at the end the group if <code>repeater.cycles</code> is set
to
* a value other than one, just before the group starts its next play
cycle.
* @eventType org.goasap.events.CYCLE
*/
[Event(name="CYCLE", type="org.goasap.events.GoEvent")]
/**
* Dispatched if the group is manually stopped.
* @eventType org.goasap.events.STOP
*/
[Event(name="STOP", type="org.goasap.events.GoEvent")]
/**
* Dispatched after all children have dispatched a STOP or COMPLETE event.
* @eventType org.goasap.events.COMPLETE
*/
[Event(name="COMPLETE", type="org.goasap.events.GoEvent")]
/**
* Batch-play a set of items and receive an event when all of them have
finished.
*
* <p>PlayableGroup accepts any IPlayable for its children, which can
include
* tweens, other groups, sequences and so forth. The group listens for both
* GoEvent.STOP and GoEvent.COMPLETE events from its children, either of
which
* are counted toward group completion.</p>
*
* <p>The <code>repeater</code> property of PlayableGroup allows you to
loop play
* any number of times, or indefinitely by setting its cycles to
Repeater.INFINITE.
* GoEvent.CYCLE is dispatched on each loop and GoEvent.COMPLETE when
finished.
* Other events dispatched include the GoEvent types START, STOP, PAUSE,
and RESUME.</p>
*
* @author Moses Gunesch
*/
public class PlayableGroup extends PlayableBase implements IPlayable {
// -== Public Properties ==-
/**
* Get or set the children array. Only IPlayable items are stored. Note
that
* unlike the methods <code>addChild</code> and <code>removeChild</code>,
* setting this property will stop any group play currently in progress.
*/
public function get children():Array {
var a:Array = [];
for (var item:Object in _children)
a.push(item);
return a;
}
public function set children(a:Array):void {
if (_listeners > 0)
stop();
for each (var item:Object in a)
if (item is IPlayable)
addChild(item as IPlayable);
}
/**
* The groups's Repeater instance, which may be used to make
* it loop and play more than one time.
*
* <p>The Repeater's cycles property can be set to an integer, or
* to Repeater.INFINITE or 0 to repeat indefinitely.</p>
*
* <pre>
* var group:PlayableGroup = new PlayableGroup(tween1, tween2, tween3);
* group.repeater.cycles = 2;
* group.start();
* trace(group.repeater.currentCycle); // output: 0
* </pre>
*/
public function get repeater(): Repeater {
return _repeater;
}
/**
* Determines the number of children currently being monitored
* for completion by the group.
*/
public function get listenerCount() : uint {
return _listeners;
}
// -== Protected Properties ==-
/** @private */
protected var _children: Dictionary = new Dictionary();
/** @private */
protected var _listeners: uint = 0;
/** @private */
protected var _repeater: Repeater;
// -== Public Methods ==-
/**
* Constructor.
*
* @param items Any number of IPlayable items as separate arguments,
* or a single array of them.
*/
public function PlayableGroup(...items) {
super();
if (items.length > 0)
this.children = ((items[ 0 ] is Array) ? items[ 0 ] : items);
_repeater = new Repeater();
_repeater.setParent(this);
}
/**
* Searches for a child with the specified playableID.
*
* @param playableID The item playableID to search for. (The item must
have a
* property called <code>playableID</code> which is a general
* GoASAP convention established in PlayableBase.)
* @param deepSearch If child is not found in the group, this option runs
a
* recursive search on any children that are PlayableGroup.
* @return The SequenceStep with the matching playableID.
*/
public function getChildByID(playableID:*,
deepSearch:Boolean=true):IPlayable {
for (var item:Object in _children)
if (item.hasOwnProperty("playableID") &&
item["playableID"]===playableID)
return (item as IPlayable);
if (deepSearch) {
for (item in _children) {
if (item is PlayableGroup) {
var match:IPlayable = ((item as
PlayableGroup).getChildByID(playableID, true));
if (match) { return (match as IPlayable); }
}
}
}
return null;
}
/**
* Adds a single IPlayable to the children array (duplicates are
rejected) and
* syncs up the group and child play-states based on various conditions.
*
* <p>Normally this method is called when both the group and the child
item are
* not playing. However in some cases either the group or the child might
be
* playing or paused, in which case calling this method will attempt to
sync
* the child state with the group's state. If syncing fails the child is
not added
* and false is returned.</p>
*
* @param item Any instance that implements IPlayable and uses
PlayState constants.
* @return The item added, or null if the item was already in the
group or
* a mismatched child state was not syncable to the group's state.
*/
public function addChild(item:IPlayable): IPlayable {
var itemState:String = item.state;
if (_children[ item ]!=null) {
return null; // child already added!
}
_children[ item ] = false;
if (_state==PlayStates.STOPPED) { // group is inactive, sync item by
stopping if necessary.
if (itemState!=PlayStates.STOPPED) {
item.stop();
}
return item;
}
// Group is active: attempt syncing of child state to group state.
var success:Boolean = true;
listenTo(item);
if (_state==PlayStates.PLAYING || _state==PlayStates.PLAYING_DELAY) {
if (itemState==PlayStates.PAUSED) {
success = item.resume();
}
else if (itemState==PlayStates.STOPPED) {
success = item.start();
}
else {
return item; // Item is already playing and only delay states
mismatch: Success.
}
}
else if (_state==PlayStates.PAUSED) {
if (itemState==PlayStates.STOPPED) {
item.start();
}
success = item.pause();
}
if (!success) {
unListenTo(item);
delete _children[ item ];
return null;
}
return item;
}
/**
* Removes a single IPlayable from the children array.
*
* <p>Note that if play is in progress when a child is added it does not
* interrupt play and the child is monitored for completion along with
* others.</p>
*
* @param item Any instance that implements IPlayable and uses PlayState
constants.
* @return The item removed, or null if the call failed.
*/
public function removeChild(item:IPlayable): IPlayable {
var v:* = _children[ item ];
if (v===null)
return null;
if (v===true)
unListenTo( item );
delete _children[ item ];
return item;
}
/**
* Enables already-playing items to be added to a group seamlessly by
presetting
* the group's state to PLAYING instead of interrupting the child item.
*
* @param item Any instance that implements IPlayable and uses PlayState
constants.
* @return The item added, or null if the call failed.
*/
public function addPlayingChildAndStart(item:IPlayable): IPlayable {
_state = PlayStates.PLAYING;
item = addChild(item); // Item will start if stopped and resume if
paused.
if (_listeners > 0) {
dispatchEvent(new GoEvent( GoEvent.START));
_playRetainer[ this ] = 1; // Developers - Important! Look up
_playRetainer.
}
else {
_state = PlayStates.STOPPED;
}
return item;
}
/**
* Test whether any child has a particular PlayState.
*
* <pre>
* // Example: resume a paused group
* if ( myGroup.anyChildHasState(PlayStates.PlayStates.PAUSED) ) {
* myGroup.resume();
* }
* </pre>
* @see org.goasap.PlayStates PlayStates
*/
public function anyChildHasState(state:String): Boolean {
for (var item:Object in _children)
if ((item as IPlayable).state==state)
return true;
return false;
}
// -== IPlayable implementation ==-
/**
* Calls start on all children.
*
* <p>If the group is active when this method is called, a
<code>stop</code> call
* is automated which will result in a GoEVent.STOP event being
dispatched.</p>
*
* @return Returns true if any child in the group starts successfully.
*/
public function start() : Boolean {
stop();
var r:Boolean = false;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
listenTo(item); // first in case of immediate STOP/COMPLETE.
var started:Boolean = item.start();
if (!started) {
unListenTo(item);
}
r = (started || r);
}
if (!r) return false; // all starts failed
_state = PlayStates.PLAYING;
dispatchEvent(new GoEvent( GoEvent.START));
_playRetainer[ this ] = 1; // Developers - Important! Look up
_playRetainer.
return true;
}
/**
* If the group is active, this method stops all child items and
* dispatches a GoEvent.STOP event.
*
* @return Returns true only if all children in the group stop
successfully.
*/
public function stop() : Boolean {
if (_state == PlayStates.STOPPED)
return false;
_state = PlayStates.STOPPED;
_repeater.reset();
delete _playRetainer[ this ]; // Developers - Important! Look up
_playRetainer.
if (_listeners==0) {
dispatchEvent(new GoEvent( GoEvent.COMPLETE ));
return true;
}
var r:Boolean = true;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
unListenTo(item);
r = (item.stop() && r);
}
dispatchEvent(new GoEvent( GoEvent.STOP ));
return r;
}
/**
* Calls <code>pause</code> on all children.
*
* @return Returns true only if all playing children in the group paused
successfully
* and at least one child was paused.
*/
public function pause() : Boolean {
if (_state!= PlayStates.PLAYING)
return false;
var r:Boolean = true;
var n:uint = 0;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
var success:Boolean = item.pause();
if (success) n++;
r = (r && success);
}
if (n>0) {
_state = PlayStates.PAUSED; // state should reflect that at least one
item was paused,
// while return value may indicate that not all pause calls
succeeded.
dispatchEvent(new GoEvent( GoEvent.PAUSE ));
}
return (n>0 && r);
}
/**
* Calls <code>resume</code> on all children.
*
* @return Returns true only if all paused children in the group resumed
successfully
* and at least one child was resumed.
*/
public function resume() : Boolean {
if (_state!= PlayStates.PAUSED)
return false;
var r:Boolean = true;
var n:uint = 0;
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
var success:Boolean = item.resume();
if (success) n++;
r = (r && success);
}
if (n>0) {
_state = PlayStates.PLAYING; // state should reflect that at least one
item was resumed,
// while return value may indicate that not all resume calls
succeeded.
dispatchEvent(new GoEvent( GoEvent.RESUME ));
}
return (n>0 && r);
}
/**
* Calls <code>skipTo</code> on all children.
*
* @return Returns true only if all children in the group skipTo the
position successfully
* and at least one child was affected.
*/
public function skipTo(position : Number) : Boolean {
var r:Boolean = true;
var n:uint = 0;
position = _repeater.skipTo(_repeater.cycles, position); // TODO: TEST
var c:Array = this.children; // array is used because cycling Dictionary
and setting entries can result in duplicates (Dictionary bug, apparently.)
for each (var item:IPlayable in c) {
listenTo(item); // first in case of immediate STOP/COMPLETE.
var started:Boolean = item.skipTo(position);
if (!started || item.state==PlayStates.STOPPED) {
unListenTo(item);
started = false;
}
else { n++; }
r = (started && r);
}
_state = (r ? PlayStates.PLAYING : PlayStates.STOPPED);
return (n>0 && r);
}
// -== Protected Methods ==-
/**
* @private
* Internal handler for item completion.
* @param event GoEvent dispatched by child item.
*/
protected function onItemEnd(event:GoEvent) : void {
unListenTo(event.target as IPlayable);
if (_listeners==0) {
complete();
}
}
/**
* @private
* Internal handler for group completion.
*/
protected function complete() : void {
if (_repeater.next()) {
dispatchEvent(new GoEvent( GoEvent.CYCLE ));
var c:Array = this.children; // array is used because cycling
Dictionary and setting entries can result in duplicates (Dictionary bug,
apparently.)
for each (var item:IPlayable in c) {
listenTo(item); // first in case of immediate STOP/COMPLETE.
var started:Boolean = (item).start();
if (!started || item.state==PlayStates.STOPPED)
unListenTo(item);
}
}
else {
stop();
}
}
/**
* @private
* Internal. Listen for item completion, keeping tight track of listeners.
* @param item Any instance that extends IPlayable (IPlayable itself
should not be used directly).
*/
protected function listenTo(item:IPlayable) : void {
if (_children[ item ] === false) {
item.addEventListener(GoEvent.STOP, onItemEnd, false, 0, true);
item.addEventListener(GoEvent.COMPLETE, onItemEnd, false, 0, true);
_children[ item ] = true;
_listeners++;
}
}
/**
* @private
* Internal. Stop listening for item completion.
* @param item Any instance that extends IPlayable (IPlayable itself
should not be used directly).
* @return Number of completion listeners remaining.
*/
protected function unListenTo(item:IPlayable) : void {
if (_children[ item ] === true) {
item.removeEventListener(GoEvent.STOP, onItemEnd);
item.removeEventListener(GoEvent.COMPLETE, onItemEnd);
_children[ item ] = false;
_listeners--;
}
}
}
}
\ No newline at end of file
Modified: branches/goasap0.5.2/src_go/org/goasap/utils/SequenceCA.as
==============================================================================
--- branches/goasap0.5.2/src_go/org/goasap/utils/SequenceCA.as (original)
+++ branches/goasap0.5.2/src_go/org/goasap/utils/SequenceCA.as Tue Mar 17
16:22:37 2009
@@ -1 +1 @@
-/**
* Copyright (c) 2007 Moses Gunesch
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the "Software"), to
deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.goasap.utils {
import org.goasap.PlayStates;
import org.goasap.events.GoEvent;
import org.goasap.events.SequenceEvent;
import org.goasap.interfaces.IPlayable;
import flash.events.Event;
/**
* Sequence with "Custom Advance" options, in which steps can specify when
they should advance.
*
* <p>This class works like Sequence but uses the special class
SequenceStepCA for its steps.
* SequenceStepCA has a property called <code>advance</code>. When steps
advance before animation
* finishes, the trailing steps are tracked so that the SequenceCA doesn't
dispatch its COMPLETE
* event until all activity has completed.</p>
*
* <p>Any step's advance property can be set to an instance of
OnDurationComplete, OnPlayableComplete,
* OnEventComplete or OnConditionTrue. Each of those classes defines its
own parameters and rules for
* when the advance occurs. For example, using OnPlayableComplete a
sequence can advance after one
* particular item in the step finishes, without needing to wait for all
the other ones in that group
* to complete.</p>
*
* <p>Additionally, you can create your own custom advance types by
subclassing the SequenceAdvance
* base class.</p>
*
* @see SequenceStepCA
* @see org.goasap.utils.customadvance.OnConditionTrue OnConditionTrue
* @see org.goasap.utils.customadvance.OnDurationComplete
OnDurationComplete
* @see org.goasap.utils.customadvance.OnEventComplete OnEventComplete
* @see org.goasap.utils.customadvance.OnPlayableComplete
OnPlayableComplete
* @see org.goasap.utils.customadvance.SequenceAdvance SequenceAdvance
* @see Sequence
* @see SequenceBase
*
* @author Moses Gunesch
*/
public class SequenceCA extends SequenceBase {
// -== Public Properties ==-
// Also in super:
// length : uint [Read-only.]
// playIndex : int [Read-only.]
// steps : Array
// start() : Boolean
// stop() : Boolean
// pause() : Boolean
// resume() : Boolean
// skipTo(index:Number) : Boolean
/**
* Returns the currently-playing SequenceStepCA.
* @return The currently-playing SequenceStepCA.
* @see #getStepAt()
* @see #getStepByID()
* @see #steps
* @see #lastStep
*/
public function get currentStep() : SequenceStepCA {
return (super._getCurrentStep() as SequenceStepCA);
}
/**
* Returns the final SequenceStepCA in the current sequence.
* @return The final SequenceStepCA in the current sequence.
* @see #getStepAt()
* @see #getStepByID()
* @see #steps
* @see #currentStep
*/
public function get lastStep() : SequenceStepCA {
return (super._getLastStep() as SequenceStepCA);
}
// -== Protected Properties ==-
/**
* @private
*/
protected var _trailingSteps : SequenceStep;
// -== Public Methods ==-
/**
* Constructor.
*
* @param items Any number of IPlayable instances (e.g. LinearGo,
PlayableGroup,
* SequenceStepCA) as separate arguments, or a single array of them.
*/
public function SequenceCA(...items) {
super((items[ 0 ] is Array) ? items[ 0 ] : items);
}
/**
* Retrieves any SequenceStepCA from the steps array.
* @param index An array index starting at 0.
* @return The SequenceStepCA instance at this index.
* @see #getStepByID()
*/
public function getStepAt(index:int) : SequenceStepCA {
return (super._getStepAt(index) as SequenceStepCA);
}
/**
* Locates a step with the specified playableID. To search within a step
for a
* child by playableID, use the step instance's <code>getChildByID</code>
method.
*
* @param playableID The step instance's playableID to search for.
* @return The SequenceStepCA with the matching playableID.
*/
public function getStepByID(playableID:*) : SequenceStepCA {
return (super._getStepByID(playableID) as SequenceStepCA);
}
/**
* Adds a single SequenceStepCA or IPlayable instance (LinearGo,
PlayableGroup,
* etc.) to the end of the steps array, or optionally adds the instance
into the
* last SequenceStepCA instead of adding it as a new step. Calling this
* method stops any sequence play currently in progress.
*
* <p>To remove a step use the <code>removeStepAt</code> method.</p>
*
* @param item The playable item to add to the sequence. Note
* that when new steps are added, any IPlayable
* instance of a type other than SequenceStepCA is
* automatically wrapped in a new SequenceStepCA.
*
* @param addToLastStep If true is passed the item is added to the last
* existing SequenceStepCA in the steps array. This
* option should be used with individual items that
* you want added as children to the SequenceStepCA.
* If there are no steps yet this option ignored and
* a new step is created.
*
* @return Item added.
*/
public function addStep(item:IPlayable, addToLastStep:Boolean=false):
IPlayable {
return (super._addStep(item, addToLastStep, SequenceStepCA));
}
/**
* Adds a single SequenceStepCA or IPlayable instance (LinearGo,
PlayableGroup,
* etc.) at a specific index in the steps array. Calling this method
stops any
* sequence play currently in progress.
*
* @param item The playable item to splice into the sequence.
*
* @param index Position in the array starting at 0, or a negative
* index like Array.splice.
*
* @return Item added.
*/
public function addStepAt(item:IPlayable, index:int): IPlayable {
return (super._addStepAt(index, item, SequenceStepCA));
}
/**
* Removes and returns the SequenceStepCA at a specific index from the
steps
* array. Calling this method stops any sequence play currently in
progress.
*
* @param index Position in the array starting at 0, or a negative
* index like Array.splice.
*
* @return The SequenceStepCA instance removed from the steps array.
*/
public function removeStepAt(index:int): SequenceStepCA {
return (super._removeStepAt(index) as SequenceStepCA);
}
// -== IPlayable implementation ==-
/**
* Begins a sequence.
*
* <p>If the group is active when this method is called, a
<code>stop</code> call
* is automated which will result in a GoEvent.STOP event being
dispatched.</p>
*
* @return Returns true unless there are no steps in the sequence.
*/
override public function start() : Boolean {
return super.start();
}
/**
* Stops all activity and dispatches a GoEvent.STOP event.
*
* @return Returns true unless sequence was already stopped.
*/
override public function stop() : Boolean {
if (super.stop()==false)
return false;
initTrailingSteps(false);
return true;
}
/**
* Pauses sequence play.
*
* @return Returns true unless sequence was unable to pause any children.
*/
override public function pause() : Boolean {
var success:Boolean = super.pause();
if (_trailingSteps!=null) {
_trailingSteps.pause();
if (_trailingSteps.state==PlayStates.PAUSED) {
_state = PlayStates.PAUSED;
success = true;
}
}
return success;
}
/**
* Resumes previously-paused sequence play.
*
* @return Returns true unless sequence was unable to resume any
children.
*/
override public function resume() : Boolean {
var success:Boolean = super.resume();
if (_trailingSteps!=null) {
_trailingSteps.resume();
if (_trailingSteps.state==PlayStates.PLAYING) {
_state = PlayStates.PLAYING;
success = true;
}
}
return success;
}
/**
* Stops current activity and skips to another step by sequence index.
*
* @return Always returns true since the index is normalized to the
sequence.
*/
override public function skipTo(index : Number) : Boolean {
if (_steps.length==0)
return false;
initTrailingSteps(false);
return super.skipTo(index);
}
// -== Protected Methods ==-
/**
* @private
* Internal handler for item completion.
* @param event SequenceEvent dispatched by child item.
*/
override protected function onStepEvent(event : Event) : void {
// A stop() call to the sequence results in step dispatching STOP, which
would recurse here.
if (_state==PlayStates.STOPPED)
return;
// trailing item
if (_trailingSteps!=null && event.target==_trailingSteps &&
event.type==SequenceEvent.ADVANCE) {
initTrailingSteps(false);
if (_steps.length-_index==1) {
if (lastStep.state==PlayStates.STOPPED) {
// A completed sequence was waiting for trailing steps to finish.
// Otherwise, trailing items have finished before sequence ended so
no action should be taken.
complete();
}
else {
// Special case where advance already fired but trailing steps have
all completed: use COMPLETE
lastStep.addEventListener(GoEvent.COMPLETE, onStepEvent);
}
}
return;
}
// Finishes special case in trailing item block. Also, returns out if
we're waiting
if (lastStep.hasEventListener(GoEvent.COMPLETE)) {
if (event.type==GoEvent.COMPLETE) {
initTrailingSteps(false); // _trailingSteps is null, this is to remove
the COMPLETE listener.
complete();
}
return;
}
super.onStepEvent(event);
}
/**
* @private
* Internal handler for step advance.
*/
override protected function advance() : void {
if (currentStep.listenerCount > 0) {
initTrailingSteps(true);
_trailingSteps.addChildAndAdoptState(currentStep);
}
super.advance();
}
/**
* @private
* Internal handler for group completion.
*/
override protected function complete() : void {
if (_trailingSteps==null) {
super.complete();
}
}
/**
* @private
* Internal setup for tracking items that are continuing to run after a
custom advance.
* @param active Whether to create or destroy the trailing-steps group.
*/
protected function initTrailingSteps(active:Boolean):void {
if (_trailingSteps==null && active) {
_trailingSteps = new SequenceStep();
_trailingSteps.playableID += "(_trailingSteps for
sequence:"+playableID+")";
_trailingSteps.addEventListener(SequenceEvent.ADVANCE, onStepEvent);
}
else if (!active) {
lastStep.removeEventListener(GoEvent.COMPLETE, onStepEvent); // Remove
special case set in onStepEvent.
if (_trailingSteps!=null) {
_trailingSteps.removeEventListener(SequenceEvent.ADVANCE, onStepEvent);
_trailingSteps.stop();
_trailingSteps = null;
}
}
}
}
}
\ No newline at end of file
+/**
* Copyright (c) 2007 Moses Gunesch
*
* Permission is hereby granted, free of charge, to any person obtaining a
copy
* of this software and associated documentation files (the "Software"), to
deal
* in the Software without restriction, including without limitation the
rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.goasap.utils {
import org.goasap.PlayStates;
import org.goasap.events.GoEvent;
import org.goasap.events.SequenceEvent;
import org.goasap.interfaces.IPlayable;
import flash.events.Event;
/**
* Sequence with "Custom Advance" options, in which steps can specify when
they should advance.
*
* <p>This class works like Sequence but uses the special class
SequenceStepCA for its steps.
* SequenceStepCA has a property called <code>advance</code>. When steps
advance before animation
* finishes, the trailing steps are tracked so that the SequenceCA doesn't
dispatch its COMPLETE
* event until all activity has completed.</p>
*
* <p>Any step's advance property can be set to an instance of
OnDurationComplete, OnPlayableComplete,
* OnEventComplete or OnConditionTrue. Each of those classes defines its
own parameters and rules for
* when the advance occurs. For example, using OnPlayableComplete a
sequence can advance after one
* particular item in the step finishes, without needing to wait for all
the other ones in that group
* to complete.</p>
*
* <p>Additionally, you can create your own custom advance types by
subclassing the SequenceAdvance
* base class.</p>
*
* @see SequenceStepCA
* @see org.goasap.utils.customadvance.OnConditionTrue OnConditionTrue
* @see org.goasap.utils.customadvance.OnDurationComplete
OnDurationComplete
* @see org.goasap.utils.customadvance.OnEventComplete OnEventComplete
* @see org.goasap.utils.customadvance.OnPlayableComplete
OnPlayableComplete
* @see org.goasap.utils.customadvance.SequenceAdvance SequenceAdvance
* @see Sequence
* @see SequenceBase
*
* @author Moses Gunesch
*/
public class SequenceCA extends SequenceBase {
// -== Public Properties ==-
// Also in super:
// length : uint [Read-only.]
// playIndex : int [Read-only.]
// steps : Array
// start() : Boolean
// stop() : Boolean
// pause() : Boolean
// resume() : Boolean
// skipTo(index:Number) : Boolean
/**
* Returns the currently-playing SequenceStepCA.
* @return The currently-playing SequenceStepCA.
* @see #getStepAt()
* @see #getStepByID()
* @see #steps
* @see #lastStep
*/
public function get currentStep() : SequenceStepCA {
return (super._getCurrentStep() as SequenceStepCA);
}
/**
* Returns the final SequenceStepCA in the current sequence.
* @return The final SequenceStepCA in the current sequence.
* @see #getStepAt()
* @see #getStepByID()
* @see #steps
* @see #currentStep
*/
public function get lastStep() : SequenceStepCA {
return (super._getLastStep() as SequenceStepCA);
}
// -== Protected Properties ==-
/**
* @private
*/
protected var _trailingSteps : SequenceStep;
// -== Public Methods ==-
/**
* Constructor.
*
* @param items Any number of IPlayable instances (e.g. LinearGo,
PlayableGroup,
* SequenceStepCA) as separate arguments, or a single array of them.
*/
public function SequenceCA(...items) {
super((items[ 0 ] is Array) ? items[ 0 ] : items);
}
/**
* Retrieves any SequenceStepCA from the steps array.
* @param index An array index starting at 0.
* @return The SequenceStepCA instance at this index.
* @see #getStepByID()
*/
public function getStepAt(index:int) : SequenceStepCA {
return (super._getStepAt(index) as SequenceStepCA);
}
/**
* Locates a step with the specified playableID. To search within a step
for a
* child by playableID, use the step instance's <code>getChildByID</code>
method.
*
* @param playableID The step instance's playableID to search for.
* @return The SequenceStepCA with the matching playableID.
*/
public function getStepByID(playableID:*) : SequenceStepCA {
return (super._getStepByID(playableID) as SequenceStepCA);
}
/**
* Adds a single SequenceStepCA or IPlayable instance (LinearGo,
PlayableGroup,
* etc.) to the end of the steps array, or optionally adds the instance
into the
* last SequenceStepCA instead of adding it as a new step. Calling this
* method stops any sequence play currently in progress.
*
* <p>To remove a step use the <code>removeStepAt</code> method.</p>
*
* @param item The playable item to add to the sequence. Note
* that when new steps are added, any IPlayable
* instance of a type other than SequenceStepCA is
* automatically wrapped in a new SequenceStepCA.
*
* @param addToLastStep If true is passed the item is added to the last
* existing SequenceStepCA in the steps array. This
* option should be used with individual items that
* you want added as children to the SequenceStepCA.
* If there are no steps yet this option ignored and
* a new step is created.
*
* @return Item added.
*/
public function addStep(item:IPlayable, addToLastStep:Boolean=false):
IPlayable {
return (super._addStep(item, addToLastStep, SequenceStepCA));
}
/**
* Adds a single SequenceStepCA or IPlayable instance (LinearGo,
PlayableGroup,
* etc.) at a specific index in the steps array. Calling this method
stops any
* sequence play currently in progress.
*
* @param item The playable item to splice into the sequence.
*
* @param index Position in the array starting at 0, or a negative
* index like Array.splice.
*
* @return Item added.
*/
public function addStepAt(item:IPlayable, index:int): IPlayable {
return (super._addStepAt(index, item, SequenceStepCA));
}
/**
* Removes and returns the SequenceStepCA at a specific index from the
steps
* array. Calling this method stops any sequence play currently in
progress.
*
* @param index Position in the array starting at 0, or a negative
* index like Array.splice.
*
* @return The SequenceStepCA instance removed from the steps array.
*/
public function removeStepAt(index:int): SequenceStepCA {
return (super._removeStepAt(index) as SequenceStepCA);
}
// -== IPlayable implementation ==-
/**
* Begins a sequence.
*
* <p>If the group is active when this method is called, a
<code>stop</code> call
* is automated which will result in a GoEvent.STOP event being
dispatched.</p>
*
* @return Returns true unless there are no steps in the sequence.
*/
override public function start() : Boolean {
return super.start();
}
/**
* Stops all activity and dispatches a GoEvent.STOP event.
*
* @return Returns true unless sequence was already stopped.
*/
override public function stop() : Boolean {
if (super.stop()==false)
return false;
initTrailingSteps(false);
return true;
}
/**
* Pauses sequence play.
*
* @return Returns true unless sequence was unable to pause any children.
*/
override public function pause() : Boolean {
var success:Boolean = super.pause();
if (_trailingSteps!=null) {
_trailingSteps.pause();
if (_trailingSteps.state==PlayStates.PAUSED) {
_state = PlayStates.PAUSED;
success = true;
}
}
return success;
}
/**
* Resumes previously-paused sequence play.
*
* @return Returns true unless sequence was unable to resume any
children.
*/
override public function resume() : Boolean {
var success:Boolean = super.resume();
if (_trailingSteps!=null) {
_trailingSteps.resume();
if (_trailingSteps.state==PlayStates.PLAYING) {
_state = PlayStates.PLAYING;
success = true;
}
}
return success;
}
/**
* Stops current activity and skips to another step by sequence index.
*
* @return Always returns true since the index is normalized to the
sequence.
*/
override public function skipTo(index : Number) : Boolean {
if (_steps.length==0)
return false;
initTrailingSteps(false);
return super.skipTo(index);
}
// -== Protected Methods ==-
/**
* @private
* Internal handler for item completion.
* @param event SequenceEvent dispatched by child item.
*/
override protected function onStepEvent(event : Event) : void {
// A stop() call to the sequence results in step dispatching STOP, which
would recurse here.
if (_state==PlayStates.STOPPED)
return;
// trailing item
if (_trailingSteps!=null && event.target==_trailingSteps &&
event.type==SequenceEvent.ADVANCE) {
initTrailingSteps(false);
if (_steps.length-_index==1) {
if (lastStep.state==PlayStates.STOPPED) {
// A completed sequence was waiting for trailing steps to finish.
// Otherwise, trailing items have finished before sequence ended so
no action should be taken.
complete();
}
else {
// Special case where advance already fired but trailing steps have
all completed: use COMPLETE
lastStep.addEventListener(GoEvent.COMPLETE, onStepEvent);
}
}
return;
}
// Finishes special case in trailing item block. Also, returns out if
we're waiting
if (lastStep.hasEventListener(GoEvent.COMPLETE)) {
if (event.type==GoEvent.COMPLETE) {
initTrailingSteps(false); // _trailingSteps is null, this is to remove
the COMPLETE listener.
complete();
}
return;
}
super.onStepEvent(event);
}
/**
* @private
* Internal handler for step advance.
*/
override protected function advance() : void {
if (currentStep.listenerCount > 0) {
initTrailingSteps(true);
_trailingSteps.addPlayingChildAndStart(currentStep);
}
super.advance();
}
/**
* @private
* Internal handler for group completion.
*/
override protected function complete() : void {
if (_trailingSteps==null) {
super.complete();
}
}
/**
* @private
* Internal setup for tracking items that are continuing to run after a
custom advance.
* @param active Whether to create or destroy the trailing-steps group.
*/
protected function initTrailingSteps(active:Boolean):void {
if (_trailingSteps==null && active) {
_trailingSteps = new SequenceStep();
_trailingSteps.playableID += "(_trailingSteps for
sequence:"+playableID+")";
_trailingSteps.addEventListener(SequenceEvent.ADVANCE, onStepEvent);
}
else if (!active) {
lastStep.removeEventListener(GoEvent.COMPLETE, onStepEvent); // Remove
special case set in onStepEvent.
if (_trailingSteps!=null) {
_trailingSteps.removeEventListener(SequenceEvent.ADVANCE, onStepEvent);
_trailingSteps.stop();
_trailingSteps = null;
}
}
}
}
}
\ No newline at end of file
More information about the GoList
mailing list