Revision: 4608 http://sourceforge.net/p/vexi/code/4608 Author: clrg Date: 2013-12-03 01:52:09 +0000 (Tue, 03 Dec 2013) Log Message: ----------- Completes the grid overhaul; now works in all known cases
Modified Paths: -------------- branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/grid.t branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve1.t branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve2.t Modified: branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/grid.t =================================================================== --- branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/grid.t 2013-11-29 16:03:37 UTC (rev 4607) +++ branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/grid.t 2013-12-03 01:52:09 UTC (rev 4608) @@ -70,6 +70,18 @@ const byCol = {}; const byRow = {}; + /* PLACING + * + * The effect of each child is measured against the region it + * occupies - the row/column boundary it is pushing. If this + * region changes then boxes in subsequent regions shift over. + * + * Note 1: (case solve2) + * There is a corner case where a spanning box occupies the + * end of an axis, pushing the next box into a region which + * has an origin with no matching frontier; so use origin-1. + */ + const placeRegions = function(axis, fullreach, gridsize, shrink, contentdim, mindim, maxdim, dim, pos) { const regions = axis.regions; const frontiers = axis.frontiers; @@ -93,10 +105,15 @@ const origin = region.origin; const frontier = region.frontier; - const priorMin = origin>0 ? frontierMin[origin] : 0; - const priorMax = origin>0 ? frontierMax[origin] : 0; - const currentMin = frontierMin[region.frontier]; - const currentMax = frontierMax[region.frontier]; + // see place note (1) + var priorMin = origin>0 ? frontierMin[origin] : 0; + if (priorMin == null) + priorMin = frontierMin[origin-1]; + var priorMax = origin>0 ? frontierMax[origin] : 0; + if (priorMax == null) + priorMax = frontierMax[origin-1]; + const currentMin = frontierMin[frontier]; + const currentMax = frontierMax[frontier]; if (currentMin == null or priorMin + minsize > currentMin) { contentMin = max(priorMin + minsize, contentMin); @@ -106,7 +123,9 @@ if (contentMax != vexi.ui.maxdim) { contentMax = min(vexi.ui.maxdim, max(priorMax + maxsize, contentMax)); frontierMax[frontier] = priorMax + maxsize; - } else frontierMax[frontier] = min(vexi.ui.maxdim, priorMax + maxsize); + } else { + frontierMax[frontier] = min(vexi.ui.maxdim, priorMax + maxsize); + } } } // by now we know our minimum/maximum size @@ -114,10 +133,14 @@ $content[maxdim] = contentMax; // PHASE 2: place wrapper boxes in accordance with region/frontier min/max sizes - if (thisbox[shrink] or $content[mindim] >= gridsize) { + if (thisbox[shrink] or contentMin >= gridsize) { // honor min sizes for (var i,region in regions.list) { - const regionPos = region.origin>0 ? frontierMin[region.origin] : 0; + const origin = region.origin; + // see place note (1) + var regionPos = origin>0 ? frontierMin[origin] : 0; + if (regionPos == null) + regionPos = frontierMin[origin-1]; const regionDim = frontierMin[region.frontier] - regionPos; for (var j,box in region.boxes) { box[pos] = regionPos; @@ -125,10 +148,14 @@ } } } else - if (gridsize >= $content[maxdim]) { + if (gridsize >= contentMax) { // honor max sizes for (var i,region in regions.list) { - const regionPos = region.origin>0 ? frontierMax[region.origin] : 0; + const origin = region.origin; + // see place note (1) + var regionPos = origin>0 ? frontierMax[origin] : 0; + if (regionPos == null) + regionPos = frontierMax[origin-1]; const regionDim = frontierMax[region.frontier] - regionPos; for (var j,box in region.boxes) { box[pos] = regionPos; @@ -173,7 +200,10 @@ target = minsize; } else { target = targetSize * reach; - const o_index = f2i[origin]; + // see place note (1) + var o_index = f2i[origin]; + if (o_index == null) + o_index = f2i[origin-1]; if (target > minsize) for (var i=f_index; i>o_index; i--) @@ -186,7 +216,11 @@ else target = maxsize; } - const frontierPush = frontierDim[origin] + target; + var originDim = frontierDim[origin]; + // see place note (1) + if (originDim == null) + originDim = frontierDim[origin-1]; + const frontierPush = originDim + target; if (frontier!=lastFrontier or frontierPush > frontierDim[frontier]) frontierDim[frontier] = frontierPush; lastFrontier = frontier; @@ -210,8 +244,9 @@ // no rows to be further decreased in size throw "Should not be possible"; } + var ts = targetSize; // else adjust targetRowSize according to target-total deficit - targetSize += ((totalSize-gridsize) / reachDown); + targetSize -= ((totalSize-gridsize) / reachDown); } else { // too small; adjust up @@ -224,12 +259,14 @@ // no rows to be further increased in size throw "Should not be possible"; } + var ts = targetSize; // adjust targetRowSize according to target-total deficit targetSize += ((gridsize-totalSize) / reachUp); } + if (i>=99) { // infinite loop prevention - vexi.log.warn("failed to solve grid "+dim+" "+fullreach); + vexi.log.warn("failed to solve grid "+dim+" "+thisbox[dim]+" with rows/cols:"+fullreach); } } @@ -238,25 +275,21 @@ // place our boxes for (var i,region in regions.list) { - const regionPos = round(frontierDim[region.origin]); - const targetDim = round(frontierDim[region.frontier]) - regionPos; - const regionDim = min(region.maxsize, max(region.minsize, targetDim)); + const origin = region.origin; + // see place note (1) + var regionPos = frontierDim[origin]; + if (regionPos == null) + regionPos = frontierDim[origin-1]; + const roundPos = round(regionPos); + const roundDim = round(frontierDim[region.frontier]) - roundPos; for (var j,box in region.boxes) { - box[pos] = regionPos; - box[dim] = regionDim; + box[pos] = roundPos; + box[dim] = roundDim; } } } } - /* - * PLACING - * - * The effect of each child is measured against the region it - * occupies - the row/column boundary it is pushing. If this - * region changes then boxes in subsequent regions shift over. - */ - const place = function() { if (!numcols or !numrows) { // not yet initialized @@ -272,14 +305,13 @@ } } - /* - * PACKING + /* PACKING * * Here we pack the child boxes as close together as their row- - * and col-span will allow. The packing is done according to - * the setting of the user - if they set rows then we pack the + * and col-span will allow. The packing approach is determined + * by which grid property is the set - if 'rows' then pack the * children down the number of rows and accomodate children by - * adding extra columns. + * adding extra columns, and vice versa for 'cols'. */ /** establish an ordered list of frontiers for placing */ @@ -314,17 +346,16 @@ establishFrontier(byRow.frontiers, rowfrontier); } - /** pack by column first, expanding rows as required */ - const packByCol = function() { - const frontier = new .vector(); - var nextcol = 0; // the next available col - var nextrow = 0; // the next available row - var minrows = 0; // the minimum row past a frontier box - var c, c0; var f, f0; + /** pack by primary axis (e.g. column) first, expanding secondary axis (e.g. rows) as required */ + const packAxis = function(mainAxis, mainSpan, v_mainAxis, growAxis, growSpan, v_growAxis) { + const frontier = new vexi.js.ProxyList(); + var nextMain = 0; // the next available col + var nextGrow = 0; // the next available row + var minFront = 0; // the minimum row past a frontier box // assign col/row values to packed children for (var i,c in $content) { - c0 = c[0]; + const c0 = c[0]; if (!c0.display) { // disregard hidden children @@ -334,176 +365,80 @@ c.display = true; } - if (nextcol!=0 and nextcol+c0.colspan > setsize) { + if ((nextMain!=0) and (nextMain+c0[mainSpan] > setsize)) { // if we don't fit on the row, jump to the next - nextcol=0; - nextrow++; + nextMain=0; + nextGrow++; } // check to see if we are making a full pass at the row - const fullpass = nextcol==0; + const fullpass = nextMain==0; // work through frontier boxes until a suitable position is found PACKME: while (frontier.length>0) { - f = frontier.first; - while (f != null) { - f0 = f[0]; - if (nextrow >= f0.v_row+f0.rowspan) { + var fKey = 0; + var f0 = frontier[fKey]; + while (f0 != null) { + if (nextGrow >= f0[v_growAxis]+f0[growSpan]) { // reduce frontier by removing boxes not affecting the frontier row - f0 = frontier.after(f); - frontier.remove(f); - f = f0; + frontier[fKey] = null; + f0 = frontier[fKey]; continue; } - if (f0.v_col+f0.colspan > nextcol and nextcol+c0.colspan > f0.v_col) { - // frontier not accomdating current child, look further + if ((f0[v_mainAxis] + f0[mainSpan] > nextMain) and + (nextMain + c0[mainSpan] > f0[v_mainAxis])) { + // frontier not accomodating current child, look further // establish next available col - nextcol = f0.v_col+f0.colspan; + nextMain = f0[v_mainAxis] + f0[mainSpan]; // establish next available row - minrows = (minrows == 0) ? f0.v_row+f0.rowspan : min(minrows, f0.v_row+f0.rowspan); + minFront = (minFront == 0) ? f0[v_growAxis] + f0[growSpan] + : min(minFront, f0[v_growAxis] + f0[growSpan]); - if (nextcol+c0.colspan > setsize) { - // c will not fit on nextrow + if (nextMain + c0[mainSpan] > setsize) { + // c will not fit on nextsec if (!fullpass) { // if not a full pass, try next immediate row - nextrow++; - nextcol=0; - minrows=0; + nextGrow++; + nextMain = 0; + minFront = 0; } else { // try c on next available row - nextcol=0; - nextrow=minrows; - minrows=0; + nextMain = 0; + nextGrow = minFront; + minFront = 0; } // try frontier again continue PACKME; } - } else if (f0.v_col >= nextcol+c0.colspan) { + } else if (f0[v_mainAxis] >= nextMain + c0[mainSpan]) { // fit between previous frontier and this frontier break PACKME; } // next frontier - f = frontier.after(f); + f0 = frontier[++fKey]; } - if (setsize >= nextcol+c0.colspan) { + if (setsize >= nextMain + c0[mainSpan]) { // fits in the col after frontier break; } } - if (c0.rowspan>1) { + if (c0[growSpan] > 1) { // add to frontier if we affect the frontier - if (f) { - f = frontier.before(f); - if (f) { - frontier.insert(c, f); - } else { - frontier.unshift(c); - } + if (f0) { + frontier[fKey] = c0; } else { - frontier.push(c); + frontier[frontier.length] = c0; } } // place packed child - assignSlot(c, nextcol, nextrow); + assignSlot(c, nextMain, nextGrow); // prepare for next iteration - minrows = 0; // reset minrows - nextcol += c0.colspan; // bump up nextcol - // update the number of rows - numrows = max(numrows, c0.v_row+c0.rowspan); + minFront = 0; // reset minFront + nextMain += c0[mainSpan]; // bump up nextMain } } - /** pack by row first - for comments see packByCol **/ - var packByRow = function() { - var frontier = new .vector(); - var nextrow = 0; // the next available row - var nextcol = 0; // the next available col - var mincols = 0; // the minimum col past a frontier box - var c, c0; var f, f0; - - // assign row/col values to packed children - for (var i,c in $content) { - c0 = c[0]; - // disregard hidden children - if (!c0.display) { - c.display = false; - continue; - } else { - c.display = true; - } - if (nextrow!=0 and nextrow+c0.rowspan > setsize) { - // does not fit in the column, jump to next row - nextrow=0; - nextcol++; - } - - // check to see if we are making a full pass at the col - const fullpass = nextrow==0; - - // work through frontier boxes until a suitable position is found - PACKME: while (frontier.length>0) { - f = frontier.first; - while (f != null) { - f0 = f[0]; - if (nextcol >= f0.v_col+f0.colspan) { - // reduce frontier by removing boxes not affecting the frontier col - f0 = frontier.after(f); - frontier.remove(f); - f = f0; - continue; - } - if (nextrow+c0.rowspan > f0.v_row and f0.v_row+f0.rowspan > nextrow) { - // frontier not accomdating current child, look further - - // establish next available row - nextrow = f0.v_row+f0.rowspan; - // establish next available col - mincols = (mincols == 0) ? f0.v_col+f0.colspan : min(mincols, f0.v_col+f0.colspan); - - if (nextrow+c0.rowspan > setsize) { - // c will not fit on nextcol - if (!fullpass) { - // if not a full pass, try next immediate col - nextrow++; nextcol=0; minrows=0; - } else { - // try c on next available col - nextrow=0; nextcol=mincols; mincols=0; - } - // try frontier again - continue PACKME; - } - } else if (f0.v_row >= nextrow+c0.rowspan) { - // fit between previous frontier and this frontier - break PACKME; - } - // next frontier - f = frontier.after(f); - } - if (setsize >= nextrow+c0.rowspan) { - // fits on this row after frontier - break; - } - } - if (c0.colspan>1) { - // add to frontier if we affect the frontier - if (f) { - f = frontier.before(f); - if (f) { - frontier.insert(c, f); - } else { - frontier.unshift(c); - } - } else frontier.push(c); - } - // place packed child - assignSlot(c, nextcol, nextrow); - // prepare for next iteration - mincols = 0; // reset mincols - nextrow += c0.rowspan; // bump up nextrow - } - } - const getIndice = function(axis) { const f2i = {}; for (var i,f in axis.frontiers) @@ -525,7 +460,9 @@ byRow.regions = new Regions(); byRow.frontiers = []; // pack! - userows ? packByRow() : packByCol(); + if (userows) + packAxis("row", "rowspan", "v_row", "col", "colspan", "v_col"); + else packAxis("col", "colspan", "v_col", "row", "rowspan", "v_row"); getIndice(byCol); getIndice(byRow); pack_children = false; Modified: branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve1.t =================================================================== --- branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve1.t 2013-11-29 16:03:37 UTC (rev 4607) +++ branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve1.t 2013-12-03 01:52:09 UTC (rev 4608) @@ -3,24 +3,28 @@ <grid id="grid" cols="6" width="766" height="250"> <ui:box colspan="1" minwidth="35" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="59" hshrink="false" minheight="26" vshrink="true" /> - <ui:box colspan="1" minwidth="40" hshrink="true" minheight="26"vshrink="true" /> + <ui:box colspan="1" minwidth="40" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="128" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="41" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="73" hshrink="true" minheight="26" vshrink="true" /> + <ui:box colspan="1" minwidth="51" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="59" hshrink="false" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="67" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="3" minwidth="59" hshrink="false" minheight="26" vshrink="true" /> + <ui:box colspan="1" minwidth="60" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="17" hshrink="false" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="41" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="17" hshrink="false" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="36" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="17" hshrink="false" minheight="26" vshrink="true" /> + <ui:box colspan="1" minwidth="38" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="39" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="1" minwidth="0" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="3" minwidth="0" hshrink="true" minheight="26" vshrink="true" /> + <ui:box colspan="1" minwidth="45" hshrink="true" minheight="26" vshrink="true" /> <ui:box colspan="5" minwidth="57" hshrink="false" minheight="26" vshrink="false" /> </grid> Modified: branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve2.t =================================================================== --- branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve2.t 2013-11-29 16:03:37 UTC (rev 4607) +++ branches/vexi3/org.vexi-vexi.widgets/src_test/test/layout/grid/solve2.t 2013-12-03 01:52:09 UTC (rev 4608) @@ -34,7 +34,8 @@ <ui:box text="9" /> <wi:textfield text="9" /> - <ui:box text="10" rowspan="4" /> + + <ui:box text="10" rowspan="4" fill="red" /> <wi:textarea text="10" colspan="3" rowspan="4" /> <ui:box text="11" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Rapidly troubleshoot problems before they affect your business. Most IT organizations don't have a clear picture of how application performance affects their revenue. With AppDynamics, you get 100% visibility into your Java,.NET, & PHP application. Start your 15-day FREE TRIAL of AppDynamics Pro! http://pubads.g.doubleclick.net/gampad/clk?id=84349351&iu=/4140/ostg.clktrk _______________________________________________ Vexi-svn mailing list Vexi-svn@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/vexi-svn