-
- /** the Box's font -- you must call textupdate() after changing this */
- String font = Platform.getDefaultFont();
-
- /** The surface for us to render on; null if none; INVARIANT: surface == getParent().surface */
- Surface surface = null;
-
- /** Our alignment: top/left == -1, center == 0, bottom/right == +1 */
- byte align = 0;
-
- /** Our background image; to set this, use setImage() */
- public Picture image;
-
- /** The flex for this box */
- int flex = 1;
-
- /** The orientation, horizontal == 0, vertical == 1 */
- byte o = 0;
-
- /** The opposite of the orientation */
- byte xo = 1;
-
- /** The id of this Box */
- public String id = "";
-
- /** The text of this Box -- you must call textupdate() after changing this */
- String text = "";
-
- /** The color of the text in this Box in 00RRGGBB form -- default is black */
- int textcolor = 0xFF000000;
-
- /** The background color of this box in AARRGGBB form -- default is clear; alpha is all-or-nothing */
- int color = 0x00000000;
-
- /** Holds four "strip images" -- 0=top, 1=bottom, 2=left, 3=right, 4=all */
- Picture[] border = null;
-
- /** true iff the box's background image should be tiled */
- boolean tile = false;
-
- /** True iff the Box is invisible */
- public boolean invisible = false;
-
- /** If true, the Box will force its own size to the natural size of its background image */
- boolean sizetoimage = false;
-
- /** If true and tile is false, the background of this image will never be stretched */
- boolean fixedaspect = false;
-
- /** If true, the box will shrink to the smallest vertical size possible */
- boolean vshrink = false;
-
- /** If true, the box will shrink to the smallest horizontal size possible */
- boolean hshrink = false;
-
- /** If true, the box will be positioned absolutely */
- boolean absolute = false;
-
- /** True iff the Box must be run through the prerender() pipeline before render()ing;<br>
- * INVARIANT: if (needs_prerender) then getParent().needs_prerender. **/
- boolean needs_prerender = true;
-
- /** The cursor for this Box -- only meaningful on the root Box */
- public String cursor = null;
-
- /** Any traps placed on this Box */
- public Hash traps = null;
-
-
- // Instance Data: IndexOf ////////////////////////////////////////////////////////////
-
- /** The indexof() Function; created lazily */
- public Function indexof = null;
- public Function indexof() {
- if (indexof == null) indexof = new IndexOf();
- return indexof;
- }
-
- /** a trivial private class to serve as the box.indexof function object */
- private class IndexOf extends JSObject implements Function {
- public IndexOf() { this.setSeal(true); }
- public Scriptable construct(Context cx, Scriptable scope, java.lang.Object[] args) { return null; }
- public Object call(Context cx, Scriptable scope, Scriptable thisObj, java.lang.Object[] args) throws JavaScriptException {
- if (args == null || args.length != 1 || args[0] == null || !(args[0] instanceof Box)) return new Integer(-1);
- Box b = (Box)args[0];
- if (b.getParent() != Box.this) {
- if (redirect == null || redirect == Box.this) return new Integer(-1);
- return Box.this.redirect.indexof().call(cx, scope, thisObj, args);
- }
- return new Integer(b.getIndexInParent());
- }
- }
-
-
- // Methods which enforce/preserve invariants ////////////////////////////////////////////
-
- /** This method MUST be used to change geometry values -- it ensures that certain invariants are preserved. */
- public final void set(int which, int axis, int newvalue) { set(which, axis, (short)newvalue); }
- public final void set(int which, int axis, short newvalue) {
-
- // if this Box is the root of the Surface, notify the Surface of size changes
- if (getParent() == null && surface != null && which == size)
- surface._setSize(axis == 0 ? newvalue : size(0), axis == 1 ? newvalue : size(1));
-
- if (getParent() == null && surface != null && (which == dmin || which == dmax))
- surface.setLimits(dmin(0), dmin(1), dmax(0), dmax(1));
-
- switch(which) {
- case dmin: if (dmin(axis) == newvalue) return; if (axis == 0) _dmin_0 = newvalue; else _dmin_1 = newvalue; break;
- case dmax: if (dmax(axis) == newvalue) return; if (axis == 0) _dmax_0 = newvalue; else _dmax_1 = newvalue; break;
- case cmin: if (cmin(axis) == newvalue) return; if (axis == 0) _cmin_0 = newvalue; else _cmin_1 = newvalue; break;
- case abs: if (abs(axis) == newvalue) return; if (axis == 0) _abs_0 = newvalue; else _abs_1 = newvalue; break;
- case pos: if (pos(axis) == newvalue) return; if (axis == 0) _pos_0 = newvalue; else _pos_1 = newvalue; break;
- case size: if (size(axis) == newvalue) return; if (axis == 0) _size_0 = newvalue; else _size_1 = newvalue; break;
- case oldpos: if (oldpos(axis) == newvalue) return; if (axis == 0) _oldpos_0 = newvalue; else _oldpos_1 = newvalue; break;
- case oldsize: if (oldsize(axis) == newvalue) return; if (axis == 0) _oldsize_0 = newvalue; else _oldsize_1 = newvalue; break;
- case pad: if (pad(axis) == newvalue) return; if (axis == 0) _pad_0 = newvalue; else _pad_1 = newvalue; break;
- case textdim: if (textdim(axis) == newvalue) return; if (axis == 0) _textdim_0 = newvalue; else _textdim_1 = newvalue; break;
- default: return;
- }
-
- // size must always agree with dmin/dmax
- if (which == dmin) set(size, axis, max(size(axis), newvalue));
- if (which == dmax) set(size, axis, min(size(axis), newvalue));
-
- // keep obedience to shrink directives
- if (which == cmin || which == textdim || which == pad || which == dmin)
- if ((hshrink && axis == 0) || (vshrink && axis == 1))
- set(dmax, axis, max(cmin(axis), (textdim(axis) + 2 * pad(axis)), dmin(axis)));
-
- // keep cmin in line with dmin/dmax/textdim
- if (which == dmax || which == dmin || which == textdim || which == pad || which == cmin)
- set(cmin, axis,
- max(
- min(cmin(axis), dmax(axis)),
- dmin(axis),
- min(dmax(axis), textdim(axis) + 2 * pad(axis))
- )
- );
-
- // if the pad changes, update cmin
- if (which == pad) sync_cmin_to_children();
-
- // needed in the shrink case, since dmin may have been the deciding factor in calculating cmin
- if ((vshrink || hshrink) && (which == dmin || which == textdim || which == pad)) sync_cmin_to_children();
-
- // if the cmin changes, we need to be re-prerendered
- if (which == cmin) mark_for_prerender();
-
- // if the absolute position of a box changes, its parent needs to be re-prerendered (to update the child's position)
- if (which == abs && getParent() != null) getParent().mark_for_prerender();
-
- // if our cmin changes, then our parent's needs to be recalculated
- if (getParent() != null && which == cmin) {
- mark_for_prerender();
- getParent().sync_cmin_to_children();
- }
-
- }
-
- /** Marks this node and all its ancestors so that they will be prerender()ed */
- public final void mark_for_prerender() {
- if (needs_prerender) return;
- needs_prerender = true;
- if (getParent() != null) getParent().mark_for_prerender();
- }
-
- /** Ensures that cmin is in sync with the cmin's of our children. This should be called whenever a child is added or
- * removed, as well as when our pad is changed. */
- final void sync_cmin_to_children() {
- short co = (short)(2 * pad(o));
- short cxo = (short)(2 * pad(xo));
-
- for(Box bt = getChild(0); bt != null; bt = bt.nextSibling()) {
- if (bt.invisible || bt.absolute) continue;
- co += bt.cmin(o);
- cxo = (short)max(bt.cmin(xo) + 2 * pad(xo), cxo);
- }
-
- set(cmin, o, co);
- set(cmin, xo, cxo);
- }
-
- /** must be called after changes to <tt>image</tt> or <tt>border</tt> if sizetoimage is true */
- public void syncSizeToImage() {
- set(dmax, 0, (image == null ? 0 : image.getWidth()) + (border == null ? 0 : border[2].getWidth()) * 2);
- set(dmax, 1, (image == null ? 0 : image.getHeight()) + (border == null ? 0 : border[0].getHeight()) * 2);
- set(dmin, 0, (image == null ? 0 : image.getWidth()) + (border == null ? 0 : border[2].getWidth()) * 2);
- set(dmin, 1, (image == null ? 0 : image.getHeight()) + (border == null ? 0 : border[0].getHeight()) * 2);
- }
-
- /** This must be called when font or text is changed */
- void textupdate() {
- if (text.equals("")) {
- set(textdim, 0, 0);
- set(textdim, 1, 0);
- } else {
- XWF xwf = XWF.getXWF(font);
- if (xwf == null) {
- set(textdim, 0, Platform.stringWidth(font, text));
- set(textdim, 1, (Platform.getMaxAscent(font) + Platform.getMaxDescent(font)));
- } else {
- set(textdim, 0, xwf.stringWidth(text));
- set(textdim, 1, (xwf.getMaxAscent() + xwf.getMaxDescent()));
- }
- }
- }
-