PageRenderTime 4981ms CodeModel.GetById 33ms RepoModel.GetById 2ms app.codeStats 1ms

/client/lib/haxegui/controls/Component.hx

http://github.com/ericmuyser/mmo
Haxe | 1534 lines | 639 code | 253 blank | 642 comment | 106 complexity | 93db8c0471f4097df088cfc4926683a8 MD5 | raw file
  1. // Copyright (c) 2009 The haxegui developers
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  4. // this software and associated documentation files (the "Software"), to deal in
  5. // the Software without restriction, including without limitation the rights to
  6. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  7. // the Software, and to permit persons to whom the Software is furnished to do so,
  8. // subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in all
  11. // copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  15. // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  16. // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  17. // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  18. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. package haxegui.controls;
  20. //{{{ Imports
  21. import feffects.Tween;
  22. import flash.accessibility.Accessibility;
  23. import flash.accessibility.AccessibilityImplementation;
  24. import flash.accessibility.AccessibilityProperties;
  25. import flash.display.BitmapData;
  26. import flash.display.DisplayObject;
  27. import flash.display.DisplayObjectContainer;
  28. import flash.display.Sprite;
  29. import flash.events.Event;
  30. import flash.events.FocusEvent;
  31. import flash.events.KeyboardEvent;
  32. import flash.events.MouseEvent;
  33. import flash.geom.ColorTransform;
  34. import flash.geom.Point;
  35. import flash.geom.Rectangle;
  36. import haxegui.Haxegui;
  37. import haxegui.Window;
  38. import haxegui.events.MoveEvent;
  39. import haxegui.events.ResizeEvent;
  40. import haxegui.managers.CursorManager;
  41. import haxegui.managers.FocusManager;
  42. import haxegui.managers.ScriptManager;
  43. import haxegui.managers.TooltipManager;
  44. import haxegui.toys.Transformer;
  45. import haxegui.utils.Color;
  46. import haxegui.utils.Opts;
  47. import haxegui.utils.Size;
  48. //}}}
  49. /**
  50. *
  51. * Component is the basic protoype for all components.<br/>
  52. * <p>It is not an abstract class, in a sense, it is amorphic, its visual appearance can easily and dynamically change at runtime.
  53. * It derives from [Sprite] so all the flash api drawing functions apply, but take a look at [redraw] function for what you more you can do.</p>
  54. * <p>More than being just the parent class, handing down all widgets with properties and functions (and having some static functions of its own),
  55. * the class abstracts some of its functionality to script. This is similar to how 3D engines pass the handling of material rendering to various script files and shaders</p>
  56. * <p>Some widgets have hard-coded actions, the default event listener callback of this class is overriden in the those cases, but still after that code executes the script action is fired.
  57. * This is because of the untyped nature of hscript, that code is better written in haxe. Most widgets just have default scripts loaded into them, which is easier to customize.</p>
  58. * <p>Controling how the component looks is just one action, the following can be used along with normal event listeners:
  59. * validate, interval, mouseClick, mouseOver, mouseOut, mouseDown, mouseUp, gainingFocus, losingFocus, focusIn, focusOut</p>
  60. * <p>Notice that even disabled components execute actions, its up for the script to respond properly.</p>
  61. * <p>Each component carries around not only an [id], but also a [box], its the [Rectangle] that will be used for drawing calculations.
  62. * This is due to several reasons, the vector rather than bitmap nature of the graphics, it prevents errors that might result when drawing transparent regions (but still allows you to do that),
  63. * its a good union of visual properites to pass around between components, has some handy functions as a class, and leaves you free to scale the result.</p>
  64. * <p>When a [ResizeEvent] is fired the listener's response typicaly uses that [box].</p>
  65. * <p>One more thing to note, is that a [MoveEvent] only fires when using the functions from this class, when manually moving a component with its inherited [x] and [y] properties, dispatch as needed.
  66. * </p>
  67. * @author Omer Goshen <gershon@goosemoose.com>
  68. * @author Russell Weir <damonsbane@gmail.com>
  69. * @version 0.26
  70. *
  71. *
  72. */
  73. class Component
  74. extends Sprite,
  75. implements IAccessible,
  76. implements IMovable,
  77. implements IToolTip,
  78. implements ITween,
  79. implements IValidate,
  80. implements haxe.rtti.Infos
  81. // implements haxe.Public,
  82. // implements Dynamic
  83. {
  84. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  85. //{{{ Members
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. //{{{ Private
  88. /** Current color tween in effect **/
  89. private var colorTween : Tween;
  90. /** Current saturation tween in effect **/
  91. private var saturationTween : Tween;
  92. /** Current position tween in effect **/
  93. private var positionTween : Tween;
  94. /** The initial opts **/
  95. private var initOpts : Dynamic;
  96. /** Number of interval calls per second **/
  97. private var intervalUpdatesPerSec : Float;
  98. /** Last timestamp when an interval occured **/
  99. private var lastInterval : Float;
  100. //}}}
  101. //{{{ Public
  102. /** A flag raised while tweening **/
  103. public var isTweening : Bool;
  104. /** Rectangular dimensions **/
  105. public var box : Rectangle;
  106. /** Minimum size **/
  107. public var minSize : Size;
  108. /** @todo Maximum size **/
  109. public var maxSize : Size;
  110. /** The color of this component, which has different meanings per component **/
  111. public var color : UInt;
  112. /** Disabled \ Enabled **/
  113. public var disabled(__getDisabled, __setDisabled) : Bool;
  114. /** Flag for when component needs a redraw **/
  115. public var dirty(__getDirty,__setDirty) : Bool;
  116. /** Whether the component can gain focus **/
  117. public var focusable : Bool;
  118. /** Unique component id number **/
  119. public var id(default, null) : Int;
  120. /** Creation timestamp **/
  121. public var created(default, null) : Float;
  122. /** Reference for tooltip **/
  123. public var tooltip : Tooltip;
  124. /** Component description for tooltip \ accessbility **/
  125. public var description : String;
  126. /** Does object validate ? **/
  127. public var validates : Bool;
  128. /** Fit horizontaly to parent **/
  129. public var fitH : Bool;
  130. /** Fit verticaly to parent **/
  131. public var fitV : Bool;
  132. public var allowedParents : Array<Class<Dynamic>>;
  133. public var left : Float;
  134. public var right : Float;
  135. public var top : Float;
  136. public var bottom : Float;
  137. //}}}
  138. //{{{ Static
  139. /** The static component id counter **/
  140. private static var nextId : Int = 0;
  141. //}}}
  142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. //}}}
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146. //{{{ Constructor
  147. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  148. /**
  149. * The common constructor for all components.<br>
  150. *
  151. * Each component is given a unique id, it then gets his name either by parameter, or by its class name.<br>
  152. *
  153. * Next the constructor sets some variables to default, like disabled to false, and focusable to true,
  154. * and registers all event listeners, component is moved to position, and is waiting to get more properties at init().
  155. *
  156. * @param DisplayObjectContainer to attach to, will default to root
  157. * @param Component's name
  158. * @param Horizontal position relative to parent
  159. * @param Vertical position relative to parent
  160. **/
  161. public function new (parent:DisplayObjectContainer=null, name:String=null, ?x:Float, ?y:Float) {
  162. super ();
  163. // id from static
  164. this.id = Component.nextId++;
  165. this.created = haxe.Timer.stamp();
  166. //
  167. color = Color.MAGENTA;
  168. box = new Rectangle();
  169. minSize = new Size();
  170. maxSize = Size.square(2<<15);
  171. //
  172. tabEnabled = mouseEnabled = true;
  173. buttonMode = false;
  174. focusable = true;
  175. doubleClickEnabled = true;
  176. disabled = false;
  177. // Name from given parameter or classname and id
  178. if(name!=null)
  179. this.name = name;
  180. else
  181. this.name = Type.getClassName(Type.getClass(this)).split(".").pop() + id;
  182. // Tooltip text
  183. description = this.name;
  184. // Attach to parent
  185. if(parent!=null)
  186. parent.addChild(this);
  187. else
  188. flash.Lib.current.addChild(this);
  189. // Move
  190. move(x,y);
  191. // Listeners
  192. addEventListener (Event.ADDED, onAdded, false, 0, true);
  193. addEventListener (FocusEvent.FOCUS_IN, onFocusIn, false, 0, true);
  194. addEventListener (FocusEvent.FOCUS_OUT, onFocusOut, false, 0, true);
  195. addEventListener (FocusEvent.KEY_FOCUS_CHANGE, __focusHandler, false, 0, true);
  196. addEventListener (FocusEvent.MOUSE_FOCUS_CHANGE, __focusHandler, false, 0, true);
  197. addEventListener (KeyboardEvent.KEY_DOWN, onKeyDown, false, 0, true);
  198. addEventListener (KeyboardEvent.KEY_UP, onKeyUp, false, 0, true);
  199. addEventListener (MouseEvent.CLICK, onMouseClick, false, 0, true);
  200. addEventListener (MouseEvent.DOUBLE_CLICK, onMouseDoubleClick, false, 0, true);
  201. addEventListener (MouseEvent.MOUSE_DOWN, onMouseDown, false, 0, true);
  202. addEventListener (MouseEvent.MOUSE_OUT, onRollOut, false, 0, true);
  203. addEventListener (MouseEvent.MOUSE_OVER, onRollOver, false, 0, true);
  204. addEventListener (MouseEvent.MOUSE_UP, onMouseUp, false, 0, true);
  205. addEventListener (MouseEvent.MOUSE_WHEEL, onMouseWheel, false, 0, true);
  206. addEventListener (ResizeEvent.RESIZE, onResize, false, 0, true);
  207. }
  208. //}}}
  209. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  210. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  211. //{{{ Functions
  212. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. //{{{ Public
  214. //{{{ toString
  215. override public function toString() : String {
  216. return this.name + "[" + Type.getClassName(Type.getClass(this)) + "]";
  217. }
  218. //}}}
  219. //{{{ init
  220. /**
  221. * Initialize a component<br/>
  222. *
  223. * When init() is called, the component overrides any default properties, and sets any new, it is ready draw to screen,
  224. * and sets the dirty flag to true.
  225. *
  226. * Writing in haxe, it is true to assume that the component and all his children have finished initializing and are on screen by the next line of code,
  227. * in xml that is not the case, please use the onLoaded action for that.
  228. *
  229. * <pre class="code haxe">
  230. * var c = new Component();
  231. * c.init({});
  232. * </pre>
  233. *
  234. * The function does'nt return anything, but it's still possible in haxe to do:
  235. * <pre class="code haxe">
  236. * var c = new Component().init({});
  237. * </pre>
  238. *
  239. * Note that hscript does'nt support dynamic objects, so just set any needed property manually:
  240. * <pre class="code haxe">
  241. * var c = new Component();
  242. * c.box = new Size(100,40).toRect();
  243. * c.color = 0xff00ff;
  244. * c.init();
  245. * </pre>
  246. *
  247. * @param opts Initial options object
  248. */
  249. public function init(opts:Dynamic=null) {
  250. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  251. if(opts == null || !Reflect.isObject(opts)) opts = {};
  252. alpha = Opts.optFloat (opts, "alpha", alpha);
  253. box.height = Opts.optFloat (opts, "height", box.height);
  254. box.width = Opts.optFloat (opts, "width", box.width);
  255. buttonMode = Opts.optBool (opts, "buttonMode", false);
  256. color = Opts.optInt (opts, "color", color);
  257. description = Opts.optString(opts, "description", description);
  258. disabled = Opts.optBool (opts, "disabled", false);
  259. fitH = Opts.optBool (opts, "fitH", false);
  260. fitV = Opts.optBool (opts, "fitV", false);
  261. mouseChildren = Opts.optBool (opts, "mouseChildren", mouseChildren);
  262. mouseEnabled = Opts.optBool (opts, "mouseEnabled" , mouseEnabled);
  263. name = Opts.optString(opts, "name", name);
  264. rotation = Opts.optFloat (opts, "rotation", rotation);
  265. visible = Opts.optBool (opts, "visible", true);
  266. scaleX = Opts.optFloat (opts, "scaleX", scaleX);
  267. scaleY = Opts.optFloat (opts, "scaleY", scaleY);
  268. x = Opts.optFloat (opts, "x", x);
  269. y = Opts.optFloat (opts, "y", y);
  270. left = Opts.optFloat (opts, "left", left);
  271. right = Opts.optFloat (opts, "right", right);
  272. top = Opts.optFloat (opts, "top", top);
  273. bottom = Opts.optFloat (opts, "bottom", bottom);
  274. //
  275. var accessProps = new AccessibilityProperties();
  276. accessProps.name = name;
  277. accessProps.description = description;
  278. accessibilityProperties = accessProps;
  279. // keep the opts in a member
  280. initOpts = Opts.clone(opts);
  281. // request a redraw
  282. dirty = true;
  283. haxegui.Profiler.end();
  284. }
  285. //}}}
  286. //{{{ destroy
  287. /**
  288. * Destroy this component and all children
  289. */
  290. public function destroy() : Void {
  291. removeChildren();
  292. stopInterval();
  293. if(this.parent != null)
  294. this.parent.removeChild(this);
  295. //~ flash.system.System.gc();
  296. }
  297. //}}}
  298. //{{{ clone
  299. /**
  300. * @todo check this works for everything, should probably write a test...
  301. */
  302. public function clone() : Dynamic {
  303. var type = Type.getClass(this);
  304. var inst = Type.createInstance(type, [parent, name+"_clone", x, y]);
  305. Reflect.callMethod( inst, inst.init, [Opts.clone(initOpts)] );
  306. // trace(inst);
  307. return inst;
  308. }
  309. //}}}
  310. //{{{ Actions & Script
  311. //{{{ getAction
  312. /**
  313. * Returns the code associated with the specified action. If this instance
  314. * does not have a script, the default from the upstyle is returned.
  315. *
  316. * @param action Action name
  317. * @return String code
  318. **/
  319. public function getAction(action:String) : String {
  320. try {
  321. return ScriptManager.getInstanceActionObject(this, action).code;
  322. }
  323. catch(e:Dynamic) {
  324. trace(e);
  325. return null;
  326. }
  327. }
  328. //}}}
  329. //{{{ getOwnAction
  330. /**
  331. * Returns the code associated with this instance for the specified action.
  332. *
  333. * @param action Action name
  334. * @return String code
  335. **/
  336. public function getOwnAction(action:String) : String {
  337. return try ScriptManager.getInstanceOwnActionObject(this, action).code
  338. catch(e:Dynamic) null;
  339. }
  340. //}}}
  341. //{{{ getParentWindow
  342. /**
  343. * Returns the window this component is contained in, if any
  344. *
  345. * @return Parent [Window] or null
  346. **/
  347. public function getParentWindow() : Window {
  348. var p = this.parent;
  349. while(p != null && !Std.is(p,Window)) {
  350. p = p.parent;
  351. }
  352. return cast p;
  353. }
  354. //}}}
  355. //{{{ getParentContainer
  356. public function getParentContainer() : Dynamic {
  357. for(i in ancestors())
  358. if(Std.is(i, haxegui.containers.IContainer)) return i;
  359. return null;
  360. }
  361. //}}}
  362. //{{{ hasAction
  363. /**
  364. * Returns true if this component has an action
  365. * registered for the action type [action]. If this instance
  366. * does not have an override, the default from the style is
  367. * checked.
  368. *
  369. * @param action Action name
  370. * @return Bool true if an action exists
  371. **/
  372. public function hasAction(action:String) : Bool {
  373. var c = try ScriptManager.getInstanceActionObject(this, action) catch(e:Dynamic) null;
  374. return (c != null);
  375. }
  376. //}}}
  377. //{{{ hasOwnAction
  378. /**
  379. * Returns true if this component has an action registered
  380. * for the action type [action]. Only returns true if the
  381. * script is only for this instance.
  382. *
  383. * @param action Action name
  384. * @return Bool true if an action exists
  385. **/
  386. public function hasOwnAction(action:String) : Bool {
  387. return (ScriptManager.getInstanceOwnActionObject(this,action) != null);
  388. }
  389. //}}}
  390. //{{{ setAction
  391. /**
  392. * Sets the action code for the specified action name for this component.
  393. *
  394. * @param action Action name
  395. * @param code Action code
  396. **/
  397. public function setAction(action:String, code:String) : Void {
  398. ScriptManager.setInstanceScript(this, action, code);
  399. }
  400. //}}}
  401. //{{{ startInterval
  402. /**
  403. * Starts an interval timer, which calls the "interval" action.
  404. *
  405. * @param updatesPerSecond Number of times per second the interval action will be called
  406. **/
  407. public function startInterval(updatesPerSecond : Float) : Void {
  408. startIntervalDelayed(updatesPerSecond, 0.0);
  409. }
  410. //}}}
  411. //{{{ startIntervalDelayed
  412. /**
  413. * Starts an interval timer, which calls the "interval" action, after waiting [wait] seconds
  414. *
  415. * @param updatesPerSecond Number of times per second the interval action will be called
  416. * @param wait Number of seconds to wait before the first update.
  417. **/
  418. public function startIntervalDelayed(updatesPerSecond : Float, wait : Float) : Void {
  419. stopInterval();
  420. if(updatesPerSecond < 1) return;
  421. if(Math.isNaN(wait)) wait = 0.0;
  422. lastInterval = haxe.Timer.stamp() + wait;
  423. intervalUpdatesPerSec = updatesPerSecond;
  424. //~ this.addEventListener(flash.events.Event.ENTER_FRAME, onEnterFrame);
  425. this.addEventListener(flash.events.Event.ENTER_FRAME, onEnterFrame, false, 200, true);
  426. }
  427. //}}}
  428. //{{{ stopInterval
  429. /**
  430. * Stop the current interval timer
  431. **/
  432. public function stopInterval() : Void {
  433. this.removeEventListener(flash.events.Event.ENTER_FRAME, onEnterFrame);
  434. }
  435. //}}}
  436. //{{{ isValid
  437. /** Returns whether object validates **/
  438. public function isValid() : Bool {
  439. if(!hasAction("validate"))
  440. return true;
  441. var rv = ScriptManager.exec(this, "validate", {});
  442. if(rv == null) return true;
  443. return cast rv;
  444. }
  445. //}}}
  446. //}}}
  447. //{{{ Transformations
  448. //{{{ rotate
  449. public inline function rotate(a:Float) : Void {
  450. this.rotation += a;
  451. }
  452. //}}}
  453. //{{{ rotateTo
  454. public inline function rotateTo(a:Float) : Void {
  455. this.rotation = a;
  456. }
  457. //}}}
  458. //{{{ place
  459. /**
  460. * Absolute placement, no event sent
  461. * @param x offset relative to parent
  462. * @param y offset relative to parent
  463. **/
  464. public inline function place(x : Float, y : Float) : Void {
  465. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  466. this.x = box.x = x;
  467. this.y = box.y = y;
  468. haxegui.Profiler.end();
  469. }
  470. //}}}
  471. //{{{ moveTo
  472. /**
  473. * Move to specific location.
  474. * @param x offset relative to parent
  475. * @param y offset relative to parent
  476. **/
  477. public inline function moveTo(x : Float, y : Float) : Void {
  478. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  479. var event = new MoveEvent(MoveEvent.MOVE, this.x, this.y);
  480. this.x = x;
  481. this.y = y;
  482. box.x = x;
  483. box.y = y;
  484. // if(Haxegui.gridSnapping) {
  485. // box.x = this.x -= this.x % Haxegui.gridSpacing;
  486. // box.y = this.y -= this.y % Haxegui.gridSpacing;
  487. // }
  488. if(!isTweening)
  489. dispatchEvent(event);
  490. haxegui.Profiler.end();
  491. }
  492. //}}}
  493. //{{{ move
  494. /**
  495. * Move relative to current location.
  496. * @param x Horizontal offset relative to current position
  497. * @param y Vertical offset relative to current position
  498. **/
  499. public inline function move(x : Float, y : Float) : Void {
  500. moveTo(this.x + x, this.y + y);
  501. }
  502. //}}}
  503. //{{{ moveToPoint
  504. /** Move to absolute position [Point], relative to parent **/
  505. public inline function moveToPoint(p:Point) : Void {
  506. moveTo(p.x, p.y);
  507. }
  508. //}}}
  509. //{{{ movePoint
  510. /** Move by [Point], relative to current position **/
  511. public inline function movePoint(p:Point) : Void {
  512. moveToPoint(p.add(new Point(x,y)));
  513. }
  514. //}}}
  515. //{{{ snap
  516. /** Snap position to grid
  517. * @see [Haxegui.gridSpacing]
  518. */
  519. public inline function snap() {
  520. move(- x % Haxegui.gridSpacing, - y % Haxegui.gridSpacing);
  521. }
  522. //}}}
  523. //{{{ center
  524. /** Move to parent's center **/
  525. public inline function center() {
  526. if(parent==flash.Lib.current)
  527. moveTo(Std.int(stage.stageWidth-box.width)>>1, Std.int(stage.stageHeight-box.height)>>1);
  528. else
  529. moveTo(Std.int((cast parent).box.width-box.width)>>1, Std.int((cast parent).box.height-box.height)>>1);
  530. }
  531. //}}}
  532. //{{{ resize
  533. /**
  534. * Resize box to [Size]
  535. * @return Rectangle new size
  536. **/
  537. public function resize(b:Size) : Rectangle {
  538. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  539. var event = new ResizeEvent(ResizeEvent.RESIZE);
  540. event.oldWidth = box.width;
  541. event.oldHeight = box.height;
  542. box = b.setAtLeastZero().toRect();
  543. if(Haxegui.gridSnapping) {
  544. box.width = box.width - box.width % Haxegui.gridSpacing;
  545. box.height = box.height - box.height % Haxegui.gridSpacing;
  546. }
  547. dispatchEvent(event);
  548. haxegui.Profiler.end();
  549. return box;
  550. }
  551. //}}}
  552. //}}}
  553. //{{{ Layering
  554. //{{{ raise
  555. /**
  556. * Raise one layer
  557. * @return Int new depth
  558. **/
  559. public function raise() : Int {
  560. var d = Std.int(Math.max(0, Math.min(parent.numChildren-1, parent.getChildIndex(this)+1)));
  561. parent.setChildIndex(this, d);
  562. return d;
  563. }
  564. //}}}
  565. //{{{ lower
  566. /**
  567. * Lower one layer
  568. * @return Int new depth
  569. **/
  570. public function lower() : Int {
  571. var d = Std.int(Math.max(0, Math.min(parent.numChildren-1, parent.getChildIndex(this)-1)));
  572. parent.setChildIndex(this, d);
  573. return d;
  574. }
  575. //}}}
  576. //{{{ toFront
  577. /**
  578. * Raise to top layer
  579. * @return Int new depth
  580. **/
  581. public function toFront() : Int {
  582. parent.setChildIndex(this, parent.numChildren-1);
  583. //return parent.numChildren-1;
  584. return parent.getChildIndex(this);
  585. }
  586. //}}}
  587. //{{{ toBack
  588. /**
  589. * Lower to bottom
  590. * @return Void
  591. **/
  592. public function toBack() : Void {
  593. parent.setChildIndex(this, 0);
  594. }
  595. //}}}
  596. //}}}
  597. //{{{ Iterators & DOM
  598. //{{{ iterator
  599. /**
  600. * Returns iterator of all children.
  601. * <pre class="code haxe">
  602. * if(this.haxeNext())
  603. * for(child in this)
  604. * ...
  605. * </pre>
  606. * @return Iterator<DisplayObject> Iterator for children
  607. */
  608. public function iterator() : Iterator<DisplayObject> {
  609. var l = new List<DisplayObject>();
  610. for(i in 0...numChildren)
  611. l.add(getChildAt(i));
  612. return l.iterator();
  613. }
  614. //}}}
  615. //{{{ ancestors
  616. /**
  617. * Returns iterator of all ancestors.
  618. * Example:
  619. * for(parent in component.ancestors())
  620. *
  621. * @return Iterator<DisplayObject> Iterator for parents
  622. */
  623. public function ancestors() : Iterator<DisplayObject> {
  624. var l = new List<DisplayObject>();
  625. var p = parent;
  626. while(p!=null) {
  627. l.add(p);
  628. p = p.parent;
  629. }
  630. return l.iterator();
  631. }
  632. //}}}
  633. //{{{ firstChild
  634. /** @return First child as [DisplayObject] **/
  635. public function firstChild() : DisplayObject {
  636. return numChildren==0 ? null : getChildAt(0);
  637. }
  638. //}}}
  639. //{{{ isEmpty
  640. /** @return True when component has no children **/
  641. public function isEmpty() : Bool {
  642. return firstChild() == null;
  643. }
  644. //}}}
  645. //{{{ prevSibling
  646. /** @return The previous sibling in the display list **/
  647. public function prevSibling() : DisplayObject {
  648. var p = Component.asComponent(parent);
  649. for(i in p)
  650. if(i==this)
  651. if(p.getChildIndex(this)>0) return p.getChildAt(p.getChildIndex(this)-1);
  652. return null;
  653. }
  654. //}}}
  655. //{{{ nextSibling
  656. /** @return The next sibling in the display list **/
  657. public function nextSibling() : DisplayObject {
  658. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  659. // var p = Component.asComponent(parent);
  660. var i = parent.getChildIndex(this);
  661. if(parent.numChildren==i) return null;
  662. // for(i in p)
  663. // if(i==this)
  664. // if(p.getChildIndex(this)<p.numChildren) return p.getChildAt(p.getChildIndex(this)+1);
  665. // return null;
  666. haxegui.Profiler.end();
  667. return parent.getChildAt(i+1);
  668. }
  669. //}}}
  670. //{{{ getChildById
  671. /** @return Returns a child by given id number **/
  672. public function getChildById(id:Int) : DisplayObject {
  673. for(i in this)
  674. if(Std.is(i, Component))
  675. if((cast i).id==id) return i;
  676. return null;
  677. }
  678. //}}}
  679. //{{{ getElementsByClass
  680. /**
  681. * Returns an iterator for all children of type.
  682. * @param c Class to match
  683. * @return All children of type [c]
  684. */
  685. public function getElementsByClass(c:Class<Dynamic>) : Iterator<Dynamic> {
  686. var l = new List<Dynamic>();
  687. for(i in this)
  688. if(Std.is(i, c))
  689. l.add(i);
  690. return l.iterator();
  691. }
  692. //}}}
  693. //{{{ getElementsByClassList
  694. /**
  695. * Returns an array of all children of type.
  696. * @param c Class to match
  697. * @return All children of type [c]
  698. */
  699. public function getElementsByClassArray(c:Class<Dynamic>) : Array<Dynamic> {
  700. var a = new Array<Dynamic>();
  701. for(i in this)
  702. if(Std.is(i, c))
  703. a.push(i);
  704. return a;
  705. }
  706. //}}}
  707. //{{{ removeChildren
  708. /**
  709. * Remove all children
  710. */
  711. public function removeChildren() : Void {
  712. for(child in this)
  713. if(Std.is(child, Component))
  714. (cast child).destroy();
  715. else
  716. removeChild(child);
  717. }
  718. //}}}
  719. //}}}
  720. //{{{ getVisibleChildren
  721. public function getHiddenChildren() {
  722. return Lambda.filter(this, function(o) { return !o.visible; });
  723. }
  724. //}}}
  725. //{{{ getVisibleChildren
  726. public function getVisibleChildren() {
  727. return Lambda.filter(this, function(o) { return o.visible; });
  728. }
  729. //}}}
  730. //{{{ replaceChild
  731. /**
  732. * @param newChild Child to add
  733. * @param oldChild Child to replace
  734. * @return Reference to new child
  735. **/
  736. public function replaceChild(newChild:Component, oldChild:Component) : Component {
  737. var i = getChildIndex(oldChild);
  738. oldChild.destroy();
  739. setChildIndex(newChild, i);
  740. return newChild;
  741. }
  742. //}}}
  743. //{{{ swapParent
  744. public function swapParent(np:DisplayObjectContainer) : Void {
  745. if(np==null) throw "new parent is null";
  746. np.addChild(this);
  747. }
  748. //}}}
  749. //{{{ hasFocus
  750. /**
  751. * @todo fix this
  752. **/
  753. public function hasFocus() : Bool {
  754. return FocusManager.getInstance().getFocus() == this ? true : false;
  755. }
  756. //}}}
  757. //{{{ swapChildrenVisible
  758. public function swapChildrenVisible(c:DisplayObject, d:DisplayObject) {
  759. c.visible = !c.visible;
  760. d.visible = !d.visible;
  761. }
  762. //}}}
  763. //{{{ swapChildrenVisibleAt
  764. public function swapChildrenVisibleAt(i:Int, j:Int) {
  765. swapChildrenVisible(getChildAt(i), getChildAt(j));
  766. }
  767. //}}}
  768. //{{{ Tweening
  769. //{{{ updateColorTween
  770. /**
  771. * Stops the current(if there is one), and creates a new color tween
  772. * <pre class="code haxe">
  773. * this.updateColorTween( new feffects.Tween(0, 100, 1000, feffects.easing.Expo.easeOut ) );
  774. * </pre>
  775. * @param t The [Tween] to use
  776. * @todo rgb color transformation
  777. **/
  778. public function updateColorTween(?t : Tween = null) : Void {
  779. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  780. var me = this;
  781. var colorTrans = new ColorTransform();
  782. if(colorTween != null)
  783. colorTween.stop();
  784. colorTween = t;
  785. if(t==null) return;
  786. colorTween.setTweenHandlers(
  787. function(v) {
  788. colorTrans.redOffset =
  789. colorTrans.greenOffset =
  790. colorTrans.blueOffset = v;
  791. me.transform.colorTransform = colorTrans;
  792. // me.isTweening = true;
  793. },
  794. function(v){
  795. // me.isTweening = false;
  796. me.colorTween = null;
  797. colorTrans = null;
  798. }
  799. );
  800. colorTween.start();
  801. haxegui.Profiler.end();
  802. }
  803. //}}}
  804. //{{{ updateSaturationTween
  805. /**
  806. * Stops the current(if there is one), and creates a new color tween
  807. * <pre class="code haxe">
  808. * this.updateColorTween( new feffects.Tween(0, 100, 1000, feffects.easing.Expo.easeOut ) );
  809. * </pre>
  810. * @param t The [Tween] to use
  811. * @todo rgb color transformation
  812. **/
  813. public function updateSaturationTween(?t : Tween = null) : Void {
  814. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  815. var me = this;
  816. if(saturationTween != null)
  817. saturationTween.stop();
  818. saturationTween = t;
  819. if(t==null) return;
  820. saturationTween.setTweenHandlers(
  821. function(v) {
  822. // me.isTweening = true;
  823. var b : Float = v / 3;
  824. var c : Float = 1 - (b * 2);
  825. var mtx : Array<Float> = [
  826. c, b, b, 0, 0,
  827. b, c, b, 0, 0,
  828. b, b, c, 0, 0,
  829. 0, 0, 0, 1, 0];
  830. me.filters = [new flash.filters.ColorMatrixFilter(mtx)];
  831. },
  832. function(v){
  833. // me.isTweening = false;
  834. me.saturationTween = null;
  835. }
  836. );
  837. saturationTween.start();
  838. haxegui.Profiler.end();
  839. }
  840. //}}}
  841. //{{{ updatePositionTween
  842. /**
  843. * Stops the old position tween and assign a new one.
  844. * <pre class="code haxe">
  845. * this.updatePositionTween( new feffects.Tween(0, 1, 1000, feffects.easing.Expo.easeOut ), new Point(x,y));
  846. * </pre>
  847. * @param t Tween to use
  848. * @param p Relative destination
  849. * @param f Optional function called on update
  850. * @return Void
  851. */
  852. public function updatePositionTween(?t:Tween=null, ?p:Point, ?f:Float->Void) : Void {
  853. var me = this;
  854. var oldPos = new Point(this.x,this.y);
  855. if(positionTween != null)
  856. positionTween.stop();
  857. positionTween = t;
  858. if(t==null) return;
  859. positionTween.setTweenHandlers(
  860. function(v) {
  861. var pos = Point.interpolate(p, new Point(), v);
  862. pos = pos.add(oldPos);
  863. me.isTweening = true;
  864. // me.moveTo(pos.x, pos.y);
  865. me.x = pos.x;
  866. me.y = pos.y;
  867. if(f!=null) f(v);
  868. },
  869. function(v) {
  870. me.positionTween = null;
  871. me.isTweening = false;
  872. }
  873. );
  874. positionTween.start();
  875. }
  876. //}}}
  877. //}}}
  878. //{{{ Events
  879. //{{{ onAdded
  880. /** Triggered by addChild() or addChildAt() **/
  881. public function onAdded(e:Event) {}
  882. //}}}
  883. //{{{ onClick
  884. /** Placeholder for [onMouseClick]
  885. * <pre class="code haxe">
  886. * trace("Do not use onClick, use onMouseClick");
  887. * onMouseClick(e);
  888. * </pre>
  889. **/
  890. private function onClick(e:MouseEvent) {
  891. trace("Do not use onClick, use onMouseClick");
  892. onMouseClick(e);
  893. }
  894. //}}}
  895. //{{{ onFocusIn
  896. /**
  897. * When a component is gaining focus, this event occurs twice.
  898. *
  899. * The first time, [focusFrom] is set to the object losing focus.
  900. *
  901. * The second time, [focusFrom == this] which shows that all parents
  902. * have been notified of the focus change.
  903. * @param e the [FocusEvent]
  904. **/
  905. public function onFocusIn(e:FocusEvent) {
  906. if(disabled) return;
  907. // -- Fired twice: first time --
  908. // related == object losing focus
  909. // target == object gaining focus
  910. // currentTarget == this
  911. // -- second time --
  912. // related == null
  913. // target == currentTarget == this
  914. //trace("++++ " + Std.string(this) + " onFocusIn");
  915. //trace("onFocusIn relatedObject: " + Std.string(e.relatedObject));
  916. //trace("onFocusIn currentTarget: " + Std.string(e.currentTarget));
  917. //trace("onFocusIn target: " + Std.string(e.target));
  918. ScriptManager.exec(this, "focusIn", {focusFrom : e.target});
  919. }
  920. //}}}
  921. //{{{ onFocusOut
  922. /**
  923. * When a component is losing focus, this event occurs
  924. *
  925. * [focusTo] is set to the object gaining focus.
  926. *
  927. * @param e the [FocusEvent]
  928. **/
  929. private function onFocusOut(e:FocusEvent) : Void {
  930. if(disabled) return;
  931. //trace("++++ " + Std.string(this) + " onFocusOut");
  932. //trace("onFocusOut relatedObject: " + Std.string(e.relatedObject));
  933. //trace("onFocusOut currentTarget: " + Std.string(e.currentTarget));
  934. //trace("onFocusOut target: " + Std.string(e.target));
  935. // -- Fired twice : a real mess... we just need one
  936. if(e.relatedObject != null)
  937. ScriptManager.exec(this, "focusOut", {focusTo : e.relatedObject});
  938. }
  939. //}}}
  940. //{{{ onGainingFocus
  941. /**
  942. * If the component will not take focus, return false from this handler
  943. * which will cancel the focus transfer.
  944. *
  945. * @param from the [InteractiveObject] who lost focus
  946. * @return Bool wheter the component will take focus
  947. **/
  948. public function onGainingFocus(from : flash.display.InteractiveObject) : Bool {
  949. var rv : Dynamic = ScriptManager.exec(this,"gainingFocus", {focusFrom : from});
  950. //trace(here.methodName + " " + rv);
  951. if(rv == null || rv == true)
  952. return true;
  953. return false;
  954. }
  955. //}}}
  956. //{{{ onLosingFocus
  957. /**
  958. * Dispatched to this object when it is about to lose focus
  959. *
  960. * @param losingTo the [InteractiveObject] who is currently getting focused
  961. * @return Bool true to allow change, false to prevent focus change
  962. **/
  963. public function onLosingFocus(losingTo : flash.display.InteractiveObject) : Bool {
  964. var rv : Dynamic = ScriptManager.exec(this,"losingFocus", {focusTo : losingTo});
  965. if(rv == null)
  966. return true;
  967. return cast rv;
  968. }
  969. //}}}
  970. //{{{ onRollOver
  971. /** onRollOver Event **/
  972. public function onRollOver(e:MouseEvent) {
  973. if(CursorManager.getInstance().lock) return;
  974. if(description!=null) TooltipManager.getInstance().create(this);
  975. ScriptManager.exec(this,"mouseOver", {event : e});
  976. }
  977. //}}}
  978. //{{{ onRollOut
  979. /** onRollOut Event **/
  980. public function onRollOut(e:MouseEvent) : Void {
  981. if(CursorManager.getInstance().lock) return;
  982. if(description!=null) TooltipManager.getInstance().destroy();
  983. ScriptManager.exec(this,"mouseOut", {event : e});
  984. }
  985. //}}}
  986. //{{{ onMouseDoubleClick
  987. /** Mouse double-click **/
  988. public function onMouseDoubleClick(e:MouseEvent) : Void {
  989. #if debug
  990. // if(e.target == this)
  991. // trace("onMouseDoubleClick " + this.name + " (trgt: " + e.target + ") hasOwnAction:" + hasOwnAction("mouseDoubleClick"));
  992. #end
  993. ScriptManager.exec(this,"mouseDoubleClick", {event : e});
  994. }
  995. //}}}
  996. //{{{ onMouseClick
  997. /** Mouse click **/
  998. public function onMouseClick(e:MouseEvent) : Void {
  999. #if debug
  1000. // trace(e);
  1001. #end
  1002. if(description!=null) TooltipManager.getInstance().destroy();
  1003. ScriptManager.exec(this, "mouseClick", {event : e});
  1004. }
  1005. //}}}
  1006. //{{{ onMouseDown
  1007. /**
  1008. * Mouse Down
  1009. * @todo remove transformer
  1010. **/
  1011. public function onMouseDown(e:MouseEvent) : Void {
  1012. #if debug
  1013. // trace(e);
  1014. #end
  1015. if(e.ctrlKey) {
  1016. e.stopImmediatePropagation();
  1017. // dont transform transformers
  1018. if(Std.is(this, haxegui.toys.Transformer) || Std.is(this.parent, haxegui.toys.Transformer)) return;
  1019. var t = new haxegui.toys.Transformer(this);
  1020. t.init();
  1021. var p = (cast this).localToGlobal( new flash.geom.Point(this.x, this.y) );
  1022. t.x = p.x - this.x - Transformer.handleSize;
  1023. t.y = p.y - this.y - Transformer.handleSize;
  1024. // no point in doing the normal action, user wants to transform
  1025. return;
  1026. }
  1027. if(description!=null) TooltipManager.getInstance().destroy();
  1028. ScriptManager.exec(this,"mouseDown", {event : e});
  1029. }
  1030. //}}}
  1031. //{{{ onMouseUp
  1032. /** Mouse Up **/
  1033. public function onMouseUp(e:MouseEvent) : Void {
  1034. ScriptManager.exec(this,"mouseUp", {event : e});
  1035. }
  1036. //}}}
  1037. //{{{ onMouseWheel
  1038. /** Mouse Wheel **/
  1039. public function onMouseWheel(e:MouseEvent) : Void {
  1040. ScriptManager.exec(this,"mouseWheel", {event : e});
  1041. }
  1042. //}}}
  1043. //{{{ onKeyDown
  1044. /** Overiden in sub-classes **/
  1045. public function onKeyDown(e:KeyboardEvent) : Void {}
  1046. //}}}
  1047. //{{{ onKeyUp
  1048. /** Overiden in sub-classes **/
  1049. public function onKeyUp(e:KeyboardEvent) : Void {}
  1050. //}}}
  1051. //{{{ onResize
  1052. /** Overiden in sub-classes **/
  1053. public function onResize(e:ResizeEvent) : Void {
  1054. box.width = Math.max(minSize.width, Math.min(maxSize.width, box.width));
  1055. box.height = Math.max(minSize.height, Math.min(maxSize.height, box.height));
  1056. dirty = true;
  1057. }
  1058. //}}}
  1059. //{{{ onEnterFrame
  1060. private function onEnterFrame(e:Event) : Void {
  1061. var now = haxe.Timer.stamp();
  1062. var stepsF : Float = (now - lastInterval) * intervalUpdatesPerSec;
  1063. var steps : Int = Math.floor( stepsF );
  1064. lastInterval += steps / intervalUpdatesPerSec;
  1065. for(x in 0...steps) {
  1066. ScriptManager.exec(this,"interval",{event:e});
  1067. }
  1068. }
  1069. //}}}
  1070. //{{{ __focusHandler
  1071. private function __focusHandler(e:FocusEvent) {
  1072. // relatedObject is one gaining focus
  1073. // target is object losing focus
  1074. // currentTarget == this
  1075. //trace("------" + Std.string(this) + " __focusHandler");
  1076. //trace("__focusHandler " + (if(e.currentTarget != this) " ******* " + Std.string(e.currentTarget) else "") + " : from " + Std.string(e.target) + " to " + Std.string(e.relatedObject));
  1077. //var o = e.target;
  1078. var comp : Component = asComponent(e.currentTarget);
  1079. // first event is fired to the target about to lose focus
  1080. if(e.currentTarget == e.target && comp != null) {
  1081. // see if current object will relinquish focus to gainer.
  1082. if(!comp.onLosingFocus(cast asComponentIfIs(e.relatedObject))) {
  1083. e.preventDefault();
  1084. e.stopImmediatePropagation();
  1085. comp.stage.focus = comp;
  1086. #if debug
  1087. trace("Losing focus to " + asComponentIfIs(e.relatedObject).name + " prevented by " + asComponentIfIs(e.target).name);
  1088. #end
  1089. return;
  1090. }
  1091. }
  1092. comp = asComponent(e.relatedObject);
  1093. // check if the object gaining focus rejects
  1094. if(comp != null) {
  1095. if(!comp.onGainingFocus(cast asComponentIfIs(e.relatedObject))) {
  1096. e.preventDefault();
  1097. e.stopImmediatePropagation();
  1098. comp.stage.focus = comp;
  1099. #if debug
  1100. trace("Gain of focus denied by " + asComponentIfIs(e.relatedObject));
  1101. #end
  1102. return;
  1103. }
  1104. }
  1105. }
  1106. //}}}
  1107. //}}}
  1108. //{{{ redraw
  1109. /**
  1110. * Excecute redrawing script
  1111. * <pre class="code haxe">
  1112. * // example of sending variables to hscript redraw action
  1113. * var com = new Component();
  1114. * var opts = { color: Color.RED, size: new Size(100,40) };
  1115. * com.setAction("redraw", "
  1116. * this.graphics.beginFill(color);
  1117. * this.graphics.drawRect(0,0,size.width,size.height);
  1118. * this.graphics.endFill();
  1119. * ");
  1120. * com.redraw(opts);
  1121. * </pre>
  1122. * @param opts to pass the redrawing script
  1123. **/
  1124. public function redraw(opts:Dynamic=null) {
  1125. haxegui.Profiler.begin(here.className.split(".").pop()+"."+here.methodName);
  1126. ScriptManager.exec(this,"redraw", opts);
  1127. haxegui.Profiler.end();
  1128. }
  1129. //}}}
  1130. //}}}
  1131. //{{{ Getters/Setters
  1132. //{{{ __getDirty
  1133. private function __getDirty() : Bool {
  1134. return this.dirty;
  1135. }
  1136. //}}}
  1137. //{{{ __setDirty
  1138. private function __setDirty(v:Bool) : Bool {
  1139. if(this.dirty == v) return v;
  1140. this.dirty = v;
  1141. if(v)
  1142. Haxegui.setDirty(this);
  1143. return v;
  1144. }
  1145. //}}}
  1146. //{{{ __getDisabled
  1147. private function __getDisabled() : Bool {
  1148. return this.disabled;
  1149. }
  1150. //}}}
  1151. //{{{ __setDisabled
  1152. private function __setDisabled(v:Bool) : Bool {
  1153. if(this.disabled == v) return v;
  1154. this.disabled = v;
  1155. this.dirty = true;
  1156. for(c in this) {
  1157. if(Std.is(c,Component))
  1158. (cast c).disabled = v;
  1159. }
  1160. return v;
  1161. }
  1162. //}}}
  1163. //}}}
  1164. //{{{ Private
  1165. //{{{ addDisplayObjectEvents
  1166. /** add the focus events to any child that is not a Component **/
  1167. private function addDisplayObjectEvents(o : DisplayObject) {
  1168. if(!Std.is(o, Component)) {
  1169. removeDisplayObjectEvents(o);
  1170. o.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, __focusHandler, false, 0, true);
  1171. o.addEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, __focusHandler, false, 0, true);
  1172. //o.addEventListener(FocusEvent.FOCUS_IN, onFocusIn, false, 0, true);
  1173. //o.addEventListener(FocusEvent.FOCUS_OUT, onFocusOut, false, 0, true);
  1174. }
  1175. }
  1176. //}}}
  1177. //{{{ removeDisplayObjectEvents
  1178. private function removeDisplayObjectEvents(o : DisplayObject) {
  1179. if(!Std.is(o, Component)) {
  1180. o.removeEventListener(FocusEvent.KEY_FOCUS_CHANGE, __focusHandler);
  1181. o.removeEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, __focusHandler);
  1182. o.removeEventListener(FocusEvent.FOCUS_IN, onFocusIn);
  1183. o.removeEventListener(FocusEvent.FOCUS_OUT, onFocusOut);
  1184. }
  1185. }
  1186. //}}}
  1187. //}}}
  1188. //{{{ Static
  1189. //{{{ asComponent
  1190. /**
  1191. * Return the Component the DisplayObject belongs to. If the [obj] DisplayObject
  1192. * is a Component, then it will be returned. Useful for finding what Component
  1193. * a Sprite belongs to.
  1194. *
  1195. * @todo maybe unstatic the function, mostly used with 'using'
  1196. * @param obj DisplayObject or Component
  1197. * @return Component, or null if is not a Component and does not belong to a Component.
  1198. **/
  1199. public static function asComponent( obj : DisplayObject ) : Component {
  1200. if(Std.is(obj, Component))
  1201. return cast obj;
  1202. if(obj == null) return null;
  1203. var p = obj.parent;
  1204. while(p != null && !Std.is(p,Component)) {
  1205. p = p.parent;
  1206. }
  1207. if(p == null)
  1208. return null;
  1209. return cast p;
  1210. }
  1211. //}}}
  1212. //{{{ asComponentIfIs
  1213. /**
  1214. * Return the Component the DisplayObject belongs to. If the [obj] DisplayObject
  1215. * is a Component, then it will be returned. Useful for finding what Component
  1216. * a Sprite belongs to.
  1217. *
  1218. * @param obj DisplayObject or Component
  1219. * @return Component, or [obj] if is not a Component and does not belong to a Component.
  1220. **/
  1221. public static function asComponentIfIs( obj : DisplayObject ) : DisplayObject {
  1222. if(Std.is(obj, Component))
  1223. return obj;
  1224. if(obj == null) return null;
  1225. var p = obj.parent;
  1226. while(p != null && !Std.is(p,Component)) {
  1227. p = p.parent;
  1228. }
  1229. if(p == null)
  1230. return obj;
  1231. return p;
  1232. }
  1233. //}}}
  1234. //{{{ getParentComponent
  1235. /**
  1236. * Find the containing Component for any DisplayObject, if any.
  1237. *
  1238. * @param obj Any display object
  1239. * @return Parent Component, or null
  1240. **/
  1241. public static function getParentComponent(obj : DisplayObject) : Component {
  1242. var p = obj.parent;
  1243. while(p != null && !Std.is(p, Component))
  1244. p = p.parent;
  1245. if(p == null) return null;
  1246. return cast p;
  1247. }
  1248. //}}}
  1249. //{{{ rasterize
  1250. /**
  1251. * @return Bitmap a [Bitmap] copy of the component
  1252. */
  1253. public static function rasterize(content:DisplayObjectContainer,rect:Rectangle=null,precision:Float=1.0) : flash.display.Bitmap {
  1254. if (rect==null)
  1255. //~ rect = content.getBounds(content);
  1256. if(Std.is(content, Component))
  1257. rect = (cast content).box;
  1258. if(rect.isEmpty()) return null;
  1259. var tmp:Rectangle = rect.clone();
  1260. tmp.inflate((precision - 1) * rect.width, (precision - 1) * rect.height);
  1261. var data = new BitmapData(cast rect.width * precision,cast rect.height * precision, true, 0x00000000);
  1262. data.draw(content, new flash.geom.Matrix(precision, 0, 0, precision, -rect.x * precision, -rect.y * precision),
  1263. null, null, null,true);
  1264. var bitmap = new flash.display.Bitmap(data);
  1265. bitmap.name ="contentBitmap";
  1266. //~ bitmap.x = tmp.x;
  1267. //~ bitmap.y = tmp.y;
  1268. bitmap.scaleX = bitmap.scaleY = 1 / precision;
  1269. //~ for (i in 0...content.numChildren)
  1270. //~ {
  1271. //~ content.getChildAt(i).visible = false;
  1272. //~ }
  1273. //~ content.addChild(bitmap);
  1274. return bitmap;
  1275. }
  1276. //}}}
  1277. //}}}
  1278. //}}}
  1279. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1280. }