package
{
import flash.geom.Point;
import mx.core.ILayoutElement;
import org.osmf.layout.PaddingLayoutFacet;
import spark.components.supportClasses.GroupBase;
import spark.layouts.HorizontalAlign;
import spark.layouts.VerticalAlign;
import spark.layouts.supportClasses.LayoutBase;
/**
* Lays out elements the same way as text area positions words: putting them in
* one line and going to next line when there is no space for new word.
*/
public class HorizontalMultilineLayout extends LayoutBase
{
private var lastWidth:Number = -1;
private var _horizontalGap:Number = 6;
public function get horizontalGap():Number
{
return _horizontalGap;
}
public function set horizontalGap(value:Number):void
{
if (value == _horizontalGap)
return;
_horizontalGap = value;
invalidateTargetSizeAndDisplayList();
}
private var _verticalGap:Number = 6;
public function get verticalGap():Number
{
return _verticalGap;
}
public function set verticalGap(value:Number):void
{
if (value == _verticalGap)
return;
_verticalGap = value;
invalidateTargetSizeAndDisplayList();
}
private var _verticalAlign:String = VerticalAlign.TOP;
[Inspectable("General", enumeration="top,bottom,middle", defaultValue="top")]
public function get verticalAlign():String
{
return _verticalAlign;
}
public function set verticalAlign(value:String):void
{
if (_verticalAlign == value)
return;
_verticalAlign = value;
invalidateTargetSizeAndDisplayList();
}
private var _paddingLeft:Number = 0;
public function get paddingLeft():Number
{
return _paddingLeft;
}
public function set paddingLeft(value:Number):void
{
if (_paddingLeft == value)
return;
_paddingLeft = value;
invalidateTargetSizeAndDisplayList();
}
private var _paddingRight:Number = 0;
public function get paddingRight():Number
{
return _paddingRight;
}
public function set paddingRight(value:Number):void
{
if (_paddingRight == value)
return;
_paddingRight = value;
invalidateTargetSizeAndDisplayList();
}
private var _paddingTop:Number = 0;
public function get paddingTop():Number
{
return _paddingTop;
}
public function set paddingTop(value:Number):void
{
if (_paddingTop == value)
return;
_paddingTop = value;
invalidateTargetSizeAndDisplayList();
}
private var _paddingBottom:Number = 0;
public function get paddingBottom():Number
{
return _paddingBottom;
}
public function set paddingBottom(value:Number):void
{
if (_paddingBottom == value)
return;
_paddingBottom = value;
invalidateTargetSizeAndDisplayList();
}
override public function measure():void
{
if (lastWidth == -1)
return;
var measuredWidth:Number = 0;
var measuredMinWidth:Number = 0;
var measuredHeight:Number = 0;
var measuredMinHeight:Number = 0;
var layoutTarget:GroupBase = target;
var n:int = layoutTarget.numElements;
var element:ILayoutElement;
var i:int;
var width:Number = layoutTarget.explicitWidth;
if (isNaN(width) && lastWidth != -1)
width = lastWidth;
if (isNaN(width)) {
for (i = 0; i < n; i++)
{
element = layoutTarget.getElementAt(i);
if (!element || !element.includeInLayout)
continue;
measuredWidth = Math.ceil(element.getPreferredBoundsWidth());
measuredHeight = Math.ceil(element.getPreferredBoundsHeight());
break;
}
measuredMinWidth = measuredWidth;
measuredMinHeight = measuredHeight;
}
else
{
var currentLineWidth:Number = 0;
var currentLineHeight:Number = 0;
var lineNum:int = 1;
for (i = 0; i < n; i++)
{
element = layoutTarget.getElementAt(i);
if (!element || !element.includeInLayout)
continue;
var widthWithoutPaddings:Number = width - _paddingLeft - _paddingRight;
var elementWidth:Number = Math.ceil(element.getPreferredBoundsWidth());
if (currentLineWidth == 0 ||
currentLineWidth + _horizontalGap + elementWidth <= widthWithoutPaddings)
{
currentLineWidth += elementWidth + (currentLineWidth == 0 ? 0 : _horizontalGap);
currentLineHeight = Math.max(currentLineHeight, Math.ceil(element.getPreferredBoundsHeight()));
}
else
{
measuredHeight += currentLineHeight;
lineNum++;
currentLineWidth = elementWidth;
currentLineHeight = Math.ceil(element.getPreferredBoundsHeight());
}
}
measuredHeight += currentLineHeight;
if (lineNum > 1)
measuredHeight += _verticalGap * (lineNum - 1);
for (i = 0; i < n; i++)
{
element = layoutTarget.getElementAt(i);
if (!element || !element.includeInLayout)
continue;
measuredWidth =
measuredMinWidth = Math.ceil(element.getPreferredBoundsWidth());
break;
}
measuredMinHeight = measuredHeight;
}
layoutTarget.measuredWidth = measuredWidth + _paddingLeft + _paddingRight;
layoutTarget.measuredMinWidth = measuredMinWidth + _paddingLeft + _paddingRight;
layoutTarget.measuredHeight = measuredHeight + _paddingTop + _paddingBottom;
layoutTarget.measuredMinHeight = measuredMinHeight + _paddingTop + _paddingBottom;
}
override public function updateDisplayList(width:Number, height:Number):void
{
var layoutTarget:GroupBase = target;
var n:int = layoutTarget.numElements;
var element:ILayoutElement;
var i:int;
var x:Number = _paddingLeft;
var y:Number = _paddingTop;
var maxLineHeight:Number = 0;
var elementCounter:int = 0;
var positions:Vector.<Point> = new Vector.<Point>();
for (i = 0; i < n; i++)
{
element = layoutTarget.getElementAt(i);
if (!element || !element.includeInLayout)
continue;
var elementWidth:Number = Math.ceil(element.getPreferredBoundsWidth());
if (x == _paddingLeft ||
x + _horizontalGap + elementWidth <= width - _paddingRight)
{
if (elementCounter > 0)
x += _horizontalGap;
positions[i] = new Point(x, y);
element.setLayoutBoundsSize(NaN, NaN);
maxLineHeight = Math.max(maxLineHeight, Math.ceil(element.getPreferredBoundsHeight()));
}
else
{
x = _paddingLeft;
y += _verticalGap + maxLineHeight;
maxLineHeight = Math.ceil(element.getPreferredBoundsHeight());
positions[i] = new Point(x, y);
element.setLayoutBoundsSize(NaN, NaN);
}
x += elementWidth;
elementCounter++;
}
var yAdd:Number = 0;
var yDifference:Number = height - (y + maxLineHeight + _paddingBottom);
if (_verticalAlign == VerticalAlign.MIDDLE)
yAdd = Math.round(yDifference / 2);
else if (_verticalAlign == VerticalAlign.BOTTOM)
yAdd = Math.round(yDifference);
for (i = 0; i < n; i++)
{
element = layoutTarget.getElementAt(i);
if (!element || !element.includeInLayout)
continue;
var point:Point = positions[i];
point.y += yAdd;
element.setLayoutBoundsPosition(point.x, point.y);
}
if (lastWidth == -1 || lastWidth != width)
{
lastWidth = width;
invalidateTargetSizeAndDisplayList();
}
}
private function invalidateTargetSizeAndDisplayList():void
{
var g:GroupBase = target;
if (!g)
return;
g.invalidateSize();
g.invalidateDisplayList();
}
}
}