X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fcore%2FBox.java;h=bb8a27b94812b8bd954dbaa7ce2f9a445befe228;hp=c898d8e1cfb502749b2aa88234e56013cedfa506;hb=fffcafc33aa4066bdf85da7a32e1a1cdb9db2d6f;hpb=4daeeb4119b901d53b44913c86f8af3ce67db925 diff --git a/src/org/ibex/core/Box.java b/src/org/ibex/core/Box.java index c898d8e..bb8a27b 100644 --- a/src/org/ibex/core/Box.java +++ b/src/org/ibex/core/Box.java @@ -1,6 +1,6 @@ // FIXME // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL] -package org.ibex; +package org.ibex.core; // FIXME: are traps on x/y meaningful? // FIXME: if we trap on cols, then set rows to 0 (forcing cols to 1), does the cols trap get triggered? @@ -17,7 +17,7 @@ package org.ibex; import java.util.*; import org.ibex.js.*; import org.ibex.util.*; -import org.ibex.translators.*; +import org.ibex.graphics.*; /** *

@@ -38,7 +38,7 @@ import org.ibex.translators.*; * trigger a Surface.abort; if rendering were done in the same pass, * rendering work done prior to the Surface.abort would be wasted. */ -public final class Box extends JSScope implements Scheduler.Task { +public final class Box extends JSScope implements Task { // Macros ////////////////////////////////////////////////////////////////////// @@ -52,7 +52,7 @@ public final class Box extends JSScope implements Scheduler.Task { //#define CHECKSET_BOOLEAN(prop) boolean nu = toBoolean(value); if (nu == prop) break; prop = nu; //#define CHECKSET_STRING(prop) if ((value==null&&prop==null)||(value!=null&&JS.toString(value).equals(prop))) break; prop=JS.toString(value); - protected Box() { super(null); } + public Box() { super(null); } // FIXME memory leak static Hash boxToCursor = new Hash(500, 3); @@ -65,8 +65,8 @@ public final class Box extends JSScope implements Scheduler.Task { static final int MOUSEINSIDE = 0x00000001; static final int VISIBLE = 0x00000002; static final int PACKED = 0x00000004; - static final int HSHRINK = 0x00000008; - static final int VSHRINK = 0x00000010; + public static final int HSHRINK = 0x00000008; + public static final int VSHRINK = 0x00000010; static final int BLACK = 0x00000020; // for red-black code static final int FIXED = 0x00000040; @@ -123,18 +123,16 @@ public final class Box extends JSScope implements Scheduler.Task { public int ay = 0; // FEATURE: roll these into x/y; requires lots of changes; perhaps y()? public int width = 0; public int height = 0; - private int contentwidth = 0; // == max(minwidth, textwidth, sum(child.contentwidth)) - private int contentheight = 0; + public int contentwidth = 0; // == max(minwidth, textwidth, sum(child.contentwidth)) + public int contentheight = 0; + private Path path = null; /* - private VectorGraphics.VectorPath path = null; - private VectorGraphics.Affine transform = null; + private Affine transform = null; private VectorGraphics.RasterPath rpath = null; - private VectorGraphics.Affine rtransform = null; + private Affine rtransform = null; */ - //#define DIRTY dirty() - // Instance Methods ///////////////////////////////////////////////////////////////////// public final int fontSize() { return font == null ? DEFAULT_FONT.pointsize : font.pointsize; } @@ -143,9 +141,9 @@ public final class Box extends JSScope implements Scheduler.Task { public void perform() throws JSExn { if (texture == null) { Log.warn(Box.class, "perform() called with null texture"); return; } if (texture.isLoaded) { - setWidth(max(texture.width, maxwidth), maxwidth); - setHeight(max(texture.height, maxheight), maxheight); - DIRTY; } + setWidth(max(texture.width, minwidth), maxwidth); + setHeight(max(texture.height, minheight), maxheight); + dirty(); } else { JS res = texture.stream; texture = null; throw new JSExn("image not found: "+res.unclone()); } } @@ -172,11 +170,17 @@ public final class Box extends JSScope implements Scheduler.Task { // Reflow //////////////////////////////////////////////////////////////////////////////////////// /** should only be invoked on the root box */ - void reflow() { pack(); resize(x, y, maxwidth, maxheight); place(); } - + public void reflow() { + pack(); + resize(x, y, + test(HSHRINK) ? contentwidth : maxwidth, + test(VSHRINK) ? contentheight : maxheight); + place(); + } + private static Box[] frontier = new Box[65535]; /** pack the boxes into rows and columns, compute contentwidth */ - void pack() { + public void pack() { if (!test(REPACK)) { constrain(); return; } boolean haskid = false; for(Box child = getChild(0); child != null; child = child.nextSibling()) { haskid = true; child.pack(); } @@ -228,7 +232,7 @@ public final class Box extends JSScope implements Scheduler.Task { void resize(int x, int y, int width, int height) { if (x == this.x && y == this.y && width == this.width && height == this.height) return; - boolean sizechange = (this.width != width || this.height != height) && getTrap("SizeChange") != null; + boolean sizechange = (this.width != width || this.height != height) && hasTrap("SizeChange"); int thisx = parent == null ? 0 : this.x; int thisy = parent == null ? 0 : this.y; Box who = (parent == null ? this : parent); @@ -242,7 +246,7 @@ public final class Box extends JSScope implements Scheduler.Task { } else { who.dirty(thisx, thisy, this.width, this.height); this.width = width; this.height = height; this.x = x; this.y = y; - DIRTY; + dirty(); } if (sizechange) putAndTriggerTrapsAndCatchExceptions("SizeChange", T); } @@ -390,7 +394,7 @@ public final class Box extends JSScope implements Scheduler.Task { // Rendering Pipeline ///////////////////////////////////////////////////////////////////// /** Renders self and children within the specified region. All rendering operations are clipped to xIn,yIn,wIn,hIn */ - void render(int parentx, int parenty, int cx1, int cy1, int cx2, int cy2, PixelBuffer buf, VectorGraphics.Affine a) { + public void render(int parentx, int parenty, int cx1, int cy1, int cx2, int cy2, PixelBuffer buf, Affine a) { if (!test(VISIBLE)) return; int globalx = parentx + (parent == null ? 0 : x); int globaly = parenty + (parent == null ? 0 : y); @@ -420,6 +424,8 @@ public final class Box extends JSScope implements Scheduler.Task { font.rasterizeGlyphs(text, buf, strokecolor, text_x, text_y, cx1, cy1, cx2, cy2); } + if (path != null) path.realize(Affine.translate(globalx, globaly)).stroke(buf, 1, strokecolor); + for(Box b = getChild(0); b != null; b = b.nextSibling()) b.render(globalx, globaly, cx1, cy1, cx2, cy2, buf, null); } @@ -442,7 +448,7 @@ public final class Box extends JSScope implements Scheduler.Task { case "distanceto": Box b = (Box)a0; - JS ret = new JS(); + JS ret = new JS.O(); ret.put("x", N(b.localToGlobalX(0) - localToGlobalX(0))); ret.put("y", N(b.localToGlobalY(0) - localToGlobalY(0))); return ret; @@ -462,10 +468,16 @@ public final class Box extends JSScope implements Scheduler.Task { case "indexof": return METHOD; case "distanceto": 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 "path": + if (path != null) return path.toString(); + if (text == null) return null; + if (font == null) return null; + String ret = ""; + for(int i=0; i 0) { CHECKSET_SHORT(colspan); if (parent != null) parent.REPACK(); } case "rowspan": if (toInt(value) > 0) { CHECKSET_SHORT(rowspan); if (parent != null) parent.REPACK(); } - case "visible": CHECKSET_FLAG(VISIBLE); RECONSTRAIN(); DIRTY; + case "visible": CHECKSET_FLAG(VISIBLE); RECONSTRAIN(); dirty(); case "packed": CHECKSET_FLAG(PACKED); if (parent != null) { parent.REPACK(); } else { REPACK(); } case "align": clear(ALIGNS); setAlign(value == null ? "center" : value); REPLACE(); case "cursor": setCursor(value); case "fill": setFill(value); - case "clip": CHECKSET_FLAG(CLIP); if (parent == null) DIRTY; else parent.DIRTY; + case "clip": CHECKSET_FLAG(CLIP); if (parent == null) dirty(); else parent.dirty(); case "rows": CHECKSET_SHORT(rows); if (rows==0){set(FIXED, COLS);if(cols==0)cols=1;} else set(FIXED, ROWS); REPACK(); case "cols": CHECKSET_SHORT(cols); if (cols==0){set(FIXED, ROWS);if(rows==0)rows=1;} else set(FIXED, COLS); REPACK(); @@ -576,13 +589,13 @@ public final class Box extends JSScope implements Scheduler.Task { for(Box cur = (Box)value; cur != null || cur == redirect; cur = cur.parent) if (cur == redirect) { redirect = (Box)value; return; } JS.error("redirect can only be set to a descendant of its current value"); - case "fontsize": font = Font.getFont(font == null ? null : font.stream, toInt(value)); RECONSTRAIN(); DIRTY; + case "fontsize": font = Font.getFont(font == null ? null : font.stream, toInt(value)); RECONSTRAIN(); dirty(); case "font": if(!(value instanceof Stream)) throw new JSExn("You can only put streams to the font property"); if (font == value) return; // FIXME: unclone() font = value == null ? null : Font.getFont((Stream)value, font == null ? 10 : font.pointsize); RECONSTRAIN(); - DIRTY; + dirty(); case "x": if (parent==null && Surface.fromBox(this)!=null) { CHECKSET_INT(x); } else { @@ -695,7 +708,7 @@ public final class Box extends JSScope implements Scheduler.Task { texture = null; fillcolor = 0; } else if (value instanceof String) { - int newfillcolor = stringToColor((String)value); + int newfillcolor = Color.stringToColor((String)value); if (newfillcolor == fillcolor) return; fillcolor = newfillcolor; texture = null; @@ -708,7 +721,7 @@ public final class Box extends JSScope implements Scheduler.Task { } else { throw new JSExn("fill must be null, a String, or a stream, not a " + value.getClass()); } - DIRTY; + dirty(); } /** @@ -761,34 +774,6 @@ public final class Box extends JSScope implements Scheduler.Task { putAndTriggerTrapsAndCatchExceptions(name.substring(1), value); } - private static int stringToColor(String s) { - // FIXME support three-char strings by doubling digits - if (s == null) return 0x00000000; - else if (SVG.colors.get(s) != null) return 0xFF000000 | toInt(SVG.colors.get(s)); - else if (s.length() == 7 && s.charAt(0) == '#') try { - // FEATURE alpha - return 0xFF000000 | - (Integer.parseInt(s.substring(1, 3), 16) << 16) | - (Integer.parseInt(s.substring(3, 5), 16) << 8) | - Integer.parseInt(s.substring(5, 7), 16); - } catch (NumberFormatException e) { - Log.info(Box.class, "invalid color " + s); - return 0; - } - else return 0; // FEATURE: error? - } - - private static String colorToString(int argb) { - if ((argb & 0xFF000000) == 0) return null; - String red = Integer.toHexString((argb & 0x00FF0000) >> 16); - String green = Integer.toHexString((argb & 0x0000FF00) >> 8); - String blue = Integer.toHexString(argb & 0x000000FF); - if (red.length() < 2) red = "0" + red; - if (blue.length() < 2) blue = "0" + blue; - if (green.length() < 2) green = "0" + green; - return "#" + red + green + blue; - } - /** figures out what box in this subtree of the Box owns the pixel at x,y relitave to the Surface */ public static Box whoIs(Box cur, int x, int y) { @@ -846,7 +831,7 @@ public final class Box extends JSScope implements Scheduler.Task { void set(int mask) { flags |= mask; } void set(int mask, boolean setclear) { if (setclear) set(mask); else clear(mask); } void clear(int mask) { flags &= ~mask; } - boolean test(int mask) { return ((flags & mask) == mask); } + public boolean test(int mask) { return ((flags & mask) == mask); } // Tree Handling ////////////////////////////////////////////////////////////////////// @@ -862,7 +847,7 @@ public final class Box extends JSScope implements Scheduler.Task { // Tree Manipulation ///////////////////////////////////////////////////////////////////// - void removeSelf() { + public void removeSelf() { if (parent != null) { parent.removeChild(parent.indexNode(this)); return; } Surface surface = Surface.fromBox(this); if (surface != null) surface.dispose(true); @@ -872,11 +857,11 @@ public final class Box extends JSScope implements Scheduler.Task { public void removeChild(int i) { Box b = getChild(i); b.RECONSTRAIN(); - b.DIRTY; + b.dirty(); b.clear(MOUSEINSIDE); deleteNode(i); b.parent = null; - RECONSTRAIN(); + REPACK(); putAndTriggerTrapsAndCatchExceptions("ChildChange", b); } @@ -929,15 +914,15 @@ public final class Box extends JSScope implements Scheduler.Task { b.parent = this; // need both of these in case child was already uncalc'ed - b.RECONSTRAIN(); - RECONSTRAIN(); + b.REPACK(); + REPACK(); - b.DIRTY; + b.dirty(); putAndTriggerTrapsAndCatchExceptions("ChildChange", b); } } - - void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) { + + public void putAndTriggerTrapsAndCatchExceptions(Object name, Object val) { try { putAndTriggerTraps(name, val); } catch (JSExn e) {