allow traps on all properties, add FIXMEs for required harmonizations
[org.ibex.core.git] / src / org / ibex / Box.java
index 560e7f5..8ff61a1 100644 (file)
@@ -2,13 +2,13 @@
 // 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
+// FIXME: are traps on x/y meaningful?
+// FIXME: if we trap on cols, then set rows to 0 (forcing cols to 1), does the cols trap get triggered?
+// FIXME: if we change min{width/height}, thereby forcing a change to max{min/height}, does a trap on those get triggered?
+// FIXME: trap on numchildren?  replaces ChildChanged?
+// FIXME: trap on visible, trigger when parent visibility changes
+
 // 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.*;
@@ -68,15 +68,6 @@ public final class Box extends JSScope implements Scheduler.Task {
     }
 
     // FIXME update these
-    // box properties can not be trapped
-    static final String[] props = new String[] {
-        "shrink", "hshrink", "vshrink", "x", "y", "width", "height", "cols", "rows",
-        "colspan", "rowspan", "align", "visible", "packed", "globalx", "globaly",
-        "minwidth", "maxwidth", "minheight", "maxheight", "indexof", "thisbox", "clip",
-        "numchildren", "redirect", "cursor", "mouse"
-    };
-
-    // FIXME update these
     // events can have write traps, but not read traps
     static final String[] events = new String[] {
         "Press1", "Press2", "Press3",
@@ -171,8 +162,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,6 +190,9 @@ 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() {
@@ -284,7 +278,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 +331,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];
@@ -476,18 +472,6 @@ public final class Box extends JSScope implements Scheduler.Task {
         return super.callMethod(method, a0, a1, a2, rest, nargs);
     }
 
-    protected boolean isTrappable(Object key, boolean isRead) {
-        if (key == null) return false;
-        else if (key instanceof String) {
-            // not allowed to trap box properties, and no read traps on events
-            String name = (String)key;
-            for (int i=0; i < props.length; i++) if (name.equals(props[i])) return false; 
-            if (isRead) for (int i=0; i < events.length; i++) if (name.equals(events[i])) return false; 
-        }
-
-        return true;
-    }
-
     public Object get(Object name) throws JSExn {
         if (name instanceof Number)
             return redirect == null ? null : redirect == this ? getChild(toInt(name)) : redirect.get(name);
@@ -516,8 +500,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 +553,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;