2003/11/27 05:05:09
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:42:10 +0000 (07:42 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 07:42:10 +0000 (07:42 +0000)
darcs-hash:20040130074210-2ba56-26bac58446febbedfdb454cc331ade435c22a120.gz

src/org/xwt/Box.java
src/org/xwt/Surface.java
src/org/xwt/Template.java

index 280924c..ebd3d85 100644 (file)
@@ -165,7 +165,7 @@ public final class Box extends JSScope {
         else if (wasinside && !isinside && getTrap("Leave") != null) putAndTriggerTraps("Leave", T);
         else if (wasinside && isinside && (mousex != oldmousex || mousey != oldmousey) && getTrap("Move")!= null)
             putAndTriggerTraps("Move", T);
-        for(Box b = getChild(numchildren - 1); b != null; b = b.prevSibling()) {
+        for(Box b = getChild(treeSize() - 1); b != null; b = b.prevSibling()) {
             b.Move(oldmousex - b.x, oldmousey - b.y, mousex - b.x, mousey - b.y, forceleave);
             if (b.inside(mousex - b.x, mousey - b.y)) forceleave = true;
         }
@@ -363,9 +363,6 @@ public final class Box extends JSScope {
 
     public Enumeration keys() { throw new Error("you cannot apply for..in to a " + this.getClass().getName()); }
 
-    /** to be filled in by the Tree implementation */
-    public int numchildren = 0;
-
     protected boolean isTrappable() { return true; }
     public Object get(Object name) {
         if (name instanceof Number)
@@ -403,7 +400,7 @@ public final class Box extends JSScope {
         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 "numchildren": return redirect == null ? N(0) : redirect == this ? N(numchildren) : redirect.get("numchildren");
+        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);
@@ -423,7 +420,6 @@ public final class Box extends JSScope {
         case "textcolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); MARK_RESIZE; dirty();
         case "text": CHECKSET_STRING(text); MARK_RESIZE; dirty();
         case "strokewidth": CHECKSET_SHORT(strokewidth); dirty();
-        case "thisbox": if (value == null) remove();
         case "shrink": put("hshrink", value); put("vshrink", value);
         case "hshrink": CHECKSET_FLAG(HSHRINK); MARK_RESIZE;
         case "vshrink": CHECKSET_FLAG(VSHRINK); MARK_RESIZE;
@@ -473,6 +469,12 @@ public final class Box extends JSScope {
         case "SizeChange":   return;  // prevent stuff from hitting the Hash
         case "childadded":   return;  // prevent stuff from hitting the Hash
         case "childremoved": return;  // prevent stuff from hitting the Hash
+        case "thisbox": {
+            if (value != null) break;
+            if (parent != null) { parent.removeChild(parent.indexNode(this)); return; }
+            Surface surface = Surface.fromBox(this); 
+            if (surface != null) surface.dispose(true);
+        }
         default: super.put(name, value);
         //#end
     }
@@ -595,7 +597,7 @@ public final class Box extends JSScope {
         if (!cur.test(VISIBLE)) return null;
         if (!cur.inside(x - globalx, y - globaly)) return cur.parent == null ? cur : null;
         OUTER: while(true) {
-            for(int i=cur.numchildren - 1; i>=0; i--) {
+            for(int i=cur.treeSize() - 1; i>=0; i--) {
                 Box child = cur.getChild(i);
                 if (child == null) continue;        // since this method is unsynchronized, we have to double-check
                 globalx += child.x;
@@ -630,347 +632,44 @@ public final class Box extends JSScope {
     void clear(int mask) { flags &= ~mask; }
     boolean test(int mask) { return ((flags & mask) == mask); }
     
-    protected Box left = null;
-    protected Box right = null;
-    protected Box rootChild = null;
-    protected Box peerTree_parent = null;
-
 
     // Tree Handling //////////////////////////////////////////////////////////////////////
 
-
-    private static boolean REDbool = false;
-    private static boolean BLACKbool = true;
-
-    public final Box peerTree_leftmost() { for (Box p = this; ; p = p.left) if (p.left == null) return p; }
-    public final Box peerTree_rightmost() { for (Box p = this; ; p = p.right) if (p.right == null) return p; }
-    static Box     peerTree_parent(Box p) { return (p == null)? null: p.peerTree_parent; }
-
-    public void insertBeforeMe(Box cell) { left = cell; cell.peerTree_parent = this; cell.fixAfterInsertion(); }
-    public void insertAfterMe(Box cell) { right = cell; cell.peerTree_parent = this; cell.fixAfterInsertion(); }
-
-    static boolean colorOf(Box p) { return (p == null) ? BLACKbool : p.test(BLACK); }
-    static void    setColor(Box p, boolean c) { if (p != null) { if (c) p.set(BLACK); else p.clear(BLACK); } }
-    static Box     leftOf(Box p) { return (p == null)? null: p.left; }
-    static Box     rightOf(Box p) { return (p == null)? null: p.right; }
-
+    // FIXME inefficient
     public final Box nextSibling() {
-        if (right != null)
-            return right.peerTree_leftmost();
-        else {
-            Box p = peerTree_parent;
-            Box ch = this;
-            while (p != null && ch == p.right) { ch = p; p = p.peerTree_parent; }
-            return p;
-        }
+        int index = parent.indexNode(this);
+        if (index >= parent.treeSize() - 1) return null;
+        return parent.getChild(index + 1);
     }
 
+    // FIXME inefficient
     public final Box prevSibling() {
-        if (left != null)
-            return left.peerTree_rightmost();
-        else {
-            Box p = peerTree_parent;
-            Box ch = this;
-            while (p != null && ch == p.left) { ch = p; p = p.peerTree_parent; }
-            return p;
-        }
-    }
-
-    public void removeNode() {
-
-        // handle case where we are only node
-        if (left == null && right == null && peerTree_parent == null) return;
-
-        // if strictly internal, swap places with a successor
-        if (left != null && right != null) {
-            Box s = nextSibling();
-            // To work nicely with arbitrary subclasses of Box, we don't want to
-            // just copy successor's fields. since we don't know what
-            // they are.  Instead we swap positions in the tree.
-            swapPosition(this, s);
-        }
-
-        // Start fixup at replacement node (normally a child).
-        // But if no children, fake it by using self
-
-        if (left == null && right == null) {
-      
-            if (test(BLACK)) fixAfterDeletion();
-
-            // Unlink  (Couldn't before since fixAfterDeletion needs peerTree_parent ptr)
-
-            if (peerTree_parent != null) {
-                if (this == peerTree_parent.left) 
-                    peerTree_parent.left = null;
-                else if (this == peerTree_parent.right) 
-                    peerTree_parent.right = null;
-                peerTree_parent = null;
-            }
-
-        }
-        else {
-            Box replacement = left;
-            if  (replacement == null) replacement = right;
-       
-            // link replacement to peerTree_parent 
-            replacement.peerTree_parent = peerTree_parent;
-
-            if (peerTree_parent == null) parent.rootChild = replacement; 
-            else if (this == peerTree_parent.left)  peerTree_parent.left  = replacement;
-            else peerTree_parent.right = replacement;
-
-            left = null;
-            right = null;
-            peerTree_parent = null;
-
-            // fix replacement
-            if (test(BLACK)) replacement.fixAfterDeletion();
-      
-        }
-    }
-
-    /**
-     * Swap the linkages of two nodes in a tree.
-     * Return new root, in case it changed.
-     **/
-    void swapPosition(Box x, Box y) {
-
-        /* Too messy. TODO: find sequence of assigments that are always OK */
-
-        Box px = x.peerTree_parent; 
-        boolean xpl = px != null && x == px.left;
-        Box lx = x.left;
-        Box rx = x.right;
-
-        Box py = y.peerTree_parent;
-        boolean ypl = py != null && y == py.left;
-        Box ly = y.left;
-        Box ry = y.right;
-
-        if (x == py) {
-            y.peerTree_parent = px;
-            if (px != null) if (xpl) px.left = y; else px.right = y;
-            x.peerTree_parent = y;
-            if (ypl) { 
-                y.left = x; 
-                y.right = rx; if (rx != null) rx.peerTree_parent = y;
-            }
-            else {
-                y.right = x;
-                y.left = lx;   if (lx != null) lx.peerTree_parent = y;
-            }
-            x.left = ly;   if (ly != null) ly.peerTree_parent = x;
-            x.right = ry;  if (ry != null) ry.peerTree_parent = x;
-        }
-        else if (y == px) {
-            x.peerTree_parent = py;
-            if (py != null) if (ypl) py.left = x; else py.right = x;
-            y.peerTree_parent = x;
-            if (xpl) { 
-                x.left = y; 
-                x.right = ry; if (ry != null) ry.peerTree_parent = x;
-            }
-            else {
-                x.right = y;
-                x.left = ly;   if (ly != null) ly.peerTree_parent = x;
-            }
-            y.left = lx;   if (lx != null) lx.peerTree_parent = y;
-            y.right = rx;  if (rx != null) rx.peerTree_parent = y;
-        }
-        else {
-            x.peerTree_parent = py; if (py != null) if (ypl) py.left = x; else py.right = x;
-            x.left = ly;   if (ly != null) ly.peerTree_parent = x;
-            x.right = ry;  if (ry != null) ry.peerTree_parent = x;
-      
-            y.peerTree_parent = px; if (px != null) if (xpl) px.left = y; else px.right = y;
-            y.left = lx;   if (lx != null) lx.peerTree_parent = y;
-            y.right = rx;  if (rx != null) rx.peerTree_parent = y;
-        }
-
-        boolean c = x.test(BLACK);
-        if (y.test(BLACK)) x.set(BLACK); else x.clear(BLACK);
-        if (c) y.set(BLACK); else y.clear(BLACK);
-
-        if (parent.rootChild == x) parent.rootChild = y;
-        else if (parent.rootChild == y) parent.rootChild = x;
+        int index = parent.indexNode(this);
+        if (index <= 0) return null;
+        return parent.getChild(index - 1);
     }
 
-    void rotateLeft() {
-        Box r = right;
-        right = r.left;
-        if (r.left != null) r.left.peerTree_parent = this;
-        r.peerTree_parent = peerTree_parent;
-        if (peerTree_parent == null) parent.rootChild = r;
-        else if (peerTree_parent.left == this) peerTree_parent.left = r;
-        else peerTree_parent.right = r;
-        r.left = this;
-        peerTree_parent = r;
-    }
-
-    void rotateRight() {
-        Box l = left;
-        left = l.right;
-        if (l.right != null) l.right.peerTree_parent = this;
-        l.peerTree_parent = peerTree_parent;
-        if (peerTree_parent == null) parent.rootChild = l;
-        else if (peerTree_parent.right == this) peerTree_parent.right = l;
-        else peerTree_parent.left = l;
-        l.right = this;
-        peerTree_parent = l;
-    }
-
-    void fixAfterInsertion() {
-        clear(BLACK);
-        Box x = this;
-    
-        while (x != null && x != parent.rootChild && !x.peerTree_parent.test(BLACK)) {
-            if (peerTree_parent(x) == leftOf(peerTree_parent(peerTree_parent(x)))) {
-                Box y = rightOf(peerTree_parent(peerTree_parent(x)));
-                if (colorOf(y) == REDbool) {
-                    setColor(peerTree_parent(x), BLACKbool);
-                    setColor(y, BLACKbool);
-                    setColor(peerTree_parent(peerTree_parent(x)), REDbool);
-                    x = peerTree_parent(peerTree_parent(x));
-                }
-                else {
-                    if (x == rightOf(peerTree_parent(x))) {
-                        x = peerTree_parent(x);
-                        x.rotateLeft();
-                    }
-                    setColor(peerTree_parent(x), BLACKbool);
-                    setColor(peerTree_parent(peerTree_parent(x)), REDbool);
-                    if (peerTree_parent(peerTree_parent(x)) != null) 
-                        peerTree_parent(peerTree_parent(x)).rotateRight();
-                }
-            }
-            else {
-                Box y = leftOf(peerTree_parent(peerTree_parent(x)));
-                if (colorOf(y) == REDbool) {
-                    setColor(peerTree_parent(x), BLACKbool);
-                    setColor(y, BLACKbool);
-                    setColor(peerTree_parent(peerTree_parent(x)), REDbool);
-                    x = peerTree_parent(peerTree_parent(x));
-                }
-                else {
-                    if (x == leftOf(peerTree_parent(x))) {
-                        x = peerTree_parent(x);
-                        x.rotateRight();
-                    }
-                    setColor(peerTree_parent(x),  BLACKbool);
-                    setColor(peerTree_parent(peerTree_parent(x)), REDbool);
-                    if (peerTree_parent(peerTree_parent(x)) != null) 
-                        peerTree_parent(peerTree_parent(x)).rotateLeft();
-                }
-            }
-        }
-        parent.rootChild.set(BLACK);
-    }
-
-    /** From CLR **/
-    void fixAfterDeletion() {
-        Box x = this;
-        while (x != parent.rootChild && colorOf(x) == BLACKbool) {
-            if (x == leftOf(peerTree_parent(x))) {
-                Box sib = rightOf(peerTree_parent(x));
-                if (colorOf(sib) == REDbool) {
-                    setColor(sib, BLACKbool);
-                    setColor(peerTree_parent(x), REDbool);
-                    peerTree_parent(x).rotateLeft();
-                    sib = rightOf(peerTree_parent(x));
-                }
-                if (colorOf(leftOf(sib)) == BLACKbool && colorOf(rightOf(sib)) == BLACKbool) {
-                    setColor(sib,  REDbool);
-                    x = peerTree_parent(x);
-                }
-                else {
-                    if (colorOf(rightOf(sib)) == BLACKbool) {
-                        setColor(leftOf(sib), BLACKbool);
-                        setColor(sib, REDbool);
-                        sib.rotateRight();
-                        sib = rightOf(peerTree_parent(x));
-                    }
-                    setColor(sib, colorOf(peerTree_parent(x)));
-                    setColor(peerTree_parent(x), BLACKbool);
-                    setColor(rightOf(sib), BLACKbool);
-                    peerTree_parent(x).rotateLeft();
-                    x = parent.rootChild;
-                }
-            }
-            else {
-                Box sib = leftOf(peerTree_parent(x));
-                if (colorOf(sib) == REDbool) {
-                    setColor(sib, BLACKbool);
-                    setColor(peerTree_parent(x), REDbool);
-                    peerTree_parent(x).rotateRight();
-                    sib = leftOf(peerTree_parent(x));
-                }
-                if (colorOf(rightOf(sib)) == BLACKbool && colorOf(leftOf(sib)) == BLACKbool) {
-                    setColor(sib,  REDbool);
-                    x = peerTree_parent(x);
-                }
-                else {
-                    if (colorOf(leftOf(sib)) == BLACKbool) {
-                        setColor(rightOf(sib), BLACKbool);
-                        setColor(sib, REDbool);
-                        sib.rotateLeft();
-                        sib = leftOf(peerTree_parent(x));
-                    }
-                    setColor(sib, colorOf(peerTree_parent(x)));
-                    setColor(peerTree_parent(x), BLACKbool);
-                    setColor(leftOf(sib), BLACKbool);
-                    peerTree_parent(x).rotateRight();
-                    x = parent.rootChild;
-                }
-            }
-        }
-        setColor(x, BLACKbool);
+    public final Box getChild(int i) {
+        if (i < 0) return null;
+        if (i >= treeSize()) return null;
+        return (Box)getNode(i);
     }
+    public final int getIndexInParent() { return parent == null ? 0 : parent.indexNode(this); }
 
     // Tree Manipulation /////////////////////////////////////////////////////////////////////
 
-    /** remove this node from its parent; INVARIANT: whenever the parent of a node is changed, remove() gets called. */
-    public void remove() {
-        if (parent == null) {
-            Surface surface = Surface.fromBox(this); 
-            if (surface != null) surface.dispose(true);
-            return;
-        } else {
-            parent.numchildren--;
-        }
-        Box oldparent = parent;
-        if (oldparent == null) return;
+    /** remove the i^th child */
+    public void removeChild(int i) {
+        Box b = getChild(i);
+        MARK_REFLOW_b;
+        b.dirty();
+        b.clear(MOUSEINSIDE);
+        deleteNode(i);
+        b.parent = null;
         MARK_REFLOW;
-        dirty();
-        clear(MOUSEINSIDE);
-        removeNode();
-        parent = null;
-        if (oldparent != null) { Box b = oldparent; MARK_REFLOW_b; }
-        if (oldparent != null) oldparent.putAndTriggerTraps("childremoved", this);
-    }
-
-    /** Returns ith child */
-    public Box getChild(int i) {
-        // FIXME: store numleft and numright in the tree
-        Box left = rootChild;
-        if (left == null) return null;
-        while (left.left != null) left = left.left;
-        for(; i > 0; i--) left = left.nextSibling();
-        return left;
+        putAndTriggerTraps("childremoved", b);
     }
     
-    /** Returns our index in our parent */
-    public int getIndexInParent() {
-        // FIXME: store numleft and numright in the tree
-        if (peerTree_parent == null) return left == null ? 0 : left.numPeerChildren() + 1;
-        else if (peerTree_parent.left == this) return peerTree_parent.getIndexInParent() - 1;
-        else if (peerTree_parent.right == this) return peerTree_parent.getIndexInParent() + 1;
-        else throw new Error("we're not a child of our parent!");
-    }
-
-    public int numPeerChildren() {
-        return (left == null ? 0 : left.numPeerChildren() + 1) + (right == null ? 0 : right.numPeerChildren() + 1);
-    }
-
     public void put(int i, Object value) {
         if (i < 0) return;
             
@@ -992,9 +691,9 @@ public final class Box extends JSScope {
             }
 
         } else if (value == null) {
-            if (i < 0 || i > numchildren) return;
+            if (i < 0 || i > treeSize()) return;
             Box b = getChild(i);
-            b.remove();
+            removeChild(i);
             putAndTriggerTraps("childremoved", b);
 
         } else {
@@ -1015,16 +714,9 @@ public final class Box extends JSScope {
                     return;
                 }
 
-            b.remove();
+            if (b.parent != null) b.parent.removeChild(b.parent.indexNode(b));
+            insertNode(i, b);
             b.parent = this;
-            numchildren++;
-
-            Box before = getChild(i);
-            if (before == null) {
-                if (rootChild == null) rootChild = b;
-                else rootChild.peerTree_rightmost().insertAfterMe(b);
-            }
-            else before.insertBeforeMe(b);
             
             // need both of these in case child was already uncalc'ed
             MARK_REFLOW_b;
index fb9585a..ac2a837 100644 (file)
@@ -298,7 +298,7 @@ public abstract class Surface extends PixelBuffer {
         this.root = root;
         Surface old = fromBox(root);
         if (old != null) old.dispose(false);
-        else root.remove();
+        else root.put("thisbox", null);
 
         // make sure the root is properly sized
         do { abort = false; root.reflow(root.width, root.height); } while(abort);
index 2921cde..2dbaa3b 100644 (file)
@@ -126,7 +126,7 @@ public class Template {
         for (int i=0; children != null && i<children.size(); i++) {
             Box kid = new Box();
             ((Template)children.elementAt(i)).apply(kid, xwt, pis);
-            b.putAndTriggerTraps(JS.N(b.numchildren), kid);
+            b.putAndTriggerTraps(JS.N(b.treeSize()), kid);
         }
 
         if (script != null) script.cloneWithNewParentScope(pis).call(null, null, null, null, 0);