reflow on demand when JS reads width/height
[org.ibex.core.git] / src / org / ibex / Box.java
index 9d2196d..b2608fb 100644 (file)
@@ -2,13 +2,7 @@
 // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.ibex;
 
-// FEATURE: reflow before allowing js to read from width/height 
-// FEATURE: fastpath for rows=1/cols=1
 // FEATURE: mark to reflow starting with a certain child
-// FEATURE: separate mark_for_reflow and mark_for_resize
-// FEATURE: make all methods final
-// FEATURE: use a linked list for the "frontier" when packing
-// FEATURE:    or else have a way to mark a column "same as last one"?
 // FEATURE: reintroduce surface.abort
 
 import java.util.*;
@@ -171,8 +165,8 @@ public final class Box extends JSScope implements Scheduler.Task {
     public void perform() throws JSExn {
         if (texture == null) { Log.warn(Box.class, "perform() called with null texture"); return; }
         if (texture.isLoaded) {
-            setMinWidth(max(texture.width, maxwidth));
-            setMinHeight(max(texture.height, maxheight));
+            setMinWidth(max(texture.width, minwidth));
+            setMinHeight(max(texture.height, minheight));
             DIRTY; }
         else { JS res = texture.stream; texture = null; throw new JSExn("image not found: "+res.unclone()); }
     }
@@ -199,13 +193,16 @@ public final class Box extends JSScope implements Scheduler.Task {
 
     // Reflow ////////////////////////////////////////////////////////////////////////////////////////
 
+    /** should only be invoked on the root box */
+    void reflow() { pack(); resize(x, y, maxwidth, maxheight); place(); }
+
     private static Box[] frontier = new Box[65535];
     /** pack the boxes into rows and columns, compute contentwidth */
     void pack() {
         if (!test(REPACK)) { constrain(); return; }
         boolean haskid = false;
         for(Box child = getChild(0); child != null; child = child.nextSibling()) { haskid = true; child.pack(); }
-        if (!haskid) { clear(REPACK); return; }
+        if (!haskid) { clear(REPACK); constrain(); return; }
         int frontier_size = 0;
         //#repeat COLS/ROWS rows/cols cols/rows col/row row/col colspan/rowspan rowspan/colspan \
         //        contentheight/contentwidth contentwidth/contentheight
@@ -284,7 +281,8 @@ public final class Box extends JSScope implements Scheduler.Task {
     void solve(boolean findMinimum) {
         int numkids = 0; for(Box c = firstPackedChild(); c != null; c = c.nextPackedSibling()) numkids++;
         //#repeat col/row colspan/rowspan contentwidth/contentheight width/height HSHRINK/VSHRINK numregions/numregions_v \
-        //        maxwidth/maxheight cols/rows minwidth/minheight regions/regions_v targetColumnSize/targetRowSize sizes/sizes_v
+        //        maxwidth/maxheight cols/rows minwidth/minheight regions/regions_v targetColumnSize/targetRowSize sizes/sizes_v \
+        //        HSHRINK/VSHRINK
         if (numkids == 0) {
             if (findMinimum) contentwidth = 0;
             else targetColumnSize = 0;
@@ -336,9 +334,10 @@ public final class Box extends JSScope implements Scheduler.Task {
                         if (regions[r+1] < child.col) continue;
                         if (regions[r] >= min(child.col+child.colspan,cols)) { minregion = r; break; }
                         total -= sizes[r];
+                        int child_maxwidth = child.test(HSHRINK)?child.contentwidth:child.maxwidth;
                         if (sizes[r] <= (float)(targetColumnSize*(regions[r+1]-regions[r])))
-                            if ((child.colspan * targetColumnSize) > (child.maxwidth + (float)0.5))
-                                sizes[r] = (float)Math.min(sizes[r], (regions[r+1]-regions[r])*(child.maxwidth/child.colspan));
+                            if ((child.colspan * targetColumnSize) > (child_maxwidth + (float)0.5))
+                                sizes[r] = (float)Math.min(sizes[r], (regions[r+1]-regions[r])*(child_maxwidth/child.colspan));
                         if ((child.colspan * targetColumnSize) < (child.contentwidth - (float)0.5))
                             sizes[r] = (float)Math.max(sizes[r], (regions[r+1]-regions[r])*(child.contentwidth/child.colspan));
                         total += sizes[r];
@@ -516,8 +515,8 @@ public final class Box extends JSScope implements Scheduler.Task {
         case "rows": return test(FIXED) == ROWS ? N(rows) : N(0);
         case "colspan": return N(colspan);
         case "rowspan": return N(rowspan);
-        case "width": return N(width);
-        case "height": return N(height);
+        case "width": getRoot().reflow(); return N(width);
+        case "height": getRoot().reflow(); return N(height);
         case "minwidth": return N(minwidth);
         case "maxwidth": return N(maxwidth);
         case "minheight": return N(minheight);
@@ -569,7 +568,7 @@ public final class Box extends JSScope implements Scheduler.Task {
     public void put(Object name, Object value) throws JSExn {
         if (name instanceof Number) { put(toInt(name), value); return; }
         //#switch(name)
-        case "text": CHECKSET_STRING(text); RECONSTRAIN(); DIRTY;
+        case "text": if (value == null) value = ""; CHECKSET_STRING(text); RECONSTRAIN(); DIRTY;
         case "strokecolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY;
         case "textcolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY;
         case "strokewidth": CHECKSET_SHORT(strokewidth); DIRTY;