// FIXME: mouse move/release still needs to propagate to boxen in which the mouse was pressed and is still held down
// FEATURE: reintroduce surface.abort
+// Broken:
+// - textures
+// - align/origin
+// - clipping (all forms)
+
import java.util.*;
import org.ibex.js.*;
import org.ibex.util.*;
+import org.ibex.plat.*;
import org.ibex.graphics.*;
/**
* 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 JS.Obj implements Callable {
+public final class Box extends JS.Obj implements Callable, Mesh.Chain {
+
+ public Mesh.Chain getMeshChainParent() { return parent; }
+ public Mesh getMesh() { return mesh; }
+ public Affine getAffine() { return transform; }
// Macros //////////////////////////////////////////////////////////////////////
private int strokecolor = 0xFF000000;
public float flex = 1;
private Path path = null;
+ private Path clippath = null;
private Affine transform = Affine.identity();
// FEATURE: polygon caching
- private Polygon polygon = null;
+ private Mesh polygon = null;
+ private Mesh mesh = null;
// specified directly by user
public int minwidth = 0;
public void dirty() { if (path==null) dirty(0, 0, contentwidth, contentheight); else dirty(path); }
public void dirty(int x, int y, int w, int h) { }
public void dirty(Path p) {
- Affine a = transform;
+ Affine a = transform.copy();
for(Box cur = this; cur != null; cur = cur.parent) a.premultiply(cur.transform);
long hbounds = p.horizontalBounds(a);
long vbounds = p.verticalBounds(a);
void place() {
if (!packed()) {
for(Box child = getChild(0); child != null; child = child.nextSibling()) {
- child.width = max(child.minwidth, child.test(HSHRINK) ? child.contentwidth : child.maxwidth);
- child.height = max(child.minheight, child.test(VSHRINK) ? child.contentheight : child.maxheight);
+ child.width = max(child.minwidth, min(child.test(HSHRINK) ? child.contentwidth : width, child.maxwidth));
+ child.height = max(child.minheight, min(child.test(VSHRINK) ? child.contentheight : height, child.maxheight));
child.place();
}
return;
transform.f = 0;
a = a.copy().premultiply(transform);
- boolean relevant = packed() || ((fillcolor&0xff000000)!=0x0) || path!=null;
+ //boolean relevant = packed() || ((fillcolor&0xff000000)!=0x0) || path!=null;
+ boolean relevant = true;
int save_xmin = xmin, save_ymin = ymin, save_xmax = xmax, save_ymax = ymax;
if (!relevant) {
for(Box child = getChild(0); child != null; child = child.nextSibling()) {
xmax = save_xmax;
ymax = save_ymax;
- contentwidth = bound(minwidth, contentwidth, maxwidth);
- contentheight = bound(minheight, contentheight, maxheight);
-
- int cw = bound(minwidth, contentwidth, maxwidth), ch = bound(minheight, contentheight, maxheight);
+ int cw = contentwidth = bound(minwidth, contentwidth, maxwidth);
+ int ch = contentheight = bound(minheight, contentheight, maxheight);
//#repeat contentwidth/contentheight contentheight/contentwidth minwidth/minheight row/col col/row \
// textwidth/textheight maxwidth/maxheight bounds/boundsy x1/y1 x2/y2 z1/q1 z2/q2 z3/q3 z4/q4 \
// horizontalBounds/verticalBounds e/f multiply_px/multiply_py xmin/ymin xmax/ymax
private static final boolean OPTIMIZE = false;
/** Renders self and children within the specified region. All rendering operations are clipped to xIn,yIn,wIn,hIn */
- public void render(int cx1, int cy1, int cx2, int cy2, PixelBuffer buf, Affine a) {
+ public void render(PixelBuffer buf, Affine a, Mesh clipFrom) { render(buf, a, clipFrom, Affine.identity()); }
+ public void render(PixelBuffer buf, Affine a, Mesh clipFrom, Affine clipa) {
if (!test(VISIBLE)) return;
- a = a.copy().premultiply(transform);
-
- // FIXME: clipping
- if (path == null) {
- if (((fillcolor & 0xFF000000) != 0x00000000 || parent == null)) {
- if (OPTIMIZE && a.doesNotRotate()) {
- int x = (int)a.multiply_px(0, 0);
- int y = (int)a.multiply_py(0, 0);
- int x2 = (int)a.multiply_px(contentwidth, contentheight);
- int y2 = (int)a.multiply_py(contentwidth, contentheight);
- buf.fillTrapezoid(x, x, y, x2, x2, y2, (fillcolor & 0xFF000000) == 0 ? 0xffffffff : fillcolor);
- } else {
- new Polygon().addrect(0, 0, contentwidth, contentheight, a).fill(buf, new Paint.SingleColorPaint(fillcolor));
- }
+ a = a.copy().multiply(transform);
+ clipa = clipa.copy().multiply(transform);
+
+ if (mesh == null)
+ if (path != null) mesh = new Mesh(path, true);
+ else {
+ if (((fillcolor & 0xFF000000) != 0x00000000 || parent == null) && (text==null||"".equals(text)))
+ mesh = new Mesh().addRect(0, 0, contentwidth, contentheight);
+ // long ret = font.rasterizeGlyphs(text, buf, a, null, 0x777777, 0);
+ // minwidth = maxwidth = font.textwidth(text);
+ // minheight = maxheight = font.textwidth(text);
+ // if (ret == 0) Platform.Scheduler.add(this);
+ // FIXME: texture
}
- // FIXME: text
- // FIXME: texture
- } else {
- Polygon p = new Polygon(path, a);
- p.fill(buf, new Paint.SingleColorPaint(fillcolor));
- p.stroke(buf, strokecolor);
+ if (mesh==null) {
+ for(Box b = getChild(0); b != null; b = b.nextSibling()) b.render(buf, a, clipFrom, clipa);
+ return;
}
- for(Box b = getChild(0); b != null; b = b.nextSibling()) b.render(cx1, cy1, cx2, cy2, buf, a);
+ // FIXME: mesh clipping code has been getting stuck in loops; to see this,
+ // uncomment the next two lines and swap the order of the last two lines.
+
+ //if (clipFrom != null) clipFrom.subtract(mesh, clipa);
+ //Mesh mesh = treeSize() > 0 ? this.mesh.copy() : this.mesh;
+ mesh.fill(buf, a, null, fillcolor, true);
+ for(Box b = getChild(0); b != null; b = b.nextSibling()) b.render(buf, a, mesh, Affine.identity());
}
-
// Methods to implement org.ibex.js.JS //////////////////////////////////////
public JS call(JS method, JS[] args) throws JSExn {
case "indexof":
Box b = (Box)args[0];
if (b.parent != this)
- return (redirect == null || redirect == this) ?
- JSU.N(-1) : redirect.call(method, args);
+ return (redirect == null || redirect == this) ? JSU.N(-1) : redirect.call(method, args);
return JSU.N(b.getIndexInParent());
case "distanceto":
if (JSU.isInt(name)) { put(JSU.toInt(name), value); return; }
//#switch(JSU.toString(name))
case "thisbox": if (value == null) removeSelf();
- case "text": { String s = value==null ? "" : JSU.toString(value); CHECKSET_STRING(text); RECONSTRAIN(); dirty(); }
+ case "text": {
+ String s = value==null ? "" : JSU.toString(value);
+ text = s;
+ minwidth = maxwidth = font.textwidth(text);
+ System.out.println("width=" + width);
+ minheight = maxheight = font.textheight(text);
+ System.out.println("height=" + height);
+ RECONSTRAIN();
+ dirty();
+ }
case "strokecolor": value = JSU.N(Color.stringToColor(JSU.toString(value))); CHECKSET_INT(strokecolor); dirty();
case "textcolor": value = JSU.N(Color.stringToColor(JSU.toString(value))); CHECKSET_INT(strokecolor); dirty();
case "shrink": CHECKSET_FLAG(HSHRINK | VSHRINK); RECONSTRAIN();
case "hshrink": CHECKSET_FLAG(HSHRINK); RECONSTRAIN();
case "vshrink": CHECKSET_FLAG(VSHRINK); RECONSTRAIN();
case "path": {
+ mesh = null;
path = new Path(JSU.toString(value));
float tx = -1 * Encode.longToFloat2(path.horizontalBounds(Affine.identity()));
float ty = -1 * Encode.longToFloat2(path.verticalBounds(Affine.identity()));
dirty();
polygon = null;
}
+ case "clippath": {
+ clippath = new Path(JSU.toString(value));
+ //float tx = -1 * Encode.longToFloat2(clippath.horizontalBounds(Affine.identity()));
+ //float ty = -1 * Encode.longToFloat2(clippath.verticalBounds(Affine.identity()));
+ //clippath.transform(Affine.translate(tx, ty), true);
+ REPLACE();
+ RECONSTRAIN();
+ dirty();
+ polygon = null;
+ }
case "transform": {
transform = Affine.parse(JSU.toString(value));
transform.e = 0;
transform.f = 0;
- if (getSurface() != null) getSurface().dirty(0, 0, 500, 500); // FIXME
+ if (getSurface() != null) // FIXME
+ getSurface().dirty(0, 0, getSurface().root.contentwidth, getSurface().root.contentheight);
REPLACE();
RECONSTRAIN(); dirty(); polygon = null;
}