Advertisement
Guest User

Untitled

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