Super quick post… I’ve created a simple LayoutHelper for Josh Tynjala’s FoxholeControls.

This will help simple containers lay out their components without having to do a ton of custom property/member inspection for each child you want to lay out!

First up, some super handy links!

 
And now the code!
[sourcecode language=”actionscript3″]
package com.killerspaz.flash.starling.foxhole.helpers
{
import flash.geom.Point;

import org.josht.starling.foxhole.core.FoxholeControl;

import starling.display.DisplayObject;

public class LayoutHelper
{
public static const DIRECTION_VERITCAL:String = "DIRECTION_VERITCAL";
public static const DIRECTION_HORIZONTAL:String = "DIRECTION_HORIZONTAL";

private var _layoutTarget:FoxholeControl;
private var _direction:String = DIRECTION_HORIZONTAL;
private var _allowFlow:Boolean = true;
private var _gap:Number = 5;
private var _padding:Number = 10;

public function LayoutHelper(layoutTarget:FoxholeControl):void
{
this._layoutTarget = layoutTarget;
}

public function get allowFlow():Boolean
{
return this._allowFlow;
}

public function set allowFlow(value:Boolean):void
{
this._allowFlow = value;
this.invalidate();
}

public function get direction():String
{
return this._direction;
}

public function set direction(value:String):void
{
this._direction = value;
this.invalidate();
}

public function get padding():Number
{
return this._padding;
}

public function set padding(value:Number):void
{
this._padding = value;
this.invalidate();
}

public function get gap():Number
{
return this._gap;
}

public function set gap(value:Number):void
{
this._gap = value;
this.invalidate();
}

public function get layoutTarget():FoxholeControl
{
return this._layoutTarget;
}

public function set layoutTarget(value:FoxholeControl):void
{
this._layoutTarget = value;
this.invalidate();
}

public function invalidate():void
{
if (null !== this._layoutTarget) {
this._layoutTarget.invalidate();
}
}

public function layout():void
{
var numChildren:int = this._layoutTarget.numChildren;

var childIdx:int;
var currChild:DisplayObject;
var layoutPoint:Point = new Point(this._padding, this._padding);

var maxBoundaries:Point = new Point();
var rowBoundaries:Point = new Point();

//Calculate w/h, excluding the padding top/bottom or left/right
maxBoundaries.x = this._layoutTarget.width – (this._padding * 2);
maxBoundaries.y = this._layoutTarget.height – (this._padding * 2);

//Iterate over children, and layout accordingly
for (childIdx = 0; childIdx < numChildren; childIdx++) {
currChild = this._layoutTarget.getChildAt(childIdx);

if (currChild is FoxholeControl) {
FoxholeControl(currChild).validate();
}

//Position Child!
currChild.x = layoutPoint.x;
currChild.y = layoutPoint.y;

//Layout based on direction
if (DIRECTION_HORIZONTAL === this._direction) {
layoutPoint.x += currChild.width + this._gap; //Increase layout sizes (except if first child)
rowBoundaries.y = Math.max(rowBoundaries.y, currChild.height); //Determine the actual row/column boundary to avoid overlapping rows/columns

//If allowed to "flow," carry on to next row…
if (this._allowFlow && layoutPoint.x >= maxBoundaries.x) {
layoutPoint.x = this._padding;
layoutPoint.y += this._gap + rowBoundaries.y;
rowBoundaries.y = 0;
}
} else { //Same as above, but inverted for VERITCAL layout
layoutPoint.y += currChild.height + this._gap;
rowBoundaries.x = Math.max(rowBoundaries.x, currChild.width);

if (this._allowFlow && layoutPoint.y >= maxBoundaries.y) {
layoutPoint.x += this._gap + rowBoundaries.x;
layoutPoint.y = this._padding;
rowBoundaries.x = 0;
}
}

//trace ("Child " + (childIdx + 1) + " of " + numChildren + " " + currChild + " — " + layoutPoint);
}
}

}
}
[/sourcecode]

Keep in mind, it’s simple, but supports the following:

  • Global container padding
  • Gapsize
  • Horizontal and Vertical “Layout”
  • Flow – whether to create a new row/column or just infinitely lay out a single direction (default = true)

Usage is simple…

1. In a FoxholeControl::initialize(), create a new instance and pass self into it:

[sourcecode language=”actionscript3″]
override protected function initialize():void
{
super.initialize();

this._layoutHelper = new LayoutHelper(this);
this._layoutHelper.direction = LayoutHelper.DIRECTION_VERITCAL;
//this._layoutHelper.allowFlow = false;

[/sourcecode]

2. In FoxholeControl::draw(), simply put:

[sourcecode language=”actionscript3″]
override protected function draw():void
{
super.draw();

this._layoutHelper.layout();
}
[/sourcecode]

That’s it! Super simple!