PageRenderTime 46ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/temple/core/CoreSprite.as

http://github.com/MediaMonks/Temple
ActionScript | 475 lines | 240 code | 55 blank | 180 comment | 36 complexity | 02db8196b87b3bcb86cda3a420efba3c MD5 | raw file
  1. /*
  2. *
  3. * Temple Library for ActionScript 3.0
  4. * Copyright Š 2010 MediaMonks B.V.
  5. * All rights reserved.
  6. *
  7. * http://code.google.com/p/templelibrary/
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are met:
  11. *
  12. * - Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * - Neither the name of the Temple Library nor the names of its contributors
  20. * may be used to endorse or promote products derived from this software
  21. * without specific prior written permission.
  22. *
  23. *
  24. * Temple Library is free software: you can redistribute it and/or modify
  25. * it under the terms of the GNU Lesser General Public License as published by
  26. * the Free Software Foundation, either version 3 of the License, or
  27. * (at your option) any later version.
  28. *
  29. * Temple Library is distributed in the hope that it will be useful,
  30. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  31. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  32. * GNU Lesser General Public License for more details.
  33. *
  34. * You should have received a copy of the GNU Lesser General Public License
  35. * along with Temple Library. If not, see <http://www.gnu.org/licenses/>.
  36. *
  37. */
  38. package temple.core
  39. {
  40. import temple.debug.Registry;
  41. import temple.debug.getClassName;
  42. import temple.debug.log.Log;
  43. import temple.destruction.DestructEvent;
  44. import temple.destruction.Destructor;
  45. import temple.destruction.EventListenerManager;
  46. import temple.utils.StageProvider;
  47. import flash.display.Loader;
  48. import flash.display.Sprite;
  49. import flash.display.Stage;
  50. import flash.events.Event;
  51. import flash.geom.Point;
  52. /**
  53. * @eventType temple.destruction.DestructEvent.DESTRUCT
  54. */
  55. [Event(name = "DestructEvent.destruct", type = "temple.destruction.DestructEvent")]
  56. /**
  57. * Base class for all Sprites in the Temple. The CoreSprite handles some core features of the Temple:
  58. * <ul>
  59. * <li>Registration to the Registry class.</li>
  60. * <li>Global reference to the stage trough the StageProvider.</li>
  61. * <li>Corrects a timeline bug in Flash (see <a href="http://www.tyz.nl/2009/06/23/weird-parent-thing-bug-in-flash/" target="_blank">http://www.tyz.nl/2009/06/23/weird-parent-thing-bug-in-flash/</a>).</li>
  62. * <li>Event dispatch optimization.</li>
  63. * <li>Easy remove of all EventListeners.</li>
  64. * <li>Wrapper for Log class for easy logging.</li>
  65. * <li>Completely destructable.</li>
  66. * <li>Automatic removes and destruct children, grant-children etc. on destruction.</li>
  67. * <li>Tracked in Memory (of this feature is enabled).</li>
  68. * <li>Some usefull extra properties like autoAlpha, position and scale.</li>
  69. * </ul>
  70. *
  71. * <p>You should always use and/or extend the CoreSprite instead of Sprite if you want to make use of the Temple features.</p>
  72. *
  73. * @see temple.Temple#registerObjectsInMemory()
  74. *
  75. * @author Thijs Broerse
  76. */
  77. public class CoreSprite extends Sprite implements ICoreDisplayObject
  78. {
  79. private namespace temple;
  80. private var _eventListenerManager:EventListenerManager;
  81. private var _isDestructed:Boolean;
  82. private var _onStage:Boolean;
  83. private var _onParent:Boolean;
  84. private var _registryId:uint;
  85. public function CoreSprite()
  86. {
  87. this._eventListenerManager = new EventListenerManager(this);
  88. super();
  89. if (this.loaderInfo) this.loaderInfo.addEventListener(Event.UNLOAD, temple::handleCoreUnload, false, 0, true);
  90. // Register object for destruction testing
  91. this._registryId = Registry.add(this);
  92. // Set listeners to keep track of object is on stage, since we can't trust the .parent property
  93. this.addEventListener(Event.ADDED, temple::handleAdded);
  94. this.addEventListener(Event.ADDED_TO_STAGE, temple::handleAddedToStage);
  95. this.addEventListener(Event.REMOVED, temple::handleRemoved);
  96. this.addEventListener(Event.REMOVED_FROM_STAGE, temple::handleRemovedFromStage);
  97. }
  98. /**
  99. * @inheritDoc
  100. *
  101. * Checks for a scrollRect and returns the width of the scrollRect.
  102. */
  103. override public function get width():Number
  104. {
  105. return this.scrollRect ? this.scrollRect.width : super.width;
  106. }
  107. /**
  108. * @inheritDoc
  109. *
  110. * If the object does not have a width and is not scaled to 0 the object is empty,
  111. * setting the width is useless and can only cause weird errors, so we don't.
  112. */
  113. override public function set width(value:Number):void
  114. {
  115. if(super.width || !this.scaleX) super.width = value;
  116. }
  117. /**
  118. * @inheritDoc
  119. *
  120. * Checks for a scrollRect and returns the height of the scrollRect.
  121. */
  122. override public function get height():Number
  123. {
  124. return this.scrollRect ? this.scrollRect.height : super.height;
  125. }
  126. /**
  127. * @inheritDoc
  128. *
  129. * If the object does not have a height and is not scaled to 0 the object is empty,
  130. * setting the height is useless and can only cause weird errors, so we don't.
  131. */
  132. override public function set height(value:Number):void
  133. {
  134. if(super.height || !this.scaleY) super.height = value;
  135. }
  136. /**
  137. * @inheritDoc
  138. */
  139. public final function get registryId():uint
  140. {
  141. return this._registryId;
  142. }
  143. /**
  144. * @inheritDoc
  145. *
  146. * When object is not on the stage it gets is stage reference from the StageProvider
  147. */
  148. override public function get stage():Stage
  149. {
  150. if (!super.stage) return StageProvider.stage;
  151. return super.stage;
  152. }
  153. /**
  154. * @inheritDoc
  155. */
  156. public function get onStage():Boolean
  157. {
  158. return this._onStage;
  159. }
  160. /**
  161. * @inheritDoc
  162. */
  163. public function get hasParent():Boolean
  164. {
  165. return this._onParent;
  166. }
  167. /**
  168. * @inheritDoc
  169. */
  170. public function get autoAlpha():Number
  171. {
  172. return this.visible ? this.alpha : 0;
  173. }
  174. /**
  175. * @inheritDoc
  176. */
  177. public function set autoAlpha(value:Number):void
  178. {
  179. this.alpha = value;
  180. this.visible = this.alpha > 0;
  181. }
  182. /**
  183. * @inheritDoc
  184. */
  185. public function get position():Point
  186. {
  187. return new Point(this.x, this.y);
  188. }
  189. /**
  190. * @inheritDoc
  191. */
  192. public function set position(value:Point):void
  193. {
  194. this.x = value.x;
  195. this.y = value.y;
  196. }
  197. /**
  198. * @inheritDoc
  199. */
  200. public function get scale():Number
  201. {
  202. if(this.scaleX == this.scaleY) return this.scaleX;
  203. return NaN;
  204. }
  205. /**
  206. * @inheritDoc
  207. */
  208. public function set scale(value:Number):void
  209. {
  210. this.scaleX = this.scaleY = value;
  211. }
  212. /**
  213. * @inheritDoc
  214. *
  215. * Check implemented if object hasEventListener, must speed up the application
  216. * http://www.gskinner.com/blog/archives/2008/12/making_dispatch.html
  217. */
  218. override public function dispatchEvent(event:Event):Boolean
  219. {
  220. if (this.hasEventListener(event.type) || event.bubbles)
  221. {
  222. return super.dispatchEvent(event);
  223. }
  224. return true;
  225. }
  226. /**
  227. * @inheritDoc
  228. */
  229. override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
  230. {
  231. super.addEventListener(type, listener, useCapture, priority, useWeakReference);
  232. if (this._eventListenerManager) this._eventListenerManager.addEventListener(type, listener, useCapture, priority, useWeakReference);
  233. }
  234. /**
  235. * @inheritDoc
  236. */
  237. override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
  238. {
  239. super.removeEventListener(type, listener, useCapture);
  240. if (this._eventListenerManager) this._eventListenerManager.removeEventListener(type, listener, useCapture);
  241. }
  242. /**
  243. * @inheritDoc
  244. */
  245. public function removeAllStrongEventListenersForType(type:String):void
  246. {
  247. if (this._eventListenerManager) this._eventListenerManager.removeAllStrongEventListenersForType(type);
  248. }
  249. /**
  250. * @inheritDoc
  251. */
  252. public function removeAllStrongEventListenersForListener(listener:Function):void
  253. {
  254. if (this._eventListenerManager) this._eventListenerManager.removeAllStrongEventListenersForListener(listener);
  255. }
  256. /**
  257. * @inheritDoc
  258. */
  259. public function removeAllEventListeners():void
  260. {
  261. if (this._eventListenerManager) this._eventListenerManager.removeAllEventListeners();
  262. }
  263. /**
  264. * @inheritDoc
  265. */
  266. public function get eventListenerManager():EventListenerManager
  267. {
  268. return this._eventListenerManager;
  269. }
  270. /**
  271. * Does a Log.debug, but has already filled in some known data
  272. * @param data the data to be logged
  273. */
  274. protected final function logDebug(data:*):void
  275. {
  276. Log.debug(data, this, this._registryId);
  277. }
  278. /**
  279. * Does a Log.error, but has already filled in some known data
  280. * @param data the data to be logged
  281. */
  282. protected final function logError(data:*):void
  283. {
  284. Log.error(data, this, this._registryId);
  285. }
  286. /**
  287. * Does a Log.fatal, but has already filled in some known data
  288. * @param data the data to be logged
  289. */
  290. protected final function logFatal(data:*):void
  291. {
  292. Log.fatal(data, this, this._registryId);
  293. }
  294. /**
  295. * Does a Log.info, but has already filled in some known data
  296. * @param data the data to be logged
  297. */
  298. protected final function logInfo(data:*):void
  299. {
  300. Log.info(data, this, this._registryId);
  301. }
  302. /**
  303. * Does a Log.status, but has already filled in some known data
  304. * @param data the data to be logged
  305. */
  306. protected final function logStatus(data:*):void
  307. {
  308. Log.status(data, this, this._registryId);
  309. }
  310. /**
  311. * Does a Log.warn, but has already filled in some known data
  312. * @param data the data to be logged
  313. */
  314. protected final function logWarn(data:*):void
  315. {
  316. Log.warn(data, this, this._registryId);
  317. }
  318. temple function handleCoreUnload(event:Event):void
  319. {
  320. this.destruct();
  321. }
  322. temple function handleAdded(event:Event):void
  323. {
  324. if (event.currentTarget == this) this._onParent = true;
  325. }
  326. temple function handleAddedToStage(event:Event):void
  327. {
  328. this._onStage = true;
  329. if(!StageProvider.stage)
  330. {
  331. StageProvider.stage = super.stage;
  332. }
  333. }
  334. temple function handleRemoved(event:Event):void
  335. {
  336. if (event.target == this)
  337. {
  338. this._onParent = false;
  339. if (!this._isDestructed) this.addEventListener(Event.ENTER_FRAME, temple::handleDestructedFrameDelay);
  340. }
  341. }
  342. temple function handleDestructedFrameDelay(event:Event):void
  343. {
  344. this.removeEventListener(Event.ENTER_FRAME, temple::handleDestructedFrameDelay);
  345. temple::checkParent();
  346. }
  347. /**
  348. * Check objects parent, after being removed. If the object still has a parent, the object has been removed by a timeline animation.
  349. * If an object is removed by a timeline animation, the object is not used anymore and can be destructed
  350. */
  351. temple function checkParent():void
  352. {
  353. if (this.parent && !this._onParent) this.destruct();
  354. }
  355. temple function handleRemovedFromStage(event:Event):void
  356. {
  357. this._onStage = false;
  358. }
  359. /**
  360. * @inheritDoc
  361. */
  362. public function get isDestructed():Boolean
  363. {
  364. return this._isDestructed;
  365. }
  366. /**
  367. * @inheritDoc
  368. */
  369. public function destruct():void
  370. {
  371. if (this._isDestructed) return;
  372. this.dispatchEvent(new DestructEvent(DestructEvent.DESTRUCT));
  373. // clear mask, so it won't keep a reference to an other object
  374. this.mask = null;
  375. if (this.stage && this.stage.focus == this) this.stage.focus = null;
  376. if (this.loaderInfo) this.loaderInfo.removeEventListener(Event.UNLOAD, temple::handleCoreUnload);
  377. this.removeEventListener(Event.ENTER_FRAME, temple::handleDestructedFrameDelay);
  378. if (this._eventListenerManager)
  379. {
  380. this.removeAllEventListeners();
  381. this._eventListenerManager.destruct();
  382. this._eventListenerManager = null;
  383. }
  384. Destructor.destructChildren(this);
  385. if (this.parent)
  386. {
  387. if (this.parent is Loader)
  388. {
  389. Loader(this.parent).unload();
  390. }
  391. else
  392. {
  393. if (this._onParent)
  394. {
  395. if(this.name && this.parent.hasOwnProperty(this.name)) this.parent[this.name] = null;
  396. this.parent.removeChild(this);
  397. }
  398. else
  399. {
  400. // something weird happened, since we have a parent but didn't receive an ADDED event. So do the try-catch thing
  401. try
  402. {
  403. if(this.name && this.parent.hasOwnProperty(this.name)) this.parent[this.name] = null;
  404. this.parent.removeChild(this);
  405. }
  406. catch (e:Error){}
  407. }
  408. }
  409. }
  410. this._isDestructed = true;
  411. }
  412. /**
  413. * @inheritDoc
  414. */
  415. override public function toString():String
  416. {
  417. return getClassName(this) + ": \"" + this.name + "\"";
  418. }
  419. }
  420. }