• TransformTool.as


    package com.senocular.display {
        
        import flash.display.DisplayObject;
        import flash.display.DisplayObjectContainer;
        import flash.display.Shape;
        import flash.display.Sprite;
        import flash.display.Stage;
        import flash.events.Event;
        import flash.events.EventPhase;
        import flash.events.MouseEvent;
        import flash.geom.Matrix;
        import flash.geom.Point;
        import flash.geom.Rectangle;
        import flash.geom.Transform;
        import flash.utils.Dictionary;
        
        
    // TODO: Documentation
        
    // TODO: Handle 0-size transformations
        
        
    /**
         
    * Creates a transform tool that allows uaers to modify display objects on the screen
         
    * 
         
    * @usage
         
    * <pre>
         
    * var tool:TransformTool = new TransformTool();
         
    * addChild(tool);
         
    * tool.target = targetDisplayObject;
         
    * </pre>
         
    * 
         
    * @version 0.9.10
         
    * @author  Trevor McCauley
         
    * @author  http://www.senocular.com
         
    */
        
    public class TransformTool extends Sprite {
            
            
    // Variables
            
    private var toolInvertedMatrix:Matrix = new Matrix();
            
    private var innerRegistration:Point = new Point();
            
    private var registrationLog:Dictionary = new Dictionary(true);
            
            
    private var targetBounds:Rectangle = new Rectangle();
            
            
    private var mouseLoc:Point = new Point();
            
    private var mouseOffset:Point = new Point();
            
    private var innerMouseLoc:Point = new Point();
            
    private var interactionStart:Point = new Point();
            
    private var innerInteractionStart:Point = new Point();
            
    private var interactionStartAngle:Number = 0;
            
    private var interactionStartMatrix:Matrix = new Matrix();
            
            
    private var toolSprites:Sprite = new Sprite();
            
    private var lines:Sprite = new Sprite();
            
    private var moveControls:Sprite = new Sprite();
            
    private var registrationControls:Sprite = new Sprite();
            
    private var rotateControls:Sprite = new Sprite();
            
    private var scaleControls:Sprite = new Sprite();
            
    private var skewControls:Sprite = new Sprite();
            
    private var cursors:Sprite = new Sprite();
            
    private var customControls:Sprite = new Sprite();
            
    private var customCursors:Sprite = new Sprite();
            
            
    // With getter/setters
            
    private var _target:DisplayObject;
            
    private var _toolMatrix:Matrix = new Matrix();
            
    private var _globalMatrix:Matrix = new Matrix();
            
            
    private var _registration:Point = new Point();
            
            
    private var _livePreview:Boolean = true;
            
    private var _raiseNewTargets:Boolean = true;
            
    private var _moveNewTargets:Boolean = false;
            
    private var _moveEnabled:Boolean = true;
            
    private var _registrationEnabled:Boolean = true;
            
    private var _rotationEnabled:Boolean = true;
            
    private var _scaleEnabled:Boolean = true
            
    private var _skewEnabled:Boolean = true;
            
    private var _outlineEnabled:Boolean = true;
            
    private var _customControlsEnabled:Boolean = true;
            
    private var _customCursorsEnabled:Boolean = true;
            
    private var _cursorsEnabled:Boolean = true
            
    private var _rememberRegistration:Boolean = true;
            
            
    private var _constrainScale:Boolean = false;
            
    private var _constrainRotationAngle:Number = Math.PI/4// default at 45 degrees
            
    private var _constrainRotation:Boolean = false;
            
            
    private var _moveUnderObjects:Boolean = true;
            
    private var _maintainControlForm:Boolean = true;
            
    private var _controlSize:Number = 8;
                
            
    private var _maxScaleX:Number = Infinity;
            
    private var _maxScaleY:Number = Infinity;
            
            
    private var _boundsTopLeft:Point = new Point();
            
    private var _boundsTop:Point = new Point();
            
    private var _boundsTopRight:Point = new Point();
            
    private var _boundsRight:Point = new Point();
            
    private var _boundsBottomRight:Point = new Point();
            
    private var _boundsBottom:Point = new Point();
            
    private var _boundsBottomLeft:Point = new Point();
            
    private var _boundsLeft:Point = new Point();
            
    private var _boundsCenter:Point = new Point();
            
            
    private var _currentControl:TransformToolControl;
            
            
    private var _moveControl:TransformToolControl;
            
    private var _registrationControl:TransformToolControl;
            
    private var _outlineControl:TransformToolControl;
            
    private var _scaleTopLeftControl:TransformToolControl;
            
    private var _scaleTopControl:TransformToolControl;
            
    private var _scaleTopRightControl:TransformToolControl;
            
    private var _scaleRightControl:TransformToolControl;
            
    private var _scaleBottomRightControl:TransformToolControl;
            
    private var _scaleBottomControl:TransformToolControl;
            
    private var _scaleBottomLeftControl:TransformToolControl;
            
    private var _scaleLeftControl:TransformToolControl;
            
    private var _rotationTopLeftControl:TransformToolControl;
            
    private var _rotationTopRightControl:TransformToolControl;
            
    private var _rotationBottomRightControl:TransformToolControl;
            
    private var _rotationBottomLeftControl:TransformToolControl;
            
    private var _skewTopControl:TransformToolControl;
            
    private var _skewRightControl:TransformToolControl;
            
    private var _skewBottomControl:TransformToolControl;
            
    private var _skewLeftControl:TransformToolControl;
                
            
    private var _moveCursor:TransformToolCursor;
            
    private var _registrationCursor:TransformToolCursor;
            
    private var _rotationCursor:TransformToolCursor;
            
    private var _scaleCursor:TransformToolCursor;
            
    private var _skewCursor:TransformToolCursor;
            
            
    // Event constants
            
    public static const NEW_TARGET:String = "newTarget";
            
    public static const TRANSFORM_TARGET:String = "transformTarget";
            
    public static const TRANSFORM_TOOL:String = "transformTool";
            
    public static const CONTROL_INIT:String = "controlInit";
            
    public static const CONTROL_TRANSFORM_TOOL:String = "controlTransformTool";
            
    public static const CONTROL_DOWN:String = "controlDown";
            
    public static const CONTROL_MOVE:String = "controlMove";
            
    public static const CONTROL_UP:String = "controlUp";
            
    public static const CONTROL_PREFERENCE:String = "controlPreference";
            
            
    // Skin constants
            
    public static const REGISTRATION:String = "registration";
            
    public static const SCALE_TOP_LEFT:String = "scaleTopLeft";
            
    public static const SCALE_TOP:String = "scaleTop";
            
    public static const SCALE_TOP_RIGHT:String = "scaleTopRight";
            
    public static const SCALE_RIGHT:String = "scaleRight";
            
    public static const SCALE_BOTTOM_RIGHT:String = "scaleBottomRight";
            
    public static const SCALE_BOTTOM:String = "scaleBottom";
            
    public static const SCALE_BOTTOM_LEFT:String = "scaleBottomLeft";
            
    public static const SCALE_LEFT:String = "scaleLeft";
            
    public static const ROTATION_TOP_LEFT:String = "rotationTopLeft";
            
    public static const ROTATION_TOP_RIGHT:String = "rotationTopRight";
            
    public static const ROTATION_BOTTOM_RIGHT:String = "rotationBottomRight";
            
    public static const ROTATION_BOTTOM_LEFT:String = "rotationBottomLeft";
            
    public static const SKEW_TOP:String = "skewTop";
            
    public static const SKEW_RIGHT:String = "skewRight";
            
    public static const SKEW_BOTTOM:String = "skewBottom";
            
    public static const SKEW_LEFT:String = "skewLeft";
            
    public static const CURSOR_REGISTRATION:String = "cursorRegistration";
            
    public static const CURSOR_MOVE:String = "cursorMove";
            
    public static const CURSOR_SCALE:String = "cursorScale";
            
    public static const CURSOR_ROTATION:String = "cursorRotate";
            
    public static const CURSOR_SKEW:String = "cursorSkew";
            
            
    // Properties
            
            
    /**
             
    * The display object the transform tool affects
             
    */
            
    public function get target():DisplayObject {
                return _target;
            }
            
    public function set target(d:DisplayObject):void {
                
                
    // null target, set target as null
                
    if (!d) {
                    
    if (_target) {
                        _target 
    = null;
                        updateControlsVisible();
                        dispatchEvent(
    new Event(NEW_TARGET));
                    }
                    return;
                }
    else{
                    
                    
    // invalid target, do nothing
                    
    if (d == _target || d == this || contains(d)
                    || (d 
    is DisplayObjectContainer && (d as DisplayObjectContainer).contains(this))) {
                        return;
                    }
                    
                    
    // valid target, set and update
                    _target 
    = d;
                    updateMatrix();
                    setNewRegistation();
                    updateControlsVisible();
                    
                    
    // raise to top of display list if applies
                    
    if (_raiseNewTargets) {
                        raiseTarget();
                    }
                }
                
                
    // if not moving new targets, apply transforms
                
    if (!_moveNewTargets) {
                    apply();
                }
                
                
    // send event; updates control points
                dispatchEvent(
    new Event(NEW_TARGET));
                    
                
    // initiate move interaction if applies after controls updated
                
    if (_moveNewTargets && _moveEnabled && _moveControl) {
                    _currentControl 
    = _moveControl;
                    _currentControl.dispatchEvent(
    new MouseEvent(MouseEvent.MOUSE_DOWN));
                }
            }
            
            
    /**
             
    * When truenew targets are placed at the top of their display list
             
    * @see target
             
    */
            
    public function get raiseNewTargets():Boolean {
                return _raiseNewTargets;
            }
            
    public function set raiseNewTargets(b:Boolean):void {
                _raiseNewTargets 
    = b;
            }
            
            
    /**
             
    * When truenew targets are immediately given a move interaction and can be dragged
             
    * @see target
             
    * @see moveEnabled
             
    */
            
    public function get moveNewTargets():Boolean {
                return _moveNewTargets;
            }
            
    public function set moveNewTargets(b:Boolean):void {
                _moveNewTargets 
    = b;
            }
            
            
    /**
             
    * When true, the target instance scales with the tool as it is transformed.
             
    * When false, transforms in the tool are only reflected when transforms are completed.
             
    */
            
    public function get livePreview():Boolean {
                return _livePreview;
            }
            
    public function set livePreview(b:Boolean):void {
                _livePreview 
    = b;
            }
            
            
    /**
             
    * Controls the default Control sizes of controls used by the tool
             
    */
            
    public function get controlSize():Number {
                return _controlSize;
            }
            
    public function set controlSize(n:Number):void {
                
    if (_controlSize != n) {
                    _controlSize 
    = n;
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * When true, counters transformations applied to controls by their parent containers
             
    */
            
    public function get maintainControlForm():Boolean {
                return _maintainControlForm;
            }
            
    public function set maintainControlForm(b:Boolean):void {
                
    if (_maintainControlForm != b) {
                    _maintainControlForm 
    = b;
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * When true (default), the transform tool uses an invisible control using the shape of the current
             
    * target to allow movement. This means any objects above the target but below the
             
    * tool cannot be clicked on since this hidden control will be clicked on first
             
    * (allowing you to move objects below others without selecting the objects on top).
             
    * When false, the target itself is used for movement and any objects above the target
             
    * become clickable preventing tool movement if the target itself is not clicked directly.
             
    */
            
    public function get moveUnderObjects():Boolean {
                return _moveUnderObjects;
            }
            
    public function set moveUnderObjects(b:Boolean):void {
                
    if (_moveUnderObjects != b) {
                    _moveUnderObjects 
    = b;
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * The transform matrix of the tool
             
    * as it exists in its on coordinate space
             
    * @see globalMatrix
             
    */
            
    public function get toolMatrix():Matrix {
                return _toolMatrix.clone();
            }
            
    public function set toolMatrix(m:Matrix):void {
                updateMatrix(m, 
    false);
                updateRegistration();
                dispatchEvent(
    new Event(TRANSFORM_TOOL));
            }
            
            
    /**
             
    * The transform matrix of the tool
             
    * as it appears in global space
             
    * @see toolMatrix
             
    */
            
    public function get globalMatrix():Matrix {
                var _globalMatrix:Matrix 
    = _toolMatrix.clone();
                _globalMatrix.concat(transform.concatenatedMatrix);
                return _globalMatrix;
            }
            
    public function set globalMatrix(m:Matrix):void {
                updateMatrix(m);
                updateRegistration();
                dispatchEvent(
    new Event(TRANSFORM_TOOL));
            }
            
            
    /**
             
    * The location of the registration point in the tool. Note: registration
             
    * points are tool-specific.  If you change the registration point of a
             
    * target, the new registration will only be reflected in the tool used
             
    * to change that point.
             
    * @see registrationEnabled
             
    * @see rememberRegistration
             
    */
            
    public function get registration():Point {
                return _registration.clone();
            }
            
    public function set registration(p:Point):void {
                _registration 
    = p.clone();
                innerRegistration 
    = toolInvertedMatrix.transformPoint(_registration);
                
                
    if (_rememberRegistration) {
                    
    // log new registration point for the next
                    
    // time this target is selected
                    registrationLog[_target] 
    = innerRegistration;
                }
                dispatchEvent(
    new Event(TRANSFORM_TOOL));
            }
            
            
    /**
             
    * The current control being used in the tool if being manipulated.
             
    * This value is null if the user is not transforming the tool.
             
    */
            
    public function get currentControl():TransformToolControl {
                return _currentControl;
            }
            
            
    /**
             
    * Allows or disallows users to move the tool
             
    */
            
    public function get moveEnabled():Boolean {
                return _moveEnabled;
            }
            
    public function set moveEnabled(b:Boolean):void {
                
    if (_moveEnabled != b) {
                    _moveEnabled 
    = b;
                    updateControlsEnabled();
                }
            }
            
            
    /**
             
    * Allows or disallows users to see and move the registration point
             
    * @see registration
             
    * @see rememberRegistration
             
    */
            
    public function get registrationEnabled():Boolean {
                return _registrationEnabled;
            }
            
    public function set registrationEnabled(b:Boolean):void {
                
    if (_registrationEnabled != b) {
                    _registrationEnabled 
    = b;
                    updateControlsEnabled();
                }
            }
            
            
    /**
             
    * Allows or disallows users to see and adjust rotation controls
             
    */
            
    public function get rotationEnabled():Boolean {
                return _rotationEnabled;
            }
            
    public function set rotationEnabled(b:Boolean):void {
                
    if (_rotationEnabled != b) {
                    _rotationEnabled 
    = b;
                    updateControlsEnabled();
                }
            }
            
            
    /**
             
    * Allows or disallows users to see and adjust scale controls
             
    */
            
    public function get scaleEnabled():Boolean {
                return _scaleEnabled;
            }
            
    public function set scaleEnabled(b:Boolean):void {
                
    if (_scaleEnabled != b) {
                    _scaleEnabled 
    = b;
                    updateControlsEnabled();
                }
            }
            
            
    /**
             
    * Allows or disallows users to see and adjust skew controls
             
    */
            
    public function get skewEnabled():Boolean {
                return _skewEnabled;
            }
            
    public function set skewEnabled(b:Boolean):void {
                
    if (_skewEnabled != b) {
                    _skewEnabled 
    = b;
                    updateControlsEnabled();
                }
            }
            
            
    /**
             
    * Allows or disallows users to see tool boundry outlines
             
    */
            
    public function get outlineEnabled():Boolean {
                return _outlineEnabled;
            }
            
    public function set outlineEnabled(b:Boolean):void {
                
    if (_outlineEnabled != b) {
                    _outlineEnabled 
    = b;
                    updateControlsEnabled();
                }
            }
            
            
    /**
             
    * Allows or disallows users to see native cursors
             
    * @see addCursor
             
    * @see removeCursor
             
    * @see customCursorsEnabled
             
    */
            
    public function get cursorsEnabled():Boolean {
                return _cursorsEnabled;
            }
            
    public function set cursorsEnabled(b:Boolean):void {
                
    if (_cursorsEnabled != b) {
                    _cursorsEnabled 
    = b;
                    updateControlsEnabled();
                }
            }
            
            
    /**
             
    * Allows or disallows users to see and use custom controls
             
    * @see addControl
             
    * @see removeControl
             
    * @see customCursorsEnabled
             
    */
            
    public function get customControlsEnabled():Boolean {
                return _customControlsEnabled;
            }
            
    public function set customControlsEnabled(b:Boolean):void {
                
    if (_customControlsEnabled != b) {
                    _customControlsEnabled 
    = b;
                    updateControlsEnabled();
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * Allows or disallows users to see custom cursors
             
    * @see addCursor
             
    * @see removeCursor
             
    * @see cursorsEnabled
             
    * @see customControlsEnabled
             
    */
            
    public function get customCursorsEnabled():Boolean {
                return _customCursorsEnabled;
            }
            
    public function set customCursorsEnabled(b:Boolean):void {
                
    if (_customCursorsEnabled != b) {
                    _customCursorsEnabled 
    = b;
                    updateControlsEnabled();
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * Allows or disallows users to see custom cursors
             
    * @see registration
             
    */
            
    public function get rememberRegistration():Boolean {
                return _rememberRegistration;
            }
            
    public function set rememberRegistration(b:Boolean):void {
                _rememberRegistration 
    = b;
                
    if (!_rememberRegistration) {
                    registrationLog 
    = new Dictionary(true);
                }
            }
            
            
    /**
             
    * Allows constraining of scale transformations that scale along both X and Y.
             
    * @see constrainRotation
             
    */
            
    public function get constrainScale():Boolean {
                return _constrainScale;
            }
            
    public function set constrainScale(b:Boolean):void {
                
    if (_constrainScale != b) {
                    _constrainScale 
    = b;
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * Allows constraining of rotation transformations by an angle
             
    * @see constrainRotationAngle
             
    * @see constrainScale
             
    */
            
    public function get constrainRotation():Boolean {
                return _constrainRotation;
            }
            
    public function set constrainRotation(b:Boolean):void {
                
    if (_constrainRotation != b) {
                    _constrainRotation 
    = b;
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * The angle at which rotation is constrainged when constrainRotation is true
             
    * @see constrainRotation
             
    */
            
    public function get constrainRotationAngle():Number {
                return _constrainRotationAngle 
    * 180/Math.PI;
            }
            
    public function set constrainRotationAngle(n:Number):void {
                var angleInRadians:Number 
    = n * Math.PI/180;
                
    if (_constrainRotationAngle != angleInRadians) {
                    _constrainRotationAngle 
    = angleInRadians;
                    dispatchEvent(
    new Event(CONTROL_PREFERENCE));
                }
            }
            
            
    /**
             
    * The maximum scaleX allowed to be applied to a target
             
    */
            
    public function get maxScaleX():Number {
                return _maxScaleX;
            }
            
    public function set maxScaleX(n:Number):void {
                _maxScaleX 
    = n;
            }
            
            
    /**
             
    * The maximum scaleY allowed to be applied to a target
             
    */
            
    public function get maxScaleY():Number {
                return _maxScaleY;
            }
            
    public function set maxScaleY(n:Number):void {
                _maxScaleY 
    = n;
            }
            
            
    public function get boundsTopLeft():Point { return _boundsTopLeft.clone(); }
            
    public function get boundsTop():Point { return _boundsTop.clone(); }
            
    public function get boundsTopRight():Point { return _boundsTopRight.clone(); }
            
    public function get boundsRight():Point { return _boundsRight.clone(); }
            
    public function get boundsBottomRight():Point { return _boundsBottomRight.clone(); }
            
    public function get boundsBottom():Point { return _boundsBottom.clone(); }
            
    public function get boundsBottomLeft():Point { return _boundsBottomLeft.clone(); }
            
    public function get boundsLeft():Point { return _boundsLeft.clone(); }
            
    public function get boundsCenter():Point { return _boundsCenter.clone(); }
            
    public function get mouse():Point { return new Point(mouseX, mouseY); }
            
            
    public function get moveControl():TransformToolControl { return _moveControl; }
            
    public function get registrationControl():TransformToolControl { return _registrationControl; }
            
    public function get outlineControl():TransformToolControl { return _outlineControl; }
            
    public function get scaleTopLeftControl():TransformToolControl { return _scaleTopLeftControl; }
            
    public function get scaleTopControl():TransformToolControl { return _scaleTopControl; }
            
    public function get scaleTopRightControl():TransformToolControl { return _scaleTopRightControl; }
            
    public function get scaleRightControl():TransformToolControl { return _scaleRightControl; }
            
    public function get scaleBottomRightControl():TransformToolControl { return _scaleBottomRightControl; }
            
    public function get scaleBottomControl():TransformToolControl { return _scaleBottomControl; }
            
    public function get scaleBottomLeftControl():TransformToolControl { return _scaleBottomLeftControl; }
            
    public function get scaleLeftControl():TransformToolControl { return _scaleLeftControl; }
            
    public function get rotationTopLeftControl():TransformToolControl { return _rotationTopLeftControl; }
            
    public function get rotationTopRightControl():TransformToolControl { return _rotationTopRightControl; }
            
    public function get rotationBottomRightControl():TransformToolControl { return _rotationBottomRightControl; }
            
    public function get rotationBottomLeftControl():TransformToolControl { return _rotationBottomLeftControl; }
            
    public function get skewTopControl():TransformToolControl { return _skewTopControl; }
            
    public function get skewRightControl():TransformToolControl { return _skewRightControl; }
            
    public function get skewBottomControl():TransformToolControl { return _skewBottomControl; }
            
    public function get skewLeftControl():TransformToolControl { return _skewLeftControl; }
            
            
    public function get moveCursor():TransformToolCursor { return _moveCursor; }
            
    public function get registrationCursor():TransformToolCursor { return _registrationCursor; }
            
    public function get rotationCursor():TransformToolCursor { return _rotationCursor; }
            
    public function get scaleCursor():TransformToolCursor { return _scaleCursor; }
            
    public function get skewCursor():TransformToolCursor { return _skewCursor; }
            
            
    /**
             
    * TransformTool Constructor.
             
    * Creates new instances of the transform tool
             
    */
            
    public function TransformTool() {
                createControls();
            }
            
            
    /**
             
    * Provides a string representation of the transform instance
             
    */
            override 
    public function toString():String {
                return 
    "[Transform Tool: target=" + String(_target) + "]" ;
            }
            
            
    // Setup
            
    private function createControls():void {
                
                
    // defining controls
                _moveControl 
    = new TransformToolMoveShape("move", moveInteraction);
                _registrationControl 
    = new TransformToolRegistrationControl(REGISTRATION, registrationInteraction, "registration");
                _rotationTopLeftControl 
    = new TransformToolRotateControl(ROTATION_TOP_LEFT, rotationInteraction, "boundsTopLeft");
                _rotationTopRightControl 
    = new TransformToolRotateControl(ROTATION_TOP_RIGHT, rotationInteraction, "boundsTopRight");
                _rotationBottomRightControl 
    = new TransformToolRotateControl(ROTATION_BOTTOM_RIGHT, rotationInteraction, "boundsBottomRight");
                _rotationBottomLeftControl 
    = new TransformToolRotateControl(ROTATION_BOTTOM_LEFT, rotationInteraction, "boundsBottomLeft");
                _scaleTopLeftControl 
    = new TransformToolScaleControl(SCALE_TOP_LEFT, scaleBothInteraction, "boundsTopLeft");
                _scaleTopControl 
    = new TransformToolScaleControl(SCALE_TOP, scaleYInteraction, "boundsTop");
                _scaleTopRightControl 
    = new TransformToolScaleControl(SCALE_TOP_RIGHT, scaleBothInteraction, "boundsTopRight");
                _scaleRightControl 
    = new TransformToolScaleControl(SCALE_RIGHT, scaleXInteraction, "boundsRight");
                _scaleBottomRightControl 
    = new TransformToolScaleControl(SCALE_BOTTOM_RIGHT, scaleBothInteraction, "boundsBottomRight");
                _scaleBottomControl 
    = new TransformToolScaleControl(SCALE_BOTTOM, scaleYInteraction, "boundsBottom");
                _scaleBottomLeftControl 
    = new TransformToolScaleControl(SCALE_BOTTOM_LEFT, scaleBothInteraction, "boundsBottomLeft");
                _scaleLeftControl 
    = new TransformToolScaleControl(SCALE_LEFT, scaleXInteraction, "boundsLeft");
                _skewTopControl 
    = new TransformToolSkewBar(SKEW_TOP, skewXInteraction, "boundsTopRight""boundsTopLeft""boundsTopRight");
                _skewRightControl 
    = new TransformToolSkewBar(SKEW_RIGHT, skewYInteraction, "boundsBottomRight""boundsTopRight""boundsBottomRight");
                _skewBottomControl 
    = new TransformToolSkewBar(SKEW_BOTTOM, skewXInteraction, "boundsBottomLeft""boundsBottomRight""boundsBottomLeft");
                _skewLeftControl 
    = new TransformToolSkewBar(SKEW_LEFT, skewYInteraction, "boundsTopLeft""boundsBottomLeft""boundsTopLeft");
                
                
    // defining cursors
                _moveCursor 
    = new TransformToolMoveCursor();
                _moveCursor.addReference(_moveControl);
                
                _registrationCursor 
    = new TransformToolRegistrationCursor();
                _registrationCursor.addReference(_registrationControl);
                
                _rotationCursor 
    = new TransformToolRotateCursor();
                _rotationCursor.addReference(_rotationTopLeftControl);
                _rotationCursor.addReference(_rotationTopRightControl);
                _rotationCursor.addReference(_rotationBottomRightControl);
                _rotationCursor.addReference(_rotationBottomLeftControl);
                
                _scaleCursor 
    = new TransformToolScaleCursor();
                _scaleCursor.addReference(_scaleTopLeftControl);
                _scaleCursor.addReference(_scaleTopControl);
                _scaleCursor.addReference(_scaleTopRightControl);
                _scaleCursor.addReference(_scaleRightControl);
                _scaleCursor.addReference(_scaleBottomRightControl);
                _scaleCursor.addReference(_scaleBottomControl);
                _scaleCursor.addReference(_scaleBottomLeftControl);
                _scaleCursor.addReference(_scaleLeftControl);
                
                _skewCursor 
    = new TransformToolSkewCursor();
                _skewCursor.addReference(_skewTopControl);
                _skewCursor.addReference(_skewRightControl);
                _skewCursor.addReference(_skewBottomControl);
                _skewCursor.addReference(_skewLeftControl);
                
                
    // adding controls
                addToolControl(moveControls, _moveControl);
                addToolControl(registrationControls, _registrationControl);
                addToolControl(rotateControls, _rotationTopLeftControl);
                addToolControl(rotateControls, _rotationTopRightControl);
                addToolControl(rotateControls, _rotationBottomRightControl);
                addToolControl(rotateControls, _rotationBottomLeftControl);
                addToolControl(scaleControls, _scaleTopControl);
                addToolControl(scaleControls, _scaleRightControl);
                addToolControl(scaleControls, _scaleBottomControl);
                addToolControl(scaleControls, _scaleLeftControl);
                addToolControl(scaleControls, _scaleTopLeftControl);
                addToolControl(scaleControls, _scaleTopRightControl);
                addToolControl(scaleControls, _scaleBottomRightControl);
                addToolControl(scaleControls, _scaleBottomLeftControl);
                addToolControl(skewControls, _skewTopControl);
                addToolControl(skewControls, _skewRightControl);
                addToolControl(skewControls, _skewBottomControl);
                addToolControl(skewControls, _skewLeftControl);
                addToolControl(lines, 
    new TransformToolOutline("outline"), false);
                
                
    // adding cursors
                addToolControl(cursors, _moveCursor, 
    false);
                addToolControl(cursors, _registrationCursor, 
    false);
                addToolControl(cursors, _rotationCursor, 
    false);
                addToolControl(cursors, _scaleCursor, 
    false);
                addToolControl(cursors, _skewCursor, 
    false);
                
                
                updateControlsEnabled();
            }
            
            
    private function addToolControl(container:Sprite, control:TransformToolControl, interactive:Boolean = true):void {
                control.transformTool 
    = this;
                
    if (interactive) {
                    control.addEventListener(MouseEvent.MOUSE_DOWN, startInteractionHandler);    
                }
                container.addChild(control);
                control.dispatchEvent(
    new Event(CONTROL_INIT));
            }
            
            
    /**
             
    * Allows you to add a custom control to the tool
             
    * @see removeControl
             
    * @see addCursor
             
    * @see removeCursor
             
    */
            
    public function addControl(control:TransformToolControl):void {
                addToolControl(customControls, control);
            }
            
            
    /**
             
    * Allows you to remove a custom control to the tool
             
    * @see addControl
             
    * @see addCursor
             
    * @see removeCursor
             
    */
            
    public function removeControl(control:TransformToolControl):TransformToolControl {
                
    if (customControls.contains(control)) {
                    customControls.removeChild(control);
                    return control;
                }
                return 
    null;
            }
            
            
    /**
             
    * Allows you to add a custom cursor to the tool
             
    * @see removeCursor
             
    * @see addControl
             
    * @see removeControl
             
    */
            
    public function addCursor(cursor:TransformToolCursor):void {
                addToolControl(customCursors, cursor);
            }
            
            
    /**
             
    * Allows you to remove a custom cursor to the tool
             
    * @see addCursor
             
    * @see addControl
             
    * @see removeControl
             
    */
            
    public function removeCursor(cursor:TransformToolCursor):TransformToolCursor {
                
    if (customCursors.contains(cursor)) {
                    customCursors.removeChild(cursor);
                    return cursor;
                }
                return 
    null;
            }
            
            
    /**
             
    * Allows you to change the appearance of default controls
             
    * @see addControl
             
    * @see removeControl
             
    */
            
    public function setSkin(controlName:String, skin:DisplayObject):void {
                var control:TransformToolInternalControl 
    = getControlByName(controlName);
                
    if (control) {
                    control.skin 
    = skin;
                }
            }
            
            
    /**
             
    * Allows you to get the skin of an existing control.
             
    * If one was not setnull is returned
             
    * @see addControl
             
    * @see removeControl
             
    */
            
    public function getSkin(controlName:String):DisplayObject {
                var control:TransformToolInternalControl 
    = getControlByName(controlName);
                return control.skin;
            }
            
            
    private function getControlByName(controlName:String):TransformToolInternalControl {
                var control:TransformToolInternalControl;
                var containers:
    Array = new Array(skewControls, registrationControls, cursors, rotateControls, scaleControls);
                var i:
    int = containers.length;
                
    while (i-- && control == null) {
                    control 
    = containers[i].getChildByName(controlName) as TransformToolInternalControl;
                }
                return control;
            }
            
            
    // Interaction Handlers
            
    private function startInteractionHandler(event:MouseEvent):void {
                _currentControl 
    = event.currentTarget as TransformToolControl;
                
    if (_currentControl) {
                    setupInteraction();
                }
            }
            
            
    private function setupInteraction():void {
                updateMatrix();
                apply();
                dispatchEvent(
    new Event(CONTROL_DOWN));
                
                
    // mouse offset to allow interaction from desired point
                mouseOffset 
    = (_currentControl && _currentControl.referencePoint) ? _currentControl.referencePoint.subtract(new Point(mouseX, mouseY)) : new Point(00);
                updateMouse();
                
                
    // set variables for interaction reference
                interactionStart 
    = mouseLoc.clone();
                innerInteractionStart 
    = innerMouseLoc.clone();
                interactionStartMatrix 
    = _toolMatrix.clone();
                interactionStartAngle 
    = distortAngle();
                
                
    if (stage) {
                    
    // setup stage events to manage control interaction
                    stage.addEventListener(MouseEvent.MOUSE_MOVE, interactionHandler);
                    stage.addEventListener(MouseEvent.MOUSE_UP, endInteractionHandler, 
    false);
                    stage.addEventListener(MouseEvent.MOUSE_UP, endInteractionHandler, 
    true);
                }
            }
            
            
    private function interactionHandler(event:MouseEvent):void {
                
    // define mouse position for interaction
                updateMouse();
                
                
    // use original toolMatrix for reference of interaction
                _toolMatrix 
    = interactionStartMatrix.clone();
                
                
    // dispatch events that let controls do their thing
                dispatchEvent(
    new Event(CONTROL_MOVE));
                dispatchEvent(
    new Event(CONTROL_TRANSFORM_TOOL));
                
                
    if (_livePreview) {
                    
    // update target if applicable
                    apply();
                }
                
                
    // smooth sailing
                event.updateAfterEvent();
            }
            
            
    private function endInteractionHandler(event:MouseEvent):void {
                
    if (event.eventPhase == EventPhase.BUBBLING_PHASE || !(event.currentTarget is Stage)) {
                    
    // ignore unrelated events received by stage
                    return;
                }
                
                
    if (!_livePreview) {
                    
    // update target if applicable
                    apply();
                }
                
                
    // get stage reference from event in case
                
    // stage is no longer accessible from this instance
                var stageRef:Stage 
    = event.currentTarget as Stage;
                stageRef.removeEventListener(MouseEvent.MOUSE_MOVE, interactionHandler);
                stageRef.removeEventListener(MouseEvent.MOUSE_UP, endInteractionHandler, 
    false);
                stageRef.removeEventListener(MouseEvent.MOUSE_UP, endInteractionHandler, 
    true);
                dispatchEvent(
    new Event(CONTROL_UP));
                _currentControl 
    = null;
            }
            
            
    // Interaction Transformations
            
    /**
             
    * Control Interaction.  Moves the tool
             
    */
            
    public function moveInteraction():void {
                var moveLoc:Point 
    = mouseLoc.subtract(interactionStart);
                _toolMatrix.tx 
    += moveLoc.x;
                _toolMatrix.ty 
    += moveLoc.y;
                updateRegistration();
                completeInteraction();
            }
            
            
    /**
             
    * Control Interaction.  Moves the registration point
             
    */
            
    public function registrationInteraction():void {
                
    // move registration point
                _registration.x 
    = mouseLoc.x;
                _registration.y 
    = mouseLoc.y;
                innerRegistration 
    = toolInvertedMatrix.transformPoint(_registration);
                
                
    if (_rememberRegistration) {
                    
    // log new registration point for the next
                    
    // time this target is selected
                    registrationLog[_target] 
    = innerRegistration;
                }
                completeInteraction();
            }
            
            
    /**
             
    * Control Interaction.  Rotates the tool
             
    */
            
    public function rotationInteraction():void {
                
    // rotate in global transform
                var globalMatrix:Matrix 
    = transform.concatenatedMatrix;
                var globalInvertedMatrix:Matrix 
    = globalMatrix.clone();
                globalInvertedMatrix.invert();
                _toolMatrix.concat(globalMatrix);
                
                
    // get change in rotation
                var angle:Number 
    = distortAngle() - interactionStartAngle;
                
                
    if (_constrainRotation) {
                    
    // constrain rotation based on constrainRotationAngle
                    
    if (angle > Math.PI) {
                        angle 
    -= Math.PI*2;
                    }
    else if (angle < -Math.PI) {
                        angle 
    += Math.PI*2;
                    }
                    angle 
    = Math.round(angle/_constrainRotationAngle)*_constrainRotationAngle;
                }
                
                
    // apply rotation to toolMatrix
                _toolMatrix.rotate(angle);
                
                _toolMatrix.concat(globalInvertedMatrix);
                completeInteraction(
    true);
            }
            
            
    /**
             
    * Control Interaction.  Scales the tool along the X axis
             
    */
            
    public function scaleXInteraction():void {
                
                
    // get distortion offset vertical movement
                var distortH:Point 
    = distortOffset(new Point(innerMouseLoc.x, innerInteractionStart.y), innerInteractionStart.x - innerRegistration.x);
                
                
    // update the matrix for vertical scale
                _toolMatrix.a 
    += distortH.x;
                _toolMatrix.b 
    += distortH.y;
                completeInteraction(
    true);
            }
            
            
    /**
             
    * Control Interaction.  Scales the tool along the Y axis
             
    */
            
    public function scaleYInteraction():void {
                
    // get distortion offset vertical movement
                var distortV:Point 
    = distortOffset(new Point(innerInteractionStart.x, innerMouseLoc.y), innerInteractionStart.y - innerRegistration.y);
                
                
    // update the matrix for vertical scale
                _toolMatrix.c 
    += distortV.x;
                _toolMatrix.d 
    += distortV.y;
                completeInteraction(
    true);
            }
            
            
    /**
             
    * Control Interaction.  Scales the tool along both the X and Y axes
             
    */
            
    public function scaleBothInteraction():void {
                
    // mouse reference, may change from innerMouseLoc if constraining
                var innerMouseRef:Point 
    = innerMouseLoc.clone();
                
                
    if (_constrainScale) {
                    
                    
    // how much the mouse has moved from starting the interaction
                    var moved:Point 
    = innerMouseLoc.subtract(innerInteractionStart);
                    
                    
    // the relationship of the start location to the registration point
                    var regOffset:Point 
    = innerInteractionStart.subtract(innerRegistration);
                    
                    
    // find the ratios between movement and the registration offset
                    var ratioH 
    = regOffset.x ? moved.x/regOffset.x : 0;
                    var ratioV 
    = regOffset.y ? moved.y/regOffset.y : 0;
                    
                    
    // have the larger of the movement distances brought down
                    
    // based on the lowest ratio to fit the registration offset
                    
    if (ratioH > ratioV) {
                        innerMouseRef.x 
    = innerInteractionStart.x + regOffset.x * ratioV;
                    }
    else{
                        innerMouseRef.y 
    = innerInteractionStart.y + regOffset.y * ratioH;
                    }
                }
                
                
    // get distortion offsets for both vertical and horizontal movements
                var distortH:Point 
    = distortOffset(new Point(innerMouseRef.x, innerInteractionStart.y), innerInteractionStart.x - innerRegistration.x);
                var distortV:Point 
    = distortOffset(new Point(innerInteractionStart.x, innerMouseRef.y), innerInteractionStart.y - innerRegistration.y);
                
                
    // update the matrix for both scales
                _toolMatrix.a 
    += distortH.x;
                _toolMatrix.b 
    += distortH.y;
                _toolMatrix.c 
    += distortV.x;
                _toolMatrix.d 
    += distortV.y;
                completeInteraction(
    true);
            }
            
            
    /**
             
    * Control Interaction.  Skews the tool along the X axis
             
    */
            
    public function skewXInteraction():void {
                var distortH:Point 
    = distortOffset(new Point(innerMouseLoc.x, innerInteractionStart.y), innerInteractionStart.y - innerRegistration.y);
                _toolMatrix.c 
    += distortH.x;
                _toolMatrix.d 
    += distortH.y;
                completeInteraction(
    true);
            }
            
            
    /**
             
    * Control Interaction.  Skews the tool along the Y axis
             
    */
            
    public function skewYInteraction():void {
                var distortV:Point 
    = distortOffset(new Point(innerInteractionStart.x, innerMouseLoc.y), innerInteractionStart.x - innerRegistration.x);
                _toolMatrix.a 
    += distortV.x;
                _toolMatrix.b 
    += distortV.y;
                completeInteraction(
    true);
            }
            
            
    private function distortOffset(offset:Point, regDiff:Number):Point {
                
    // get changes in matrix combinations based on targetBounds
                var ratioH:Number 
    = regDiff ? targetBounds.width/regDiff : 0;
                var ratioV:Number 
    = regDiff ? targetBounds.height/regDiff : 0;
                offset 
    = interactionStartMatrix.transformPoint(offset).subtract(interactionStart);
                offset.x 
    *= targetBounds.width ? ratioH/targetBounds.width : 0;
                offset.y 
    *= targetBounds.height ? ratioV/targetBounds.height : 0;
                return offset;
            }
            
            
    private function completeInteraction(offsetReg:Boolean = false):void {
                enforceLimits();
                
    if (offsetReg) {
                    
    // offset of registration to have transformations based around
                    
    // custom registration point
                    var offset:Point 
    = _registration.subtract(_toolMatrix.transformPoint(innerRegistration));
                    _toolMatrix.tx 
    += offset.x;
                    _toolMatrix.ty 
    += offset.y;
                }
                updateBounds();
            }
            
            
    // Information
            
    private function distortAngle():Number {
                
    // use global mouse and registration
                var globalMatrix:Matrix 
    = transform.concatenatedMatrix;
                var gMouseLoc:Point 
    = globalMatrix.transformPoint(mouseLoc);
                var gRegistration:Point 
    = globalMatrix.transformPoint(_registration);
                
                
    // distance and angle of mouse from registration
                var offset:Point 
    = gMouseLoc.subtract(gRegistration);
                return Math.atan2(offset.y, offset.x);
            }
            
            
    // Updates
            
    private function updateMouse():void {
                mouseLoc 
    = new Point(mouseX, mouseY).add(mouseOffset);
                innerMouseLoc 
    = toolInvertedMatrix.transformPoint(mouseLoc);
            }
            
            
    private function updateMatrix(useMatrix:Matrix = null, counterTransform:Boolean = true):void {
                
    if (_target) {
                    _toolMatrix 
    = useMatrix ? useMatrix.clone() : _target.transform.concatenatedMatrix.clone();
                    
    if (counterTransform) {
                        
    // counter transform of the parents of the tool
                        var current:Matrix 
    = transform.concatenatedMatrix;
                        current.invert();
                        _toolMatrix.concat(current);
                    }
                    enforceLimits();
                    toolInvertedMatrix 
    = _toolMatrix.clone();
                    toolInvertedMatrix.invert();
                    updateBounds();
                }
            }
            
            
    private function updateBounds():void {
                
    if (_target) {
                    
    // update tool bounds based on target bounds
                    targetBounds 
    = _target.getBounds(_target);
                    _boundsTopLeft 
    = _toolMatrix.transformPoint(new Point(targetBounds.left, targetBounds.top));
                    _boundsTopRight 
    = _toolMatrix.transformPoint(new Point(targetBounds.right, targetBounds.top));
                    _boundsBottomRight 
    = _toolMatrix.transformPoint(new Point(targetBounds.right, targetBounds.bottom));
                    _boundsBottomLeft 
    = _toolMatrix.transformPoint(new Point(targetBounds.left, targetBounds.bottom));
                    _boundsTop 
    = Point.interpolate(_boundsTopLeft, _boundsTopRight, .5);
                    _boundsRight 
    = Point.interpolate(_boundsTopRight, _boundsBottomRight, .5);
                    _boundsBottom 
    = Point.interpolate(_boundsBottomRight, _boundsBottomLeft, .5);
                    _boundsLeft 
    = Point.interpolate(_boundsBottomLeft, _boundsTopLeft, .5);
                    _boundsCenter 
    = Point.interpolate(_boundsTopLeft, _boundsBottomRight, .5);
                }
            }
            
            
    private function updateControlsVisible():void {
                
    // show toolSprites only if there is a valid target
                var isChild:
    Boolean = contains(toolSprites);
                
    if (_target) {
                    
    if (!isChild) {
                        addChild(toolSprites);
                    }                
                }
    else if (isChild) {
                    removeChild(toolSprites);
                }
            }
            
            
    private function updateControlsEnabled():void {
                
    // highest arrangement
                updateControlContainer(customCursors, _customCursorsEnabled);
                updateControlContainer(cursors, _cursorsEnabled);
                updateControlContainer(customControls, _customControlsEnabled);
                updateControlContainer(registrationControls, _registrationEnabled);
                updateControlContainer(scaleControls, _scaleEnabled);
                updateControlContainer(skewControls, _skewEnabled);
                updateControlContainer(moveControls, _moveEnabled);
                updateControlContainer(rotateControls, _rotationEnabled);
                updateControlContainer(lines, _outlineEnabled);
                
    // lowest arrangement
            }
            
            
    private function updateControlContainer(container:Sprite, enabled:Boolean):void {
                var isChild:
    Boolean = toolSprites.contains(container);
                
    if (enabled) {
                    
    // add child or sent to bottom if enabled
                    
    if (isChild) {
                        toolSprites.setChildIndex(container, 
    0);
                    }
    else{
                        toolSprites.addChildAt(container, 
    0);
                    }
                }
    else if (isChild) {
                    
    // removed if disabled
                    toolSprites.removeChild(container);
                }
            }
            
            
    private function updateRegistration():void {
                _registration 
    = _toolMatrix.transformPoint(innerRegistration);
            }
            
            
    private function enforceLimits():void {
                
                var currScale:Number;
                var angle:Number;
                var enforced:
    Boolean = false;
                
                
    // use global matrix
                var _globalMatrix:Matrix 
    = _toolMatrix.clone();
                _globalMatrix.concat(transform.concatenatedMatrix);
                
                
    // check current scale in X
                currScale 
    = Math.sqrt(_globalMatrix.a * _globalMatrix.a + _globalMatrix.b * _globalMatrix.b);
                
    if (currScale > _maxScaleX) {
                    
    // set scaleX to no greater than _maxScaleX
                    angle 
    = Math.atan2(_globalMatrix.b, _globalMatrix.a);
                    _globalMatrix.a 
    = Math.cos(angle) * _maxScaleX;
                    _globalMatrix.b 
    = Math.sin(angle) * _maxScaleX;
                    enforced 
    = true;
                }
                
                
    // check current scale in Y
                currScale 
    = Math.sqrt(_globalMatrix.c * _globalMatrix.c + _globalMatrix.d * _globalMatrix.d);
                
    if (currScale > _maxScaleY) {
                    
    // set scaleY to no greater than _maxScaleY
                    angle
    = Math.atan2(_globalMatrix.c, _globalMatrix.d);
                    _globalMatrix.d 
    = Math.cos(angle) * _maxScaleY;
                    _globalMatrix.c 
    = Math.sin(angle) * _maxScaleY;
                    enforced 
    = true;
                }
                
                
                
    // if scale was enforced, apply to _toolMatrix
                
    if (enforced) {
                    _toolMatrix 
    = _globalMatrix;
                    var current:Matrix 
    = transform.concatenatedMatrix;
                    current.invert();
                    _toolMatrix.concat(current);
                }
            }
            
            
    // Render
            
    private function setNewRegistation():void {
                
    if (_rememberRegistration && _target in registrationLog) {
                    
                    
    // retrieved saved reg point in log
                    var savedReg:Point 
    = registrationLog[_target];
                    innerRegistration 
    = registrationLog[_target];
                }
    else{
                    
                    
    // use internal own point
                    innerRegistration 
    = new Point(00);
                }
                updateRegistration();
            }
            
            
    private function raiseTarget():void {
                
    // set target to last object in display list
                var index:
    int = _target.parent.numChildren - 1;
                _target.parent.setChildIndex(_target, index);
                
                
    // if this tool is in the same display list
                
    // raise it to the top above target
                
    if (_target.parent == parent) {
                    parent.setChildIndex(this, index);
                }
            }
            
            
    /**
             
    * Draws the transform tool over its target instance
             
    */
            
    public function draw():void {
                
    // update the matrix and draw controls
                updateMatrix();
                dispatchEvent(
    new Event(TRANSFORM_TOOL));
            }
            
            
    /**
             
    * Applies the current tool transformation to its target instance
             
    */
            
    public function apply():void {
                
    if (_target) {
                    
                    
    // get matrix to apply to target
                    var applyMatrix:Matrix 
    = _toolMatrix.clone();
                    applyMatrix.concat(transform.concatenatedMatrix);
                    
                    
    // if target has a parent, counter parent transformations
                    
    if (_target.parent) {
                        var invertMatrix:Matrix 
    = target.parent.transform.concatenatedMatrix;
                        invertMatrix.invert();
                        applyMatrix.concat(invertMatrix);
                    }
                    
                    
    // set target's matrix
                    _target.transform.matrix = applyMatrix;
                    
                    dispatchEvent(
    new Event(TRANSFORM_TARGET));
                }
            }
        }
    }


    import flash.display.DisplayObject;
    import flash.display.InteractiveObject;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.geom.Point;

    import com.senocular.display.TransformTool;
    import com.senocular.display.TransformToolControl;
    import com.senocular.display.TransformToolCursor;

    // Controls
    class TransformToolInternalControl extends TransformToolControl {
        
        
    public var interactionMethod:Function;
        
    public var referenceName:String;
        
    public var _skin:DisplayObject;
        
        
    public function set skin(skin:DisplayObject):void {
            
    if (_skin && contains(_skin)) {
                removeChild(_skin);
            }
            _skin 
    = skin;
            
    if (_skin) {
                addChild(_skin);
            }
            draw();
        }
        
        
    public function get skin():DisplayObject {
            return _skin;
        }
        
        override 
    public function get referencePoint():Point {
            
    if (referenceName in _transformTool) {
                return _transformTool[referenceName];
            }
            return 
    null;
        }
            
        
    /*
         
    * Constructor
         
    */    
        
    public function TransformToolInternalControl(name:String, interactionMethod:Function = null, referenceName:String = null) {
            this.name 
    = name;
            this.interactionMethod 
    = interactionMethod;
            this.referenceName 
    = referenceName;
            addEventListener(TransformTool.CONTROL_INIT, init);
        }
        
        protected 
    function init(event:Event):void {
            _transformTool.addEventListener(TransformTool.NEW_TARGET, draw);
            _transformTool.addEventListener(TransformTool.TRANSFORM_TOOL, draw);
            _transformTool.addEventListener(TransformTool.CONTROL_TRANSFORM_TOOL, position);
            _transformTool.addEventListener(TransformTool.CONTROL_PREFERENCE, draw);
            _transformTool.addEventListener(TransformTool.CONTROL_MOVE, controlMove);
            draw();
        }
        
        
    public function draw(event:Event = null):void {
            
    if (_transformTool.maintainControlForm) {
                counterTransform();
            }
            position();
        }
        
        
    public function position(event:Event = null):void {
            var reference:Point 
    = referencePoint;
            
    if (reference) {
                x 
    = reference.x;
                y 
    = reference.y;
            }
        }
        
        
    private function controlMove(event:Event):void {
            
    if ((interactionMethod is Function&& (_transformTool.currentControl == this)) {
                interactionMethod();
            }
        }
    }


    class TransformToolMoveShape extends TransformToolInternalControl {
        
        
    private var lastTarget:DisplayObject;
        
        
    function TransformToolMoveShape(name:String, interactionMethod:Function) {
            super(name, interactionMethod);
        }
        
        override 
    public function draw(event:Event = null):void {
            
            var currTarget:DisplayObject;
            var moveUnderObjects:
    Boolean = _transformTool.moveUnderObjects;
            
            
    // use hitArea if moving under objects
            
    // then movement would have the same depth as the tool
            
    if (moveUnderObjects) {
                hitArea 
    = _transformTool.target as Sprite;
                currTarget 
    = null;
                relatedObject 
    = this;
                
            }
    else{
                
                
    // when not moving under objects
                
    // use the tool target to handle movement allowing
                
    // objects above it to be selectable
                hitArea 
    = null;
                currTarget 
    = _transformTool.target;
                relatedObject 
    = _transformTool.target as InteractiveObject;
            }
            
            
    if (lastTarget != currTarget) {
                
    // set up/remove listeners for target being clicked
                
    if (lastTarget) {
                    lastTarget.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDown, 
    false);
                }
                
    if (currTarget) {
                    currTarget.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown, 
    false0true);
                }
                
                
    // register/unregister cursor with the object
                var cursor:TransformToolCursor 
    = _transformTool.moveCursor;
                cursor.removeReference(lastTarget);
                cursor.addReference(currTarget);
                
                lastTarget 
    = currTarget;
            }
        }
        
        
    private function mouseDown(event:MouseEvent):void {
            dispatchEvent(
    new MouseEvent(MouseEvent.MOUSE_DOWN));
        }
    }


    class TransformToolRegistrationControl extends TransformToolInternalControl {
            
        
    function TransformToolRegistrationControl(name:String, interactionMethod:Function, referenceName:String) {
            super(name, interactionMethod, referenceName);
        }

        override 
    public function draw(event:Event = null):void {
            graphics.clear();
            
    if (!_skin) {
                graphics.lineStyle(
    10);
                graphics.beginFill(0xFFFFFF);
                graphics.drawCircle(
    00, _transformTool.controlSize/2);
                graphics.endFill();
            }
            super.draw();
        }
    }


    class TransformToolScaleControl extends TransformToolInternalControl {
        
        
    function TransformToolScaleControl(name:String, interactionMethod:Function, referenceName:String) {
            super(name, interactionMethod, referenceName);
        }

        override 
    public function draw(event:Event = null):void {
            graphics.clear();
            
    if (!_skin) {
                graphics.lineStyle(
    2, 0xFFFFFF);
                graphics.beginFill(
    0);
                var size 
    = _transformTool.controlSize;
                var size2:Number 
    = size/2;
                graphics.drawRect(
    -size2, -size2, size, size);
                graphics.endFill();
            }
            super.draw();
        }
    }


    class TransformToolRotateControl extends TransformToolInternalControl {
        
        
    private var locationName:String;
        
        
    function TransformToolRotateControl(name:String, interactionMethod:Function, locationName:String) {
            super(name, interactionMethod);
            this.locationName 
    = locationName;
        }

        override 
    public function draw(event:Event = null):void {
            graphics.clear();
            
    if (!_skin) {
                graphics.beginFill(0xFF, 
    0);
                graphics.drawCircle(
    00, _transformTool.controlSize*2);
                graphics.endFill();
            }
            super.draw();
        }
        
        override 
    public function position(event:Event = null):void {
            
    if (locationName in _transformTool) {
                var location:Point 
    = _transformTool[locationName];
                x 
    = location.x;
                y 
    = location.y;
            }
        }
    }


    class TransformToolSkewBar extends TransformToolInternalControl {
        
        
    private var locationStart:String;
        
    private var locationEnd:String;
        
        
    function TransformToolSkewBar(name:String, interactionMethod:Function, referenceName:String, locationStart:String, locationEnd:String) {
            super(name, interactionMethod, referenceName);
            this.locationStart 
    = locationStart;
            this.locationEnd 
    = locationEnd;
        }
        
        override 
    public function draw(event:Event = null):void {
            graphics.clear();
            
            
    if (_skin) {
                super.draw(event);
                return;
            }
            
            
    // derive point locations for bar
            var locStart:Point 
    = _transformTool[locationStart];
            var locEnd:Point 
    = _transformTool[locationEnd];
            
            
    // counter transform
            var toolTrans:Matrix;
            var toolTransInverted:Matrix;
            var maintainControlForm:
    Boolean = _transformTool.maintainControlForm;
            
    if (maintainControlForm) {
                toolTrans 
    = transform.concatenatedMatrix;
                toolTransInverted 
    = toolTrans.clone();
                toolTransInverted.invert();
                
                locStart 
    = toolTrans.transformPoint(locStart);
                locEnd 
    = toolTrans.transformPoint(locEnd);
            }
            
            var size:Number 
    = _transformTool.controlSize/2;
            var diff:Point 
    = locEnd.subtract(locStart);
            var angle:Number 
    = Math.atan2(diff.y, diff.x) - Math.PI/2;    
            var offset:Point 
    = Point.polar(size, angle);
            
            var corner1:Point 
    = locStart.add(offset);
            var corner2:Point 
    = locEnd.add(offset);
            var corner3:Point 
    = locEnd.subtract(offset);
            var corner4:Point 
    = locStart.subtract(offset);
            
    if (maintainControlForm) {
                corner1 
    = toolTransInverted.transformPoint(corner1);
                corner2 
    = toolTransInverted.transformPoint(corner2);
                corner3 
    = toolTransInverted.transformPoint(corner3);
                corner4 
    = toolTransInverted.transformPoint(corner4);
            }
            
            
    // draw bar
            graphics.beginFill(0xFF0000, 
    0);
            graphics.moveTo(corner1.x, corner1.y);
            graphics.lineTo(corner2.x, corner2.y);
            graphics.lineTo(corner3.x, corner3.y);
            graphics.lineTo(corner4.x, corner4.y);
            graphics.lineTo(corner1.x, corner1.y);
            graphics.endFill();
        }

        override 
    public function position(event:Event = null):void {
            
    if (_skin) {
                var locStart:Point 
    = _transformTool[locationStart];
                var locEnd:Point 
    = _transformTool[locationEnd];
                var location:Point 
    = Point.interpolate(locStart, locEnd, .5);
                x 
    = location.x;
                y 
    = location.y;
            }
    else{
                x 
    = 0;
                y 
    = 0;
                draw(event);
            }
        }
    }


    class TransformToolOutline extends TransformToolInternalControl {
        
        
    function TransformToolOutline(name:String) {
            super(name);
        }

        override 
    public function draw(event:Event = null):void {
            var topLeft:Point 
    = _transformTool.boundsTopLeft;
            var topRight:Point 
    = _transformTool.boundsTopRight;
            var bottomRight:Point 
    = _transformTool.boundsBottomRight;
            var bottomLeft:Point 
    = _transformTool.boundsBottomLeft;
            
            graphics.clear();
            graphics.lineStyle(
    00);
            graphics.moveTo(topLeft.x, topLeft.y);
            graphics.lineTo(topRight.x, topRight.y);
            graphics.lineTo(bottomRight.x, bottomRight.y);
            graphics.lineTo(bottomLeft.x, bottomLeft.y);
            graphics.lineTo(topLeft.x, topLeft.y);
        }
        
        override 
    public function position(event:Event = null):void {
            draw(event);
        }
    }


    // Cursors
    class TransformToolInternalCursor extends TransformToolCursor {
        
        
    public var offset:Point = new Point();
        
    public var icon:Shape = new Shape();
        
        
    public function TransformToolInternalCursor() {
            addChild(icon);
            offset 
    = _mouseOffset;
            addEventListener(TransformTool.CONTROL_INIT, init);
        }
            
        
    private function init(event:Event):void {
            _transformTool.addEventListener(TransformTool.NEW_TARGET, maintainTransform);
            _transformTool.addEventListener(TransformTool.CONTROL_PREFERENCE, maintainTransform);
            draw();
        }
        
        protected 
    function maintainTransform(event:Event):void {
            offset 
    = _mouseOffset;
            
    if (_transformTool.maintainControlForm) {
                transform.matrix 
    = new Matrix();
                var concatMatrix:Matrix 
    = transform.concatenatedMatrix;
                concatMatrix.invert();
                transform.matrix 
    = concatMatrix;
                offset 
    = concatMatrix.deltaTransformPoint(offset);
            }
            updateVisible(event);
        }
        
        protected 
    function drawArc(originX:Number, originY:Number, radius:Number, angle1:Number, angle2:Number, useMove:Boolean = true):void {
            var diff:Number 
    = angle2 - angle1;
            var divs:Number 
    = 1 + Math.floor(Math.abs(diff)/(Math.PI/4));
            var span:Number 
    = diff/(2*divs);
            var cosSpan:Number 
    = Math.cos(span);
            var radiusc:Number 
    = cosSpan ? radius/cosSpan : 0;
            var i:
    int;
            
    if (useMove) {
                icon.graphics.moveTo(originX 
    + Math.cos(angle1)*radius, originY - Math.sin(angle1)*radius);
            }
    else{
                icon.graphics.lineTo(originX 
    + Math.cos(angle1)*radius, originY - Math.sin(angle1)*radius);
            }
            
    for (i=0; i<divs; i++) {
                angle2 
    = angle1 + span;
                angle1 
    = angle2 + span;
                icon.graphics.curveTo(
                    originX 
    + Math.cos(angle2)*radiusc, originY - Math.sin(angle2)*radiusc,
                    originX 
    + Math.cos(angle1)*radius, originY - Math.sin(angle1)*radius
                );
            }
        }
        
        protected 
    function getGlobalAngle(vector:Point):Number {
            var globalMatrix:Matrix 
    = _transformTool.globalMatrix;
            vector 
    = globalMatrix.deltaTransformPoint(vector);
            return Math.atan2(vector.y, vector.x) 
    * (180/Math.PI);
        }
        
        override 
    public function position(event:Event = null):void {
            
    if (parent) {
                x 
    = parent.mouseX + offset.x;
                y 
    = parent.mouseY + offset.y;
            }
        }
        
        
    public function draw():void {
            icon.graphics.beginFill(
    0);
            icon.graphics.lineStyle(
    1, 0xFFFFFF);
        }
    }


    class TransformToolRegistrationCursor extends TransformToolInternalCursor {
        
        
    public function TransformToolRegistrationCursor() {
        }
        
        override 
    public function draw():void {
            super.draw();
            icon.graphics.drawCircle(
    0,0,2);
            icon.graphics.drawCircle(
    0,0,4);
            icon.graphics.endFill();
        }
    }


    class TransformToolMoveCursor extends TransformToolInternalCursor {
        
        
    public function TransformToolMoveCursor() {
        }
        
        override 
    public function draw():void {
            super.draw();
            
    // up arrow
            icon.graphics.moveTo(
    11);
            icon.graphics.lineTo(
    1-2);
            icon.graphics.lineTo(
    -1-2);
            icon.graphics.lineTo(
    2-6);
            icon.graphics.lineTo(
    5-2);
            icon.graphics.lineTo(
    3-2);
            icon.graphics.lineTo(
    31);
            
    // right arrow
            icon.graphics.lineTo(
    61);
            icon.graphics.lineTo(
    6-1);
            icon.graphics.lineTo(
    102);
            icon.graphics.lineTo(
    65);
            icon.graphics.lineTo(
    63);
            icon.graphics.lineTo(
    33);
            
    // down arrow
            icon.graphics.lineTo(
    35);
            icon.graphics.lineTo(
    36);
            icon.graphics.lineTo(
    56);
            icon.graphics.lineTo(
    210);
            icon.graphics.lineTo(
    -16);
            icon.graphics.lineTo(
    16);
            icon.graphics.lineTo(
    15);
            
    // left arrow
            icon.graphics.lineTo(
    13);
            icon.graphics.lineTo(
    -23);
            icon.graphics.lineTo(
    -25);
            icon.graphics.lineTo(
    -62);
            icon.graphics.lineTo(
    -2-1);
            icon.graphics.lineTo(
    -21);
            icon.graphics.lineTo(
    11);
            icon.graphics.endFill();
        }
    }


    class TransformToolScaleCursor extends TransformToolInternalCursor {
        
        
    public function TransformToolScaleCursor() {
        }
        
        override 
    public function draw():void {
            super.draw();
            
    // right arrow
            icon.graphics.moveTo(
    4.5-0.5);
            icon.graphics.lineTo(
    4.5-2.5);
            icon.graphics.lineTo(
    8.50.5);
            icon.graphics.lineTo(
    4.53.5);
            icon.graphics.lineTo(
    4.51.5);
            icon.graphics.lineTo(
    -0.51.5);
            
    // left arrow
            icon.graphics.lineTo(
    -3.51.5);
            icon.graphics.lineTo(
    -3.53.5);
            icon.graphics.lineTo(
    -7.50.5);
            icon.graphics.lineTo(
    -3.5-2.5);
            icon.graphics.lineTo(
    -3.5-0.5);
            icon.graphics.lineTo(
    4.5-0.5);
            icon.graphics.endFill();
        }
        
        override 
    public function updateVisible(event:Event = null):void {
            super.updateVisible(event);
            
    if (event) {
                var reference:TransformToolScaleControl 
    = event.target as TransformToolScaleControl;
                
    if (reference) {
                    switch(reference) {
                        
    case _transformTool.scaleTopLeftControl:
                        
    case _transformTool.scaleBottomRightControl:
                            icon.rotation 
    = (getGlobalAngle(new Point(0,100)) + getGlobalAngle(new Point(100,0)))/2;
                            break;
                        
    case _transformTool.scaleTopRightControl:
                        
    case _transformTool.scaleBottomLeftControl:
                            icon.rotation 
    = (getGlobalAngle(new Point(0,-100)) + getGlobalAngle(new Point(100,0)))/2;
                            break;
                        
    case _transformTool.scaleTopControl:
                        
    case _transformTool.scaleBottomControl:
                            icon.rotation 
    = getGlobalAngle(new Point(0,100));
                            break;
                        default:
                            icon.rotation 
    = getGlobalAngle(new Point(100,0));
                    }
                }
            }
        }
    }


    class TransformToolRotateCursor extends TransformToolInternalCursor {
        
        
    public function TransformToolRotateCursor() {
        }
        
        override 
    public function draw():void {
            super.draw();
            
    // curve
            var angle1:Number 
    = Math.PI;
            var angle2:Number 
    = -Math.PI/2;
            drawArc(
    0,0,4, angle1, angle2);
            drawArc(
    0,0,6, angle2, angle1, false);
            
    // arrow
            icon.graphics.lineTo(
    -80);
            icon.graphics.lineTo(
    -54);
            icon.graphics.lineTo(
    -20);
            icon.graphics.lineTo(
    -40);
            icon.graphics.endFill();
        }
    }


    class TransformToolSkewCursor extends TransformToolInternalCursor {
        
        
    public function TransformToolSkewCursor() {
        }
        
        override 
    public function draw():void {
            super.draw();
            
    // right arrow
            icon.graphics.moveTo(
    -6-1);
            icon.graphics.lineTo(
    6-1);
            icon.graphics.lineTo(
    6-4);
            icon.graphics.lineTo(
    101);
            icon.graphics.lineTo(
    -61);
            icon.graphics.lineTo(
    -6-1);
            icon.graphics.endFill();
            
            super.draw();
            
    // left arrow
            icon.graphics.moveTo(
    105);
            icon.graphics.lineTo(
    -25);
            icon.graphics.lineTo(
    -28);
            icon.graphics.lineTo(
    -63);
            icon.graphics.lineTo(
    103);
            icon.graphics.lineTo(
    105);
            icon.graphics.endFill();
        }
        
        override 
    public function updateVisible(event:Event = null):void {
            super.updateVisible(event);
            
    if (event) {
                var reference:TransformToolSkewBar 
    = event.target as TransformToolSkewBar;
                
    if (reference) {
                    switch(reference) {
                        
    case _transformTool.skewLeftControl:
                        
    case _transformTool.skewRightControl:
                            icon.rotation 
    = getGlobalAngle(new Point(0,100));
                            break;
                        default:
                            icon.rotation 
    = getGlobalAngle(new Point(100,0));
                    }
                }
            }
        }
    }
  • 相关阅读:
    extel操作
    postman 使用post方式提交参数值
    json_encode 转化数组时,中文不转义出现乱码的解决方法
    csnd 不好使,所以我来博客园了
    Nodejs 之Ajax的一个实例(sql单条件查询&并显示在Browser端界面上)
    JS 之JSON
    Nodejs sql模块及模块化思想
    Nodejs之Ajax
    Nodejs 之express框架的应用---简单的登录界面
    Nodejs 入门 12-28
  • 原文地址:https://www.cnblogs.com/ddw1997/p/1579916.html
Copyright © 2020-2023  润新知