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: * * * * ButtonEventHandler uses onEnterFrame and hitTest to determine what events are fired and * when. This allows it to bypass the restriction of normal button event handling, however, * because of this, it is also more CPU intensive than normal button events. * Some differences between using ButtonEventHandler and normal button event handers: * * * To enable a movie clip to receive events from ButtonEventHandler, you must first initialize it with * ButtonEventHandler.initialize (note that movie clips with child clips that have already been initialized * will automatically be initialized themselves). The initialize method returns a ButtonEvent instance which is * used to handle events sent managed by ButtonEventHandler. Using that instance's addEventListener method, * you can register objects to receive events detected by ButtonEventHandler relating to the movie clip * initialized. The ButtonEvent object returned from initialization is automatically set as a * listener to itself (and each event recognized by ButtonEventHandler). The event object passed to * listeners for those events will be the respective ButtonEvent instance. * @author Trevor McCauley * @link http://www.senocular.com * @version 0.9.7 * @requires com.senocular.events.ButtonEvent * @usage myButtonEvent:ButtonEvent = ButtonEventHandler.initialize(movie:MovieClip); * @example
 * // 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