Permalink
Fetching contributors…
Cannot retrieve contributors at this time
231 lines (212 sloc) 8.74 KB
package feathers.utils.touch
{
import feathers.controls.LayoutGroup;
import feathers.events.ExclusiveTouch;
import flash.geom.Point;
import starling.display.DisplayObject;
import starling.display.Sprite;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.events.TouchPhase;
import starling.utils.Pool;
/**
* A modified version of TouchSheet for Feathers.
*/
public class TouchSheet extends LayoutGroup
{
public static const MOVE:String = "move";
public static const ZOOM:String = "zoom";
public static const ROTATE:String = "rotate";
public function TouchSheet(contents:DisplayObject=null)
{
addEventListener(TouchEvent.TOUCH, onTouch);
useHandCursor = true;
if (contents)
{
contents.x = int(contents.width / -2);
contents.y = int(contents.height / -2);
addChild(contents);
}
}
public var moveEnabled:Boolean = true;
public var rotateEnabled:Boolean = true;
public var zoomEnabled:Boolean = true;
public var bringToFrontEnabled:Boolean = true;
protected var touchAID:int = -1;
protected var touchBID:int = -1;
private function onTouch(event:TouchEvent):void
{
var exclusiveTouch:ExclusiveTouch = ExclusiveTouch.forStage(this.stage);
//first check if the existing touches ended
if(touchBID != -1)
{
var touchB:Touch = event.getTouch(this, null, touchBID);
if(touchB !== null)
{
if(touchB.phase === TouchPhase.ENDED)
{
touchBID = -1;
}
else
{
//if the touch has been claimed since we first started
//watching it, we can no longer use it
var claim:DisplayObject = exclusiveTouch.getClaim(touchBID);
if(claim !== null && claim !== this)
{
touchBID = -1;
}
}
}
}
//we checeked touch b first because a might be replaced by b
if(touchAID != -1)
{
var touchA:Touch = event.getTouch(this, null, touchAID);
if(touchA !== null)
{
if(touchA.phase === TouchPhase.ENDED)
{
touchAID = touchBID;
touchBID = -1;
}
else
{
claim = exclusiveTouch.getClaim(touchAID);
if(claim !== null && claim !== this)
{
touchAID = touchBID;
touchBID = -1;
}
}
}
}
//then, check for new touches, if necessary
if(touchAID == -1 || touchBID == -1)
{
var touches:Vector.<Touch> = event.getTouches(this, TouchPhase.BEGAN);
var touchCount:int = touches.length;
for(var i:int = 0; i < touchCount; i++)
{
var touch:Touch = touches[i];
claim = exclusiveTouch.getClaim(touch.id);
if(claim !== null)
{
//this touch is claimed, so we can't use it
continue;
}
if(touchAID == -1)
{
touchAID = touch.id;
if(this.moveEnabled)
{
exclusiveTouch.claimTouch(touchAID, this);
}
}
else if(touchBID == -1)
{
touchBID = touch.id;
//if we've found both touches, claim them to stop containers
//from scrolling
exclusiveTouch.claimTouch(touchAID, this);
exclusiveTouch.claimTouch(touchBID, this);
}
}
}
//do a multi-touch gesture if we have enough touches
if(touchAID != -1 && touchBID != -1)
{
// two fingers touching -> rotate and scale
touchA = event.getTouch(this, null, touchAID);
touchB = event.getTouch(this, null, touchBID);
if(touchA.phase !== TouchPhase.MOVED && touchB.phase !== TouchPhase.MOVED)
{
//neither touch moved, so nothing has changed
return;
}
// updated to use stage instead of parent because the
// parent might move, but the stage never will. -JT
var currentPosA:Point = touchA.getLocation(stage, Pool.getPoint());
var previousPosA:Point = touchA.getPreviousLocation(stage, Pool.getPoint());
var currentPosB:Point = touchB.getLocation(stage, Pool.getPoint());
var previousPosB:Point = touchB.getPreviousLocation(stage, Pool.getPoint());
var currentVector:Point = currentPosA.subtract(currentPosB);
var previousVector:Point = previousPosA.subtract(previousPosB);
var currentAngle:Number = Math.atan2(currentVector.y, currentVector.x);
var previousAngle:Number = Math.atan2(previousVector.y, previousVector.x);
var deltaAngle:Number = currentAngle - previousAngle;
// update pivot point based on previous center
var point:Point = Pool.getPoint(
(previousPosA.x + previousPosB.x) * 0.5,
(previousPosA.y + previousPosB.y) * 0.5);
globalToLocal(point, point);
pivotX = point.x;
pivotY = point.y;
// update location based on the current center
point.setTo(
(currentPosA.x + currentPosB.x) * 0.5,
(currentPosA.y + currentPosB.y) * 0.5);
parent.globalToLocal(point, point);
x = point.x;
y = point.y;
Pool.putPoint(point);
Pool.putPoint(currentPosA);
Pool.putPoint(previousPosA);
Pool.putPoint(currentPosB);
Pool.putPoint(previousPosB);
if (rotateEnabled && deltaAngle != 0)
{
rotation += deltaAngle;
dispatchEventWith(ROTATE);
}
var sizeDiff:Number = currentVector.length / previousVector.length;
if (zoomEnabled && sizeDiff !== 1)
{
var zoomed:Boolean = false;
var newScaleX:Number = scaleX * sizeDiff;
if(scaleX !== newScaleX)
{
scaleX = newScaleX;
zoomed = true;
}
var newScaleY:Number = scaleY * sizeDiff;
if(scaleY !== newScaleY)
{
scaleY = newScaleY;
zoomed = true;
}
if(zoomed)
{
dispatchEventWith(ZOOM);
}
}
}
else if(touchAID != -1) //single touch gesture
{
touchA = event.getTouch(this, null, touchAID);
if (moveEnabled)
{
// one finger touching -> move
// updated to use stage instead of parent because the
// parent might move, but the stage won't -JT
var delta:Point = touchA.getMovement(stage, Pool.getPoint());
if(delta.length != 0)
{
x += delta.x;
y += delta.y;
dispatchEventWith(MOVE);
}
Pool.putPoint(delta);
}
}
var touchEnded:Touch = event.getTouch(this, TouchPhase.ENDED);
if (touchEnded)
{
if (bringToFrontEnabled && touchEnded.tapCount == 2)
{
parent.addChild(this); // bring self to front
}
}
}
}
}