mirror of
https://github.com/scratchfoundation/Gestouch.git
synced 2024-11-27 09:45:38 -05:00
Experimental requireGestureToFail API implemented
This commit is contained in:
parent
4e02d4ae63
commit
2efa95b85c
5 changed files with 163 additions and 13 deletions
|
@ -14,6 +14,7 @@ package org.gestouch.gestures
|
||||||
import flash.events.EventDispatcher;
|
import flash.events.EventDispatcher;
|
||||||
import flash.geom.Point;
|
import flash.geom.Point;
|
||||||
import flash.system.Capabilities;
|
import flash.system.Capabilities;
|
||||||
|
import flash.utils.Dictionary;
|
||||||
|
|
||||||
|
|
||||||
[Event(name="stateChange", type="org.gestouch.events.GestureStateEvent")]
|
[Event(name="stateChange", type="org.gestouch.events.GestureStateEvent")]
|
||||||
|
@ -46,6 +47,12 @@ package org.gestouch.gestures
|
||||||
protected var _touchesMap:Object = {};
|
protected var _touchesMap:Object = {};
|
||||||
protected var _centralPoint:Point = new Point();
|
protected var _centralPoint:Point = new Point();
|
||||||
protected var _localLocation:Point;
|
protected var _localLocation:Point;
|
||||||
|
/**
|
||||||
|
* List of gesture we require to fail.
|
||||||
|
* @see requireGestureToFail()
|
||||||
|
*/
|
||||||
|
protected var _gesturesToFail:Dictionary = new Dictionary(true);
|
||||||
|
protected var _pendingRecognizedState:uint;
|
||||||
|
|
||||||
|
|
||||||
public function Gesture(target:InteractiveObject = null)
|
public function Gesture(target:InteractiveObject = null)
|
||||||
|
@ -177,12 +184,19 @@ package org.gestouch.gestures
|
||||||
*/
|
*/
|
||||||
public function reset():void
|
public function reset():void
|
||||||
{
|
{
|
||||||
//TODO
|
//FIXME: proper state change?
|
||||||
_location.x = 0;
|
_location.x = 0;
|
||||||
_location.y = 0;
|
_location.y = 0;
|
||||||
_touchesMap = {};
|
_touchesMap = {};
|
||||||
_touchesCount = 0;
|
_touchesCount = 0;
|
||||||
|
|
||||||
|
for (var key:* in _gesturesToFail)
|
||||||
|
{
|
||||||
|
var gestureToFail:Gesture = key as Gesture;
|
||||||
|
gestureToFail.removeEventListener(GestureStateEvent.STATE_CHANGE, gestureToFail_stateChangeHandler);
|
||||||
|
}
|
||||||
|
_pendingRecognizedState = 0;
|
||||||
|
|
||||||
setState(GestureState.IDLE);
|
setState(GestureState.IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +211,7 @@ package org.gestouch.gestures
|
||||||
//TODO
|
//TODO
|
||||||
reset();
|
reset();
|
||||||
target = null;
|
target = null;
|
||||||
|
_gesturesToFail = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -212,9 +227,13 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>NB! Current implementation is highly experimental!</b> See examples for more info.
|
||||||
|
*/
|
||||||
public function requireGestureToFail(gesture:Gesture):void
|
public function requireGestureToFail(gesture:Gesture):void
|
||||||
{
|
{
|
||||||
//TODO
|
//TODO
|
||||||
|
_gesturesToFail[gesture] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -319,6 +338,39 @@ package org.gestouch.gestures
|
||||||
|
|
||||||
if (newState == GestureState.BEGAN || newState == GestureState.RECOGNIZED)
|
if (newState == GestureState.BEGAN || newState == GestureState.RECOGNIZED)
|
||||||
{
|
{
|
||||||
|
var gestureToFail:Gesture;
|
||||||
|
// first we check if other required-to-fail gestures recognized
|
||||||
|
// TODO: is this really necessary? using "requireGestureToFail" API assume that
|
||||||
|
// required-to-fail gesture always recognizes AFTER this one.
|
||||||
|
for (var key:* in _gesturesToFail)
|
||||||
|
{
|
||||||
|
gestureToFail = key as Gesture;
|
||||||
|
if (gestureToFail.state != GestureState.IDLE && gestureToFail.state != GestureState.POSSIBLE
|
||||||
|
&& gestureToFail.state != GestureState.FAILED)
|
||||||
|
{
|
||||||
|
// Looks like other gesture won't fail,
|
||||||
|
// which means the required condition will not happen, so we must fail
|
||||||
|
setState(GestureState.FAILED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// then we check of other required-to-fail gestures are actually tracked (not IDLE)
|
||||||
|
// and not still not recognized (e.g. POSSIBLE state)
|
||||||
|
for (key in _gesturesToFail)
|
||||||
|
{
|
||||||
|
gestureToFail = key as Gesture;
|
||||||
|
if (gestureToFail.state == GestureState.POSSIBLE)
|
||||||
|
{
|
||||||
|
// Other gesture might fail soon, so we postpone state change
|
||||||
|
_pendingRecognizedState = newState;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// else if gesture is in IDLE state it means it doesn't track anything,
|
||||||
|
// so we simply ignore it as it doesn't seem like conflict from this perspective
|
||||||
|
// (perspective of using "requireGestureToFail" API)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (delegate && !delegate.gestureShouldBegin(this))
|
if (delegate && !delegate.gestureShouldBegin(this))
|
||||||
{
|
{
|
||||||
setState(GestureState.FAILED);
|
setState(GestureState.FAILED);
|
||||||
|
@ -381,6 +433,17 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executed once requiredToFail gestures have been failed and
|
||||||
|
* pending (delayed) recognized state has been entered.
|
||||||
|
* You must dispatch gesture event here.
|
||||||
|
*/
|
||||||
|
protected function onDelayedRecognize():void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
@ -398,6 +461,12 @@ package org.gestouch.gestures
|
||||||
|
|
||||||
if (_touchesCount == 1 && state == GestureState.IDLE)
|
if (_touchesCount == 1 && state == GestureState.IDLE)
|
||||||
{
|
{
|
||||||
|
for (var key:* in _gesturesToFail)
|
||||||
|
{
|
||||||
|
var gestureToFail:Gesture = key as Gesture;
|
||||||
|
gestureToFail.addEventListener(GestureStateEvent.STATE_CHANGE, gestureToFail_stateChangeHandler, false, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
setState(GestureState.POSSIBLE);
|
setState(GestureState.POSSIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,5 +486,37 @@ package org.gestouch.gestures
|
||||||
|
|
||||||
onTouchEnd(touch);
|
onTouchEnd(touch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function gestureToFail_stateChangeHandler(event:GestureStateEvent):void
|
||||||
|
{
|
||||||
|
if (state != GestureState.POSSIBLE)
|
||||||
|
return;//just in case..FIXME?
|
||||||
|
|
||||||
|
if (!_pendingRecognizedState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event.newState == GestureState.FAILED)
|
||||||
|
{
|
||||||
|
for (var key:* in _gesturesToFail)
|
||||||
|
{
|
||||||
|
var gestureToFail:Gesture = key as Gesture;
|
||||||
|
if (gestureToFail.state == GestureState.POSSIBLE)
|
||||||
|
{
|
||||||
|
// we're still waiting for some gesture to fail
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setState(_pendingRecognizedState))
|
||||||
|
{
|
||||||
|
onDelayedRecognize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event.newState != GestureState.POSSIBLE)
|
||||||
|
{
|
||||||
|
setState(GestureState.FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -152,6 +152,16 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override protected function onDelayedRecognize():void
|
||||||
|
{
|
||||||
|
if (hasEventListener(LongPressGestureEvent.GESTURE_LONG_PRESS))
|
||||||
|
{
|
||||||
|
dispatchEvent(new LongPressGestureEvent(LongPressGestureEvent.GESTURE_LONG_PRESS, false, false, GestureState.BEGAN,
|
||||||
|
_location.x, _location.y, _localLocation.x, _localLocation.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
|
@ -23,6 +23,9 @@ package org.gestouch.gestures
|
||||||
*/
|
*/
|
||||||
public var direction:uint = PanGestureDirection.NO_DIRECTION;
|
public var direction:uint = PanGestureDirection.NO_DIRECTION;
|
||||||
|
|
||||||
|
protected var _gestureBeginOffsetX:Number;
|
||||||
|
protected var _gestureBeginOffsetY:Number;
|
||||||
|
|
||||||
|
|
||||||
public function PanGesture(target:InteractiveObject = null)
|
public function PanGesture(target:InteractiveObject = null)
|
||||||
{
|
{
|
||||||
|
@ -88,6 +91,15 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override public function reset():void
|
||||||
|
{
|
||||||
|
_gestureBeginOffsetX = NaN;
|
||||||
|
_gestureBeginOffsetY = NaN;
|
||||||
|
|
||||||
|
super.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
|
@ -142,20 +154,14 @@ package org.gestouch.gestures
|
||||||
updateLocation();
|
updateLocation();
|
||||||
offsetX = _location.x - prevLocationX;
|
offsetX = _location.x - prevLocationX;
|
||||||
offsetY = _location.y - prevLocationY;
|
offsetY = _location.y - prevLocationY;
|
||||||
// Unfortunately we create several new point instances here,
|
// acummulate begin offsets for the case when this gesture recognition is delayed by requireGestureToFail
|
||||||
// but thats not a big deal since this code executed only once per recognition session
|
_gestureBeginOffsetX = (_gestureBeginOffsetX != _gestureBeginOffsetX) ? offsetX : _gestureBeginOffsetX + offsetX;
|
||||||
var offset:Point = new Point(offsetX, offsetY);
|
_gestureBeginOffsetY = (_gestureBeginOffsetY != _gestureBeginOffsetY) ? offsetY : _gestureBeginOffsetY + offsetY;
|
||||||
if (offset.length > slop)
|
|
||||||
{
|
|
||||||
var slopVector:Point = offset.clone();
|
|
||||||
slopVector.normalize(slop);
|
|
||||||
offset = offset.subtract(slopVector);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setState(GestureState.BEGAN) && hasEventListener(PanGestureEvent.GESTURE_PAN))
|
if (setState(GestureState.BEGAN) && hasEventListener(PanGestureEvent.GESTURE_PAN))
|
||||||
{
|
{
|
||||||
dispatchEvent(new PanGestureEvent(PanGestureEvent.GESTURE_PAN, false, false, GestureState.BEGAN,
|
dispatchEvent(new PanGestureEvent(PanGestureEvent.GESTURE_PAN, false, false, GestureState.BEGAN,
|
||||||
_location.x, _location.y, _localLocation.x, _localLocation.y, offset.x, offset.y));
|
_location.x, _location.y, _localLocation.x, _localLocation.y, offsetX, offsetY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,5 +204,15 @@ package org.gestouch.gestures
|
||||||
updateLocation();
|
updateLocation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override protected function onDelayedRecognize():void
|
||||||
|
{
|
||||||
|
if (hasEventListener(PanGestureEvent.GESTURE_PAN))
|
||||||
|
{
|
||||||
|
dispatchEvent(new PanGestureEvent(PanGestureEvent.GESTURE_PAN, false, false, GestureState.BEGAN,
|
||||||
|
_location.x, _location.y, _localLocation.x, _localLocation.y, _gestureBeginOffsetX, _gestureBeginOffsetY));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -176,11 +176,12 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
else if (absVelX >= minVelocity && (minOffset != minOffset || absOffsetX >= minOffset))
|
else if (absVelX >= minVelocity && (minOffset != minOffset || absOffsetX >= minOffset))
|
||||||
{
|
{
|
||||||
|
_offset.y = 0;
|
||||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||||
{
|
{
|
||||||
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
||||||
dispatchEvent(new SwipeGestureEvent(SwipeGestureEvent.GESTURE_SWIPE, false, false, GestureState.RECOGNIZED,
|
dispatchEvent(new SwipeGestureEvent(SwipeGestureEvent.GESTURE_SWIPE, false, false, GestureState.RECOGNIZED,
|
||||||
_location.x, _location.y, _localLocation.x, _localLocation.y, _offset.x, 0));
|
_location.x, _location.y, _localLocation.x, _localLocation.y, _offset.x, _offset.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,11 +204,12 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
else if (absVelY >= minVelocity && (minOffset != minOffset || absOffsetY >= minOffset))
|
else if (absVelY >= minVelocity && (minOffset != minOffset || absOffsetY >= minOffset))
|
||||||
{
|
{
|
||||||
|
_offset.x = 0;
|
||||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||||
{
|
{
|
||||||
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
||||||
dispatchEvent(new SwipeGestureEvent(SwipeGestureEvent.GESTURE_SWIPE, false, false, GestureState.RECOGNIZED,
|
dispatchEvent(new SwipeGestureEvent(SwipeGestureEvent.GESTURE_SWIPE, false, false, GestureState.RECOGNIZED,
|
||||||
_location.x, _location.y, _localLocation.x, _localLocation.y, 0, _offset.y));
|
_location.x, _location.y, _localLocation.x, _localLocation.y, _offset.x, _offset.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,5 +228,16 @@ package org.gestouch.gestures
|
||||||
setState(GestureState.FAILED);
|
setState(GestureState.FAILED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override protected function onDelayedRecognize():void
|
||||||
|
{
|
||||||
|
if (hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||||
|
{
|
||||||
|
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
||||||
|
dispatchEvent(new SwipeGestureEvent(SwipeGestureEvent.GESTURE_SWIPE, false, false, GestureState.RECOGNIZED,
|
||||||
|
_location.x, _location.y, _localLocation.x, _localLocation.y, _offset.x, _offset.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -152,6 +152,16 @@ package org.gestouch.gestures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override protected function onDelayedRecognize():void
|
||||||
|
{
|
||||||
|
if (hasEventListener(TapGestureEvent.GESTURE_TAP))
|
||||||
|
{
|
||||||
|
dispatchEvent(new TapGestureEvent(TapGestureEvent.GESTURE_TAP, false, false, GestureState.RECOGNIZED,
|
||||||
|
_location.x, _location.y, _localLocation.x, _localLocation.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue