//////////////////////////////////////////////////////////////////////////////// // // 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 { import mx.core.ILayoutElement; import mx.events.PropertyChangeEvent; import mx.formatters.NumberBase; import spark.components.supportClasses.GroupBase; import spark.layouts.HorizontalLayout; public class HBaselineLayout extends HorizontalLayout { public function HBaselineLayout() { super(); } //---------------------------------- // globalBaseline //---------------------------------- [Inspectable(category="General")] private var _globalBaseline:Number = NaN; public function get globalBaseline():Number { return _globalBaseline; } public function set globalBaseline(value:Number):void { _globalBaseline = value; var target:GroupBase = this.target; if (target) { target.invalidateSize(); target.invalidateDisplayList(); } } //---------------------------------- // actualBaseline //---------------------------------- private var _actualBaseline:Number; [Bindable("propertyChange")] [Inspectable(category="General")] public function get actualBaseline():Number { return _actualBaseline; } private function setActualBaseline(value:Number):void { if (value == _actualBaseline) return; var oldValue:Number = _actualBaseline; _actualBaseline = value; dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, "actualBaseline", oldValue, value)); } //---------------------------------- // verticalAlign //---------------------------------- [Inspectable(category="General", enumeration="top,bottom,middle,justify,contentJustify,baseline", defaultValue="top")] override public function get verticalAlign():String { return super.verticalAlign; } /** * @private */ override public function measure():void { super.measure(); var target:GroupBase = this.target; if (!target || verticalAlign != "baseline") return; measureBaseline(true /*usePreferredSize*/); if (!isNaN(_globalBaseline)) measuredBaselineTop = _globalBaseline; // The measured height is the sum of the space above and below the baseline if (isNaN(paddingTop)) measuredBaselineTop += paddingTop; if (isNaN(paddingBottom)) measuredBaselineBottom += paddingBottom; target.measuredHeight = Math.round(measuredBaselineTop + measuredBaselineBottom); } /** * @private */ override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); var target:GroupBase = this.target; if (!target || verticalAlign != "baseline") return; measureBaseline(false /*usePreferredSize*/); if (!isNaN(_globalBaseline)) measuredBaselineTop = _globalBaseline; if (isNaN(paddingTop)) measuredBaselineTop += paddingTop; // Adjust the position of the elements var contentHeight:Number = 0; var count:int = target.numElements; for (var i:int = 0; i < count; i++) { var element:ILayoutElement = target.getElementAt(i); if (!element || !element.includeInLayout) continue; var elementBaseline:Number = element.baseline as Number; if (isNaN(elementBaseline)) elementBaseline = 0; var baselinePosition:Number = element.baselinePosition; var y:Number = measuredBaselineTop + (elementBaseline - baselinePosition); element.setLayoutBoundsPosition(element.getLayoutBoundsX(), y); contentHeight = Math.max(contentHeight, element.getLayoutBoundsHeight() + y); } // Adjust the content height if (isNaN(paddingBottom)) contentHeight += paddingBottom; target.setContentSize(target.contentWidth, contentHeight); // Update the baseline setActualBaseline(measuredBaselineTop); } private var measuredBaselineTop:Number = 0; // How much space is needed above the baseline to fit all the elements private var measuredBaselineBottom:Number = 0; // How much space is needed below the baseline to fit all the elements /** * @private */ private function measureBaseline(usePreferredSize:Boolean):void { var elementBaseline:Number = 0; // The current element's explicit baseline constraint var elementBaselineTop:Number = 0; // The portiono of the current element that's above the baseline var elementBaselineBottom:Number = 0; // The portion of the current element that's below the baseline measuredBaselineTop = 0; measuredBaselineBottom = 0; var count:int = target.numElements; for (var i:int = 0; i < count; i++) { var element:ILayoutElement = target.getElementAt(i); if (!element || !element.includeInLayout) continue; var elementHeight:Number = usePreferredSize ? element.getPreferredBoundsHeight() : element.getLayoutBoundsHeight(); elementBaseline = element.baseline as Number; if (isNaN(elementBaseline)) elementBaseline = 0; var baselinePosition:Number = element.baselinePosition; elementBaselineTop = baselinePosition - elementBaseline; elementBaselineBottom = elementHeight - elementBaselineTop; measuredBaselineTop = Math.max(elementBaselineTop, measuredBaselineTop); measuredBaselineBottom = Math.max(elementBaselineBottom, measuredBaselineBottom); } } } }