This is an automated email from the ASF dual-hosted git repository. aharui pushed a commit to branch feature/MXRoyale in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
commit 78d84b66d350bc92d881107202bd5c2455bec4bf Author: Alex Harui <[email protected]> AuthorDate: Mon Aug 13 11:48:24 2018 -0700 get GroupBase and Spark Image working --- .../SparkRoyale/src/main/resources/defaults.css | 12 + .../src/main/royale/SparkRoyaleClasses.as | 2 + .../src/main/royale/spark/components/Image.as | 70 ++- .../spark/components/supportClasses/GroupBase.as | 182 ++++++- .../src/main/royale/spark/layouts/BasicLayout.as | 551 +++++++++++++++++++++ .../layouts/supportClasses/SparkLayoutBead.as | 122 +++++ 6 files changed, 912 insertions(+), 27 deletions(-) diff --git a/frameworks/projects/SparkRoyale/src/main/resources/defaults.css b/frameworks/projects/SparkRoyale/src/main/resources/defaults.css index afeed51..aa26fed 100644 --- a/frameworks/projects/SparkRoyale/src/main/resources/defaults.css +++ b/frameworks/projects/SparkRoyale/src/main/resources/defaults.css @@ -52,6 +52,18 @@ ComboBox IPopUp: ClassReference("org.apache.royale.html.supportClasses.ComboBoxList"); } +GroupBase +{ + IBeadLayout: ClassReference("spark.layouts.supportClasses.SparkLayoutBead"); + IBeadView: ClassReference("org.apache.royale.html.beads.GroupView"); +} + +Image +{ + IBeadModel: ClassReference("org.apache.royale.html.beads.models.ImageModel"); + IBeadView: ClassReference("org.apache.royale.html.beads.ImageView"); +} + List { diff --git a/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as b/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as index d3c22b4..e34eec7 100644 --- a/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as +++ b/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as @@ -37,6 +37,8 @@ internal class SparkRoyaleClasses import spark.skins.spark.ComboBoxButtonSkin; ComboBoxButtonSkin; import spark.skins.spark.ComboBoxTextInputSkin; ComboBoxTextInputSkin; + import spark.layouts.supportClasses.SparkLayoutBead; SparkLayoutBead; + } } diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Image.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Image.as index 74d5a38..c914bc6 100644 --- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Image.as +++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/Image.as @@ -38,6 +38,15 @@ import spark.components.supportClasses.Range; import spark.components.supportClasses.SkinnableComponent; import spark.primitives.BitmapImage; +import org.apache.royale.core.IImage; +import org.apache.royale.core.IImageModel; +COMPILE::JS { + import org.apache.royale.core.WrappedHTMLElement; + import org.apache.royale.events.Event; + import org.apache.royale.events.BrowserEvent; + import org.apache.royale.html.util.addElementToWrapper; +} + //use namespace mx_internal; //-------------------------------------- @@ -362,7 +371,7 @@ import spark.primitives.BitmapImage; * @playerversion AIR 2.5 * @productversion Flex 4.5 */ -public class Image extends SkinnableComponent +public class Image extends SkinnableComponent implements IImage { //-------------------------------------------------------------------------- // @@ -408,6 +417,59 @@ public class Image extends SkinnableComponent //-------------------------------------------------------------------------- // + // Inherited methods: UIComponent + // + //-------------------------------------------------------------------------- + + /** + * @royaleignorecoercion org.apache.royale.core.WrappedHTMLElement + */ + COMPILE::JS + override protected function createElement():WrappedHTMLElement + { + addElementToWrapper(this,'img'); + typeNames = 'Image'; + return element; + } + + COMPILE::JS + public function get imageElement():Element + { + return element; + } + + COMPILE::JS + public function applyImageData(binaryDataAsString:String):void + { + element.addEventListener("load", handleImageLoaded); + (element as HTMLImageElement).src = binaryDataAsString; + } + + COMPILE::JS + public function get complete():Boolean + { + return (element as HTMLImageElement).complete; + } + + COMPILE::JS + private function handleImageLoaded(event:BrowserEvent):void + { + trace("The image src "+source+" is now loaded"); + + trace("Image offset size is: "+(element as HTMLImageElement).naturalWidth+" x "+(element as HTMLImageElement).naturalHeight); + // should we now set the image's measured sizes? + measuredWidth = (element as HTMLImageElement).naturalWidth; + measuredHeight = (element as HTMLImageElement).naturalHeight; + setActualSize(getExplicitOrMeasuredWidth(), getExplicitOrMeasuredHeight()); + + dispatchEvent(new Event("complete")); + + var newEvent:Event = new Event("layoutNeeded",true); + dispatchEvent(newEvent); + } + + //-------------------------------------------------------------------------- + // // Variables // //-------------------------------------------------------------------------- @@ -894,7 +956,7 @@ public class Image extends SkinnableComponent else return imageDisplayProperties.source; */ - return null; + return (model as IImageModel).url; } /** @@ -907,10 +969,12 @@ public class Image extends SkinnableComponent */ public function set source(value:Object):void { + (model as IImageModel).url = value as String; + + /* if (source == value) return; - /* _loading = false; _invalid = false; _ready = false; diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/GroupBase.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/GroupBase.as index 2e02cae..ef4ff64 100644 --- a/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/GroupBase.as +++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/components/supportClasses/GroupBase.as @@ -33,19 +33,25 @@ package spark.components.supportClasses //import flash.geom.Rectangle; //import mx.core.ILayoutElement; +import mx.core.IUIComponent; import mx.core.IVisualElement; import mx.core.UIComponent; -//import mx.core.UIComponentGlobals; import mx.core.mx_internal; import mx.events.PropertyChangeEvent; -//import mx.graphics.shaderClasses.LuminosityMaskShader; - -//import spark.components.ResizeMode; -//import spark.core.IViewport; -//import spark.core.MaskType; -//import spark.events.DisplayLayerObjectExistenceEvent; -//import spark.layouts.BasicLayout; -//import spark.layouts.supportClasses.LayoutBase; + +import spark.layouts.BasicLayout; +import spark.layouts.supportClasses.LayoutBase; + +import org.apache.royale.binding.ContainerDataBinding; +import org.apache.royale.binding.DataBindingBase; +import org.apache.royale.core.IBeadLayout; +import org.apache.royale.core.ILayoutHost; +import org.apache.royale.core.ILayoutParent; +import org.apache.royale.core.ValuesManager; +import org.apache.royale.events.Event; +import org.apache.royale.utils.MXMLDataInterpreter; +import org.apache.royale.utils.loadBeadFromValuesManager; + //import spark.utils.FTETextUtil; //import spark.utils.MaskUtil; @@ -321,7 +327,7 @@ include "../../styles/metadata/SelectionFormatTextStyles.as" */ * @playerversion AIR 1.5 * @productversion Royale 0.9.4 */ -public class GroupBase extends UIComponent +public class GroupBase extends UIComponent implements ILayoutParent { //implements IViewport //-------------------------------------------------------------------------- @@ -526,9 +532,11 @@ public class GroupBase extends UIComponent _layout = value; - /* if (_layout) + if (_layout) { _layout.target = this; + } + /* _layout.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, redispatchLayoutEvent); if (_layoutProperties) @@ -550,6 +558,33 @@ public class GroupBase extends UIComponent invalidateDisplayList(); */ } + + /* + * ILayoutParent + */ + + /** + * Returns the ILayoutHost which is its view. From ILayoutParent. + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.8 + */ + public function getLayoutHost():ILayoutHost + { + return view as ILayoutHost; + } + + //---------------------------------- + // getLayoutChildAt for compatibility + //---------------------------------- + + public function getLayoutChildAt(index:int):IUIComponent + { + return getElementAt(index) as IUIComponent; + } + /** * @private * Redispatch the bindable LayoutBase properties that we expose (that we "facade"). @@ -567,6 +602,24 @@ public class GroupBase extends UIComponent } } */ + override public function get measuredWidth():Number + { + if (isNaN(_measuredWidth)) + measure(); + if (isNaN(_measuredWidth)) + return width; + return _measuredWidth; + } + + override public function get measuredHeight():Number + { + if (isNaN(_measuredHeight)) + measure(); + if (isNaN(_measuredHeight)) + return height; + return _measuredHeight; + } + //---------------------------------- // horizontalScrollPosition //---------------------------------- @@ -764,9 +817,9 @@ public class GroupBase extends UIComponent * @private * Storage for the autoLayout property. */ - /* private var _autoLayout:Boolean = true; + private var _autoLayout:Boolean = true; - [Inspectable(defaultValue="true")] */ + [Inspectable(defaultValue="true")] /** * If <code>true</code>, measurement and layout are done @@ -781,29 +834,30 @@ public class GroupBase extends UIComponent * @playerversion AIR 1.5 * @productversion Royale 0.9.4 */ - /* public function get autoLayout():Boolean + public function get autoLayout():Boolean { return _autoLayout; - } */ + } /** * @private */ - /* public function set autoLayout(value:Boolean):void + public function set autoLayout(value:Boolean):void { if (_autoLayout == value) return; _autoLayout = value; + /* // If layout is being turned back on, trigger a layout to occur now. if (value) { invalidateSize(); invalidateDisplayList(); invalidateParentSizeAndDisplayList(); - } - } */ + }*/ + } //---------------------------------- // overlay @@ -1110,6 +1164,28 @@ public class GroupBase extends UIComponent super.invalidateDisplayList(); } */ + override public function addedToParent():void + { + if (!initialized) { + // each MXML file can also have styles in fx:Style block + ValuesManager.valuesImpl.init(this); + } + + if (MXMLDescriptor) + component = this; + + super.addedToParent(); + + // Load the layout bead if it hasn't already been loaded. + if (loadBeadFromValuesManager(IBeadLayout, "iBeadLayout", this)) + { + dispatchEvent(new Event("initComplete")); + if ((isHeightSizedToContent() || !isNaN(explicitHeight)) && + (isWidthSizedToContent() || !isNaN(explicitWidth))) + dispatchEvent(new Event("layoutNeeded")); + } + } + /** * <p>If the layout object has not been set yet, * createChildren() assigns this container a @@ -1122,14 +1198,69 @@ public class GroupBase extends UIComponent * @playerversion AIR 2.5 * @productversion Royale 0.9.4.5 */ - /* override protected function createChildren():void + override protected function createChildren():void { - super.createChildren(); - if (!layout) layout = new BasicLayout(); - } */ + + MXMLDataInterpreter.generateMXMLInstances(_mxmlDocument, this, MXMLDescriptor); + + if (getBeadByType(DataBindingBase) == null) + addBead(new ContainerDataBinding()); + + dispatchEvent(new Event("initBindings")); + } + private var _mxmlDescriptor:Array; + private var _mxmlDocument:Object = this; + + /** + * @copy org.apache.royale.core.Application#MXMLDescriptor + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.8 + */ + public function get MXMLDescriptor():Array + { + return _mxmlDescriptor; + } + + /** + * @private + */ + public function setMXMLDescriptor(document:Object, value:Array):void + { + _mxmlDocument = document; + _mxmlDescriptor = value; + } + + /** + * @copy org.apache.royale.core.Application#generateMXMLAttributes() + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.8 + */ + public function generateMXMLAttributes(data:Array):void + { + MXMLDataInterpreter.generateMXMLProperties(this, data); + } + + /** + * @copy org.apache.royale.core.ItemRendererClassFactory#mxmlContent + * + * @langversion 3.0 + * @playerversion Flash 10.2 + * @playerversion AIR 2.6 + * @productversion Royale 0.8 + * + * @royalesuppresspublicvarwarning + */ + public var mxmlContent:Array; + /** * @private */ @@ -1155,8 +1286,10 @@ public class GroupBase extends UIComponent super.measure(); layoutInvalidateSizeFlag = false; + */ _layout.measure(); + /* // Special case: If the group clips content, or resizeMode is "scale" // then measured minimum size is zero if (clipAndEnableScrolling || resizeMode == ResizeMode.SCALE) @@ -1300,9 +1433,10 @@ public class GroupBase extends UIComponent if (layoutInvalidateDisplayListFlag) { layoutInvalidateDisplayListFlag = false; + */ if (autoLayout && _layout) _layout.updateDisplayList(unscaledWidth, unscaledHeight); - + /* if (_layout) _layout.updateScrollRect(unscaledWidth, unscaledHeight); } */ @@ -1746,11 +1880,11 @@ public class GroupBase extends UIComponent * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Royale 0.9.4 - */ override public function get numElements():int { return -1; } + */ /** * @copy mx.core.IVisualElementContainer#getElementAt() diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/BasicLayout.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/BasicLayout.as new file mode 100644 index 0000000..d1552ef --- /dev/null +++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/BasicLayout.as @@ -0,0 +1,551 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 spark.layouts +{ + +import mx.core.ILayoutElement; +import mx.core.IVisualElement; +import mx.core.mx_internal; +//import mx.resources.ResourceManager; + +import spark.components.supportClasses.GroupBase; +import spark.layouts.supportClasses.LayoutBase; +import spark.layouts.supportClasses.LayoutElementHelper; + +use namespace mx_internal; + +//[ResourceBundle("layout")] + +/** + * The BasicLayout class arranges the layout elements according to their individual settings, + * independent of each-other. BasicLayout, also called absolute layout, requires that you + * explicitly position each container child. + * You can use the <code>x</code> and <code>y</code> properties of the child, + * or constraints to position each child. + * + * <p><b>Note: </b>The Spark list-based controls (the Spark List control and its subclasses + * such as ButtonBar, ComboBox, DropDownList, and TabBar) do not support the BasicLayout class. + * Do not use BasicLayout with the Spark list-based controls.</p> + * + * <p>Per-element supported constraints are <code>left</code>, <code>right</code>, + * <code>top</code>, <code>bottom</code>, <code>horizontalCenter</code>, + * <code>verticalCenter</code>, <code>baseline</code>, <code>percentWidth</code>, and <code>percentHeight</code>. + * Element's minimum and maximum sizes will always be respected.</p> + * + * <p>The measured size of the container is calculated from the elements, their + * constraints and their preferred sizes. The measured size of the container + * is big enough to fit in all of the elements at their preferred sizes with + * their constraints satisfied. </p> + * + * <p>Here are some examples of how measured size is calculated: + * <ul> + * <li>If the container has a single element with <code>left</code> constraint specified, + * then the container's measured width will be equal to the element's preferred + * width plus the value of the <code>left</code> constraint.</li> + * + * <li>If the container has a single element with <code>percentWidth</code> specified, + * then the container's measured width will be equal to the element's preferred width. + * Even though the element's <code>percentWidth</code> is not directly factored in the calculations, + * it will be respected during a call to the <code>updateDisplayList()</code> method.</li> + * + * <li>If the container has a single element with <code>baseline</code> constraint specified, + * then the container's measured height will be equal to the element's preferred height + * plus the <code>baseline</code> and minus the value of the element's <code>baselinePosition</code> property.</li> + * + * <li>If the container has a single element with <code>verticalCenter</code> constraint specified, + * then the container's measured height will be equal to the element's preferred height + * plus double the value of the <code>verticalCenter</code> constraint.</li> + * </ul> + * </p> + * + * <p>During a call to the <code>updateDisplayList()</code> method, + * the element's size is determined according to + * the rules in the following order of precedence (the element's minimum and + * maximum sizes are always respected):</p> + * <ul> + * <li>If the element has <code>percentWidth</code> or <code>percentHeight</code> set, + * then its size is calculated as a percentage of the available size, where the available + * size is the container size minus any <code>left</code>, <code>right</code>, + * <code>top</code>, or <code>bottom</code> constraints.</li> + * + * <li>If the element has both left and right constraints, it's width is + * set to be the container's width minus the <code>left</code> + * and <code>right</code> constraints.</li> + * + * <li>If the element has both <code>top</code> and <code>bottom</code> constraints, + * it's height is set to be the container's height minus the <code>top</code> + * and <code>bottom</code> constraints.</li> + * + * <li>The element is set to its preferred width and/or height.</li> + * </ul> + * + * <p>The BasicLayout class calculates its minimum size as the maximum of the minimum child sizes:</p> + * + * <ol> + * <li>For each child in the container, determine the minimum size + * to which the child could shrink: + * <ul> + * <li>If the child is constrained to its parent's width or height, + * then the child could shrink to its minimum width or height. + * Use the minimum size of the child.</li> + * <li>If the child is not constrained to the parent, + * then it remains at its preferred size. + * Use the preferred size of the child. </li> + * </ul></li> + * <li>Find the maximum of the sizes from step 1. </li> + * </ol> + * + * <p>Therefore, if a child is constrained to its parent, then the layout + * uses the child's minimum size. + * Otherwise, it uses its preferred size of the child to calculate + * the minimum size for the container.</p> + * + * <p>The element's position is determined according to the rules in the following + * order of precedence:</p> + * <ul> + * <li>The <code>horizontalCenter</code> or <code>verticalCenter</code> constraints + * specify the distance between the container's center and the element's center. + * Set the <code>horizontalCenter</code> or <code>verticalCenter</code> constraints + * to zero to center the element within the container in + * the horizontal or vertical direction.</li> + * + * <li>If element's baseline is specified, then the element is positioned in + * the vertical direction such that its <code>baselinePosition</code> (usually the base line + * of its first line of text) is aligned with <code>baseline</code> constraint.</li> + * + * <li>If element's <code>top</code> or <code>left</code> constraints + * are specified, then the element is + * positioned such that the top-left corner of the element's layout bounds is + * offset from the top-left corner of the container by the specified values.</li> + * + * <li>If element's <code>bottom</code> or <code>right</code> constraints are specified, + * then the element is positioned such that the bottom-right corner + * of the element's layout bounds is + * offset from the bottom-right corner of the container by the specified values.</li> + * + * <li>When no constraints determine the position in the horizontal or vertical + * direction, the element is positioned according to its x and y coordinates.</li> + * </ul> + * + * <p>The content size of the container is calculated as the maximum of the + * coordinates of the bottom-right corner of all the layout elements.</p> + * + * @mxml + * <p>The <code><s:BasicLayout></code> tag inherits all of the tag + * attributes of its superclass and adds no additional tag attributes:</p> + * + * <pre> + * <s:BasicLayout/> + * </pre> + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ +public class BasicLayout extends LayoutBase +{ +// include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + private static function constraintsDetermineWidth(layoutElement:ILayoutElement):Boolean + { + return !isNaN(layoutElement.percentWidth) || + !isNaN(LayoutElementHelper.parseConstraintValue(layoutElement.left)) && + !isNaN(LayoutElementHelper.parseConstraintValue(layoutElement.right)); + } + + private static function constraintsDetermineHeight(layoutElement:ILayoutElement):Boolean + { + return !isNaN(layoutElement.percentHeight) || + !isNaN(LayoutElementHelper.parseConstraintValue(layoutElement.top)) && + !isNaN(LayoutElementHelper.parseConstraintValue(layoutElement.bottom)); + } + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public function BasicLayout():void + { + super(); + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + override mx_internal function get virtualLayoutSupported():Boolean + { + return false; + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private function checkUseVirtualLayout():void + { + if (useVirtualLayout) + throw new Error(/*ResourceManager.getInstance().getString("layout", */"basicLayoutNotVirtualized"/*)*/); + } + + /** + * @private + */ + override public function measure():void + { + // Check for unsuported values here instead of in the useVirtualLayout setter, as + // List may toggle the property several times before the actual layout pass. + checkUseVirtualLayout(); + super.measure(); + + var layoutTarget:GroupBase = target; + if (!layoutTarget) + return; + + var width:Number = 0; + var height:Number = 0; + var minWidth:Number = 0; + var minHeight:Number = 0; + + var count:int = layoutTarget.numElements; + for (var i:int = 0; i < count; i++) + { + var layoutElement:ILayoutElement = layoutTarget.getElementAt(i) as ILayoutElement; + if (!layoutElement || !layoutElement.includeInLayout) + continue; + + var hCenter:Number = LayoutElementHelper.parseConstraintValue(layoutElement.horizontalCenter); + var vCenter:Number = LayoutElementHelper.parseConstraintValue(layoutElement.verticalCenter); + //var baseline:Number = LayoutElementHelper.parseConstraintValue(layoutElement.baseline); + var left:Number = LayoutElementHelper.parseConstraintValue(layoutElement.left); + var right:Number = LayoutElementHelper.parseConstraintValue(layoutElement.right); + var top:Number = LayoutElementHelper.parseConstraintValue(layoutElement.top); + var bottom:Number = LayoutElementHelper.parseConstraintValue(layoutElement.bottom); + + // Extents of the element - how much additional space (besides its own width/height) + // the element needs based on its constraints. + var extX:Number; + var extY:Number; + + if (!isNaN(left) && !isNaN(right)) + { + // If both left & right are set, then the extents is always + // left + right so that the element is resized to its preferred + // size (if it's the one that pushes out the default size of the container). + extX = left + right; + } + else if (!isNaN(hCenter)) + { + // If we have horizontalCenter, then we want to have at least enough space + // so that the element is within the parent container. + // If the element is aligned to the left/right edge of the container and the + // distance between the centers is hCenter, then the container width will be + // parentWidth = 2 * (abs(hCenter) + elementWidth / 2) + // <=> parentWidth = 2 * abs(hCenter) + elementWidth + // Since the extents is the additional space that the element needs + // extX = parentWidth - elementWidth = 2 * abs(hCenter) + extX = Math.abs(hCenter) * 2; + } + else if (!isNaN(left) || !isNaN(right)) + { + extX = isNaN(left) ? 0 : left; + extX += isNaN(right) ? 0 : right; + } + else + { + extX = layoutElement.getBoundsXAtSize(NaN, NaN); + } + + if (!isNaN(top) && !isNaN(bottom)) + { + // If both top & bottom are set, then the extents is always + // top + bottom so that the element is resized to its preferred + // size (if it's the one that pushes out the default size of the container). + extY = top + bottom; + } + else if (!isNaN(vCenter)) + { + // If we have verticalCenter, then we want to have at least enough space + // so that the element is within the parent container. + // If the element is aligned to the top/bottom edge of the container and the + // distance between the centers is vCenter, then the container height will be + // parentHeight = 2 * (abs(vCenter) + elementHeight / 2) + // <=> parentHeight = 2 * abs(vCenter) + elementHeight + // Since the extents is the additional space that the element needs + // extY = parentHeight - elementHeight = 2 * abs(vCenter) + extY = Math.abs(vCenter) * 2; + } + /*else if (!isNaN(baseline)) + { + extY = Math.round(baseline - layoutElement.baselinePosition); + }*/ + else if (!isNaN(top) || !isNaN(bottom)) + { + extY = isNaN(top) ? 0 : top; + extY += isNaN(bottom) ? 0 : bottom; + } + else + { + extY = layoutElement.getBoundsYAtSize(NaN, NaN); + } + + var preferredWidth:Number = layoutElement.getPreferredBoundsWidth(); + var preferredHeight:Number = layoutElement.getPreferredBoundsHeight(); + + width = Math.max(width, extX + preferredWidth); + height = Math.max(height, extY + preferredHeight); + + // Find the minimum default extents, we take the minimum width/height only + // when the element size is determined by the parent size + var elementMinWidth:Number = + constraintsDetermineWidth(layoutElement) ? layoutElement.getMinBoundsWidth() : + preferredWidth; + var elementMinHeight:Number = + constraintsDetermineHeight(layoutElement) ? layoutElement.getMinBoundsHeight() : + preferredHeight; + + minWidth = Math.max(minWidth, extX + elementMinWidth); + minHeight = Math.max(minHeight, extY + elementMinHeight); + } + + // Use Math.ceil() to make sure that if the content partially occupies + // the last pixel, we'll count it as if the whole pixel is occupied. + layoutTarget.measuredWidth = Math.ceil(Math.max(width, minWidth)); + layoutTarget.measuredHeight = Math.ceil(Math.max(height, minHeight)); + layoutTarget.measuredMinWidth = Math.ceil(minWidth); + layoutTarget.measuredMinHeight = Math.ceil(minHeight); + } + + /** + * @return Returns the maximum value for an element's dimension so that the component doesn't + * spill out of the container size. Calculations are based on the layout rules. + * Pass in unscaledWidth, hCenter, left, right, childX to get a maxWidth value. + * Pass in unscaledHeight, vCenter, top, bottom, childY to get a maxHeight value. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + static private function maxSizeToFitIn(totalSize:Number, + center:Number, + lowConstraint:Number, + highConstraint:Number, + position:Number):Number + { + if (!isNaN(center)) + { + // (1) x == (totalSize - childWidth) / 2 + hCenter + // (2) x + childWidth <= totalSize + // (3) x >= 0 + // + // Substitue x in (2): + // (totalSize - childWidth) / 2 + hCenter + childWidth <= totalSize + // totalSize - childWidth + 2 * hCenter + 2 * childWidth <= 2 * totalSize + // 2 * hCenter + childWidth <= totalSize se we get: + // (3) childWidth <= totalSize - 2 * hCenter + // + // Substitute x in (3): + // (4) childWidth <= totalSize + 2 * hCenter + // + // From (3) & (4) above we get: + // childWidth <= totalSize - 2 * abs(hCenter) + + return totalSize - 2 * Math.abs(center); + } + else if (!isNaN(lowConstraint)) + { + // childWidth + left <= totalSize + return totalSize - lowConstraint; + } + else if (!isNaN(highConstraint)) + { + // childWidth + right <= totalSize + return totalSize - highConstraint; + } + else + { + // childWidth + childX <= totalSize + return totalSize - position; + } + } + + /** + * @private + */ + override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void + { + // Check for unsuported values here instead of in the useVirtualLayout setter, as + // List may toggle the property several times before the actual layout pass. + checkUseVirtualLayout(); + super.updateDisplayList(unscaledWidth, unscaledHeight); + + var layoutTarget:GroupBase = target; + if (!layoutTarget) + return; + + var count:int = layoutTarget.numElements; + var maxX:Number = 0; + var maxY:Number = 0; + for (var i:int = 0; i < count; i++) + { + var layoutElement:ILayoutElement = layoutTarget.getElementAt(i) as ILayoutElement; + if (!layoutElement || !layoutElement.includeInLayout) + continue; + + var hCenter:Number = LayoutElementHelper.parseConstraintValue(layoutElement.horizontalCenter); + var vCenter:Number = LayoutElementHelper.parseConstraintValue(layoutElement.verticalCenter); + //var baseline:Number = LayoutElementHelper.parseConstraintValue(layoutElement.baseline); + var left:Number = LayoutElementHelper.parseConstraintValue(layoutElement.left); + var right:Number = LayoutElementHelper.parseConstraintValue(layoutElement.right); + var top:Number = LayoutElementHelper.parseConstraintValue(layoutElement.top); + var bottom:Number = LayoutElementHelper.parseConstraintValue(layoutElement.bottom); + var percentWidth:Number = layoutElement.percentWidth; + var percentHeight:Number = layoutElement.percentHeight; + + var elementMaxWidth:Number = NaN; + var elementMaxHeight:Number = NaN; + + // Calculate size + var childWidth:Number = NaN; + var childHeight:Number = NaN; + + if (!isNaN(percentWidth)) + { + var availableWidth:Number = unscaledWidth; + if (!isNaN(left)) + availableWidth -= left; + if (!isNaN(right)) + availableWidth -= right; + + childWidth = Math.round(availableWidth * Math.min(percentWidth * 0.01, 1)); + elementMaxWidth = Math.min(layoutElement.getMaxBoundsWidth(), + maxSizeToFitIn(unscaledWidth, hCenter, left, right, layoutElement.getLayoutBoundsX())); + } + else if (!isNaN(left) && !isNaN(right)) + { + childWidth = unscaledWidth - right - left; + } + + if (!isNaN(percentHeight)) + { + var availableHeight:Number = unscaledHeight; + if (!isNaN(top)) + availableHeight -= top; + if (!isNaN(bottom)) + availableHeight -= bottom; + + childHeight = Math.round(availableHeight * Math.min(percentHeight * 0.01, 1)); + elementMaxHeight = Math.min(layoutElement.getMaxBoundsHeight(), + maxSizeToFitIn(unscaledHeight, vCenter, top, bottom, layoutElement.getLayoutBoundsY())); + } + else if (!isNaN(top) && !isNaN(bottom)) + { + childHeight = unscaledHeight - bottom - top; + } + + // Apply min and max constraints, make sure min is applied last. In the cases + // where childWidth and childHeight are NaN, setLayoutBoundsSize will use preferredSize + // which is already constrained between min and max. + if (!isNaN(childWidth)) + { + if (isNaN(elementMaxWidth)) + elementMaxWidth = layoutElement.getMaxBoundsWidth(); + childWidth = Math.max(layoutElement.getMinBoundsWidth(), Math.min(elementMaxWidth, childWidth)); + } + if (!isNaN(childHeight)) + { + if (isNaN(elementMaxHeight)) + elementMaxHeight = layoutElement.getMaxBoundsHeight(); + childHeight = Math.max(layoutElement.getMinBoundsHeight(), Math.min(elementMaxHeight, childHeight)); + } + + // Set the size. + layoutElement.setLayoutBoundsSize(childWidth, childHeight); + var elementWidth:Number = layoutElement.getLayoutBoundsWidth(); + var elementHeight:Number = layoutElement.getLayoutBoundsHeight(); + + var childX:Number = NaN; + var childY:Number = NaN; + + // Horizontal position + if (!isNaN(hCenter)) + childX = Math.round((unscaledWidth - elementWidth) / 2 + hCenter); + else if (!isNaN(left)) + childX = left; + else if (!isNaN(right)) + childX = unscaledWidth - elementWidth - right; + else + childX = layoutElement.getLayoutBoundsX(); + + // Vertical position + if (!isNaN(vCenter)) + childY = Math.round((unscaledHeight - elementHeight) / 2 + vCenter); + //else if (!isNaN(baseline)) + // childY = Math.round(baseline - IVisualElement(layoutElement).baselinePosition); + else if (!isNaN(top)) + childY = top; + else if (!isNaN(bottom)) + childY = unscaledHeight - elementHeight - bottom; + else + childY = layoutElement.getLayoutBoundsY(); + + // Set position + layoutElement.setLayoutBoundsPosition(childX, childY); + + // update content limits + maxX = Math.max(maxX, childX + elementWidth); + maxY = Math.max(maxY, childY + elementHeight); + } + + // Make sure that if the content spans partially over a pixel to the right/bottom, + // the content size includes the whole pixel. + layoutTarget.setContentSize(Math.ceil(maxX), Math.ceil(maxY)); + } +} + +} diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/supportClasses/SparkLayoutBead.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/supportClasses/SparkLayoutBead.as new file mode 100644 index 0000000..af956ec --- /dev/null +++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/layouts/supportClasses/SparkLayoutBead.as @@ -0,0 +1,122 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 spark.layouts.supportClasses +{ +import mx.core.Container; +import mx.core.ILayoutElement; +import mx.core.IVisualElement; +import mx.core.UIComponent; +import mx.core.mx_internal; + +import spark.components.supportClasses.GroupBase; +import spark.core.NavigationUnit; + +import org.apache.royale.core.IStrand; +import org.apache.royale.core.IBeadLayout; +import org.apache.royale.core.LayoutBase; +import org.apache.royale.core.UIBase; +import org.apache.royale.events.Event; +import org.apache.royale.events.EventDispatcher; +import org.apache.royale.utils.MXMLDataInterpreter; +import org.apache.royale.utils.loadBeadFromValuesManager; + +use namespace mx_internal; + +/** + * The SparkLayoutBead class is a layout bead that pumps the Spark + * LayoutBase subclasses. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ +public class SparkLayoutBead extends org.apache.royale.core.LayoutBase +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public function SparkLayoutBead() + { + super(); + } + + override public function layout():Boolean + { + var n:int = target.numChildren; + if (n == 0) + return false; + + target.layout.updateDisplayList(target.width, target.height); + + // update the target's actual size if needed. + if (target.isWidthSizedToContent() && target.isHeightSizedToContent()) { + target.setActualSize(target.getExplicitOrMeasuredWidth(), + target.getExplicitOrMeasuredHeight()); + } + else if (target.isWidthSizedToContent()) + target.setWidth(target.getExplicitOrMeasuredWidth()); + else if (target.isHeightSizedToContent()) + target.setHeight(target.getExplicitOrMeasuredHeight()); + + return true; + } + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + private var _strand:IStrand; + + override public function set strand(value:IStrand):void + { + _strand = value; + _target = value as GroupBase; + super.strand = value; + + } + + private var _target:GroupBase; + + public function get target():GroupBase + { + return _target; + } + + public function set target(value:GroupBase):void + { + _target = value; + } + +} +}
