gridsliderlayout.lzx
<library>
<class name="gridsliderlayout" extends="layout">
<attribute name="spacing" value="0
" setter="this.spacing = spacing"/>
<attribute name="cols" value="6
" setter="this.cols = cols"/>
<attribute name="rows" value="6
" setter="this.set_rows(rows);"/>
<attribute name="doanimation" value="false
"/>
<attribute name="duration" value="300
"/>
<attribute name="displaymode" value="grid
" type="string"/>
<attribute name="openrow_only" value="false
"/>
<attribute name="opencol_only" value="false
"/>
<attribute name="openview" value="null
"/>
<attribute name="openrow" value="-1
" setter="this.setopenrow(openrow)"/>
<attribute name="opencol" value="-1
" setter="this.setopencol(opencol)"/>
<attribute name="displayrow" value="-1
"/>
<attribute name="displaycol" value="-1
"/>
<attribute name="addedOpenWidth" value="150
"/>
<attribute name="addedOpenHeight" value="170
"/>
<attribute name="cw" type="number" value="0
"/>
<attribute name="ch" type="number" value="0
"/>
<attribute name="cellwidth" type="number" value="0
"/>
<attribute name="cellheight" type="number" value="0
"/>
<attribute name="lastsel" value="${null}"/>
<handler name="oninit">
// Create delegates used by the update method.
this.doupdateDelegate = new LzDelegate(this, "doupdate");
this.doupdateDelegate.register( immediateparent, "onwidth");
this.doupdateDelegate.register( immediateparent, "onheight");
this.resetvisDL = new LzDelegate(this,'resetVisibility');
</handler>
<method name="addSubview" args="v">
super.addSubview(v);
v.col = (this.subviews.length - 1) % 7;
v.row = Math.floor((this.subviews.length - 1)/ 7);
</method>
<method name="set_rows" args="r">
if (this['rows'] != r) {
this.rows = r;
this.doupdate(null);
}
</method>
<method name="setopen" args="row,col,withupdate">
// create a reference to the view at row,col
var newView = this.subviews[this.cols*row + col];
// call setopen with new view reference
setopenview(newView,withupdate);
</method>
<event name="onopenstart"/>
<event name="onclosestart"/>
<method name="setopenview" args="v,withupdate">
this.locked = true;
if (this.openview)
if (this.openview!=v){
// Save a reference to close the view later
// by sending an 'onclosestart' event
this.closedview=this.openview;
this.openview['onclosestart']['sendEvent']();
}
this.openview = v;
if (v == null) {
this.openrow = -1
this.opencol = -1; }
else {
this.openrow = v.row;
this.opencol = v.col;
// will send the event 'onopenstart' later
// once the grid is finished updating
this.openview['onopenstart']['sendEvent']();
}
this.locked = false;
if (this.displaymode == 'grid') doanimation = false;
if (withupdate) this.doupdate(null);
</method>
<method name="setopenrow" args="row">
// using brackets avoids the undefined warning in the Debugger
if (this['openrow'] == row) { return; }
this.openrow = row;
this.doupdate(null);
</method>
<method name="setopencol" args="col">
// using brackets avoids the undefined warning in the Debugger
if (this['opencol'] == col) { return; }
this.opencol = col;
this.doupdate(null);
</method>
<method name="showcell" args="row,col">
this.locked = true;
// set the open view
this.setopen(row,col,false);
// Set these to only display one cell fully
this.openrow_only = true;
this.opencol_only = true;
this.locked = false;
this.displaymode = 'cell';
this.doanimation = true;
this.doupdate(null);
</method>
<method name="showrow" args="row">
if (row) this.displayrow = row
else this.displayrow = 0;
this.locked = true;
this.openrow_only = true;
if (this.displaymode == 'row') {
// Already in 'row' mode so close openday to make
// the columnm widths all same size
this.opencol_only = false;
this.setopenview(null,false);
} else if (this.openrow != row) {
// not in 'week' display mode
// the opened row is different than the one
// that will be shown, so close day
// and expand row.
this.openrow_only = true;
this.displaymode = 'row';
this.setopenview(null,false);
} else {
// the opened row is the same as the row to be
// expanded so just make sure there is no column only focus.
this.opencol_only = false;
}
this.doanimation = true;
this.locked = false;
this.doupdate(null);
this.displaymode = 'row';
</method>
<method name="showgrid" args="noanimation">
this.displayrow = -1;
this.displaycol = -1;
if ( this.displaymode == "grid" ) {
// if gridslider already in grid mode, close cell
// without animation
this.doanimation = false;
if (this.openview) {
this.doanimation = false;
this.setopenview(null,false);
}
} else {
this.doanimation = true;
this.openrow_only = false;
this.opencol_only = false;
if (this.opencol < 0) this.openrow = -1;
}
if(noanimation) this.doanimation = false;
this.doupdate(null);
this.displaymode = "grid";
</method>
<event name="onupdatestart"/>
<method name="doupdate" args="v">
if ( this['locked'] ) { return }
if (this.onupdatestart) {
this.onupdatestart.sendEvent(this.openview);
}
// store a local value for fast reference
var didAnimation=false;
// [bshine 10.01.06] uh-oh, we re-declare w and h below
var w = immediateparent.width;
var h = immediateparent.height;
// the values for 'this.rows' and 'this.cols' were set in calgrid.calcBoundaryDates()
var nrows = this.rows;
var ncols = this.cols < this.subviews.length ? this.cols : this.subviews.length;
// store a local value for fast reference
var fr = this.openrow < 0 ? this.displayrow : this.openrow;
var fc = this.opencol < 0 ? this.displaycol : this.opencol;
// This is the what each (cw=colwidth) and (ch=columnheight) should be with no open
this.cw = Math.floor((w - this.spacing*(ncols-1))/ncols);
this.ch = Math.floor((h - this.spacing*(nrows-1))/nrows);
// If there is a column open then that column will be wider than the rest
// so adjust this difference.
var k = this.opencol < 0 ? 0 : 1;
this.cellwidth = cw - Math.floor((k*this.addedOpenWidth )/(ncols - 1));
this.cellheight = ch - Math.floor((k*this.addedOpenHeight)/(nrows - 1));
// Set the intialis values for the first view in the grid
var x = 0; var y = 0; var w = 0; var h = 0;
var i = 0; // start the index counter at 0
// if only a row and/or column is being displayed ignore the spacing in that dimension
var hspace = openrow_only ? 0 : this.spacing;
var wspace = opencol_only ? 0 : this.spacing;
// iterate once through entire subviews
for (var rowi = 0; rowi < nrows; rowi++) {
x=0; // the initial position of the subview for this row
// First if this row is the opened row then set its appropriate height
if (openrow_only) { // 'only' means all other rows will be invisible... h=0;
if (rowi == fr) h = immediateparent.height;
else h = 0;
} else if (rowi != fr) {
h = cellheight;
} else {
h = ch + this.addedOpenHeight;
}
// Now for each column in this row...
// set its appropriate width
for (var coli = 0; coli < ncols; coli++) {
var s = this.subviews[i];
if (opencol_only) {
if (coli == fc) w = immediateparent.width - this.spacing;
else w = 0;
} else if (coli != fc) {
w = cellwidth;
} else {
w = cw + this.addedOpenWidth;
}
// Now using the values above update the subview.
// A zero width and height implies that the subview should be set
// to be invisible WITHOUT actually setting its height and width.
// This avoids activating contraints
var vis = (w > 0) && (h > 0);
if (vis) {
if (this.doanimation) {
if (!s.visible) {
if (s.x != x) s.setAttribute('x', x);
if (s.y != y) s.setAttribute('y', y);
if (s.width != w) s.setAttribute('width', w);
if (s.height != h) s.setAttribute('height', h);
// To speed up the process only the currently visible
// views are animated, while the hidden views are
// given there final dimensions and then popped into view
// at the end of the animations. called by the 'delayvisDL'
// delegate.
s.update_vis_later = true;
} else {
s.animateTo(x, y, w, h);
didAnimation=true;
}
} else {
if (s.x != x) s.setAttribute('x', x);
if (s.y != y) s.setAttribute('y', y);
if (s.width != w) s.setAttribute('width', w);
if (s.height != h) s.setAttribute('height', h);
if (!s.visible) s.setAttribute('visible', true);
}
} else {
if (rowi ==0) {
// move the top row even though its invisible so that the
// headers for the day of week (which are constrained to the
// top row) move correctly. only need width and x info.
if (this.doanimation) {
s.animateTo(x, s.y, w, s.height);
} else {
if (s.x != x) s.setAttribute('x', x);
if (s.width != w) s.setAttribute('width', w);
}
}
if (s.visible) s.setAttribute('visible', false);
s.update_vis_later = false;
}
i++; //increment index counter
if (i >= this.subviews.length) { break; }
x += w + wspace; // increment the x value for the next subview in this row
}
if (i >= this.subviews.length) { break; }
y += h + hspace;
}
// Check to see if we need the last row, and if not hide these days
if (nrows == 5) { // hide last row
for (var c = 35; c < 42; c++) {
this.subviews[c].setAttribute('visible', false);
this.subviews[c].update_vis_later = false;
}
}
// When the layout is in its completed state,
// correct the visibility of all of the calendar cells.
// We can do this right way if there wasn't any animation...
if (!didAnimation)
this.resetVisibility(null);
else { // if we started some animation, wait until it finishes
// to reset the visibility.
// We know that the animations are set to 500 ms,
// so we wait a little tiny bit longer than that,
// then call this delegate to correct visibility.
// [bshine 10.01.06] Instead of a constant delay and a timer,
// here, we could put an onstop delegate on an animator, but
// this way is simpler. Less flexibile, but simpler.
lz.Timer.addTimer(this.resetvisDL,600); }
super.update();
</method>
<event name="onupdatestop"/>
<method name="resetVisibility" args="v">
// Debug.write("resetting visibility");
// Now show the views that were hidden
var s;
for (var i =0; i < this.subviews.length; i++) {
s = this.subviews[i];
if (s['update_vis_later']){
if (!s.opened && s.details.bgrect.container.dataview) s.details.bgrect.container.dataview.setAttribute('y', 0);
s.setAttribute('visible', true);
}
}
//this['closedview']['onclosestart']['sendevent']();
//this['openview']['onopenstart']['sendevent']();
// Process is complete so send onupdatestop event
this['onupdatestop']['sendEvent'](this.openview);
</method>
<method name="startTrack">
if ( ! this[ 'positiondel' ] ){
this.positiondel = new LzDelegate( this , "checkMousePosition" );
}
this.positiondel.register( lz.Idle , "onidle" );
</method>
<method name="stopTrack">
this.positiondel.unregisterAll( );
if ( lastsel != null ){
lastsel.hilite(false, false);
lastsel.acceptDrop();
} else {
//cancel drop
}
</method>
<method name="checkMousePosition" args="v">
//this runs every frame while dragging -- it's private to the layout
var x = immediateparent.getMouse( 'x' );
var y = immediateparent.getMouse( 'y' );
var s;
//if it's not on the grid
if ( x < 0 || x > parent.width
|| y < 0 || y > parent.height ) {
s = null;
}else if ( this.openrow_only ){
//grid special condition
if ( this.opencol_only ){
//in day only view
s = this.subviews[ this.cols * openrow + opencol ];
} else {
//in week view
var newcol = Math.floor( x/ (cellwidth + spacing ) );
if ( opencol != -1 && newcol > opencol ){
var rightedge = ( opencol * ( spacing + cellwidth ) )+ cw + addedOpenWidth;
if ( x < rightedge ) {
newcol = opencol;
} else {
newcol = opencol + 1 + Math.floor( ( x - rightedge ) / (cellwidth + spacing ) );
}
}
s = this.subviews[ this.cols * displayrow + newcol ];
}
} else {
var newcol = Math.floor( x/ (cellwidth + spacing ) );
if ( opencol != -1 && newcol > opencol ){
var rightedge = ( opencol * ( spacing + cellwidth ) )+ cw + addedOpenWidth;
if ( x < rightedge ) {
newcol = opencol;
} else {
newcol = opencol + 1 + Math.floor( ( x - rightedge ) / (cellwidth + spacing ) );
}
}
//this doesn't find the case where the mouse is over the spacing between cells
var newrow = Math.floor( y/ (cellheight + spacing ) );
if ( openrow != -1 && newrow > openrow ){
var bottom = ( openrow * ( spacing + cellheight ) )+ cw + addedOpenHeight;
if ( y < bottom ) {
newrow = openrow;
} else {
newrow = openrow + 1 + Math.floor( ( y - bottom ) / (cellheight + spacing ) );
}
}
s = this.subviews[ this.cols * newrow + newcol ];
}
if( s != this['lastsel'] ){
if (this['lastsel'] != null ){
lastsel.hilite(false, false);
}
this.lastsel = s;
// update the hilite
if (lastsel != null){
lastsel.hilite(true, false);
}
}
</method>
</class>
</library>