PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/flex3/src/ws/tink/mx/skins/SpriteProgrammaticSkin.as

http://github.com/tinklondon/tink_flash_platform
ActionScript | 785 lines | 259 code | 84 blank | 442 comment | 25 complexity | 8b5e58e97b94f010682dcbf7e15644e8 MD5 | raw file
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2008 Tink Ltd | http://www.tink.ws
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
  6. // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
  7. // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
  8. // to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in all copies or substantial portions
  11. // of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  14. // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  16. // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17. // SOFTWARE.
  18. //
  19. ////////////////////////////////////////////////////////////////////////////////
  20. package ws.tink.mx.skins
  21. {
  22. import flash.display.Graphics;
  23. import flash.display.Sprite;
  24. import flash.geom.Matrix;
  25. import mx.core.IFlexDisplayObject;
  26. import mx.core.IInvalidating;
  27. import mx.core.IProgrammaticSkin;
  28. import mx.core.UIComponentGlobals;
  29. import mx.core.mx_internal;
  30. import mx.managers.ILayoutManagerClient;
  31. import mx.styles.ISimpleStyleClient;
  32. import mx.styles.IStyleClient;
  33. import mx.utils.GraphicsUtil;
  34. use namespace mx_internal;
  35. /**
  36. * This class is the base class for skin elements
  37. * which draw themselves programmatically.
  38. */
  39. public class SpriteProgrammaticSkin extends Sprite
  40. implements IFlexDisplayObject, IInvalidating,
  41. ILayoutManagerClient, ISimpleStyleClient, IProgrammaticSkin
  42. {
  43. //--------------------------------------------------------------------------
  44. //
  45. // Class variables
  46. //
  47. //--------------------------------------------------------------------------
  48. /**
  49. * @private
  50. * Set by horizontalGradientMatrix() or verticalGradientMatrix().
  51. */
  52. private static var tempMatrix:Matrix = new Matrix();
  53. //--------------------------------------------------------------------------
  54. //
  55. // Constructor
  56. //
  57. //--------------------------------------------------------------------------
  58. /**
  59. * Constructor.
  60. */
  61. public function SpriteProgrammaticSkin()
  62. {
  63. super();
  64. // If nobody explicitly sets a size for this object,
  65. // then set its width and height to be its measured size.
  66. _width = measuredWidth;
  67. _height = measuredHeight;
  68. }
  69. //--------------------------------------------------------------------------
  70. //
  71. // Variables
  72. //
  73. //--------------------------------------------------------------------------
  74. /**
  75. * @private
  76. */
  77. private var invalidateDisplayListFlag:Boolean = false;
  78. //--------------------------------------------------------------------------
  79. //
  80. // Overridden properties
  81. //
  82. //--------------------------------------------------------------------------
  83. //----------------------------------
  84. // height
  85. //----------------------------------
  86. /**
  87. * @private
  88. * Storage for the height property.
  89. */
  90. private var _height:Number;
  91. /**
  92. * @private
  93. */
  94. override public function get height():Number
  95. {
  96. return _height;
  97. }
  98. /**
  99. * @private
  100. */
  101. override public function set height(value:Number):void
  102. {
  103. _height = value;
  104. invalidateDisplayList();
  105. }
  106. //----------------------------------
  107. // width
  108. //----------------------------------
  109. /**
  110. * @private
  111. * Storage for the width property.
  112. */
  113. private var _width:Number;
  114. /**
  115. * @private
  116. */
  117. override public function get width():Number
  118. {
  119. return _width;
  120. }
  121. /**
  122. * @private
  123. */
  124. override public function set width(value:Number):void
  125. {
  126. _width = value;
  127. invalidateDisplayList();
  128. }
  129. //--------------------------------------------------------------------------
  130. //
  131. // Properties: IFlexDisplayObject
  132. //
  133. //--------------------------------------------------------------------------
  134. //----------------------------------
  135. // measuredHeight
  136. //----------------------------------
  137. /**
  138. * The measured height of this object.
  139. * This should be overridden by subclasses to return the preferred height for
  140. * the skin.
  141. *
  142. * @return The measured height of the object, in pixels.
  143. */
  144. public function get measuredHeight():Number
  145. {
  146. return 0;
  147. }
  148. //----------------------------------
  149. // measuredWidth
  150. //----------------------------------
  151. /**
  152. * The measured width of this object.
  153. * This should be overridden by subclasses to return the preferred width for
  154. * the skin.
  155. *
  156. * @return The measured width of the object, in pixels.
  157. */
  158. public function get measuredWidth():Number
  159. {
  160. return 0;
  161. }
  162. //--------------------------------------------------------------------------
  163. //
  164. // Properties: ILayoutManagerClient
  165. //
  166. //--------------------------------------------------------------------------
  167. //----------------------------------
  168. // initialized
  169. //----------------------------------
  170. /**
  171. * @private
  172. * Storage for the initialized property.
  173. */
  174. private var _initialized:Boolean = false;
  175. /**
  176. * @copy mx.core.UIComponent#initialized
  177. */
  178. public function get initialized():Boolean
  179. {
  180. return _initialized;
  181. }
  182. /**
  183. * @private
  184. */
  185. public function set initialized(value:Boolean):void
  186. {
  187. _initialized = value;
  188. }
  189. //----------------------------------
  190. // nestLevel
  191. //----------------------------------
  192. /**
  193. * @private
  194. * Storage for the nestLevel property.
  195. */
  196. private var _nestLevel:int = 0;
  197. /**
  198. * @copy mx.core.UIComponent#nestLevel
  199. */
  200. public function get nestLevel():int
  201. {
  202. return _nestLevel;
  203. }
  204. /**
  205. * @private
  206. */
  207. public function set nestLevel(value:int):void
  208. {
  209. _nestLevel = value;
  210. // After nestLevel is initialized, add this object to the
  211. // LayoutManager's queue, so that it is drawn at least once
  212. invalidateDisplayList();
  213. }
  214. //----------------------------------
  215. // processedDescriptors
  216. //----------------------------------
  217. /**
  218. * @private
  219. * Storage for the processedDescriptors property.
  220. */
  221. private var _processedDescriptors:Boolean = false;
  222. /**
  223. * @copy mx.core.UIComponent#processedDescriptors
  224. */
  225. public function get processedDescriptors():Boolean
  226. {
  227. return _processedDescriptors;
  228. }
  229. /**
  230. * @private
  231. */
  232. public function set processedDescriptors(value:Boolean):void
  233. {
  234. _processedDescriptors = value;
  235. }
  236. //----------------------------------
  237. // updateCompletePendingFlag
  238. //----------------------------------
  239. /**
  240. * @private
  241. * Storage for the updateCompletePendingFlag property.
  242. */
  243. private var _updateCompletePendingFlag:Boolean = true;
  244. /**
  245. * A flag that determines if an object has been through all three phases
  246. * of layout validation (provided that any were required).
  247. */
  248. public function get updateCompletePendingFlag():Boolean
  249. {
  250. return _updateCompletePendingFlag;
  251. }
  252. /**
  253. * @private
  254. */
  255. public function set updateCompletePendingFlag(value:Boolean):void
  256. {
  257. _updateCompletePendingFlag = value;
  258. }
  259. //--------------------------------------------------------------------------
  260. //
  261. // Properties: ISimpleStyleClient
  262. //
  263. //--------------------------------------------------------------------------
  264. //----------------------------------
  265. // styleName
  266. //----------------------------------
  267. /**
  268. * @private
  269. * Storage for the styleName property.
  270. * For skins, it is always a UIComponent.
  271. */
  272. private var _styleName:IStyleClient;
  273. /**
  274. * A parent component used to obtain style values. This is typically set to the
  275. * component that created this skin.
  276. */
  277. public function get styleName():Object
  278. {
  279. return _styleName;
  280. }
  281. /**
  282. * @private
  283. */
  284. public function set styleName(value:Object):void
  285. {
  286. if (_styleName != value)
  287. {
  288. _styleName = value as IStyleClient;
  289. invalidateDisplayList();
  290. }
  291. }
  292. //--------------------------------------------------------------------------
  293. //
  294. // Methods: IFlexDisplayObject
  295. //
  296. //--------------------------------------------------------------------------
  297. /**
  298. * Moves this object to the specified x and y coordinates.
  299. *
  300. * @param x The horizontal position, in pixels.
  301. *
  302. * @param y The vertical position, in pixels.
  303. */
  304. public function move(x:Number, y:Number):void
  305. {
  306. this.x = x;
  307. this.y = y;
  308. }
  309. /**
  310. * Sets the height and width of this object.
  311. *
  312. * @param newWidth The width, in pixels, of this object.
  313. *
  314. * @param newHeight The height, in pixels, of this object.
  315. */
  316. public function setActualSize(newWidth:Number, newHeight:Number):void
  317. {
  318. var changed:Boolean = false;
  319. if (_width != newWidth)
  320. {
  321. _width = newWidth;
  322. changed = true;
  323. }
  324. if (_height != newHeight)
  325. {
  326. _height = newHeight;
  327. changed = true;
  328. }
  329. if (changed)
  330. invalidateDisplayList();
  331. }
  332. //--------------------------------------------------------------------------
  333. //
  334. // Methods: ILayoutManagerClient
  335. //
  336. //--------------------------------------------------------------------------
  337. /**
  338. * This function is an empty stub so that ProgrammaticSkin
  339. * can implement the ILayoutManagerClient interface.
  340. * Skins do not call <code>LayoutManager.invalidateProperties()</code>,
  341. * which would normally trigger a call to this method.
  342. */
  343. public function validateProperties():void
  344. {
  345. }
  346. /**
  347. * This function is an empty stub so that ProgrammaticSkin
  348. * can implement the ILayoutManagerClient interface.
  349. * Skins do not call <code>LayoutManager.invalidateSize()</code>,
  350. * which would normally trigger a call to this method.
  351. *
  352. * @param recursive Determines whether children of this skin are validated.
  353. */
  354. public function validateSize(recursive:Boolean = false):void
  355. {
  356. }
  357. /**
  358. * This function is called by the LayoutManager
  359. * when it's time for this control to draw itself.
  360. * The actual drawing happens in the <code>updateDisplayList</code>
  361. * function, which is called by this function.
  362. */
  363. public function validateDisplayList():void
  364. {
  365. invalidateDisplayListFlag = false;
  366. updateDisplayList(width, height);
  367. }
  368. //--------------------------------------------------------------------------
  369. //
  370. // Methods: ISimpleStyleClient
  371. //
  372. //--------------------------------------------------------------------------
  373. /**
  374. * Whenever any style changes, redraw this skin.
  375. * Subclasses can override this method
  376. * and perform a more specific test before calling invalidateDisplayList().
  377. *
  378. * @param styleProp The name of the style property that changed, or null
  379. * if all styles have changed.
  380. */
  381. public function styleChanged(styleProp:String):void
  382. {
  383. invalidateDisplayList();
  384. }
  385. //--------------------------------------------------------------------------
  386. //
  387. // Methods: Other
  388. //
  389. //--------------------------------------------------------------------------
  390. /**
  391. * @copy mx.core.UIComponent#invalidateDisplayList()
  392. */
  393. public function invalidateDisplayList():void
  394. {
  395. // Don't try to add the object to the display list queue until we've
  396. // been assigned a nestLevel, or we'll get added at the wrong place in
  397. // the LayoutManager's priority queue.
  398. if (!invalidateDisplayListFlag && nestLevel > 0)
  399. {
  400. invalidateDisplayListFlag = true;
  401. UIComponentGlobals.layoutManager.invalidateDisplayList(this);
  402. }
  403. }
  404. /**
  405. * Programmatically draws the graphics for this skin.
  406. *
  407. * <p>Subclasses should override this method and include calls
  408. * to methods such as <code>graphics.moveTo()</code> and
  409. * <code>graphics.lineTo()</code>.</p>
  410. *
  411. * <p>This occurs before any scaling from sources
  412. * such as user code or zoom effects.
  413. * The component is unaware of the scaling that takes place later.</p>
  414. *
  415. * @param unscaledWidth
  416. * The width, in pixels, of this object before any scaling.
  417. *
  418. * @param unscaledHeight
  419. * The height, in pixels, of this object before any scaling.
  420. */
  421. protected function updateDisplayList(unscaledWidth:Number,
  422. unscaledHeight:Number):void
  423. {
  424. }
  425. /**
  426. * @inheritDoc
  427. */
  428. public function invalidateSize():void
  429. {
  430. }
  431. /**
  432. * @inheritDoc
  433. */
  434. public function invalidateProperties():void
  435. {
  436. }
  437. /**
  438. * Validate and update the properties and layout of this object
  439. * and redraw it, if necessary.
  440. */
  441. public function validateNow():void
  442. {
  443. // Since we don't have commit/measure/layout phases,
  444. // all we need to do here is the draw phase
  445. if (invalidateDisplayListFlag)
  446. validateDisplayList();
  447. }
  448. /**
  449. * Returns the value of the specified style property.
  450. *
  451. * @param styleProp Name of the style property.
  452. *
  453. * @return The style value. This can be any type of object that style properties can be, such as
  454. * int, Number, String, etc.
  455. */
  456. public function getStyle(styleProp:String):*
  457. {
  458. return _styleName.getStyle(styleProp);
  459. }
  460. /**
  461. * Utility function to create a horizontal gradient matrix.
  462. *
  463. * @param x The left edge of the gradient.
  464. *
  465. * @param y The top edge of the gradient.
  466. *
  467. * @param width The width of the gradient.
  468. *
  469. * @param height The height of the gradient.
  470. *
  471. * @return The horizontal gradient matrix. This is a temporary
  472. * object that should only be used for a single subsequent call
  473. * to the <code>drawRoundRect()</code> method.
  474. */
  475. protected function horizontalGradientMatrix(x:Number, y:Number,
  476. width:Number,
  477. height:Number):Matrix
  478. {
  479. return rotatedGradientMatrix(x, y, width, height, 0);
  480. }
  481. /**
  482. * Utility function to create a vertical gradient matrix.
  483. *
  484. * @param x The left edge of the gradient.
  485. *
  486. * @param y The top edge of the gradient.
  487. *
  488. * @param width The width of the gradient.
  489. *
  490. * @param height The height of the gradient.
  491. *
  492. * @return The horizontal gradient matrix. This is a temporary
  493. * object that should only be used for a single subsequent call
  494. * to the <code>drawRoundRect()</code> method.
  495. */
  496. protected function verticalGradientMatrix(x:Number, y:Number,
  497. width:Number,
  498. height:Number):Matrix
  499. {
  500. return rotatedGradientMatrix(x, y, width, height, 90);
  501. }
  502. /**
  503. * Utility function to create a rotated gradient matrix.
  504. *
  505. * @param x The left edge of the gradient.
  506. *
  507. * @param y The top edge of the gradient.
  508. *
  509. * @param width The width of the gradient.
  510. *
  511. * @param height The height of the gradient.
  512. *
  513. * @param rotation The amount to rotate, in degrees.
  514. *
  515. * @return The horizontal gradient matrix. This is a temporary
  516. * object that should only be used for a single subsequent call
  517. * to the <code>drawRoundRect()</code> method.
  518. */
  519. protected function rotatedGradientMatrix(x:Number, y:Number,
  520. width:Number,
  521. height:Number,
  522. rotation:Number):Matrix
  523. {
  524. tempMatrix.createGradientBox(width, height,
  525. rotation * Math.PI / 180, x, y);
  526. return tempMatrix;
  527. }
  528. /**
  529. * Programatically draws a rectangle into this skin's Graphics object.
  530. *
  531. * <p>The rectangle can have rounded corners.
  532. * Its edges are stroked with the current line style
  533. * of the Graphics object.
  534. * It can have a solid color fill, a gradient fill, or no fill.
  535. * A solid fill can have an alpha transparency.
  536. * A gradient fill can be linear or radial. You can specify
  537. * up to 15 colors and alpha values at specified points along
  538. * the gradient, and you can specify a rotation angle
  539. * or transformation matrix for the gradient.
  540. * Finally, the rectangle can have a rounded rectangular hole
  541. * carved out of it.</p>
  542. *
  543. * <p>This versatile rectangle-drawing routine is used by many skins.
  544. * It calls the <code>drawRect()</code> or
  545. * <code>drawRoundRect()</code>
  546. * methods (in the flash.display.Graphics class) to draw into this
  547. * skin's Graphics object.</p>
  548. *
  549. * @param x Horizontal position of upper-left corner
  550. * of rectangle within this skin.
  551. *
  552. * @param y Vertical position of upper-left corner
  553. * of rectangle within this skin.
  554. *
  555. * @param width Width of rectangle, in pixels.
  556. *
  557. * @param height Height of rectangle, in pixels.
  558. *
  559. * @param cornerRadius Corner radius/radii of rectangle.
  560. * Can be <code>null</code>, a Number, or an Object.
  561. * If it is <code>null</code>, it specifies that the corners should be square
  562. * rather than rounded.
  563. * If it is a Number, it specifies the same radius, in pixels,
  564. * for all four corners.
  565. * If it is an Object, it should have properties named
  566. * <code>tl</code>, <code>tr</code>, <code>bl</code>, and
  567. * <code>br</code>, whose values are Numbers specifying
  568. * the radius, in pixels, for the top left, top right,
  569. * bottom left, and bottom right corners.
  570. * For example, you can pass a plain Object such as
  571. * <code>{ tl: 5, tr: 5, bl: 0, br: 0 }</code>.
  572. * The default value is null (square corners).
  573. *
  574. * @param color The RGB color(s) for the fill.
  575. * Can be <code>null</code>, a uint, or an Array.
  576. * If it is <code>null</code>, the rectangle not filled.
  577. * If it is a uint, it specifies an RGB fill color.
  578. * For example, pass <code>0xFF0000</code> to fill with red.
  579. * If it is an Array, it should contain uints
  580. * specifying the gradient colors.
  581. * For example, pass <code>[ 0xFF0000, 0xFFFF00, 0x0000FF ]</code>
  582. * to fill with a red-to-yellow-to-blue gradient.
  583. * You can specify up to 15 colors in the gradient.
  584. * The default value is null (no fill).
  585. *
  586. * @param alpha Alpha value(s) for the fill.
  587. * Can be null, a Number, or an Array.
  588. * This argument is ignored if <code>color</code> is null.
  589. * If <code>color</code> is a uint specifying an RGB fill color,
  590. * then <code>alpha</code> should be a Number specifying
  591. * the transparency of the fill, where 0.0 is completely transparent
  592. * and 1.0 is completely opaque.
  593. * You can also pass null instead of 1.0 in this case
  594. * to specify complete opaqueness.
  595. * If <code>color</code> is an Array specifying gradient colors,
  596. * then <code>alpha</code> should be an Array of Numbers, of the
  597. * same length, that specifies the corresponding alpha values
  598. * for the gradient.
  599. * In this case, the default value is <code>null</code> (completely opaque).
  600. *
  601. * @param gradientMatrix Matrix object used for the gradient fill.
  602. * The utility methods <code>horizontalGradientMatrix()</code>,
  603. * <code>verticalGradientMatrix()</code>, and
  604. * <code>rotatedGradientMatrix()</code> can be used to create the value for
  605. * this parameter.
  606. *
  607. * @param gradientType Type of gradient fill. The possible values are
  608. * <code>GradientType.LINEAR</code> or <code>GradientType.RADIAL</code>.
  609. * (The GradientType class is in the package flash.display.)
  610. *
  611. * @param gradientRatios (optional default [0,255])
  612. * Specifies the distribution of colors. The number of entries must match
  613. * the number of colors defined in the <code>color</code> parameter.
  614. * Each value defines the percentage of the width where the color is
  615. * sampled at 100%. The value 0 represents the left-hand position in
  616. * the gradient box, and 255 represents the right-hand position in the
  617. * gradient box.
  618. *
  619. * @param hole (optional) A rounded rectangular hole
  620. * that should be carved out of the middle
  621. * of the otherwise solid rounded rectangle
  622. * { x: #, y: #, w: #, h: #, r: # or { br: #, bl: #, tl: #, tr: # } }
  623. *
  624. * @see flash.display.Graphics#beginGradientFill()
  625. */
  626. protected function drawRoundRect(
  627. x:Number, y:Number, width:Number, height:Number,
  628. cornerRadius:Object = null,
  629. color:Object = null,
  630. alpha:Object = null,
  631. gradientMatrix:Matrix = null,
  632. gradientType:String = "linear",
  633. gradientRatios:Array /* of Number */ = null,
  634. hole:Object = null):void
  635. {
  636. var g:Graphics = graphics;
  637. // Quick exit if weight or height is zero.
  638. // This happens when scaling a component to a very small value,
  639. // which then gets rounded to 0.
  640. if (width == 0 || height == 0)
  641. return;
  642. // If color is an object then allow for complex fills.
  643. if (color !== null)
  644. {
  645. if (color is uint)
  646. {
  647. g.beginFill(uint(color), Number(alpha));
  648. }
  649. else if (color is Array)
  650. {
  651. var alphas:Array = alpha is Array ?
  652. alpha as Array :
  653. [ alpha, alpha ];
  654. if (!gradientRatios)
  655. gradientRatios = [ 0, 0xFF ];
  656. g.beginGradientFill(gradientType,
  657. color as Array, alphas,
  658. gradientRatios, gradientMatrix);
  659. }
  660. }
  661. var ellipseSize:Number;
  662. // Stroke the rectangle.
  663. if (!cornerRadius)
  664. {
  665. g.drawRect(x, y, width, height);
  666. }
  667. else if (cornerRadius is Number)
  668. {
  669. ellipseSize = Number(cornerRadius) * 2;
  670. g.drawRoundRect(x, y, width, height,
  671. ellipseSize, ellipseSize);
  672. }
  673. else
  674. {
  675. GraphicsUtil.drawRoundRectComplex(g,
  676. x, y, width, height,
  677. cornerRadius.tl, cornerRadius.tr,
  678. cornerRadius.bl, cornerRadius.br);
  679. }
  680. // Carve a rectangular hole out of the middle of the rounded rect.
  681. if (hole)
  682. {
  683. var holeR:Object = hole.r;
  684. if (holeR is Number)
  685. {
  686. ellipseSize = Number(holeR) * 2;
  687. g.drawRoundRect(hole.x, hole.y, hole.w, hole.h,
  688. ellipseSize, ellipseSize);
  689. }
  690. else
  691. {
  692. GraphicsUtil.drawRoundRectComplex(g,
  693. hole.x, hole.y, hole.w, hole.h,
  694. holeR.tl, holeR.tr, holeR.bl, holeR.br);
  695. }
  696. }
  697. if (color !== null)
  698. g.endFill();
  699. }
  700. }
  701. }