blob: c90713d6ddfac30e5f46a42dfd6223743f966144 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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.flash
{
import flash.display.DisplayObjectContainer;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.geom.Rectangle;
import mx.core.ILayoutDirectionElement;
import mx.core.IUIComponent;
import mx.core.IVisualElement;
import mx.core.IVisualElementContainer;
import mx.core.mx_internal;
use namespace mx_internal;
[DefaultProperty("content")]
/**
* Container components created in Adobe Flash Professional for use in Flex
* are subclasses of the mx.flash.ContainerMovieClip class.
* You can use a subclass of ContainerMovieClip
* as a Flex container, it can hold children,
* and it can respond to events, define view states and transitions,
* and work with effects in the same way as can any Flex component.
*
* <p>A Flash container can only have a single Flex IUIComponent child.
* However, this child can be a Flex container which allows
* you to add additional children.</p>
*
* <p>If your Flash container modifies the visual characteristics
* of the Flex components contained in it, such as changing the <code>alpha</code> property,
* you must embed the fonts used by the Flex components.
* This is the same requirement that you have when using the Dissolve, Fade,
* and Rotate effects with Flex components. </p>
*
* <p>The following procedure describes the basic process for creating
* a Flex component in Flash Professional:</p>
*
* <ol>
* <li>Install the Adobe Flash Workflow Integration Kit.</li>
* <li>Create symbols for your dynamic assets in the FLA file.</li>
* <li>Run Commands &gt; Make Flex Container to convert your symbol
* to a subclass of the ContainerMovieClip class, to configure
* the Flash Professional publishing settings for use with Flex, and
* add a new symbol named FlexContentHolder to the Library.
* This symbol defines the content area of the container in which
* you can place child Flex components..</li>
* <li>Publish your FLA file as a SWC file.</li>
* <li>Reference the class name of your symbols in your Flex application
* as you would any class.</li>
* <li>Include the SWC file in your <code>library-path</code> when you compile
* your Flex application.</li>
* </ol>
*
* <p>For more information, see the documentation that ships with the
* Flex/Flash Integration Kit at
* <a href="http://www.adobe.com/go/flex3_cs3_swfkit">http://www.adobe.com/go/flex3_cs3_swfkit</a>.</p>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public dynamic class ContainerMovieClip extends UIMovieClip implements IVisualElementContainer
{
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function ContainerMovieClip()
{
super();
addEventListener(Event.ADDED, addedHandler);
addEventListener(Event.REMOVED, removedHandler);
}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// bounds
//----------------------------------
/**
* @private
* Need to override here to set the scaleX and scaleY of the contentHolderObj.
*/
override protected function get bounds():Rectangle
{
// not calling super.bounds but the functionality is copied here.
// if we have a bounding box, use that. With a bounding box,
// this bounds getter might get called frequently.
if (boundingBoxName && boundingBoxName != ""
&& boundingBoxName in this && this[boundingBoxName])
{
return this[boundingBoxName].getBounds(this);
}
// otherwise we need to change the scaleX and scaleY of the contentHolderObj so that we don't
// take the contentHolderObj into account at all
if (contentHolderObj)
{
var oldScaleX:Number = contentHolderObj.$scaleX;
var oldScaleY:Number = contentHolderObj.$scaleY;
contentHolderObj.$scaleX = 0.001;
contentHolderObj.$scaleY = 0.001;
}
var bounds:Rectangle = getBounds(this);
if (contentHolderObj)
{
contentHolderObj.$scaleX = oldScaleX;
contentHolderObj.$scaleY = oldScaleY;
}
return bounds;
}
//----------------------------------
// contentHolder
//----------------------------------
private var _contentHolder:*;
/**
* @private
*/
protected function get contentHolderObj():FlexContentHolder
{
if (_contentHolder === undefined)
{
for (var i:int = 0; i < numChildren; i++)
{
var child:FlexContentHolder = getChildAt(i) as FlexContentHolder;
if (child)
{
_contentHolder = child;
break;
}
}
}
return _contentHolder;
}
//----------------------------------
// content
//----------------------------------
private var _content:IUIComponent;
/**
* The Flex content to display inside this container.
*
* <p>Typically, to add a child to a container in ActionScript,
* you use the <code>Container.addChild()</code> or <code>Container.addChildAt()</code> method.
* However, to add a child to the <code>ContainerMovieClip.content</code> property
* of a Flash container, you do not use the <code>addChild()</code> or <code>addChildAt()</code> method.
* Instead, you assign the child directly to the content property. </p>
*
* <p>The following example assigns a container to the <code>ContainerMovieClip.content</code> property.</p>
* <pre>
* &lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
* xmlns:myComps="~~"&gt;
*
* &lt;mx:Script&gt;
* &lt;![CDATA[
* import mx.containers.HBox;
* import mx.controls.Image;
*
* private function init():void {
* // Define the Image control.
* var image1:Image = new Image();
* image1.source = "../assets/logowithtext.jpg";
* image1.percentWidth = 80;
* image1.percentHeight = 80;
*
* // Define the HBox container.
* var hb1:HBox = new HBox();
* hb1.percentWidth = 100;
* hb1.percentHeight = 100;
* hb1.setStyle('borderStyle', 'solid');
* hb1.addChild(image1);
*
* // Assign the HBox container to the
* // ContainerMovieClip.content property..
* pFrame.content = hb1;
* }
* ]]&gt;
* &lt;/mx:Script&gt;
*
* &lt;myComps:MyPictureFrameContainer id="pFrame"
* initialize="init();"/&gt;
* &lt;/mx:Application&gt;</pre>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get content():IUIComponent
{
return contentHolderObj ? contentHolderObj.content : _content;
}
/**
* @private
*/
public function set content(value:IUIComponent):void
{
if (contentHolderObj)
{
contentHolderObj.content = value;
}
_content = value;
invalidateParentSizeAndDisplayList();
}
//----------------------------------
// scaleContentWhenResized
//----------------------------------
private var _scaleContentWhenResized:Boolean = false;
[Inspectable(category="General", enumeration="false,true", defaultValue="false")]
/**
* Whether the scale of the container due to sizing
* affects the scale of the flex content.
*
* <p>When Flash components are resized, they scale up or down to their new size.
* However, this means their children are also scaled up or down. By setting this
* flag to false, the children are inversely scaled when the container is resized.</p>
*
* <p>Note: When the container is scaled direclty (through scaleX or scaleY), the
* content will also be scaled accordingly. This only affects scaling of the
* container due to sizing.</p>
*
* @default false
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get scaleContentWhenResized():Boolean
{
return _scaleContentWhenResized;
}
/**
* @private
*/
public function set scaleContentWhenResized(value:Boolean):void
{
_scaleContentWhenResized = value;
if (initialized)
sizeContentHolder();
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
override public function setActualSize(newWidth:Number, newHeight:Number):void
{
super.setActualSize(newWidth, newHeight);
sizeContentHolder();
}
/**
* @private
*
* Sizes the contentHolder and sets the scale of the contentHolder
* according to applyInverseScaleToContent.
*/
protected function sizeContentHolder():void
{
if (contentHolderObj)
{
// width and height are what we actually want our content
// to fill up, but it doesn't take in to account our secretScale.
if (!scaleContentWhenResized && _layoutFeatures != null)
{
// apply inverse of the scale
contentHolderObj.scaleX = 1/_layoutFeatures.stretchX;
contentHolderObj.scaleY = 1/_layoutFeatures.stretchY;
}
else
{
// apply the scale to the width/height
contentHolderObj.scaleX = 1;
contentHolderObj.scaleY = 1;
}
contentHolderObj.sizeFlexContent();
}
}
/**
* @private
*/
override protected function findFocusCandidates(obj:DisplayObjectContainer):void
{
// No-op. Container movie clips use Flex focus management only.
}
/**
* @private
*/
override protected function focusInHandler(event:FocusEvent):void
{
// No-op. Flex focus management does all the work.
}
/**
* @private
* This is only called if the parent's layoutDirection has changed.
*/
override public function invalidateLayoutDirection():void
{
super.invalidateLayoutDirection();
// Since this component is not a StyleClient it can't take advantage
// of the styleChanged() machinery to notify its children that its
// layoutDirection has changed.
const thisLayoutDirection:String = layoutDirection;
const thisContainerNumElements:int = numElements;
for (var i:int = 0; i < thisContainerNumElements; i++)
{
const elt:IVisualElement = getElementAt(i);
ILayoutDirectionElement(elt).layoutDirection = thisLayoutDirection;
}
}
//--------------------------------------------------------------------------
//
// Methods: IVisualElementContainer
//
//--------------------------------------------------------------------------
/**
* Returns 1 if there is a viewport, 0 otherwise.
*
* @return The number of visual elements in this visual container
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function get numElements():int
{
return content ? 1 : 0;
}
/**
* Returns the viewport if there is a viewport and the
* index passed in is 0. Otherwise, it throws a RangeError.
*
* @param index The index of the element to retrieve.
*
* @return The element at the specified index.
*
* @throws RangeError If the index position does not exist in the child list.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function getElementAt(index:int):IVisualElement
{
if (content && index == 0)
return content as IVisualElement;
else
throw new RangeError("Index " + index + " is out of range.");
}
/**
* Returns the 0 if the element passed in is the viewport.
* Otherwise, it throws an ArgumentError.
*
* @param element The element to identify.
*
* @return The index position of the element to identify.
*
* @throws ArgumentError If the element is not a child of this object.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function getElementIndex(element:IVisualElement):int
{
if (element != null && element == content)
return 0;
else
throw ArgumentError(element + " is not found in this container.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function addElement(element:IVisualElement):IVisualElement
{
throw new ArgumentError("This operation is not supported.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function addElementAt(element:IVisualElement, index:int):IVisualElement
{
throw new ArgumentError("This operation is not supported.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function removeElement(element:IVisualElement):IVisualElement
{
throw new ArgumentError("This operation is not supported.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function removeElementAt(index:int):IVisualElement
{
throw new ArgumentError("This operation is not supported.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function removeAllElements():void
{
throw new ArgumentError("This operation is not supported.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function setElementIndex(element:IVisualElement, index:int):void
{
throw new ArgumentError("This operation is not supported.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function swapElements(element1:IVisualElement, element2:IVisualElement):void
{
throw new ArgumentError("This operation is not supported.");
}
/**
* @inheritDoc
*
* <p>This operation is not supported in ContainerMovieClip. ContainerMovieClip
* only has one child. Use the <code>content</code> property to manipulate
* it.</p>
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public function swapElementsAt(index1:int, index2:int):void
{
throw new ArgumentError("This operation is not supported.");
}
//--------------------------------------------------------------------------
//
// Event Handlers
//
//--------------------------------------------------------------------------
/**
* @private
* Any time a display object gets added, let's see if this is a child
* that belongs to use and needs to be initialized. Also if it is
* the contentHolder, let's stuff the content down into it.
*
* <p>We only need this method if the child gets added after
* we've already been initialized.</p>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 4
*/
protected function addedHandler(event:Event):void
{
// if we haven't initialized, we'll handle
// that stuff in there
if (!initialized)
return;
// if it's not a direct descendent, don't
// worry about it
if (event.target.parent != this)
return;
// if it's the FlexContentHolder, let's
// treat it as such.
if (event.target is FlexContentHolder && !_contentHolder)
{
_contentHolder = event.target;
if (_content)
content = _content;
}
// Call initialize() on any IUIComponent children
var child:IUIComponent = event.target as IUIComponent;
if (child)
child.initialize();
}
/**
* @private
* Any time a display object gets removed, let's see if this child
* is the contentHolder. If it is, let's null out our reference to
* _contentHolder.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 4
*/
protected function removedHandler(event:Event):void
{
if (event.target == _contentHolder)
{
_contentHolder = null;
}
}
}
}