Revision: 4605
          http://sourceforge.net/p/vexi/code/4605
Author:   clrg
Date:     2013-11-29 15:11:07 +0000 (Fri, 29 Nov 2013)
Log Message:
-----------
Rewrite of grid to work across both regions and frontiers. Update grid demo.

Modified Paths:
--------------
    branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/grid.t
    branches/vexi3/org.vexi-vexi.demo/src_poke/testfeature.t
    branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/grid.t

Removed Paths:
-------------
    branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/inner/grid_block.t

Modified: 
branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/grid.t
===================================================================
--- branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/grid.t     
2013-11-29 15:08:38 UTC (rev 4604)
+++ branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/feature/grid.t     
2013-11-29 15:11:07 UTC (rev 4605)
@@ -1,7 +1,9 @@
-<!-- Copyright 2007 - see COPYING for details [LGPL] -->
+<!-- Copyright 2013 - see COPYING for details [LGPL] -->
 
-<vexi xmlns:ui="vexi://ui" xmlns:lay="vexi.layout" xmlns="vexi.widget"
-    xmlns:demo="org.vexi.demo">
+<vexi xmlns:ui="vexi://ui"
+      xmlns:lang="vexi://lang"
+      xmlns:lay="vexi.layout"
+      xmlns="vexi.widget">
     
     static.name = "Grid";
     static.category = "Layout";
@@ -31,9 +33,9 @@
                 <button id="create" hshrink="false" text="Create" />
                 <separator />
                 <ui:box text="Colspan:" />
-                <spin width="50" id="colspan" minvalue="1" maxvalue="20" 
value="1" />
+                <spin width="50" id="colspan" minvalue="1" maxvalue="20" />
                 <ui:box text="Rowspan:" />
-                <spin width="50" id="rowspan" minvalue="1" maxvalue="20" 
value="1" />
+                <spin width="50" id="rowspan" minvalue="1" maxvalue="20" />
                 <separator />
                 <button id="moveup" hshrink="false" text="Move up" />
                 <button id="movedown" hshrink="false" text="Move down" />
@@ -41,16 +43,43 @@
             </ui:box>
             <bevel id="bvl" form="down" margintop="5" marginleft="5">
                 <scrollpane autohide="true">
-                    <lay:grid id="grid" cols="6" />
+                    <lay:grid id="grid" /> // cols initialized by reset
                 </scrollpane>
             </bevel>
         </ui:box>
         
+        <lang:subtemplate property="GridBlock">
+            <border border="black" cursor="hand" depth="2" fill="white" 
layout="place">
+                <ui:box orient="vertical" shrink="true">
+                    <ui:box shrink="true" id="boxindex" />
+                    <ui:box shrink="true">
+                        <ui:box id="boxcol" />
+                        <ui:box id="boxcolspan" />
+                    </ui:box>
+                    <ui:box shrink="true">
+                        <ui:box id="boxrow" />
+                        <ui:box id="boxrowspan" />
+                    </ui:box>
+                </ui:box>
+                
+                thisbox.v_col   ++= function(v) { cascade = v; $boxcol.text = 
" Col: "+v; }
+                thisbox.colspan ++= function(v) { cascade = v; 
$boxcolspan.text = ", Span: "+v+" "; }
+                thisbox.v_row   ++= function(v) { cascade = v; $boxrow.text = 
" Row: "+v; }
+                thisbox.rowspan ++= function(v) { cascade = v; 
$boxrowspan.text = ", Span: "+v+" "; }
+                thisbox.index   ++= function(v) { cascade = v; $boxindex.text 
= " Index: "+v+" "; }
+                
+                thisbox.selected ++= function(v) { cascade = v; fill = v ? 
"#ffeedd" : "white"; }
+                
+            </border>
+        </lang:subtemplate>
+        
         thisbox.selected ++= function(v) {
             cascade = v;
-            $delete.enabled = (selected != null);
-            $moveup.enabled = (selected != null);
-            $movedown.enabled = (selected != null);
+            $delete.enabled = (v != null);
+            $moveup.enabled = (v != null);
+            $movedown.enabled = (v != null);
+            $colspan.value = v?v.colspan:1;
+            $rowspan.value = v?v.rowspan:1;
         }
         selected = null;
         
@@ -67,11 +96,11 @@
         }
         
         $create.action ++= function(v) {
-            var b = demo.inner.grid_block(vexi.box);
+            var b = new GridBlock();
             b.colspan = $colspan.value;
             b.rowspan = $rowspan.value;
             b.Press1 ++= selectWrite;
-            $grid[$grid.numchildren] = b;
+            $grid.add(b);
             return;
         }
         
@@ -87,20 +116,29 @@
             return;
         }
         
+        const updateIndice = function() {
+            for (var i,b in $grid) {
+                b.index = i;
+            }
+        }
+        
         $delete.action ++= function(v) {
             selected.thisbox = null;
+            updateIndice();
             return;
         }
         
