- private void renderBorder(int x, int y, int w, int h, DoubleBuffer buf) {
- int bw = border[4].getWidth();
- int bh = border[4].getHeight();
- buf.setClip(x, y, w + x, h + y);
-
- if ((color & 0xFF000000) != 0xFF000000) {
- // if the color is null, we have to be very careful about drawing the corners
- //if (Log.verbose) Log.log(this, "WARNING: (color == null && border != null) on box with border " + imageToNameMap.get(border[4]));
-
- // upper left corner
- buf.drawPicture(border[4],
- pos(0), pos(1), pos(0) + bw / 2, pos(1) + bh / 2,
- 0, 0, bw / 2, bh / 2);
-
- // upper right corner
- buf.drawPicture(border[4],
- pos(0) + size(0) - bw / 2, pos(1), pos(0) + size(0), pos(1) + bh / 2,
- bw - bw / 2, 0, bw, bh / 2);
-
- // lower left corner
- buf.drawPicture(border[4],
- pos(0), pos(1) + size(1) - bh / 2, pos(0) + bw / 2, pos(1) + size(1),
- 0, bh - bh / 2, bw / 2, bh);
-
- // lower right corner
- buf.drawPicture(border[4],
- pos(0) + size(0) - bw / 2, pos(1) + size(1) - bh / 2, pos(0) + size(0), pos(1) + size(1),
- bw - bw / 2, bh - bh / 2, bw, bh);
-
- } else {
- buf.drawPicture(border[4], pos(0), pos(1)); // upper left corner
- buf.drawPicture(border[4], pos(0) + size(0) - bw, pos(1)); // upper right corner
- buf.drawPicture(border[4], pos(0), pos(1) + size(1) - bh); // lower left corner
- buf.drawPicture(border[4], pos(0) + size(0) - bw, pos(1) + size(1) - bh); // lower right corner
-
- }
-
- // top and bottom edges
- buf.setClip(max(x, pos(0) + bw / 2), y, min(x + w, pos(0) + size(0) - bw / 2), h + y);
- for(int i = max(x, pos(0) + bw / 2); i + 100 < min(x + w, pos(0) + size(0) - bw / 2); i += 100) {
- buf.drawPicture(border[0], i, pos(1));
- buf.drawPicture(border[1], i, pos(1) + size(1) - bh / 2);
- }
- buf.drawPicture(border[0], min(x + w, pos(0) + size(0) - bw / 2) - 100, pos(1));
- buf.drawPicture(border[1], min(x + w, pos(0) + size(0) - bw / 2) - 100, pos(1) + size(1) - bh / 2);
-
- // left and right edges
- buf.setClip(x, max(y, pos(1) + bh / 2), w + x, min(y + h, pos(1) + size(1) - bh / 2));
- for(int i = max(y, pos(1) + bh / 2); i + 100 < min(y + h, pos(1) + size(1) - bh / 2); i += 100) {
- buf.drawPicture(border[2], pos(0), i);
- buf.drawPicture(border[3], pos(0) + size(0) - bw / 2, i);
+ 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 "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 "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 "noclip": return B(test(NOCLIP));
+ 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 "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);
+ //#end
+ 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); }
+
+ 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;
+ case "maxheight": setMaxHeight(value);
+ case "minheight": CHECKSET_INT(minheight); MARK_RESIZE;
+ 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 "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 "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 "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.log(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 "_Move": propagateDownward(name, value, false);
+ case "_Press1": propagateDownward(name, value, false);
+ case "_Press2": propagateDownward(name, value, false);
+ case "_Press3": propagateDownward(name, value, false);
+ case "_Release1": propagateDownward(name, value, false);
+ case "_Release2": propagateDownward(name, value, false);
+ case "_Release3": propagateDownward(name, value, false);
+ case "_Click1": propagateDownward(name, value, false);
+ case "_Click2": propagateDownward(name, value, false);
+ case "_Click3": propagateDownward(name, value, false);
+ case "_DoubleClick1": propagateDownward(name, value, false);
+ case "_DoubleClick2": propagateDownward(name, value, false);
+ case "_DoubleClick3": propagateDownward(name, value, false);
+ case "_KeyPressed": propagateDownward(name, value, false);
+ case "_KeyReleased": propagateDownward(name, value, false);
+
+ case "PosChange": return;
+ case "SizeChange": return;
+ case "childadded": return;
+ case "childremoved": return;
+
+ case "thisbox": if (value == null) removeSelf();
+
+ default: super.put(name, value);
+ //#end
+ }
+
+ private String alignToString() {
+ switch(flags & ALIGNS) {
+ case (ALIGN_TOP | ALIGN_LEFT): return "topleft";
+ case (ALIGN_BOTTOM | ALIGN_LEFT): return "bottomleft";
+ case (ALIGN_TOP | ALIGN_RIGHT): return "topright";
+ case (ALIGN_BOTTOM | ALIGN_RIGHT): return "bottomright";
+ case ALIGN_TOP: return "top";
+ case ALIGN_BOTTOM: return "bottom";
+ case ALIGN_LEFT: return "left";
+ case ALIGN_RIGHT: return "right";
+ case 0: return "center";
+ default: throw new Error("invalid alignment flags: " + (flags & ALIGNS));
+ }
+ }
+
+ private void setAlign(Object value) {
+ //#switch(value)
+ case "center": clear(ALIGNS);
+ case "topleft": set(ALIGN_TOP | ALIGN_LEFT);
+ case "bottomleft": set(ALIGN_BOTTOM | ALIGN_LEFT);
+ case "topright": set(ALIGN_TOP | ALIGN_RIGHT);
+ case "bottomright": set(ALIGN_BOTTOM | ALIGN_RIGHT);
+ case "top": set(ALIGN_TOP);
+ case "bottom": set(ALIGN_BOTTOM);
+ case "left": set(ALIGN_LEFT);
+ case "right": set(ALIGN_RIGHT);
+ default: Log.logJS("invalid alignment \"" + value + "\"");
+ //#end
+ }
+
+ private void setCursor(Object value) {
+ if (value == null) { clear(CURSOR); boxToCursor.remove(this); return; }
+ if (value.equals(boxToCursor.get(this))) return;
+ set(CURSOR);
+ boxToCursor.put(this, value);
+ Surface surface = getSurface();
+ String tempcursor = surface.cursor;
+ // FIXME
+ //Move(surface.mousex, surface.mousey, surface.mousex, surface.mousey);
+ if (surface.cursor != tempcursor) surface.syncCursor();
+ }
+
+ private void setFill(Object value) {
+ if (value == null) return;
+ if (value instanceof String) {
+ // FIXME check double set
+ int newfillcolor = stringToColor((String)value);
+ if (newfillcolor == fillcolor) return;
+ fillcolor = newfillcolor;
+ dirty();
+ return;