- /**
- * A helper class for properties of Box which require special
- * handling.
- *
- * To avoid excessive use of String.equals(), the Box.get() and
- * Box.put() methods employ a Hash keyed on property names that
- * require special handling. The value stored in the Hash is an
- * instance of an anonymous subclass of SpecialBoxProperty, which knows
- * how to handle get()s and put()s for that property name. There
- * should be one anonymous subclass of SpecialBoxProperty for each
- * specially-handled property on Box.
- */
- static class SpecialBoxProperty {
-
- SpecialBoxProperty() { }
-
- /** stores instances of SpecialBoxProperty; keyed on property name */
- static Hash specialBoxProperties = new Hash(200, 3);
-
- /** this method defines the behavior when the property is get()ed from b */
- Object get(Box b) { return null; }
-
- /** this method defines the behavior when the property is put() to b */
- void put(Box b, Object value) { }
-
- /** this method defines the behavior when the property is put() to b, allows a single SpecialBoxProperty to serve multiple properties */
- void put(String name, Box b, Object value) { put(b, value); }
-
- static {
- specialBoxProperties.put("fill", new ColorBoxProperty() {
- public void put(final Box b, final Object value) {
- if (value == null || !(value instanceof Res)) super.put(b, value);
- else {
- Callback callback = new Callback() { public Object call(Object pic) {
- b.image = (Picture)pic;
- b.minwidth = b.image.getWidth();
- b.minheight = b.image.getHeight();
- MARK_FOR_REFLOW_b;
- b.dirty();
- return null;
- } };
- Picture pic = Picture.fromRes((Res)value, callback);
- if (pic != null) callback.call(pic);
- }
- }
- public int getColor(Box b) { return b.fillcolor; }
- public void putColor(Box b, int argb) { b.fillcolor = argb; }
- });
- specialBoxProperties.put("textcolor", new ColorBoxProperty() {
- public int getColor(Box b) { return b.textcolor; }
- public void putColor(Box b, int argb) { b.textcolor = argb; }
- });
- specialBoxProperties.put("strokecolor", new ColorBoxProperty() {
- public int getColor(Box b) { return b.strokecolor; }
- public void putColor(Box b, int argb) { b.strokecolor = argb; }
- });
-
- specialBoxProperties.put("text", new SpecialBoxProperty() {
- public Object get(Box b) { return b.text; }
- public void put(Box b, Object value) {
- String t = value == null ? "null" : value.toString();
- if (t.equals(b.text)) return;
- b.text = t;
- b.dirty();
- b.recompute_font();
- } });
-
- specialBoxProperties.put("path", new SpecialBoxProperty() {
- public Object get(Box b) { throw new JS.Exn("cannot read from the path property"); }
- public void put(Box b, Object value) {
- String t = value == null ? "null" : value.toString();
- b.path = value == null ? null : VectorGraphics.parseVectorPath(value.toString());
- MARK_FOR_REFLOW_b;
- b.dirty();
- } });
-
- specialBoxProperties.put("transform", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- String t = value.toString().trim();
- b.transform = VectorGraphics.Affine.identity();
- while (t.length() > 0) {
- if (t.startsWith("skewX(")) {
- // FIXME
-
- } else if (t.startsWith("shear(")) {
- // FIXME: nonstandard; remove this
- b.transform.multiply(VectorGraphics.Affine.shear(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')')))));
-
- } else if (t.startsWith("skewY(")) {
- // FIXME
-
- } else if (t.startsWith("rotate(")) {
- String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- if (sub.indexOf(',') != -1) {
- float angle = Float.parseFloat(sub.substring(0, sub.indexOf(',')));
- sub = sub.substring(sub.indexOf(',') + 1);
- float cx = Float.parseFloat(sub.substring(0, sub.indexOf(',')));
- sub = sub.substring(sub.indexOf(',') + 1);
- float cy = Float.parseFloat(sub);
- b.transform.multiply(VectorGraphics.Affine.translate(cx, cy));
- b.transform.multiply(VectorGraphics.Affine.rotate(angle));
- b.transform.multiply(VectorGraphics.Affine.translate(-1 * cx, -1 * cy));
- } else {
- b.transform.multiply(VectorGraphics.Affine.rotate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(')')))));
- }
-
- } else if (t.startsWith("translate(")) {
- String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- if (sub.indexOf(',') > -1) {
- b.transform.multiply(VectorGraphics.Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
- Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')')))));
- } else {
- b.transform.multiply(VectorGraphics.Affine.translate(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))), 0));
- }
-
- } else if (t.startsWith("flip(")) {
- String which = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- b.transform.multiply(VectorGraphics.Affine.flip(which.equals("horizontal"), which.equals("vertical")));
-
- } else if (t.startsWith("scale(")) {
- String sub = t.substring(t.indexOf('(') + 1, t.indexOf(')'));
- if (sub.indexOf(',') > -1) {
- b.transform.multiply(VectorGraphics.Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
- Float.parseFloat(t.substring(t.indexOf(',') + 1, t.indexOf(')')))));
- } else {
- b.transform.multiply(VectorGraphics.Affine.scale(Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(','))),
- Float.parseFloat(t.substring(t.indexOf('(') + 1, t.indexOf(',')))));
- }
-
- } else if (t.startsWith("matrix(")) {
- // FIXME: is this mapped right?
- float d[] = new float[6];
- StringTokenizer st = new StringTokenizer(t, ",", false);
- for(int i=0; i<6; i++)
- d[i] = Float.parseFloat(st.nextToken());
- b.transform.multiply(new VectorGraphics.Affine(d[0], d[1], d[2], d[3], d[4], d[5]));
- }
- t = t.substring(t.indexOf(')') + 1).trim();
- }
- MARK_FOR_REFLOW_b;
- b.dirty();
- }
- public Object get(Box b) { return b.transform.toString(); }
- });
-
- specialBoxProperties.put("font", new SpecialBoxProperty() {
- public Object get(Box b) { return b.font; }
- public void put(Box b, Object value) {
- // FIXME: translate value into a resource if it is a string
- b.font = value == null ? null :
- Font.getFont((Res)value, b.font == null ? 10 : b.font.pointsize); // FIXME
- MARK_FOR_REFLOW_b;
- b.flags |= FONT_CHANGED_FLAG;
- b.dirty();
- b.recompute_font();
- } });
-
- specialBoxProperties.put("fontsize", new SpecialBoxProperty() {
- public Object get(Box b) { return b.font; }
- public void put(Box b, Object value) {
- if (b.font != null && b.font.pointsize == stoi(value)) return;
- b.font = value == null ? null :
- Font.getFont(b.font == null ? null : b.font.res, stoi(value)); // FIXME
- MARK_FOR_REFLOW_b;
- b.flags |= FONT_CHANGED_FLAG;
- b.dirty();
- b.recompute_font();
- } });
-
- specialBoxProperties.put("strokewidth", new SpecialBoxProperty() {
- public Object get(Box b) { return new Integer(b.strokewidth); }
- public void put(Box b, Object value) {
- if (b.strokewidth == stoi(value)) return;
- b.strokewidth = stoi(value);
- b.dirty();
- } });
-
- specialBoxProperties.put("align", new SpecialBoxProperty() {
- public Object get(Box b) {
- switch(b.flags & ALIGN_FLAGS) {
- case (ALIGN_TOP_FLAG | ALIGN_LEFT_FLAG): return "topleft";
- case (ALIGN_BOTTOM_FLAG | ALIGN_LEFT_FLAG): return "bottomleft";
- case (ALIGN_TOP_FLAG | ALIGN_RIGHT_FLAG): return "topright";
- case (ALIGN_BOTTOM_FLAG | ALIGN_RIGHT_FLAG): return "bottomright";
- case ALIGN_TOP_FLAG: return "top";
- case ALIGN_BOTTOM_FLAG: return "bottom";
- case ALIGN_LEFT_FLAG: return "left";
- case ALIGN_RIGHT_FLAG: return "right";
- case 0: return "center";
- default: throw new Error("invalid alignment flags: " + (b.flags & ALIGN_FLAGS));
- }
- }
- public void put(Box b, Object value) {
- b.flags &= ~ALIGN_FLAGS;
- if (value == null || value.equals("center")) { b.flags &= ALIGN_FLAGS; }
- else if (value.equals("topleft")) { b.flags |= ALIGN_TOP_FLAG | ALIGN_LEFT_FLAG; }
- else if (value.equals("bottomleft")) { b.flags |= ALIGN_BOTTOM_FLAG | ALIGN_LEFT_FLAG; }
- else if (value.equals("topright")) { b.flags |= ALIGN_TOP_FLAG | ALIGN_RIGHT_FLAG; }
- else if (value.equals("bottomright")) { b.flags |= ALIGN_BOTTOM_FLAG | ALIGN_RIGHT_FLAG; }
- else if (value.equals("top")) { b.flags |= ALIGN_TOP_FLAG; }
- else if (value.equals("bottom")) { b.flags |= ALIGN_BOTTOM_FLAG; }
- else if (value.equals("left")) { b.flags |= ALIGN_LEFT_FLAG; }
- else if (value.equals("right")) { b.flags |= ALIGN_RIGHT_FLAG; }
- else Log.logJS("invalid alignment specifier \"" + value + "\"");
- MARK_FOR_REFLOW_b;
- b.dirty();
- } });
-
- specialBoxProperties.put("thisbox", new SpecialBoxProperty() {
- public Object get(Box b) { return b; }
- public void put(Box b, Object value) {
- if (value == null) b.remove();
- else if (Log.on) Log.log(this, "put invalid value to 'thisbox' property: " + value);
- }
- });
-
- specialBoxProperties.put("orient", new SpecialBoxProperty() {
- public Object get(Box b) {
- Log.log(this, "warning: the orient property is deprecated");
- if (b.redirect == null) return "horizontal";
- else if (b.redirect != b) return get(b.redirect);
- else if (b.cols == 1) return "vertical";
- else if (b.rows == 1) return "horizontal";
- else return "grid";
- }
- public void put(Box b, Object value) {
- Log.log(this, "warning: the orient property is deprecated");
- if (value == null) return;
- if (b.redirect == null) return;
- if (b.redirect != b) { put(b.redirect, value); return; }
- if (value.equals("vertical")) {
- if (b.rows == 0) return;
- b.rows = 0; b.cols = 1;
- } else if (value.equals("horizontal")) {
- if (b.cols == 0) return;
- b.cols = 0; b.rows = 1;
- } else if (Log.on)
- Log.log(this, "invalid value put to orient property: " + value);
- MARK_FOR_REFLOW_b;
- } });
-
- specialBoxProperties.put("shrink", new SpecialBoxProperty() {
- public Object get(Box b) { return (((b.flags & HSHRINK_FLAG) != 0) || ((b.flags & VSHRINK_FLAG) != 0)) ? Boolean.TRUE : Boolean.FALSE; }
- public void put(Box b, Object value) { b.put("hshrink", value); b.put("vshrink", value); }
- });
-
- //#repeat hshrink/vshrink HSHRINK_FLAG/VSHRINK_FLAG
- specialBoxProperties.put("hshrink", new SpecialBoxProperty() {
- public Object get(Box b) { return new Boolean((b.flags & HSHRINK_FLAG) != 0); }
- public void put(Box b, Object value) {
- boolean newshrink = stob(value);
- if (((b.flags & HSHRINK_FLAG) != 0) == newshrink) return;
- if (newshrink) b.flags |= HSHRINK_FLAG; else b.flags &= ~HSHRINK_FLAG;
- MARK_FOR_REFLOW_b;
- }
- });
- //#end
-
- //#repeat x/y
- specialBoxProperties.put("x", new SpecialBoxProperty() {
- public Object get(Box b) {
- if (b.surface == null) return new Integer(0);
- if ((b.flags & INVISIBLE_FLAG) != 0) return new Integer(0);
- return new Integer(b.x);
- }
- public void put(Box b, Object value) {
- if (!((b.flags & NOTPACKED_FLAG) != 0) && (b.parent != null || b.surface == null)) return;
- int x = stoi(value);
- if (x == b.x) return;
- b.dirty();
- b.x = x;
- if (b.parent == null && b.surface != null) b.surface.setLocation();
- MARK_FOR_REFLOW_b;
- b.dirty();
- }
- });
- //#end
-
- //#repeat width/height height/width minwidth/minheight maxwidth/maxheight true/false
- specialBoxProperties.put("width", new SpecialBoxProperty() {
- public Object get(Box b) { return new Integer(b.width); }
- public void put(Box b, Object value) {
- int newval = stoi(value);
- if (b.parent == null && b.surface != null) {
- // hack to circumvent #repeat
- int other = b.height;
- if (true) b.surface.setSize(newval, other);
- else b.surface.setSize(other, newval);
- MARK_FOR_REFLOW_b;
- } else {
- if (b.minwidth == newval && b.maxwidth == newval) return;
- b.minwidth = b.maxwidth = newval;
- MARK_FOR_REFLOW_b;
- }
- } });
- //#end
-
- //#repeat cols/rows rows/cols
- specialBoxProperties.put("cols", new SpecialBoxProperty() {
- public Object get(Box b) { return new Double(b.cols); }
- public void put(Box b, Object value) {
- if (b.cols == stoi(value)) return;
- b.cols = stoi(value);
- if (b.cols == 0 && b.rows == 0) b.rows = 1;
- if (b.cols != 0 && b.rows != 0) b.rows = 0;
- MARK_FOR_REFLOW_b;
- } });
- //#end
-
- //#repeat colspan/rowspan
- specialBoxProperties.put("colspan", new SpecialBoxProperty() {
- public Object get(Box b) { return new Double(b.colspan); }
- public void put(Box b, Object value) {
- if (b.colspan == stoi(value)) return;
- b.colspan = stoi(value);
- MARK_FOR_REFLOW_b;
- }
- });
- //#end
-
- specialBoxProperties.put("noclip", new SpecialBoxProperty() {
- public Object get(Box b) { return ((b.flags & NOCLIP_FLAG) != 0) ? Boolean.TRUE : Boolean.FALSE; }
- public void put(Box b, Object value) {
- if (((b.flags & NOCLIP_FLAG) != 0) == stob(value)) return;
- if (stob(value)) b.flags |= NOCLIP_FLAG; else b.flags &= ~NOCLIP_FLAG;
- MARK_FOR_REFLOW_b;
- b.dirty();
- } });
-
- specialBoxProperties.put("visible", new SpecialBoxProperty() {
- public Object get(Box b) {
- for (Box cur = b; cur != null; cur = cur.parent) {
- if ((cur.flags & INVISIBLE_FLAG) != 0) return Boolean.FALSE; }
- return Boolean.TRUE;
- }
- public void put(Box b, Object value) {
- if (!stob(value) == ((b.flags & INVISIBLE_FLAG) != 0)) return;
- if (!stob(value)) b.flags |= INVISIBLE_FLAG; else b.flags &= ~INVISIBLE_FLAG;
- if (b.parent == null) {
- if (b.surface != null) b.surface.setInvisible((b.flags & INVISIBLE_FLAG) != 0);
- } else {
- b.dirty();
- MARK_FOR_REFLOW_b_parent;
- b.parent.dirty(b.x, b.y, b.width, b.height);
- }
- }});
-
- specialBoxProperties.put("packed", new SpecialBoxProperty() {
- public Object get(Box b) { return ((b.flags & NOTPACKED_FLAG) != 0) ? Boolean.TRUE : Boolean.FALSE; }
- public void put(Box b, Object value) {
- if (stob(value) == ((b.flags & NOTPACKED_FLAG) == 0)) return;
- if (!stob(value)) b.flags |= NOTPACKED_FLAG; else b.flags &= ~NOTPACKED_FLAG;
- if ((b.flags & NOTPACKED_FLAG) != 0) { b.x = 0; b.y = 0; }
- if (b.parent != null) MARK_FOR_REFLOW_b_parent;
- } });
-
- //#repeat globalx/globaly x/y
- specialBoxProperties.put("globalx", new SpecialBoxProperty() {
- public Object get(Box b) { return new Integer(b.parent == null || b.surface == null ? 0 : b.x); }
- public void put(Box b, Object value) {
- if (b.surface == null || b.parent == null) return;
- b.put("x", new Integer(stoi(value) - stoi(get(b.parent))));
- MARK_FOR_REFLOW_b;
- }
- });
- //#end
-
- specialBoxProperties.put("cursor", new SpecialBoxProperty() {
- public Object get(Box b) { return b.cursor; }
- public void put(Box b, Object value) {
- b.cursor = (String)value;
- if (b.surface == null) return;
-
- // see if we need to update the surface cursor
- Surface surface = b.getRoot().surface;
- String tempcursor = surface.cursor;
- b.Move(surface.mousex, surface.mousey, surface.mousex, surface.mousey);
- if (surface.cursor != tempcursor) surface.syncCursor();
- }
- });
-
- //#repeat mousex/mousey x/y
- specialBoxProperties.put("mousex", new SpecialBoxProperty() {
- public Object get(Box b) {
- Surface surface = b.getRoot().surface;
- if (surface == null) return new Integer(0);
- int mousex = surface.mousex;
- for(Box cur = b; cur != null && cur.parent != null; cur = cur.parent) mousex -= cur.x;
- return new Integer(mousex);
- }
- });
- //#end
-
- specialBoxProperties.put("mouseinside", new SpecialBoxProperty() {
- public Object get(Box b) {
- return ((b.flags & MOUSEINSIDE_FLAG) != 0) ? Boolean.TRUE : Boolean.FALSE; }
- });
-
- specialBoxProperties.put("numchildren", new SpecialBoxProperty() {
- public Object get(Box b) {
- if (b.redirect == null) return new Integer(0);
- if (b.redirect != b) return get(b.redirect);
- return new Integer(b.numChildren());
- } });
-
- SpecialBoxProperty mouseEventHandler = new SpecialBoxProperty() {
- public void put(String name, Box b, Object value) {
- Surface surface = b.getRoot().surface;
- if (surface == null) return;
- int mousex = surface.mousex;
- int mousey = surface.mousey;
- for(Box c = b.parent; c != null && c.parent != null; c = c.parent) {
- mousex -= c.x;
- mousey -= c.y;
- }
- for(Box c = b.prevSibling(); c != null; c = c.prevSibling()) {
- if (c.inside(mousex - c.x, mousey - c.y)) {
- c.put(name, value);
- return;
- }
- }
- if (b.parent != null) b.parent.put(name, value);
- }};
-
- specialBoxProperties.put("Press1", mouseEventHandler);
- specialBoxProperties.put("Press2", mouseEventHandler);
- specialBoxProperties.put("Press3", mouseEventHandler);
- specialBoxProperties.put("Release1", mouseEventHandler);
- specialBoxProperties.put("Release2", mouseEventHandler);
- specialBoxProperties.put("Release3", mouseEventHandler);
- specialBoxProperties.put("Click1", mouseEventHandler);
- specialBoxProperties.put("Click2", mouseEventHandler);
- specialBoxProperties.put("Click3", mouseEventHandler);
- specialBoxProperties.put("DoubleClick1", mouseEventHandler);
- specialBoxProperties.put("DoubleClick2", mouseEventHandler);
- specialBoxProperties.put("DoubleClick3", mouseEventHandler);
-
- specialBoxProperties.put("root", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- if (stob(value)) b.flags |= ISROOT_FLAG;
- else b.flags &= ~ISROOT_FLAG;
- }
- public Object get(Box b) {
- if (b.parent == null || ((b.flags & ISROOT_FLAG) != 0)) return b;
- else return get(b.parent);
- } });
-
- specialBoxProperties.put("Minimized", new SpecialBoxProperty() {
- public Object get(Box b) {
- if (b.parent == null && b.surface != null) return b.surface.minimized ? Boolean.TRUE : Boolean.FALSE;
- else return null;
- }
- public void put(Box b, Object value) {
- if (b.surface == null) return;
- boolean val = stob(value);
- if (b.parent == null && b.surface.minimized != val) b.surface.setMinimized(val);
- }
- });
-
- specialBoxProperties.put("Maximized", new SpecialBoxProperty() {
- public Object get(Box b) {
- if (b.parent == null && b.surface != null) return b.surface.maximized ? Boolean.TRUE : Boolean.FALSE;
- else return null;
- }
- public void put(Box b, Object value) {
- if (b.surface == null) return;
- boolean val = stob(value);
- if (b.parent == null && b.surface.maximized != val) b.surface.setMaximized(val);
- }
- });
-
- specialBoxProperties.put("toback", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- if (b.parent == null && stob(value) && b.surface != null) b.surface.toBack();
- }
- });
-
- specialBoxProperties.put("tofront", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- if (b.parent == null && stob(value) && b.surface != null) b.surface.toFront();
- }
- });
-
- specialBoxProperties.put("Close", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- if (b.parent == null && b.surface != null) b.surface.dispose(true);
- }
- });
-
- // these are all do-nothings; just to prevent space from getting taken up in the params Hash.
- specialBoxProperties.put("KeyPressed", new SpecialBoxProperty());
- specialBoxProperties.put("KeyReleased", new SpecialBoxProperty());
- specialBoxProperties.put("PosChange", new SpecialBoxProperty());
- specialBoxProperties.put("SizeChange", new SpecialBoxProperty());
-
- //#repeat minwidth/minheight maxwidth/maxheight
- specialBoxProperties.put("minwidth", new SpecialBoxProperty() {
- public Object get(Box b) { return new Integer(b.minwidth); }
- public void put(Box b, Object value) {
- if (stoi(value) == b.minwidth) return;
- b.minwidth = stoi(value);
- MARK_FOR_REFLOW_b;
- }
- });
- specialBoxProperties.put("maxwidth", new SpecialBoxProperty() {
- public Object get(Box b) { return new Integer(b.maxwidth); }
- public void put(Box b, Object value) {
- if (stoi(value) == b.maxwidth) return;
- b.maxwidth = stoi(value);
- MARK_FOR_REFLOW_b;
- }
- });
- //#end
-
- specialBoxProperties.put("redirect", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- if (b.redirect != b) Log.log(this, "cannot change the redirect of a box once it is set");
- else if (value == null) b.redirect = null;
- else {
- Box b2 = (Box)value;
- while(b2 != b && b2 != null) b2 = b2.parent;
- if (b2 == null) Log.log(this, "a box's redirect must be one of its descendants");
- b.redirect = (Box)value;
- }
- }
- public Object get(Box b) {
- if (b.redirect == null) return null;
- if (b.redirect == b) return Boolean.TRUE;
- return get(b.redirect);
- }
- });
-
- // FEATURE: this still isn't totally harmonious; when you createSurface, these aren't checked
- specialBoxProperties.put("titlebar", new SpecialBoxProperty() {
- public void put(Box b, Object value) {
- if (b.surface != null) b.surface.setTitleBarText(value.toString());
- b.put_("titlebar", value);
- }
- public Object get(Box b) { return b.get_("titlebar"); }
- });
-
- specialBoxProperties.put("icon", new SpecialBoxProperty() {
- // FIXME
- /*
- public void put(Box b, Object value) {
- b.put_("icon", value);
- if (b.surface == null) return;
- Picture pic = ImageDecoder.getPicture(value.toString());
- if (pic != null) b.surface.setIcon(pic);
- else if (Log.on) Log.log(this, "unable to load icon " + value);
- }
- public Object get(Box b) { return b.get_("icon"); }
- */
- });