-        $moveup.action ++= function(v) {
+        $movedown.action ++= function(v) {
             var i = $grid.indexof(selected);
             if (i>0) $grid[i-1] = selected;
+            updateIndice();
             return;
         }
         
         $moveup.action ++= function(v) {
             var i = $grid.indexof(selected);
             if ($grid.numchildren>i+1) $grid[i+1] = selected;
+            updateIndice();
             return;
         }
         
@@ -119,11 +157,16 @@
             if (v == null) {
                var _v = $grid[trapname];
                if (_v == selected) selected = null;
+            } else {
+               // adding
+               v.index = trapname;
             }
             cascade = v;
         }
         
         var startGrid = [ [1,1], [2,1], [1,1], [1,2], [1,2], [3,2], [1,1], 
[1,1] ];
+        // the below starting grid only occupies 4 of the 5 available columns
+        //var startGrid = [ [1,1], [1,1], [1,1], [1,2], [2,1], [1,2], [3,2], 
[1,1] ];
         
         $reset.action ++= function(v) {
             $clear.action = true;
@@ -131,7 +174,7 @@
             $use.value = 5;
             var l = startGrid.length;
             for (var i=0; l>i; i++) {
-                var b = demo.inner.grid_block(vexi.box);
+                var b = new GridBlock();
                 b.colspan = startGrid[i][0];
                 b.rowspan = startGrid[i][1];
                 b.Press1 ++= selectWrite;

Deleted: 
branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/inner/grid_block.t
===================================================================
--- branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/inner/grid_block.t 
2013-11-29 15:08:38 UTC (rev 4604)
+++ branches/vexi3/org.vexi-vexi.demo/src_main/org/vexi/demo/inner/grid_block.t 
2013-11-29 15:11:07 UTC (rev 4605)
@@ -1,30 +0,0 @@
-<!-- Copyright 2007 - see COPYING for details [LGPL] -->
-
-<vexi xmlns:ui="vexi://ui" xmlns="vexi.layout">
-    <border border="black" depth="2" fill="white" layout="place">
-        <ui:box orient="vertical" shrink="true">
-            <ui:box shrink="true">
-                <ui:box text=" Col: " />
-                <ui:box id="col" />
-                <ui:box text=" Span: " />
-                <ui:box id="colspan" />
-                <ui:box text=" " />
-            </ui:box>
-            <ui:box shrink="true">
-                <ui:box text=" Row: " />
-                <ui:box id="row" />
-                <ui:box text=" Span: " />
-                <ui:box id="rowspan" />
-                <ui:box text=" " />
-            </ui:box>
-        </ui:box>
-        
-        thisbox.v_col ++= function(v) { $col.text = v; cascade = v; }
-        thisbox.colspan ++= function(v) { $colspan.text = v; cascade = v; }
-        thisbox.v_row ++= function(v) { $row.text = v; cascade = v; }
-        thisbox.rowspan ++= function(v) { $rowspan.text = v; cascade = v; }
-        
-        thisbox.selected ++= function(v) { cascade = v; fill = v ? "#ffeedd" : 
"white"; }
-        
-    </border>
-</vexi>

Modified: branches/vexi3/org.vexi-vexi.demo/src_poke/testfeature.t
===================================================================
--- branches/vexi3/org.vexi-vexi.demo/src_poke/testfeature.t    2013-11-29 
15:08:38 UTC (rev 4604)
+++ branches/vexi3/org.vexi-vexi.demo/src_poke/testfeature.t    2013-11-29 
15:11:07 UTC (rev 4605)
@@ -1,12 +1,18 @@
-<!-- Copyright 2007 - see COPYING for details [LGPL] -->
+<!-- public domain -->
 
 <vexi xmlns:ui="vexi://ui" xmlns="vexi.widget" xmlns:f="org.vexi.demo.feature">
     <surface />
     <ui:box>
+        
         // very simple template to open a feature in a frame
         var feature = vexi.params["feature"];
         if (feature==null) feature = "grid";
         thisbox[0] = f[feature](vexi.box);
+        
+        // or comment out the above and uncomment this
+        <!--f:testcase_grid2 /-->
+        
         vexi.ui.frame = thisbox;
+        
     </ui:box>
 </vexi>
\ No newline at end of file

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 15:08:38 UTC (rev 4604)
+++ branches/vexi3/org.vexi-vexi.widgets/src_main/org/vexi/lib/layout/grid.t    
2013-11-29 15:11:07 UTC (rev 4605)
@@ -1,348 +1,276 @@
-<!-- Copyright 2011 - see COPYING for details [LGPL] -->
+<!-- Copyright 2013 - see COPYING for details [LGPL] -->
 
-<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="vexi.util">
-    <meta:doc>
-        <author>Charles Goodwin</author>
-        <todo>
-            * hand out slack like the core does when packing
-            * use static functions to make grids lightweight
-            * potential optimization: do not restart frontier
-              checking if next child to pack has colspan gte
-              previous child (i.e. as big or bigger).
-        </todo>
-    </meta:doc>
-    
+<vexi xmlns:ui="vexi://ui"
+      xmlns:lang="vexi://lang"
+      xmlns:js="vexi://js"
+      xmlns="vexi.util">
+
     <ui:box layout="layer">
+        <!-- no redirect; it is managed by a Children trap -->
         <ui:box id="content" align="topleft" layout="place" />
         
+        <lang:subtemplate property="Regions">
+            <js:Object>
+                
+                /** A region is represented primarily by 2 facets
+                 *  - the origin i.e. box.col
+                 *  - the frontier it affects i.e. box.col+box.colspan
+                 
+                 *  As multiple boxes may affect the same region, it is
+                 *  convenient to group them together with the region
+                 */
+                const newRegion = function(box, origin, frontier) {
+                    return { boxes:[box], origin:origin, frontier:frontier };
+                }
+                
+                thisobj.list = new vexi.js.ProxyList();
+                
+                thisobj.add = function(box, origin, frontier) {
+                    for (var i=list.length; i>0; i--) {
+                        const region = list[i-1];
+                        if (region.frontier > frontier) continue;
+                        if (frontier == region.frontier) {
+                            if (region.origin > origin)
+                                continue;
+                            if (region.origin == origin) {
+                                region.boxes.push(box);
+                                return;
+                            }
+                        }
+                        list[i] = newRegion(box, origin, frontier);
+                        return;
+                    }
+                    // reached the end
+                    list[0] = newRegion(box, origin, frontier);
+                };
+                
+            </js:Object>
+        </lang:subtemplate>
+        
         /********************************
          ******** INTERNAL LOGIC ********
          ********************************/
         
-        var numcols = 0;
-        var numrows = 1;
-        var userows = true;
+        var numcols = 0; // these two vars
+        var numrows = 0; // are calcualated
         
+        var setsize = 1;    // these two vars represent
+        var userows = true; // the user-specified break
+        
         var pack_children = false;
+        var place_horizontal = false;
+        var place_vertical = false;
         
-        var min = function(a, b) { return a > b ? b : a; }
-        var max = function(a, b) { return a > b ? a : b; }
+        const min = function(a, b) { return a > b ? b : a; }
+        const max = function(a, b) { return a > b ? a : b; }
+        const round = vexi.math.round;
         
-        // used to track what regions of the grid a child affects
-        var colregions = new .orderedlist();
-        var colregrefs = {};
-        var rowregions = new .orderedlist();
-        var rowregrefs = {};
+        // container object for regions,frontiers,etc
+        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.
-         */
-        
-        var fromHAlign = function(a, v1, v2) {
-            if (a.indexOf("left") > -1) return v1;
-            if (a.indexOf("right") > -1) return v1+v2;
-            return v1+(v2/2); 
-        }
-        
-        var fromVAlign = function(a, v1, v2) {
-            if (a.indexOf("top") > -1) return v1;
-            if (a.indexOf("bottom") > -1) return v1+v2;
-            return v1+(v2/2); 
-        }
-        
-        var place = function(findwidths, findheights) {
-            if (!numcols or !numrows) {
-                return;
-            }
-            // honor min/max sizes for boxes in order of region
-            var n = $content.numchildren;
-            var c, c0;
-            var content;
-            var mindim;
-            var maxdim;
-            var minsizes;
-            var maxsizes;
-            var regmark;
-            var regions;
-            var rindmap;
-            var r1, r2;
-            var sizes;
+        const placeRegions = function(bySet, fullreach, gridsize, shrink, 
contentdim, mindim, maxdim, dim, pos) {
+            const regions = bySet.regions;
+            const frontiers = bySet.frontiers;
+            const f2i = bySet.frontier2index;
             
-            // child width solving
-            if (findwidths) {
-                // PHASE 1: honor min/max sizes for boxes in order of region
-                content = 0;
-                minsizes = [0];
-                maxsizes = [0];
-                regions = [0];
-                rindmap = {};
-                rindmap[0] = 0;
-                regmark = 1;
-                sizes = [0];
-                for (c = colregions.mark(); c != null; c = colregions.next()) {
-                    c0 = c[0];
-                    // bypass hidden children
-                    if (!c0.display) continue;
-                    r1 = rindmap[c0.v_col];
-                    r2 = rindmap[c0.v_col+c0.colspan];
-                    if (r2 == null) {
-                        // first to affect this region
-                        r2 = regmark;
-                        regions[r2] = c0.v_col+c0.colspan;
-                        rindmap[regions[r2]] = r2;
-                        minsizes[r2] = 0;
-                        maxsizes[r2] = 0;
-                        sizes[r2] = 0;
-                        content += minsizes[regmark-1];
-                        regmark++;
-                    }
-                    if (r2-r1 == 1) {
-                        // affect single region
-                        minsizes[r2] = max(c0.contentwidth, minsizes[r2]);
-                        maxsizes[r2] = max((c0.hshrink ? c0.contentwidth : 
c0.maxwidth), maxsizes[r2]);
-                    } else {
-                        // affect multiple regions
-                        mindim = c0.contentwidth;
-                        maxdim = c0.hshrink ? c0.contentwidth : c0.maxwidth;
-                        // work out the minimum size of this box's region
-                        // the box affects c.v_col+1 -> c.v_col+c.colspan
-                        for (var r=r1+1; r2>r; r++) {
-                            mindim -= minsizes[r];
-                        }
-                        minsizes[r2] = max(mindim, minsizes[r2]);
-                        // work out the maximum size of this box's region
-                        for (var r=r1+1; r2>r; r++) {
-                            if (maxdim > maxsizes[r]) {
-                                maxdim -= maxsizes[r];
-                            } else {
-                                maxdim = 0;
-                                break;
-                            }
-                        }
-                        maxsizes[r2] = max(maxdim, maxsizes[r2]);
-                    }
+            // PHASE 1: honor min/max sizes for boxes in order of region
+            var contentMin = 0;
+            var contentMax = 0;
+            const frontierMin = {};
+            const frontierMax = {};
+            for (var i,region in regions.list) {
+                var minsize = 0;
+                var maxsize = 0;
+                for (var j,box in region.boxes) {
+                    const c = box[0];
+                    minsize = max(c[contentdim], minsize);
+                    maxsize = max((c[shrink] ? c[contentdim] : c[maxdim]), 
maxsize);
                 }
-                // by now we know our minimum size
-                $content.minwidth = content + (r2!=null?minsizes[r2]:0);
+                region.minsize = minsize;
+                region.maxsize = maxsize;
                 
-                // PHASE 2: final region width assignment
-                // priority 0: (inviolable) honor minwidths
-                // priority 1: sum of columns no greater than parent
-                // priority 2: honor maxwidths
-                // priority 3: equalize columns
+                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];
                 
-                var mincols, maxcols;
-                var diff, size;
-                var target = width;
-                var targetColumnSize = target / numcols;
-                
-                // limit solving loop to 100 iterations
-                for (var i=0; 100>i; i++) {
-                    // reset markers
-                    r1 = 0; mincols=0; maxcols=0;
-                    // calculate size for each region based on targetColumnSize
-                    for (var r=1; regmark>r; r++) {
-                        r2 = regions[r];
-                        // honor maxwidths then minwidths
-                        diff = max(minsizes[r], min(maxsizes[r], 
targetColumnSize * (r2-r1)));
-                        sizes[r] = diff + sizes[r-1];
-                        // account for cols that can be further affected
-                        if (diff > minsizes[r]) mincols += (r2-r1);
-                        if (maxsizes[r] > diff) maxcols += (r2-r1);
-                        r1 = r2;
-                    }
-                    // our current size 
-                    size = sizes[regmark-1];
-                    if (0.5 > size-target and size-target >= -0.5) {
-                        // break if we were close to the target
-                        break;
-                    }
-                    if (size > target) {
-                        // not at the target size, adjust accordingly
-                        if (mincols == 0) {
-                            // no cols to be further decreased in size
-                            break;
-                        }
-                        // else adjust targetColumnSize according to 
target-total deficit
-                        targetColumnSize += ((target-size) / mincols);
-                    } else {
-                        if (maxcols == 0) {
-                            // no cols to be further increased in size
-                            break;
-                        }
-                        // adjust targetColumnSize according to target-total 
deficit
-                        targetColumnSize += ((target-size) / maxcols);
-                    }
-                    if (i>=99) {
-                        // infinite loop prevention
-                        vexi.log.warn("failed to solve grid");
-                    }
+                if (currentMin == null or priorMin + minsize > currentMin) {
+                    contentMin = max(priorMin + minsize, contentMin);
+                    frontierMin[frontier] = priorMin + minsize;
                 }
-                
-                // place our boxes
-                c = colregions.mark();
-                c0 = c?c[0]:null;
-                for (var r=1; regmark>r; r++) {
-                    sizes[r] = vexi.math.round(sizes[r]);
-                    while (c and regions[r] == c0.v_col+c0.colspan) {
-                        r1 = sizes[rindmap[c0.v_col]];
-                        r2 = sizes[r];
-                        c.width = c0.hshrink ? c0.contentwidth : 
min(c0.maxwidth, r2-r1);
-                        c.x = (c.width == r2-r1) ? r1 : fromHAlign(c0.align, 
r1, r2-r1-c.width);
-                        c = colregions.next();
-                        if (c) {
-                            c0 = c[0];
-                        }
-                    }
+                if (currentMax == null or priorMax + maxsize > currentMax) {
+                    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);
                 }
-                
-                // hand out any slack
-                //if (target > size+0.5) {
-                //    targetColumnSize = (target-size) / cols;
-                //    for (int r=0; regmark>r; r++)
-                //        sizes[regions[r]] += regions[r] * 
targetColumnSize+0.5;
             }
+            // by now we know our minimum/maximum size
+            $content[mindim] = contentMin;
+            $content[maxdim] = contentMax;
             
-            // child height solving
-            if (findheights) {
-                // PHASE 1: honor min/max sizes for boxes in order of region
-                content = 0;
-                minsizes = [0];
-                maxsizes = [0];
-                regions = [0];
-                rindmap = {};
-                rindmap[0] = 0;
-                regmark = 1;
-                sizes = [0];
-                for (c = rowregions.mark(); c != null; c = rowregions.next()) {
-                    c0 = c[0];
-                    // bypass hidden children
-                    if (!c0.display) continue;
-                    r1 = rindmap[c0.v_row];
-                    r2 = rindmap[c0.v_row+c0.rowspan];
-                    // first to affect this region
-                    if (r2 == null) {
-                        r2 = regmark;
-                        regions[r2] = c0.v_row+c0.rowspan;
-                        rindmap[regions[r2]] = r2;
-                        minsizes[r2] = 0;
-                        maxsizes[r2] = 0;
-                        sizes[r2] = 0;
-                        content += minsizes[regmark-1];
-                        regmark++;
+            // PHASE 2: place wrapper boxes in accordance with region/frontier 
min/max sizes
+            if (thisbox[shrink] or $content[mindim] > gridsize) {
+                // honor min sizes
+                for (var i,region in regions.list) {
+                    const regionPos = region.origin>0 ? 
frontierMin[region.origin] : 0; 
+                    const regionDim = frontierMin[region.frontier] - regionPos;
+                    for (var j,box in region.boxes) {
+                        box[pos] = regionPos;
+                        box[dim] = regionDim;
                     }
-                    if (r2-r1 == 1) {
-                        // affect single region
-                        minsizes[r2] = max(c0.contentheight, minsizes[r2]);
-                        maxsizes[r2] = max((c0.vshrink ? c0.contentheight : 
c0.maxheight), maxsizes[r2]);
-                    } else {
-                        // affect multiple regions
-                        mindim = c0.contentheight;
-                        maxdim = c0.vshrink ? c0.contentheight : c0.maxheight;
-                        // work out the minimum size of this box's region
-                        // the box affects c.v_col+1 -> c.v_col+c.colspan
-                        for (var r=r1+1; r2>r; r++) {
-                            mindim -= minsizes[r];
-                        }
-                        minsizes[r2] = max(mindim, minsizes[r2]);
-                        // work out the maximum size of this box's region
-                        for (var r=r1+1; r2>r; r++) {
-                            if (maxdim > maxsizes[r]) {
-                                maxdim -= maxsizes[r];
-                            } else {
-                                maxdim = 0;
-                                break;
-                            }
-                        }
-                        maxsizes[r2] = max(maxdim, maxsizes[r2]);
+                }
+            } else
+            if (gridsize >= $content[maxdim]) {
+                // honor max sizes
+                for (var i,region in regions.list) {
+                    const regionPos = region.origin>0 ? 
frontierMax[region.origin] : 0; 
+                    const regionDim = frontierMax[region.frontier] - regionPos;
+                    for (var j,box in region.boxes) {
+                        box[pos] = regionPos;
+                        box[dim] = regionDim;
                     }
                 }
-                // by now we know our minimum size
-                $content.minheight = content + (r2!=null?minsizes[r2]:0);
+            } else {
+                // solving required; guess at a workable target col/row size,
+                // test it and adjust it up/down until it tests successfully 
+                var targetSize = gridsize / fullreach;
                 
-                // PHASE 2: final region height assignment
-                // priority 0: (inviolable) honor minwidths
-                // priority 1: sum of columns no greater than parent
-                // priority 2: honor maxwidths
-                // priority 3: equalize columns
+                // these exist outside of the loop as their
+                // contents get fully overwritten each pass
+                const frontierMin = [];
+                const frontierMax = [];
+                const frontierDim = {};
+                // this is constant
+                frontierDim[0] = 0;
+                // need this after solving
+                var lastFrontier;
                 
-                var minrows, maxrows;
-                var diff, size;
-                var target = height;
-                var targetRowSize = target / numrows;
-                
                 // limit solving loop to 100 iterations
                 for (var i=0; 100>i; i++) {
-                    // reset markers
-                    r1 = 0; minrows=0; maxrows=0;
-                    // calculate size for each region based on targetRowSize
-                    for (var r=1; regmark>r; r++) {
-                        r2 = regions[r];
-                        // honor maxwidths then minwidths
-                        diff = max(minsizes[r], min(maxsizes[r], targetRowSize 
* (r2-r1)));
-                        sizes[r] = diff + (r == 0 ? 0 : sizes[r-1]);
-                        // account for rows that can be further affected
-                        if (diff > minsizes[r]) minrows += (r2-r1);
-                        if (maxsizes[r] > diff) maxrows += (r2-r1);
-                        r1 = r2;
+                    lastFrontier = 0;
+                    for (var i,region in regions.list) {
+                        const frontier = region.frontier;
+                        const f_index = f2i[frontier];
+                        const origin = region.origin;
+                        const reach = frontier-origin;
+                        const minsize = region.minsize;
+                        const maxsize = region.maxsize;
+                        var target;
+                        
+                        if (frontier!=lastFrontier) {
+                            // reset frontierMin/Max
+                            frontierMin[f_index] = false;
+                            frontierMax[f_index] = false;
+                        }
+                        
+                        if (minsize == maxsize) {
+                            // region size fixed
+                            target = minsize;
+                        } else {
+                            target = targetSize * reach;
+                            const o_index = f2i[origin];
+                            
+                            if (target > minsize)
+                                for (var i=f_index; i>o_index; i--)
+                                    frontierMin[i] = true;
+                            else target = minsize;
+                            
+                            if (maxsize > target)
+                                for (var i=f_index; i>o_index; i--)
+                                    frontierMax[i] = true;
+                            else target = maxsize;
+                        }
+                        
+                        const frontierPush = frontierDim[origin] + target;
+                        if (frontier!=lastFrontier or frontierPush > 
frontierDim[frontier])
+                            frontierDim[frontier] = frontierPush;
+                        lastFrontier = frontier;
                     }
-                    // our current size 
-                    size = sizes[regmark-1];
-                    if (0.5 > size-target and size-target >= -0.5) {
+                    
+                    const totalSize = frontierDim[lastFrontier];
+                    if (0.5 > totalSize-gridsize and totalSize-gridsize >= 
-0.5) {
                         // break if we were close to the target
                         break;
                     }
-                    if (size > target) {
-                        // not at the target size, adjust accordingly
-                        if (minrows == 0) {
+                    
+                    // not at the target size, adjust accordingly
+                    if (totalSize > gridsize) {
+                        // too big; adjust down
+                        var reachDown = 0;
+                        for (var i,isMin in frontierMin) {
+                            if (isMin) continue;
+                            reachDown += frontiers[i]-(i==0?0:frontiers[i-1]);
+                        }
+                        if (reachDown == 0) {
                             // no rows to be further decreased in size
-                            break;
+                            throw "Should not be possible";
                         }
                         // else adjust targetRowSize according to target-total 
deficit
-                        targetRowSize += ((target-size) / minrows);
+                        targetSize += ((totalSize-gridsize) / reachDown);
+                        
                     } else {
-                        if (maxrows == 0) {
+                        // too small; adjust up
+                        var reachUp = 0;
+                        for (var i,isMax in frontierMax) {
+                            if (isMax) continue;
+                            reachUp += frontiers[i]-(i==0?0:frontiers[i-1]);
+                        }
+                        if (reachUp == 0) {
                             // no rows to be further increased in size
-                            break;
+                            throw "Should not be possible";
                         }
                         // adjust targetRowSize according to target-total 
deficit
-                        targetRowSize += ((target-size) / maxrows);
+                        targetSize += ((gridsize-totalSize) / reachUp);
                     }
                     if (i>=99) {
                         // infinite loop prevention
-                        vexi.log.warn("failed to solve grid");
+                        vexi.log.warn("failed to solve grid "+dim+" 
"+fullreach);
                     }
                 }
                 
+                // just to be sure we don't miss the edge of the grid
+                frontierDim[lastFrontier] = gridsize;
+                
                 // place our boxes
-                c = rowregions.mark();
-                c0 = c?c[0]:null;
-                for (var r=1; regmark>r; r++) {
-                    sizes[r] = vexi.math.round(sizes[r]);
-                    while (c and regions[r] == c0.v_row+c0.rowspan) {
-                        r1 = sizes[rindmap[c0.v_row]];
-                        r2 = sizes[r];
-                        c.height = c0.vshrink ? c0.contentheight : 
min(c0.maxheight, r2-r1);
-                        c.y = (c.height == r2-r1) ? r1 : fromVAlign(c0.align, 
r1, r2-r1-c.height);
-                        c = rowregions.next();
-                        if (c) {
-                            c0 = c[0];
-                        }
+                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));
+                    for (var j,box in region.boxes) {
+                        box[pos] = regionPos;
+                        box[dim] = regionDim;
                     }
                 }
-                
-                // hand out any slack
-                //if (target > size+0.5) {
-                //    targetRowSize = (target-size) / rows;
-                //    for (int r=0; regmark>r; r++)
-                //        sizes[regions[r]] += regions[r] * targetRowSize+0.5;
             }
         }
         
+        /*
+         * 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
+                return;
+            }
+            if (place_horizontal) {
+                placeRegions(byCol, numcols, width, "hshrink", "contentwidth", 
"minwidth", "maxwidth", "width", "x");
+                place_horizontal = false;
+            }
+            if (place_vertical) {
+                placeRegions(byRow, numrows, height, "vshrink", 
"contentheight", "minheight", "maxheight", "height", "y");
+                place_vertical = false;
+            }
+        }
+        
         /* 
          * PACKING
          *
@@ -353,34 +281,50 @@
          * adding extra columns.
          */
         
+        /** establish an ordered list of frontiers for placing */
+        const establishFrontier = function(frontiers, frontier) {
+            for (var i = frontiers.length-1; i>=0; --i) {
+                var f = frontiers[i];
+                if (f == frontier)
+                    return;
+                if (f > frontier)
+                    continue;
+                frontiers.splice(i+1, 0, frontier);
+                return;
+            }
+            frontiers.unshift(frontier);
+        }
+        
         /** assign child c to the pack slot specific by col,row */
-        var assignSlot = function(c, col, row) {
+        const assignSlot = function(c, col, row) {
             var c0 = c[0];
-            if (!colregions.contains(c) or c0.v_col != col) {
-                // col-related assignments
-                c0.v_col = col;
-                colregions.insert(c, c0.v_col+c0.colspan);
-            }
-            if (!rowregions.contains(c) or c0.v_row != row) {
-                // row-related assignments
-                c0.v_row = row;
-                rowregions.insert(c, c0.v_row+c0.rowspan);
-            }
+            c0.v_col = col;
+            c0.v_row = row;
+            var colfrontier = col+c0.colspan;
+            var rowfrontier = row+c0.rowspan;
+            // update the number of in-use rows/cols
+            numcols = max(numcols, colfrontier);
+            numrows = max(numrows, rowfrontier);
+            // establish a list of frontier/from-col pairs
+            // which can be iterated over for solving
+            byCol.regions.add(c, col, colfrontier);
+            byRow.regions.add(c, row, rowfrontier);
+            establishFrontier(byCol.frontiers, colfrontier);
+            establishFrontier(byRow.frontiers, rowfrontier);
         }
         
         /** pack by column first, expanding rows as required */
-        var packByCol = function() {
-            var frontier = new .vector();
-            var fullpass = true;
+        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 n = $content.numchildren;
             var c, c0; var f, f0;
+            
             // assign col/row values to packed children
-            for (var j=0; n>j; j++) {
-                c = $content[j];
+            for (var i,c in $content) {
                 c0 = c[0];
+                
                 if (!c0.display) {
                     // disregard hidden children
                     c.display = false;
@@ -388,13 +332,16 @@
                 } else {
                     c.display = true;
                 }
-                if (nextcol!=0 and nextcol+c0.colspan > numcols) {
+                
+                if (nextcol!=0 and nextcol+c0.colspan > setsize) {
                     // if we don't fit on the row, jump to the next
                     nextcol=0;
                     nextrow++;
                 }
+                
                 // check to see if we are making a full pass at the row
-                fullpass = nextcol==0;
+                const fullpass = nextcol==0;
+                
                 // work through frontier boxes until a suitable position is 
found
                 PACKME: while (frontier.length>0) {
                     f = frontier.first;
@@ -415,7 +362,7 @@
                             // establish next available row
                             minrows = (minrows == 0) ? f0.v_row+f0.rowspan : 
min(minrows, f0.v_row+f0.rowspan);
                             
-                            if (nextcol+c0.colspan > numcols) {
+                            if (nextcol+c0.colspan > setsize) {
                                 // c will not fit on nextrow
                                 if (!fullpass) {
                                     // if not a full pass, try next immediate 
row
@@ -438,7 +385,7 @@
                         // next frontier
                         f = frontier.after(f);
                     }
-                    if (numcols >= nextcol+c0.colspan) {
+                    if (setsize >= nextcol+c0.colspan) {
                         // fits in the col after frontier
                         break;
                     }
@@ -464,22 +411,18 @@
                 // update the number of rows
                 numrows = max(numrows, c0.v_row+c0.rowspan);
             }
-            // always want to do this after packing
-            place(true, true);
         }
         
         /** pack by row first - for comments see packByCol **/
         var packByRow = function() {
             var frontier = new .vector();
-            var fullpass = true;
             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 n = $content.numchildren;
             var c, c0; var f, f0;
+            
             // assign row/col values to packed children
-            for (var j=0; n>j; j++) {
-                c = $content[j];
+            for (var i,c in $content) {
                 c0 = c[0];
                 // disregard hidden children
                 if (!c0.display) {
@@ -488,13 +431,14 @@
                 } else {
                     c.display = true;
                 }
-                if (nextrow!=0 and nextrow+c0.rowspan > numrows) {
+                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
-                fullpass = nextrow==0;
+                const fullpass = nextrow==0;
                 
                 // work through frontier boxes until a suitable position is 
found
                 PACKME: while (frontier.length>0) {
@@ -516,7 +460,7 @@
                             // establish next available col
                             mincols = (mincols == 0) ? f0.v_col+f0.colspan : 
min(mincols, f0.v_col+f0.colspan);
                             
-                            if (nextrow+c0.rowspan > numrows) {
+                            if (nextrow+c0.rowspan > setsize) {
                                 // c will not fit on nextcol
                                 if (!fullpass) {
                                     // if not a full pass, try next immediate 
col
@@ -535,7 +479,7 @@
                         // next frontier
                         f = frontier.after(f);
                     }
-                    if (numrows >= nextrow+c0.rowspan) {
+                    if (setsize >= nextrow+c0.rowspan) {
                         // fits on this row after frontier
                         break;
                     }
@@ -556,27 +500,44 @@
                 // prepare for next iteration
                 mincols = 0;            // reset mincols
                 nextrow += c0.rowspan;  // bump up nextrow
-                // update the number of cols
-                numcols = max(numcols, c0.v_col+c0.colspan);
             }
-            // always want to do this after packing
-            place(true, true);
         }
         
+        const getIndice = function(bySet) {
+            const f2i = {};
+            for (var i,f in bySet.frontiers)
+                f2i[f] = i;
+            bySet.frontier2index = f2i;
+        }
+        
         /************************************
          ****** SCHEDULING FUNCTIONS ********
          ************************************/
         
         /** ambiguous function to invoke specific packing function */
         var pack = function() {
+            // reset!
+            numcols = 0;
+            numrows = 0;
+            byCol.regions = new Regions();
+            byCol.frontiers = [];
+            byRow.regions = new Regions();
+            byRow.frontiers = [];
+            // pack!
             userows ? packByRow() : packByCol();
+            getIndice(byCol);
+            getIndice(byRow);
             pack_children = false;
         }
         
         thisbox.Resize ++= function(v) {
-            if (pack_children)
+            if (pack_children) {
                 pack();
-            else place(true, true);
+                // always want to place after packing
+                place_horizontal = true;
+                place_vertical = true;
+            }
+            place();
         }
         
         var schedulePack = function() {
@@ -584,11 +545,6 @@
             reflow();
         }
         
-        var sc_number = "number";
-        var checkInt = function(v) {
-            cascade = typeof(v)==sc_number ? v : vexi.string.parseInt(v);
-        }
-        
         var invokePack = function(v) {
             if (v == trapee[trapname]) return;
             cascade = v;
@@ -597,6 +553,7 @@
         
         var invokePlaceWidth = function(v) {
             if (v != trapee[trapname]) {
+                place_horizontal = true;
                 reflow();
             }
             cascade = v;
@@ -604,15 +561,47 @@
         
         var invokePlaceHeight = function(v) {
             if (v != trapee[trapname]) {
+                place_vertical = true;
                 reflow();
             }
             cascade = v;
         }
         
+        var sc_number = "number";
+        var checkInt = function(v) {
+            cascade = typeof(v)==sc_number ? v : vexi.string.parseInt(v);
+        }
+        
         /****************************
          ******** PUBLIC API ********
          ****************************/
         
+        thisbox.height ++= invokePlaceHeight;
+        thisbox.width ++= invokePlaceWidth;
+        
+        thisbox.cols ++= function(v) {
+            if (userows or v != setsize) {
+                setsize = v;
+                userows = false;
+                orient = "vertical"; // symbolic
+                schedulePack();
+            }
+            return;
+        }
+        
+        thisbox.rows ++= function(v) {
+            if (!userows or v != setsize) {
+                setsize = v;
+                userows = true;
+                orient = "horizontal"; // symbolic
+                schedulePack();
+            }
+            return;
+        }
+        
+        thisbox.cols ++= function() { return userows ? numcols : setsize; }
+        thisbox.rows ++= function() { return userows ? setsize : numrows; }
+        
         var gridboxChildren = function(v) {
             cascade = v;
             if (v == null) {
@@ -621,8 +610,6 @@
                     return;
                 }
                 $content[i] = null;
-                colregions.remove(trapee);
-                rowregions.remove(trapee);
                 schedulePack();
             }
         }
@@ -636,7 +623,7 @@
                     var n = c.numchildren;
                     for (var i=0; n>i; i++) {
                         thisbox.add(c[0]);
-                    } 
+                    }
                     return;
                 }
                 // adding a child
@@ -659,6 +646,10 @@
                 v.rowspan ++= invokePack;
                 v.rowspan ++= checkInt;
                 v.display ++= invokePack;
+                v.maxwidth ++= invokePlaceWidth;
+                v.minwidth ++= invokePlaceWidth;
+                v.maxheight ++= invokePlaceHeight;
+                v.minheight ++= invokePlaceHeight;
                 // we wrap them in an outer box which we can manipulate
                 var b = v.v_gridbox;
                 if (b == null) {
@@ -682,8 +673,6 @@
                 var b = $content[trapname];
                 if (b) {
                     b.Children --= gridboxChildren;
-                    colregions.remove(b);
-                    rowregions.remove(b);
                     c = b[0];
                 } else {
                     throw "attempt to get null child from a box";
@@ -710,6 +699,8 @@
             var c = $content[trapname];
             return c ? c[0] : null;
         }
+        
+        /** no redirect so must redirect this manually */
         thisbox.numchildren ++= function() { return $content.numchildren; }
         
         /** return the grid wrapper index as grid.indexof(child) == -1 */
@@ -722,46 +713,21 @@
         }
         thisbox.indexof ++= function() { return getindexof; }
         
-        thisbox.height ++= invokePlaceHeight;
-        thisbox.width ++= invokePlaceWidth;
-        
-        thisbox.cols ++= function(v) {
-            if (userows or v != numcols) {
-                numcols = v;
-                numrows = 0;
-                userows = false;
-                orient = "vertical";
-                schedulePack();
-            }
-            return;
-        }
-        
-        thisbox.rows ++= function(v) {
-            if (!userows or v != numrows) {
-                numcols = 0;
-                numrows = v;
-                userows = true;
-                orient = "horizontal";
-                schedulePack();
-            }
-            return;
-        }
-        
-        thisbox.cols ++= function() { return numcols; }
-        thisbox.rows ++= function() { return numrows; }
-        
         /** forward align property to children */
-        thisbox.align ++= function(v) {
+        thisbox.gridalign ++= function(v) {
+            cascade = v;
             for (var i,box in $content) {
                 box.align = v;
             }
-            return;
         }
         
-        /** prevent breaking of grid */
-        thisbox.layout ++= function(v) {
-            throw new vexi.js.Exception("Layout is fixed on grid"); 
-        }
+        thisbox.layout ++= static.layoutRead;
+        thisbox.layout ++= static.layoutWrite;
         
     </ui:box>
-</vexi>
\ No newline at end of file
+    
+    /** prevent breaking of grid */
+    static.layoutWrite = function(v) { throw new vexi.js.Exception("Layout is 
fixed on grid"); }
+    static.layoutRead = function() { return "grid"; }
+    
+</vexi>

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

Reply via email to