| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package mx.core |
| { |
| |
| import flash.display.DisplayObjectContainer; |
| import flash.events.Event; |
| import flash.geom.Point; |
| import flash.system.ApplicationDomain; |
| |
| /** |
| * SpriteAsset is a subclass of the flash.display.Sprite class which |
| * represents vector graphic images that you embed in an application. |
| * It implements the IFlexDisplayObject interface, which makes it |
| * possible for an embedded vector graphic image to be displayed in an Image |
| * control, or to be used as a container background or a component skin. |
| * |
| * <p>The vector graphic image that you're embedding can be in an SVG file. |
| * You can also embed a sprite symbol that is in a SWF file produced |
| * by Flash. |
| * In both cases, the MXML compiler autogenerates a class that extends |
| * SpriteAsset to represent the embedded vector graphic image.</p> |
| * |
| * <p>You don't generally have to use the SpriteAsset class directly |
| * when you write a Flex application. |
| * For example, you can embed a sprite symbol from a SWF file and display |
| * it in an Image control by writing the following:</p> |
| * |
| * <pre> |
| * <mx:Image id="logo" source="@Embed(source='Assets.swf', symbol='Logo')"/></pre> |
| * |
| * <p>Or use it as the application's background image in CSS syntax |
| * by writing the following:</p> |
| * |
| * <pre> |
| * <fx:Style> |
| * @namespace mx "library://ns.adobe.com/flex/mx" |
| * mx|Application { |
| * backgroundImage: Embed(source="Assets.swf", symbol='Logo') |
| * } |
| * <fx:Style/></pre> |
| * |
| * <p>without having to understand that the MXML compiler has created |
| * a subclass of BitmapAsset for you.</p> |
| * |
| * <p>However, it may be useful to understand what is happening |
| * at the ActionScript level. |
| * To embed a vector graphic image in ActionScript, you declare a variable |
| * of type Class, and put <code>[Embed]</code> metadata on it. |
| * For example, you embed a sprite symbol from a SWF file like this:</p> |
| * |
| * <pre> |
| * [Bindable] |
| * [Embed(source="Assets.swf", symbol="Logo")] |
| * private var logoClass:Class;</pre> |
| * |
| * <p>The MXML compiler notices that the Logo symbol in Assets.swf |
| * is a sprite, autogenerates a subclass of the SpriteAsset class |
| * to represent it, and sets your variable to be a reference to this |
| * autogenerated class. |
| * You can then use this class reference to create instances of the |
| * SpriteAsset using the <code>new</code> operator, and use APIs |
| * of the Sprite class on them:</p> |
| * |
| * <pre> |
| * var logo:SpriteAsset = SpriteAsset(new logoClass()); |
| * logo.rotation=45;</pre> |
| * |
| * <p>However, you rarely need to create SpriteAsset instances yourself |
| * because image-related properties and styles can simply be set to an |
| * image-producing class, and components will create image instances |
| * as necessary. |
| * For example, to display this vector graphic image in an Image control, |
| * you can set the Image's <code>source</code> property to |
| * <code>logoClass</code>. |
| * In MXML you could do this as follows:</p> |
| * |
| * <pre> |
| * <mx:Image id="logo" source="{logoClass}"/></pre> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class SpriteAsset extends FlexSprite |
| implements IFlexAsset, IFlexDisplayObject, IBorder, |
| ILayoutDirectionElement |
| { |
| include "../core/Version.as"; |
| |
| // Softlink FlexVersion and MatrixUtil to remove dependencies of embeds on |
| // framework classes. This helps to reduce swf size in AS-only projects. |
| private static var FlexVersionClass:Class; |
| private static var MatrixUtilClass:Class; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function SpriteAsset() |
| { |
| super(); |
| |
| // Remember initial size as our measured size. |
| _measuredWidth = width; |
| _measuredHeight = height; |
| |
| if (FlexVersionClass == null) |
| { |
| var appDomain:ApplicationDomain = ApplicationDomain.currentDomain; |
| if (appDomain.hasDefinition("mx.core::FlexVersion")) |
| FlexVersionClass = Class(appDomain.getDefinition("mx.core::FlexVersion")); |
| } |
| |
| if (FlexVersionClass && FlexVersionClass["compatibilityVersion"] >= FlexVersionClass["VERSION_4_0"]) |
| this.addEventListener(Event.ADDED, addedHandler); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| // Softlink AdvancedLayoutFeatures to remove dependencies of embeds on |
| // framework classes. This helps to reduce swf size in AS-only projects. |
| private var layoutFeaturesClass:Class; |
| private var layoutFeatures:IAssetLayoutFeatures; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // x |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get x():Number |
| { |
| // TODO(hmuller): by default get x returns transform.matrix.tx rounded to the nearest 20th. |
| // should do the same here, if we're returning layoutFeatures.layoutX. |
| return (layoutFeatures == null) ? super.x : layoutFeatures.layoutX; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set x(value:Number):void |
| { |
| if (x == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.x = value; |
| } |
| else |
| { |
| layoutFeatures.layoutX = value; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // y |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get y():Number |
| { |
| return (layoutFeatures == null) ? super.y : layoutFeatures.layoutY; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set y(value:Number):void |
| { |
| if (y == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.y = value; |
| } |
| else |
| { |
| layoutFeatures.layoutY = value; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // z |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get z():Number |
| { |
| return (layoutFeatures == null) ? super.z : layoutFeatures.layoutZ; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set z(value:Number):void |
| { |
| if (z == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.z = value; |
| } |
| else |
| { |
| layoutFeatures.layoutZ = value; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // width |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get width():Number |
| { |
| if (layoutFeatures == null) |
| return super.width; |
| |
| // Return bounding box width in mirroring case |
| var p:Point; |
| if (MatrixUtilClass != null) |
| p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix); |
| |
| return p ? p.x : super.width; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set width(value:Number):void |
| { |
| if (width == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.width = value; |
| } |
| else |
| { |
| layoutFeatures.layoutWidth = value; |
| // Calculate scaleX based on initial width. We set scaleX |
| // here because resizing a BitmapAsset normally would adjust |
| // the scale to match. |
| layoutFeatures.layoutScaleX = measuredWidth != 0 ? value / measuredWidth : 0; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // height |
| //---------------------------------- |
| |
| private var _height:Number; |
| |
| /** |
| * @private |
| */ |
| override public function get height():Number |
| { |
| |
| if (layoutFeatures == null) |
| return super.height; |
| |
| // Return bounding box height in mirroring case |
| var p:Point; |
| if (MatrixUtilClass != null) |
| p = MatrixUtilClass["transformSize"](layoutFeatures.layoutWidth, _height, transform.matrix); |
| |
| return p ? p.y : super.height; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set height(value:Number):void |
| { |
| if (height == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.height = value; |
| } |
| else |
| { |
| _height = value; |
| // Calculate scaleY based on initial height. We set scaleY |
| // here because resizing a BitmapAsset normally would adjust |
| // the scale to match. |
| layoutFeatures.layoutScaleY = measuredHeight != 0 ? value / measuredHeight : 0; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // rotation |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get rotationX():Number |
| { |
| return (layoutFeatures == null) ? super.rotationX : layoutFeatures.layoutRotationX; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set rotationX(value:Number):void |
| { |
| if (rotationX == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.rotationX = value; |
| } |
| else |
| { |
| layoutFeatures.layoutRotationX = value; |
| validateTransformMatrix(); |
| } |
| } |
| /** |
| * @private |
| */ |
| override public function get rotationY():Number |
| { |
| return (layoutFeatures == null) ? super.rotationY : layoutFeatures.layoutRotationY; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set rotationY(value:Number):void |
| { |
| if (rotationY == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.rotationY = value; |
| } |
| else |
| { |
| layoutFeatures.layoutRotationY = value; |
| validateTransformMatrix(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function get rotationZ():Number |
| { |
| return (layoutFeatures == null) ? super.rotationZ : layoutFeatures.layoutRotationZ; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set rotationZ(value:Number):void |
| { |
| if (rotationZ == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.rotationZ = value; |
| } |
| else |
| { |
| layoutFeatures.layoutRotationZ = value; |
| validateTransformMatrix(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function get rotation():Number |
| { |
| return (layoutFeatures == null) ? super.rotation : layoutFeatures.layoutRotationZ; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set rotation(value:Number):void |
| { |
| // TODO (klin): rotation actually affects width and height as well. |
| if (rotation == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.rotation = value; |
| } |
| else |
| { |
| layoutFeatures.layoutRotationZ = value; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // scaleX |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get scaleX():Number |
| { |
| return (layoutFeatures == null) ? super.scaleX : layoutFeatures.layoutScaleX; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set scaleX(value:Number):void |
| { |
| if (scaleX == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.scaleX = value; |
| } |
| else |
| { |
| layoutFeatures.layoutScaleX = value; |
| layoutFeatures.layoutWidth = Math.abs(value) * measuredWidth; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // scaleY |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get scaleY():Number |
| { |
| return (layoutFeatures == null) ? super.scaleY : layoutFeatures.layoutScaleY; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set scaleY(value:Number):void |
| { |
| if (scaleY == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.scaleY = value; |
| } |
| else |
| { |
| layoutFeatures.layoutScaleY = value; |
| _height = Math.abs(value) * measuredHeight; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //---------------------------------- |
| // scaleZ |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get scaleZ():Number |
| { |
| return (layoutFeatures == null) ? super.scaleZ : layoutFeatures.layoutScaleZ; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set scaleZ(value:Number):void |
| { |
| if (scaleZ == value) |
| return; |
| |
| if (layoutFeatures == null) |
| { |
| super.scaleZ = value; |
| } |
| else |
| { |
| layoutFeatures.layoutScaleZ = value; |
| validateTransformMatrix(); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // layoutDirection |
| //---------------------------------- |
| |
| // Use "ltr" instead of LayoutDirection.LTR to avoid depending |
| // on that framework class. |
| private var _layoutDirection:String = "ltr"; |
| |
| [Inspectable(category="General", enumeration="ltr,rtl")] |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.1 |
| */ |
| public function get layoutDirection():String |
| { |
| return _layoutDirection; |
| } |
| |
| public function set layoutDirection(value:String):void |
| { |
| if (value == _layoutDirection) |
| return; |
| |
| _layoutDirection = value; |
| invalidateLayoutDirection(); |
| } |
| |
| //---------------------------------- |
| // measuredHeight |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the measuredHeight property. |
| */ |
| private var _measuredHeight:Number; |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get measuredHeight():Number |
| { |
| return _measuredHeight; |
| } |
| |
| //---------------------------------- |
| // measuredWidth |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the measuredWidth property. |
| */ |
| private var _measuredWidth:Number; |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get measuredWidth():Number |
| { |
| return _measuredWidth; |
| } |
| |
| //---------------------------------- |
| // borderMetrics |
| //---------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get borderMetrics():EdgeMetrics |
| { |
| if (scale9Grid == null) |
| { |
| return EdgeMetrics.EMPTY; |
| } |
| else |
| { |
| return new EdgeMetrics(scale9Grid.left, |
| scale9Grid.top, |
| Math.ceil(measuredWidth - scale9Grid.right), |
| Math.ceil(measuredHeight - scale9Grid.bottom)); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.1 |
| */ |
| public function invalidateLayoutDirection():void |
| { |
| var p:DisplayObjectContainer = parent; |
| |
| // We check the closest parent's layoutDirection property |
| // to create or destroy layoutFeatures if needed. |
| while (p) |
| { |
| if (p is ILayoutDirectionElement) |
| { |
| // mirror is true if our layoutDirection differs from our parent's. |
| var mirror:Boolean = _layoutDirection != null && |
| ILayoutDirectionElement(p).layoutDirection != null && |
| (_layoutDirection != ILayoutDirectionElement(p).layoutDirection); |
| |
| // If our layoutDirection is different from our parent's and if it used to |
| // be the same, create layoutFeatures to handle mirroring. |
| if (mirror && layoutFeatures == null) |
| { |
| initAdvancedLayoutFeatures(); |
| if (layoutFeatures != null) |
| { |
| layoutFeatures.mirror = mirror; |
| validateTransformMatrix(); |
| } |
| } |
| else if (!mirror && layoutFeatures) |
| { |
| // If our layoutDirection is not different from our parent's and if |
| // it used to be different, then recover our matrix and remove layoutFeatures. |
| layoutFeatures.mirror = mirror; |
| validateTransformMatrix(); |
| layoutFeatures = null; |
| } |
| |
| break; |
| } |
| |
| p = p.parent; |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function move(x:Number, y:Number):void |
| { |
| this.x = x; |
| this.y = y; |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function setActualSize(newWidth:Number, newHeight:Number):void |
| { |
| width = newWidth; |
| height = newHeight; |
| } |
| |
| /** |
| * @private |
| */ |
| private function addedHandler(event:Event):void |
| { |
| invalidateLayoutDirection(); |
| } |
| |
| /** |
| * @private |
| * Initializes AdvancedLayoutFeatures for this asset when mirroring. |
| */ |
| private function initAdvancedLayoutFeatures():void |
| { |
| // Get AdvancedLayoutFeatures if it exists. |
| if (layoutFeaturesClass == null) |
| { |
| var appDomain:ApplicationDomain = ApplicationDomain.currentDomain; |
| |
| if (appDomain.hasDefinition("mx.core::AdvancedLayoutFeatures")) |
| layoutFeaturesClass = Class(appDomain.getDefinition("mx.core::AdvancedLayoutFeatures")); |
| |
| // Get MatrixUtil class if it exists |
| if (MatrixUtilClass == null) |
| { |
| if (appDomain.hasDefinition("mx.utils::MatrixUtil")) |
| MatrixUtilClass = Class(appDomain.getDefinition("mx.utils::MatrixUtil")); |
| } |
| } |
| |
| if (layoutFeaturesClass != null) |
| { |
| var features:IAssetLayoutFeatures = new layoutFeaturesClass(); |
| |
| features.layoutScaleX = scaleX; |
| features.layoutScaleY = scaleY; |
| features.layoutScaleZ = scaleZ; |
| features.layoutRotationX = rotationX; |
| features.layoutRotationY = rotationY; |
| features.layoutRotationZ = rotation; |
| features.layoutX = x; |
| features.layoutY = y; |
| features.layoutZ = z; |
| features.layoutWidth = width; // for the mirror transform |
| _height = height; // for backing storage |
| layoutFeatures = features; |
| } |
| } |
| |
| /** |
| * @private |
| * Applies the transform matrix calculated by AdvancedLayoutFeatures |
| * so that this bitmap will not be mirrored if a parent is mirrored. |
| */ |
| private function validateTransformMatrix():void |
| { |
| if (layoutFeatures != null) |
| { |
| if (layoutFeatures.is3D) |
| super.transform.matrix3D = layoutFeatures.computedMatrix3D; |
| else |
| super.transform.matrix = layoutFeatures.computedMatrix; |
| } |
| } |
| } |
| |
| } |