X-Git-Url: http://git.megacz.com/?p=org.ibex.core.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fcore%2FBox.java;h=496725226d590b75639e8ac29c0ce0896cf5b790;hp=c898d8e1cfb502749b2aa88234e56013cedfa506;hb=48760d1df22a8925ad93fc2fa422faf15ef94cc1;hpb=4daeeb4119b901d53b44913c86f8af3ce67db925 diff --git a/src/org/ibex/core/Box.java b/src/org/ibex/core/Box.java index c898d8e..4967252 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); @@ -126,15 +126,13 @@ public final class Box extends JSScope implements Scheduler.Task { private int contentwidth = 0; // == max(minwidth, textwidth, sum(child.contentwidth)) private 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,11 @@ 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, maxwidth, 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(); } @@ -242,7 +240,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 +388,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 +418,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); } @@ -443,8 +443,8 @@ public final class Box extends JSScope implements Scheduler.Task { case "distanceto": Box b = (Box)a0; JS ret = new JS(); - ret.put("x", N(b.localToGlobalX(0) - localToGlobalX(0))); - ret.put("y", N(b.localToGlobalY(0) - localToGlobalY(0))); + ret.put("x", N(localToGlobalX(0) - b.localToGlobalX(0))); + ret.put("y", N(localToGlobalY(0) - b.localToGlobalY(0))); return ret; //#end @@ -463,9 +463,9 @@ public final class Box extends JSScope implements Scheduler.Task { 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 "fill": return Color.colorToString(fillcolor); + case "strokecolor": return Color.colorToString(strokecolor); + case "textcolor": return Color.colorToString(strokecolor); case "font": return font == null ? null : font.stream; case "fontsize": return font == null ? N(10) : N(font.pointsize); case "strokewidth": return N(strokewidth); @@ -538,13 +538,14 @@ public final class Box extends JSScope implements Scheduler.Task { if (name instanceof Number) { put(toInt(name), value); return; } //#switch(name) case "thisbox": if (value == null) removeSelf(); - case "text": if (value == null) value = ""; CHECKSET_STRING(text); RECONSTRAIN(); DIRTY; - case "strokecolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY; - case "textcolor": value = N(stringToColor((String)value)); CHECKSET_INT(strokecolor); DIRTY; - case "strokewidth": CHECKSET_SHORT(strokewidth); DIRTY; + case "text": if (value == null) value = ""; CHECKSET_STRING(text); RECONSTRAIN(); dirty(); + case "strokecolor": value = N(Color.stringToColor((String)value)); CHECKSET_INT(strokecolor); dirty(); + case "textcolor": value = N(Color.stringToColor((String)value)); CHECKSET_INT(strokecolor); dirty(); + case "strokewidth": CHECKSET_SHORT(strokewidth); dirty(); case "shrink": CHECKSET_FLAG(HSHRINK | VSHRINK); RECONSTRAIN(); case "hshrink": CHECKSET_FLAG(HSHRINK); RECONSTRAIN(); case "vshrink": CHECKSET_FLAG(VSHRINK); RECONSTRAIN(); + case "path": path = Path.parse(toString(value)); dirty(); case "width": setWidth(toInt(value), toInt(value)); case "height": setHeight(toInt(value), toInt(value)); case "maxwidth": setWidth(minwidth, toInt(value)); @@ -553,12 +554,12 @@ public final class Box extends JSScope implements Scheduler.Task { case "minheight": setHeight(toInt(value), maxheight); case "colspan": if (toInt(value) > 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 +577,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 +696,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 +709,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 +762,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) { @@ -862,7 +835,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 +845,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 +902,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) {