blob: 46d3648c044913429696ff70a2ff258e8faf3e76 [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.containers
{
import flash.events.Event;
import mx.containers.utilityClasses.BoxLayout;
import mx.core.Container;
import mx.core.IUIComponent;
import mx.core.mx_internal;
use namespace mx_internal;
//--------------------------------------
// Styles
//--------------------------------------
include "../styles/metadata/AlignStyles.as";
include "../styles/metadata/GapStyles.as";
/**
* Number of pixels between the container's bottom border
* and the bottom of its content area.
* The default value is 0.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="paddingBottom", type="Number", format="Length", inherit="no")]
/**
* Number of pixels between the container's top border
* and the top of its content area.
* The default value is 0.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="paddingTop", type="Number", format="Length", inherit="no")]
//--------------------------------------
// Excluded APIs
//--------------------------------------
[Exclude(name="focusIn", kind="event")]
[Exclude(name="focusOut", kind="event")]
[Exclude(name="focusBlendMode", kind="style")]
[Exclude(name="focusSkin", kind="style")]
[Exclude(name="focusThickness", kind="style")]
[Exclude(name="focusInEffect", kind="effect")]
[Exclude(name="focusOutEffect", kind="effect")]
//--------------------------------------
// Other metadata
//--------------------------------------
[IconFile("Box.png")]
[Alternative(replacement="spark.components.HGroup", since="4.0")]
[Alternative(replacement="spark.components.VGroup", since="4.0")]
[Alternative(replacement="spark.components.BorderContainer", since="4.0")]
/**
* A Halo Box container lays out its children in a single vertical column
* or a single horizontal row.
* The <code>direction</code> property determines whether to use
* vertical (default) or horizontal layout.
*
* <p><b>Note:</b> Adobe recommends that, when possible, you use the Spark containers
* with HorizontalLayout or VerticalLayout instead of the Halo Box container.</p>
*
* <p>The Box class is the base class for the VBox and HBox classes.
* You use the <code>&lt;mx:Box&gt;</code>, <code>&lt;mx:VBox&gt;</code>,
* and <code>&lt;mx:HBox&gt;</code> tags to define Box containers.</p>
*
* <p>A Box container has the following default sizing characteristics:</p>
* <table class="innertable">
* <tr>
* <th>Characteristic</th>
* <th>Description</th>
* </tr>
* <tr>
* <td>Default size</td>
* <td><strong>Vertical Box</strong> The height is large enough to hold all its children at the default
* or explicit height of the children, plus any vertical gap between the children, plus the top and
* bottom padding of the container. The width is the default or explicit width of the widest child,
* plus the left and right padding of the container.
* <br><strong>Horizontal Box</strong> The width is large enough to hold all of its children at the
* default width of the children, plus any horizontal gap between the children, plus the left and
* right padding of the container. The height is the default or explicit height of the tallest child,
* plus the top and bottom padding for the container.</br>
* </td>
* </tr>
* <tr>
* <td>Default padding</td>
* <td>0 pixels for the top, bottom, left, and right values.</td>
* </tr>
* </table>
*
* @mxml
*
* <p>The <code>&lt;mx:Box&gt;</code> tag inherits all of the tag
* attributes of its superclass, and adds the following tag attributes:</p>
*
* <p>
* <pre>
* &lt;mx:Box
* <strong>Properties</strong>
* direction="vertical|horizontal"
* <strong>Styles</strong>
* horizontalAlign="left|center|right"
* horizontalGap="8"
* paddingBottom="0"
* paddingTop="0"
* verticalAlign="top|middle|bottom"
* verticalGap="6"
* &gt;
* ...
* <i>child tags</i>
* ...
* &lt;/mx:Box&gt;
* </pre>
* </p>
*
* @includeExample examples/SimpleBoxExample.mxml
*
* @see mx.core.Container
* @see mx.containers.HBox
* @see mx.containers.VBox
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class Box extends Container
{
include "../core/Version.as"
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function Box()
{
super();
layoutObject.target = this;
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
mx_internal var layoutObject:BoxLayout = new BoxLayout();
//--------------------------------------------------------------------------
//
// Public properties
//
//--------------------------------------------------------------------------
//----------------------------------
// direction
//----------------------------------
[Bindable("directionChanged")]
[Inspectable(category="General", enumeration="vertical,horizontal", defaultValue="vertical")]
/**
* The direction in which this Box container lays out its children.
* Possible MXML values are
* <code>"horizontal"</code> and <code>"vertical"</code>.
* Possible values in ActionScript are <code>BoxDirection.HORIZONTAL</code>
* and <code>BoxDirection.VERTICAL</code>.
*
* @default BoxDirection.VERTICAL
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get direction():String
{
return layoutObject.direction;
}
/**
* @private
*/
public function set direction(value:String):void
{
layoutObject.direction = value;
invalidateSize();
invalidateDisplayList();
dispatchEvent(new Event("directionChanged"));
}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
/**
* Calculates the default sizes and minimum and maximum values of the Box
* container.
*
* <p>If the Box container's <code>direction</code> property is set to
* <code>BoxDirection.HORIZONTAL</code>, its <code>measuredWidth</code>
* property is equal to the sum of default widths of all of its children,
* plus the thickness of the borders, plus the left and right padding,
* plus the horizontal gap between each child.
* The value of the <code>measuredHeight</code> property is the maximum of
* all the children's default heights, plus room for the borders and
* padding.
* If the Box container's <code>direction</code> property is set to
* <code>BoxDirection.VERTICAL</code>, these two values are reversed.</p>
*
* <p>The Box container's <code>minWidth</code> and <code>minHeight</code>
* properties are calculated similarly, by combining the minimum widths
* and minimum heights of the children.
* If the child's <code>width</code> property is a percentage value, the
* Box container's minimum width is equal to the value of the child's
* <code>minWidth</code> property.
* If the child's <code>width</code> is unset or set to a fixed value,
* the child refuses to grow or shrink, so the Box container's minimum
* width is equal to the value of the child's <code>explicitWidth</code>
* property.
* The child's minimum height is calculated similarly.</p>
*
* <p>The Box container's <code>maxWidth</code> and
* <code>maxHeight</code> properties are not calculated.
* The Box container is assumed to have an infinite maximum width and
* height.</p>
*
* <p>All of the values described previously are the <i>measured</i>
* widths and heights of the Box container.
* The user can override the measured values by explicitly supplying
* a value for the following properties:</p>
*
* <ul>
* <li><code>width</code></li>
* <li><code>height</code></li>
* <li><code>minWidth</code></li>
* <li><code>minHeight</code></li>
* <li><code>maxWidth</code></li>
* <li><code>maxHeight</code></li>
* </ul>
*
* <p>You should not call the <code>measure()</code> method directly.
* The Flex LayoutManager calls it at the appropriate time.
* At application startup, the Flex LayoutManager attempts to measure
* all components from the children to the parents before setting them
* to their final sizes.</p>
*
* <p>This is an advanced method for use in subclassing.
* If you override this method, your implementation must call
* the <code>super.measure()</code> method, or set the
* <code>measuredHeight</code> and
* <code>measuredWidth</code> properties.
* You may also optionally set the following properties:</p>
*
* <ul>
* <li><code>measuredMinWidth</code></li>
* <li><code>measuredMinHeight</code></li>
* </ul>
*
* <p>These properties correspond to the layout properties listed
* previously and, therefore, are not separately documented.</p>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
override protected function measure():void
{
super.measure();
layoutObject.measure();
}
/**
* Sets the size and position of each child of the Box container.
*
* <p>To understand the layout algorithm for the Box container, assume
* that the Box container's direction is horizontal.</p>
*
* <p>All of the Box container's children are positioned side-by-side in a
* single horizontal row, with <code>horizontalGap</code> pixels between
* each pair of adjacent children.
* Initially, the widths of children without an explicit
* width value are set equal to the values of their
* <code>measuredWidth</code> properties.</p>
*
* <p>If the sum of the values of the <code>measuredWidth</code>
* properties of the children is greater than or less than the width of
* the Box container, and if some of the children have a percentage value
* for the <code>width</code> property, the sizes of those children are
* grown or shrunk until all children exactly fit in the Box.
* However, no child is shrunk to less than the value of its
* <code>minWidth</code> property or increased greater than the value of
* its <code>maxWidth</code> property.
* Among the growing (or shrinking) children, extra space is added
* (or removed) in proportion to the child's <code>percentWidth</code>.
* For example, a child with a <code>percentWidth</code> of 40 percent
* will grow twice as much as a child with a <code>percentWidth</code> of
* 20 percent until all of the available space is filled or the prescribed
* sizes are reached.</p>
*
* <p>After all flexible children have grown or shrunk, Flex checks to see
* if the sum of the children's widths match the width of the Box
* container.
* If not, the group of children are all shifted according to the value
* of the Box container's <code>horizontalAlign</code> property, so the
* children are aligned with the left edge of the Box, aligned with the
* right edge of the Box, or centered in the middle of the Box.</p>
*
* <p>To determine the height of each child, Flex examines the value
* of the child's <code>height</code> property.
* If the <code>height</code> is unset, the child's height
* is set to its <code>measuredHeight</code>.
* If the <code>height</code> is set to a pixel value, that value is used.
* If the <code>height</code> is set to a percentage value,
* the child's height is grown or shrunk to match the specified
* percentage of the height of the Box, as long as the child's height
* is not shrunk to less than the value of its <code>minHeight</code>
* property or grown to be larger than the value of its
* <code>maxHeight</code> property.</p>
*
* <p>The vertical position of each child is determined by
* the Box container's <code>verticalAlign</code> property.
* Each child is shifted so that it is aligned with the top edge
* of the box, aligned with the bottom edge of the box,
* or centered in the Box.</p>
*
* <p>If the Box container's <code>direction</code> is
* <code>vertical</code>, the same rules apply, except that the widths and
* heights are swapped.
* The children are arranged in a single vertical column.</p>
*
* <p>You should not call this method directly.
* The Flex LayoutManager calls it at the appropriate time.
* At application startup, the Flex LayoutManager calls the
* <code>updateDisplayList()</code> method on every component,
* starting with the Application object and working downward.</p>
*
* <p>This is an advanced method for use in subclassing.
* If you override this method, your implementation should call the
* <code>super.updateDisplayList()</code> method and call the
* <code>move()</code> and <code>setActualSize()</code> methods
* on each of the children.
* For the purposes of performing layout, you should get the size
* of this container from the <code>unscaledWidth</code> and
* <code>unscaledHeight</code> properties, not the <code>width</code>
* and <code>height</code> properties.
* The <code>width</code> and <code>height</code> properties
* do not take into account the values of the <code>scaleX</code>
* and <code>scaleY</code> properties for this container.</p>
*
* @param unscaledWidth Specifies the width of the component, in pixels,
* in the component's coordinates, regardless of the value of the
* <code>scaleX</code> property of the component.
*
* @param unscaledHeight Specifies the height of the component, in pixels,
* in the component's coordinates, regardless of the value of the
* <code>scaleY</code> property of the component.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
layoutObject.updateDisplayList(unscaledWidth, unscaledHeight);
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Method used to convert number of pixels to a
* percentage relative to the contents of this container.
*
* <p>The percentage value is relevant only while the
* container does not change size or layout.
* After a resize and/or new layout has occurred,
* the value returned from this method may be stale.</p>
*
* <p>An example of how this method could be used would
* be to restore a component's size to a specific number
* of pixels after hiding it.</p>
*
* @param pxl The number of pixels for which a percentage
* value is desired.
*
* @return The percentage value that would be equivalent
* to <code>pxl</code> under the current layout conditions
* of this container.
* A negative value indicates that the container must grow
* in order to accommodate the requested size.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function pixelsToPercent(pxl:Number):Number
{
var vertical:Boolean = isVertical();
// Compute our total percent and total # pixels for that percent.
var totalPerc:Number = 0;
var totalSize:Number = 0;
var n:int = numChildren;
for (var i:int = 0; i < n; i++)
{
var child:IUIComponent = getLayoutChildAt(i);
var size:Number = vertical ? child.height : child.width;
var perc:Number = vertical ? child.percentHeight : child.percentWidth;
if (!isNaN(perc))
{
totalPerc += perc;
totalSize += size;
}
}
// Now if we found one let's compute the percent amount
// that we'd require for a given number of pixels.
var p:Number = 100;
if (totalSize != pxl)
{
// Now we want the ratio of pixels per percent to
// remain constant as we assume the a component
// will consume them. So,
//
// (totalSize - pxl) / totalPerc = totalSize / (totalPerc + p)
//
// where we solve for p.
p = ((totalSize * totalPerc) / (totalSize - pxl)) - totalPerc;
}
return p;
}
/**
* @private
*/
mx_internal function isVertical():Boolean
{
return direction != BoxDirection.HORIZONTAL;
}
}
}