2003/12/25 23:54:52
[org.ibex.core.git] / src / org / xwt / Box.java
index a96383e..3e2599b 100644 (file)
@@ -172,10 +172,12 @@ public final class Box extends JSScope implements Scheduler.Task {
 
     /** invoked when a resource needed to render ourselves finishes loading */
     public void perform() throws JSExn {
+
+        // FIXME; we can't assume that just because we were performed the image is loaded.
         // as external events have occured, check the state of box
         if (texture != null) {
-           if (texture.isLoaded) { minwidth = texture.width; minheight = texture.height; }
-           else { Res res = texture.res; texture = null; throw new JSExn("image not found: "+res); }
+            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); }
         }
 
         MARK_REPACK;
@@ -255,15 +257,28 @@ public final class Box extends JSScope implements Scheduler.Task {
     void resize(LENGTH x, LENGTH y, LENGTH width, LENGTH height) {
         // FEATURE reimplement, but we're destroying this
         // FIXME: uncommenting this breaks; see http://bugs.xwt.org/show_bug.cgi?id=345
-        //if (x != this.x || y != this.y || width != this.width || height != this.height) {
-            (parent == null ? this : parent).dirty(this.x, this.y, this.width, this.height);
+        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 {
+                if (texture == null && (text == null || text.equals(""))) {
+                    if ((fillcolor & 0xff000000) == 0) break;
+                    // FEATURE: more optimizations here
+                    if (this.x == x && this.y == y) {
+                        Box who = (parent == null ? this : parent);
+                        who.dirty(min(this.x+this.width,x+width), y, Math.abs(width-this.width), max(this.height, height));
+                        who.dirty(x, min(this.y+this.height,y+height), max(this.width, width), Math.abs(height-this.height));
+                        break;
+                    }
+                }
+                (parent == null ? this : parent).dirty(this.x, this.y, 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;
-            dirty();
             if (sizechange) putAndTriggerTrapsAndCatchExceptions("SizeChange", T);
             if (poschange)  putAndTriggerTrapsAndCatchExceptions("PosChange", T);
-            //}
+        }
     }
 
     void resize_children() {
@@ -340,6 +355,7 @@ public final class Box extends JSScope implements Scheduler.Task {
         int globaly = parenty + (parent == null ? 0 : y);
 
         // intersect the x,y,w,h rendering window with ourselves; quit if it's empty
+
         if (!test(NOCLIP)) {
             cx1 = max(cx1, parent == null ? 0 : globalx);
             cy1 = max(cy1, parent == null ? 0 : globaly);
@@ -349,7 +365,7 @@ public final class Box extends JSScope implements Scheduler.Task {
         }
 
         if ((fillcolor & 0xFF000000) != 0x00000000)
-            buf.fillTrapezoid(globalx, globalx + width, globaly, globalx, globalx + width, globaly + height, fillcolor);
+            buf.fillTrapezoid(cx1, cx2, cy1, cx1, cx2, cy2, fillcolor);
 
         // FIXME: do aspect in here
         if (texture != null && texture.isLoaded)
@@ -431,9 +447,11 @@ public final class Box extends JSScope implements Scheduler.Task {
         case "globalx": return N(localToGlobalX(0));
         case "globaly": return N(localToGlobalY(0));
         case "cursor": return test(CURSOR) ? boxToCursor.get(this) : null;
-        case "mousex": { Surface s = getSurface(); return N(s == null ? 0 : globalToLocalX(s.mousex)); }
-        case "mousey": { Surface s = getSurface(); return N(s == null ? 0 : globalToLocalY(s.mousey)); }
-        case "mouseinside": return B(test(MOUSEINSIDE));
+        case "mouse":
+            if (getSurface() == null) return null;
+            if (getSurface()._mousex == Integer.MAX_VALUE)
+                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);
@@ -446,6 +464,19 @@ public final class Box extends JSScope implements Scheduler.Task {
         throw new Error("unreachable"); // unreachable
     }
 
+    private class Mouse extends JS {
+        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);
+            //#end
+            return null;
+        }
+    }
+
     void setMaxWidth(Object value) { do { CHECKSET_INT(maxwidth); MARK_RESIZE; } while(false); }
     void setMaxHeight(Object value) { do { CHECKSET_INT(maxheight); MARK_RESIZE; } while(false); }
 
@@ -473,12 +504,17 @@ public final class Box extends JSScope implements Scheduler.Task {
         case "noclip": CHECKSET_FLAG(NOCLIP); if (parent == null) dirty(); else parent.dirty();
         case "visible": CHECKSET_FLAG(VISIBLE); dirty(); MARK_RESIZE; dirty();
         case "packed": CHECKSET_FLAG(PACKED); MARK_REPACK_parent;
-        case "aspect": CHECKSET_INT(aspect); DIRTY;
+        case "aspect": CHECKSET_INT(aspect); dirty();
         case "globalx": put("x", N(globalToLocalX(toInt(value))));
         case "globaly": put("y", N(globalToLocalY(toInt(value))));
         case "align": clear(ALIGNS); setAlign(value == null ? "center" : value); MARK_RESIZE;
         case "cursor": setCursor(value);
         case "fill": setFill(value);
+        case "mouse":
+            int mousex = toInt(((JS)value).get("x"));
+            int mousey = toInt(((JS)value).get("y"));
+            getSurface()._mousex = localToGlobalX(mousex);
+            getSurface()._mousey = localToGlobalY(mousey);
         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);
@@ -588,7 +624,6 @@ public final class Box extends JSScope implements Scheduler.Task {
             return;
         }
         if (!(value instanceof Res)) return;
-
         texture = Picture.load((Res)value, this);
     }
 
@@ -600,8 +635,8 @@ public final class Box extends JSScope implements Scheduler.Task {
 
         String name = (String)name_;
         if (getSurface() == null) return;
-        int x = globalToLocalX(getSurface().mousex);
-        int y = globalToLocalY(getSurface().mousey);
+        int x = globalToLocalX(getSurface()._mousex);
+        int y = globalToLocalY(getSurface()._mousey);
         boolean wasinside = test(MOUSEINSIDE);
         boolean isinside = test(VISIBLE) && inside(x, y) && !obscured;
         if (!wasinside && isinside) { set(MOUSEINSIDE);   putAndTriggerTrapsAndCatchExceptions("Enter", T); }
@@ -630,6 +665,7 @@ public final class Box extends JSScope implements Scheduler.Task {
     }
 
     private static int stringToColor(String s) {
+        // 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 {