/***************************************************** * * Copyright 2009 Adobe Systems Incorporated. All Rights Reserved. * ***************************************************** * The contents of this file are subject to the Mozilla Public License * Version 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * * The Initial Developer of the Original Code is Adobe Systems Incorporated. * Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems * Incorporated. All Rights Reserved. * *****************************************************/ package org.osmf.containers { import flash.display.DisplayObject; import flash.errors.IllegalOperationError; import flash.geom.Rectangle; import flash.utils.Dictionary; import org.osmf.events.ContainerChangeEvent; import org.osmf.layout.LayoutMetadata; import org.osmf.layout.LayoutRenderer; import org.osmf.layout.LayoutRendererBase; import org.osmf.layout.LayoutTargetEvent; import org.osmf.layout.LayoutTargetSprite; import org.osmf.layout.MediaElementLayoutTarget; import org.osmf.media.MediaElement; import org.osmf.utils.OSMFStrings; /** * MediaContainer defines a Sprite-based IMediaContainer implementation. * * @includeExample MediaContainerExample.as -noswf * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public class MediaContainer extends LayoutTargetSprite implements IMediaContainer { /** * Constructor. * * @param layoutRenderer The layout renderer that will render * the MediaElement instances that get added to this container. If no * renderer is specified, a LayoutRenderer instance will be used. * @param layoutMetadata The LayoutMetadata to use to layout this * sprite. Optional. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function MediaContainer(layoutRenderer:LayoutRendererBase=null, layoutMetadata:LayoutMetadata=null) { super(layoutMetadata); _layoutRenderer = layoutRenderer || new LayoutRenderer(); _layoutRenderer.container = this; } /** * Adds a MediaElement instance to the container. * * @param element The MediaElement instance to add to the container. * @returns The added MediaElement instance. * @throws IllegalOperationError if the specified element is null, * or already a child of the container. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function addMediaElement(element:MediaElement):MediaElement { if (element == null) { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.NULL_PARAM)); } if (layoutTargets[element] == undefined) { // Media containers are under obligation to dispatch a container change event when // they add a media element: element.dispatchEvent ( new ContainerChangeEvent ( ContainerChangeEvent.CONTAINER_CHANGE , false, false , element.container, this ) ); var contentTarget:MediaElementLayoutTarget = MediaElementLayoutTarget.getInstance(element); layoutTargets[element] = contentTarget; _layoutRenderer.addTarget(contentTarget); element.addEventListener(ContainerChangeEvent.CONTAINER_CHANGE, onElementContainerChange); } else { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); } return element; } /** * Removes a MediaElement instance from the container. * * @param element The element to remove from the container. * @returns The removed MediaElement instance. * @throws IllegalOperationError if the specified element isn't * a child element, or is null. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function removeMediaElement(element:MediaElement):MediaElement { if (element == null) { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.NULL_PARAM)); } var result:MediaElement; var contentTarget:MediaElementLayoutTarget = layoutTargets[element]; if (contentTarget) { element.removeEventListener(ContainerChangeEvent.CONTAINER_CHANGE, onElementContainerChange); _layoutRenderer.removeTarget(contentTarget); delete layoutTargets[element]; result = element; // Media containers are under obligation to dispatch a container change event when // they remove a media element. See if we're still the element's container, though. // For if not, a change has already occured. if (element.container == this) { element.dispatchEvent ( new ContainerChangeEvent ( ContainerChangeEvent.CONTAINER_CHANGE , false, false , element.container, null ) ); } } else { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.INVALID_PARAM)); } return result; } /** * Verifies if an element is a child of the container. * * @param element Element to verify. * @return True if the element if a child of the container. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function containsMediaElement(element:MediaElement):Boolean { return layoutTargets[element] != undefined } /** * The layout renderer that renders the MediaElement instances within * this container. **/ public function get layoutRenderer():LayoutRendererBase { return _layoutRenderer; } /** * Defines if the children of the container that display outside of its bounds * will be clipped or not. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get clipChildren():Boolean { return scrollRect != null; } public function set clipChildren(value:Boolean):void { if (value && scrollRect == null) { scrollRect = new Rectangle(0, 0, _layoutRenderer.measuredWidth, _layoutRenderer.measuredHeight); } else if (value == false && scrollRect) { scrollRect = null; } } /** * Defines the container's background color. By default, this value * is set to NaN, which results in no background being drawn. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get backgroundColor():Number { return _backgroundColor; } public function set backgroundColor(value:Number):void { if (value != _backgroundColor) { _backgroundColor = value; drawBackground(); } } /** * Defines the container's background alpha. By default, this value * is set to 1, which results in the background being fully opaque. * * Note that a container will not have a background drawn unless its * backgroundColor property is set. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion OSMF 1.0 */ public function get backgroundAlpha():Number { return _backgroundAlpha; } public function set backgroundAlpha(value:Number):void { if (value != _backgroundAlpha) { _backgroundAlpha = value; drawBackground(); } } // Overrides // /** * @private **/ override public function layout(availableWidth:Number, availableHeight:Number, deep:Boolean = true):void { super.layout(availableWidth, availableHeight, deep); lastAvailableWidth = availableWidth; lastAvailableHeight = availableHeight; if (!isNaN(backgroundColor)) { drawBackground(); } if (scrollRect) { scrollRect = new Rectangle(0, 0, availableWidth, availableHeight); } } /** * @private */ override public function validateNow():void { _layoutRenderer.validateNow(); } // Overrides // /** * @private **/ override public function addChild(child:DisplayObject):DisplayObject { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.DIRECT_DISPLAY_LIST_MOD_ERROR)); } /** * @private **/ override public function addChildAt(child:DisplayObject, index:int):DisplayObject { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.DIRECT_DISPLAY_LIST_MOD_ERROR)); } /** * @private **/ override public function removeChild(child:DisplayObject):DisplayObject { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.DIRECT_DISPLAY_LIST_MOD_ERROR)); } /** * @private **/ override public function setChildIndex(child:DisplayObject, index:int):void { throw new IllegalOperationError(OSMFStrings.getString(OSMFStrings.DIRECT_DISPLAY_LIST_MOD_ERROR)); } /** * @private **/ override protected function onAddChildAt(event:LayoutTargetEvent):void { super.addChildAt(event.displayObject, event.index); } /** * @private **/ override protected function onRemoveChild(event:LayoutTargetEvent):void { super.removeChild(event.displayObject); } /** * @private **/ override protected function onSetChildIndex(event:LayoutTargetEvent):void { super.setChildIndex(event.displayObject, event.index); } // Internals // private function drawBackground():void { graphics.clear(); if ( !isNaN(_backgroundColor) && _backgroundAlpha != 0 && lastAvailableWidth && lastAvailableHeight ) { graphics.beginFill(_backgroundColor,_backgroundAlpha); graphics.drawRect(0, 0, lastAvailableWidth, lastAvailableHeight); graphics.endFill(); } } private function onElementContainerChange(event:ContainerChangeEvent):void { if (event.oldContainer == this) { removeMediaElement(event.target as MediaElement); } } /** * @private * * Dictionary of MediaElementLayoutTarget instances, index by the * media elements that they wrap: */ private var layoutTargets:Dictionary = new Dictionary(); private var _layoutRenderer:LayoutRendererBase; private var _backgroundColor:Number; private var _backgroundAlpha:Number; private var lastAvailableWidth:Number; private var lastAvailableHeight:Number; } }