changes made after tupshins reconstruction
[org.ibex.core.git] / src / org / xwt / Box.java
index 186e93d..7743120 100644 (file)
@@ -1,3 +1,4 @@
+// FIXME
 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
 package org.xwt;
 
@@ -67,7 +68,7 @@ public final class Box extends JSScope implements Scheduler.Task {
    
     static {
         Font f = null;
-        try { f = Font.getFont((Res)Main.builtin.get("fonts/vera/Vera.ttf"), 10); }
+        try { f = Font.getFont((Stream)Main.builtin.get("fonts/vera/Vera.ttf"), 10); }
         catch(JSExn e) { Log.info(Box.class, "should never happen: "+e); }
         DEFAULT_FONT = f;
     }
@@ -75,12 +76,10 @@ public final class Box extends JSScope implements Scheduler.Task {
     // FIXME update these
     // box properties can not be trapped
     static final String[] props = new String[] {
-        "fill", "stroke", "image", "tile", "fixedaspect", "text", "path", "font",
         "shrink", "hshrink", "vshrink", "x", "y", "width", "height", "cols", "rows",
-        "colspan", "rowspan", "align", "visible", "absolute", "globalx", "globaly",
-        "minwidth", "maxwidth", "minheight", "maxheight",
-        "numchildren", "redirect", "cursor", "mousex", "mousey", "xwt", "static",
-        "mouseinside", "root", "thisbox", "indexof"
+        "colspan", "rowspan", "align", "visible", "packed", "globalx", "globaly",
+        "minwidth", "maxwidth", "minheight", "maxheight", "indexof", "thisbox", "clip",
+        "numchildren", "redirect", "cursor", "mouse"
     };
 
     // FIXME update these
@@ -177,7 +176,7 @@ public final class Box extends JSScope implements Scheduler.Task {
         // as external events have occured, check the state of box
         if (texture != null) {
             if (texture.isLoaded) { minwidth = min(texture.width, maxwidth); minheight = min(texture.height, maxheight); }
-            else { Res res = texture.res; texture = null; throw new JSExn("image not found: "+res); }
+            else { JS res = texture.stream; texture = null; throw new JSExn("image not found: "+res); }
         }
 
         MARK_REPACK;
@@ -259,9 +258,15 @@ public final class Box extends JSScope implements Scheduler.Task {
         if (x != this.x || y != this.y || width != this.width || height != this.height) {
             boolean sizechange = (this.width != width || this.height != height) && getTrap("SizeChange") != null;
             boolean poschange = (this.x != x || this.y != y) && getTrap("PosChange") != null;
-            do {
+            //do {
                 int thisx = parent == null ? 0 : this.x;
                 int thisy = parent == null ? 0 : this.y;
+
+                // we can't reenable this until we track
+                // surface-relative sizes; imagine the case of a clear
+                // surface with nonclear children
+
+                /*
                 if (texture == null && (text == null || text.equals(""))) {
                     if ((fillcolor & 0xff000000) == 0) break;
                     // FEATURE: more optimizations here
@@ -272,11 +277,12 @@ public final class Box extends JSScope implements Scheduler.Task {
                         break;
                     }
                 }
+                */
                 (parent == null ? this : parent).dirty(thisx, thisy, this.width, this.height);
                 this.width = width; this.height = height; this.x = x; this.y = y;
                 dirty();
-            } while (false);
-            this.width = width; this.height = height; this.x = x; this.y = y;
+                //} while (false);
+                //this.width = width; this.height = height; this.x = x; this.y = y;
             if (sizechange) putAndTriggerTrapsAndCatchExceptions("SizeChange", T);
             if (poschange)  putAndTriggerTrapsAndCatchExceptions("PosChange", T);
         }
@@ -302,7 +308,8 @@ public final class Box extends JSScope implements Scheduler.Task {
             int increment = max(1, x_slack / cols);
             startslack = x_slack;
             for(short col=0; col < cols; col++) {
-                int diff = min(colMaxWidth[col], colWidth[col] + increment) - colWidth[col];
+                // FIXME: double check this
+                int diff = min(min(colMaxWidth[col], colWidth[col] + increment) - colWidth[col], x_slack);
                 x_slack -= diff;
                 colWidth[col] += diff;
             }
@@ -316,8 +323,8 @@ public final class Box extends JSScope implements Scheduler.Task {
             if (!child.test(PACKED)) {
                 child_x = child.x;
                 child_y = child.y;
-                child_width = child.test(HSHRINK) ? child.contentwidth : min(child.maxwidth, width - child.x);
-                child_height = child.test(VSHRINK) ? child.contentheight : min(child.maxheight, height - child.y);
+                child_width = child.test(HSHRINK) ? child.contentwidth : min(child.maxwidth, width - child_x);
+                child_height = child.test(VSHRINK) ? child.contentheight : min(child.maxheight, height - child_y);
                 child_width = max(child.minwidth, child_width);
                 child_height = max(child.minheight, child_height);
             } else {
@@ -419,14 +426,14 @@ public final class Box extends JSScope implements Scheduler.Task {
             return redirect == null ? null : redirect == this ? getChild(toInt(name)) : redirect.get(name);
 
         //#switch(name)
-        case "surface": return parent == null ? null : parent.get("surface");
+        case "surface": return parent == null ? null : parent.getAndTriggerTraps("surface");
         case "indexof": return METHOD;
         case "text": return text;
         case "path": throw new JSExn("cannot read from the path property");
         case "fill": return colorToString(fillcolor);
         case "strokecolor": return colorToString(strokecolor);
         case "textcolor": return colorToString(strokecolor);
-        case "font": return font == null ? null : font.res;
+        case "font": return font == null ? null : font.stream;
         case "fontsize": return font == null ? N(10) : N(font.pointsize);
         case "strokewidth": return N(strokewidth);
         case "align": return alignToString();
@@ -437,12 +444,16 @@ public final class Box extends JSScope implements Scheduler.Task {
         case "aspect": return N(aspect);
         case "x": return (parent == null || !test(VISIBLE)) ? N(0) : N(x);
         case "y": return (parent == null || !test(VISIBLE)) ? N(0) : N(y);
-        case "width": return N(width);
-        case "height": return N(height);
         case "cols": return test(FIXED) == COLS ? N(cols) : N(0);
         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 "minwidth": return N(minwidth);
+        case "maxwidth": return N(maxwidth);
+        case "minheight": return N(minheight);
+        case "maxheight": return N(maxheight);
         case "clip": return B(test(CLIP));
         case "visible": return B(test(VISIBLE) && (parent == null || (parent.get("visible") == T)));
         case "packed": return B(test(PACKED));
@@ -455,10 +466,6 @@ public final class Box extends JSScope implements Scheduler.Task {
                 throw new JSExn("you cannot read from the box.mouse property in background thread context");
             return new Mouse();
         case "numchildren": return redirect == null ? N(0) : redirect == this ? N(treeSize()) : redirect.get("numchildren");
-        case "minwidth": return N(minwidth);
-        case "maxwidth": return N(maxwidth);
-        case "minheight": return N(minheight);
-        case "maxheight": return N(maxheight);
         case "redirect": return redirect == null ? null : redirect == this ? T : redirect.get("redirect");
         case "Minimized": if (parent == null && getSurface() != null) return B(getSurface().minimized);
         default: return super.get(name);
@@ -466,14 +473,14 @@ public final class Box extends JSScope implements Scheduler.Task {
         throw new Error("unreachable"); // unreachable
     }
 
-    private class Mouse extends JS {
+    private class Mouse extends JS.Cloneable {
         public Object get(Object key) {
             //#switch(key)
             case "x": return N(globalToLocalX(getSurface()._mousex));
             case "y": return N(globalToLocalY(getSurface()._mousey));
 
             // this might not get recomputed if we change mousex/mousey...
-            case "inside": return B(MOUSEINSIDE);
+            case "inside": return B(test(MOUSEINSIDE));
             //#end
             return null;
         }
@@ -503,8 +510,12 @@ public final class Box extends JSScope implements Scheduler.Task {
         case "height": put("maxheight", value); put("minheight", value); MARK_RESIZE;
         case "maxwidth": setMaxWidth(value);
         case "minwidth": CHECKSET_INT(minwidth); MARK_RESIZE;
+                         if (parent == null && getSurface() != null)
+                             getSurface().setMinimumSize(minwidth, minheight, minwidth != maxwidth || minheight != maxheight);
         case "maxheight": setMaxHeight(value);
         case "minheight": CHECKSET_INT(minheight); MARK_RESIZE;
+                         if (parent == null && getSurface() != null)
+                             getSurface().setMinimumSize(minwidth, minheight, minwidth != maxwidth || minheight != maxheight);
         case "colspan": CHECKSET_SHORT(colspan); MARK_REPACK_parent;
         case "rowspan": CHECKSET_SHORT(rowspan); MARK_REPACK_parent;
         case "rows": CHECKSET_SHORT(rows); if (rows==0){set(FIXED, COLS);if(cols==0)cols=1;} else set(FIXED, ROWS); MARK_REPACK;
@@ -526,31 +537,36 @@ public final class Box extends JSScope implements Scheduler.Task {
         case "Minimized": if (parent == null && getSurface() != null) getSurface().minimized = toBoolean(value);  // FEATURE
         case "Maximized": if (parent == null && getSurface() != null) getSurface().maximized = toBoolean(value);  // FEATURE
         case "Close": if (parent == null && getSurface() != null) getSurface().dispose(true);
-        case "toback": if (parent == null && getSurface() != null && toBoolean(value)) { getSurface().toBack(); }
-        case "tofront": if (parent == null && getSurface() != null && toBoolean(value)) { getSurface().toFront(); }
         case "redirect": if (redirect == this) redirect = (Box)value; else Log.info(this, "redirect can only be set once");
-        case "font": font = value == null ? null : Font.getFont((Res)value, font == null ? 10 : font.pointsize); MARK_RESIZE; dirty();
-        case "fontsize": font = Font.getFont(font == null ? null : font.res, toInt(value)); MARK_RESIZE; dirty();
-        case "x": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(x); } else { if (test(PACKED) && parent != null) return; CHECKSET_INT(x); dirty(); MARK_RESIZE; dirty(); }
-        case "y": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(y); } else { if (test(PACKED) && parent != null) return; CHECKSET_INT(y); dirty(); MARK_RESIZE; dirty(); }
-
-        case "Press1":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Press2":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Press3":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Release1":      if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Release2":      if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Release3":      if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Click1":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Click2":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Click3":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "DoubleClick1":  if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "DoubleClick2":  if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "DoubleClick3":  if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "KeyPressed":    if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "KeyReleased":   if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Move":          if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Enter":         if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
-        case "Leave":         if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.put(name, value);
+        case "font":
+            if(!(value instanceof Stream)) throw new JSExn("You can only put streams to the font property");
+            font = value == null ? null : Font.getFont((Stream)value, font == null ? 10 : font.pointsize);
+            MARK_RESIZE;
+            dirty();
+        case "fontsize": font = Font.getFont(font == null ? null : font.stream, toInt(value)); MARK_RESIZE; dirty();
+        case "x": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(x); } else { if (test(PACKED) && parent != null) return; dirty(); CHECKSET_INT(x); dirty(); MARK_RESIZE; dirty(); }
+        case "y": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(y); } else { if (test(PACKED) && parent != null) return; dirty(); CHECKSET_INT(y); dirty(); MARK_RESIZE; dirty(); }
+        case "titlebar":
+            if (getSurface() != null && value != null) getSurface().setTitleBarText(JS.toString(value));
+            super.put(name,value);
+            
+        case "Press1":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Press2":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Press3":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Release1":      if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Release2":      if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Release3":      if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Click1":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Click2":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Click3":        if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "DoubleClick1":  if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "DoubleClick2":  if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "DoubleClick3":  if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "KeyPressed":    if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "KeyReleased":   if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Move":          if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Enter":         if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
+        case "Leave":         if (!test(STOP_UPWARD_PROPAGATION) && parent != null) parent.putAndTriggerTraps(name, value);
 
         case "_Move":         propagateDownward(name, value, false);
         case "_Press1":       propagateDownward(name, value, false);
@@ -621,18 +637,22 @@ public final class Box extends JSScope implements Scheduler.Task {
         if (surface.cursor != tempcursor) surface.syncCursor();
     }
 
-    private void setFill(Object value) {
-        if (value == null) return;
-        if (value instanceof String) {
+    private void setFill(Object value) throws JSExn {
+        if (value == null) {
+            // FIXME: Check this... does this make it transparent? 
+            texture = null;
+            fillcolor = 0;
+        } else if (value instanceof String) {
             // FIXME check double set
             int newfillcolor = stringToColor((String)value);
             if (newfillcolor == fillcolor) return;
             fillcolor = newfillcolor;
-            dirty();
-            return;
+        } else if(value instanceof JS) {
+            texture = Picture.load((JS)value, this);
+        } else {
+            throw new JSExn("fill must be null, a String, or a stream, not a " + value.getClass());
         }
-        if (!(value instanceof Res)) return;
-        texture = Picture.load((Res)value, this);
+        dirty();
     }
 
     // FIXME: mouse move/release still needs to propagate to boxen in which the mouse was pressed and is still held down
@@ -677,7 +697,7 @@ public final class Box extends JSScope implements Scheduler.Task {
         // FIXME support three-char strings by doubling digits
         if (s == null) return 0x00000000;
         else if (SVG.colors.get(s) != null) return 0xFF000000 | toInt(SVG.colors.get(s));
-        else if (s.length() > 0 && s.charAt(0) == '#') try {
+        else if (s.length() == 7 && s.charAt(0) == '#') try {
             // FEATURE  alpha
             return 0xFF000000 |
                 (Integer.parseInt(s.substring(1, 3), 16) << 16) |
@@ -785,13 +805,13 @@ public final class Box extends JSScope implements Scheduler.Task {
         if (i < 0) return;
             
         if (value != null && !(value instanceof Box)) {
-            if (Log.on) JS.log(this, "attempt to set a numerical property on a box to a non-box");
+            if (Log.on) JS.warn("attempt to set a numerical property on a box to a non-box");
             return;
         }
 
         if (redirect == null) {
             if (value == null) putAndTriggerTrapsAndCatchExceptions("childremoved", getChild(i));
-            else JS.log(this, "attempt to add/remove children to/from a node with a null redirect");
+            else JS.warn("attempt to add/remove children to/from a node with a null redirect");
 
         } else if (redirect != this) {
             if (value != null) putAndTriggerTrapsAndCatchExceptions("childadded", value);
@@ -813,14 +833,14 @@ public final class Box extends JSScope implements Scheduler.Task {
             // check if box being moved is currently target of a redirect
             for(Box cur = b.parent; cur != null; cur = cur.parent)
                 if (cur.redirect == b) {
-                    if (Log.on) JS.log(this, "attempt to move a box that is the target of a redirect");
+                    if (Log.on) JS.warn("attempt to move a box that is the target of a redirect");
                     return;
                 }
 
             // check for recursive ancestor violation
             for(Box cur = this; cur != null; cur = cur.parent)
                 if (cur == b) {
-                    if (Log.on) JS.log(this, "attempt to make a node a parent of its own ancestor");
+                    if (Log.on) JS.warn("attempt to make a node a parent of its own ancestor");
                     if (Log.on) Log.info(this, "box == " + this + "  ancestor == " + b);
                     return;
                 }
@@ -841,6 +861,9 @@ public final class Box extends JSScope implements Scheduler.Task {
     void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) {
         try {
             putAndTriggerTraps(name, val);
+        } catch (JSExn e) {
+            JS.log("caught js exception while putting to trap \""+name+"\"");
+            JS.log(e);
         } catch (Exception e) {
             JS.log("caught exception while putting to trap \""+name+"\"");
             JS.log(e);