resizelayout.lzx
<library>
<include href="utils/layouts/layout.lzx"/>
<class name="resizelayout" extends="layout">
<attribute name="axis" setter="this.setAxis( axis )" value="y
" type="string"/>
<attribute name="spacing" value="0
"/>
<method name="construct" args="view , args">
super.construct( view , args );
this.resetDelegate = new LzDelegate( this , "reset");
this.heldSubs = new Object;
if ( args[ 'releaseview' ] != null ){
this.heldSubs[ view[args.releaseview].getUID() ] = false;
}
if ( args[ 'release' ] != null ){
this.heldSubs[ args.release.getUID() ] = false;
}
</method>
<method name="setAxis" args="a">
this.axis = a;
this.sizeAxis = a == "x" ? "width" : "height"
this.updateDelegate.register( this.immediateparent , "on" + this.sizeAxis);
</method>
<method name="addSubview" args="sd">
super.addSubview( sd );
var subview_id = sd.getUID(); // creates a UID if needed
if (sd.getOption('releasetolayout')) {
sd.setAttribute(this.sizeAxis,0);
} else {
this.hold( sd ); //subviews are held by default
}
this.resetDelegate.register( sd , "onvisible" );
this.resetDelegate.register( sd , "on" + this.sizeAxis );
this.reset();
</method>
<method name="hold" args="subview">
//right now if a held subview is resized, the layout will
//not do the right thing automatically
//should register a delegate
this.heldSubs[ subview.getUID() ] = true;
this.reset();
</method>
<method name="release" args="subview">
this.heldSubs[ subview.getUID() ] = false;
this.reset();
</method>
<method name="reset" args="e=null">
if ( this.locked ) { return; }
var l = this.subviews.length;
this.totalHeld = 0;
this.heldAmount = 0;
this.lastUnheld = -1;
// Only consider views that are visible
var inuse = 0;
for (var i = 0; i < l; i++ ) {
var s = this.subviews[i];
if (s.visible) inuse++;
}
// i is the view counter, j = visible view counter
var j = 0;
for (var i = 0; i < l; i++ ) {
var s = this.subviews[i];
if ( !s.visible ) continue;
var hs = (j < inuse-1) ? this.spacing : 0;
if ( this.heldSubs[ s.getUID() ] ) {
hs += s[(this.sizeAxis)];
this.heldAmount += hs;
this.totalHeld++;
} else {
this.lastUnheld = i;
this.heldAmount += hs;
}
j++;
}
this.unheldCount = inuse - this.totalHeld ;
this.update( );
</method>
<method name="update" args="e=null">
if ( this.locked ) { return; }
this.lock();
var layoutSize = this.immediateparent[(this.sizeAxis)];
var sizeDifference = layoutSize - (this.heldAmount );
var newElementSize = sizeDifference /this.unheldCount;
var l = this.subviews.length;
var c = 0;
for ( var i=0; i < l ; i++) {
var s = this.subviews[i];
if ( !s.visible ) continue;
// Set the position
s.setAttribute( this.axis , c );
// IF THE VIEW ALLOWS ITS size TO BE ALTERED THEN SET IT.
if ( ! this.heldSubs[ s.getUID() ] ) {
s.setAttribute( this.sizeAxis, newElementSize );
}
c += this.spacing + s[( this.sizeAxis )] ;
}
this.locked = false;
</method>
<doc>
<tag name="shortdesc"><text>A layout with fixed and stretchable views.</text></tag>
<text>
<classname>resizelayout</classname> extends <sgmltag class="element" role="LzLayout"><layout></sgmltag>, and therefore is responsible
for arranging a set of views. Like simplelayout, <classname>resizelayout</classname> positions a set of views vertically or horizontally
depending on the axis specified. The difference is that <classname>resizelayout</classname> can also stretch views.
<example>
<canvas height="100">
<view bgcolor="yellow" width="200">
<view bgcolor="blue" height="30" width="50"/>
<view bgcolor="red" height="30" width="50"/>
<view bgcolor="blue" height="30" width="50"/>
<simplelayout axis="x" spacing="10"/>
</view>
<view y="40" bgcolor="yellow" width="200">
<view bgcolor="blue" height="30" width="50"/>
<view bgcolor="red" height="30" options="releasetolayout"/>
<view bgcolor="blue" height="30" width="50"/>
<resizelayout axis="x"/>
</view>
</canvas>
</example>
<para>This example is similar to the one used in <sgmltag class="element" role="lz.stableborderlayout"><stableborderlayout></sgmltag>, and is in
fact visually equivalent. This is because <sgmltag class="element" role="lz.stableborderlayout"><stableborderlayout></sgmltag> is a special case
of <classname>resizelayout</classname> that is optimized for the common occurrence of having two fixed views with one stretchable view between them.</para>
<para>Unlike <sgmltag class="element" role="lz.stableborderlayout"><stableborderlayout></sgmltag>, <classname>resizelayout</classname> works
with any number of views. All the views that are controlled by a <classname>resizelayout</classname> are assumed to be fixed size until defined differently.
A view is defined as stretchable using the attribute <literal>options="releasetolayout"</literal>. These views will stretch to fill in the space that is not
taken by the fixed views. The <classname>resizelayout</classname> uses the width (or height) of its view to determine the total amount of space to fill, and
then those subviews are placed and stretched to fill that space. If there is more than one subview that is stretchable, then the available space is split
evenly between those subviews.</para>
<para>Then next example demonstrates what happens when two views are stretchable. The difference between the top and bottom views is only the spacing attribute.</para>
<example>
<canvas height="100">
<view bgcolor="yellow" width="300">
<view bgcolor="blue" height="30" width="50"/>
<view bgcolor="red" height="30" options="releasetolayout"/>
<view bgcolor="blue" height="30" width="50"/>
<view bgcolor="red" height="30" options="releasetolayout"/>
<resizelayout axis="x"/>
</view >
<view y="40" bgcolor="yellow" width="300">
<view bgcolor="blue" height="30" width="50"/>
<view bgcolor="red" height="30" options="releasetolayout"/>
<view bgcolor="blue" height="30" width="50"/>
<view bgcolor="red" height="30" options="releasetolayout"/>
<resizelayout axis="x" spacing="5"/>
</view>
</canvas>
</example>
</text>
</doc>
</class>
</library>
Cross References
Includes
Classes