Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial flash.events.IEventDispatcher implementation #394

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions starling/src/starling/display/DisplayObject.as
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ package starling.display
// part of the stage, (b) it must not cause memory leaks when the user forgets to call
// dispose and (c) there might be multiple listeners for this event.

public override function addEventListener(type:String, listener:Function):void
public override function addEventListener(type:String, listener:Function, notSupported:Boolean = false, notSupported2:int = 0, notSupported3:Boolean = false):void
{
if (type == Event.ENTER_FRAME && !hasEventListener(type))
{
Expand All @@ -403,7 +403,7 @@ package starling.display
super.addEventListener(type, listener);
}

public override function removeEventListener(type:String, listener:Function):void
public override function removeEventListener(type:String, listener:Function, notSupported:Boolean = false):void
{
super.removeEventListener(type, listener);

Expand Down
2 changes: 1 addition & 1 deletion starling/src/starling/display/DisplayObjectContainer.as
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ package starling.display
* The method uses an internal pool of event objects to avoid allocations. */
public function broadcastEventWith(type:String, data:Object=null):void
{
var event:Event = Event.fromPool(type, false, data);
var event:Event = Event.fromPool(type, false, data, false);
broadcastEvent(event);
Event.toPool(event);
}
Expand Down
2 changes: 1 addition & 1 deletion starling/src/starling/events/EnterFrameEvent.as
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ package starling.events
/** Creates an enter frame event with the passed time. */
public function EnterFrameEvent(type:String, passedTime:Number, bubbles:Boolean=false)
{
super(type, bubbles, passedTime);
super(type, bubbles, passedTime, false);
}

/** The time that has passed since the last frame (in seconds). */
Expand Down
83 changes: 62 additions & 21 deletions starling/src/starling/events/Event.as
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
// =================================================================================================
//
// Starling Framework
// Copyright 2011 Gamua OG. All Rights Reserved.
// Starling Framework
// Copyright 2011 Gamua OG. All Rights Reserved.
//
// This program is free software. You can redistribute and/or modify it
// in accordance with the terms of the accompanying license agreement.
// This program is free software. You can redistribute and/or modify it
// in accordance with the terms of the accompanying license agreement.
//
// =================================================================================================

package starling.events
{
import flash.events.Event;
import flash.events.EventPhase;
import flash.utils.getQualifiedClassName;

import starling.core.starling_internal;
import starling.utils.formatString;

use namespace starling_internal;

[Exclude(name="clone",kind="method")]

/** Event objects are passed as parameters to event listeners when an event occurs.
* This is Starling's version of the Flash Event class.
*
Expand All @@ -35,7 +39,7 @@ package starling.events
*
* @see EventDispatcher
*/
public class Event
public class Event extends flash.events.Event
{
/** Event type for a display object that is added to a parent. */
public static const ADDED:String = "added";
Expand Down Expand Up @@ -77,7 +81,7 @@ package starling.events
/** An event type to be utilized in custom events. Not used by Starling right now. */
public static const SELECT:String = "select";

private static var sEventPool:Vector.<Event> = new <Event>[];
private static var sEventPool:Vector.<starling.events.Event>;

private var mTarget:EventDispatcher;
private var mCurrentTarget:EventDispatcher;
Expand All @@ -86,45 +90,75 @@ package starling.events
private var mStopsPropagation:Boolean;
private var mStopsImmediatePropagation:Boolean;
private var mData:Object;
private var mEventPhase:uint = EventPhase.AT_TARGET;
private var mCancelable:Boolean;
private var mIsDefaultPrevented:Boolean;

/** Creates an event object that can be passed to listeners. */
public function Event(type:String, bubbles:Boolean=false, data:Object=null)
public function Event(type:String, bubbles:Boolean=false, data:Object=null, cancelable:Boolean=false)
{
super(type, bubbles, false);
mType = type;
mBubbles = bubbles;
mData = data;
mCancelable = cancelable;
}

/** Prevents listeners at the next bubble stage from receiving the event. */
public function stopPropagation():void
override public function stopPropagation():void
{
mStopsPropagation = true;
}

/** Prevents any other listeners from receiving the event. */
public function stopImmediatePropagation():void
override public function stopImmediatePropagation():void
{
mStopsPropagation = mStopsImmediatePropagation = true;
}

/** Prevents the default behavior if the event is cancelable. */
override public function preventDefault():void
{
if (!mCancelable)
{
return;
}
mIsDefaultPrevented = true;
}

/** Indicates if the event has been cancelled. */
override public function isDefaultPrevented():Boolean { return mIsDefaultPrevented; }

/** Clones the event instance. */
override public function clone():flash.events.Event
{
return new starling.events.Event(mType, mBubbles, mData, mCancelable );
}

/** Returns a description of the event, containing type and bubble information. */
public function toString():String
override public function toString():String
{
return formatString("[{0} type=\"{1}\" bubbles={2}]",
getQualifiedClassName(this).split("::").pop(), mType, mBubbles);
}

/** Indicates if event will bubble. */
public function get bubbles():Boolean { return mBubbles; }
override public function get bubbles():Boolean { return mBubbles; }

/** Indicates if the event may be canceled. */
override public function get cancelable():Boolean { return mCancelable; }

/** Indicates if the event is being dispatched by its target or if the event is bubbling. */
override public function get eventPhase():uint { return mEventPhase; }

/** The object that dispatched the event. */
public function get target():EventDispatcher { return mTarget; }
override public function get target():Object { return mTarget; }

/** The object the event is currently bubbling at. */
public function get currentTarget():EventDispatcher { return mCurrentTarget; }
override public function get currentTarget():Object { return mCurrentTarget; }

/** A string that identifies the event. */
public function get type():String { return mType; }
override public function get type():String { return mType; }

/** Arbitrary data that is attached to the event. */
public function get data():Object { return mData; }
Expand All @@ -145,31 +179,38 @@ package starling.events

/** @private */
internal function get stopsImmediatePropagation():Boolean { return mStopsImmediatePropagation; }

/** @private */
internal function setEventPhase(value:uint):void { mEventPhase = value; }

// event pooling

/** @private */
starling_internal static function fromPool(type:String, bubbles:Boolean=false, data:Object=null):Event
starling_internal static function fromPool(type:String, bubbles:Boolean=false, data:Object=null, cancelable:Boolean=false):starling.events.Event
{
if (sEventPool.length) return sEventPool.pop().reset(type, bubbles, data);
else return new Event(type, bubbles, data);
if (!sEventPool) sEventPool = new <starling.events.Event>[];
if (sEventPool.length) return sEventPool.pop().reset(type, bubbles, data, cancelable);
else return new starling.events.Event(type, bubbles, data);
}

/** @private */
starling_internal static function toPool(event:Event):void
starling_internal static function toPool(event:starling.events.Event):void
{
event.mData = event.mTarget = event.mCurrentTarget = null;
sEventPool[sEventPool.length] = event; // avoiding 'push'
}

/** @private */
starling_internal function reset(type:String, bubbles:Boolean=false, data:Object=null):Event
starling_internal function reset(type:String, bubbles:Boolean=false, data:Object=null, cancelable:Boolean=false):starling.events.Event
{
mType = type;
mBubbles = bubbles;
mData = data;
mCancelable = cancelable;
mTarget = mCurrentTarget = null;
mStopsPropagation = mStopsImmediatePropagation = false;
mEventPhase = EventPhase.AT_TARGET;
mIsDefaultPrevented = false;
return this;
}
}
Expand Down
95 changes: 68 additions & 27 deletions starling/src/starling/events/EventDispatcher.as
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// =================================================================================================
//
// Starling Framework
// Copyright 2011 Gamua OG. All Rights Reserved.
// Starling Framework
// Copyright 2011 Gamua OG. All Rights Reserved.
//
// This program is free software. You can redistribute and/or modify it
// in accordance with the terms of the accompanying license agreement.
// This program is free software. You can redistribute and/or modify it
// in accordance with the terms of the accompanying license agreement.
//
// =================================================================================================

package starling.events
{
import flash.events.EventPhase;
import flash.events.IEventDispatcher;
import flash.utils.Dictionary;

import starling.core.starling_internal;
Expand All @@ -35,7 +37,7 @@ package starling.events
* @see Event
* @see starling.display.DisplayObject DisplayObject
*/
public class EventDispatcher
public class EventDispatcher implements IEventDispatcher
{
private var mEventListeners:Dictionary;

Expand All @@ -47,7 +49,7 @@ package starling.events
{ }

/** Registers an event listener at a certain object. */
public function addEventListener(type:String, listener:Function):void
public function addEventListener(type:String, listener:Function, notSupported:Boolean = false, notSupported2:int = 0, notSupported3:Boolean = false):void
{
if (mEventListeners == null)
mEventListeners = new Dictionary();
Expand All @@ -60,7 +62,7 @@ package starling.events
}

/** Removes an event listener from the object. */
public function removeEventListener(type:String, listener:Function):void
public function removeEventListener(type:String, listener:Function, notSupported:Boolean = false):void
{
if (mEventListeners)
{
Expand Down Expand Up @@ -95,30 +97,60 @@ package starling.events
* If an event with enabled 'bubble' property is dispatched to a display object, it will
* travel up along the line of parents, until it either hits the root object or someone
* stops its propagation manually. */
public function dispatchEvent(event:Event):void
public function dispatchEvent(event:flash.events.Event):Boolean
{
var starlingEvent:starling.events.Event = event as starling.events.Event;
if(!starlingEvent)
{
throw new ArgumentError("Starling events must be of type starling.events.Event");
}
var bubbles:Boolean = event.bubbles;

if (!bubbles && (mEventListeners == null || !(event.type in mEventListeners)))
return; // no need to do anything
if (!bubbles && (mEventListeners == null || !(starlingEvent.type in mEventListeners)))
return false; // no need to do anything

// we save the current target and restore it later;
// this allows users to re-dispatch events without creating a clone.

var previousTarget:EventDispatcher = event.target;
event.setTarget(this);
var previousTarget:EventDispatcher = EventDispatcher(starlingEvent.target);
starlingEvent.setTarget(this);

if (bubbles && this is DisplayObject) bubbleEvent(event);
else invokeEvent(event);
if (bubbles && this is DisplayObject) bubbleEvent(starlingEvent);
else
{
starlingEvent.setEventPhase(EventPhase.AT_TARGET);
invokeEvent(starlingEvent);
}

if (previousTarget) event.setTarget(previousTarget);
if (previousTarget) starlingEvent.setTarget(previousTarget);
return event.isDefaultPrevented();
}

/** Returns if there are listeners registered for a certain event type on this object or
* on any objects that an event of the specified type can bubble to. */
public function willTrigger(type:String):Boolean
{
var element:DisplayObject = this as DisplayObject;
if(!element)
{
return this.hasEventListener(type);
}
do
{
if(element.hasEventListener(type))
{
return true;
}
}
while ((element = element.parent) != null)
return false;
}

/** @private
* Invokes an event on the current object. This method does not do any bubbling, nor
* does it back-up and restore the previous target on the event. The 'dispatchEvent'
* method uses this method internally. */
internal function invokeEvent(event:Event):Boolean
internal function invokeEvent(event:starling.events.Event):Boolean
{
var listeners:Vector.<Function> = mEventListeners ?
mEventListeners[event.type] as Vector.<Function> : null;
Expand Down Expand Up @@ -154,42 +186,51 @@ package starling.events
}

/** @private */
internal function bubbleEvent(event:Event):void
internal function bubbleEvent(event:starling.events.Event):void
{
// we determine the bubble chain before starting to invoke the listeners.
// that way, changes done by the listeners won't affect the bubble chain.

var chain:Vector.<EventDispatcher>;
var element:DisplayObject = this as DisplayObject;
var length:int = 1;

if (sBubbleChains.length > 0) { chain = sBubbleChains.pop(); chain[0] = element; }
else chain = new <EventDispatcher>[element];

var length:int = 0;

event.setEventPhase(EventPhase.AT_TARGET);
var stopPropagation:Boolean = element.invokeEvent(event);
if (stopPropagation)
{
return;
}
if (sBubbleChains.length > 0) { chain = sBubbleChains.pop(); }
else chain = new <EventDispatcher>[];

while ((element = element.parent) != null)
chain[int(length++)] = element;

event.setEventPhase(EventPhase.BUBBLING_PHASE);
for (var i:int=0; i<length; ++i)
{
var stopPropagation:Boolean = chain[i].invokeEvent(event);
stopPropagation = chain[i].invokeEvent(event);
if (stopPropagation) break;
}

chain.length = 0;
sBubbleChains.push(chain);
}

/** Dispatches an event with the given parameters to all objects that have registered
* listeners for the given type. The method uses an internal pool of event objects to
* avoid allocations. */
public function dispatchEventWith(type:String, bubbles:Boolean=false, data:Object=null):void
public function dispatchEventWith(type:String, bubbles:Boolean=false, data:Object=null, cancelable:Boolean=false):Boolean
{
if (bubbles || hasEventListener(type))
{
var event:Event = Event.fromPool(type, bubbles, data);
dispatchEvent(event);
var event:starling.events.Event = Event.fromPool(type, bubbles, data, cancelable);
var result:Boolean = dispatchEvent(event);
Event.toPool(event);
return result;
}
return false;
}

/** Returns if there are listeners registered for a certain event type. */
Expand Down
Loading