X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2FBox.java;h=3da445a86b5ffecfddef6c40a5edac73739a1d69;hb=bc6ac951869686b84803f45f549ccb888a9f776c;hp=b7512bbb3938eaf8b610d6c3c3537ef52972ea50;hpb=add9c1c1765814ff41c3ae54ec0e5496aa747c6e;p=org.ibex.core.git diff --git a/src/org/xwt/Box.java b/src/org/xwt/Box.java index b7512bb..3da445a 100644 --- a/src/org/xwt/Box.java +++ b/src/org/xwt/Box.java @@ -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; } @@ -205,7 +205,7 @@ public final class Box extends JSScope { short r = 0; for(Box child = firstPackedChild(); child != null; r++) { for(short c=0, numclear=0; child != null && c < cols; c++) { - if (numRowsInCol[c] > r) continue; + if (numRowsInCol[c] > r) { numclear = 0; continue; } if (c != 0 && c + min(cols, child.colspan) - numclear > cols) break; if (++numclear < min(cols, child.colspan)) continue; for(int i=c - numclear + 1; i <= c; i++) numRowsInCol[i] += child.rowspan; @@ -363,11 +363,8 @@ 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) { + public Object get(Object name) throws JSExn { if (name instanceof Number) return redirect == null ? null : redirect == this ? getChild(toInt(name)) : redirect.get(name); @@ -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); @@ -412,19 +409,17 @@ public final class Box extends JSScope { case "Minimized": if (parent == null && getSurface() != null) return B(getSurface().minimized); default: return super.get(name); //#end - return null; + throw new Error("unreachable"); // unreachable } - public void put(Object name, Object value) { + 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); MARK_RESIZE; dirty(); case "strokecolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); MARK_RESIZE; dirty(); 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; @@ -435,7 +430,7 @@ public final class Box extends JSScope { case "maxheight": CHECKSET_INT(maxheight); MARK_RESIZE; case "minheight": CHECKSET_INT(minheight); MARK_RESIZE; case "colspan": CHECKSET_SHORT(colspan); MARK_REPACK_parent; - case "rowspan": 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; case "cols": CHECKSET_SHORT(cols); if (cols==0){set(FIXED, ROWS);if(rows==0)rows=1;} else set(FIXED, COLS); MARK_REPACK; case "noclip": CHECKSET_FLAG(NOCLIP); if (parent == null) dirty(); else parent.dirty(); @@ -468,12 +463,19 @@ public final class Box extends JSScope { case "fontsize": font = Font.getFont(font == null ? null : font.res, toInt(value)); MARK_RESIZE; dirty(); case "x": if (test(PACKED) && parent != null) return; CHECKSET_INT(x); dirty(); MARK_RESIZE; dirty(); case "y": if (test(PACKED) && parent != null) return; CHECKSET_INT(y); dirty(); MARK_RESIZE; dirty(); - case "KeyPressed": // prevent stuff from hitting the Hash - case "KeyReleased": // prevent stuff from hitting the Hash - case "PosChange": // prevent stuff from hitting the Hash - case "SizeChange": // prevent stuff from hitting the Hash - case "childadded": // prevent stuff from hitting the Hash - case "childremoved": // prevent stuff from hitting the Hash + case "KeyPressed": return; // prevent stuff from hitting the Hash + case "KeyReleased": return; // prevent stuff from hitting the Hash + case "PosChange": return; // prevent stuff from hitting the Hash + 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,361 +632,33 @@ 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 Box insertBeforeMe(Box cell) { left = cell; cell.peerTree_parent = this; return cell.fixAfterInsertion(); } - public Box insertAfterMe(Box cell) { right = cell; cell.peerTree_parent = this; return 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; } - - 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; - } - } - - 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 Box removeNode() { - Box root = peerTree_parent.rootChild; - - // handle case where we are only node - if (left == null && right == null && peerTree_parent == null) return null; - - // 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. - root = 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)) root = this.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) root = 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)) root = replacement.fixAfterDeletion(); - - } - - return root; - } - - /** - * Swap the linkages of two nodes in a tree. - * Return new root, in case it changed. - **/ - Box swapPosition(Box x, Box y) { - Box root = peerTree_parent.rootChild; - - /* 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 (root == x) root = y; - else if (root == y) root = x; - return parent.rootChild = root; - } - - Box rotateLeft() { - Box root = parent.rootChild; - Box r = right; - right = r.left; - if (r.left != null) r.left.peerTree_parent = this; - r.peerTree_parent = peerTree_parent; - if (peerTree_parent == null) root = r; - else if (peerTree_parent.left == this) peerTree_parent.left = r; - else peerTree_parent.right = r; - r.left = this; - peerTree_parent = r; - return parent.rootChild = root; - } - - Box rotateRight() { - Box root = parent.rootChild; - Box l = left; - left = l.right; - if (l.right != null) l.right.peerTree_parent = this; - l.peerTree_parent = peerTree_parent; - if (peerTree_parent == null) root = l; - else if (peerTree_parent.right == this) peerTree_parent.right = l; - else peerTree_parent.left = l; - l.right = this; - peerTree_parent = l; - return parent.rootChild; - } - - Box fixAfterInsertion() { - Box root = parent.rootChild; - clear(BLACK); - Box x = this; - - while (x != null && x != root && !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); - root = x.rotateLeft(); - } - setColor(peerTree_parent(x), BLACKbool); - setColor(peerTree_parent(peerTree_parent(x)), REDbool); - if (peerTree_parent(peerTree_parent(x)) != null) - root = 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); - root = x.rotateRight(); - } - setColor(peerTree_parent(x), BLACKbool); - setColor(peerTree_parent(peerTree_parent(x)), REDbool); - if (peerTree_parent(peerTree_parent(x)) != null) - root = peerTree_parent(peerTree_parent(x)).rotateLeft(); - } - } - } - root.set(BLACK); - return parent.rootChild = root; - } - - /** From CLR **/ - Box fixAfterDeletion() { - Box root = peerTree_parent.rootChild; - Box x = this; - while (x != root && 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); - root = 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); - root = sib.rotateRight(); - sib = rightOf(peerTree_parent(x)); - } - setColor(sib, colorOf(peerTree_parent(x))); - setColor(peerTree_parent(x), BLACKbool); - setColor(rightOf(sib), BLACKbool); - root = peerTree_parent(x).rotateLeft(); - x = root; - } - } - else { - Box sib = leftOf(peerTree_parent(x)); - if (colorOf(sib) == REDbool) { - setColor(sib, BLACKbool); - setColor(peerTree_parent(x), REDbool); - root = 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); - root = sib.rotateLeft(); - sib = leftOf(peerTree_parent(x)); - } - setColor(sib, colorOf(peerTree_parent(x))); - setColor(peerTree_parent(x), BLACKbool); - setColor(leftOf(sib), BLACKbool); - root = peerTree_parent(x).rotateRight(); - x = root; - } - } - } - setColor(x, BLACKbool); - return parent.rootChild = root; + public final int getIndexInParent() { return parent == null ? 0 : parent.indexNode(this); } + public final Box nextSibling() { return parent == null ? null : parent.getChild(parent.indexNode(this) + 1); } + public final Box prevSibling() { return parent == null ? null : parent.getChild(parent.indexNode(this) - 1); } + public final Box getChild(int i) { + if (i < 0) return null; + if (i >= treeSize()) return null; + return (Box)getNode(i); } // 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) { + public void put(int i, Object value) throws JSExn { if (i < 0) return; if (value != null && !(value instanceof Box)) { @@ -1005,9 +679,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 { @@ -1028,16 +702,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; @@ -1048,6 +715,25 @@ public final class Box extends JSScope { } } + + public final void putAndTriggerTraps(Object key, Object value) { + try { + super.putAndTriggerTraps(key, value); + } catch (JSExn jse) { + Log.logJS("attempt to put value " + value + " to key " + key + " on a box triggered a trap which threw:"); + Log.logJS(jse); + } + } + + public final Object getAndTriggerTraps(Object key) { + try { + return super.getAndTriggerTraps(key); + } catch (JSExn jse) { + Log.logJS("attempt to get key " + key + " on a box triggered a trap which threw:"); + Log.logJS(jse); + return null; + } + } }