http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/CanvasLayout.as ---------------------------------------------------------------------- diff --cc frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/CanvasLayout.as index 16f9b7f,0000000..2538b11 mode 100644,000000..100644 --- a/frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/CanvasLayout.as +++ b/frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/CanvasLayout.as @@@ -1,1938 -1,0 +1,1938 @@@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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.utilityClasses +{ + - COMPILE::AS3 ++COMPILE::SWF +{ +import flash.display.DisplayObject; +import flash.geom.Rectangle; +} +COMPILE::JS +{ +import flex.display.DisplayObject; +import org.apache.flex.geom.Rectangle; +} +COMPILE::LATER +{ +import mx.containers.Canvas; +} +import mx.containers.errors.ConstraintError; +import mx.core.Container; +import mx.core.EdgeMetrics; +import mx.core.IConstraintClient; +import mx.core.IUIComponent; +import mx.core.mx_internal; +import mx.events.ChildExistenceChangedEvent; +import mx.events.MoveEvent; +import mx.resources.IResourceManager; +import mx.resources.ResourceManager; +COMPILE::LATER +{ +import flash.utils.Dictionary; +} + +use namespace mx_internal; + +[ExcludeClass] + +[ResourceBundle("containers")] + +/** + * @private + * The CanvasLayout class is for internal use only. + */ +public class CanvasLayout extends Layout +{ + include "../../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class variables + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private static var r:Rectangle = new Rectangle(); + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + /** + * @private + * Restrict a number to a particular min and max. + */ + private function bound(a:Number, min:Number, max:Number):Number + { + if (a < min) + a = min; + else if (a > max) + a = max; + else + a = Math.floor(a); + + return a; + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + private var _contentArea:Rectangle; + + //Arrays that keep track of children spanning + //content size columns or rows. + private var colSpanChildren:Array = []; + private var rowSpanChildren:Array = []; + + COMPILE::LATER + { + private var constraintCache:Dictionary = new Dictionary(true); + } + + private var constraintRegionsInUse:Boolean = false; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function CanvasLayout() + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Overridden properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // target + //---------------------------------- + + /** + * @private + */ + override public function set target(value:Container):void + { + var target:Container = super.target; + if (value != target) + { + var i:int; + var n:int; + + if (target) + { + // Start listening for child existence events. + // We want to track the movement of children + // so we can update our size every time a + // child moves. + + target.removeEventListener( + ChildExistenceChangedEvent.CHILD_ADD, + target_childAddHandler); + target.removeEventListener( + ChildExistenceChangedEvent.CHILD_REMOVE, + target_childRemoveHandler); + + n = target.numChildren; + for (i = 0; i < n; i++) + { + DisplayObject(target.getChildAt(i)).removeEventListener( + MoveEvent.MOVE, child_moveHandler); + } + } + + if (value) + { + value.addEventListener( + ChildExistenceChangedEvent.CHILD_ADD, + target_childAddHandler); + value.addEventListener( + ChildExistenceChangedEvent.CHILD_REMOVE, + target_childRemoveHandler); + + n = value.numChildren; + for (i = 0; i < n; i++) + { + DisplayObject(value.getChildAt(i)).addEventListener( + MoveEvent.MOVE, child_moveHandler); + } + } + + super.target = value; + } + } + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * @private + * Measure container as per Canvas layout rules. + */ + override public function measure():void + { + var target:Container = super.target; + var w:Number = 0; + var h:Number = 0; + var i:Number = 0; + + var vm:EdgeMetrics = target.viewMetrics; + + for (i = 0; i < target.numChildren; i++) + { + var child:IUIComponent = target.getLayoutChildAt(i); + parseConstraints(child); + } + + //We need to NaN out content-sized columns and rows width/height values + //so that new values are calculated correctly and we avoid stale values + for (i = 0; i < IConstraintLayout(target).constraintColumns.length; i++) + { + var col:ConstraintColumn = IConstraintLayout(target).constraintColumns[i]; + if (col.contentSize) + col._width = NaN; + } + for (i = 0; i < IConstraintLayout(target).constraintRows.length; i++) + { + var row:ConstraintRow = IConstraintLayout(target).constraintRows[i]; + if (row.contentSize) + row._height = NaN; + } + + measureColumnsAndRows(); + + _contentArea = null; + var contentArea:Rectangle = measureContentArea(); + + // Only add viewMetrics padding + // if children are bigger than existing size. + target.measuredWidth = contentArea.width + vm.left + vm.right; + target.measuredHeight = contentArea.height + vm.top + vm.bottom; + } + + /** + * @private + * Lay out children as per Canvas layout rules. + */ + override public function updateDisplayList(unscaledWidth:Number, + unscaledHeight:Number):void + { + var i:int; + var child:IUIComponent; + var target:Container = super.target; + var n:int = target.numChildren; + // viewMetrics include scrollbars during updateDisplayList, but not + // during measure. In order to avoid a race condition when the + // scrollable area is within a scrollbar's width of the view metrics, + // we use the non-update viewMetrics, which don't include scrollbars. + target.doingLayout = false; + var vm:EdgeMetrics = target.viewMetrics; + target.doingLayout = true; + + var viewableWidth:Number = unscaledWidth - vm.left - vm.right; + var viewableHeight:Number = unscaledHeight - vm.top - vm.bottom; + + if (IConstraintLayout(target).constraintColumns.length > 0 || + IConstraintLayout(target).constraintRows.length > 0) + constraintRegionsInUse = true; + if (constraintRegionsInUse) + { + for (i = 0; i < n; i++) + { + child = target.getLayoutChildAt(i); + parseConstraints(child); + } + + //We need to NaN out content-sized columns and rows width/height values + //so that new values are calculated correctly and we avoid stale values + for (i = 0; i < IConstraintLayout(target).constraintColumns.length; i++) + { + var col:ConstraintColumn = IConstraintLayout(target).constraintColumns[i]; + if (col.contentSize) + col._width = NaN; + } + for (i = 0; i < IConstraintLayout(target).constraintRows.length; i++) + { + var row:ConstraintRow = IConstraintLayout(target).constraintRows[i]; + if (row.contentSize) + row._height = NaN; + } + + measureColumnsAndRows(); + } + + // Apply the CSS styles left, top, right, bottom, + // horizontalCenter, and verticalCenter; + // these override x, y, width, and height if specified. + for (i = 0; i < n; i++) + { + child = target.getLayoutChildAt(i); + applyAnchorStylesDuringUpdateDisplayList(viewableWidth, viewableHeight, child); + } + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * @private + * Figure out the content area based on whether there are + * ConstraintColumn instances or ConstraintRow instances + * specified and the constraint style values. + */ + private function applyAnchorStylesDuringMeasure(child:IUIComponent, + r:Rectangle):void + { + var constraintChild:IConstraintClient = child as IConstraintClient; + if (!constraintChild) + return; + //Calculate constraint boundaries if it has not been calculated + //already + COMPILE::LATER + { + var childInfo:ChildConstraintInfo = constraintCache[constraintChild]; + } + var childInfo:ChildConstraintInfo; + if (!childInfo) + childInfo = parseConstraints(child); + var left:Number = childInfo.left; + var right:Number = childInfo.right; + var horizontalCenter:Number = childInfo.hc; + var top:Number = childInfo.top; + var bottom:Number = childInfo.bottom; + var verticalCenter:Number = childInfo.vc; + + var cols:Array = IConstraintLayout(target).constraintColumns; + var rows:Array = IConstraintLayout(target).constraintRows; + + var i:int; + var holder:Number = 0; + + if (!cols.length > 0) + { + if (!isNaN(horizontalCenter)) + { + r.x = Math.round((target.width - child.width) / 2 + horizontalCenter); + } + else if (!isNaN(left) && !isNaN(right)) + { + r.x = left; + r.width += right; + } + else if (!isNaN(left)) + { + r.x = left; + } + else if (!isNaN(right)) + { + r.x = 0; + r.width += right; + } + } + else //sum up the column widths + { + r.x = 0; + for (i = 0; i < cols.length; i++) + { + holder += ConstraintColumn(cols[i]).width; + } + r.width = holder; + } + + if (!rows.length > 0) + { + if (!isNaN(verticalCenter)) + { + r.y = Math.round((target.height - child.height) / 2 + verticalCenter); + } + else if (!isNaN(top) && !isNaN(bottom)) + { + r.y = top; + r.height += bottom; + } + else if (!isNaN(top)) + { + r.y = top; + } + else if (!isNaN(bottom)) + { + r.y = 0; + r.height += bottom; + } + } + else //sum up the row heights + { + holder = 0; + r.y = 0; + for (i = 0; i < rows.length; i++) + { + holder += ConstraintRow(rows[i]).height; + } + r.height = holder; + } + } + + /** + * @private + * Here is a description of the layout algorithm. + * It is described in terms of horizontal coordinates, + * but the vertical ones are similar. + * + * 1. First the actual width for the child is determined. + * + * 1a. If both left and right anchors are specified, + * the actual width is determined by them. + * However, the actual width is subject to the child's + * minWidth. + * + * 1b. Otherwise, if a percentWidth was specified, + * this percentage is applied to the + * ConstraintColumn/Parent's content width + * (the widest specified point of content, or the width of + * the parent/column, whichever is greater). + * The actual width is subject to the child's + * minWidth and maxWidth. + * + * 1c. Otherwise, if an explicitWidth was specified, + * this is used as the actual width. + * + * 1d. Otherwise, the measuredWidth is used is used as the + * actual width. + * + * 2. Then the x coordinate of the child is determined. + * + * Note:If a baseline constraint is specified, the center + * of the child (y position) is placed relative to the + * ConstraintRow specified. + * + * 2a. If a horizonalCenter anchor is specified, + * the center of the child is placed relative to the center + * of the parent/column. + * + * 2b. Otherwise, if a left anchor is specified, + * the left edge of the child is placed there. + * + * 2c. Otherwise, if a right anchor is specified, + * the right edge of the child is placed there. + * + * 2d. Otherwise, the child is left at its previously set + * x coordinate. + * + * 3. If the width is a percentage, try to make sure it + * doesn't overflow the content width (while still honoring + * minWidth). We need to wait + * until after the x coordinate is set to test this. + */ + private function applyAnchorStylesDuringUpdateDisplayList( + availableWidth:Number, + availableHeight:Number, + child:IUIComponent = null):void + { + var constraintChild:IConstraintClient = child as IConstraintClient; + if (!constraintChild) + return; + var childInfo:ChildConstraintInfo = parseConstraints(child); + // Variables to track the offsets + var left:Number = childInfo.left; + var right:Number = childInfo.right; + var horizontalCenter:Number = childInfo.hc; + var top:Number = childInfo.top; + var bottom:Number = childInfo.bottom; + var verticalCenter:Number = childInfo.vc; + var baseline:Number = childInfo.baseline; + + // Variables to track the boundaries from which + // the offsets are calculated from. If null, the + // boundary is the parent container edge. + var leftBoundary:String = childInfo.leftBoundary; + var rightBoundary:String = childInfo.rightBoundary; + var hcBoundary:String = childInfo.hcBoundary; + var topBoundary:String = childInfo.topBoundary; + var bottomBoundary:String = childInfo.bottomBoundary; + var vcBoundary:String = childInfo.vcBoundary; + var baselineBoundary:String = childInfo.baselineBoundary; + + var i:int; + var w:Number; + var h:Number; + + var x:Number; + var y:Number; + var message:String; + var checkWidth:Boolean = false; + var checkHeight:Boolean = false; + + // If we are to evaluate the left, right, and horizontalCenter + // styles relative to the parent boundaries, parentBoundariesLR will + // be true + var parentBoundariesLR:Boolean = (!hcBoundary && !leftBoundary && !rightBoundary); + // If we are to evaluate the top, bottom, verticalCenter and baseline + // styles relative to the parent boundaries, parentBoundariesTB will + // be true + var parentBoundariesTB:Boolean = (!vcBoundary && !topBoundary && !bottomBoundary && !baselineBoundary); + + var leftHolder:Number = 0; + var rightHolder:Number = availableWidth; + var topHolder:Number = 0; + var bottomHolder:Number = availableHeight; + var vcHolder:Number; + var hcHolder:Number; + var vcY:Number; + var hcX:Number; + var baselineY:Number; + // If we are not evaluating left, right, and horizontalCenter + // relative to the parent container edges, we need to match + // the column specified in the constraint expression with the + // actual ConstraintColumn instance so later we can determine how + // much space the control has to live in. + var length:int = IConstraintLayout(target).constraintColumns.length; + + if (!parentBoundariesLR && length > 0) + { + var matchLeft:Boolean = leftBoundary ? true : false; + var matchRight:Boolean = rightBoundary ? true : false; + var matchHC:Boolean = hcBoundary ? true : false; + + for (i = 0; i < length; i++) + { + var col:ConstraintColumn = ConstraintColumn(IConstraintLayout(target).constraintColumns[i]); + if (matchLeft) + { + if (leftBoundary == col.id) + { + leftHolder = col.x; + matchLeft = false; + } + } + if (matchRight) + { + if (rightBoundary == col.id) + { + rightHolder = col.x + col.width; + matchRight = false; + } + } + if (matchHC) + { + if (hcBoundary == col.id) + { + hcHolder = col.width; + hcX = col.x; + matchHC = false; + } + } + } + // Error throwing - we could not match one of the boundaries to the + // declared constraintColumns + if (matchLeft) + { + message = resourceManager.getString( + "containers", "columnNotFound", [ leftBoundary ]); + throw new ConstraintError(message); + } + if (matchRight) + { + message = resourceManager.getString( + "containers", "columnNotFound", [ rightBoundary ]); + throw new ConstraintError(message); + } + if (matchHC) + { + message = resourceManager.getString( + "containers", "columnNotFound", [ hcBoundary ]); + throw new ConstraintError(message); + } + } + else if (!parentBoundariesLR && length == 0) + { + // The left, right or horizontalCenter style has been set to + // a non-parent region, but no columns were declared + message = resourceManager.getString( + "containers", "noColumnsFound"); + throw new ConstraintError(message); + } + + // The width of the region which + // the control will live in. + availableWidth = Math.round(rightHolder - leftHolder); + + // If a percentage size is specified for a child, + // it specifies a percentage of the parent's content size + // minus any specified left, top, right, or bottom + // anchors for this child. + // Also, respect the child's minimum and maximum sizes. + if (!isNaN(left) && !isNaN(right)) + { + w = availableWidth - left - right; + if (w < child.minWidth) + w = child.minWidth; + } + else if (!isNaN(child.percentWidth)) + { + w = child.percentWidth / 100 * availableWidth; + w = bound(w, child.minWidth, child.maxWidth); + + checkWidth = true; + } + else + { + w = child.getExplicitOrMeasuredWidth(); + } + + // If we are not evaluating top, bottom, and verticalCenter + // relative to the parent container edges, we need to match + // the row specified in the constraint expression with the + // actual ConstraintRow instance so later we can determine how + // much space the control has to live in. + length = IConstraintLayout(target).constraintRows.length; + if (!parentBoundariesTB && length > 0) + { + var matchTop:Boolean = topBoundary ? true : false; + var matchBottom:Boolean = bottomBoundary ? true : false; + var matchVC:Boolean = vcBoundary ? true : false; + var matchBaseline:Boolean = baselineBoundary ? true : false; + length = IConstraintLayout(target).constraintRows.length; + for (i = 0; i < length; i++) + { + var row:ConstraintRow = ConstraintRow(IConstraintLayout(target).constraintRows[i]); + if (matchTop) + { + if (topBoundary == row.id) + { + topHolder = row.y; + matchTop = false; + } + } + if (matchBottom) + { + if (bottomBoundary == row.id) + { + bottomHolder = row.y + row.height; + matchBottom = false; + } + } + if (matchVC) + { + if (vcBoundary == row.id) + { + vcHolder = row.height; + vcY = row.y; + matchVC = false; + } + } + if (matchBaseline) + { + if (baselineBoundary == row.id) + { + baselineY = row.y; + matchBaseline = false; + } + } + } + // Error throwing - we could not match one of the boundaries to the + // declared constraintRows + if (matchTop) + { + message = resourceManager.getString( + "containers", "rowNotFound", [ topBoundary ]); + throw new ConstraintError(message); + } + if (matchBottom) + { + message = resourceManager.getString( + "containers", "rowNotFound", [ bottomBoundary ]); + throw new ConstraintError(message); + } + if (matchVC) + { + message = resourceManager.getString( + "containers", "rowNotFound", [ vcBoundary ]); + throw new ConstraintError(message); + } + if (matchBaseline) + { + message = resourceManager.getString( + "containers", "rowNotFound", [ baselineBoundary ]); + throw new ConstraintError(message); + } + } + else if (!parentBoundariesTB && length == 0) + { + // The top, bottom or verticalCenter style has been set to + // a non-parent region, but no rows were declared + message = resourceManager.getString( + "containers", "noRowsFound"); + throw new ConstraintError(message); + } + + // The height of the region which + // the control will live in. + availableHeight = Math.round(bottomHolder - topHolder); + if (!isNaN(top) && !isNaN(bottom)) + { + h = availableHeight - top - bottom; + if (h < child.minHeight) + h = child.minHeight; + } + else if (!isNaN(child.percentHeight)) + { + h = child.percentHeight / 100 * availableHeight; + h = bound(h, child.minHeight, child.maxHeight); + + checkHeight = true; + } + else + { + h = child.getExplicitOrMeasuredHeight(); + } + + // The left, right, and horizontalCenter styles + // affect the child's x and/or its actual width. + if (!isNaN(horizontalCenter)) + { + if (hcBoundary) + x = Math.round((hcHolder - w) / 2 + horizontalCenter + hcX); + else + x = Math.round((availableWidth - w) / 2 + horizontalCenter); + } + else if (!isNaN(left)) + { + if (leftBoundary) + x = leftHolder + left; + else + x = left; + } + else if (!isNaN(right)) + { + if (rightBoundary) + x = rightHolder - right - w; + else + x = availableWidth - right - w; + } + + // The top, bottom, verticalCenter and baseline styles + // affect the child's y and/or its actual height. + if (!isNaN(baseline)) + { + if (baselineBoundary) + { + //trace(child.name, child.baselinePosition); + y = (baselineY - child.baselinePosition) + baseline; + } + else + y = baseline; + } + if (!isNaN(verticalCenter)) + { + if (vcBoundary) + { + y = Math.round((vcHolder - h) / 2 + verticalCenter + vcY); + } + else + y = Math.round((availableHeight - h) / 2 + verticalCenter); + } + else if (!isNaN(top)) + { + if (topBoundary) + y = topHolder + top; + else + y = top; + } + else if (!isNaN(bottom)) + { + if (bottomBoundary) + y = bottomHolder - bottom - h; + else + y = availableHeight - bottom - h; + } + + x = isNaN(x) ? child.x : x; + y = isNaN(y) ? child.y : y; + + child.move(x, y); + + // One last test here. If the width/height is a percentage, + // limit the width/height to the available content width/height, + // but honor the minWidth/minHeight. + if (checkWidth) + { + if (x + w > availableWidth) + w = Math.max(availableWidth - x, child.minWidth); + } + + if (checkHeight) + { + if (y + h > availableHeight) + h = Math.max(availableHeight - y, child.minHeight); + } + + if (!isNaN(w) && !isNaN(h)) + child.setActualSize(w, h); + } + + /** + * @private + * This function measures the bounds of the content area. + * It looks at each child included in the layout, and determines + * right and bottom edge. + * + * When we are laying out the children, we use the larger of the + * content area and viewable area to determine percentages and + * the edges for constraints. + * + * If the child has a percentageWidth or both left and right values + * set, the minWidth is used for determining its area. Otherwise + * the explicit or measured width is used. The same rules apply in + * the vertical direction. + */ + private function measureContentArea():Rectangle + { + if (_contentArea) + return _contentArea; + var i:int; + _contentArea = new Rectangle(); + var n:int = target.numChildren; + + //Special case where there are no children but there + //are columns or rows + if (n == 0 && constraintRegionsInUse) + { + var cols:Array = IConstraintLayout(target).constraintColumns; + var rows:Array = IConstraintLayout(target).constraintRows; + //The right of the contentArea rectangle is the x position of the last + //column plus its width. If there are no columns, its 0. + if (cols.length > 0) + _contentArea.right = cols[cols.length-1].x + cols[cols.length-1].width; + else + _contentArea.right = 0; + //The bottom of the contentArea rectangle is the y position of the last row + //plus its height. If there are no rows, its 0; + if (rows.length > 0) + _contentArea.bottom = rows[rows.length-1].y + rows[rows.length-1].height; + else _contentArea.bottom = 0; + } + + for (i = 0; i < n; i++) + { + var child:IUIComponent = target.getLayoutChildAt(i); + var childConstraints:LayoutConstraints = getLayoutConstraints(child); + + if (!child.includeInLayout) + continue; + + var cx:Number = child.x; + var cy:Number = child.y; + var pw:Number = child.getExplicitOrMeasuredWidth(); + var ph:Number = child.getExplicitOrMeasuredHeight(); + + if (!isNaN(child.percentWidth) || + (childConstraints && + !isNaN(childConstraints.left) && + !isNaN(childConstraints.right) && + isNaN(child.explicitWidth))) + { + pw = child.minWidth; + } + + if (!isNaN(child.percentHeight) || + (childConstraints && + !isNaN(childConstraints.top) && + !isNaN(childConstraints.bottom) && + isNaN(child.explicitHeight))) + { + ph = child.minHeight; + } + + r.x = cx + r.y = cy + r.width = pw; + r.height = ph; + applyAnchorStylesDuringMeasure(child, r); + cx = r.x; + cy = r.y; + pw = r.width; + ph = r.height; + + if (isNaN(cx)) + cx = child.x; + if (isNaN(cy)) + cy = child.y; + + var rightEdge:Number = cx; + var bottomEdge:Number = cy; + + if (isNaN(pw)) + pw = child.width; + + if (isNaN(ph)) + ph = child.height; + + rightEdge += pw; + bottomEdge += ph; + + _contentArea.right = Math.max(_contentArea.right, rightEdge); + _contentArea.bottom = Math.max(_contentArea.bottom, bottomEdge); + } + return _contentArea; + } + + /** + * @private + */ + private function parseConstraints(child:IUIComponent = null):ChildConstraintInfo + { + var constraints:LayoutConstraints = getLayoutConstraints(child); + if (!constraints) + return null; + //Variables to track the offsets + var left:Number; + var right:Number; + var horizontalCenter:Number; + var top:Number; + var bottom:Number; + var verticalCenter:Number; + var baseline:Number; + + //Variables to track the boundaries from which + //the offsets are calculated from. If null, the + //boundary is the parent container edge. + var leftBoundary:String; + var rightBoundary:String; + var hcBoundary:String; + var topBoundary:String; + var bottomBoundary:String; + var vcBoundary:String; + var baselineBoundary:String; + + //Evaluate the constraint expression and store the offsets + //and boundaries. + var temp:Array; + while (true) + { + temp = parseConstraintExp(constraints.left); + if (!temp) + left = NaN; + else if (temp.length == 1) + left = Number(temp[0]); + else + { + leftBoundary = temp[0]; + left = temp[1]; + } + + temp = parseConstraintExp(constraints.right); + if (!temp) + right = NaN; + else if (temp.length == 1) + right = Number(temp[0]); + else + { + rightBoundary = temp[0]; + right = temp[1]; + } + + temp = parseConstraintExp(constraints.horizontalCenter); + if (!temp) + horizontalCenter = NaN; + else if (temp.length == 1) + horizontalCenter = Number(temp[0]); + else + { + hcBoundary = temp[0]; + horizontalCenter = temp[1]; + } + + temp = parseConstraintExp(constraints.top); + if (!temp) + top = NaN; + else if (temp.length == 1) + top = Number(temp[0]); + else + { + topBoundary = temp[0]; + top = temp[1]; + } + + temp = parseConstraintExp(constraints.bottom); + if (!temp) + bottom = NaN; + else if (temp.length == 1) + bottom = Number(temp[0]); + else + { + bottomBoundary = temp[0]; + bottom = temp[1]; + } + + temp = parseConstraintExp(constraints.verticalCenter); + if (!temp) + verticalCenter = NaN; + else if (temp.length == 1) + verticalCenter = Number(temp[0]); + else + { + vcBoundary = temp[0]; + verticalCenter = temp[1]; + } + temp = parseConstraintExp(constraints.baseline); + if (!temp) + baseline = NaN; + else if (temp.length == 1) + baseline = Number(temp[0]); + else + { + baselineBoundary = temp[0]; + baseline = temp[1]; + } + + break; + } + + //Store entries for the children who span columns/rows in + //the colSpanChildren and rowSpanChildren arrays. + var i:int; + var colEntry:ContentColumnChild = new ContentColumnChild(); + var pushEntry:Boolean = false; + var leftIndex:Number = 0; + var rightIndex:Number = 0; + var hcIndex:Number = 0; + + for (i = 0; i < IConstraintLayout(target).constraintColumns.length; i++) + { + var col:ConstraintColumn = IConstraintLayout(target).constraintColumns[i]; + if (col.contentSize) + { + if (col.id == leftBoundary) + { + colEntry.leftCol = col; + colEntry.leftOffset = left; + colEntry.left = leftIndex = i; + pushEntry = true; + } + if (col.id == rightBoundary) + { + colEntry.rightCol = col; + colEntry.rightOffset = right; + colEntry.right = rightIndex = i + 1; + pushEntry = true; + } + if (col.id == hcBoundary) + { + colEntry.hcCol = col; + colEntry.hcOffset = horizontalCenter; + colEntry.hc = hcIndex = i + 1; + pushEntry = true; + } + } + } + + //Figure out the bounding columns, + //span value and the child spanning and push that + //information onto colSpanChildren for evaluation + //when measuring content sized columns + if (pushEntry) + { + colEntry.child = child; + if (colEntry.leftCol && !colEntry.rightCol || + colEntry.rightCol && !colEntry.leftCol || + colEntry.hcCol) + { + colEntry.span = 1; + } + else + colEntry.span = rightIndex - leftIndex; + + //push the entry if it's not there already + var found:Boolean = false; + for (i = 0; i < colSpanChildren.length; i++) + { + if (colEntry.child == colSpanChildren[i].child) + { + found = true; + break; + } + } + + if (!found) + colSpanChildren.push(colEntry); + } + pushEntry = false; + + var rowEntry:ContentRowChild = new ContentRowChild(); + var topIndex:Number = 0; + var bottomIndex:Number = 0; + var vcIndex:Number = 0; + var baselineIndex:Number = 0; + for (i = 0; i < IConstraintLayout(target).constraintRows.length; i++) + { + var row:ConstraintRow = IConstraintLayout(target).constraintRows[i]; + if (row.contentSize) + { + if (row.id == topBoundary) + { + rowEntry.topRow = row; + rowEntry.topOffset = top; + rowEntry.top = topIndex = i; + pushEntry = true; + } + if (row.id == bottomBoundary) + { + rowEntry.bottomRow = row; + rowEntry.bottomOffset = bottom; + rowEntry.bottom = bottomIndex = i + 1; + pushEntry = true; + } + if (row.id == vcBoundary) + { + rowEntry.vcRow = row; + rowEntry.vcOffset = verticalCenter; + rowEntry.vc = vcIndex = i + 1; + pushEntry = true; + } + if (row.id == baselineBoundary) + { + rowEntry.baselineRow = row; + rowEntry.baselineOffset = baseline; + rowEntry.baseline = baselineIndex = i + 1; + pushEntry = true; + } + } + } + //Figure out the bounding rows, + //span value and the child spanning and push that + //information onto rowSpanChildren for evaluation + //when measuring content sized rows + if (pushEntry) + { + rowEntry.child = child; + if (rowEntry.topRow && !rowEntry.bottomRow || + rowEntry.bottomRow && !rowEntry.topRow || + rowEntry.vcRow || rowEntry.baselineRow) + { + rowEntry.span = 1; + } + else + rowEntry.span = bottomIndex - topIndex; + + //push the entry if it's not there already + found = false; + for (i = 0; i < rowSpanChildren.length; i++) + { + if (rowEntry.child == rowSpanChildren[i].child) + { + found = true; + break; + } + } + + if (!found) + rowSpanChildren.push(rowEntry); + } + //Cache constraint styles for future lookup + var info:ChildConstraintInfo = new ChildConstraintInfo(left, right, horizontalCenter, + top, bottom, verticalCenter, baseline, leftBoundary, + rightBoundary, hcBoundary, topBoundary, bottomBoundary, + vcBoundary, baselineBoundary); + COMPILE::LATER + { + constraintCache[child] = info; + } + return info; + } + + /** + * @private + * This function measures the ConstraintColumns and + * and ConstraintRows partitioning a Canvas and sets + * up their x/y positions. + * + * The algorithm works like this (in the horizontal + * direction): + * 1. Fixed columns honor their pixel values. + * + * 2. Content sized columns whose children span + * only that column assume the width of the widest child. + * + * 3. Those Content sized columns that span multiple + * columns do the following: + * a. Sort the children by order of how many columns they + * are spanning. + * b. For children spanning a single column, make each + * column as wide as the preferred size of the child. + * c. For subsequent children, divide the remainder space + * equally between shared columns. + * + * 4. Remaining space is shared between the percentage size + * columns. + * + * 5. x positions are set based on the column widths + * + */ + private function measureColumnsAndRows():void + { + var cols:Array = IConstraintLayout(target).constraintColumns; + var rows:Array = IConstraintLayout(target).constraintRows; + if (!rows.length > 0 && !cols.length > 0) + { + constraintRegionsInUse = false; + return; + } + else + constraintRegionsInUse = true; + var i:int; + var k:int; + var canvasX:Number = 0; + var canvasY:Number = 0; + var vm:EdgeMetrics = Container(target).viewMetrics; + var availableWidth:Number = Container(target).width - vm.left - vm.right; + var availableHeight:Number = Container(target).height - vm.top - vm.bottom; + var fixedSize:Array = []; + var percentageSize:Array = []; + var contentSize:Array = []; + var cc:ConstraintColumn; + var cr:ConstraintRow; + var spaceToDistribute:Number; + var w:Number; + var h:Number; + var remainingSpace:Number; + + if (cols.length > 0) + { + for (i = 0; i < cols.length; i++) + { + cc = cols[i]; + if (!isNaN(cc.percentWidth)) + percentageSize.push(cc); + else if (!isNaN(cc.width) && !cc.contentSize) + fixedSize.push(cc); + else + { + contentSize.push(cc); + cc.contentSize = true; + } + } + //fixed size columns + for (i = 0; i < fixedSize.length; i++) + { + cc = ConstraintColumn(fixedSize[i]); + availableWidth = availableWidth - cc.width; + } + //content size columns + if (contentSize.length > 0) + { + //first we figure allocate space to those columns + //with children spanning them + if (colSpanChildren.length > 0) + { + colSpanChildren.sortOn("span"); + for (k = 0; k < colSpanChildren.length; k++) + { + var colEntry:ContentColumnChild = colSpanChildren[k]; + //For those children that span 1 column, give that column + //the max preferred width of the child; + if (colEntry.span == 1) + { + //Match the columns + if (colEntry.hcCol) + cc = ConstraintColumn(cols[cols.indexOf(colEntry.hcCol)]); + else if (colEntry.leftCol) + cc = ConstraintColumn(cols[cols.indexOf(colEntry.leftCol)]); + else if (colEntry.rightCol) + cc = ConstraintColumn(cols[cols.indexOf(colEntry.rightCol)]); + //Use preferred size if left and right are specified + w = colEntry.child.getExplicitOrMeasuredWidth(); + //Now we add in offsets + if (colEntry.hcOffset) + w += colEntry.hcOffset; + else + { + if (colEntry.leftOffset) + w += colEntry.leftOffset; + if (colEntry.rightOffset) + w += colEntry.rightOffset; + } + //width may have been set by a previous pass - so we want to take the max + if (!isNaN(cc.width)) + w = Math.max(cc.width, w); + w = bound(w, cc.minWidth, cc.maxWidth); + cc.setActualWidth(w); + availableWidth -= cc.width; + } + //otherwise we share space amongst the spanned columns + else + { + availableWidth = shareColumnSpace(colEntry, availableWidth); + } + } + //reset + colSpanChildren = []; + } + //now for those content size columns that don't have widths + //give them their minWidth or 0. + for (i = 0; i < contentSize.length; i++) + { + cc = contentSize[i]; + if (!cc.width) + { + w = bound(0, cc.minWidth, 0); + cc.setActualWidth(w); + } + } + } + //percentage size columns + remainingSpace = availableWidth; + for (i = 0; i < percentageSize.length; i++) + { + cc = ConstraintColumn(percentageSize[i]); + if (remainingSpace <= 0) + w = 0; + else + w = Math.round((remainingSpace * cc.percentWidth)/100); + w = bound(w, cc.minWidth, cc.maxWidth); + cc.setActualWidth(w); + availableWidth -= w; + } + + //In the order they were declared, set up the x positions + for (i = 0; i < cols.length; i++) + { + cc = ConstraintColumn(cols[i]); + cc.x = canvasX; + canvasX += cc.width; + } + } + + fixedSize = []; + percentageSize = []; + contentSize = []; + if (rows.length > 0) + { + for (i = 0; i < rows.length; i++) + { + cr = rows[i]; + if (!isNaN(cr.percentHeight)) + { + percentageSize.push(cr); + } + else if (!isNaN(cr.height) && !cr.contentSize) + fixedSize.push(cr); + else + { + contentSize.push(cr); + cr.contentSize = true; + } + } + //fixed size rows + for (i = 0; i < fixedSize.length; i++) + { + cr = ConstraintRow(fixedSize[i]); + availableHeight = availableHeight - cr.height; + } + //content size rows + if (contentSize.length > 0) + { + //first we figure allocate space to those rows + //with children spanning them + if (rowSpanChildren.length > 0) + { + rowSpanChildren.sortOn("span"); + for (k = 0; k < rowSpanChildren.length; k++) + { + var rowEntry:ContentRowChild = rowSpanChildren[k]; + //For those children that span 1 row, give that row + //the max preferred height of the child; + if (rowEntry.span == 1) + { + //Match the rows + if (rowEntry.vcRow) + cr = ConstraintRow(rows[rows.indexOf(rowEntry.vcRow)]); + else if (rowEntry.baselineRow) + cr = ConstraintRow(rows[rows.indexOf(rowEntry.baselineRow)]); + else if (rowEntry.topRow) + cr = ConstraintRow(rows[rows.indexOf(rowEntry.topRow)]); + else if (rowEntry.bottomRow) + cr = ConstraintRow(rows[rows.indexOf(rowEntry.bottomRow)]); + //Use preferred size if both top and bottom are specified + h = rowEntry.child.getExplicitOrMeasuredHeight(); + //Now we add in offsets + if (rowEntry.baselineOffset) + h += rowEntry.baselineOffset; + else if (rowEntry.vcOffset) + h += rowEntry.vcOffset; + else + { + if (rowEntry.topOffset) + h += rowEntry.topOffset; + if (rowEntry.bottomOffset) + h += rowEntry.bottomOffset; + } + //height may have been set by a previous pass - so we want to take the max + if (!isNaN(cr.height)) + h = Math.max(cr.height, h); + h = bound(h, cr.minHeight, cr.maxHeight); + cr.setActualHeight(h); + availableHeight -= cr.height; + } + //otherwise we share space amongst the spanned rows + else + { + availableHeight = shareRowSpace(rowEntry, availableHeight); + } + } + //reset + rowSpanChildren = []; + } + //now for those content size rows that don't have heights + //give them their minHeight or 0. + for (i = 0; i < contentSize.length; i++) + { + cr = ConstraintRow(contentSize[i]); + if (!cr.height) + { + h = bound(0, cr.minHeight, 0); + cr.setActualHeight(h); + } + } + } + //percentage size rows + remainingSpace = availableHeight; + for (i = 0; i < percentageSize.length; i++) + { + cr = ConstraintRow(percentageSize[i]); + if (remainingSpace <= 0) + h = 0; + else + h = Math.round((remainingSpace * cr.percentHeight)/100); + h = bound(h, cr.minHeight, cr.maxHeight); + cr.setActualHeight(h); + availableHeight -= h; + } + //In the order they were declared, set up the y positions + for (i = 0; i < rows.length; i++) + { + cr = rows[i]; + cr.y = canvasY; + canvasY += cr.height; + } + } + } + + /** + * @private + * Shares available space between content-size columns that have content + * spanning them. + */ + private function shareColumnSpace(entry:ContentColumnChild, availableWidth:Number):Number + { + var leftCol:ConstraintColumn = entry.leftCol; + var rightCol:ConstraintColumn = entry.rightCol; + var child:IUIComponent = entry.child; + var leftWidth:Number = 0; + var rightWidth:Number = 0; + var right:Number = entry.rightOffset ? entry.rightOffset : 0; + var left:Number = entry.leftOffset ? entry.leftOffset : 0; + + if (leftCol && leftCol.width) + leftWidth += leftCol.width; + else if (rightCol && !leftCol) + { + leftCol = IConstraintLayout(target).constraintColumns[entry.right - 2]; + if (leftCol && leftCol.width) + leftWidth += leftCol.width; + } + if (rightCol && rightCol.width) + rightWidth += rightCol.width; + else if (leftCol && !rightCol) + { + rightCol = IConstraintLayout(target).constraintColumns[entry.left + 1]; + if (rightCol && rightCol.width) + rightWidth += rightCol.width; + } + + if (leftCol && isNaN(leftCol.width)) + { + leftCol.setActualWidth(Math.max(0, leftCol.maxWidth)); + } + if (rightCol && isNaN(rightCol.width)) + { + rightCol.setActualWidth(Math.max(0, rightCol.maxWidth)); + } + + var childWidth:Number = child.getExplicitOrMeasuredWidth(); + if (childWidth) + { + var tempLeftWidth:Number; + var tempRightWidth:Number; + if (!entry.leftCol) + { + if (childWidth > leftWidth) + tempRightWidth = childWidth - leftWidth + right; + else + tempRightWidth = childWidth + right; + } + if (!entry.rightCol) + { + if (childWidth > rightWidth) + tempLeftWidth = childWidth - rightWidth + left; + else + tempLeftWidth = childWidth + left; + } + if (entry.leftCol && entry.rightCol) + { + var share:Number = childWidth/Number(entry.span); + if ((share + left) < leftWidth) + { + tempLeftWidth = leftWidth; + tempRightWidth = (childWidth - (leftWidth - left)) + right; + } + else + tempLeftWidth = share + left; + if ((share + right) < rightWidth) + { + tempRightWidth = rightWidth; + tempLeftWidth = (childWidth - (rightWidth - right)) + left; + } + else + tempRightWidth = share + right; + } + //set the left + tempLeftWidth = bound(tempLeftWidth, leftCol.minWidth, leftCol.maxWidth); + leftCol.setActualWidth(tempLeftWidth); + availableWidth -= tempLeftWidth; + //set the right + tempRightWidth = bound(tempRightWidth, rightCol.minWidth, rightCol.maxWidth); + rightCol.setActualWidth(tempRightWidth); + availableWidth -= tempRightWidth; + } + return availableWidth; + } + + /** + * @private + * Shares available space between content-size rows that have content + * spanning them. + */ + private function shareRowSpace(entry:ContentRowChild, availableHeight:Number):Number + { + var topRow:ConstraintRow = entry.topRow; + var bottomRow:ConstraintRow = entry.bottomRow; + var child:IUIComponent = entry.child; + var topHeight:Number = 0; + var bottomHeight:Number = 0; + var top:Number = entry.topOffset ? entry.topOffset : 0; + var bottom:Number = entry.bottomOffset ? entry.bottomOffset : 0; + + if (topRow && topRow.height) + topHeight += topRow.height; + else if (bottomRow && !topRow) + { + topRow = IConstraintLayout(target).constraintRows[entry.bottom - 2]; + if (topRow && topRow.height) + topHeight += topRow.height; + } + if (bottomRow && bottomRow.height) + bottomHeight += bottomRow.height; + else if (topRow && !bottomRow) + { + bottomRow = IConstraintLayout(target).constraintRows[entry.top + 1]; + if (bottomRow && bottomRow.height) + bottomHeight += bottomRow.height; + } + if (topRow && isNaN(topRow.height)) + { + topRow.setActualHeight(Math.max(0, topRow.maxHeight)); + } + if (bottomRow && isNaN(bottomRow.height)) + { + bottomRow.setActualHeight(Math.max(0, bottomRow.height)); + } + + var childHeight:Number = child.getExplicitOrMeasuredHeight(); + if (childHeight) + { + var tempTopHeight:Number; + var tempBtmHeight:Number; + if (!entry.topRow) + { + if (childHeight > topHeight) + tempBtmHeight = childHeight - topHeight + bottom; + else + tempBtmHeight = childHeight + bottom; + } + if (!entry.bottomRow) + { + if (childHeight > bottomHeight) + tempTopHeight = childHeight - bottomHeight + top; + else + tempTopHeight = childHeight + top; + } + if (entry.topRow && entry.bottomRow) + { + var share:Number = childHeight/Number(entry.span); + if ((share + top) < topHeight) + { + tempTopHeight = topHeight; + tempBtmHeight = (childHeight - (topHeight - top)) + bottom; + } + else + tempTopHeight = share + top; + if ((share + bottom) < bottomHeight) + { + tempBtmHeight = bottomHeight; + tempTopHeight = (childHeight - (bottomHeight - bottom)) + top; + } + else + tempBtmHeight = share + bottom; + } + //set the bottom + tempBtmHeight = bound(tempBtmHeight, bottomRow.minHeight, bottomRow.maxHeight); + bottomRow.setActualHeight(tempBtmHeight); + availableHeight -= tempBtmHeight; + //set the top + tempTopHeight = bound(tempTopHeight, topRow.minHeight, topRow.maxHeight); + topRow.setActualHeight(tempTopHeight); + availableHeight -= tempTopHeight; + } + return availableHeight; + } + + /** + * @private + * Collect all the layout constraints for this child and package + * into a LayoutConstraints object. + * Returns null if the child is not an IConstraintClient. + */ + private function getLayoutConstraints(child:IUIComponent):LayoutConstraints + { + var constraintChild:IConstraintClient = child as IConstraintClient; + + if (!constraintChild) + return null; + + var constraints:LayoutConstraints = new LayoutConstraints(); + + constraints.baseline = constraintChild.getConstraintValue("baseline"); + constraints.bottom = constraintChild.getConstraintValue("bottom"); + constraints.horizontalCenter = constraintChild.getConstraintValue("horizontalCenter"); + constraints.left = constraintChild.getConstraintValue("left"); + constraints.right = constraintChild.getConstraintValue("right"); + constraints.top = constraintChild.getConstraintValue("top"); + constraints.verticalCenter = constraintChild.getConstraintValue("verticalCenter"); + + return constraints; + } + + /** + * @private + * Parses a constraint expression, like left="col1:10" + * so that an array is returned where the first value is + * the boundary (ie: "col1") and the second value is + * the offset (ie: 10) + */ + private function parseConstraintExp(val:String):Array + { + if (!val) + return null; + // Replace colons with spaces + var temp:String = val.replace(/:/g, " "); + + // Split the string into an array + var args:Array = temp.split(/\s+/); + return args; + } + + //-------------------------------------------------------------------------- + // + // Event handlers + // + //-------------------------------------------------------------------------- + + /** + * @private + * If a child has been added, listen for its move event. + */ + private function target_childAddHandler( + event:ChildExistenceChangedEvent):void + { + DisplayObject(event.relatedObject).addEventListener( + MoveEvent.MOVE, child_moveHandler); + } + + /** + * @private + * If a child has been removed, stop listening for its move event. + */ + private function target_childRemoveHandler( + event:ChildExistenceChangedEvent):void + { + DisplayObject(event.relatedObject).removeEventListener( + MoveEvent.MOVE, child_moveHandler); + + COMPILE::LATER + { + //delete this child from the constraint cache if it exists + delete constraintCache[event.relatedObject]; + } + } + + /** + * @private + * If a child's position has changed, then the measured preferred + * size of this canvas may have changed. + */ + private function child_moveHandler(event:MoveEvent):void + { + if (event.target is IUIComponent) + if (!(IUIComponent(event.target).includeInLayout)) + return; + + var target:Container = super.target; + if (target) + { + target.invalidateSize(); + target.invalidateDisplayList(); + _contentArea = null; + } + } +} +} + +import mx.containers.utilityClasses.ConstraintColumn; +import mx.core.IUIComponent; +import mx.containers.utilityClasses.ConstraintRow; + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: ChildConstraintInfo +// +//////////////////////////////////////////////////////////////////////////////// + +class ChildConstraintInfo +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + public function ChildConstraintInfo( + left:Number, right:Number, hc:Number, + top:Number, bottom:Number, vc:Number, + baseline:Number, leftBoundary:String = null, + rightBoundary:String = null, hcBoundary:String = null, + topBoundary:String = null, bottomBoundary:String = null, + vcBoundary:String = null, baselineBoundary:String = null):void + { + super(); + + // offsets + this.left = left; + this.right = right; + this.hc = hc; + this.top = top; + this.bottom = bottom; + this.vc = vc; + this.baseline = baseline; + + // boundaries (ie: parent, column or row edge) + this.leftBoundary = leftBoundary; + this.rightBoundary = rightBoundary; + this.hcBoundary = hcBoundary; + this.topBoundary = topBoundary; + this.bottomBoundary = bottomBoundary; + this.vcBoundary = vcBoundary; + this.baselineBoundary = baselineBoundary; + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + public var left:Number; + public var right:Number; + public var hc:Number; + public var top:Number; + public var bottom:Number; + public var vc:Number; + public var baseline:Number; + public var leftBoundary:String; + public var rightBoundary:String; + public var hcBoundary:String; + public var topBoundary:String; + public var bottomBoundary:String; + public var vcBoundary:String; + public var baselineBoundary:String; + +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: ContentColumnChild +// +//////////////////////////////////////////////////////////////////////////////// + +class ContentColumnChild +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + public function ContentColumnChild():void + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + public var leftCol:ConstraintColumn; + public var leftOffset:Number; + public var left:Number; + public var rightCol:ConstraintColumn; + public var rightOffset:Number; + public var right:Number; + public var hcCol:ConstraintColumn; + public var hcOffset:Number; + public var hc:Number; + public var child:IUIComponent; + public var span:Number; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: ContentRowChild +// +//////////////////////////////////////////////////////////////////////////////// + +class ContentRowChild +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + public function ContentRowChild():void + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + public var topRow:ConstraintRow; + public var topOffset:Number; + public var top:Number; + public var bottomRow:ConstraintRow; + public var bottomOffset:Number; + public var bottom:Number; + public var vcRow:ConstraintRow; + public var vcOffset:Number; + public var vc:Number; + public var baselineRow:ConstraintRow; + public var baselineOffset:Number; + public var baseline:Number; + public var child:IUIComponent; + public var span:Number; + +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Helper class: LayoutConstraints +// +//////////////////////////////////////////////////////////////////////////////// + +class LayoutConstraints +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + public function LayoutConstraints():void + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + public var baseline:*; + public var bottom:*; + public var horizontalCenter:*; + public var left:*; + public var right:*; + public var top:*; + public var verticalCenter:*; +}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/ConstraintColumn.as ---------------------------------------------------------------------- diff --cc frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/ConstraintColumn.as index 0ffaf26,0000000..b0229b4 mode 100644,000000..100644 --- a/frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/ConstraintColumn.as +++ b/frameworks/projects/MX/src/main/flex/mx/containers/utilityClasses/ConstraintColumn.as @@@ -1,471 -1,0 +1,471 @@@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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.utilityClasses +{ + - COMPILE::AS3 ++COMPILE::SWF +{ +import flash.events.Event; +import flash.events.EventDispatcher; +} +COMPILE::JS +{ +import org.apache.flex.events.Event; +import org.apache.flex.events.EventDispatcher; +} +import mx.core.IInvalidating; +import mx.core.mx_internal; +import mx.core.IMXMLObject; + +use namespace mx_internal; + +//-------------------------------------- +// Excluded APIs +//-------------------------------------- +[Exclude(name="container", kind="property")] + +/** + * The ConstraintColumn class partitions an absolutely + * positioned container in the vertical plane. + * + * ConstraintColumn instances have 3 sizing options: fixed, percentage, and + * content. These options dictate the position of the + * constraint column, the amount of space the constraint column + * takes in the container, and how the constraint column deals with + * changes in the size of the container. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class ConstraintColumn extends EventDispatcher implements IMXMLObject +{ + include "../../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function ConstraintColumn() + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + mx_internal var contentSize:Boolean = false; + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // container + //---------------------------------- + /** + * @private + */ + private var _container:IInvalidating; + + /** + * The container which this ConstraintColumn instance is + * partitioning. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get container():IInvalidating + { + return _container; + } + + /** + * @private + */ + public function set container(value:IInvalidating):void + { + _container = value; + } + + //---------------------------------- + // id + //---------------------------------- + /** + * @private + */ + private var _id:String; + + /** + * ID of the ConstraintColumn instance. This value becomes the instance name of the + * ConstraintColumn instance and should not contain white space or special characters. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get id():String + { + return _id; + } + + /** + * @private + */ + public function set id(value:String):void + { + _id = value; + } + + //---------------------------------- + // maxWidth + //---------------------------------- + /** + * @private + * Storage for the maxWidth property. + */ + private var _explicitMaxWidth:Number; + [Bindable("maxWidthChanged")] + [Inspectable(category="Size", defaultValue="10000")] + + /** + * Number that specifies the maximum width of the ConstraintColumn + * instance, in pixels, in the ConstraintColumn instance's coordinates. + * + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get maxWidth():Number + { + // Since ConstraintColumn doesn't have a measuredMaxWidth, we explictly return + // the default value of 10000 when no maxWidth is set. + return (!isNaN(_explicitMaxWidth)) ? _explicitMaxWidth : 10000; + } + + /** + * @private + */ + public function set maxWidth(value:Number):void + { + if (_explicitMaxWidth != value) + { + _explicitMaxWidth = value; + if (container) + { + container.invalidateSize(); + container.invalidateDisplayList(); + } + dispatchEvent(new Event("maxWidthChanged")); + } + } + + //---------------------------------- + // minWidth + //---------------------------------- + /** + * @private + * Storage for the minWidth property. + */ + private var _explicitMinWidth:Number; + [Bindable("minWidthChanged")] + [Inspectable(category="Size", defaultValue="0")] + + /** + * Number that specifies the minimum width of the ConstraintColumn instance, + * in pixels, in the ConstraintColumn instance's coordinates. + * + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get minWidth():Number + { + // Since ConstraintColumn doesn't have a measuredMinWidth, we explictly return + // the default value of 0 when no minWidth is set. + return (!isNaN(_explicitMinWidth)) ? _explicitMinWidth : 0; + } + + /** + * @private + */ + public function set minWidth(value:Number):void + { + if (_explicitMinWidth != value) + { + _explicitMinWidth = value; + if (container) + { + container.invalidateSize(); + container.invalidateDisplayList(); + } + dispatchEvent(new Event("minWidthChanged")); + } + } + + //---------------------------------- + // width + //---------------------------------- + /** + * @private + * Storage for the width property. + */ + mx_internal var _width:Number; + [Bindable("widthChanged")] + [Inspectable(category="General")] + [PercentProxy("percentWidth")] + + /** + * Number that specifies the width of the ConstraintColumn instance, in pixels, + * in the parent container's coordinates. + * + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get width():Number + { + return _width; + } + + /** + * @private + */ + public function set width(value:Number):void + { + if (explicitWidth != value) + { + explicitWidth = value; + if (_width != value) + { + _width = value; + if (!isNaN(_width)) + contentSize = false; + if (container) + { + container.invalidateSize(); + container.invalidateDisplayList(); + } + dispatchEvent(new Event("widthChanged")); + } + } + } + + //---------------------------------- + // explicitWidth + //---------------------------------- + /** + * @private + * Storage for the explicitWidth property. + */ + + private var _explicitWidth:Number; + [Inspectable(environment="none")] + [Bindable("explicitWidthChanged")] + + /** + * Number that specifies the explicit width of the ConstraintColumn instance, + * in pixels, in the ConstraintColumn instance's coordinates. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get explicitWidth():Number + { + return _explicitWidth; + } + + /** + * @private + */ + public function set explicitWidth(value:Number):void + { + if (_explicitWidth == value) + return; + + // width can be pixel or percent not both + if (!isNaN(value)) + _percentWidth = NaN; + + _explicitWidth = value; + + if (container) + { + container.invalidateSize(); + container.invalidateDisplayList(); + } + + dispatchEvent(new Event("explicitWidthChanged")); + } + + //---------------------------------- + // percentWidth + //---------------------------------- + /** + * @private + * Storage for the percentWidth property. + */ + private var _percentWidth:Number; + [Bindable("percentWidthChanged")] + [Inspectable(environment="none")] + + /** + * Number that specifies the width of a component as a percentage of its + * parent container's size. Allowed values are 0-100. The default value is NaN. + * Setting the <code>width</code> property resets this property to NaN. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get percentWidth():Number + { + return _percentWidth; + } + + /** + * @private + */ + public function set percentWidth(value:Number):void + { + if (_percentWidth == value) + return; + + if (!isNaN(value)) + _explicitWidth = NaN; + + _percentWidth = value; + if (!isNaN(_percentWidth)) + contentSize = false; + + if (container) + { + container.invalidateSize(); + container.invalidateDisplayList(); + } + + dispatchEvent(new Event("percentWidthChanged")); + } + + //---------------------------------- + // x + //---------------------------------- + private var _x:Number; + [Bindable("xChanged")] + + /** + * @private + */ + public function get x():Number + { + return _x; + } + + /** + * @private + */ + public function set x(value:Number):void + { + if (value != _x) + { + _x = value; + dispatchEvent(new Event("xChanged")); + } + } + + //-------------------------------------------------------------------------- + // + // Methods: IMXMLObject + // + //-------------------------------------------------------------------------- + + /** + * Called automatically by the MXML compiler when the ConstraintColumn + * instance is created using an MXML tag. + * If you create the ConstraintColumn instance through ActionScript, you + * must call this method passing in the MXML document and + * <code>null</code> for the <code>id</code>. + * + * @param document The MXML document containing this ConstraintColumn. + * + * @param id Ignored. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function initialized(document:Object, id:String):void + { + this.id = id; + if (!this.width && !this.percentWidth) + contentSize = true; + } + + /** + * Sizes the constraint column. + * + * @param width Width of constaint column computed during parent container + * processing. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function setActualWidth(w:Number):void + { + if (_width != w) + { + _width = w; + dispatchEvent(new Event("widthChanged")); + } + } + +} + +}
