+ public int globalToLocalX(int x) { return parent == null ? x : parent.globalToLocalX(x - this.x); }
+ public int globalToLocalY(int y) { return parent == null ? y : parent.globalToLocalY(y - this.y); }
+ public int localToGlobalX(int x) { return parent == null ? x : parent.globalToLocalX(x + this.x); }
+ public int localToGlobalY(int y) { return parent == null ? y : parent.globalToLocalY(y + this.y); }
+
+ public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+ if (nargs != 1 || !"indexof".equals(method)) return super.callMethod(method, a0, a1, a2, rest, nargs);
+ Box b = (Box)a0;
+ if (b.parent != this)
+ return (redirect == null || redirect == this) ?
+ N(-1) :
+ redirect.callMethod(method, a0, a1, a2, rest, nargs);
+ return N(b.getIndexInParent());
+ }
+
+ public Enumeration keys() { throw new Error("you cannot apply for..in to a " + this.getClass().getName()); }
+
+ 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);
+
+ //#switch(name)
+ 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 "fontsize": return font == null ? N(10) : N(font.pointsize);
+ case "strokewidth": return N(strokewidth);
+ case "align": return alignToString();
+ case "thisbox": return this;
+ case "shrink": return B(test(HSHRINK) || test(VSHRINK));
+ case "hshrink": return B(test(HSHRINK));
+ case "vshrink": return B(test(VSHRINK));
+ 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 "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));
+ case "globalx": return N(localToGlobalX(0));
+ case "globaly": return N(localToGlobalY(0));
+ case "cursor": return test(CURSOR) ? boxToCursor.get(this) : null;
+ 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 "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);
+ //#end
+ throw new Error("unreachable"); // unreachable
+ }
+
+ 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(test(MOUSEINSIDE));
+ //#end
+ return null;
+ }
+ }
+
+ void setMaxWidth(Object value) {
+ do { CHECKSET_INT(maxwidth); MARK_RESIZE; } while(false);
+ if (parent == null && getSurface() != null) getSurface().pendingWidth = maxwidth;
+ }
+ void setMaxHeight(Object value) {
+ do { CHECKSET_INT(maxheight); MARK_RESIZE; } while(false);
+ if (parent == null && getSurface() != null) getSurface().pendingHeight = maxheight;
+ }
+
+ 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 "shrink": put("hshrink", value); put("vshrink", value);
+ case "hshrink": CHECKSET_FLAG(HSHRINK); MARK_RESIZE;
+ case "vshrink": CHECKSET_FLAG(VSHRINK); MARK_RESIZE;
+ case "width": put("maxwidth", value); put("minwidth", value); MARK_RESIZE;
+ 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;
+ case "cols": CHECKSET_SHORT(cols); if (cols==0){set(FIXED, ROWS);if(rows==0)rows=1;} else set(FIXED, COLS); MARK_REPACK;
+ case "clip": CHECKSET_FLAG(CLIP); 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 "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);
+ case "redirect": if (redirect == this) redirect = (Box)value; else Log.info(this, "redirect can only be set once");
+ 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.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 "titlebar":
+ if (getSurface() != null && value != null) getSurface().setTitleBarText(JS.toString(value));
+ super.put(name,value);