Advertisement
Guest User

StageTextTextEditor.as

a guest
Mar 26th, 2020
253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. Feathers
  3. Copyright 2012-2013 Joshua Tynjala. All Rights Reserved.
  4.  
  5. This program is free software. You can redistribute and/or modify it in
  6. accordance with the terms of the accompanying license agreement.
  7. */
  8. package feathers.controls.text {
  9. import com.sf.util.AndroidSoftKeyboardHelper;
  10.  
  11. import feathers.core.FeathersControl;
  12. import feathers.core.ITextEditor;
  13. import feathers.events.FeathersEventType;
  14. import feathers.text.StageTextField;
  15. import feathers.utils.geom.matrixToScaleX;
  16. import feathers.utils.geom.matrixToScaleY;
  17.  
  18. import flash.display.BitmapData;
  19. import flash.events.Event;
  20. import flash.events.FocusEvent;
  21. import flash.events.KeyboardEvent;
  22. import flash.events.SoftKeyboardEvent;
  23. import flash.geom.Matrix;
  24. import flash.geom.Point;
  25. import flash.geom.Rectangle;
  26. import flash.text.TextField;
  27. import flash.text.TextFieldAutoSize;
  28. import flash.text.TextFormat;
  29. import flash.text.TextFormatAlign;
  30. import flash.text.engine.FontPosture;
  31. import flash.text.engine.FontWeight;
  32. import flash.ui.Keyboard;
  33. import flash.utils.getDefinitionByName;
  34.  
  35. import starling.core.RenderSupport;
  36. import starling.core.Starling;
  37. import starling.display.Image;
  38. import starling.events.Event;
  39. import starling.textures.ConcreteTexture;
  40. import starling.textures.Texture;
  41. import starling.utils.MatrixUtil;
  42.  
  43. /**
  44.  * Dispatched when the text property changes.
  45.  */
  46. [Event(name="change", type="starling.events.Event")]
  47.  
  48. /**
  49.  * Dispatched when the user presses the Enter key while the editor has
  50.  * focus. This event may not be dispatched on some platforms, depending on
  51.  * the value of <code>returnKeyLabel</code>. This issue may even occur when
  52.  * using the <em>default value</em> of <code>returnKeyLabel</code>!
  53.  *
  54.  * @eventType feathers.events.FeathersEventType.ENTER
  55.  * @see #returnKeyLabel
  56.  * @see flash.text.ReturnKeyLabel
  57.  */
  58. [Event(name="enter", type="starling.events.Event")]
  59.  
  60. /**
  61.  * Dispatched when the text editor receives focus.
  62.  *
  63.  * @eventType feathers.events.FeathersEventType.FOCUS_IN
  64.  */
  65. [Event(name="focusIn", type="starling.events.Event")]
  66.  
  67. /**
  68.  * Dispatched when the text editor loses focus.
  69.  *
  70.  * @eventType feathers.events.FeathersEventType.FOCUS_OUT
  71.  */
  72. [Event(name="focusOut", type="starling.events.Event")]
  73.  
  74. /**
  75.  * Dispatched when the soft keyboard is activated. Not all text editors will
  76.  * activate a soft keyboard.
  77.  *
  78.  * @eventType feathers.events.FeathersEventType.SOFT_KEYBOARD_ACTIVATE
  79.  */
  80. [Event(name="softKeyboardActivate", type="starling.events.Event")]
  81.  
  82. /**
  83.  * Dispatched when the soft keyboard is deactivated. Not all text editors
  84.  * will activate a soft keyboard.
  85.  *
  86.  * @eventType feathers.events.FeathersEventType.SOFT_KEYBOARD_DEACTIVATE
  87.  */
  88. [Event(name="softKeyboardDeactivate", type="starling.events.Event")]
  89.  
  90. /**
  91.  * A Feathers text editor that uses the native <code>StageText</code> class
  92.  * in AIR, and the custom <code>StageTextField</code> class (that simulates
  93.  * <code>StageText</code>) in Flash Player.
  94.  *
  95.  * @see http://wiki.starling-framework.org/feathers/text-editors
  96.  * @see flash.text.StageText
  97.  * @see feathers.text.StageTextField
  98.  */
  99. public class StageTextTextEditor extends FeathersControl implements ITextEditor {
  100.     /**
  101.      * @private
  102.      */
  103.     private static const HELPER_MATRIX:Matrix = new Matrix();
  104.  
  105.     /**
  106.      * @private
  107.      */
  108.     private static const HELPER_POINT:Point = new Point();
  109.  
  110.     /**
  111.      * @private
  112.      */
  113.     protected static const INVALIDATION_FLAG_POSITION:String = "position";
  114.  
  115.     /**
  116.      * Constructor.
  117.      */
  118.     public function StageTextTextEditor() {
  119.         this.isQuickHitAreaEnabled = true;
  120.         this.addEventListener(starling.events.Event.ADDED_TO_STAGE, addedToStageHandler);
  121.         this.addEventListener(starling.events.Event.REMOVED_FROM_STAGE, removedFromStageHandler);
  122.     }
  123.  
  124.     /**
  125.      * @private
  126.      */
  127.     override public function set x(value:Number):void {
  128.         super.x = value;
  129.         //we need to know when the position changes to change the position
  130.         //of the StageText instance.
  131.         this.invalidate(INVALIDATION_FLAG_POSITION);
  132.     }
  133.  
  134.     /**
  135.      * @private
  136.      */
  137.     override public function set y(value:Number):void {
  138.         super.y = value;
  139.         this.invalidate(INVALIDATION_FLAG_POSITION);
  140.     }
  141.  
  142.     /**
  143.      * The StageText instance. It's typed Object so that a replacement class
  144.      * can be used in browser-based Flash Player.
  145.      */
  146.     protected var stageText:Object;
  147.  
  148.     /**
  149.      * An image that displays a snapshot of the native <code>StageText</code>
  150.      * in the Starling display list when the editor doesn't have focus.
  151.      */
  152.     protected var textSnapshot:Image;
  153.  
  154.     /**
  155.      * @private
  156.      */
  157.     protected var _needsNewTexture:Boolean = false;
  158.  
  159.     /**
  160.      * @private
  161.      */
  162.     protected var _ignoreStageTextChanges:Boolean = false;
  163.  
  164.     /**
  165.      * @private
  166.      */
  167.     protected var _text:String = "";
  168.  
  169.     /**
  170.      * The text displayed by the input.
  171.      *
  172.      * <p>In the following example, the text is changed:</p>
  173.      *
  174.      * <listing version="3.0">
  175.      * textEditor.text = "Lorem ipsum";</listing>
  176.      *
  177.      * @default ""
  178.      */
  179.     public function get text():String {
  180.         return this._text;
  181.     }
  182.  
  183.     /**
  184.      * @private
  185.      */
  186.     public function set text(value:String):void {
  187.         if (!value) {
  188.             //don't allow null or undefined
  189.             value = "";
  190.         }
  191.         if (this._text == value) {
  192.             return;
  193.         }
  194.         this._text = value;
  195.         this.invalidate(INVALIDATION_FLAG_DATA);
  196.         this.dispatchEventWith(starling.events.Event.CHANGE);
  197.     }
  198.  
  199.     /**
  200.      * @private
  201.      */
  202.     protected var _measureTextField:TextField;
  203.  
  204.     /**
  205.      * @private
  206.      */
  207.     protected var _stageTextHasFocus:Boolean = false;
  208.  
  209.     /**
  210.      * @private
  211.      */
  212.     protected var _isWaitingToSetFocus:Boolean = false;
  213.  
  214.     /**
  215.      * @private
  216.      */
  217.     protected var _pendingSelectionStartIndex:int = -1;
  218.  
  219.     /**
  220.      * @private
  221.      */
  222.     protected var _pendingSelectionEndIndex:int = -1;
  223.  
  224.     /**
  225.      * @private
  226.      */
  227.     protected var _stageTextIsComplete:Boolean = false;
  228.  
  229.     /**
  230.      * @private
  231.      */
  232.     protected var _oldGlobalX:Number = 0;
  233.  
  234.     /**
  235.      * @private
  236.      */
  237.     protected var _oldGlobalY:Number = 0;
  238.  
  239.     /**
  240.      * @private
  241.      */
  242.     protected var _autoCapitalize:String = "none";
  243.  
  244.     /**
  245.      * Same as the <code>StageText</code> property with the same name.
  246.      *
  247.      * <p>In the following example, the auto capitalize behavior is changed:</p>
  248.      *
  249.      * <listing version="3.0">
  250.      * textEditor.autoCapitalize = AutoCapitalize.WORD;</listing>
  251.      *
  252.      * @default flash.text.AutoCapitalize.NONE
  253.      */
  254.     public function get autoCapitalize():String {
  255.         return this._autoCapitalize;
  256.     }
  257.  
  258.     /**
  259.      * @private
  260.      */
  261.     public function set autoCapitalize(value:String):void {
  262.         if (this._autoCapitalize == value) {
  263.             return;
  264.         }
  265.         this._autoCapitalize = value;
  266.         this.invalidate(INVALIDATION_FLAG_STYLES);
  267.     }
  268.  
  269.     /**
  270.      * @private
  271.      */
  272.     protected var _autoCorrect:Boolean = false;
  273.  
  274.     /**
  275.      * Same as the <code>StageText</code> property with the same name.
  276.      *
  277.      * <p>In the following example, auto correct is enabled:</p>
  278.      *
  279.      * <listing version="3.0">
  280.      * textEditor.autoCorrect = true;</listing>
  281.      *
  282.      * @default false
  283.      */
  284.     public function get autoCorrect():Boolean {
  285.         return this._autoCorrect;
  286.     }
  287.  
  288.     /**
  289.      * @private
  290.      */
  291.     public function set autoCorrect(value:Boolean):void {
  292.         if (this._autoCorrect == value) {
  293.             return;
  294.         }
  295.         this._autoCorrect = value;
  296.         this.invalidate(INVALIDATION_FLAG_STYLES);
  297.     }
  298.  
  299.     /**
  300.      * @private
  301.      */
  302.     protected var _color:uint = 0x000000;
  303.  
  304.     /**
  305.      * Same as the <code>StageText</code> property with the same name.
  306.      *
  307.      * <p>In the following example, the text color is changed:</p>
  308.      *
  309.      * <listing version="3.0">
  310.      * textEditor.color = 0xff9900;</listing>
  311.      *
  312.      * @default 0x000000
  313.      */
  314.     public function get color():uint {
  315.         return this._color as uint;
  316.     }
  317.  
  318.     /**
  319.      * @private
  320.      */
  321.     public function set color(value:uint):void {
  322.         if (this._color == value) {
  323.             return;
  324.         }
  325.         this._color = value;
  326.         this.invalidate(INVALIDATION_FLAG_STYLES);
  327.     }
  328.  
  329.     /**
  330.      * @private
  331.      */
  332.     protected var _displayAsPassword:Boolean = false;
  333.  
  334.     /**
  335.      * Same as the <code>StageText</code> property with the same name.
  336.      *
  337.      * <p>In the following example, the text is displayed as a password:</p>
  338.      *
  339.      * <listing version="3.0">
  340.      * textEditor.displayAsPassword = true;</listing>
  341.      *
  342.      * @default false
  343.      */
  344.     public function get displayAsPassword():Boolean {
  345.         return this._displayAsPassword;
  346.     }
  347.  
  348.     /**
  349.      * @private
  350.      */
  351.     public function set displayAsPassword(value:Boolean):void {
  352.         if (this._displayAsPassword == value) {
  353.             return;
  354.         }
  355.         this._displayAsPassword = value;
  356.         this.invalidate(INVALIDATION_FLAG_STYLES);
  357.     }
  358.  
  359.     /**
  360.      * @private
  361.      */
  362.     protected var _isEditable:Boolean = true;
  363.  
  364.     /**
  365.      * Determines if the text input is editable. If the text input is not
  366.      * editable, it will still appear enabled.
  367.      *
  368.      * <p>In the following example, the text is not editable:</p>
  369.      *
  370.      * <listing version="3.0">
  371.      * textEditor.isEditable = false;</listing>
  372.      *
  373.      * @default true
  374.      */
  375.     public function get isEditable():Boolean {
  376.         return this._isEditable;
  377.     }
  378.  
  379.     /**
  380.      * @private
  381.      */
  382.     public function set isEditable(value:Boolean):void {
  383.         if (this._isEditable == value) {
  384.             return;
  385.         }
  386.         this._isEditable = value;
  387.         this.invalidate(INVALIDATION_FLAG_STYLES);
  388.     }
  389.  
  390.     /**
  391.      * @inheritDoc
  392.      *
  393.      * @default true
  394.      */
  395.     public function get setTouchFocusOnEndedPhase():Boolean {
  396.         return true;
  397.     }
  398.  
  399.     /**
  400.      * @private
  401.      */
  402.     protected var _fontFamily:String = null;
  403.  
  404.     /**
  405.      * Same as the <code>StageText</code> property with the same name.
  406.      *
  407.      * <p>In the following example, the font family is changed:</p>
  408.      *
  409.      * <listing version="3.0">
  410.      * textEditor.fontFamily = "Source Sans Pro";</listing>
  411.      *
  412.      * @default null
  413.      */
  414.     public function get fontFamily():String {
  415.         return this._fontFamily;
  416.     }
  417.  
  418.     /**
  419.      * @private
  420.      */
  421.     public function set fontFamily(value:String):void {
  422.         if (this._fontFamily == value) {
  423.             return;
  424.         }
  425.         this._fontFamily = value;
  426.         this.invalidate(INVALIDATION_FLAG_STYLES);
  427.     }
  428.  
  429.     /**
  430.      * @private
  431.      */
  432.     protected var _fontPosture:String = FontPosture.NORMAL;
  433.  
  434.     /**
  435.      * Same as the <code>StageText</code> property with the same name.
  436.      *
  437.      * <p>In the following example, the font posture is changed:</p>
  438.      *
  439.      * <listing version="3.0">
  440.      * textEditor.fontPosture = FontPosture.ITALIC;</listing>
  441.      *
  442.      * @default flash.text.engine.FontPosture.NORMAL
  443.      */
  444.     public function get fontPosture():String {
  445.         return this._fontPosture;
  446.     }
  447.  
  448.     /**
  449.      * @private
  450.      */
  451.     public function set fontPosture(value:String):void {
  452.         if (this._fontPosture == value) {
  453.             return;
  454.         }
  455.         this._fontPosture = value;
  456.         this.invalidate(INVALIDATION_FLAG_STYLES);
  457.     }
  458.  
  459.     /**
  460.      * @private
  461.      */
  462.     protected var _fontSize:int = 12;
  463.  
  464.     /**
  465.      * Same as the <code>StageText</code> property with the same name.
  466.      *
  467.      * <p>In the following example, the font size is changed:</p>
  468.      *
  469.      * <listing version="3.0">
  470.      * textEditor.fontSize = 16;</listing>
  471.      *
  472.      * @default 12
  473.      */
  474.     public function get fontSize():int {
  475.         return this._fontSize;
  476.     }
  477.  
  478.     /**
  479.      * @private
  480.      */
  481.     public function set fontSize(value:int):void {
  482.         if (this._fontSize == value) {
  483.             return;
  484.         }
  485.         this._fontSize = value;
  486.         this.invalidate(INVALIDATION_FLAG_STYLES);
  487.     }
  488.  
  489.     /**
  490.      * @private
  491.      */
  492.     protected var _fontWeight:String = FontWeight.NORMAL;
  493.  
  494.     /**
  495.      * Same as the <code>StageText</code> property with the same name.
  496.      *
  497.      * <p>In the following example, the font weight is changed:</p>
  498.      *
  499.      * <listing version="3.0">
  500.      * textEditor.fontWeight = FontWeight.BOLD;</listing>
  501.      *
  502.      * @default flash.text.engine.FontWeight.NORMAL
  503.      */
  504.     public function get fontWeight():String {
  505.         return this._fontWeight;
  506.     }
  507.  
  508.     /**
  509.      * @private
  510.      */
  511.     public function set fontWeight(value:String):void {
  512.         if (this._fontWeight == value) {
  513.             return;
  514.         }
  515.         this._fontWeight = value;
  516.         this.invalidate(INVALIDATION_FLAG_STYLES);
  517.     }
  518.  
  519.     /**
  520.      * @private
  521.      */
  522.     protected var _locale:String = "en";
  523.  
  524.     /**
  525.      * Same as the <code>StageText</code> property with the same name.
  526.      *
  527.      * <p>In the following example, the locale is changed:</p>
  528.      *
  529.      * <listing version="3.0">
  530.      * textEditor.locale = "ru";</listing>
  531.      *
  532.      * @default "en"
  533.      */
  534.     public function get locale():String {
  535.         return this._locale;
  536.     }
  537.  
  538.     /**
  539.      * @private
  540.      */
  541.     public function set locale(value:String):void {
  542.         if (this._locale == value) {
  543.             return;
  544.         }
  545.         this._locale = value;
  546.         this.invalidate(INVALIDATION_FLAG_STYLES);
  547.     }
  548.  
  549.     /**
  550.      * @private
  551.      */
  552.     protected var _maxChars:int = 0;
  553.  
  554.     /**
  555.      * Same as the <code>StageText</code> property with the same name.
  556.      *
  557.      * <p>In the following example, the maximum character count is changed:</p>
  558.      *
  559.      * <listing version="3.0">
  560.      * textEditor.maxChars = 10;</listing>
  561.      *
  562.      * @default 0
  563.      */
  564.     public function get maxChars():int {
  565.         return this._maxChars;
  566.     }
  567.  
  568.     /**
  569.      * @private
  570.      */
  571.     public function set maxChars(value:int):void {
  572.         if (this._maxChars == value) {
  573.             return;
  574.         }
  575.         this._maxChars = value;
  576.         this.invalidate(INVALIDATION_FLAG_STYLES);
  577.     }
  578.  
  579.     /**
  580.      * @private
  581.      */
  582.     protected var _multiline:Boolean = false;
  583.  
  584.     /**
  585.      * Same as the <code>StageText</code> property with the same name,
  586.      * except it is configurable after the text renderer is created. The
  587.      * <code>StageText</code> instance will be disposed and recreated when
  588.      * this property changes after the <code>StageText</code> text was
  589.      * initially created.
  590.      *
  591.      * <p>In the following example, multiline is enabled:</p>
  592.      *
  593.      * <listing version="3.0">
  594.      * textEditor.multiline = true;</listing>
  595.      *
  596.      * @default false
  597.      */
  598.     public function get multiline():Boolean {
  599.         return this._multiline;
  600.     }
  601.  
  602.     /**
  603.      * @private
  604.      */
  605.     public function set multiline(value:Boolean):void {
  606.         if (this._multiline == value) {
  607.             return;
  608.         }
  609.         this._multiline = value;
  610.         this.invalidate(INVALIDATION_FLAG_STYLES);
  611.     }
  612.  
  613.     /**
  614.      * @private
  615.      */
  616.     protected var _restrict:String;
  617.  
  618.     /**
  619.      * Same as the <code>StageText</code> property with the same name.
  620.      *
  621.      * <p>In the following example, the text is restricted to numbers:</p>
  622.      *
  623.      * <listing version="3.0">
  624.      * textEditor.restrict = "0-9";</listing>
  625.      *
  626.      * @default null
  627.      */
  628.     public function get restrict():String {
  629.         return this._restrict;
  630.     }
  631.  
  632.     /**
  633.      * @private
  634.      */
  635.     public function set restrict(value:String):void {
  636.         if (this._restrict == value) {
  637.             return;
  638.         }
  639.         this._restrict = value;
  640.         this.invalidate(INVALIDATION_FLAG_STYLES);
  641.     }
  642.  
  643.     /**
  644.      * @private
  645.      */
  646.     protected var _returnKeyLabel:String = "default";
  647.  
  648.     /**
  649.      * Same as the <code>StageText</code> property with the same name.
  650.      *
  651.      * <p>In the following example, the return key label is changed:</p>
  652.      *
  653.      * <listing version="3.0">
  654.      * textEditor.returnKeyLabel = ReturnKeyLabel.GO;</listing>
  655.      *
  656.      * @default flash.text.ReturnKeyLabel.DEFAULT
  657.      */
  658.     public function get returnKeyLabel():String {
  659.         return this._returnKeyLabel;
  660.     }
  661.  
  662.     /**
  663.      * @private
  664.      */
  665.     public function set returnKeyLabel(value:String):void {
  666.         if (this._returnKeyLabel == value) {
  667.             return;
  668.         }
  669.         this._returnKeyLabel = value;
  670.         this.invalidate(INVALIDATION_FLAG_STYLES);
  671.     }
  672.  
  673.     /**
  674.      * @private
  675.      */
  676.     protected var _softKeyboardType:String = "default";
  677.  
  678.     /**
  679.      * Same as the <code>StageText</code> property with the same name.
  680.      *
  681.      * <p>In the following example, the soft keyboard type is changed:</p>
  682.      *
  683.      * <listing version="3.0">
  684.      * textEditor.softKeyboardType = SoftKeyboardType.NUMBER;</listing>
  685.      *
  686.      * @default flash.text.SoftKeyboardType.DEFAULT
  687.      */
  688.     public function get softKeyboardType():String {
  689.         return this._softKeyboardType;
  690.     }
  691.  
  692.     /**
  693.      * @private
  694.      */
  695.     public function set softKeyboardType(value:String):void {
  696.         if (this._softKeyboardType == value) {
  697.             return;
  698.         }
  699.         this._softKeyboardType = value;
  700.         this.invalidate(INVALIDATION_FLAG_STYLES);
  701.     }
  702.  
  703.     /**
  704.      * @private
  705.      */
  706.     protected var _textAlign:String = TextFormatAlign.START;
  707.  
  708.     /**
  709.      * Same as the <code>StageText</code> property with the same name.
  710.      *
  711.      * <p>In the following example, the text is centered:</p>
  712.      *
  713.      * <listing version="3.0">
  714.      * textEditor.textAlign = TextFormatAlign.CENTER;</listing>
  715.      *
  716.      * @default flash.text.TextFormatAlign.START
  717.      */
  718.     public function get textAlign():String {
  719.         return this._textAlign;
  720.     }
  721.  
  722.     /**
  723.      * @private
  724.      */
  725.     public function set textAlign(value:String):void {
  726.         if (this._textAlign == value) {
  727.             return;
  728.         }
  729.         this._textAlign = value;
  730.         this.invalidate(INVALIDATION_FLAG_STYLES);
  731.     }
  732.  
  733.     /**
  734.      * @private
  735.      */
  736.     override public function dispose():void {
  737.         this.disposeContent();
  738.         super.dispose();
  739.     }
  740.  
  741.     /**
  742.      * @private
  743.      */
  744.     override public function render(support:RenderSupport, parentAlpha:Number):void {
  745.         HELPER_POINT.x = HELPER_POINT.y = 0;
  746.         this.getTransformationMatrix(this.stage, HELPER_MATRIX);
  747.         MatrixUtil.transformCoords(HELPER_MATRIX, 0, 0, HELPER_POINT);
  748.         if (HELPER_POINT.x != this._oldGlobalX || HELPER_POINT.y != this._oldGlobalY) {
  749.             this._oldGlobalX = HELPER_POINT.x;
  750.             this._oldGlobalY = HELPER_POINT.y;
  751.             const starlingViewPort:Rectangle = Starling.current.viewPort;
  752.             var stageTextViewPort:Rectangle = this.stageText.viewPort;
  753.             if (!stageTextViewPort) {
  754.                 stageTextViewPort = new Rectangle();
  755.             }
  756.             stageTextViewPort.x = Math.round(starlingViewPort.x + (HELPER_POINT.x * Starling.contentScaleFactor));
  757.             stageTextViewPort.y = Math.round(starlingViewPort.y + (HELPER_POINT.y * Starling.contentScaleFactor));
  758.             this.stageText.viewPort = stageTextViewPort;
  759.         }
  760.  
  761.         if (this.textSnapshot) {
  762.             this.textSnapshot.x = Math.round(HELPER_MATRIX.tx) - HELPER_MATRIX.tx;
  763.             this.textSnapshot.y = Math.round(HELPER_MATRIX.ty) - HELPER_MATRIX.ty;
  764.         }
  765.  
  766.         super.render(support, parentAlpha);
  767.     }
  768.  
  769.     /**
  770.      * @inheritDoc
  771.      */
  772.     public function setFocus(position:Point = null):void {
  773.         if (this.stageText && this._stageTextIsComplete) {
  774.             if (position) {
  775.                 const positionX:Number = position.x;
  776.                 const positionY:Number = position.y;
  777.                 if (positionX < 0) {
  778.                     this._pendingSelectionStartIndex = this._pendingSelectionEndIndex = 0;
  779.                 } else {
  780.                     this._pendingSelectionStartIndex = this._measureTextField.getCharIndexAtPoint(positionX, positionY);
  781.                     if (this._pendingSelectionStartIndex < 0) {
  782.                         if (this._multiline) {
  783.                             const lineIndex:int = int(positionY / this._measureTextField.getLineMetrics(0).height);
  784.                             try {
  785.                                 this._pendingSelectionStartIndex = this._measureTextField.getLineOffset(lineIndex) + this._measureTextField.getLineLength(lineIndex);
  786.                                 if (this._pendingSelectionStartIndex != this._text.length) {
  787.                                     this._pendingSelectionStartIndex--;
  788.                                 }
  789.                             } catch (error:Error) {
  790.                                 //we may be checking for a line beyond the
  791.                                 //end that doesn't exist
  792.                                 this._pendingSelectionStartIndex = this._text.length;
  793.                             }
  794.                         } else {
  795.                             this._pendingSelectionStartIndex = this._text.length;
  796.                         }
  797.                     } else {
  798.                         const bounds:Rectangle = this._measureTextField.getCharBoundaries(this._pendingSelectionStartIndex);
  799.                         const boundsX:Number = bounds.x;
  800.                         if (bounds && (boundsX + bounds.width - positionX) < (positionX - boundsX)) {
  801.                             this._pendingSelectionStartIndex++;
  802.                         }
  803.                     }
  804.                     this._pendingSelectionEndIndex = this._pendingSelectionStartIndex;
  805.                 }
  806.             } else {
  807.                 this._pendingSelectionStartIndex = this._pendingSelectionEndIndex = -1;
  808.             }
  809.             this.stageText.visible = true;
  810.             this.stageText.assignFocus();
  811.         } else {
  812.             this._isWaitingToSetFocus = true;
  813.         }
  814.     }
  815.  
  816.     /**
  817.      * @inheritDoc
  818.      */
  819.     public function clearFocus():void {
  820.         if (!this._stageTextHasFocus) {
  821.             return;
  822.         }
  823.         Starling.current.nativeStage.focus = Starling.current.nativeStage;
  824.         this.dispatchEventWith(FeathersEventType.FOCUS_OUT);
  825.     }
  826.  
  827.     /**
  828.      * @inheritDoc
  829.      */
  830.     public function selectRange(startIndex:int, endIndex:int):void {
  831.         if (this._stageTextIsComplete && this.stageText) {
  832.             this._pendingSelectionStartIndex = -1;
  833.             this._pendingSelectionEndIndex = -1;
  834.             this.stageText.selectRange(startIndex, endIndex);
  835.         } else {
  836.             this._pendingSelectionStartIndex = startIndex;
  837.             this._pendingSelectionEndIndex = endIndex;
  838.         }
  839.     }
  840.  
  841.     /**
  842.      * @inheritDoc
  843.      */
  844.     public function measureText(result:Point = null):Point {
  845.         if (!result) {
  846.             result = new Point();
  847.         }
  848.  
  849.         if (!this._measureTextField) {
  850.             result.x = result.y = 0;
  851.             return result;
  852.         }
  853.  
  854.         const needsWidth:Boolean = isNaN(this.explicitWidth);
  855.         const needsHeight:Boolean = isNaN(this.explicitHeight);
  856.         if (!needsWidth && !needsHeight) {
  857.             result.x = this.explicitWidth;
  858.             result.y = this.explicitHeight;
  859.             return result;
  860.         }
  861.  
  862.  
  863.         const stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
  864.         const dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
  865.  
  866.         if (stylesInvalid || dataInvalid) {
  867.             this.refreshMeasureProperties();
  868.         }
  869.  
  870.         result = this.measure(result);
  871.  
  872.         return result;
  873.     }
  874.  
  875.     /**
  876.      * @private
  877.      */
  878.     override protected function draw():void {
  879.         var sizeInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SIZE);
  880.  
  881.         this.commit();
  882.  
  883.         sizeInvalid = this.autoSizeIfNeeded() || sizeInvalid;
  884.  
  885.         this.layout(sizeInvalid);
  886.     }
  887.  
  888.     /**
  889.      * @private
  890.      */
  891.     protected function commit():void {
  892.         const stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE);
  893.         const stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
  894.         const dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
  895.  
  896.         if (stylesInvalid || dataInvalid) {
  897.             this.refreshMeasureProperties();
  898.         }
  899.  
  900.         const oldIgnoreStageTextChanges:Boolean = this._ignoreStageTextChanges;
  901.         this._ignoreStageTextChanges = true;
  902.         if (stylesInvalid) {
  903.             this.refreshStageTextProperties();
  904.         }
  905.  
  906.         if (dataInvalid) {
  907.             if (this.stageText.text != this._text) {
  908.                 if (this._pendingSelectionStartIndex < 0) {
  909.                     this._pendingSelectionStartIndex = this.stageText.selectionActiveIndex;
  910.                     this._pendingSelectionEndIndex = this.stageText.selectionAnchorIndex;
  911.                 }
  912.                 this.stageText.text = this._text;
  913.             }
  914.         }
  915.         this._ignoreStageTextChanges = oldIgnoreStageTextChanges;
  916.  
  917.         if (stylesInvalid || stateInvalid) {
  918.             this.stageText.editable = this._isEditable && this._isEnabled;
  919.         }
  920.     }
  921.  
  922.     /**
  923.      * @private
  924.      */
  925.     protected function measure(result:Point = null):Point {
  926.         if (!result) {
  927.             result = new Point();
  928.         }
  929.  
  930.         const needsWidth:Boolean = isNaN(this.explicitWidth);
  931.         const needsHeight:Boolean = isNaN(this.explicitHeight);
  932.  
  933.         this._measureTextField.autoSize = TextFieldAutoSize.LEFT;
  934.  
  935.         var newWidth:Number = this.explicitWidth;
  936.         if (needsWidth) {
  937.             newWidth = Math.max(this._minWidth, Math.min(this._maxWidth, this._measureTextField.width));
  938.         }
  939.  
  940.         this._measureTextField.width = newWidth;
  941.         var newHeight:Number = this.explicitHeight;
  942.         if (needsHeight) {
  943.             newHeight = Math.max(this._minHeight, Math.min(this._maxHeight, this._measureTextField.height));
  944.         }
  945.  
  946.         this._measureTextField.autoSize = TextFieldAutoSize.NONE;
  947.  
  948.         //put the width and height back just in case we measured without
  949.         //a full validation
  950.         this._measureTextField.width = this.actualWidth;
  951.         this._measureTextField.height = this.actualHeight;
  952.  
  953.         result.x = newWidth;
  954.         result.y = newHeight;
  955.  
  956.         return result;
  957.     }
  958.  
  959.     /**
  960.      * @private
  961.      */
  962.     protected function layout(sizeInvalid:Boolean):void {
  963.         const stateInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STATE);
  964.         const stylesInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_STYLES);
  965.         const dataInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_DATA);
  966.         const positionInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_POSITION);
  967.         const skinInvalid:Boolean = this.isInvalid(INVALIDATION_FLAG_SKIN);
  968.  
  969.         if (positionInvalid || sizeInvalid || stylesInvalid || skinInvalid || stateInvalid) {
  970.             this.refreshViewPort();
  971.             const viewPort:Rectangle = this.stageText.viewPort;
  972.             const textureRoot:ConcreteTexture = this.textSnapshot ? this.textSnapshot.texture.root : null;
  973.             this._needsNewTexture = this._needsNewTexture || !this.textSnapshot || viewPort.width != textureRoot.width || viewPort.height != textureRoot.height;
  974.         }
  975.  
  976.         if (!this._stageTextHasFocus && (stylesInvalid || dataInvalid || sizeInvalid || this._needsNewTexture)) {
  977.             const hasText:Boolean = this._text.length > 0;
  978.             if (hasText) {
  979.                 this.refreshSnapshot();
  980.             }
  981.             if (this.textSnapshot) {
  982.                 this.textSnapshot.visible = !this._stageTextHasFocus;
  983.                 this.textSnapshot.alpha = hasText ? 1 : 0;
  984.                 if (!this._stageTextHasFocus) {
  985.                     this.stageText.visible = false;
  986.                 }
  987.             }
  988.         }
  989.  
  990.         this.doPendingActions();
  991.     }
  992.  
  993.     /**
  994.      * If the component's dimensions have not been set explicitly, it will
  995.      * measure its content and determine an ideal size for itself. If the
  996.      * <code>explicitWidth</code> or <code>explicitHeight</code> member
  997.      * variables are set, those value will be used without additional
  998.      * measurement. If one is set, but not the other, the dimension with the
  999.      * explicit value will not be measured, but the other non-explicit
  1000.      * dimension will still need measurement.
  1001.      *
  1002.      * <p>Calls <code>setSizeInternal()</code> to set up the
  1003.      * <code>actualWidth</code> and <code>actualHeight</code> member
  1004.      * variables used for layout.</p>
  1005.      *
  1006.      * <p>Meant for internal use, and subclasses may override this function
  1007.      * with a custom implementation.</p>
  1008.      */
  1009.     protected function autoSizeIfNeeded():Boolean {
  1010.         const needsWidth:Boolean = isNaN(this.explicitWidth);
  1011.         const needsHeight:Boolean = isNaN(this.explicitHeight);
  1012.         if (!needsWidth && !needsHeight) {
  1013.             return false;
  1014.         }
  1015.  
  1016.         this.measure(HELPER_POINT);
  1017.         return this.setSizeInternal(HELPER_POINT.x, HELPER_POINT.y, false);
  1018.     }
  1019.  
  1020.     /**
  1021.      * @private
  1022.      */
  1023.     protected function refreshMeasureProperties():void {
  1024.         this._measureTextField.displayAsPassword = this._displayAsPassword;
  1025.         this._measureTextField.maxChars = this._maxChars;
  1026.         this._measureTextField.restrict = this._restrict;
  1027.         this._measureTextField.multiline = this._measureTextField.wordWrap = this._multiline;
  1028.  
  1029.         const format:TextFormat = this._measureTextField.defaultTextFormat;
  1030.         format.color = this._color;
  1031.         format.font = this._fontFamily;
  1032.         format.italic = this._fontPosture == FontPosture.ITALIC;
  1033.         format.size = this._fontSize;
  1034.         format.bold = this._fontWeight == FontWeight.BOLD;
  1035.         var alignValue:String = this._textAlign;
  1036.         if (alignValue == TextFormatAlign.START) {
  1037.             alignValue = TextFormatAlign.LEFT;
  1038.         } else if (alignValue == TextFormatAlign.END) {
  1039.             alignValue = TextFormatAlign.RIGHT;
  1040.         }
  1041.         format.align = alignValue;
  1042.         this._measureTextField.defaultTextFormat = format;
  1043.         this._measureTextField.setTextFormat(format);
  1044.         this._measureTextField.text = this._text;
  1045.     }
  1046.  
  1047.     /**
  1048.      * @private
  1049.      */
  1050.     protected function refreshStageTextProperties():void {
  1051.         if (this.stageText.multiline != this._multiline) {
  1052.             if (this.stageText) {
  1053.                 this.disposeStageText();
  1054.             }
  1055.             this.createStageText();
  1056.         }
  1057.  
  1058.         this.stageText.autoCapitalize = this._autoCapitalize;
  1059.         this.stageText.autoCorrect = this._autoCorrect;
  1060.         this.stageText.color = this._color;
  1061.         this.stageText.displayAsPassword = this._displayAsPassword;
  1062.         this.stageText.fontFamily = this._fontFamily;
  1063.         this.stageText.fontPosture = this._fontPosture;
  1064.  
  1065.         this.getTransformationMatrix(this.stage, HELPER_MATRIX);
  1066.         var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX);
  1067.         var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX);
  1068.         var smallerGlobalScale:Number = globalScaleX;
  1069.         if (globalScaleY < globalScaleX) {
  1070.             smallerGlobalScale = globalScaleY;
  1071.         }
  1072.         this.stageText.fontSize = this._fontSize * Starling.contentScaleFactor * smallerGlobalScale;
  1073.  
  1074.         this.stageText.fontWeight = this._fontWeight;
  1075.         this.stageText.locale = this._locale;
  1076.         this.stageText.maxChars = this._maxChars;
  1077.         this.stageText.restrict = this._restrict;
  1078.         this.stageText.returnKeyLabel = this._returnKeyLabel;
  1079.         this.stageText.softKeyboardType = this._softKeyboardType;
  1080.         this.stageText.textAlign = this._textAlign;
  1081.     }
  1082.  
  1083.     /**
  1084.      * @private
  1085.      */
  1086.     protected function doPendingActions():void {
  1087.         if (this._isWaitingToSetFocus) {
  1088.             this._isWaitingToSetFocus = false;
  1089.             this.setFocus();
  1090.         }
  1091.         if (this._pendingSelectionStartIndex >= 0) {
  1092.             const startIndex:int = this._pendingSelectionStartIndex;
  1093.             const endIndex:int = (this._pendingSelectionEndIndex < 0) ? this._pendingSelectionStartIndex : this._pendingSelectionEndIndex;
  1094.             this._pendingSelectionStartIndex = -1;
  1095.             this._pendingSelectionEndIndex = -1;
  1096.             this.selectRange(startIndex, endIndex);
  1097.         }
  1098.     }
  1099.  
  1100.     /**
  1101.      * @private
  1102.      */
  1103.     protected function texture_onRestore():void {
  1104.         this.refreshSnapshot();
  1105.         if (this.textSnapshot) {
  1106.             this.textSnapshot.visible = !this._stageTextHasFocus;
  1107.             this.textSnapshot.alpha = this._text.length > 0 ? 1 : 0;
  1108.             if (!this._stageTextHasFocus) {
  1109.                 this.stageText.visible = false;
  1110.             }
  1111.         }
  1112.     }
  1113.  
  1114.     /**
  1115.      * @private
  1116.      */
  1117.     protected function refreshSnapshot():void {
  1118.         const viewPort:Rectangle = this.stageText.viewPort;
  1119.         if (viewPort.width == 0 || viewPort.height == 0) {
  1120.             return;
  1121.         }
  1122.  
  1123.         //StageText sucks because it requires that the BitmapData's width
  1124.         //and height exactly match its view port width and height.
  1125.         var bitmapData:BitmapData = new BitmapData(viewPort.width, viewPort.height, true, 0x00ff00ff);
  1126.         this.stageText.drawViewPortToBitmapData(bitmapData);
  1127.  
  1128.         var newTexture:Texture;
  1129.         if (!this.textSnapshot || this._needsNewTexture) {
  1130.             newTexture = Texture.fromBitmapData(bitmapData, false, false, Starling.contentScaleFactor);
  1131.             newTexture.root.onRestore = texture_onRestore;
  1132.         }
  1133.         if (!this.textSnapshot) {
  1134.             this.textSnapshot = new Image(newTexture);
  1135.             this.addChild(this.textSnapshot);
  1136.         } else {
  1137.             if (this._needsNewTexture) {
  1138.                 this.textSnapshot.texture.dispose();
  1139.                 this.textSnapshot.texture = newTexture;
  1140.                 this.textSnapshot.readjustSize();
  1141.             } else {
  1142.                 //this is faster, if we haven't resized the bitmapdata
  1143.                 const existingTexture:Texture = this.textSnapshot.texture;
  1144.                 existingTexture.root.uploadBitmapData(bitmapData);
  1145.             }
  1146.         }
  1147.         this.getTransformationMatrix(this.stage, HELPER_MATRIX);
  1148.         this.textSnapshot.scaleX = 1 / matrixToScaleX(HELPER_MATRIX);
  1149.         this.textSnapshot.scaleY = 1 / matrixToScaleY(HELPER_MATRIX);
  1150.         bitmapData.dispose();
  1151.         this._needsNewTexture = false;
  1152.     }
  1153.  
  1154.     /**
  1155.      * @private
  1156.      */
  1157.     protected function refreshViewPort():void {
  1158.         const starlingViewPort:Rectangle = Starling.current.viewPort;
  1159.         var stageTextViewPort:Rectangle = this.stageText.viewPort;
  1160.         if (!stageTextViewPort) {
  1161.             stageTextViewPort = new Rectangle();
  1162.         }
  1163.         if (!this.stageText.stage) {
  1164.             this.stageText.stage = Starling.current.nativeStage;
  1165.         }
  1166.  
  1167.         HELPER_POINT.x = HELPER_POINT.y = 0;
  1168.         this.getTransformationMatrix(this.stage, HELPER_MATRIX);
  1169.         var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX);
  1170.         var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX);
  1171.         MatrixUtil.transformCoords(HELPER_MATRIX, 0, 0, HELPER_POINT);
  1172.         this._oldGlobalX = HELPER_POINT.x;
  1173.         this._oldGlobalY = HELPER_POINT.y;
  1174.         stageTextViewPort.x = Math.round(starlingViewPort.x + HELPER_POINT.x * Starling.contentScaleFactor);
  1175.         stageTextViewPort.y = Math.round(starlingViewPort.y + HELPER_POINT.y * Starling.contentScaleFactor);
  1176.         var viewPortWidth:Number = Math.round(this.actualWidth * Starling.contentScaleFactor * globalScaleX);
  1177.         if (viewPortWidth < 1 || isNaN(viewPortWidth)) {
  1178.             viewPortWidth = 1;
  1179.         }
  1180.         var viewPortHeight:Number = Math.round(this.actualHeight * Starling.contentScaleFactor * globalScaleY);
  1181.         if (viewPortHeight < 1 || isNaN(viewPortHeight)) {
  1182.             viewPortHeight = 1;
  1183.         }
  1184.         stageTextViewPort.width = viewPortWidth;
  1185.         stageTextViewPort.height = viewPortHeight;
  1186.         this.stageText.viewPort = stageTextViewPort;
  1187.  
  1188.         this._measureTextField.width = this.actualWidth;
  1189.         this._measureTextField.height = this.actualHeight;
  1190.     }
  1191.  
  1192.     /**
  1193.      * @private
  1194.      */
  1195.     protected function disposeContent():void {
  1196.         if (this._measureTextField) {
  1197.             Starling.current.nativeStage.removeChild(this._measureTextField);
  1198.             this._measureTextField = null;
  1199.         }
  1200.  
  1201.         if (this.stageText) {
  1202.             this.disposeStageText();
  1203.         }
  1204.  
  1205.         if (this.textSnapshot) {
  1206.             //avoid the need to call dispose(). we'll create a new snapshot
  1207.             //when the renderer is added to stage again.
  1208.             this.textSnapshot.texture.dispose();
  1209.             this.removeChild(this.textSnapshot, true);
  1210.             this.textSnapshot = null;
  1211.         }
  1212.     }
  1213.  
  1214.     /**
  1215.      * @private
  1216.      */
  1217.     protected function disposeStageText():void {
  1218.         if (!this.stageText) {
  1219.             return;
  1220.         }
  1221.         this.stageText.removeEventListener(flash.events.Event.CHANGE, stageText_changeHandler);
  1222.         this.stageText.removeEventListener(KeyboardEvent.KEY_DOWN, stageText_keyDownHandler);
  1223.         this.stageText.removeEventListener(KeyboardEvent.KEY_UP, stageText_keyUpHandler);
  1224.         this.stageText.removeEventListener(FocusEvent.FOCUS_IN, stageText_focusInHandler);
  1225.         this.stageText.removeEventListener(FocusEvent.FOCUS_OUT, stageText_focusOutHandler);
  1226.         this.stageText.removeEventListener(flash.events.Event.COMPLETE, stageText_completeHandler);
  1227.         this.stageText.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, stageText_softKeyboardActivateHandler);
  1228.         this.stageText.removeEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, stageText_softKeyboardDeactivateHandler);
  1229.         this.stageText.stage = null;
  1230.         this.stageText.dispose();
  1231.         this.stageText = null;
  1232.     }
  1233.  
  1234.     /**
  1235.      * Creates and adds the <code>stageText</code> instance.
  1236.      *
  1237.      * <p>Meant for internal use, and subclasses may override this function
  1238.      * with a custom implementation.</p>
  1239.      */
  1240.     protected function createStageText():void {
  1241.         this._stageTextIsComplete = false;
  1242.         var StageTextType:Class;
  1243.         var initOptions:Object;
  1244.         try {
  1245.             StageTextType = Class(getDefinitionByName("flash.text.StageText"));
  1246.             const StageTextInitOptionsType:Class = Class(getDefinitionByName("flash.text.StageTextInitOptions"));
  1247.             initOptions = new StageTextInitOptionsType(this._multiline);
  1248.         } catch (error:Error) {
  1249.             StageTextType = StageTextField;
  1250.             initOptions = {multiline: this._multiline};
  1251.         }
  1252.         this.stageText = new StageTextType(initOptions);
  1253.         this.stageText.visible = false;
  1254.         this.stageText.addEventListener(flash.events.Event.CHANGE, stageText_changeHandler);
  1255.         this.stageText.addEventListener(KeyboardEvent.KEY_DOWN, stageText_keyDownHandler);
  1256.         this.stageText.addEventListener(KeyboardEvent.KEY_UP, stageText_keyUpHandler);
  1257.         this.stageText.addEventListener(FocusEvent.FOCUS_IN, stageText_focusInHandler);
  1258.         this.stageText.addEventListener(FocusEvent.FOCUS_OUT, stageText_focusOutHandler);
  1259.         this.stageText.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, stageText_softKeyboardActivateHandler);
  1260.         this.stageText.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, stageText_softKeyboardDeactivateHandler);
  1261.         this.stageText.addEventListener(flash.events.Event.COMPLETE, stageText_completeHandler);
  1262.         this.invalidate();
  1263.     }
  1264.  
  1265.     /**
  1266.      * @private
  1267.      */
  1268.     protected function addedToStageHandler(event:starling.events.Event):void {
  1269.         if (this._measureTextField && !this._measureTextField.parent) {
  1270.             Starling.current.nativeStage.addChild(this._measureTextField);
  1271.         } else if (!this._measureTextField) {
  1272.             this._measureTextField = new TextField();
  1273.             this._measureTextField.visible = false;
  1274.             this._measureTextField.mouseEnabled = this._measureTextField.mouseWheelEnabled = false;
  1275.             this._measureTextField.autoSize = TextFieldAutoSize.LEFT;
  1276.             this._measureTextField.multiline = false;
  1277.             this._measureTextField.wordWrap = false;
  1278.             this._measureTextField.embedFonts = false;
  1279.             this._measureTextField.defaultTextFormat = new TextFormat(null, 11, 0x000000, false, false, false);
  1280.             Starling.current.nativeStage.addChild(this._measureTextField);
  1281.         }
  1282.  
  1283.         this.createStageText();
  1284.     }
  1285.  
  1286.     /**
  1287.      * @private
  1288.      */
  1289.     protected function removedFromStageHandler(event:starling.events.Event):void {
  1290.         this.disposeContent();
  1291.     }
  1292.  
  1293.     /**
  1294.      * @private
  1295.      */
  1296.     protected function stageText_changeHandler(event:flash.events.Event):void {
  1297.         if (this._ignoreStageTextChanges) {
  1298.             return;
  1299.         }
  1300.         this.text = this.stageText.text;
  1301.     }
  1302.  
  1303.     /**
  1304.      * @private
  1305.      */
  1306.     protected function stageText_completeHandler(event:flash.events.Event):void {
  1307.         this.stageText.removeEventListener(flash.events.Event.COMPLETE, stageText_completeHandler);
  1308.         this.invalidate();
  1309.  
  1310.         this._stageTextIsComplete = true;
  1311.     }
  1312.  
  1313.     /**
  1314.      * @private
  1315.      */
  1316.     protected function stageText_focusInHandler(event:FocusEvent):void {
  1317.         this._stageTextHasFocus = true;
  1318.         if (this.textSnapshot) {
  1319.             this.textSnapshot.visible = false;
  1320.         }
  1321.         this.invalidate(INVALIDATION_FLAG_SKIN);
  1322.         this.dispatchEventWith(FeathersEventType.FOCUS_IN);
  1323.     }
  1324.  
  1325.     /**
  1326.      * @private
  1327.      */
  1328.     protected function stageText_focusOutHandler(event:FocusEvent):void {
  1329.         this._stageTextHasFocus = false;
  1330.         //since StageText doesn't expose its scroll position, we need to
  1331.         //set the selection back to the beginning to scroll there. it's a
  1332.         //hack, but so is everything about StageText.
  1333.         //in other news, why won't 0,0 work here?
  1334.         this.stageText.selectRange(1, 1);
  1335.  
  1336.         this.invalidate(INVALIDATION_FLAG_DATA);
  1337.         this.invalidate(INVALIDATION_FLAG_SKIN);
  1338.         this.dispatchEventWith(FeathersEventType.FOCUS_OUT);
  1339.  
  1340.         deletePan();
  1341.     }
  1342.  
  1343.     /**
  1344.      * @private
  1345.      */
  1346.     protected function stageText_keyDownHandler(event:KeyboardEvent):void {
  1347.         if (!this._multiline && (event.keyCode == Keyboard.ENTER || event.keyCode == Keyboard.NEXT)) {
  1348.             event.preventDefault();
  1349.             this.dispatchEventWith(FeathersEventType.ENTER);
  1350.         } else if (event.keyCode == Keyboard.BACK) {
  1351.             //even a listener on the stage won't detect the back key press that
  1352.             //will close the application if the StageText has focus, so we
  1353.             //always need to prevent it here
  1354.             event.preventDefault();
  1355.             Starling.current.nativeStage.focus = Starling.current.nativeStage;
  1356.         }
  1357.     }
  1358.  
  1359.     /**
  1360.      * @private
  1361.      */
  1362.     protected function stageText_keyUpHandler(event:KeyboardEvent):void {
  1363.         if (!this._multiline && (event.keyCode == Keyboard.ENTER || event.keyCode == Keyboard.NEXT)) {
  1364.             event.preventDefault();
  1365.         }
  1366.     }
  1367.  
  1368.     /**
  1369.      * @private
  1370.      */
  1371.     protected function stageText_softKeyboardActivateHandler(event:SoftKeyboardEvent):void {
  1372.         addPan();
  1373.  
  1374.         this.dispatchEventWith(FeathersEventType.SOFT_KEYBOARD_ACTIVATE, true);
  1375.     }
  1376.  
  1377.     /**
  1378.      * @private
  1379.      */
  1380.     protected function stageText_softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void {
  1381.         this.dispatchEventWith(FeathersEventType.SOFT_KEYBOARD_DEACTIVATE, true);
  1382.  
  1383.         deletePan();
  1384.     }
  1385.  
  1386.     var panAmount = 0;
  1387.  
  1388.     private function addPan():void {
  1389.         AndroidSoftKeyboardHelper.onSoftKeyboardInitialized(movePan);
  1390.     }
  1391.  
  1392.     private function movePan():void {
  1393.         if (!AndroidSoftKeyboardHelper.isNeeded) {
  1394.             return;
  1395.         }
  1396.  
  1397.         var softKeyboardHeight:int = AndroidSoftKeyboardHelper.SoftKeyboardHeight;
  1398.         if (softKeyboardHeight <= 0) {
  1399.             softKeyboardHeight = Starling.current.nativeStage.softKeyboardRect.height;
  1400.         }
  1401.  
  1402.         if (panAmount == 0 && Starling.current != null && Starling.current.nativeStage != null && Starling.current.root != null) {
  1403.             var positionStarlingY = 0;
  1404.             var target = this;
  1405.             while (target != null) {
  1406.                 positionStarlingY += target.y;
  1407.                 target = target.parent;
  1408.             }
  1409.  
  1410.             positionStarlingY += this.parent.height;
  1411.  
  1412.             var fullScreenHeight:Number = Starling.current.nativeStage.fullScreenHeight;
  1413.             var screenHeight:Number = Starling.current.nativeStage.stageHeight;
  1414.             var fullScreenWidth:Number = Starling.current.nativeStage.fullScreenWidth;
  1415.  
  1416.             var navigationBarAtHeight:Number = fullScreenHeight - screenHeight; // Calculates navigation bar of the Operating System if app is not full screen
  1417.             var navigationBarAtWidth:Number = fullScreenWidth - Starling.current.nativeStage.stageWidth;
  1418.             var maxNavigationBarLength:Number = Math.max(navigationBarAtHeight, navigationBarAtWidth);
  1419.  
  1420.  
  1421.             panAmount = Math.max(0, positionStarlingY - (fullScreenHeight - softKeyboardHeight - maxNavigationBarLength));
  1422.  
  1423.             Starling.current.root.y -= panAmount;
  1424.         }
  1425.     }
  1426.  
  1427.     private function deletePan():void {
  1428.         if (!AndroidSoftKeyboardHelper.isNeeded) {
  1429.             return;
  1430.         }
  1431.  
  1432.         if (panAmount != 0) {
  1433.             Starling.current.root.y += panAmount;
  1434.             panAmount = 0;
  1435.         }
  1436.     }
  1437. }
  1438. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement