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  true new  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  true new  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   set null   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( 0 0 );
            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( 0 0 );
            }
            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, 
false 0 true );
            }
            
            
//  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(
1 0 );
            graphics.beginFill(0xFFFFFF);
            graphics.drawCircle(
0 0 , _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(
0 0 , _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(
0 0 );
        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(
1 1 );
        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(
3 1 );
        
//   right  arrow
        icon.graphics.lineTo(
6 1 );
        icon.graphics.lineTo(
6 - 1 );
        icon.graphics.lineTo(
10 2 );
        icon.graphics.lineTo(
6 5 );
        icon.graphics.lineTo(
6 3 );
        icon.graphics.lineTo(
3 3 );
        
//  down arrow
        icon.graphics.lineTo(
3 5 );
        icon.graphics.lineTo(
3 6 );
        icon.graphics.lineTo(
5 6 );
        icon.graphics.lineTo(
2 10 );
        icon.graphics.lineTo(
- 1 6 );
        icon.graphics.lineTo(
1 6 );
        icon.graphics.lineTo(
1 5 );
        
//   left  arrow
        icon.graphics.lineTo(
1 3 );
        icon.graphics.lineTo(
- 2 3 );
        icon.graphics.lineTo(
- 2 5 );
        icon.graphics.lineTo(
- 6 2 );
        icon.graphics.lineTo(
- 2 - 1 );
        icon.graphics.lineTo(
- 2 1 );
        icon.graphics.lineTo(
1 1 );
        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.5 0.5 );
        icon.graphics.lineTo(
4.5 3.5 );
        icon.graphics.lineTo(
4.5 1.5 );
        icon.graphics.lineTo(
- 0.5 1.5 );
        
//   left  arrow
        icon.graphics.lineTo(
- 3.5 1.5 );
        icon.graphics.lineTo(
- 3.5 3.5 );
        icon.graphics.lineTo(
- 7.5 0.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(
- 8 0 );
        icon.graphics.lineTo(
- 5 4 );
        icon.graphics.lineTo(
- 2 0 );
        icon.graphics.lineTo(
- 4 0 );
        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(
10 1 );
        icon.graphics.lineTo(
- 6 1 );
        icon.graphics.lineTo(
- 6 - 1 );
        icon.graphics.endFill();
        
        super.draw();
        
//   left  arrow
        icon.graphics.moveTo(
10 5 );
        icon.graphics.lineTo(
- 2 5 );
        icon.graphics.lineTo(
- 2 8 );
        icon.graphics.lineTo(
- 6 3 );
        icon.graphics.lineTo(
10 3 );
        icon.graphics.lineTo(
10 5 );
        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 ));
                }
            }
        }
    }
}

转载于:https://www.cnblogs.com/ddw1997/archive/2009/10/09/1579916.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值