list.lzx
<library>
<include href="base/baselist.lzx"/>
<include href="base/basetrackgroup.lzx"/>
<include href="lz/vscrollbar.lzx"/>
<include href="utils/layouts/simplelayout.lzx"/>
<class name="list" extends="baselist" width="100">
<attribute name="rightinset" value="0
"/>
<attribute name="defaultplacement" value="content
" type="string"/>
<attribute name="bordersize" value="1
"/>
<attribute name="border_top" value="${this.bordersize}"/>
<attribute name="border_left" value="${this.bordersize}"/>
<attribute name="border_right" value="${this.bordersize}"/>
<attribute name="border_bottom" value="${this.bordersize}"/>
<attribute name="tracking" value="false
"/>
<attribute name="spacing" value="0
"/>
<attribute name="minheight" value="24
" type="number"/>
<attribute name="shownitems" value="-1
" setter="this._setShownItems(shownitems)"/>
<event name="onshownitems"/>
<attribute name="scrollable" value="false
"/>
<attribute name="autoscrollbar" value="true
"/>
<attribute name="scrollbarclassname" type="string" value="vscrollbar
"/>
<method name="init">
super.init();
if (this._hasSetHeight) this.setAttribute('height', this.height);
adjustmyheight();
</method>
<view name="interior" x="${classroot.border_left}" y="${classroot.border_top}" width="${classroot.width - classroot.border_right - classroot.border_left}" bgcolor="${classroot._bgcolor}" clip="true">
<attribute name="_sbar" value="null
"/>
<event name="onmousetrackoutleft"/>
<event name="onmousetrackoutright"/>
<basetrackgroup name="content" width="100%" tracking="${classroot.tracking}" boundsref="${parent}" deactivateevents="['onmouseup','onselect']">
<simplelayout axis="y">
<attribute name="spacing" value="${classroot.spacing}"/>
</simplelayout>
<handler name="onaddsubview" args="v">
if ( classroot.itemclassname == "" ){
classroot.__itemclass = v.constructor;
}
if ( ( classroot.dataoption == "lazy" ||
classroot.dataoption == "resize" ) &&
!classroot._itemheight ){
classroot._itemheight = v.height;
}
classroot.adjustmyheight();
</handler>
<handler name="onheight">
classroot.adjustmyheight();
</handler>
</basetrackgroup>
<method name="ensurevscrollbar">
if (this._sbar == null) {
var classname = classroot.scrollbarclassname;
if (classname == "") {
classname = "vscrollbar";
}
if (classname && lz[classname]) {
this._sbar = new lz[classname](this, { stepsize: "20" });
} else if ($debug) {
Debug.error("%s.scrollbarclassname invalid: %s", classroot, classname)
}
}
</method>
<method name="showvscrollbar">
if (this._sbar == null) {
this.ensurevscrollbar();
}
this._sbar.setAttribute('visible', true);
classroot.setAttribute('rightinset', this._sbar.width);
</method>
<method name="hidevscrollbar">
if (this._sbar != null) {
this._sbar.setAttribute('visible', false);
}
classroot.setAttribute('rightinset', 0);
</method>
<method name="vscrollbarisvisible">
return (this._sbar != null && this._sbar.visible);
</method>
<handler name="onmousetrackoutbottom" args="y">
if ( this.vscrollbarisvisible() ) _sbar.step(1);
</handler>
<handler name="onmousetrackouttop" args="y">
if ( this.vscrollbarisvisible() ) _sbar.step(-1);
</handler>
</view>
<method name="_setShownItems" args="n">
this.shownitems = n;
if ( onshownitems ) this.onshownitems.sendEvent();
if ( this._initcomplete ) this.adjustmyheight();
</method>
<method name="select" args="v">
// ensure selected is scrolled to visible
var sel = v;
if (sel && sel['length'] > 0) {
sel = sel[0];
}
ensureItemInView(sel);
super.select(v);
</method>
<method name="_doFocus" args="ignore">
super._doFocus(ignore);
if (! this.__focusfromchild) {
var sel = getSelection();
if (this.multiselect) {
sel = (sel.length == 0) ? null : sel[0];
}
ensureItemInView(sel);
}
</method>
<method name="ensureItemInView" args="item">
if (!item) return;
if (_initcomplete) {
_selector.ensureItemInView(item);
}
</method>
<attribute name="_itemheight" value="null
"/>
<method name="calcMyHeight">
var len = getNumItems();
if (len == 0) {
return this.minheight;
}
var hgt;
if ((( shownitems > -1 ) && ( shownitems < len )) ||
dataoption == "lazy" || dataoption == "resize"
) { // lazy always has shownitems > -1 (if no set height)
var iheight;
if (this.dataoption == "lazy" || dataoption == "resize") {
iheight = this._itemheight;
if (shownitems < len) len = shownitems;
} else {
len = shownitems;
iheight = this.interior.content.subviews[0].height;
}
hgt = iheight*len + spacing*(len-1);
} else {
hgt = this.interior.content.height;
}
return hgt;
</method>
<attribute name="_hasSetHeight" value="false
"/>
<attribute name="_heightinternal" value="false
" type="boolean"/>
<setter name="height" args="h">
if (h != null && !this._heightinternal) {
this._hasSetHeight = true;
} else {
this._hasSetHeight = false;
if (!this._heightinternal) {
var hgt = this.calcMyHeight();
h = hgt + border_top + border_bottom;
}
}
super.setAttribute('height', h);
if ( this._initcomplete ) {
interior.setAttribute('height', h - border_top - border_bottom );
checkscrollbar();
}
</setter>
<method name="checkscrollbar">
if (this.autoscrollbar) {
if ( this._contentview.height > this.interior.height ) {
this.interior.showvscrollbar();
} else {
this.interior.hidevscrollbar();
}
}
</method>
<method name="adjustmyheight">
if ( !this._initcomplete ) return;
if (this._hasSetHeight) {
checkscrollbar();
} else {
var hgt = this.calcMyHeight();
this._heightinternal = true;
this.setAttribute('height', hgt + border_top + border_bottom);
this._heightinternal = false;
}
</method>
<method name="addItem" args="txt, val=null">
if (this.itemclassname == "") {
this.setAttribute("itemclassname", "textlistitem");
}
super.addItem(txt,val);
this.adjustmyheight();
</method>
<attribute name="_setbordercolor" value="false
" type="boolean"/>
<attribute name="_bgcolor" value="null
"/>
<setter name="bgcolor" args="c">
if (this._setbordercolor) {
super.setAttribute('bgcolor', c);
}
else {
// DON'T call the super setter, 'interior' view
// sets its bgcolor from this attribute
this._bgcolor = c;
var event = this['onbgcolor'];
if (event && event.ready) {
event.sendEvent(c);
}
}
</setter>
<method name="_applystyle" args="s">
if (this.style != null) {
super._applystyle(s);
this._setbordercolor = true;
this.setAttribute('bgcolor', s.bordercolor);
this._setbordercolor = false;
if (this._bgcolor == null) this.interior.setAttribute('bgcolor', s.bgcolor);
}
</method>
<method name="destroy">
if (this.autoscrollbar)
this.setAttribute("autoscrollbar", false);
if (this.shownitems != -1)
this.setAttribute("shownitems", -1);
super.destroy();
</method>
<doc>
<tag name="shortdesc"><text>
contains listitems and provides selection capabilities.
</text></tag>
<text>
<p>The <tagname>list</tagname> tag creates a list which may contain
<tagname>listitem</tagname>s. Subclasses of
<classname>listitem</classname>, such as
<classname>textlistitem</classname>, may be used as well.
<tagname>list</tagname> provides basic layout and a selection API
. If there are more items than specified in the
<attribute>shownitems</attribute> attribute, a
<classname>scrollbar</classname> will be provided.</p>
<example>
<canvas height="100">
<list x="10" y="10">
<textlistitem text="item 1" value="1" selected="true"/>
<textlistitem text="item 2" value="2"/>
<textlistitem text="item 3" value="3"/>
</list>
</canvas>
</example>
<h2>Optimizing performance with lazy replication and data pooling</h2>
<p>When you have more items on your list than appear to the user, or if you are creating a list from data and then changing
the data that is represented by the list, you should use "lazy replication" and data pooling, respectively, to
optimize performance of your lists. See <a href="${dguide}performance-tuning.htm}">Performance Tuning</a> for a discussion.</p>
<p>See the <a href="${examples}components/list_example.lz}">list_example.lzx</a> for
more list use cases.</p>
</text>
</doc>
</class>
</library>
Cross References
Includes
Classes
- <class name="list" extends="baselist">