mirror of
https://github.com/scratchfoundation/Gestouch.git
synced 2025-02-16 23:40:14 -05:00
Merge branch 'refs/heads/features/starling' into develop
This commit is contained in:
commit
00040bb2e2
43 changed files with 1297 additions and 766 deletions
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<AS3Classpath>
|
||||
<AS3LibraryFolder>libs</AS3LibraryFolder>
|
||||
<AS3Classpath generateProblems="true" sdkBased="false" type="source" useAsSharedCode="false">src</AS3Classpath>
|
||||
<AS3Classpath generateProblems="false" sdkBased="true" type="lib" useAsSharedCode="false">frameworks/libs/air/airglobal.swc</AS3Classpath>
|
||||
<AS3Classpath generateProblems="false" sdkBased="true" type="lib" useAsSharedCode="false">frameworks/libs/mobile/mobilecomponents.swc</AS3Classpath>
|
||||
|
@ -10,4 +11,5 @@
|
|||
<AS3Classpath generateProblems="false" sdkBased="true" type="lib" useAsSharedCode="false">frameworks/libs/air/servicemonitor.swc</AS3Classpath>
|
||||
<AS3Classpath generateProblems="false" sdkBased="true" type="lib" useAsSharedCode="false">frameworks/themes/Mobile/mobile.swc</AS3Classpath>
|
||||
<AS3Classpath generateProblems="false" sdkBased="true" type="lib" useAsSharedCode="false">frameworks/libs/mx/mx.swc</AS3Classpath>
|
||||
<AS3Classpath generateProblems="false" sdkBased="false" type="lib" useAsSharedCode="false">libs/starling.swc</AS3Classpath>
|
||||
</AS3Classpath>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
h1. Gestouch: NUI gestures detection framework for mouse, touch and multitouch AS3 development.
|
||||
h1. Gestouch: multitouch gesture recognition library for Flash (ActionScript) development.
|
||||
|
||||
Gestouch is a ActionScript library/framework that helps you to deal with single- and multitouch gestures for building better NUI (Natural User Interface).
|
||||
Gestouch is a ActionScript (AS3) library that helps you to deal with single- and multitouch gestures for building better NUI (Natural User Interface).
|
||||
|
||||
|
||||
h3. Why? There's already gesture support in Flash/AIR!
|
||||
|
@ -13,9 +13,9 @@ _Upd:_ With "native way" you also won't get anything out of Stage3D and of custo
|
|||
h3. What Gestouch does in short?
|
||||
|
||||
Well basically there's 3 distinctive tasks to solve.
|
||||
# To provide various input. It can be standard MouseEvents, TouchEvents or more complex things like custom input via TUIO protocol for your hand-made installation. So what we get here is Touches (touch points).
|
||||
# To recognize gesture out of touch points. Each type of Gesture has it's own inner algorithms that ...
|
||||
# To manage gestures relations. Because they may "overlap" and once some has been recognized probably we don't want other to do so.
|
||||
# To provide various input. It can be native MouseEvents, TouchEvents or more complex things like custom input via TUIO protocol for your hand-made installation. So what we get here is Touches (touch points).
|
||||
# To recognize gesture analyzing touches. Each type of Gesture has it's own inner algorithms that ...
|
||||
# To manage gestures conflicts. As multiple gestures may be recognized simultaneously, we need to be able to control whether it's allowed or some of them should not be recognized (fail).
|
||||
|
||||
Gestouch solves these 3 tasks.
|
||||
I was hardly inspired by Apple team, how they solved this (quite recently to my big surprise! I thought they had it right from the beginning) in they Cocoa-touch UIKit framework. Gestouch is very similar in many ways. But I wouldn't call it "direct port" because 1) the whole architecture was implemented based just on conference videos and user documentation 2) flash platform is a different platform with own specialization, needs, etc.
|
||||
|
@ -23,12 +23,11 @@ So I want Gestouch to go far beyond that.
|
|||
|
||||
Features:
|
||||
* Pretty neat architecture! Very similar to Apple's UIGestureRecognizers (Cocoa-Touch UIKit)
|
||||
* Works with any display list hierarchy structures: native DisplayList (pure AS3/Flex/your UI framework), Starling or ND2D (Stage3D) and 3D libs...
|
||||
* Doesn't require any additional software (may use runtime's build-in touch support)
|
||||
* Works across all platforms (where Flash Player or AIR run of course) in exactly same way
|
||||
* Doesn't break your DisplayList architecture (could be easily used for Flex development)
|
||||
* Extendable. You can write your own application-specific gestures
|
||||
* Open-source and free
|
||||
* *_+Planning to make it work with Stage3D. Hello Starling!+_*
|
||||
|
||||
|
||||
|
||||
|
@ -69,9 +68,40 @@ private function onFreeTransform(event:TransformGestureEvent):void
|
|||
|
||||
|
||||
|
||||
h3. Advanced usage: Starling, ...
|
||||
|
||||
Recent changes made it possible to work with "Starling":http://www.starling-framework.org display list objects as well as any other display list hierarchical structures, e.g. other Stage3D frameworks that have display objects hierarchy like "ND2D":https://github.com/nulldesign/nd2d or even 3D libraries.
|
||||
In order to use Gestouch with Starling do the following:
|
||||
<pre><code>starling = new Starling(MyStarlingRootClass, stage);
|
||||
/* setup & start your Starling instance here */
|
||||
|
||||
// Gestouch initialization step 1 of 3:
|
||||
// Initialize native (default) input adapter. Needed for non-DisplayList usage.
|
||||
Gestouch.inputAdapter ||= new NativeInputAdapter(stage);
|
||||
|
||||
// Gestouch initialization step 2 of 3:
|
||||
// Register instance of StarlingDisplayListAdapter to be used for objects of type starling.display.DisplayObject.
|
||||
// What it does: helps to build hierarchy (chain of parents) for any Starling display object and
|
||||
// acts as a adapter for gesture target to provide strong-typed access to methods like globalToLocal() and contains().
|
||||
Gestouch.addDisplayListAdapter(starling.display.DisplayObject, new StarlingDisplayListAdapter());
|
||||
|
||||
// Gestouch initialization step 3 of 3:
|
||||
// Initialize and register StarlingTouchHitTester.
|
||||
// What it does: finds appropriate target for the new touches (uses Starling Stage#hitTest() method)
|
||||
// What does "-1" mean: priority for this hit-tester. Since Stage3D layer sits behind native DisplayList
|
||||
// we give it lower priority in the sense of interactivity.
|
||||
Gestouch.addTouchHitTester(new StarlingTouchHitTester(starling), -1);
|
||||
// NB! Use Gestouch#removeTouchHitTester() method if you manage multiple Starling instances during
|
||||
// your application lifetime.
|
||||
</code></pre>
|
||||
|
||||
Now you can register gesture in familiar, exactly same way:
|
||||
<pre><code>var tap:TapGesture = new TapGesture(starlingSprite);</code></pre>
|
||||
|
||||
|
||||
|
||||
h3. Roadmap, TODOs
|
||||
|
||||
* *Stage3D support.* Hello Starling! Must move away from target as InteractiveObject to some abstract adapters.
|
||||
* "Massive gestures" & Clusters. For bigger form-factor multitouch usage, when gestures must be a bit less about separate fingers but rather touch clusters (massive multitouch)
|
||||
* -Simulator (for testing multitouch gestures without special devices)- With new architecture it must be relatively easy to create SimulatorInputAdapter
|
||||
* Chained gestures concept? To transfer touches from one gesture to another. Example: press/hold for circular menu, then drag it around.
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
<arg value="-include-sources=${src.dir}"/>
|
||||
<!-- Exclude Flex Framework classes (some mx events comes from binding). -->
|
||||
<arg value="-external-library-path+=${flexSDK.dir}/frameworks/libs"/>
|
||||
<!-- Exclude any external classes (such as Starling framework classes) -->
|
||||
<arg value="-external-library-path+=${libs.dir}"/>
|
||||
<!-- Keep the metatags (Apparat?). -->
|
||||
<arg value="-keep-as3-metadata+=Abstract"/>
|
||||
<!-- Boolean mosh pit! -->
|
||||
|
@ -44,6 +46,7 @@
|
|||
</delete>
|
||||
<java jar="${FLEX_HOME}/lib/asdoc.jar" dir="${FLEX_HOME}/frameworks" fork="true" failonerror="true">
|
||||
<arg line="-source-path ${src.dir}"/>
|
||||
<arg line="-external-library-path+=${libs.dir}"/>
|
||||
<arg line="-doc-sources ${src.dir}"/>
|
||||
<arg line="-output ${asdoc.dir}"/>
|
||||
<arg value="-keep-xml=true"/>
|
||||
|
|
BIN
libs/starling.swc
Normal file
BIN
libs/starling.swc
Normal file
Binary file not shown.
98
src/org/gestouch/core/DisplayListAdapter.as
Normal file
98
src/org/gestouch/core/DisplayListAdapter.as
Normal file
|
@ -0,0 +1,98 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.DisplayObjectContainer;
|
||||
import flash.geom.Point;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
final public class DisplayListAdapter implements IDisplayListAdapter
|
||||
{
|
||||
private var _targetWeekStorage:Dictionary;
|
||||
|
||||
|
||||
public function DisplayListAdapter(target:DisplayObject = null)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
_targetWeekStorage = new Dictionary(true);
|
||||
_targetWeekStorage[target] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function get target():Object
|
||||
{
|
||||
for (var key:Object in _targetWeekStorage)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function globalToLocal(point:Point):Point
|
||||
{
|
||||
return (target as DisplayObject).globalToLocal(point);
|
||||
}
|
||||
|
||||
|
||||
public function contains(object:Object):Boolean
|
||||
{
|
||||
const targetAsDOC:DisplayObjectContainer = this.target as DisplayObjectContainer;
|
||||
const objectAsDO:DisplayObject = object as DisplayObject;
|
||||
if (objectAsDO)
|
||||
{
|
||||
return (targetAsDOC && targetAsDOC.contains(objectAsDO));
|
||||
}
|
||||
/**
|
||||
* There might be case when we use some old "software" 3D library for instace,
|
||||
* which viewport is added to classic Display List. So native stage, root and some other
|
||||
* sprites will actually be parents of 3D objects. To ensure all gestures (both for
|
||||
* native and 3D objects) work correctly with each other contains() method should be
|
||||
* a bit more sophisticated.
|
||||
* But as all 3D engines (at least it looks like that) are moving towards Stage3D layer
|
||||
* this task doesn't seem significant anymore. So I leave this implementation as
|
||||
* comments in case someone will actually need it.
|
||||
* Just uncomment this and it should work.
|
||||
|
||||
// else: more complex case.
|
||||
// object is not of the same type as this.target (flash.display::DisplayObject)
|
||||
// it might we some 3D library object in it's viewport (which itself is in DisplayList).
|
||||
// So we perform more general check:
|
||||
const adapter:IDisplayListAdapter = Gestouch.gestouch_internal::getDisplayListAdapter(object);
|
||||
if (adapter)
|
||||
{
|
||||
return adapter.getHierarchy(object).indexOf(this.target) > -1;
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public function getHierarchy(genericTarget:Object):Vector.<Object>
|
||||
{
|
||||
var list:Vector.<Object> = new Vector.<Object>();
|
||||
var i:uint = 0;
|
||||
var target:DisplayObject = genericTarget as DisplayObject;
|
||||
while (target)
|
||||
{
|
||||
list[i] = target;
|
||||
target = target.parent;
|
||||
i++;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public function reflect():Class
|
||||
{
|
||||
return DisplayListAdapter;
|
||||
}
|
||||
}
|
||||
}
|
121
src/org/gestouch/core/Gestouch.as
Normal file
121
src/org/gestouch/core/Gestouch.as
Normal file
|
@ -0,0 +1,121 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.utils.getQualifiedClassName;
|
||||
import flash.display.DisplayObject;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
final public class Gestouch
|
||||
{
|
||||
private static const _displayListAdaptersMap:Dictionary = new Dictionary();
|
||||
|
||||
{
|
||||
initClass();
|
||||
}
|
||||
|
||||
|
||||
/** @private */
|
||||
private static var _inputAdapter:IInputAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function get inputAdapter():IInputAdapter
|
||||
{
|
||||
return _inputAdapter;
|
||||
}
|
||||
public static function set inputAdapter(value:IInputAdapter):void
|
||||
{
|
||||
if (_inputAdapter == value)
|
||||
return;
|
||||
|
||||
_inputAdapter = value;
|
||||
if (inputAdapter)
|
||||
{
|
||||
inputAdapter.touchesManager = touchesManager;
|
||||
inputAdapter.init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static var _touchesManager:TouchesManager;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function get touchesManager():TouchesManager
|
||||
{
|
||||
return _touchesManager ||= new TouchesManager(gesturesManager);
|
||||
}
|
||||
|
||||
|
||||
private static var _gesturesManager:GesturesManager;
|
||||
public static function get gesturesManager():GesturesManager
|
||||
{
|
||||
return _gesturesManager ||= new GesturesManager();
|
||||
}
|
||||
|
||||
|
||||
public static function addDisplayListAdapter(targetClass:Class, adapter:IDisplayListAdapter):void
|
||||
{
|
||||
if (!targetClass || !adapter)
|
||||
{
|
||||
throw new Error("Argument error: both arguments required.");
|
||||
}
|
||||
|
||||
_displayListAdaptersMap[targetClass] = adapter;
|
||||
}
|
||||
|
||||
|
||||
public static function addTouchHitTester(hitTester:ITouchHitTester, priority:int = 0):void
|
||||
{
|
||||
touchesManager.gestouch_internal::addTouchHitTester(hitTester, priority);
|
||||
}
|
||||
|
||||
|
||||
public static function removeTouchHitTester(hitTester:ITouchHitTester):void
|
||||
{
|
||||
touchesManager.gestouch_internal::removeInputAdapter(hitTester);
|
||||
}
|
||||
|
||||
|
||||
// public static function getTouches(target:Object = null):Array
|
||||
// {
|
||||
// return touchesManager.getTouches(target);
|
||||
// }
|
||||
|
||||
gestouch_internal static function createGestureTargetAdapter(target:Object):IDisplayListAdapter
|
||||
{
|
||||
const adapter:IDisplayListAdapter = Gestouch.gestouch_internal::getDisplayListAdapter(target);
|
||||
if (adapter)
|
||||
{
|
||||
return new (adapter.reflect())(target);
|
||||
}
|
||||
|
||||
throw new Error("Cannot create adapter for target " + target + " of type " + getQualifiedClassName(target) + ".");
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal static function getDisplayListAdapter(object:Object):IDisplayListAdapter
|
||||
{
|
||||
for (var key:Object in _displayListAdaptersMap)
|
||||
{
|
||||
var targetClass:Class = key as Class;
|
||||
if (object is targetClass)
|
||||
{
|
||||
return _displayListAdaptersMap[key] as IDisplayListAdapter;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static function initClass():void
|
||||
{
|
||||
addDisplayListAdapter(DisplayObject, new DisplayListAdapter());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,99 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.errors.IllegalOperationError;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class GestureState
|
||||
{
|
||||
public static const IDLE:uint = 1 << 0;//1
|
||||
public static const POSSIBLE:uint = 1 << 1;//2
|
||||
public static const RECOGNIZED:uint = 1 << 2;//4
|
||||
public static const BEGAN:uint = 1 << 3;//8
|
||||
public static const CHANGED:uint = 1 << 4;//16
|
||||
public static const ENDED:uint = 1 << 5;//32
|
||||
public static const CANCELLED:uint = 1 << 6;//64
|
||||
public static const FAILED:uint = 1 << 7;//128
|
||||
public static const IDLE:GestureState = new GestureState(1 << 0, "IDLE");
|
||||
public static const POSSIBLE:GestureState = new GestureState(1 << 1, "POSSIBLE");
|
||||
public static const RECOGNIZED:GestureState = new GestureState(1 << 2, "RECOGNIZED");
|
||||
public static const BEGAN:GestureState = new GestureState(1 << 3, "BEGAN");
|
||||
public static const CHANGED:GestureState = new GestureState(1 << 4, "CHANGED");
|
||||
public static const ENDED:GestureState = new GestureState(1 << 5, "ENDED");
|
||||
public static const CANCELLED:GestureState = new GestureState(1 << 6, "CANCELLED");
|
||||
public static const FAILED:GestureState = new GestureState(1 << 7, "FAILED");
|
||||
|
||||
private static const endStatesBitMask:uint =
|
||||
GestureState.CANCELLED.toUint() |
|
||||
GestureState.RECOGNIZED.toUint() |
|
||||
GestureState.ENDED.toUint() |
|
||||
GestureState.FAILED.toUint();
|
||||
|
||||
private static var allStatesInitialized:Boolean;
|
||||
|
||||
|
||||
private var value:uint;
|
||||
private var name:String;
|
||||
private var validTransitionsBitMask:uint;
|
||||
|
||||
{
|
||||
_initClass();
|
||||
}
|
||||
|
||||
|
||||
public function GestureState(value:uint, name:String)
|
||||
{
|
||||
if (allStatesInitialized)
|
||||
{
|
||||
throw new IllegalOperationError("You cannot create gesture states." +
|
||||
"Use predefined constats like GestureState.RECOGNIZED");
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
private static function _initClass():void
|
||||
{
|
||||
IDLE.setValidNextStates(POSSIBLE);
|
||||
POSSIBLE.setValidNextStates(RECOGNIZED, BEGAN, FAILED);
|
||||
RECOGNIZED.setValidNextStates(IDLE);
|
||||
BEGAN.setValidNextStates(CHANGED, ENDED, CANCELLED);
|
||||
CHANGED.setValidNextStates(CHANGED, ENDED, CANCELLED);
|
||||
ENDED.setValidNextStates(IDLE);
|
||||
FAILED.setValidNextStates(IDLE);
|
||||
|
||||
allStatesInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
public function toString():String
|
||||
{
|
||||
return "GestureState." + name;
|
||||
}
|
||||
|
||||
|
||||
public function toUint():uint
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
private function setValidNextStates(...states):void
|
||||
{
|
||||
var mask:uint;
|
||||
for each (var state:GestureState in states)
|
||||
{
|
||||
mask = mask | state.value;
|
||||
}
|
||||
validTransitionsBitMask = mask;
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function canTransitionTo(state:GestureState):Boolean
|
||||
{
|
||||
return (validTransitionsBitMask & state.value) > 0;
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function get isEndState():Boolean
|
||||
{
|
||||
return (endStatesBitMask & value) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,117 +1,37 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.errors.IllegalOperationError;
|
||||
import org.gestouch.gestures.Gesture;
|
||||
import org.gestouch.input.MouseInputAdapter;
|
||||
import org.gestouch.input.TouchInputAdapter;
|
||||
import org.gestouch.input.NativeInputAdapter;
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.DisplayObjectContainer;
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Shape;
|
||||
import flash.display.Stage;
|
||||
import flash.events.Event;
|
||||
import flash.ui.Multitouch;
|
||||
import flash.events.IEventDispatcher;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.getQualifiedClassName;
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class GesturesManager implements IGesturesManager
|
||||
public class GesturesManager
|
||||
{
|
||||
public static var initDefaultInputAdapter:Boolean = true;
|
||||
private static var _instance:IGesturesManager;
|
||||
private static var _allowInstantiation:Boolean;
|
||||
|
||||
protected const _touchesManager:ITouchesManager = TouchesManager.getInstance();
|
||||
protected const _frameTickerShape:Shape = new Shape();
|
||||
protected var _inputAdapters:Vector.<IInputAdapter> = new Vector.<IInputAdapter>();
|
||||
protected var _stage:Stage;
|
||||
protected var _gesturesMap:Dictionary = new Dictionary(true);
|
||||
protected var _gesturesForTouchMap:Array = [];
|
||||
protected var _gesturesForTouchMap:Dictionary = new Dictionary();
|
||||
protected var _gesturesForTargetMap:Dictionary = new Dictionary(true);
|
||||
protected var _dirtyGestures:Vector.<Gesture> = new Vector.<Gesture>();
|
||||
protected var _dirtyGesturesLength:uint = 0;
|
||||
protected var _dirtyGesturesCount:uint = 0;
|
||||
protected var _dirtyGesturesMap:Dictionary = new Dictionary(true);
|
||||
protected var _stage:Stage;
|
||||
|
||||
use namespace gestouch_internal;
|
||||
|
||||
|
||||
public function GesturesManager()
|
||||
{
|
||||
if (Object(this).constructor == GesturesManager && !_allowInstantiation)
|
||||
{
|
||||
throw new Error("Do not instantiate GesturesManager directly.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function get inputAdapters():Vector.<IInputAdapter>
|
||||
{
|
||||
return _inputAdapters.concat();
|
||||
}
|
||||
|
||||
|
||||
public static function setImplementation(value:IGesturesManager):void
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
throw new ArgumentError("value cannot be null.");
|
||||
}
|
||||
if (_instance)
|
||||
{
|
||||
throw new Error("Instance of GesturesManager is already created. If you want to have own implementation of single GesturesManager instace, you should set it earlier.");
|
||||
}
|
||||
_instance = value;
|
||||
}
|
||||
|
||||
|
||||
public static function getInstance():IGesturesManager
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
_allowInstantiation = true;
|
||||
_instance = new GesturesManager();
|
||||
_allowInstantiation = false;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function addInputAdapter(inputAdapter:IInputAdapter):void
|
||||
{
|
||||
if (!inputAdapter)
|
||||
{
|
||||
throw new Error("Input adapter must be non null.");
|
||||
}
|
||||
|
||||
if (_inputAdapters.indexOf(inputAdapter) > -1)
|
||||
return;//TODO: throw Error or ignore?
|
||||
|
||||
_inputAdapters.push(inputAdapter);
|
||||
inputAdapter.touchesManager = _touchesManager;
|
||||
inputAdapter.gesturesManager = this;
|
||||
inputAdapter.init();
|
||||
}
|
||||
|
||||
|
||||
public function removeInputAdapter(inputAdapter:IInputAdapter, dispose:Boolean = true):void
|
||||
{
|
||||
if (!inputAdapter)
|
||||
{
|
||||
throw new Error("Input adapter must be non null.");
|
||||
}
|
||||
var index:int = _inputAdapters.indexOf(inputAdapter);
|
||||
if (index == -1)
|
||||
{
|
||||
throw new Error("This input manager is not registered.");
|
||||
}
|
||||
|
||||
_inputAdapters.splice(index, 1);
|
||||
if (dispose)
|
||||
{
|
||||
inputAdapter.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,29 +43,21 @@ package org.gestouch.core
|
|||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
protected function installStage(stage:Stage):void
|
||||
protected function onStageAvailable(stage:Stage):void
|
||||
{
|
||||
_stage = stage;
|
||||
|
||||
if (Multitouch.supportsTouchEvents)
|
||||
{
|
||||
addInputAdapter(new TouchInputAdapter(stage));
|
||||
}
|
||||
else
|
||||
{
|
||||
addInputAdapter(new MouseInputAdapter(stage));
|
||||
}
|
||||
Gestouch.inputAdapter ||= new NativeInputAdapter(stage);
|
||||
}
|
||||
|
||||
|
||||
protected function resetDirtyGestures():void
|
||||
{
|
||||
for each (var gesture:Gesture in _dirtyGestures)
|
||||
for (var gesture:* in _dirtyGesturesMap)
|
||||
{
|
||||
gesture.reset();
|
||||
(gesture as Gesture).reset();
|
||||
}
|
||||
_dirtyGestures.length = 0;
|
||||
_dirtyGesturesLength = 0;
|
||||
_dirtyGesturesCount = 0;
|
||||
_dirtyGesturesMap = new Dictionary(true);
|
||||
_frameTickerShape.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
|
||||
}
|
||||
|
@ -157,30 +69,43 @@ package org.gestouch.core
|
|||
{
|
||||
throw new ArgumentError("Argument 'gesture' must be not null.");
|
||||
}
|
||||
if (_gesturesMap[gesture])
|
||||
|
||||
const target:Object = gesture.target;
|
||||
if (!target)
|
||||
{
|
||||
throw new Error("This gesture is already registered.. something wrong.");
|
||||
throw new IllegalOperationError("Gesture must have target.");
|
||||
}
|
||||
|
||||
var target:Object = gesture.target;
|
||||
var targetGestures:Vector.<Gesture> = _gesturesForTargetMap[target] as Vector.<Gesture>;
|
||||
if (!targetGestures)
|
||||
if (targetGestures)
|
||||
{
|
||||
targetGestures = _gesturesForTargetMap[gesture.target] = new Vector.<Gesture>();
|
||||
if (targetGestures.indexOf(gesture) == -1)
|
||||
{
|
||||
targetGestures.push(gesture);
|
||||
}
|
||||
}
|
||||
targetGestures.push(gesture);
|
||||
else
|
||||
{
|
||||
targetGestures = _gesturesForTargetMap[target] = new Vector.<Gesture>();
|
||||
targetGestures[0] = gesture;
|
||||
}
|
||||
|
||||
|
||||
_gesturesMap[gesture] = true;
|
||||
|
||||
if (GesturesManager.initDefaultInputAdapter)
|
||||
if (!_stage)
|
||||
{
|
||||
if (!_stage && gesture.target.stage)
|
||||
var targetAsDO:DisplayObject = target as DisplayObject;
|
||||
if (targetAsDO)
|
||||
{
|
||||
installStage(gesture.target.stage);
|
||||
}
|
||||
else
|
||||
{
|
||||
gesture.target.addEventListener(Event.ADDED_TO_STAGE, gestureTarget_addedToStageHandler);
|
||||
if (targetAsDO.stage)
|
||||
{
|
||||
onStageAvailable(targetAsDO.stage);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetAsDO.addEventListener(Event.ADDED_TO_STAGE, gestureTarget_addedToStageHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,21 +119,28 @@ package org.gestouch.core
|
|||
}
|
||||
|
||||
|
||||
var target:InteractiveObject = gesture.target;
|
||||
var targetGestures:Vector.<Gesture> = _gesturesForTargetMap[target] as Vector.<Gesture>;
|
||||
if (targetGestures.length > 1)
|
||||
var target:Object = gesture.target;
|
||||
// check for target because it could be already GC-ed (since target reference is weak)
|
||||
if (target)
|
||||
{
|
||||
targetGestures.splice(targetGestures.indexOf(gesture), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete _gesturesForTargetMap[target];
|
||||
target.removeEventListener(Event.ADDED_TO_STAGE, gestureTarget_addedToStageHandler);
|
||||
var targetGestures:Vector.<Gesture> = _gesturesForTargetMap[target] as Vector.<Gesture>;
|
||||
if (targetGestures.length > 1)
|
||||
{
|
||||
targetGestures.splice(targetGestures.indexOf(gesture), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete _gesturesForTargetMap[target];
|
||||
if (target is IEventDispatcher)
|
||||
{
|
||||
(target as IEventDispatcher).removeEventListener(Event.ADDED_TO_STAGE, gestureTarget_addedToStageHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete _gesturesMap[gesture];
|
||||
|
||||
//TODO: decide about gesture state and _dirtyGestures
|
||||
gesture.reset();
|
||||
}
|
||||
|
||||
|
||||
|
@ -216,8 +148,8 @@ package org.gestouch.core
|
|||
{
|
||||
if (!_dirtyGesturesMap[gesture])
|
||||
{
|
||||
_dirtyGestures.push(gesture);
|
||||
_dirtyGesturesLength++;
|
||||
_dirtyGesturesMap[gesture] = true;
|
||||
_dirtyGesturesCount++;
|
||||
_frameTickerShape.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
|
||||
}
|
||||
}
|
||||
|
@ -225,11 +157,12 @@ package org.gestouch.core
|
|||
|
||||
gestouch_internal function onGestureRecognized(gesture:Gesture):void
|
||||
{
|
||||
const target:Object = gesture.target;
|
||||
|
||||
for (var key:Object in _gesturesMap)
|
||||
{
|
||||
var otherGesture:Gesture = key as Gesture;
|
||||
var target:DisplayObject = gesture.target;
|
||||
var otherTarget:DisplayObject = otherGesture.target;
|
||||
var otherTarget:Object = otherGesture.target;
|
||||
|
||||
// conditions for otherGesture "own properties"
|
||||
if (otherGesture != gesture &&
|
||||
|
@ -237,10 +170,10 @@ package org.gestouch.core
|
|||
otherGesture.enabled &&
|
||||
otherGesture.state == GestureState.POSSIBLE)
|
||||
{
|
||||
// conditions for otherGesture target
|
||||
if (otherTarget == target ||
|
||||
(target is DisplayObjectContainer && (target as DisplayObjectContainer).contains(otherTarget)) ||
|
||||
(otherTarget is DisplayObjectContainer && (otherTarget as DisplayObjectContainer).contains(target)))
|
||||
gesture.targetAdapter.contains(otherTarget) ||
|
||||
otherGesture.targetAdapter.contains(target)
|
||||
)
|
||||
{
|
||||
var gestureDelegate:IGestureDelegate = gesture.delegate;
|
||||
var otherGestureDelegate:IGestureDelegate = otherGesture.delegate;
|
||||
|
@ -250,9 +183,9 @@ package org.gestouch.core
|
|||
(!gestureDelegate || !gestureDelegate.gesturesShouldRecognizeSimultaneously(gesture, otherGesture)) &&
|
||||
(!otherGestureDelegate || !otherGestureDelegate.gesturesShouldRecognizeSimultaneously(otherGesture, gesture)))
|
||||
{
|
||||
otherGesture.gestouch_internal::setState_internal(GestureState.FAILED);
|
||||
otherGesture.setState_internal(GestureState.FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +193,7 @@ package org.gestouch.core
|
|||
|
||||
gestouch_internal function onTouchBegin(touch:Touch):void
|
||||
{
|
||||
if (_dirtyGesturesLength > 0)
|
||||
if (_dirtyGesturesCount > 0)
|
||||
{
|
||||
resetDirtyGestures();
|
||||
}
|
||||
|
@ -268,24 +201,41 @@ package org.gestouch.core
|
|||
var gesture:Gesture;
|
||||
var i:uint;
|
||||
|
||||
// This vector will contain active gestures for specific touch (ID) during all touch session.
|
||||
var gesturesForTouch:Vector.<Gesture> = _gesturesForTouchMap[touch.id] as Vector.<Gesture>;
|
||||
// This vector will contain active gestures for specific touch during all touch session.
|
||||
var gesturesForTouch:Vector.<Gesture> = _gesturesForTouchMap[touch] as Vector.<Gesture>;
|
||||
if (!gesturesForTouch)
|
||||
{
|
||||
gesturesForTouch = new Vector.<Gesture>();
|
||||
_gesturesForTouchMap[touch.id] = gesturesForTouch;
|
||||
gesturesForTouch = _gesturesForTouchMap[touch] = new Vector.<Gesture>();
|
||||
}
|
||||
else
|
||||
{
|
||||
gesturesForTouch.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
var target:Object = touch.target;
|
||||
const displayListAdapter:IDisplayListAdapter = Gestouch.gestouch_internal::getDisplayListAdapter(target);
|
||||
const hierarchy:Vector.<Object> = displayListAdapter.getHierarchy(target);
|
||||
if (!hierarchy)
|
||||
{
|
||||
throw new Error("Display list adapter not found for target of type '" + getQualifiedClassName(target) + "'.");
|
||||
}
|
||||
const hierarchyLength:uint = hierarchy.length;
|
||||
if (hierarchyLength == 0)
|
||||
{
|
||||
throw new Error("No hierarchy build for target '" + target +"'. Something is wrong with that IDisplayListAdapter.");
|
||||
}
|
||||
if (_stage && !(hierarchy[hierarchyLength - 1] is Stage))
|
||||
{
|
||||
// Looks like some non-native (non DisplayList) hierarchy
|
||||
// but we must always handle gestures with Stage target
|
||||
// since Stage is anyway the top-most parent
|
||||
hierarchy[hierarchyLength] = _stage;
|
||||
}
|
||||
|
||||
// Create a sorted(!) list of gestures which are interested in this touch.
|
||||
// Sorting priority: deeper target has higher priority, recently added gesture has higher priority.
|
||||
var target:InteractiveObject = touch.target;
|
||||
var gesturesForTarget:Vector.<Gesture>;
|
||||
while (target)
|
||||
for each (target in hierarchy)
|
||||
{
|
||||
gesturesForTarget = _gesturesForTargetMap[target] as Vector.<Gesture>;
|
||||
if (gesturesForTarget)
|
||||
|
@ -302,8 +252,6 @@ package org.gestouch.core
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
target = target.parent;
|
||||
}
|
||||
|
||||
// Then we populate them with this touch and event.
|
||||
|
@ -315,7 +263,7 @@ package org.gestouch.core
|
|||
// Check for state because previous (i+1) gesture may already abort current (i) one
|
||||
if (gesture.state != GestureState.FAILED)
|
||||
{
|
||||
gesture.gestouch_internal::touchBeginHandler(touch);
|
||||
gesture.touchBeginHandler(touch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -327,12 +275,12 @@ package org.gestouch.core
|
|||
|
||||
gestouch_internal function onTouchMove(touch:Touch):void
|
||||
{
|
||||
if (_dirtyGesturesLength > 0)
|
||||
if (_dirtyGesturesCount > 0)
|
||||
{
|
||||
resetDirtyGestures();
|
||||
}
|
||||
|
||||
var gesturesForTouch:Vector.<Gesture> = _gesturesForTouchMap[touch.id] as Vector.<Gesture>;
|
||||
var gesturesForTouch:Vector.<Gesture> = _gesturesForTouchMap[touch] as Vector.<Gesture>;
|
||||
var gesture:Gesture;
|
||||
var i:int = gesturesForTouch.length;
|
||||
while (i-- > 0)
|
||||
|
@ -341,7 +289,7 @@ package org.gestouch.core
|
|||
|
||||
if (gesture.state != GestureState.FAILED && gesture.isTrackingTouch(touch.id))
|
||||
{
|
||||
gesture.gestouch_internal::touchMoveHandler(touch);
|
||||
gesture.touchMoveHandler(touch);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -354,23 +302,25 @@ package org.gestouch.core
|
|||
|
||||
gestouch_internal function onTouchEnd(touch:Touch):void
|
||||
{
|
||||
if (_dirtyGesturesLength > 0)
|
||||
if (_dirtyGesturesCount > 0)
|
||||
{
|
||||
resetDirtyGestures();
|
||||
}
|
||||
|
||||
var gesturesForTouch:Vector.<Gesture> = _gesturesForTouchMap[touch.id] as Vector.<Gesture>;
|
||||
var gesturesForTouch:Vector.<Gesture> = _gesturesForTouchMap[touch] as Vector.<Gesture>;
|
||||
var gesture:Gesture;
|
||||
var i:int = gesturesForTouch.length;
|
||||
while (i-- > 0)
|
||||
{
|
||||
gesture = gesturesForTouch[i] as Gesture;
|
||||
|
||||
|
||||
if (gesture.state != GestureState.FAILED && gesture.isTrackingTouch(touch.id))
|
||||
{
|
||||
gesture.gestouch_internal::touchEndHandler(touch);
|
||||
{
|
||||
gesture.touchEndHandler(touch);
|
||||
}
|
||||
}
|
||||
|
||||
gesturesForTouch.length = 0;// release for GC
|
||||
}
|
||||
|
||||
|
||||
|
@ -386,15 +336,15 @@ package org.gestouch.core
|
|||
//
|
||||
// Event handlers
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
protected function gestureTarget_addedToStageHandler(event:Event):void
|
||||
{
|
||||
var target:DisplayObject = event.target as DisplayObject;
|
||||
target.removeEventListener(Event.ADDED_TO_STAGE, gestureTarget_addedToStageHandler);
|
||||
if (!_stage && GesturesManager.initDefaultInputAdapter)
|
||||
if (!_stage)
|
||||
{
|
||||
installStage(target.stage);
|
||||
onStageAvailable(target.stage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
12
src/org/gestouch/core/IDisplayListAdapter.as
Normal file
12
src/org/gestouch/core/IDisplayListAdapter.as
Normal file
|
@ -0,0 +1,12 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public interface IDisplayListAdapter extends IGestureTargetAdapter
|
||||
{
|
||||
function getHierarchy(target:Object):Vector.<Object>;
|
||||
|
||||
function reflect():Class;
|
||||
}
|
||||
}
|
15
src/org/gestouch/core/IGestureTargetAdapter.as
Normal file
15
src/org/gestouch/core/IGestureTargetAdapter.as
Normal file
|
@ -0,0 +1,15 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.geom.Point;
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public interface IGestureTargetAdapter
|
||||
{
|
||||
function get target():Object;
|
||||
|
||||
function globalToLocal(point:Point):Point;
|
||||
|
||||
function contains(object:Object):Boolean;
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
/**
|
||||
* The class that implements this interface must also
|
||||
* implement next methods under gestouch_internal namespace:
|
||||
*
|
||||
* function addGesture(gesture:Gesture):void;
|
||||
* function removeGesture(gesture:Gesture):void;
|
||||
* function scheduleGestureStateReset(gesture:Gesture):void;
|
||||
* function onGestureRecognized(gesture:Gesture):void;
|
||||
*/
|
||||
public interface IGesturesManager
|
||||
{
|
||||
function addInputAdapter(inputAdapter:IInputAdapter):void;
|
||||
function removeInputAdapter(inputAdapter:IInputAdapter, dispose:Boolean = true):void;
|
||||
}
|
||||
}
|
|
@ -5,10 +5,14 @@ package org.gestouch.core
|
|||
*/
|
||||
public interface IInputAdapter
|
||||
{
|
||||
function set touchesManager(value:ITouchesManager):void;
|
||||
function set gesturesManager(value:IGesturesManager):void;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function set touchesManager(value:TouchesManager):void;
|
||||
|
||||
/**
|
||||
* Called when input adapter is set.
|
||||
*/
|
||||
function init():void;
|
||||
function dispose():void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
14
src/org/gestouch/core/ITouchHitTester.as
Normal file
14
src/org/gestouch/core/ITouchHitTester.as
Normal file
|
@ -0,0 +1,14 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public interface ITouchHitTester
|
||||
{
|
||||
function hitTest(point:Point, nativeTarget:InteractiveObject):Object;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public interface ITouchesManager
|
||||
{
|
||||
function get activeTouchesCount():uint;
|
||||
|
||||
function createTouch():Touch;
|
||||
function addTouch(touch:Touch):Touch;
|
||||
function removeTouch(touch:Touch):Touch;
|
||||
function getTouch(touchPointID:int):Touch;
|
||||
function hasTouch(touchPointID:int):Boolean;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
|
@ -19,13 +18,15 @@ package org.gestouch.core
|
|||
/**
|
||||
* The original event target for this touch (touch began with).
|
||||
*/
|
||||
public var target:InteractiveObject;
|
||||
public var target:Object;
|
||||
|
||||
public var sizeX:Number;
|
||||
public var sizeY:Number;
|
||||
public var pressure:Number;
|
||||
|
||||
// public var lastMove:Point;
|
||||
|
||||
use namespace gestouch_internal;
|
||||
|
||||
|
||||
public function Touch(id:uint = 0)
|
||||
|
@ -39,13 +40,16 @@ package org.gestouch.core
|
|||
{
|
||||
return _location.clone();
|
||||
}
|
||||
gestouch_internal function setLocation(value:Point):void
|
||||
gestouch_internal function setLocation(x:Number, y:Number, time:uint):void
|
||||
{
|
||||
_location = value;
|
||||
_location = new Point(x, y);
|
||||
_beginLocation = _location.clone();
|
||||
_previousLocation = _location.clone();
|
||||
|
||||
_time = time;
|
||||
_beginTime = time;
|
||||
}
|
||||
gestouch_internal function updateLocation(x:Number, y:Number):void
|
||||
gestouch_internal function updateLocation(x:Number, y:Number, time:uint):void
|
||||
{
|
||||
if (_location)
|
||||
{
|
||||
|
@ -53,10 +57,11 @@ package org.gestouch.core
|
|||
_previousLocation.y = _location.y;
|
||||
_location.x = x;
|
||||
_location.y = y;
|
||||
_time = time;
|
||||
}
|
||||
else
|
||||
{
|
||||
gestouch_internal::setLocation(new Point(x, y));
|
||||
setLocation(x, y, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,30 @@
|
|||
package org.gestouch.core
|
||||
{
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Stage;
|
||||
import flash.geom.Point;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class TouchesManager implements ITouchesManager
|
||||
public class TouchesManager
|
||||
{
|
||||
private static var _instance:ITouchesManager;
|
||||
private static var _allowInstantiation:Boolean;
|
||||
|
||||
protected var _gesturesManager:GesturesManager;
|
||||
protected var _touchesMap:Object = {};
|
||||
protected var _hitTesters:Vector.<ITouchHitTester> = new Vector.<ITouchHitTester>();
|
||||
protected var _hitTesterPrioritiesMap:Dictionary = new Dictionary(true);
|
||||
|
||||
use namespace gestouch_internal;
|
||||
|
||||
|
||||
public function TouchesManager()
|
||||
public function TouchesManager(gesturesManager:GesturesManager)
|
||||
{
|
||||
if (Object(this).constructor == TouchesManager && !_allowInstantiation)
|
||||
{
|
||||
throw new Error("Do not instantiate TouchesManager directly.");
|
||||
}
|
||||
_gesturesManager = gesturesManager;
|
||||
|
||||
addTouchHitTester(new DefaultTouchHitTester());
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,77 +35,207 @@ package org.gestouch.core
|
|||
}
|
||||
|
||||
|
||||
public static function setImplementation(value:ITouchesManager):void
|
||||
public function getTouches(target:Object = null):Array
|
||||
{
|
||||
if (!value)
|
||||
const touches:Array = [];
|
||||
if (!target || target is Stage)
|
||||
{
|
||||
throw new ArgumentError("value cannot be null.");
|
||||
// return all touches
|
||||
var i:uint = 0;
|
||||
for each (var touch:Touch in _touchesMap)
|
||||
{
|
||||
touches[i++] = touch;
|
||||
}
|
||||
}
|
||||
if (_instance)
|
||||
else
|
||||
{
|
||||
throw new Error("Instance of TouchesManager is already created. If you want to have own implementation of single TouchesManager instace, you should set it earlier.");
|
||||
//TODO
|
||||
}
|
||||
_instance = value;
|
||||
}
|
||||
|
||||
|
||||
public static function getInstance():ITouchesManager
|
||||
{
|
||||
if (!_instance)
|
||||
{
|
||||
_allowInstantiation = true;
|
||||
_instance = new TouchesManager();
|
||||
_allowInstantiation = false;
|
||||
}
|
||||
|
||||
return _instance;
|
||||
|
||||
return touches;
|
||||
}
|
||||
|
||||
|
||||
public function createTouch():Touch
|
||||
gestouch_internal function addTouchHitTester(touchHitTester:ITouchHitTester, priority:int = 0):void
|
||||
{
|
||||
if (!touchHitTester)
|
||||
{
|
||||
throw new ArgumentError("Argument must be non null.");
|
||||
}
|
||||
|
||||
if (_hitTesters.indexOf(touchHitTester) == -1)
|
||||
{
|
||||
_hitTesters.push(touchHitTester);
|
||||
}
|
||||
|
||||
_hitTesterPrioritiesMap[touchHitTester] = priority;
|
||||
// Sort hit testers using their priorities
|
||||
_hitTesters.sort(hitTestersSorter);
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function removeInputAdapter(touchHitTester:ITouchHitTester):void
|
||||
{
|
||||
if (!touchHitTester)
|
||||
{
|
||||
throw new ArgumentError("Argument must be non null.");
|
||||
}
|
||||
|
||||
var index:int = _hitTesters.indexOf(touchHitTester);
|
||||
if (index == -1)
|
||||
{
|
||||
throw new Error("This touchHitTester is not registered.");
|
||||
}
|
||||
|
||||
_hitTesters.splice(index, 1);
|
||||
delete _hitTesterPrioritiesMap[touchHitTester];
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function onTouchBegin(touchID:uint, x:Number, y:Number, nativeTarget:InteractiveObject = null):Boolean
|
||||
{
|
||||
if (touchID in _touchesMap)
|
||||
return false;// touch with specified ID is already registered and being tracked
|
||||
|
||||
const location:Point = new Point(x, y);
|
||||
|
||||
for each (var registeredTouch:Touch in _touchesMap)
|
||||
{
|
||||
// Check if touch at the same location exists.
|
||||
// In case we listen to both TouchEvents and MouseEvents, one of them will come first
|
||||
// (right now looks like MouseEvent dispatched first, but who know what Adobe will
|
||||
// do tomorrow). This check helps to filter out the one comes after.
|
||||
|
||||
// NB! According to the tests with some IR multitouch frame and Windows computer
|
||||
// TouchEvent comes first, but the following MouseEvent has slightly offset location
|
||||
// (1px both axis). That is why Point#distance() used instead of Point#equals()
|
||||
|
||||
if (Point.distance(registeredTouch.location, location) < 2)
|
||||
return false;
|
||||
}
|
||||
|
||||
const touch:Touch = createTouch();
|
||||
touch.id = touchID;
|
||||
|
||||
var target:Object;
|
||||
var altTarget:Object;
|
||||
for each (var hitTester:ITouchHitTester in _hitTesters)
|
||||
{
|
||||
target = hitTester.hitTest(location, nativeTarget);
|
||||
if (target)
|
||||
{
|
||||
if ((target is Stage))
|
||||
{
|
||||
// NB! Target is flash.display::Stage is a special case. If it is true, we want
|
||||
// to give a try to a lower-priority (Stage3D) hit-testers.
|
||||
altTarget = target;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We found a target.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!target && !altTarget)
|
||||
{
|
||||
throw new Error("Not touch target found (hit test)." +
|
||||
"Something is wrong, at least flash.display::Stage should be found." +
|
||||
"See Gestouch#addTouchHitTester() and Gestouch#inputAdapter.");
|
||||
}
|
||||
|
||||
touch.target = target || altTarget;
|
||||
touch.setLocation(x, y, getTimer());
|
||||
|
||||
_touchesMap[touchID] = touch;
|
||||
_activeTouchesCount++;
|
||||
|
||||
_gesturesManager.onTouchBegin(touch);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function onTouchMove(touchID:uint, x:Number, y:Number):void
|
||||
{
|
||||
const touch:Touch = _touchesMap[touchID] as Touch;
|
||||
if (!touch)
|
||||
return;// touch with specified ID isn't registered
|
||||
|
||||
touch.updateLocation(x, y, getTimer());
|
||||
|
||||
_gesturesManager.onTouchMove(touch);
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function onTouchEnd(touchID:uint, x:Number, y:Number):void
|
||||
{
|
||||
const touch:Touch = _touchesMap[touchID] as Touch;
|
||||
if (!touch)
|
||||
return;// touch with specified ID isn't registered
|
||||
|
||||
touch.updateLocation(x, y, getTimer());
|
||||
|
||||
delete _touchesMap[touchID];
|
||||
_activeTouchesCount--;
|
||||
|
||||
_gesturesManager.onTouchEnd(touch);
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function onTouchCancel(touchID:uint, x:Number, y:Number):void
|
||||
{
|
||||
const touch:Touch = _touchesMap[touchID] as Touch;
|
||||
if (!touch)
|
||||
return;// touch with specified ID isn't registered
|
||||
|
||||
touch.updateLocation(x, y, getTimer());
|
||||
|
||||
delete _touchesMap[touchID];
|
||||
_activeTouchesCount--;
|
||||
|
||||
_gesturesManager.onTouchCancel(touch);
|
||||
}
|
||||
|
||||
|
||||
protected function createTouch():Touch
|
||||
{
|
||||
//TODO: pool
|
||||
return new Touch();
|
||||
}
|
||||
|
||||
|
||||
public function addTouch(touch:Touch):Touch
|
||||
/**
|
||||
* Sorts from higher priority to lower. Items with the same priority keep the order
|
||||
* of addition, e.g.:
|
||||
* add(a), add(b), add(c, -1), add(d, 1) will be ordered to
|
||||
* d, a, b, c
|
||||
*/
|
||||
protected function hitTestersSorter(x:ITouchHitTester, y:ITouchHitTester):Number
|
||||
{
|
||||
if (_touchesMap.hasOwnProperty(touch.id))
|
||||
{
|
||||
throw new Error("Touch with id " + touch.id + " is already registered.");
|
||||
}
|
||||
const d:int = int(_hitTesterPrioritiesMap[x]) - int(_hitTesterPrioritiesMap[y]);
|
||||
if (d > 0)
|
||||
return -1;
|
||||
else if (d < 0)
|
||||
return 1;
|
||||
|
||||
_touchesMap[touch.id] = touch;
|
||||
_activeTouchesCount++;
|
||||
|
||||
return touch;
|
||||
}
|
||||
|
||||
|
||||
public function removeTouch(touch:Touch):Touch
|
||||
{
|
||||
if (!_touchesMap.hasOwnProperty(touch.id))
|
||||
{
|
||||
throw new Error("Touch with id " + touch.id + " is not registered.");
|
||||
}
|
||||
|
||||
delete _touchesMap[touch.id];
|
||||
_activeTouchesCount--;
|
||||
|
||||
return touch;
|
||||
}
|
||||
|
||||
|
||||
public function hasTouch(touchPointID:int):Boolean
|
||||
{
|
||||
return _touchesMap.hasOwnProperty(touchPointID);
|
||||
}
|
||||
|
||||
|
||||
public function getTouch(touchPointID:int):Touch
|
||||
{
|
||||
return _touchesMap[touchPointID] as Touch;
|
||||
return _hitTesters.indexOf(x) > _hitTesters.indexOf(y) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import flash.geom.Point;
|
||||
import flash.display.InteractiveObject;
|
||||
|
||||
import org.gestouch.core.ITouchHitTester;
|
||||
|
||||
|
||||
class DefaultTouchHitTester implements ITouchHitTester
|
||||
{
|
||||
public function hitTest(point:Point, nativeTarget:InteractiveObject):Object
|
||||
{
|
||||
return nativeTarget;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -8,7 +10,7 @@ package org.gestouch.events
|
|||
*/
|
||||
public class GestureEvent extends Event
|
||||
{
|
||||
public var gestureState:uint;
|
||||
public var gestureState:GestureState;
|
||||
public var stageX:Number;
|
||||
public var stageY:Number;
|
||||
public var localX:Number;
|
||||
|
@ -16,7 +18,7 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function GestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -10,11 +12,11 @@ package org.gestouch.events
|
|||
{
|
||||
public static const STATE_CHANGE:String = "stateChange";
|
||||
|
||||
public var newState:uint;
|
||||
public var oldState:uint;
|
||||
public var newState:GestureState;
|
||||
public var oldState:GestureState;
|
||||
|
||||
|
||||
public function GestureStateEvent(type:String, newState:uint, oldState:uint)
|
||||
public function GestureStateEvent(type:String, newState:GestureState, oldState:GestureState)
|
||||
{
|
||||
super(type, false, false);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -12,7 +14,7 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function LongPressGestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -12,7 +14,7 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function PanGestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0,
|
||||
offsetX:Number = 0, offsetY:Number = 0)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -12,7 +14,7 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function RotateGestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0,
|
||||
rotation:Number = 0)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -12,7 +14,7 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function SwipeGestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0,
|
||||
offsetX:Number = 0, offsetY:Number = 0)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -12,7 +14,8 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function TapGestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0, stageX:Number = 0, stageY:Number = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0)
|
||||
{
|
||||
super(type, bubbles, cancelable, gestureState, stageX, stageY, localX, localY);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -18,7 +20,7 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function TransformGestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0,
|
||||
scaleX:Number = 1.0, scaleY:Number = 1.0,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.gestouch.events
|
||||
{
|
||||
import org.gestouch.core.GestureState;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
|
||||
|
@ -12,7 +14,7 @@ package org.gestouch.events
|
|||
|
||||
|
||||
public function ZoomGestureEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false,
|
||||
gestureState:uint = 0,
|
||||
gestureState:GestureState = null,
|
||||
stageX:Number = 0, stageY:Number = 0,
|
||||
localX:Number = 0, localY:Number = 0,
|
||||
scaleX:Number = 1.0, scaleY:Number = 1.0)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package org.gestouch.extensions.starling
|
||||
{
|
||||
import starling.core.Starling;
|
||||
import starling.display.DisplayObject;
|
||||
import starling.display.DisplayObjectContainer;
|
||||
|
||||
import org.gestouch.core.IDisplayListAdapter;
|
||||
|
||||
import flash.geom.Point;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
final public class StarlingDisplayListAdapter implements IDisplayListAdapter
|
||||
{
|
||||
private var targetWeekStorage:Dictionary;
|
||||
|
||||
|
||||
public function StarlingDisplayListAdapter(target:DisplayObject = null)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
targetWeekStorage = new Dictionary(true);
|
||||
targetWeekStorage[target] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function get target():Object
|
||||
{
|
||||
for (var key:Object in targetWeekStorage)
|
||||
{
|
||||
return key;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function globalToLocal(point:Point):Point
|
||||
{
|
||||
point = StarlingUtils.adjustGlobalPoint(Starling.current, point);
|
||||
return (target as DisplayObject).globalToLocal(point);
|
||||
}
|
||||
|
||||
|
||||
public function contains(object:Object):Boolean
|
||||
{
|
||||
const targetAsDOC:DisplayObjectContainer = this.target as DisplayObjectContainer;
|
||||
const objectAsDO:DisplayObject = object as DisplayObject;
|
||||
return (targetAsDOC && objectAsDO && targetAsDOC.contains(objectAsDO));
|
||||
}
|
||||
|
||||
|
||||
public function getHierarchy(genericTarget:Object):Vector.<Object>
|
||||
{
|
||||
var list:Vector.<Object> = new Vector.<Object>();
|
||||
var i:uint = 0;
|
||||
var target:DisplayObject = genericTarget as DisplayObject;
|
||||
while (target)
|
||||
{
|
||||
list[i] = target;
|
||||
target = target.parent;
|
||||
i++;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public function reflect():Class
|
||||
{
|
||||
return StarlingDisplayListAdapter;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.gestouch.extensions.starling
|
||||
{
|
||||
import starling.core.Starling;
|
||||
|
||||
import org.gestouch.core.ITouchHitTester;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
final public class StarlingTouchHitTester implements ITouchHitTester
|
||||
{
|
||||
private var starling:Starling;
|
||||
|
||||
|
||||
public function StarlingTouchHitTester(starling:Starling)
|
||||
{
|
||||
if (!starling)
|
||||
{
|
||||
throw ArgumentError("Missing starling argument.");
|
||||
}
|
||||
|
||||
this.starling = starling;
|
||||
}
|
||||
|
||||
|
||||
public function hitTest(point:Point, nativeTarget:InteractiveObject):Object
|
||||
{
|
||||
point = StarlingUtils.adjustGlobalPoint(starling, point);
|
||||
return starling.stage.hitTest(point, true);
|
||||
}
|
||||
}
|
||||
}
|
38
src/org/gestouch/extensions/starling/StarlingUtils.as
Normal file
38
src/org/gestouch/extensions/starling/StarlingUtils.as
Normal file
|
@ -0,0 +1,38 @@
|
|||
package org.gestouch.extensions.starling
|
||||
{
|
||||
import starling.display.Stage;
|
||||
import starling.core.Starling;
|
||||
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
final public class StarlingUtils
|
||||
{
|
||||
/**
|
||||
* Transforms real global point (in the scope of flash.display::Stage) into
|
||||
* starling stage "global" coordinates.
|
||||
*/
|
||||
public static function adjustGlobalPoint(starling:Starling, point:Point):Point
|
||||
{
|
||||
const vp:Rectangle = starling.viewPort;
|
||||
const stStage:Stage = starling.stage;
|
||||
|
||||
if (vp.x != 0 || vp.y != 0 ||
|
||||
stStage.stageWidth != vp.width || stStage.stageHeight != vp.height)
|
||||
{
|
||||
point = point.clone();
|
||||
|
||||
// Same transformation they do in Starling
|
||||
// WTF!? https://github.com/PrimaryFeather/Starling-Framework/issues/72
|
||||
point.x = stStage.stageWidth * (point.x - vp.x) / vp.width;
|
||||
point.y = stStage.stageHeight * (point.y - vp.y) / vp.height;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +1,32 @@
|
|||
package org.gestouch.gestures
|
||||
{
|
||||
import org.gestouch.core.Gestouch;
|
||||
import org.gestouch.core.GestureState;
|
||||
import org.gestouch.core.GesturesManager;
|
||||
import org.gestouch.core.IGestureDelegate;
|
||||
import org.gestouch.core.IGesturesManager;
|
||||
import org.gestouch.core.IGestureTargetAdapter;
|
||||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.core.gestouch_internal;
|
||||
import org.gestouch.events.GestureStateEvent;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.errors.IllegalOperationError;
|
||||
import flash.events.EventDispatcher;
|
||||
import flash.geom.Point;
|
||||
import flash.system.Capabilities;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
|
||||
/**
|
||||
* Dispatched when the state of the gesture changes.
|
||||
*
|
||||
* @eventType org.gestouch.events.GestureStateEvent
|
||||
* @see #state
|
||||
*/
|
||||
[Event(name="stateChange", type="org.gestouch.events.GestureStateEvent")]
|
||||
/**
|
||||
* Base class for all gestures. Gesture is essentially a detector that tracks touch points
|
||||
* in order detect specific gesture motion and form gesture event on target.
|
||||
*
|
||||
* TODO:
|
||||
* -
|
||||
*
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class Gesture extends EventDispatcher
|
||||
|
@ -32,10 +36,10 @@ package org.gestouch.gestures
|
|||
* (not an accidental offset on touch),
|
||||
* based on 20 pixels on a 252ppi device.
|
||||
*/
|
||||
public static const DEFAULT_SLOP:uint = Math.round(20 / 252 * flash.system.Capabilities.screenDPI);
|
||||
public static var DEFAULT_SLOP:uint = Math.round(20 / 252 * flash.system.Capabilities.screenDPI);
|
||||
|
||||
|
||||
protected const _gesturesManager:IGesturesManager = GesturesManager.getInstance();
|
||||
protected const _gesturesManager:GesturesManager = Gestouch.gesturesManager;
|
||||
/**
|
||||
* Map (generic object) of tracking touch points, where keys are touch points IDs.
|
||||
*/
|
||||
|
@ -47,10 +51,12 @@ package org.gestouch.gestures
|
|||
* @see requireGestureToFail()
|
||||
*/
|
||||
protected var _gesturesToFail:Dictionary = new Dictionary(true);
|
||||
protected var _pendingRecognizedState:uint;
|
||||
protected var _pendingRecognizedState:GestureState;
|
||||
|
||||
use namespace gestouch_internal;
|
||||
|
||||
|
||||
public function Gesture(target:InteractiveObject = null)
|
||||
public function Gesture(target:Object = null)
|
||||
{
|
||||
super();
|
||||
|
||||
|
@ -61,9 +67,22 @@ package org.gestouch.gestures
|
|||
|
||||
|
||||
/** @private */
|
||||
private var _targetWeekStorage:Dictionary;
|
||||
protected var _targetAdapter:IGestureTargetAdapter;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
gestouch_internal function get targetAdapter():IGestureTargetAdapter
|
||||
{
|
||||
return _targetAdapter;
|
||||
}
|
||||
protected function get targetAdapter():IGestureTargetAdapter
|
||||
{
|
||||
return _targetAdapter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
* InteractiveObject (DisplayObject) which this gesture is tracking the actual gesture motion on.
|
||||
*
|
||||
* <p>Could be some image, component (like map) or the larger view like Stage.</p>
|
||||
|
@ -74,29 +93,18 @@ package org.gestouch.gestures
|
|||
*
|
||||
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html
|
||||
*/
|
||||
public function get target():InteractiveObject
|
||||
public function get target():Object
|
||||
{
|
||||
for (var key:Object in _targetWeekStorage)
|
||||
{
|
||||
return key as InteractiveObject;
|
||||
}
|
||||
return null;
|
||||
return _targetAdapter ? _targetAdapter.target : null;
|
||||
}
|
||||
public function set target(value:InteractiveObject):void
|
||||
public function set target(value:Object):void
|
||||
{
|
||||
var target:InteractiveObject = this.target;
|
||||
var target:Object = this.target;
|
||||
if (target == value)
|
||||
return;
|
||||
|
||||
uninstallTarget(target);
|
||||
for (var key:Object in _targetWeekStorage)
|
||||
{
|
||||
delete _targetWeekStorage[key];
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
(_targetWeekStorage ||= new Dictionary(true))[value] = true;
|
||||
}
|
||||
_targetAdapter = value ? Gestouch.createGestureTargetAdapter(value) : null;
|
||||
installTarget(value);
|
||||
}
|
||||
|
||||
|
@ -117,11 +125,18 @@ package org.gestouch.gestures
|
|||
return;
|
||||
|
||||
_enabled = value;
|
||||
//TODO
|
||||
if (!_enabled && state != GestureState.IDLE)
|
||||
|
||||
if (!_enabled)
|
||||
{
|
||||
setState(GestureState.CANCELLED);
|
||||
reset();
|
||||
if (state == GestureState.POSSIBLE)
|
||||
{
|
||||
setState(GestureState.FAILED);
|
||||
}
|
||||
else
|
||||
if (state == GestureState.BEGAN || state == GestureState.CHANGED)
|
||||
{
|
||||
setState(GestureState.CANCELLED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,8 +163,8 @@ package org.gestouch.gestures
|
|||
}
|
||||
|
||||
|
||||
protected var _state:uint = GestureState.IDLE;
|
||||
public function get state():uint
|
||||
protected var _state:GestureState = GestureState.IDLE;
|
||||
public function get state():GestureState
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
@ -173,7 +188,6 @@ package org.gestouch.gestures
|
|||
*/
|
||||
public function get location():Point
|
||||
{
|
||||
//TODO: to clone or not clone? performance & convention or ...
|
||||
return _location.clone();
|
||||
}
|
||||
|
||||
|
@ -184,7 +198,7 @@ package org.gestouch.gestures
|
|||
//
|
||||
// Public methods
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
[Abstract]
|
||||
/**
|
||||
|
@ -213,7 +227,7 @@ package org.gestouch.gestures
|
|||
*/
|
||||
public function reset():void
|
||||
{
|
||||
var state:uint = this.state;//caching getter
|
||||
var state:GestureState = this.state;//caching getter
|
||||
|
||||
if (state == GestureState.IDLE)
|
||||
return;// Do nothing as we're in IDLE and nothing to reset
|
||||
|
@ -228,14 +242,14 @@ package org.gestouch.gestures
|
|||
var gestureToFail:Gesture = key as Gesture;
|
||||
gestureToFail.removeEventListener(GestureStateEvent.STATE_CHANGE, gestureToFail_stateChangeHandler);
|
||||
}
|
||||
_pendingRecognizedState = 0;
|
||||
_pendingRecognizedState = null;
|
||||
|
||||
if (state == GestureState.POSSIBLE)
|
||||
{
|
||||
// manual reset() call. Set to FAILED to keep our State Machine clean and stable
|
||||
setState(GestureState.FAILED);
|
||||
}
|
||||
else if (state == GestureState.BEGAN || state == GestureState.RECOGNIZED)
|
||||
else if (state == GestureState.BEGAN || state == GestureState.CHANGED)
|
||||
{
|
||||
// manual reset() call. Set to CANCELLED to keep our State Machine clean and stable
|
||||
setState(GestureState.CANCELLED);
|
||||
|
@ -285,6 +299,11 @@ package org.gestouch.gestures
|
|||
public function requireGestureToFail(gesture:Gesture):void
|
||||
{
|
||||
//TODO
|
||||
if (!gesture)
|
||||
{
|
||||
throw new ArgumentError();
|
||||
}
|
||||
|
||||
_gesturesToFail[gesture] = true;
|
||||
}
|
||||
|
||||
|
@ -310,11 +329,11 @@ package org.gestouch.gestures
|
|||
*
|
||||
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html
|
||||
*/
|
||||
protected function installTarget(target:InteractiveObject):void
|
||||
protected function installTarget(target:Object):void
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
_gesturesManager.gestouch_internal::addGesture(this);
|
||||
_gesturesManager.addGesture(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,11 +345,11 @@ package org.gestouch.gestures
|
|||
*
|
||||
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html
|
||||
*/
|
||||
protected function uninstallTarget(target:InteractiveObject):void
|
||||
protected function uninstallTarget(target:Object):void
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
_gesturesManager.gestouch_internal::removeGesture(this);
|
||||
_gesturesManager.removeGesture(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,30 +394,33 @@ package org.gestouch.gestures
|
|||
}
|
||||
|
||||
|
||||
protected function setState(newState:uint):Boolean
|
||||
protected function setState(newState:GestureState):Boolean
|
||||
{
|
||||
if (_state == newState && _state == GestureState.CHANGED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO: is state sequence validation needed? e.g.:
|
||||
//POSSIBLE should be followed by BEGAN or RECOGNIZED or FAILED
|
||||
//BEGAN should be follwed by CHANGED or ENDED or CANCELLED
|
||||
//CHANGED should be followed by CHANGED or ENDED or CANCELLED
|
||||
//...
|
||||
if (!_state.canTransitionTo(newState))
|
||||
{
|
||||
throw new IllegalOperationError("You cannot change from state " +
|
||||
_state + " to state " + newState + ".");
|
||||
}
|
||||
|
||||
|
||||
if (newState == GestureState.BEGAN || newState == GestureState.RECOGNIZED)
|
||||
{
|
||||
var gestureToFail:Gesture;
|
||||
var key:*;
|
||||
// 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)
|
||||
for (key in _gesturesToFail)
|
||||
{
|
||||
gestureToFail = key as Gesture;
|
||||
if (gestureToFail.state != GestureState.IDLE && gestureToFail.state != GestureState.POSSIBLE
|
||||
&& gestureToFail.state != GestureState.FAILED)
|
||||
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
|
||||
|
@ -406,7 +428,7 @@ package org.gestouch.gestures
|
|||
return false;
|
||||
}
|
||||
}
|
||||
// then we check of other required-to-fail gestures are actually tracked (not IDLE)
|
||||
// then we check if other required-to-fail gestures are actually tracked (not IDLE)
|
||||
// and not still not recognized (e.g. POSSIBLE state)
|
||||
for (key in _gesturesToFail)
|
||||
{
|
||||
|
@ -415,6 +437,13 @@ package org.gestouch.gestures
|
|||
{
|
||||
// Other gesture might fail soon, so we postpone state change
|
||||
_pendingRecognizedState = newState;
|
||||
|
||||
for (key in _gesturesToFail)
|
||||
{
|
||||
gestureToFail = key as Gesture;
|
||||
gestureToFail.addEventListener(GestureStateEvent.STATE_CHANGE, gestureToFail_stateChangeHandler, false, 0, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// else if gesture is in IDLE state it means it doesn't track anything,
|
||||
|
@ -430,12 +459,12 @@ package org.gestouch.gestures
|
|||
}
|
||||
}
|
||||
|
||||
var oldState:uint = _state;
|
||||
var oldState:GestureState = _state;
|
||||
_state = newState;
|
||||
|
||||
if (((GestureState.CANCELLED | GestureState.RECOGNIZED | GestureState.ENDED | GestureState.FAILED) & _state) > 0)
|
||||
if (_state.isEndState)
|
||||
{
|
||||
_gesturesManager.gestouch_internal::scheduleGestureStateReset(this);
|
||||
_gesturesManager.scheduleGestureStateReset(this);
|
||||
}
|
||||
|
||||
//TODO: what if RTE happens in event handlers?
|
||||
|
@ -447,14 +476,14 @@ package org.gestouch.gestures
|
|||
|
||||
if (_state == GestureState.BEGAN || _state == GestureState.RECOGNIZED)
|
||||
{
|
||||
_gesturesManager.gestouch_internal::onGestureRecognized(this);
|
||||
_gesturesManager.onGestureRecognized(this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
gestouch_internal function setState_internal(state:uint):void
|
||||
gestouch_internal function setState_internal(state:GestureState):void
|
||||
{
|
||||
setState(state);
|
||||
}
|
||||
|
@ -481,7 +510,7 @@ package org.gestouch.gestures
|
|||
updateCentralPoint();
|
||||
_location.x = _centralPoint.x;
|
||||
_location.y = _centralPoint.y;
|
||||
_localLocation = target.globalToLocal(_location);
|
||||
_localLocation = targetAdapter.globalToLocal(_location);
|
||||
}
|
||||
|
||||
|
||||
|
@ -513,12 +542,6 @@ package org.gestouch.gestures
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -542,10 +565,7 @@ package org.gestouch.gestures
|
|||
|
||||
protected function gestureToFail_stateChangeHandler(event:GestureStateEvent):void
|
||||
{
|
||||
if (state != GestureState.POSSIBLE)
|
||||
return;//just in case..FIXME?
|
||||
|
||||
if (!_pendingRecognizedState)
|
||||
if (!_pendingRecognizedState || state != GestureState.POSSIBLE)
|
||||
return;
|
||||
|
||||
if (event.newState == GestureState.FAILED)
|
||||
|
@ -560,15 +580,20 @@ package org.gestouch.gestures
|
|||
}
|
||||
}
|
||||
|
||||
// at this point all gestures-to-fail are either in IDLE or in FAILED states
|
||||
if (setState(_pendingRecognizedState))
|
||||
{
|
||||
onDelayedRecognize();
|
||||
}
|
||||
}
|
||||
else if (event.newState != GestureState.POSSIBLE)
|
||||
else if (event.newState != GestureState.IDLE && event.newState != GestureState.POSSIBLE)
|
||||
{
|
||||
// NB: _other_ gesture may switch to IDLE state if it was in FAILED when
|
||||
// _this_ gesture initially attempted to switch to one of recognized state.
|
||||
// ...and that's OK (we ignore that)
|
||||
|
||||
setState(GestureState.FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,11 +4,15 @@ package org.gestouch.gestures
|
|||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.events.LongPressGestureEvent;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.utils.Timer;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @eventType org.gestouch.events.LongPressGestureEvent
|
||||
*/
|
||||
[Event(name="gestureLongPress", type="org.gestouch.events.LongPressGestureEvent")]
|
||||
/**
|
||||
* TODO: -location
|
||||
* - check on iOS (Obj-C) what happens when numTouchesRequired=2, two finger down, then quickly release one.
|
||||
|
@ -30,7 +34,7 @@ package org.gestouch.gestures
|
|||
protected var _numTouchesRequiredReached:Boolean;
|
||||
|
||||
|
||||
public function LongPressGesture(target:InteractiveObject = null)
|
||||
public function LongPressGesture(target:Object = null)
|
||||
{
|
||||
super(target);
|
||||
}
|
||||
|
@ -124,7 +128,7 @@ package org.gestouch.gestures
|
|||
//TODO: check proper condition (behavior) on iOS native
|
||||
if (_numTouchesRequiredReached)
|
||||
{
|
||||
if (((GestureState.BEGAN | GestureState.CHANGED) & state) > 0)
|
||||
if (state == GestureState.BEGAN || state == GestureState.CHANGED)
|
||||
{
|
||||
updateLocation();
|
||||
if (setState(GestureState.ENDED) && hasEventListener(LongPressGestureEvent.GESTURE_LONG_PRESS))
|
||||
|
|
|
@ -4,9 +4,13 @@ package org.gestouch.gestures
|
|||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.events.PanGestureEvent;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @eventType org.gestouch.events.PanGestureEvent
|
||||
*/
|
||||
[Event(name="gesturePan", type="org.gestouch.events.PanGestureEvent")]
|
||||
/**
|
||||
* TODO:
|
||||
|
@ -27,7 +31,7 @@ package org.gestouch.gestures
|
|||
protected var _gestureBeginOffsetY:Number;
|
||||
|
||||
|
||||
public function PanGesture(target:InteractiveObject = null)
|
||||
public function PanGesture(target:Object = null)
|
||||
{
|
||||
super(target);
|
||||
}
|
||||
|
|
|
@ -5,9 +5,13 @@ package org.gestouch.gestures
|
|||
import org.gestouch.events.RotateGestureEvent;
|
||||
import org.gestouch.utils.GestureUtils;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @eventType org.gestouch.events.RotateGestureEvent
|
||||
*/
|
||||
[Event(name="gestureRotate", type="org.gestouch.events.RotateGestureEvent")]
|
||||
/**
|
||||
* TODO:
|
||||
|
@ -24,7 +28,7 @@ package org.gestouch.gestures
|
|||
protected var _transformVector:Point;
|
||||
|
||||
|
||||
public function RotateGesture(target:InteractiveObject = null)
|
||||
public function RotateGesture(target:Object = null)
|
||||
{
|
||||
super(target);
|
||||
}
|
||||
|
|
|
@ -4,9 +4,13 @@ package org.gestouch.gestures
|
|||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.events.SwipeGestureEvent;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @eventType org.gestouch.events.SwipeGestureEvent
|
||||
*/
|
||||
[Event(name="gestureSwipe", type="org.gestouch.events.SwipeGestureEvent")]
|
||||
/**
|
||||
* TODO:
|
||||
|
@ -31,7 +35,7 @@ package org.gestouch.gestures
|
|||
protected var _decelerationCounter:uint = 0;
|
||||
|
||||
|
||||
public function SwipeGesture(target:InteractiveObject = null)
|
||||
public function SwipeGesture(target:Object = null)
|
||||
{
|
||||
super(target);
|
||||
}
|
||||
|
@ -143,7 +147,7 @@ package org.gestouch.gestures
|
|||
{
|
||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||
{
|
||||
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
||||
_localLocation = targetAdapter.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));
|
||||
}
|
||||
|
@ -179,7 +183,7 @@ package org.gestouch.gestures
|
|||
_offset.y = 0;
|
||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||
{
|
||||
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
||||
_localLocation = targetAdapter.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));
|
||||
}
|
||||
|
@ -207,7 +211,7 @@ package org.gestouch.gestures
|
|||
_offset.x = 0;
|
||||
if (setState(GestureState.RECOGNIZED) && hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||
{
|
||||
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
||||
_localLocation = targetAdapter.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));
|
||||
}
|
||||
|
@ -234,7 +238,7 @@ package org.gestouch.gestures
|
|||
{
|
||||
if (hasEventListener(SwipeGestureEvent.GESTURE_SWIPE))
|
||||
{
|
||||
_localLocation = target.globalToLocal(_location);//refresh local location in case target moved
|
||||
_localLocation = targetAdapter.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));
|
||||
}
|
||||
|
|
|
@ -4,11 +4,14 @@ package org.gestouch.gestures
|
|||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.events.TapGestureEvent;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.utils.Timer;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @eventType org.gestouch.events.TapGestureEvent
|
||||
*/
|
||||
[Event(name="gestureTap", type="org.gestouch.events.TapGestureEvent")]
|
||||
/**
|
||||
* TODO: check failing conditions (iDevice)
|
||||
|
@ -28,7 +31,7 @@ package org.gestouch.gestures
|
|||
protected var _tapCounter:uint = 0;
|
||||
|
||||
|
||||
public function TapGesture(target:InteractiveObject = null)
|
||||
public function TapGesture(target:Object = null)
|
||||
{
|
||||
super(target);
|
||||
}
|
||||
|
|
|
@ -5,10 +5,13 @@ package org.gestouch.gestures
|
|||
import org.gestouch.events.TransformGestureEvent;
|
||||
import org.gestouch.utils.GestureUtils;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @eventType org.gestouch.events.TransformGestureEvent
|
||||
*/
|
||||
[Event(name="gestureTransform", type="org.gestouch.events.TransformGestureEvent")]
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
|
@ -22,7 +25,7 @@ package org.gestouch.gestures
|
|||
protected var _transformVector:Point;
|
||||
|
||||
|
||||
public function TransformGesture(target:InteractiveObject = null)
|
||||
public function TransformGesture(target:Object = null)
|
||||
{
|
||||
super(target);
|
||||
}
|
||||
|
@ -127,7 +130,7 @@ package org.gestouch.gestures
|
|||
{
|
||||
// Note that we dispatch previous location point which gives a way to perform
|
||||
// accurate UI redraw. See examples project for more info.
|
||||
prevLocalLocation = target.globalToLocal(prevLocation);
|
||||
prevLocalLocation = targetAdapter.globalToLocal(prevLocation);
|
||||
dispatchEvent(new TransformGestureEvent(TransformGestureEvent.GESTURE_TRANSFORM, false, false, GestureState.BEGAN,
|
||||
prevLocation.x, prevLocation.y, prevLocalLocation.x, prevLocalLocation.y, scale, scale, rotation, offsetX, offsetY));
|
||||
}
|
||||
|
@ -138,7 +141,7 @@ package org.gestouch.gestures
|
|||
{
|
||||
// Note that we dispatch previous location point which gives a way to perform
|
||||
// accurate UI redraw. See examples project for more info.
|
||||
prevLocalLocation = target.globalToLocal(prevLocation);
|
||||
prevLocalLocation = targetAdapter.globalToLocal(prevLocation);
|
||||
dispatchEvent(new TransformGestureEvent(TransformGestureEvent.GESTURE_TRANSFORM, false, false, GestureState.CHANGED,
|
||||
prevLocation.x, prevLocation.y, prevLocalLocation.x, prevLocalLocation.y, scale, scale, rotation, offsetX, offsetY));
|
||||
}
|
||||
|
|
|
@ -4,9 +4,13 @@ package org.gestouch.gestures
|
|||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.events.ZoomGestureEvent;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.geom.Point;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @eventType org.gestouch.events.ZoomGestureEvent
|
||||
*/
|
||||
[Event(name="gestureZoom", type="org.gestouch.events.ZoomGestureEvent")]
|
||||
/**
|
||||
* TODO:
|
||||
|
@ -24,7 +28,7 @@ package org.gestouch.gestures
|
|||
protected var _transformVector:Point;
|
||||
|
||||
|
||||
public function ZoomGesture(target:InteractiveObject = null)
|
||||
public function ZoomGesture(target:Object = null)
|
||||
{
|
||||
super(target);
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
package org.gestouch.input
|
||||
{
|
||||
import org.gestouch.core.IGesturesManager;
|
||||
import org.gestouch.core.IInputAdapter;
|
||||
import org.gestouch.core.ITouchesManager;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class AbstractInputAdapter implements IInputAdapter
|
||||
{
|
||||
protected var _touchesManager:ITouchesManager;
|
||||
protected var _gesturesManager:IGesturesManager;
|
||||
|
||||
|
||||
public function AbstractInputAdapter()
|
||||
{
|
||||
if (Object(this).constructor == AbstractInputAdapter)
|
||||
{
|
||||
throw new Error("This is abstract class and should not be directly instantiated.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function set touchesManager(value:ITouchesManager):void
|
||||
{
|
||||
_touchesManager = value;
|
||||
}
|
||||
|
||||
|
||||
public function set gesturesManager(value:IGesturesManager):void
|
||||
{
|
||||
_gesturesManager = value;
|
||||
}
|
||||
|
||||
|
||||
[Abstract]
|
||||
public function init():void
|
||||
{
|
||||
throw new Error("This is abstract method.");
|
||||
}
|
||||
|
||||
|
||||
[Abstract]
|
||||
public function dispose():void
|
||||
{
|
||||
throw new Error("This is abstract method.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
package org.gestouch.input
|
||||
{
|
||||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.core.gestouch_internal;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Stage;
|
||||
import flash.events.EventPhase;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.geom.Point;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class MouseInputAdapter extends AbstractInputAdapter
|
||||
{
|
||||
private static const PRIMARY_TOUCH_POINT_ID:uint = 0;
|
||||
|
||||
protected var _stage:Stage;
|
||||
|
||||
|
||||
public function MouseInputAdapter(stage:Stage)
|
||||
{
|
||||
super();
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
throw new Error("Stage must be not null.");
|
||||
}
|
||||
|
||||
_stage = stage;
|
||||
}
|
||||
|
||||
|
||||
override public function init():void
|
||||
{
|
||||
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);// to catch with EventPhase.AT_TARGET
|
||||
}
|
||||
|
||||
|
||||
override public function dispose():void
|
||||
{
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
|
||||
uninstallStageListeners();
|
||||
}
|
||||
|
||||
|
||||
protected function installStageListeners():void
|
||||
{
|
||||
// Maximum priority to prevent event hijacking
|
||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true, int.MAX_VALUE);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false, int.MAX_VALUE);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true, int.MAX_VALUE);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, int.MAX_VALUE);
|
||||
}
|
||||
|
||||
|
||||
protected function uninstallStageListeners():void
|
||||
{
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true);
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true);
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
|
||||
}
|
||||
|
||||
|
||||
protected function mouseDownHandler(event:MouseEvent):void
|
||||
{
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;//we listen in capture or at_target (to catch on empty stage)
|
||||
// Way to prevent MouseEvent/TouchEvent collisions.
|
||||
// Also helps to ignore possible fake events.
|
||||
if (_touchesManager.hasTouch(PRIMARY_TOUCH_POINT_ID))
|
||||
return;
|
||||
|
||||
installStageListeners();
|
||||
|
||||
var touch:Touch = _touchesManager.createTouch();
|
||||
touch.target = event.target as InteractiveObject;
|
||||
touch.id = PRIMARY_TOUCH_POINT_ID;
|
||||
touch.gestouch_internal::setLocation(new Point(event.stageX, event.stageY));
|
||||
touch.gestouch_internal::setTime(getTimer());
|
||||
touch.gestouch_internal::setBeginTime(getTimer());
|
||||
|
||||
_touchesManager.addTouch(touch);
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchBegin(touch);
|
||||
}
|
||||
|
||||
|
||||
protected function mouseMoveHandler(event:MouseEvent):void
|
||||
{
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;//we listen in capture or at_target (to catch on empty stage)
|
||||
// Way to prevent MouseEvent/TouchEvent collisions.
|
||||
// Also helps to ignore possible fake events.
|
||||
if (!_touchesManager.hasTouch(PRIMARY_TOUCH_POINT_ID))
|
||||
return;
|
||||
|
||||
var touch:Touch = _touchesManager.getTouch(PRIMARY_TOUCH_POINT_ID);
|
||||
touch.gestouch_internal::updateLocation(event.stageX, event.stageY);
|
||||
touch.gestouch_internal::setTime(getTimer());
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchMove(touch);
|
||||
}
|
||||
|
||||
|
||||
protected function mouseUpHandler(event:MouseEvent):void
|
||||
{
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;//we listen in capture or at_target (to catch on empty stage)
|
||||
|
||||
// Way to prevent MouseEvent/TouchEvent collisions.
|
||||
// Also helps to ignore possible fake events.
|
||||
if (!_touchesManager.hasTouch(PRIMARY_TOUCH_POINT_ID))
|
||||
return;
|
||||
|
||||
var touch:Touch = _touchesManager.getTouch(PRIMARY_TOUCH_POINT_ID);
|
||||
touch.gestouch_internal::updateLocation(event.stageX, event.stageY);
|
||||
touch.gestouch_internal::setTime(getTimer());
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchEnd(touch);
|
||||
|
||||
_touchesManager.removeTouch(touch);
|
||||
|
||||
if (_touchesManager.activeTouchesCount == 0)
|
||||
{
|
||||
uninstallStageListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
224
src/org/gestouch/input/NativeInputAdapter.as
Normal file
224
src/org/gestouch/input/NativeInputAdapter.as
Normal file
|
@ -0,0 +1,224 @@
|
|||
package org.gestouch.input
|
||||
{
|
||||
import org.gestouch.core.IInputAdapter;
|
||||
import org.gestouch.core.TouchesManager;
|
||||
import org.gestouch.core.gestouch_internal;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Stage;
|
||||
import flash.events.EventPhase;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.events.TouchEvent;
|
||||
import flash.ui.Multitouch;
|
||||
import flash.ui.MultitouchInputMode;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class NativeInputAdapter implements IInputAdapter
|
||||
{
|
||||
protected static const MOUSE_TOUCH_POINT_ID:uint = 0;
|
||||
|
||||
protected var _stage:Stage;
|
||||
protected var _explicitlyHandleTouchEvents:Boolean;
|
||||
protected var _explicitlyHandleMouseEvents:Boolean;
|
||||
|
||||
use namespace gestouch_internal;
|
||||
|
||||
|
||||
{
|
||||
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
|
||||
}
|
||||
|
||||
|
||||
public function NativeInputAdapter(stage:Stage,
|
||||
explicitlyHandleTouchEvents:Boolean = false,
|
||||
explicitlyHandleMouseEvents:Boolean = false)
|
||||
{
|
||||
super();
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
throw new ArgumentError("Stage must be not null.");
|
||||
}
|
||||
|
||||
_stage = stage;
|
||||
|
||||
_explicitlyHandleTouchEvents = explicitlyHandleTouchEvents;
|
||||
_explicitlyHandleMouseEvents = explicitlyHandleMouseEvents;
|
||||
}
|
||||
|
||||
|
||||
protected var _touchesManager:TouchesManager;
|
||||
public function set touchesManager(value:TouchesManager):void
|
||||
{
|
||||
_touchesManager = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Public methods
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
public function init():void
|
||||
{
|
||||
if (Multitouch.supportsTouchEvents || _explicitlyHandleTouchEvents)
|
||||
{
|
||||
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, false);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false);
|
||||
// Maximum priority to prevent event hijacking and loosing the touch
|
||||
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, true, int.MAX_VALUE);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, false, int.MAX_VALUE);
|
||||
}
|
||||
|
||||
if (!Multitouch.supportsTouchEvents || _explicitlyHandleMouseEvents)
|
||||
{
|
||||
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function onDispose():void
|
||||
{
|
||||
_touchesManager = null;
|
||||
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, false);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, true);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, false);
|
||||
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, true);
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler, false);
|
||||
unstallMouseListeners();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
protected function installMouseListeners():void
|
||||
{
|
||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false);
|
||||
// Maximum priority to prevent event hijacking
|
||||
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true, int.MAX_VALUE);
|
||||
_stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false, int.MAX_VALUE);
|
||||
}
|
||||
|
||||
|
||||
protected function unstallMouseListeners():void
|
||||
{
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, true);
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler, false);
|
||||
// Maximum priority to prevent event hijacking
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, true);
|
||||
_stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Event handlers
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
protected function touchBeginHandler(event:TouchEvent):void
|
||||
{
|
||||
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||
// (to catch on empty stage) phases only
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;
|
||||
|
||||
_touchesManager.onTouchBegin(event.touchPointID, event.stageX, event.stageY, event.target as InteractiveObject);
|
||||
}
|
||||
|
||||
|
||||
protected function touchMoveHandler(event:TouchEvent):void
|
||||
{
|
||||
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||
// (to catch on empty stage) phases only
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;
|
||||
|
||||
_touchesManager.onTouchMove(event.touchPointID, event.stageX, event.stageY);
|
||||
}
|
||||
|
||||
|
||||
protected function touchEndHandler(event:TouchEvent):void
|
||||
{
|
||||
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||
// (to catch on empty stage) phases only
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;
|
||||
|
||||
if (event.hasOwnProperty("isTouchPointCanceled") && event["isTouchPointCanceled"])
|
||||
{
|
||||
_touchesManager.onTouchCancel(event.touchPointID, event.stageX, event.stageY);
|
||||
}
|
||||
else
|
||||
{
|
||||
_touchesManager.onTouchEnd(event.touchPointID, event.stageX, event.stageY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function mouseDownHandler(event:MouseEvent):void
|
||||
{
|
||||
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||
// (to catch on empty stage) phases only
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;
|
||||
|
||||
const touchAccepted:Boolean = _touchesManager.onTouchBegin(MOUSE_TOUCH_POINT_ID, event.stageX, event.stageY, event.target as InteractiveObject);
|
||||
|
||||
if (touchAccepted)
|
||||
{
|
||||
installMouseListeners();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function mouseMoveHandler(event:MouseEvent):void
|
||||
{
|
||||
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||
// (to catch on empty stage) phases only
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;
|
||||
|
||||
_touchesManager.onTouchMove(MOUSE_TOUCH_POINT_ID, event.stageX, event.stageY);
|
||||
}
|
||||
|
||||
|
||||
protected function mouseUpHandler(event:MouseEvent):void
|
||||
{
|
||||
// We listen in EventPhase.CAPTURE_PHASE or EventPhase.AT_TARGET
|
||||
// (to catch on empty stage) phases only
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;
|
||||
|
||||
_touchesManager.onTouchEnd(MOUSE_TOUCH_POINT_ID, event.stageX, event.stageY);
|
||||
|
||||
if (_touchesManager.activeTouchesCount == 0)
|
||||
{
|
||||
unstallMouseListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,33 @@
|
|||
package org.gestouch.input
|
||||
{
|
||||
import org.gestouch.input.AbstractInputAdapter;
|
||||
import org.gestouch.core.IInputAdapter;
|
||||
import org.gestouch.core.TouchesManager;
|
||||
|
||||
|
||||
/**
|
||||
* TODO: You can implement your own TUIO Input Adapter (and supply touchesManager with
|
||||
* touch info), but IMHO it is way easier to use NativeInputAdapter and any TUIO library
|
||||
* and manually dispatch native TouchEvents using DisplayObjectContainer#getObjectsUnderPoint()
|
||||
*
|
||||
* @see NativeInputAdapter
|
||||
* @see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html#getObjectsUnderPoint() DisplayObjectContainer#getObjectsUnderPoint()
|
||||
*
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class TUIOInputAdapter extends AbstractInputAdapter
|
||||
public class TUIOInputAdapter implements IInputAdapter
|
||||
{
|
||||
public function TUIOInputAdapter()
|
||||
public function init():void
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function onDispose():void
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function set touchesManager(value:TouchesManager):void
|
||||
{
|
||||
super();
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,186 +0,0 @@
|
|||
package org.gestouch.input
|
||||
{
|
||||
import org.gestouch.core.Touch;
|
||||
import org.gestouch.core.gestouch_internal;
|
||||
|
||||
import flash.display.InteractiveObject;
|
||||
import flash.display.Stage;
|
||||
import flash.events.EventPhase;
|
||||
import flash.events.TouchEvent;
|
||||
import flash.geom.Point;
|
||||
import flash.ui.Multitouch;
|
||||
import flash.ui.MultitouchInputMode;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
|
||||
/**
|
||||
* @author Pavel fljot
|
||||
*/
|
||||
public class TouchInputAdapter extends AbstractInputAdapter
|
||||
{
|
||||
protected var _stage:Stage;
|
||||
/**
|
||||
* The hash map of touches instantiated via TouchEvent.
|
||||
* Used to avoid collisions (double processing) with MouseInputAdapter.
|
||||
*
|
||||
* TODO: any better way?
|
||||
*/
|
||||
protected var _touchesMap:Object = {};
|
||||
|
||||
{
|
||||
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
|
||||
}
|
||||
|
||||
|
||||
public function TouchInputAdapter(stage:Stage)
|
||||
{
|
||||
super();
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
throw new Error("Stage must be not null.");
|
||||
}
|
||||
|
||||
_stage = stage;
|
||||
}
|
||||
|
||||
|
||||
override public function init():void
|
||||
{
|
||||
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);// to catch with EventPhase.AT_TARGET
|
||||
}
|
||||
|
||||
|
||||
override public function dispose():void
|
||||
{
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler, true);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_BEGIN, touchBeginHandler);
|
||||
uninstallStageListeners();
|
||||
}
|
||||
|
||||
|
||||
protected function installStageListeners():void
|
||||
{
|
||||
// Maximum priority to prevent event hijacking
|
||||
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true, int.MAX_VALUE);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, false, int.MAX_VALUE);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, true, int.MAX_VALUE);
|
||||
_stage.addEventListener(TouchEvent.TOUCH_END, touchEndHandler, false, int.MAX_VALUE);
|
||||
}
|
||||
|
||||
|
||||
protected function uninstallStageListeners():void
|
||||
{
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler, true);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_MOVE, touchMoveHandler);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler, true);
|
||||
_stage.removeEventListener(TouchEvent.TOUCH_END, touchEndHandler);
|
||||
}
|
||||
|
||||
|
||||
protected function touchBeginHandler(event:TouchEvent):void
|
||||
{
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;//we listen in capture or at_target (to catch on empty stage)
|
||||
// Way to prevent MouseEvent/TouchEvent collisions.
|
||||
// Also helps to ignore possible fake events.
|
||||
if (_touchesManager.hasTouch(event.touchPointID))
|
||||
return;
|
||||
|
||||
installStageListeners();
|
||||
|
||||
var touch:Touch = _touchesManager.createTouch();
|
||||
touch.id = event.touchPointID;
|
||||
touch.target = event.target as InteractiveObject;
|
||||
touch.gestouch_internal::setLocation(new Point(event.stageX, event.stageY));
|
||||
touch.sizeX = event.sizeX;
|
||||
touch.sizeY = event.sizeY;
|
||||
touch.pressure = event.pressure;
|
||||
//TODO: conditional compilation?
|
||||
if (event.hasOwnProperty("timestamp"))
|
||||
{
|
||||
touch.gestouch_internal::setTime(event["timestamp"]);
|
||||
touch.gestouch_internal::setBeginTime(event["timestamp"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
touch.gestouch_internal::setTime(getTimer());
|
||||
touch.gestouch_internal::setBeginTime(getTimer());
|
||||
}
|
||||
|
||||
_touchesManager.addTouch(touch);
|
||||
_touchesMap[touch.id] = true;
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchBegin(touch);
|
||||
}
|
||||
|
||||
|
||||
protected function touchMoveHandler(event:TouchEvent):void
|
||||
{
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;//we listen in capture or at_target (to catch on empty stage)
|
||||
// Way to prevent MouseEvent/TouchEvent collisions.
|
||||
// Also helps to ignore possible fake events.
|
||||
if (!_touchesManager.hasTouch(event.touchPointID) || !_touchesMap.hasOwnProperty(event.touchPointID))
|
||||
return;
|
||||
|
||||
var touch:Touch = _touchesManager.getTouch(event.touchPointID);
|
||||
touch.gestouch_internal::updateLocation(event.stageX, event.stageY);
|
||||
touch.sizeX = event.sizeX;
|
||||
touch.sizeY = event.sizeY;
|
||||
touch.pressure = event.pressure;
|
||||
//TODO: conditional compilation?
|
||||
if (event.hasOwnProperty("timestamp"))
|
||||
{
|
||||
touch.gestouch_internal::setTime(event["timestamp"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
touch.gestouch_internal::setTime(getTimer());
|
||||
}
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchMove(touch);
|
||||
}
|
||||
|
||||
|
||||
protected function touchEndHandler(event:TouchEvent):void
|
||||
{
|
||||
if (event.eventPhase == EventPhase.BUBBLING_PHASE)
|
||||
return;//we listen in capture or at_target (to catch on empty stage)
|
||||
|
||||
// Way to prevent MouseEvent/TouchEvent collisions.
|
||||
// Also helps to ignore possible fake events.
|
||||
if (!_touchesManager.hasTouch(event.touchPointID))
|
||||
return;
|
||||
|
||||
var touch:Touch = _touchesManager.getTouch(event.touchPointID);
|
||||
touch.gestouch_internal::updateLocation(event.stageX, event.stageY);
|
||||
touch.sizeX = event.sizeX;
|
||||
touch.sizeY = event.sizeY;
|
||||
touch.pressure = event.pressure;
|
||||
//TODO: conditional compilation?
|
||||
if (event.hasOwnProperty("timestamp"))
|
||||
{
|
||||
touch.gestouch_internal::setTime(event["timestamp"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
touch.gestouch_internal::setTime(getTimer());
|
||||
}
|
||||
|
||||
_gesturesManager.gestouch_internal::onTouchEnd(touch);
|
||||
|
||||
_touchesManager.removeTouch(touch);
|
||||
delete _touchesMap[touch.id];
|
||||
|
||||
if (_touchesManager.activeTouchesCount == 0)
|
||||
{
|
||||
uninstallStageListeners();
|
||||
}
|
||||
|
||||
// TODO: handle cancelled touch:
|
||||
// if (event.hasOwnProperty("isTouchPointCanceled") && event["isTouchPointCanceled"] && ...
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package org.gestouch.utils
|
||||
{
|
||||
import flash.geom.Point;
|
||||
import flash.system.Capabilities;
|
||||
/**
|
||||
* Set of constants.
|
||||
|
@ -24,5 +25,6 @@ package org.gestouch.utils
|
|||
* Precalculated coefficient Math.PI * 2
|
||||
*/
|
||||
public static const PI_DOUBLE:Number = Math.PI * 2;
|
||||
public static const GLOBAL_ZERO:Point = new Point();
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
project.version = 0.3.1
|
||||
project.version = 0.4-alpha
|
Loading…
Reference in a new issue