import com.senocular.events.ButtonEvent; /** * The ButtonEventHandler class allows for timeline-based instances * (MovieClips) to receive button events and allows for those events to * bubble up to parent clips. This is contrary to normal button event * behavior (Buttons and MovieClips) which starts at the parent clip, or the * first parent clip with any kind of button event assigned to it, and prevents * any child clips from receiving any button events at all. * A list of all supported events are as follows: * *
* // Example 1: Using a basic event handler from a ButtonEvent object
* var my_mcEvent:ButtonEvent = ButtonEventHandler.initialize(my_mc);
* my_mcEvent.onPress = function(event:ButtonEvent){
* // my_mc.gotoAndStop("_down");
* event.target.gotoAndStop("_down");
* // optional; prevents onPress from being called for parents
* event.stopPropagation();
* }
*
* // Example 2: Using handleEvent with an initialized instance
* // (this can also be used on a ButtonEvent object)
* ButtonEventHandler.initialize(my_mc);
* my_mc.handleEvent = function(event:ButtonEvent){
* switch(event.type){
* case "onPress":
* // my_mc.gotoAndStop("_down");
* this.gotoAndStop("_down");
* // optional; prevents onPress from being called for parents
* event.stopPropagation();
* break;
* case "onRelease":
* // my_mc.gotoAndStop("_up");
* this.gotoAndStop("_up");
* break;
* }
* }
*
* Note that handleEvent can also be used with my_mc's associated ButtonEvent instance,
* though be cautious of the fact that the scope of the function would change from that
* of the movie clip to that of the ButtonEvent instance.
*/
class com.senocular.events.ButtonEventHandler {
// VARIABLES
// public variables
/**
* Determines whether or not arrangement for handled movie clips
* is automatically updated every frame. If depths are altered for
* movie clips receiving events, this should be kept false.
* @usage ButtonEventHandler.autoUpdateArrangement = value:Boolean
*/
public static var autoUpdateArrangement:Boolean = false;
/**
* Determines whether or not overlapping prevents events for objects in
* the same timeline (no parent/child relationships) from triggering. If
* true, the behavior is like that of normal Flash buttons where buttons
* above other buttons, prevent the buttons below from receiving events.
* @usage ButtonEventHandler.overlapBlocksEvents = value:Boolean
* @see autoUpdateArrangement
*/
public static var overlapBlocksEvents:Boolean = true;
// private variables
private static var isMouseDown:Boolean = false;
private static var children:Array = new Array();
private static var stoppedOverlapping:Object = null;
private static var stoppedEvents:Object = new Object();
private static var currentTargetEvents:Object = new Object();
// METHODS
// public methods
/**
* Initializes a target timeline instance (MovieClip) to be registered for receiving events
* from the ButtonEventHandler class. When initialized, the target as well as all its parents are
* initialized too, if not already. The returned ButtonEvent object can be used to handle
* received events.
* @usage event:ButtonEvent = ButtonEventHandler.initialize(target:MovieClip);
* @param target Movie clip which is to receive events from
* ButtonEventHandler. This movie clip needs to be detectable with hitTest.
* @return ButtonEvent object associated with the target movie clip passed. This is the same
* object sent to event handlers when they are called.
*/
public static function initialize(target:Object):ButtonEvent {
var foundObject:Object = findInstance("target", target);
if (foundObject) return foundObject.instance;
var instance:ButtonEvent = new ButtonEvent(target);
if (target._parent){
var parentInstance:ButtonEvent = getEventObject(target._parent);
parentInstance.children.push(instance);
}else{
children.push(instance);
}
updateArrangement();
return instance;
}
/**
* Removes the target movie clip from initialization preventing from receiving further events
* from ButtonEventHandler. Any child movie clips are removed along with target.
* @usage success:Boolean = ButtonEventHandler.initialize(target:MovieClip);
* @param target Movie clip which is to be removed from receiving events from
* ButtonEventHandler.
* @return True or false depending on whether or not the removal was successful.
*/
public static function uninitialize(target:Object):Boolean {
var foundObject:Object = findInstance("target", target);
if (foundObject){
foundObject.instances.splice(foundObject.index, 1);
return true;
}
return false;
}
/**
* Returns an event object associated with the target movie clip. If no ButtonEvent is associated with
* the target, the target will be initialized and a new ButtonEvent object will be created and returned.
* @usage event:ButtonEvent = ButtonEventHandler.getEventObject(movie:MovieClip);
* @param target Movie clip to get a ButtonEvent object for
* @return ButtonEvent object associated with the target movie clip passed. This is the same
* object sent to event handlers when they are called.
*/
public static function getEventObject(target:Object):ButtonEvent {
return initialize(target);
}
/**
* Updates the arrangement and precedence of movie clips handled by
* ButtonEventHandler. This will automatically be called every frame
* if autoUpdateArrangement is true. You would only need to call this if
* autoUpdateArrangement is false and you've altered the depths of any movie clips
* receiving events from ButtonEventHandler.
* @usage ButtonEventHandler.updateArrangement();
* @param instances Optional parameter specifying which movie clips are
* to be arranged. Only used internally within the class.
* @see autoUpdateArrangement
*/
public static function updateArrangement(instances:Array):Void {
if (instances == undefined) instances = children;
var n:Number = instances.length;
var i:Number;
var instance:ButtonEvent;
for (i=0; i