created mirror

This commit is contained in:
whatever
2026-09-14 20:19:29 -04:00
commit 6764738d92
600 changed files with 87187 additions and 0 deletions

134
Java/flob/ArrowDecor.java Normal file
View File

@@ -0,0 +1,134 @@
/*
ArrwDecor.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** Arrows.
*/
public class ArrowDecor extends CoordDecor {
public static final String rcsid = "$Id: ArrowDecor.java,v 1.4 2000/10/26 18:09:29 tjl Exp $";
public static final boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
Color color;
/** A simple class that knows how to efficiently build
* ArrowDecors.
*/
static public class Builder extends CoordDecor.Builder {
Color col;
public Builder(FlobSet into, Color col) {
super(into);
this.col = col;
}
/** Make a line.
*/
public final void ar(int x0, int y0, int x1, int y1) {
makeRoom(4);
p[curp] = x0;
p[curp+1] = y0;
p[curp+2] = x1;
p[curp+3] = y1;
curp += 4;
}
protected Renderable create() {
return new ArrowDecor(p, np, col, d);
}
}
public ArrowDecor(int[] coords, int n, int d) {
this(coords, n, null, d);
}
/** Usual constructor.
* @param coords The coordinates for the lines, given as
* quadruplets x1, y1, x2, y2.
*/
public ArrowDecor(int[] coords, int n, Color color, int d) {
super(coords, n, d);
this.color = color;
}
public ArrowDecor(int x1, int y1, int x2, int y2, Color color, int d) {
super(null, 4, d);
this.coords = new int[] {
x1, y1, x2, y2
};
this.color = color;
this.d = d;
}
public void render(Graphics g) {
Color old = null;
if(color != null) {
old = g.getColor();
g.setColor(color);
}
for(int i=0; i+3<n; i+=4) {
int x1 = coords[i]; int y1=coords[i+1];
int x2 = coords[i+2]; int y2=coords[i+3];
int dx = x2 - x1;
int dy = y2 - y1;
int ox = -dy;
int oy = dx;
int [] x = new int[] {
x1 + ox/3 - dx/3,
x1 + ox/6 + (3*dx)/5,
x1 + ox/2 + (2*dx)/5,
x1 + dx,
x1 - ox/2 + (2*dx)/5,
x1 - ox/6 + (3*dx)/5,
x1 - ox/3 - dx/3,
x1
};
int [] y = new int[] {
y1 + oy/3 - dy/3,
y1 + oy/6 + (3*dy)/5,
y1 + oy/2 + (2*dy)/5,
y1 + dy,
y1 - oy/2 + (2*dy)/5,
y1 - oy/6 + (3*dy)/5,
y1 - oy/3 - dy/3,
y1
};
Color c = g.getColor();
g.setColor(color);
g.fillPolygon(x, y, x.length);
g.setColor(c);
g.drawPolyline(x, y, x.length-1);
}
if(old != null)
g.setColor(old);
}
}

159
Java/flob/BallCell.java Normal file
View File

@@ -0,0 +1,159 @@
/*
BallCell.java
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A ball-and-stick graphical representation of a cell.
*/
public class BallCell extends Flob implements Colorer {
public static final String rcsid = "$Id: BallCell.java,v 1.1.10.1 2002/02/16 18:51:42 tuukkah Exp $";
public static final boolean dbg = true;
String s;
Font f;
// XXX Should this *really* need to be stored here?
FontMetrics fm;
/** Font height. */
int fh;
int fasc;
/** String width. */
int sw;
ZZCell strCell;
int xoffs = 3;
int yoffs = 3;
Color ballColor;
Color bgColor;
public boolean addColor(Color c) {
if(ballColor == null) ballColor = c;
return true;
}
static public final Dimension getSize(FontMetrics fm, String str,
int xoffs, int yoffs) {
int w = fm.stringWidth(str) + xoffs * 2 + 2;
int h = fm.getHeight() + 2*yoffs;
w += h; // Room for the ball.
return new Dimension( w, h );
}
public int getStrX(int ind) {
if(fm == null) throw new Error("No fontmetrics");
if(ind > s.length()) {
// XXX What to do?
return x + xoffs + h + fm.stringWidth(s);
}
return x + xoffs + h + fm.stringWidth(s.substring(0, ind)) ;
}
public void render(Graphics g, int mx, int my, int md,
int mw, int mh) {
int ty = my + (mh-fh)/2 + fasc;
Color bu = g.getColor();
g.setColor(ballColor != null ? ballColor : Color.white);
g.fillOval(mx+yoffs, my+yoffs, mh-2*yoffs, mh-2*yoffs);
g.setFont(f);
int start = 0;
int end = -1;
while (end < s.length()) { // Split into lines
do {
end = s.indexOf(' ', end + 1);
if (end == -1) break;
} while (fm.stringWidth(s.substring(start, end)) < mw);
if (end == -1)
end = s.length();
if (start < end) {
String line = s.substring(start, end);
g.setColor(bgColor);
if (false && start != 0) {
g.fillRect(mx+xoffs + h - 2, ty - (fasc - (fh-fasc)), fm.stringWidth(line), fasc-(fh-fasc));
} else {
g.drawString(line, mx+xoffs + h - 1, ty - 1);
g.drawString(line, mx+xoffs + h + 2, ty + 2);
}
g.setColor(Color.white);
g.drawString(line, mx+xoffs + h + 1, ty + 1);
g.setColor(bu);
g.drawString(line, mx+xoffs + h, ty);
ty += fasc;
}
start = end + 1;
}
g.setColor(bu);
g.drawOval(mx+yoffs, my+yoffs, mh-2*yoffs, mh-2*yoffs);
}
public BallCell(int x, int y, int d, int w, int h,
ZZCell c, ZZCell strCell, String s,
Font f, FontMetrics fm, FlobSet fs) {
super(x, y, d, w, h, c);
// Not true, since c can be the flob cell and d the referring
// cell.
// this.s = c.getText();
this.s = (s==null? "" : s);
this.strCell = strCell;
this.f = f;
this.fm = fm;
this.fh = fm.getAscent()+fm.getDescent();
this.fasc = fm.getAscent()+fm.getLeading();
this.sw = fm.stringWidth(this.s);
this.bgColor = fs.getBackground();
}
public Object hit(int x0, int y0) {
if(!insideRect(x0, y0)) return null;
// Search for the right position in the string.
// We return a virtual cursor.
int ind = ZZUtil.findStringHit(s, x0-x-xoffs-h, fm);
return new ZZCursorVirtual(strCell, ind);
}
public Point getCenter(Point p) {
p.x = x + h/2;
p.y = y + h/2;
return p;
}
}

107
Java/flob/BeamDecor.java Normal file
View File

@@ -0,0 +1,107 @@
/*
BeamDecor.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A class for drawing beam decorations.
* Beams are currently irregular octagons.
* NOTE: Beams are rendered in reverse order: the first beam put in here
* becomes the topmost.
*/
public class BeamDecor extends CoordDecor {
public static final String rcsid = "$Id: BeamDecor.java,v 1.4 2000/09/19 10:31:59 ajk Exp $";
public static boolean dbg = false;
static void p(String s) { if(dbg) System.out.println(s); }
static void pa(String s) { System.out.println(s); }
Color[] colors;
/** A simple class that knows how to efficiently build
* these things.
*/
static public class Builder extends CoordDecor.Builder {
Color []col;
public Builder(FlobSet into) {
super(into);
}
protected void makeRoom(int l) {
if(col != null && nth >= col.length)
endl();
super.makeRoom(l);
}
protected void alloc() {
super.alloc();
col = new Color[np/16];
}
/** Make a beam.
* Coords: first 8x, then 8y.
*/
public final void b(int []xy, Color c) {
makeRoom(16);
p("beam: "+p+" "+col+" "+curp+" "+nth);
for(int i=0; i<16; i++)
p[curp+i] = xy[i];
col[nth] = c;
curp += 16;
nth++;
}
protected Renderable create() {
Color[] col2 = col;
col = null;
return new BeamDecor(p, np, d, col2);
}
}
public BeamDecor(int[] coords, int n, int d, Color[] cols) {
super(coords, n, d);
this.colors = cols;
}
public void render(Graphics g) {
Color old = null;
old = g.getColor();
int[] x = new int[8];
int[] y = new int[8];
for(int i=(n-16)-n%16; i>=0; i-=16) {
for(int k = 0; k<8; k++)
x[k] = coords[i+k];
for(int k = 0; k<8; k++)
y[k] = coords[i+8+k];
g.setColor(colors[i/16]);
g.fillPolygon(x, y, 8);
}
g.setColor(old);
}
}

90
Java/flob/BoxType.java Normal file
View File

@@ -0,0 +1,90 @@
/*
BoxType.java
*
* Copyright (c) 2001, Ted Nelson and Tuomas Lukka
* Copyright (c) 2001, Benja Fallenstein
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benja Fallenstein
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A type of boxes to be drawn around vobs (like the CellBgFlob backgrounds).
* Default: render nothing.
*/
public class BoxType {
public static final String rcsid = "$Id: BoxType.java,v 1.2 2001/03/18 17:50:16 bfallenstein Exp $";
public static final boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
protected Color bg = Color.white;
public void setBg(Color c) { if( c != null ) bg = c; }
protected void renderBg(Graphics g, BoxedFlob f, int mx, int my,
int md, int mw, int mh) {}
protected void renderFrame(Graphics g, BoxedFlob f, int mx, int my,
int md, int mw, int mh) {}
/** Render the background behind the flob.
*/
public void renderBg(Graphics g, Flob f) {
renderBg(g, (BoxedFlob)f, f.x, f.y, f.d, f.w, f.h);
}
/** Render the frame around the flob.
*/
public void renderFrame(Graphics g, Flob f) {
renderFrame(g, (BoxedFlob)f, f.x, f.y, f.d, f.w, f.h);
}
/** Render the interpolated background behind the flob.
*/
public void renderBg(Graphics g, Flob f, float fract) {
// XXX the interpolation path isn't necessarily linear!
Flob r = f.interpTo;
renderBg(g, (BoxedFlob)f,
(int)(f.x + fract*(r.x-f.x)),
(int)(f.y + fract*(r.y-f.y)),
(int)(f.d + fract*(r.d-f.d)),
(int)(f.w + fract*(r.w-f.w)),
(int)(f.h + fract*(r.h-f.h))
);
}
/** Render the interpolated frame around the flob.
*/
public void renderFrame(Graphics g, Flob f, float fract) {
// XXX the interpolation path isn't necessarily linear!
Flob r = f.interpTo;
renderFrame(g, (BoxedFlob)f,
(int)(f.x + fract*(r.x-f.x)),
(int)(f.y + fract*(r.y-f.y)),
(int)(f.d + fract*(r.d-f.d)),
(int)(f.w + fract*(r.w-f.w)),
(int)(f.h + fract*(r.h-f.h))
);
}
}

83
Java/flob/BoxedFlob.java Normal file
View File

@@ -0,0 +1,83 @@
/*
BoxedFlob.java
*
* Copyright (c) 2001, Ted Nelson and Tuomas Lukka
* Copyright (c) 2001, Benja Fallenstein
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka, adapted by Benja Fallenstein
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A flob which gets rendered by FlobSet with a background.
* XXX support for different shapes than rectangular?
* XXX replace Colorer entirely by this?
* XXX renderer must know whether background is transparent!
* XXX move needsBox here and default to true?!? replace by instanceof Boxed?
*/
public class BoxedFlob extends Flob implements Colorer {
public static final String rcsid = "$Id: BoxedFlob.java,v 1.1 2001/03/20 11:08:36 ajk Exp $";
public static final boolean dbg = true;
// static final void p(String s) { if(dbg) System.out.println(s); }
// static final void pa(String s) { System.out.println(s); }
// XXX need this? boolean drawBorder = true;
public boolean needsBox() { return true; }
int nsolids = 0;
Color[] solids;
protected Color bg = Color.white;
public Object hit(int x0, int y0) {
if( x0 >= x && y0 >= y && x0 < x+w && y0 < y+h )
return c;
return null;
}
public void setBg(Color c){ if( c != null ) bg = c; }
/** Adds one more solid color to be drawn inside
* the cell.
*/
public boolean addColor(Color c) {
if(solids == null || nsolids >= solids.length) {
Color[] n= new Color[nsolids + 10];
if(solids != null) System.arraycopy(solids, 0, n, 0, nsolids);
solids = n;
}
solids[nsolids++] = c;
return false;
}
/** The currently put solid colors.
* null = none. There may be null references near the end
* of the array. Mostly useful for checking for nullness.
*/
public Color[] getSolidColors() { return solids; }
public BoxedFlob(int x, int y, int d, int w, int h,
ZZCell c) {
super(x, y, d, w, h, c);
}
}

118
Java/flob/CellBgFlob.java Normal file
View File

@@ -0,0 +1,118 @@
/*
CellBgFlob.java
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A flob for the cell background.
* Draws a filled (possibly with several colors) background rectangle,
* surrounded by a rectangle of the current foreground color.
*/
public class CellBgFlob extends Flob implements Colorer {
public static final String rcsid = "$Id: CellBgFlob.java,v 1.16 2001/02/26 18:03:29 raulir Exp $";
public static final boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
boolean drawBorder = true;
int nsolids = 0;
Color[] solids;
protected Color bg = Color.white;
public Object hit(int x0, int y0) {
if( x0 >= x && y0 >= y && x0 < x+w && y0 < y+h )
return c;
return null;
}
public void setBg(Color c){ if( c != null ) bg = c; }
/** Override this in subclasses to render something inside the cell.
*/
protected void renderContent(Graphics g, int mx, int my, int mw, int mh) {
}
public void render(Graphics g, int mx, int my, int md, int mw, int mh) {
// p("ZZCC1 render: "+g+" "+mx+" "+my+" "+mw+" "+mh);
Color oldfg = g.getColor();
Shape oldclip = g.getClip();
// XXX save font?
g.clipRect(mx, my, mw, mh);
if(solids != null) {
for(int i=0; i<nsolids; i++) {
g.setColor(solids[i]);
g.fillRect(mx+(mw*i)/nsolids, my, mw/nsolids+1, mh);
}
} else {
g.setColor(bg);
g.fillRect(mx, my, mw, mh);
}
g.setColor(oldfg);
renderContent(g, mx, my, mw, mh);
// XXX Span indication???
if(drawBorder) {
g.drawRect(mx, my, mw-1, mh-1);
if(mh >= 14) {
g.drawRect(mx+1, my+1, mw-3, mh-3);
}
}
g.setClip(oldclip);
}
/** Adds one more solid color to be drawn inside
* the cell.
*/
public boolean addColor(Color c) {
if(solids == null || nsolids >= solids.length) {
Color[] n= new Color[nsolids + 10];
if(solids != null) System.arraycopy(solids, 0, n, 0, nsolids);
solids = n;
}
solids[nsolids++] = c;
return false;
}
/** The currently put solid colors.
* null = none. There may be null references near the end
* of the array. Mostly useful for checking for nullness.
*/
public Color[] getSolidColors() { return solids; }
public CellBgFlob(int x, int y, int d, int w, int h,
ZZCell c) {
super(x, y, d, w, h, c);
}
}

105
Java/flob/CellFlob1.java Normal file
View File

@@ -0,0 +1,105 @@
/*
CellFlob1.java
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class CellFlob1 extends BoxedFlob {
public static final String rcsid = "$Id: CellFlob1.java,v 1.16 2001/03/18 17:50:16 bfallenstein Exp $";
public static final boolean dbg = true;
String s;
Font f;
// XXX Should this *really* need to be stored here?
FontMetrics fm;
/** Font height. */
int fh;
int fasc;
/** String width. */
int sw;
ZZCell strCell;
int xoffs = 0; // Previously, these margins where three, but at the moment
int yoffs = 0; // margins are cared for by the BoxTypes
static public final Dimension getSize(FontMetrics fm, String str,
int xoffs, int yoffs) {
int w = fm.stringWidth(str) + xoffs * 2 + 2;
int h = fm.getHeight() + 2*yoffs;
if(w < h) w = h;
return new Dimension( w, h );
}
public int getStrX(int ind) {
if(fm == null) throw new Error("No fontmetrics");
if(ind > s.length()) {
// XXX What to do?
return x + xoffs + fm.stringWidth(s);
}
return x + xoffs + fm.stringWidth(s.substring(0, ind)) ;
}
public void render(Graphics g, int mx, int my, int md, int mw, int mh) {
Shape oldClip = g.getClip();
g.clipRect(mx, my, mw, mh);
int ty = my + (mh-fh)/2 + fasc;
g.setFont(f);
g.drawString(s, mx+xoffs, ty);
g.setClip(oldClip);
}
public CellFlob1(int x, int y, int d, int w, int h,
ZZCell c, ZZCell strCell, String s,
Font f, FontMetrics fm) {
super(x, y, d, w, h, c);
// Not true, since c can be the flob cell and d the referring
// cell.
// this.s = c.getText();
this.s = (s==null? "" : s);
this.strCell = strCell;
this.f = f;
this.fm = fm;
this.fh = fm.getAscent()+fm.getDescent();
this.fasc = fm.getAscent()+fm.getLeading();
this.sw = fm.stringWidth(this.s);
}
public Object hit(int x0, int y0) {
if(!insideRect(x0, y0)) return null;
// Search for the right position in the string.
// We return a virtual cursor.
int ind = ZZUtil.findStringHit(s, x0-x-xoffs, fm);
return new ZZCursorVirtual(strCell, ind);
}
}

View File

@@ -0,0 +1,205 @@
/*
RasterFactory1.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A simple cell factory that gives the cells as one-line strings.
* Variable length is possible.
*/
public class CellFlobFactory1 implements FlobFactory, ZOb {
public static final String rcsid = "$Id$";
public static boolean dbg = false;
private static void p(String s) { if(dbg) ZZLogger.log(s); }
private static void pa(String s) { ZZLogger.log(s); }
STRUCTPARAMS {
/** The string to use to get the default cell width. */
String widthstr
= "0000000000";
/** The default background color.
* XXX Currently, because of color mixing, the foreground
* comes from FlobSet. This should maybe change - check later.
*/
Color bg
= Color.white;
/** The font for the default enlargement. */
ScalableFont font
= new ScalableFont("SansSerif", Font.PLAIN, 12);
/** Whether the font changes size with the enlargement. */
boolean zoomfont
= true;
/** Whether the font can get bigger than the default font.
* Ignored (or rather, doesn't have any effect) when zoomfont is false.
*/
boolean enlargefont
= true;
/** The x and y margins
*/
int[] margins
= new int[] {2, 1};
/** Whether to produce BallCells instead?
*/
boolean ball
= false;
}
/*
RasterCellFactory1(Component c) {
comp = c;
}
*/
protected Font fon(int scale) { return font.getFont(scale); }
protected FontMetrics fonmet(int scale) {
return font.getFontMetrics(scale);
}
protected int getScale(float fract) { return getScale(fract,false); }
protected int getScale(float fract,boolean real) {
if(!enlargefont && !real && fract>=1.0) return 1000;
return (int)(fract*1000);
}
public Dimension getSize(ZZCell c, float fract) {
String str = widthstr;
if(c != null) str = c.getText();
if(str == null) str = "";
FontMetrics fm = fonmet(getScale(fract,true));
if(ball)
return BallCell.getSize(fm, str, margins[0], margins[1]);
else
return CellFlob1.getSize(fm, str, margins[0], margins[1]);
}
public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int d, int w, int h) {
int scale = getScale(fract);
Font f = fon(scale);
FontMetrics fm = fonmet(scale);
if(ball) {
BallCell cf = new BallCell(x, y, d, w, h, handleCell, c,
c.getText(), f, fm, into);
cf.xoffs = margins[0];
cf.yoffs = margins[1];
addSolidColors(into, cf, cf);
into.add(cf);
return cf;
} else {
CellFlob1 cf = new CellFlob1(x, y, d, w, h, handleCell, c,
c.getText(), f, fm);
cf.bg = bg;
cf.xoffs = margins[0];
cf.yoffs = margins[1];
addSolidColors(into, cf, cf);
into.add(cf);
return cf;
}
}
public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int depth,
float xfract, float yfract) {
Dimension d = getSize(c, fract);
return makeFlob(into, c, handleCell, fract,
(int)(x-xfract*d.width),
(int)(y-yfract*d.height),
depth, d.width, d.height);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign,
int depth, Dimension d) {
if(d == null) d = getSize(c, fract);
int x, y;
if(ball) {
x = p.x - d.height/2; y = p.y - d.height/2;
} else {
x = p.x - d.width/2; y = p.y - d.height/2;
}
if(xalign < 0) x = p.x;
if(xalign > 0) x = p.x - d.width;
if(yalign < 0) y = p.y;
if(yalign > 0) y = p.y - d.height;
p("centerFlob "+p+" "+d+" at "+x+" "+y+" align "+xalign+" "+yalign);
return makeFlob(into, c, handleCell, fract, x, y,
depth, d.width, d.height);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign, int depth) {
return centerFlob(into, c, handleCell, fract, p, xalign, yalign,
depth, null);
}
/** A routine to add solid background colors according to scheme 1.
* No better place to put it right now, but this routine can be
* called from anywhere to color the background of a cellbgflob
* as requested.
* Also adds line cursors, if any.
*/
static public void addSolidColors(FlobSet into, Flob f, Colorer col) {
// Special case check: Is this a cursor or a cursor's clone?
ZZCell orig = f.c.h("d.clone", -1);
if(orig.h("d.cursor-list", -1).s("d.cursor", -1)
!= null) {
col.addColor(ZZCursorReal.getColorOrWhite(orig));
return; // XXX should draw line cursors!
}
Enumeration e = ZZCursorReal.getPointers(f.c);
while(e.hasMoreElements()) {
ZZCell cu = (ZZCell)e.nextElement();
Color color = ZZCursorReal.getColor(cu);
if(color != null) if(col.addColor(color)) return;
if(!(f instanceof CellFlob1)) continue;
int offs = ZZCursorReal.getOffs(cu);
if(offs == ZZCursor.NO_OFFSET) continue;
int x = ((CellFlob1)f).getStrX(offs);
into.add(new LineDecor(x, f.y, x, f.y+f.h,
Color.black, f.d));
}
// XXX Does not check whose mark it is - should!
if(f.c.s("d.mark-set", 1)!=null)
if(col.addColor(Color.red)) return;
if(f.c.s("d.clone", -1) != null)
if(col.addColor(Color.yellow)) return;
else if(f.c.s("d.clone", 1) != null)
if(col.addColor(new Color(255, 255, 192))) return;
}
}
// vim: set syntax=java :

View File

@@ -0,0 +1,207 @@
/*
RasterFactory2.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka, multiline by Benjamin Fallenstein
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A simple cell factory that gives the cells as one-line strings.
* Variable length is possible.
* XXX This class is a bad copy of RasterCellFactory 1.
* Inheritance should be rather used, but doesn't work yet with ZObs.
*/
public class CellFlobFactory2 implements FlobFactory, ZOb {
public static final String rcsid = "$Id$";
public static boolean dbg = false;
private static final void p(String s) { if(dbg) System.out.println(s); }
private static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** The string to use to get the default cell width. */
String widthstr
= "0000000000";
/** The default background color.
* XXX Currently, because of color mixing, the foreground
* comes from FlobSet. This should maybe change - check later.
*/
Color bg
= Color.white;
/** The font for the default enlargement. */
ScalableFont font
= new ScalableFont("SansSerif", Font.PLAIN, 12);
/** Whether the font changes size with the enlargement. */
boolean zoomfont
= true;
/** Whether the font can get bigger than the default font.
* Ignored (or rather, doesn't have any effect) when zoomfont is false.
*/
boolean enlargefont
= true;
/** The x and y margins
*/
int[] margins
= new int[] {3, 2};
ZOb ftextlayouter
= new FTextLayouter();
}
protected Font fon(int scale) { return font.getFont(scale); }
protected FontMetrics fonmet(int scale) {
return font.getFontMetrics(scale);
}
protected int getScale(float fract) { return getScale(fract, false); }
protected int getScale(float fract, boolean real) {
if(!enlargefont && !real && fract>=1.0) return 1000;
return (int)(fract*1000);
}
public Dimension getSize(ZZCell c, float fract) {
String str = widthstr;
if(c != null) str = c.getText();
if(str == null) str = "";
FontMetrics fm = fonmet(getScale(fract, true));
return CellFlob1.getSize(fm, str, margins[0]*2, margins[1]*2);
}
public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, int x, int y, int d, int w, int h) {
int scale = getScale(fract);
Font f = fon(scale);
FontMetrics fm = fonmet(scale);
CellBgFlob cf = new CellBgFlob(x, y, d, w, h, c);
Point p = cf.getPoint(1, 1);
p = cf.getPoint(-1, -1);
cf.bg = bg;
int xm = margins[0], ym = margins[1];
addSolidColors(into, cf);
FText ftxt = new FText(new FText.Part[] {
new FText.CellPart(c, 0, -1, f, fm, null, null)
});
Rectangle rect = new Rectangle(x+xm, y+ym, w-xm-xm, h-ym-ym);
// XXX -- make this work! (shall place cursor in middle if text too long)
// int offs = -1;
// for(Enumeration e=ZZCursorReal.getPointers(c); e.hasMoreElements();) {
// int offs0 = ZZCursorReal.getOffs((ZZCell)e.nextElement());
// if(offs0 != ZZCursorReal.NO_OFFSET) { offs = offs0; break; }
// }
FTextLayouter ftl = (FTextLayouter)ftextlayouter;
ftl.firstCap = false;
// if(offs < 0)
ftl.place(into, ftxt, rect, d, 1, rect.y+1, 0, true, cf);
// else
// ftl.place(into, ftxt, rect, d, 0,
// rect.y+rect.height/2-fm.getHeight()/2, offs, true, cf);
into.add(cf);
return cf;
}
public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int depth,
float xfract, float yfract) {
Dimension d = getSize(c, fract);
return makeFlob(into, c, handleCell, fract,
(int)(x-xfract*d.width),
(int)(y-yfract*d.height),
depth, d.width, d.height);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign,
int depth, Dimension d) {
if(d == null) d = getSize(c, fract);
int x, y;
x = p.x - d.width/2; y = p.y - d.height/2;
if(xalign < 0) x = p.x - d.width;
if(xalign > 0) x = p.x;
if(yalign < 0) y = p.y - d.height;
if(yalign > 0) y = p.y;
return makeFlob(into, c, handleCell, fract, x, y,
depth, d.width, d.height);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign, int depth) {
return centerFlob(into, c, handleCell, fract, p, xalign, yalign,
depth, null);
}
/** A routine to add solid background colors according to scheme 1.
* No better place to put it right now, but this routine can be
* called from anywhere to color the background of a cellbgflob
* as requested.
* Also adds line cursors, if any.
*/
static public void addSolidColors(FlobSet into, CellBgFlob f) {
// Special case check: Is this a cursor or a cursor's clone?
ZZCell orig = f.c.h("d.clone", -1);
if(orig.h("d.cursor-list", -1).s("d.cursor", -1)
!= null) {
f.addColor(ZZCursorReal.getColorOrWhite(orig));
return; // XXX should draw line cursors!
}
ZZCell cu = f.c.s("d.cursor", 1);
while(cu != null) {
Color color = ZZCursorReal.getColor(cu);
if(color != null) f.addColor(color);
// String txt = cu.getText();
// if(txt != null && !txt.equals("") && f instanceof CellBgFlob) {
// try {
// int ind = Integer.parseInt(txt);
// int x = ((CellBgFlob)f).getStrX(ind);
// into.add(new LineDecor(x, f.y, x, f.y+f.h,
// Color.black, f.d));
// } catch(NumberFormatException e) {
// }
// }
cu = cu.s("d.cursor-list", 1);
}
// XXX Does not check whose mark it is - should!
if(f.c.s("d.mark-set", 1)!=null)
f.addColor(Color.red);
if(f.c.s("d.clone", -1) != null)
f.addColor(Color.yellow);
else if(f.c.s("d.clone", 1) != null)
f.addColor(new Color(255, 255, 192));
}
}
// vim: set syntax=java :

41
Java/flob/Colorer.java Normal file
View File

@@ -0,0 +1,41 @@
/*
Colorer.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
/** An interface for coloring cell background -like things.
* The information about how many colors are appropriate should
* move separately from this.
*/
public interface Colorer {
String rcsid = "$Id: Colorer.java,v 1.1 2000/10/26 18:15:05 tjl Exp $";
/** Add the given color to the set of colors to be shown in the background,
* or whatever.
* It is assumed that the colors come more significant first, so that
* Colorers are free to take any number of the first ones and ignore
* the rest.
* @return Whether the rest of the colors will be ignored.
*/
boolean addColor(Color c);
}

View File

@@ -0,0 +1,58 @@
/*
CombinedView.zob
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag;
import java.awt.*;
/** A view that shows all views of the accursed cell next to each other.
*/
public class CombinedView implements FlobView, ZOb {
public static final String rcsid = "$Id: CombinedView.zob,v 1.6 2000/12/31 15:15:50 bfallenstein Exp $";
/** Should we print out debugging info? */
public static boolean dbg = false;
static final void p(String s) { if(dbg) pa(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {}
public void raster(FlobSet into, FlobFactory fact,
ZZCell win, String[] dims, ZZCell accursed) {
ZZCell[] apps = ApplitudeMgr.getApplitudes(accursed);
if(apps.length == 0)
apps = new ZZCell[] { ApplitudeMgr.getFallback(win.getSpace()) };
int n = apps.length;
ZZCell pref = ApplitudeMgr.getWindowApp(win);
Dimension size = new Dimension(into.getSize());
if(pref != null)
fact.centerFlob(into, pref, pref, (float)1.5,
new Point(size.width, size.height), 1, 1, 1);
size.width = size.width / n;
for(int i=0; i<n; i++) {
FlobSet set = into.create(size);
FlobView view = ApplitudeMgr.getView(apps[i]);
view.raster(set, fact, win, dims, accursed);
into.fetch(set, size.width * i, 0, 0, apps[i]);
}
}
}

149
Java/flob/CompassView.zob Normal file
View File

@@ -0,0 +1,149 @@
/*
CompassRaster.zob
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuukka Hastrup
*/
package org.gzigzag;
import java.awt.Dimension;
import java.lang.Math;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.util.Vector;
public class CompassView implements FlobView, ZOb {
public static final String rcsid = "$Id$";
public static boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
Font dfont = new Font("SansSerif", Font.PLAIN, 12);
}
int dfonth;
FontMetrics dfm;
INITIALIZE {
dfm = FONTMETRICS(dfont);
dfonth = dfm.getHeight();
}
public void raster(FlobSet into, FlobFactory fact, ZZCell view,
String[]vds, ZZCell accursed) {
Dimension d = into.getSize();
int midx = d.width / 2;
int midy = d.height / 2;
Dimension c = fact.getSize(null, 1);
int cw = c.width;
int ch = c.height;
ZZCell stdim = ZZCursorReal.get(view.s("d.dims", 1));
/* ZZConnection[] conns = accursed.getConns();
for (int i = 0; i < conns.length; i++)
System.out.println("Conn #" + i + ": " +
conns[i].c1.getID() + "-<" +
conns[i].c2.getID() + (conns[i].dir == -1 ?
"-" : "") +
conns[i].dim + ">-" +
conns[i].c2.getID());*/
Vector dims = new Vector(); // Dims to be drawn
Vector pos = new Vector(); // Cells to positive directions to be drawn
Vector neg = new Vector(); // Cells to negative directions to be drawn
ZZCell dim, pc, nc;
dim=stdim;
do { // Go through the DimList starting from the x-axis dimension
String cdim = dim.getText();
p("Found dim: "+cdim);
pc = accursed.s(cdim, 1);
nc = accursed.s(cdim, -1);
if(nc != null || pc != null) {
dims.addElement(cdim);
pos.addElement(pc);
neg.addElement(nc);
}
dim = dim.s("d.2", 1);
} while(dim != stdim); // Do until loop closes
int numdirs = pos.size()+neg.size(); // Number of cells and thus sectors
if(numdirs == 0)
return; // No cells to draw
double angle = 2 * Math.PI / (numdirs);
int l = (int) ((d.height < d.width ? d.height : d.width) / 2 * 0.5);
fact.makeFlob(into, accursed, accursed, 1,
(d.width-cw) / 2, (d.height-ch) / 2, 1, cw, ch);
int i = 0;
LineDecor.Builder nldb = new LineDecor.Builder(into, Color.black);
LineDecor.Builder pldb = new LineDecor.Builder(into, Color.red);
nldb.startl(numdirs/2*4, 12);
pldb.startl(numdirs/2*4, 12);
double a = (double)-2/3*Math.PI; // Begin placing positive cells top left
while (i < numdirs/2) {
int dx = x(a, l);
int dy = y(a, l);
if(pos.elementAt(i)!=null) {
fact.makeFlob(into, (ZZCell)pos.elementAt(i), (ZZCell)pos.elementAt(i),
(float) 0.7,
midx + dx-cw/2, midy + dy-ch/2,
1, cw, ch);
pldb.l(midx, midy, midx + dx, midy + dy);
into.add(new TextDecor(
midx+dx+cw/2-dfm.stringWidth("+"+(String)dims.elementAt(i)),
midy+dy-ch/2, "+"+(String)dims.elementAt(i), Color.red, dfont));
}
if(neg.elementAt(i)!=null) {
fact.makeFlob(into, (ZZCell)neg.elementAt(i), (ZZCell)neg.elementAt(i),
(float) 0.7,
midx -dx -cw/2, midy -dy -ch/2,
1, cw, ch);
nldb.l(midx, midy, midx -dx, midy -dy);
into.add(new TextDecor(
midx-dx-cw/2, midy-dy+ch/2+dfonth,
"-"+(String)dims.elementAt(i), Color.black, dfont));
}
i++;
a += angle; // Rotate clockwise
}
nldb.endl();
pldb.endl();
}
protected int x(double angle, int length) {
return (int) (Math.cos(angle) * length);
}
protected int y(double angle, int length) {
return (int) (Math.sin(angle) * length);
}
}
// vim: set syntax=java :

View File

@@ -0,0 +1,174 @@
/*
ConnectionLineDecor.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A decoration of lines connecting flobs to each other.
* Interpolation is done by this class. The coordinates are
* given as points inside the flob's rectangle.
*/
public class ConnectionLineDecor extends Flob {
public static final String rcsid = "$Id: ConnectionLineDecor.java,v 1.5 2000/09/19 10:31:59 ajk Exp $";
public static final boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
/** A class that incrementally builds these.
*/
static public class Builder {
FlobSet into;
int curp; int np;
Flob[] flobs;
int[] p;
Color col;
int d;
public Builder(FlobSet into, Color col) {
this.into = into;
this.col = col;
}
public final void startl(int n, int d) {
if(curp != 0) endl();
this.d = d;
curp = 0;
np = n;
p = null;
flobs = null;
}
public final void l(Flob f0, int x0, int y0, Flob f1, int x1, int y1) {
if(p==null) {
p = new int[np * 4];
flobs = new Flob[np * 2];
} else if(curp >= np) {
endl();
p = new int[np * 4];
flobs = new Flob[np * 2];
curp = 0;
}
flobs[curp*2 + 0] = f0;
flobs[curp*2 + 1] = f1;
p[curp*4 + 0] = x0;
p[curp*4 + 1] = y0;
p[curp*4 + 2] = x1;
p[curp*4 + 3] = y1;
curp ++;
}
public void endl() {
if(p==null) return;
into.add(new ConnectionLineDecor(flobs, p, curp, col, d));
p = null; flobs = null; curp = 0;
}
}
Color color;
int n;
Flob[] flobs;
int[] coords; // 256th parts
public ConnectionLineDecor(Flob[] flobs, int[] coords, int n, int d) {
this(flobs, coords, n, null, d);
}
/** Usual constructor.
* @param coords The coordinates for the lines, given as
* quadruplets x1, y1, x2, y2.
*/
public ConnectionLineDecor(Flob[] flobs, int[] coords, int n, Color color, int d) {
// XXX Is size 0x0 right?
super(0, 0, d, 0, 0, null);
this.flobs = flobs;
this.coords = coords;
this.n = n;
this.color = color;
}
public void render(Graphics g) {
Color old = null;
if(color != null) {
old = g.getColor();
g.setColor(color);
}
g.setColor(Color.black);
p("Drawing flobconns");
for(int i=0; i<n; i++) {
Flob f1 = flobs[i*2];
Flob f2 = flobs[i*2+1];
p("Draw: "+
f1.x+" "+f1.y+" "+f1.w+" "+f1.h+" "+
f2.x+" "+f2.y+" "+f2.w+" "+f2.h+" "+
coords[i*4]+" "+
coords[i*4+1]+" "+
coords[i*4+2]+" "+
coords[i*4+3]+" ");
g.drawLine(
f1.x + (f1.w * coords[i*4])/256,
f1.y + (f1.h * coords[i*4+1])/256,
f2.x + (f2.w * coords[i*4+2])/256,
f2.y + (f2.h * coords[i*4+3])/256
);
}
if(old != null)
g.setColor(old);
}
public void renderInterp(Graphics g, float fract) {
Color old = null;
if(color != null) {
old = g.getColor();
g.setColor(color);
}
g.setColor(Color.black);
for(int i=0; i<n; i++) {
Flob f1 = flobs[i*2];
Flob f1i = f1.interpTo;
Flob f2 = flobs[i*2+1];
Flob f2i = f2.interpTo;
int c1x = f1.x + (f1.w * coords[i*4])/256;
int c1y = f1.y + (f1.h * coords[i*4+1])/256;
int c2x = f2.x + (f2.w * coords[i*4+2])/256;
int c2y = f2.y + (f2.h * coords[i*4+3])/256;
int ic1x = f1i.x + (f1i.w * coords[i*4])/256;
int ic1y = f1i.y + (f1i.h * coords[i*4+1])/256;
int ic2x = f2i.x + (f2i.w * coords[i*4+2])/256;
int ic2y = f2i.y + (f2i.h * coords[i*4+3])/256;
g.drawLine(
(int)(c1x + fract * (ic1x - c1x)),
(int)(c1y + fract * (ic1y - c1y)),
(int)(c2x + fract * (ic2x - c2x)),
(int)(c2y + fract * (ic2y - c2y))
);
}
if(old != null)
g.setColor(old);
}
}

122
Java/flob/CoordDecor.java Normal file
View File

@@ -0,0 +1,122 @@
/*
CoordDecor.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A base class from which to derive fast decorations with coordinates.
*/
abstract public class CoordDecor extends Renderable {
public static final String rcsid = "$Id: CoordDecor.java,v 1.7 2000/12/26 20:15:14 bfallenstein Exp $";
public static boolean dbg = false;
static void p(String s) { if(dbg) System.out.println(s); }
static void pa(String s) { System.out.println(s); }
/** The number of coordinates.
*/
int n;
/** The coordinates.
* Note: the translate() method assumes that at each even index there's
* an x coordinate, and at each odd index there's an y coordinate. If
* that's not true, override translate() in subclasses (possibly returning
* false, if the coords can't be translated).
*/
int[] coords;
/** A simple class that knows how to efficiently build
* these things. The efficiency comes from always allocating
* an array and never letting go of it; adding the arrays to the
* flob when they're full and starting fresh.
*/
static abstract public class Builder {
/** The flobset the finished products go into. */
FlobSet into;
/** The depth of the finished product. */
int d;
/** The nth object being rendered. */
int nth;
/** The current point index. */
int curp;
/** The number of point coordinates to reserve. */
int np;
/** The coordinates. */
int[] p;
public Builder(FlobSet into) {
this.into = into;
}
/** Start a set.
* @param n The estimated number of coordinates to come.
* @param d The depth of the set now begun.
*/
public void startl(int n, int d) {
if(curp != 0) endl();
this.d = d;
curp = 0;
np = n;
p = null;
}
/** Make room for n coordinates. */
protected void makeRoom(int l) {
if(p!=null && curp + l > p.length)
endl();
if(p==null)
alloc();
}
/** Allocate the arrays. */
protected void alloc() {
p = new int[np];
curp = 0;
nth = 0;
}
public void endl() {
if(p==null) return;
into.add(create());
p = null; curp = 0;
}
abstract protected Renderable create();
}
public CoordDecor(int[] coords, int n, int d) {
this.coords = coords;
this.n = n;
this.d = d;
if(coords != null && coords.length < n)
throw new Error("CoordDecor: less length than n!!!");
}
abstract public void render(Graphics g);
public boolean translate(int x, int y) {
for(int i=0; i<coords.length; i+=2) {
coords[i] += x;
if(i+1 < coords.length) coords[i+1] += y;
}
return true;
}
}

218
Java/flob/CursorView.zob Normal file
View File

@@ -0,0 +1,218 @@
/*
CursorView.zob
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Antti-Juhani Kaijanaho
*/
package org.gzigzag;
import java.awt.*;
import java.util.*;
class CursorView implements FlobView, ZOb {
public static boolean dbg = false;
static final void p(String s) { if(dbg) ZZLogger.log(s); }
static final void pa(String s) { ZZLogger.log(s); }
STRUCTPARAMS {
float horizonlevel
= (float) 0.5;
float pointerradius
= (float) 0.3;
float sizefactor
= (float) 0.8;
int initdepth
= 2;
int maxdepth
= 8;
Color linecolor
= Color.blue;
double arrowhead_angle
= Math.PI / 6;
int arrowhead_length
= 5;
}
// translation (rotation && scaling) matrices
double a00, a01, a10, a11, b00, b01, b10, b11;
INITIALIZE {
if (!(0 < horizonlevel && horizonlevel < 1)) {
throw new ZZError("horizonlevel parameter outside ]0,1[");
}
if (!(0 < pointerradius && pointerradius < 1)) {
throw new ZZError("pointerradius parameter outside ]0,1[");
}
a00 = arrowhead_length * Math.cos(arrowhead_angle);
a01 = arrowhead_length * Math.sin(arrowhead_angle);
a10 = arrowhead_length * -Math.sin(arrowhead_angle);
a11 = arrowhead_length * Math.cos(arrowhead_angle);
b00 = arrowhead_length * Math.cos(arrowhead_angle);
b01 = arrowhead_length * -Math.sin(arrowhead_angle);
b10 = arrowhead_length * Math.sin(arrowhead_angle);
b11 = arrowhead_length * Math.cos(arrowhead_angle);
}
Hashtable drawn;
private void drawPointerCells(FlobSet into, FlobFactory fact,
ZZCell centercell, Point centerpoint,
int radius, int level, float sfactor) {
if (level > maxdepth) return;
if (drawn.containsKey(centercell)) return;
Vector pointers = new Vector();
{
Dimension s = fact.getSize(null, 1);
int width = (int) (s.width * sfactor);
int height = (int) (s.height * sfactor);
int x = centerpoint.x - width / 2;
int y = centerpoint.y - height / 2;
p("radius = " + radius + ", x = " + x + ", y = "
+ y + ", width = " + width + ", height = "
+ height + ", centercell = " + centercell);
Flob fl = fact.makeFlob(into, centercell, centercell, 1,
x, y, level, width, height);
drawn.put(centercell, centercell);
}
for (Enumeration e = ZZCursorReal.getPointers(centercell);
e.hasMoreElements();) {
ZZCell c = (ZZCell) e.nextElement();
pointers.addElement(c);
p("Found cursor " + c);
}
int n = pointers.size();
p("n = " + n);
if (n == 0) return;
int prad = (int) (pointerradius * radius);
double baseangle = Math.PI / (n + 1);
int newradius;
{
double a = prad - prad * Math.cos(baseangle);
double b = prad * Math.sin(baseangle);
newradius = (int) Math.sqrt(a * a + b * b);
p("a = " + a + ", b = " + b + ", newradius = " + newradius);
}
for (int i = 0; i < n; i++) {
ZZCell c = (ZZCell) pointers.elementAt(i);
if (ZZCursorReal.get(c) != centercell) pa("WRONG CURSOR CELL FOUND!!!");
double angle = (i + 1) * baseangle;
p("angle = " + angle + " rad, " + angle * 180 / Math.PI + " deg");
int x = (int)(centerpoint.x + prad * Math.cos(angle));
int y = (int)(centerpoint.y + prad * Math.sin(angle));
drawPointerCells(into, fact, c, new Point(x, y), newradius,
level + 1, sfactor * sizefactor);
}
}
public void raster(final FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
ZZCell c = accursed;
Point pt = new Point(into.getSize().width / 2,
into.getSize().width / 2);
ZZCell ccand = ZZCursorReal.get(c);
if (ccand != null) {
c = ccand;
pt.y /= 2;
}
drawn = new Hashtable();
drawPointerCells(into, fact, c, pt,
into.getSize().width, initdepth, 1);
// Draw the cursor arrows
into.iterDepth(new FlobSet.DepthIter() {
public void act(Flob[] flobs, int start, int n) {
for(int i = start; i < start+n; i++) {
ZZCell pointer = flobs[i].c;
if (pointer == null) continue;
ZZCell pointee = ZZCursorReal.get(pointer);
if (pointee == null) continue;
p("pointer = " + pointer + ", pointee = " + pointee);
Flob from = flobs[i];
Flob[] tos = into.findFlobs(null, pointee);
for (int j = 0; j < tos.length; j++) {
Flob to = (Flob) tos[j];
int[] cs = new int[16];
// we make the arrow body in two parts:
// one from head to arrow point and one
// from arrow point to tail
cs[0] = from.x + from.w / 2;
cs[1] = from.y;
cs[2] = to.x + to.w / 2;
cs[3] = to.y + to.h;
double or1 = (cs[0] + cs[2]) / 2;
double or2 = (cs[1] + cs[3]) / 2;
cs[6] = cs[2];
cs[7] = cs[3];
cs[2] = (int) (or1 + 0.5);
cs[3] = (int) (or2 + 0.5);
cs[4] = cs[2];
cs[5] = cs[3];
double v1 = cs[0] - cs[2];
double v2 = cs[1] - cs[3];
double vlen = Math.sqrt(v1*v1 + v2*v2);
v1 = v1 / vlen;
v2 = v2 / vlen;
cs[8] = (int) (or1 + 0.5);
cs[9] = (int) (or2 + 0.5);
cs[10] = (int) (v1 * a00 + v2 * a01 + or1 + 0.5);
cs[11] = (int) (v1 * a10 + v2 * a11 + or2 + 0.5);
cs[12] = (int) (or1 + 0.5);
cs[13] = (int) (or2 + 0.5);
cs[14] = (int) (v1 * b00 + v2 * b01 + or1 + 0.5);
cs[15] = (int) (v1 * b10 + v2 * b11 + or2 + 0.5);
into.add(new LineDecor(cs, cs.length,
linecolor,
(from.d + to.d) / 2));
}
}
}
}, true);
}
}

179
Java/flob/FTextCellView.zob Normal file
View File

@@ -0,0 +1,179 @@
/*
FTextCellView.zob
*
* Copyright (c) 2001, Benja Fallenstein
* Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benja Fallenstein
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A cell view showing some FText.
* This class exists in order to make it easy to create cell views which
* just take an FText for a cell somehow and then render it on the screen.
* Subclasses have to implement getFText(ZZCell, int). Default: render the
* cell's content in the specified string.
* <p>
* XXX Don't use scene flobs. Instead, just place the split cell flobs in the
* higher level flob set and create a BoxedFlob 'round them.
*/
public class FTextCellView implements FlobFactory, ZOb {
public static final String rcsid = "$Id: FTextCellView.zob,v 1.4 2001/04/02 20:20:54 bfallenstein Exp $";
public static boolean dbg = false;
private static void p(String s) { if(dbg) ZZLogger.log(s); }
private static void pa(String s) { ZZLogger.log(s); }
// WHAT SUBCLASSES NEED TO OVERRIDE
/** Get the FText for this cell at the given scale.
* scale == fract * 1000.
*/
protected FText getFText(ZZCell c, int scale) {
return new FText(new FText.Part[] {
new FText.CellPart(c, 0, -1, f(scale), fm(scale), null, null)
});
}
// IMPLEMENTATION
/** Get the font for a given scale. */
protected final Font f(int sc) { return font.getFont(sc); }
/** Get the font metrics for a given scale. */
protected final FontMetrics fm(int sc) { return font.getFontMetrics(sc); }
STRUCTPARAMS {
/** The string to use to get the default cell width. */
String widthstr
= "0000000000";
/** The default background color.
* XXX Currently, because of color mixing, the foreground
* comes from FlobSet. This should maybe change - check later.
*/
Color bg
= Color.white;
/** The font for the default enlargement. */
ScalableFont font
= new ScalableFont("SansSerif", Font.PLAIN, 12);
ZOb ftextlayouter
= new FTextLayouter(false);
/** The x and y margins
*/
int[] margins
= new int[] {2, 1};
}
protected int getScale(float fract) {
return (int)(fract*1000);
}
public Dimension getSize(ZZCell c, float fract) {
if(c != null) {
FText ftxt = getFText(c.getRootclone(), getScale(fract));
return new Dimension(FText.Part.width(ftxt.parts) + margins[0]*2,
FText.Part.height(ftxt.parts) + margins[1]*2);
} else {
String str = widthstr;
if(str == null) str = "";
FontMetrics fm = fm(getScale(fract));
return CellFlob1.getSize(fm, str, margins[0], margins[1]);
}
}
public Flob getFlob(FlobSet into, ZZCell c, FText ftxt,
int x, int y, int d, int w, int h) {
int xm = margins[0], ym = margins[1];
BoxedFlob box = new BoxedFlob(x, y, d, w, h, c);
CellFlobFactory1.addSolidColors(into, box, box);
Rectangle rect = new Rectangle(x+xm, y+ym, w-xm, h-ym);
((FTextLayouter)ftextlayouter).place(into, ftxt, rect, d, 1, y+ym, 0,
true, box);
// Add the box last, so that it is shown under the text.
into.add(box);
return box;
}
public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, int x, int y, int d, int w, int h) {
FText ftxt = getFText(c.getRootclone(), getScale(fract));
return getFlob(into, c, ftxt, x, y, d, w, h);
}
public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int depth,
float xfract, float yfract) {
FText ftxt = getFText(c.getRootclone(), getScale(fract));
int w = FText.Part.width(ftxt.parts) + margins[0]*2;
int h = FText.Part.height(ftxt.parts) + margins[1]*2;
return getFlob(into, c, ftxt,
(int)(x-xfract*w),
(int)(y-yfract*h),
depth, w, h);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign,
int depth, Dimension d) {
if(d == null) return centerFlob(into, c, handleCell, fract, p, xalign,
yalign, depth);
int x, y;
x = p.x - d.width/2; y = p.y - d.height/2;
if(xalign < 0) x = p.x;
if(xalign > 0) x = p.x - d.width;
if(yalign < 0) y = p.y;
if(yalign > 0) y = p.y - d.height;
p("centerFlob "+p+" "+d+" at "+x+" "+y+" align "+xalign+" "+yalign);
return makeFlob(into, c, handleCell, fract, x, y,
depth, d.width, d.height);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign, int depth) {
int x, y;
FText ftxt = getFText(c.getRootclone(), getScale(fract));
int w = FText.Part.width(ftxt.parts) + margins[0]*2;
int h = FText.Part.height(ftxt.parts) + margins[1]*2;
x = p.x - w/2; y = p.y - h/2;
if(xalign < 0) x = p.x;
if(xalign > 0) x = p.x - w;
if(yalign < 0) y = p.y;
if(yalign > 0) y = p.y - h;
p("centerFlob "+p+" at "+x+" "+y+" "+w+" "+h+" align "+xalign+" "+yalign);
return getFlob(into, c, ftxt, x, y, depth, w, h);
}
}
// vim: set syntax=java :

253
Java/flob/FTextLayouter.zob Normal file
View File

@@ -0,0 +1,253 @@
/*
FTextLayouter.java
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A layouter for flowing formatted text in a fixed-width rectangle.
* @see FText
*/
public class FTextLayouter implements ZOb {
public static final String rcsid = "$Id: FTextLayouter.zob,v 1.10 2001/03/30 16:19:37 bfallenstein Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
public FTextLayouter() {}
public FTextLayouter(boolean firstCap) { this.firstCap = firstCap; }
STRUCTPARAMS {
/** Capitalize any letter after two spaces.
* This allows simple rearrangement of text without having
* to think about capitalization at all times by ending
* each sentence with the period/question/... and two spaces.
* XXX Maybe this shouldn't be here after all - maybe
* separate FText.Part firstcap completely from rendering
* to a separate call??
*/
boolean firstCap
= true;
}
/** (Internal convenience) Place a number of lines from an array,
* given first and last line.
*/
void placeLines(FlobSet into,
FText.Part[][] lines,
int[] heights,
Rectangle rect,
int first,
int last,
int depth,
boolean cursors,
Flob fparent) {
int y = rect.y, maxx = rect.x + rect.width;
p("FTextLayouter placeLines first "+first+" last "+last+" length "+lines.length);
Renderable prev = null;
for(int linenr=first; linenr<=last; linenr++) {
FText.Part[] line = lines[linenr];
int x = rect.x;
y += heights[linenr];
for(int partnr = 0; partnr<line.length; partnr++) {
FText.Part part = line[partnr];
int h = part.height(), w = part.width();
prev = part.rend(x, y-h, depth, prev);
if(prev instanceof SplitCellFlob1) {
SplitCellFlob1 cur = (SplitCellFlob1)prev;
if(cursors) addCurs(into, cur);
cur.fg = part.fg; // makes them depth-aware if part.fg is null
}
if(into!=null) {
if(prev instanceof Flob) {
Flob f = (Flob)prev;
if(fparent != null) f.setParent(fparent);
if(f.x + f.w > rect.x + rect.width) {
p("FTL clip: "+f.x+" "+f.w+" in "+rect.x+" "+rect.width+" at "+f.c);
f.w = rect.x + rect.width - f.x;
if(f instanceof SplitCellFlob1)
((SplitCellFlob1)f).doClip = true;
}
if(f.w < 0) f.w = 0;
}
into.add(prev);
}
x += w;
if(x > maxx) break;
}
}
}
/** (Internal convenience) Find the correct span of lines to layout.
* Returns an array with two ints: the last line number and the height.
*/
int[] layout(FText.Part[][] lines,
int[] heights,
int start,
int dir,
int maxh) {
int height = 0, i = start;
for(; i>=0 && i<lines.length; i+=dir) {
int lineh = FText.Part.height(lines[i]);
heights[i] = lineh;
if(height + lineh > maxh) return new int[] { i-dir, height };
height += lineh;
}
return new int[] { i-dir, height };
}
public Rectangle place(FlobSet into, FText txt, Rectangle rect,
int direction, int initY,
int middleoffs,
boolean cursors) {
return place(into, txt, rect, 100,
direction, initY, middleoffs, cursors, (Flob)null);
}
/** To be deprecated -- DON'T USE! */
public Rectangle place(FlobSet into, FText txt, Rectangle rect,
int direction, int initY,
int middleoffs,
boolean cursors,
boolean[] beginningSentence) {
return place(into, txt, rect, 100,
direction, initY, middleoffs, cursors, (Flob)null);
}
/** To be deprecated -- DON'T USE! */
public Rectangle place(FlobSet into, FText txt, Rectangle rect,
int depth,
int direction, int initY,
int middleoffs,
boolean cursors,
boolean[] beginningSentence) {
return place(into, txt, rect, depth,
direction, initY, middleoffs, cursors, (Flob)null);
}
public Rectangle place(FlobSet into, FText txt, Rectangle rect,
int depth,
int direction, int initY,
int middleoffs,
boolean cursors) {
return place(into, txt, rect, depth,
direction, initY, middleoffs, cursors, (Flob)null);
}
/** Place a piece of formatted text into a fixed-width rectangle.
* @param into The flobset to place the text into.
* @param txt The formatted text object
* @param rect The rectangle to fit things into. This is used for
* both stopping rendering at the upper and lower edges
* and for the margin widths.
* (XXX How to i18nize this for other directions?!?!)
* @param depth The depth at which to place the flobs.
* @param direction The direction we're moving.
* 0 = starting from the middle of a paragraph,
* 1 = down, -1 = up
* @param initY The y coordinate to place the middle/first/last line
* of text at, depending on direction.
* @param middleoffs If direction==0, the offset that should be at initY.
* @param cursors Whether to draw cursors.
* @param fparent The flob parent.
*/
public Rectangle place(FlobSet into, FText txt, Rectangle rect,
int depth,
int direction, int initY,
int middleoffs,
boolean cursors,
Flob fparent) {
if(firstCap) txt.capitalize();
FText.Part[][] lines = txt.getLines(rect.width);
if(lines.length == 0)
return new Rectangle(rect.x, initY, rect.width, 0);
/** The height of each line. */
int[] heights = new int[lines.length];
/** The first and last lines to place. */
int first, last;
Rectangle res;
if(direction < 0) {
last = lines.length-1;
int[] lay = layout(lines, heights, last, -1,
initY-rect.y);
first = lay[0]; last = lines.length-1;
res = new Rectangle(rect.x, initY-lay[1], rect.width, lay[1]);
} else if(direction > 0) {
first = 0;
int[] lay = layout(lines, heights, first, 1,
rect.y + rect.height - initY);
last = lay[0];
res = new Rectangle(rect.x, initY, rect.width, lay[1]);
} else {
int middle = FText.findLine(lines, middleoffs);
// Make it the middle of the middle line.
initY -= FText.Part.height(lines[middle])/2;
int[] lay1 = layout(lines, heights, middle-1, -1,
rect.y + rect.height - initY);
int[] lay2 = layout(lines, heights, middle, 1, initY-rect.y);
first = lay1[0]; last = lay2[0];
res = new Rectangle(rect.x, initY-lay1[1], rect.width,
lay1[1]+lay2[1]);
}
placeLines(into, lines, heights, res, first, last, depth,
cursors, fparent);
return res;
}
// XXX make more efficient: do cursor search only for parent sf
public static void addCurs(FlobSet into, SplitCellFlob1 sf) {
Enumeration e = ZZCursorReal.getPointers(sf.getCell());
while(e.hasMoreElements()) {
ZZCell c = (ZZCell)e.nextElement();
int ind = ZZCursorReal.getOffs(c);
if(ind == ZZCursorReal.NO_OFFSET) continue;
if(!(ind >= sf.start && ind <= sf.start + sf.n))
continue;
int x = sf.getStrX(ind);
if(x >= 0 && into != null)
into.add(new LineDecor(x, sf.y, x, sf.y+sf.h,
Color.black, sf.d));
}
}
}
// vim: set syntax=java :

202
Java/flob/Flob.java Normal file
View File

@@ -0,0 +1,202 @@
/*
Flob.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** An abstract class to represent a flob shown on screen.
* Flobs are constant read-only objects like Strings.
* <p>
* Flobs should be able to render themselves quickly for animations;
* caching relevant
* information in this structure is therefore a good idea.
* <p>
* The minimal flob implementation simply implements the
* render(Graphics, int, int, int, int, int) method.
*/
public abstract class Flob extends Renderable {
public static final String rcsid = "$Id: Flob.java,v 1.18 2001/03/17 23:08:23 bfallenstein Exp $";
public int x, y, w, h;
/** The identifier of the place this flob is.
* This is used to create a possibly hierarchical
* system so that animation doesn't confuse two
* instances of the same cell.
* deprecated Use setParent() / getParent().
*/
public String flobPath = "";
/** The cell associated with this flob.
* This may be set to null for things that are - well - just
* things rendered. But those should be in a minority always.
*/
public ZZCell c;
/** The flob we are interpolating with.
* Storing it here is a pure speed hack: in reality it'd belong in
* a hashtable somewhere. But this is crucial for the frame rate.
*/
protected Flob interpTo;
/** The parent of this flob.
* Only flobs with no parents and flobs whose parents are interpolated
* to each other are interpolated to each other.
* <p>
* set/get by setParent() / getParent()
*/
private Flob flobparent = null;
/** The applitude that has placed this flob.
* When the views of different applitudes are combined, this field is set
* by the combining view. When a flob is clicked upon, the field is read,
* the applitude is made the window's prefered applitude, and the mouse
* binding is executed according to the bindings of that applitude.
*/
public ZZCell applitude = null;
public void setParent(Flob p) {
flobparent = p;
flobPath = p.flobPath + "-" + p;
}
public Flob getParent() { return flobparent; }
/** Return true if a box should be drawn around this flob.
*/
public boolean needsBox() { return false; }
public Flob(int x, int y, int d, int w, int h, ZZCell c) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.d = d;
this.c = c;
}
/** Get a point aligned in a cell.
* getPoint(-1, 0) --> left/middle
* getPoint(1, 1) --> right/lower
* etc. -- middle means visual center (getCenter()).
*/
public Point getPoint(Point p, int xa, int ya) {
getCenter(p);
if(xa < 0) p.x = x;
if(xa > 0) p.x = x+w;
if(ya < 0) p.y = y;
if(ya > 0) p.y = y+h;
return p;
}
public Point getPoint(int xo, int yo) {
return getPoint(new Point(), xo, yo);
}
/** Get the visual center of this flob.
*/
public Point getCenter(Point p) {
p.x = x+w/2; p.y = y+h/2;
return p;
}
/** Get the visual center of this flob.
*/
public Point getCenter() {
return getCenter(new Point());
}
/** Render this flob at the given coordinates.
* Default: render nothing.
* You may override either this function or one or both of
* render(Graphics) and renderInterp(Graphics, float).
*/
public void render(Graphics g, int mx, int my, int md,
int mw, int mh) {
}
/** Render this flob.
* May be overridden; default implementation uses render(g, x, y, w, h, d);
*/
public void render(Graphics g) {
render(g, x, y, d, w, h);
}
/** Render an interpolated version of this flob.
* Default implementation uses render(g, x, y, w, h, d) with linearly
* interpolated coordinates.
*/
public void renderInterp(Graphics g, float fract) {
Flob r = interpTo;
if(r==null) return;
render(g,
(int)(x + fract*(r.x-x)),
(int)(y + fract*(r.y-y)),
(int)(d + fract*(r.d-d)),
(int)(w + fract*(r.w-w)),
(int)(h + fract*(r.h-h))
);
}
/** If there is a XOR-cursor associated with this flob,
* render it.
* This can be made to e.g. follow the mouse cursor to
* show where the click would land.
* Default implementation: do nothing, return
* <pre> hit(x,y)!=null </pre>
* @return Whether the coordinates hit this flob, i.e.
* whether the system should stop looking for the
* XOR curser.
*/
public boolean renderXOR(Graphics g, int x, int y) {
return hit(x,y) != null;
}
/** Whether it would make visually sense to interpolate
* this flob.
* Default implementation: whether the sum of the squares of
* the differences of the coordinates and widths is more than 100.
* Not a terribly useful measure but good enough.
*/
public boolean isInterpUseful() {
Flob r = interpTo;
if(r==null) return false;
return (r.x - x) * (r.x - x) +
(r.y - y) * (r.y - y) +
(r.w - w) * (r.w - w) +
(r.h - h) * (r.h - h) > 100;
}
/** Returns an object telling what was hit.
* Default implementation: returns null.
*/
public Object hit(int x, int y) { return null; }
/** A convenience routine to check whether a point
* is inside the defining rectangle.
* If the flob is (as many are) rectangular, this routine can
* be used to check the hit.
*/
public final boolean insideRect(int x0, int y0) {
return x0 >= x && y0 >= y && x0 < x+w && y0 < y+h;
}
}

View File

@@ -0,0 +1,39 @@
/*
FlobDecorator.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** An interface for classes that decorate FlobSets by drawing connections
* or so.
*/
public interface FlobDecorator {
String rcsid = "$Id: FlobDecorator.java,v 1.6 2000/10/26 18:09:29 tjl Exp $";
/** Add Renderables or Flobs to the given flobset,
* based on the flobs already in there.
*/
void decorate(FlobSet f, String path, ZZCell view);
}

View File

@@ -0,0 +1,89 @@
/*
RasterFlobFactory.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** An interface to generate flobs to put in a raster.
* This is for abstracting out what the cells look like.
* The "CellViews" in ZZDefaultSpace corresponds to classes
* implementing this interface.
*/
public interface FlobFactory {
String rcsid = "$Id$";
/** Get the default dimensions for the given cell and fraction.
* @param c The cell. If null, the default dimensions overall are returned.
* @param fract The magnification fraction.
*/
Dimension getSize(ZZCell c, float fract);
/** Create a 2-D flob.
* This call creates the flob and places it into the given FlobSet.
* @param c The cell for the flob
* @param handleCell The cell from which to show e.g. cursor.
* This mechanism may change.
*/
Flob makeFlob(FlobSet f,
ZZCell c, ZZCell handleCell,
float fract, int x, int y, int d, int w, int h);
/** Place a flob.
* Here, the size can vary freely: the flob is placed so that
* the point (x,y) is at (xfract, yfract) in the unit coordinate
* system stretched to fit inside. E.g. if (xfract, yfract)==(0,1)
* then (x,y) will be the lower left corner.
* The reason for this call is that it may be almost twice as fast
* as doing getSize() and makeFlob() since both may have to do some
* of the same calculations (e.g. line breaking).
* <p>
* This call should give the same results as
* <pre>
* Dimension d = getSize(c, fract);
* return makeFlob(c, fract,
* (int)(x-xfract*d.width),
* (int)(y-yfract*d.height),
* depth, d.width, d.height);
* </pre>
*/
Flob placeFlob(FlobSet f,
ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int depth,
float xfract, float yfract);
// should call centerFlob(..., null)
Flob centerFlob(FlobSet f,
ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign,
int depth);
// if d==null, use what getSize would return
Flob centerFlob(FlobSet f,
ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign,
int depth, Dimension d);
}

521
Java/flob/FlobSet.java Normal file
View File

@@ -0,0 +1,521 @@
/*
FlobSet.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A set of flobs, i.e.things that are rendered to screen associated
* with cells.
* Flobs are stored with depths, which are stably sorted in the end
* so that the flobs placed later are on top.
*/
public class FlobSet implements ZZScene {
public static final String rcsid = "$Id: FlobSet.java,v 1.41.2.1 2002/03/07 21:02:41 bfallenstein Exp $";
public static final boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
Dimension size;
public Dimension getSize() {
return size;
}
Color fg, bg;
Component cpt;
public SceneFlob sflob = null;
public BoxType box = new SimpleBoxType();
public FlobSet(Dimension size, Color foreground, Color background,
Component cpt) {
this.size = size;
this.bg = background;
this.fg = foreground;
this.cpt = cpt;
}
public Component getComponent() { return cpt; }
public Color getForeground() { return fg; }
public Color getBackground() { return bg; }
private Hashtable c2ph;
private Hashtable nph; // Hashtable for flobs w/o parents
private final Hashtable getPH(Flob parent) {
if(parent == null)
return nph;
Hashtable res = (Hashtable)c2ph.get(parent);
if(res == null)
c2ph.put(parent, res=new Hashtable());
return res;
}
private int nflobs;
private Flob[] flobs = new Flob[30];
boolean fsorted = false;
boolean ftagged = false;
private int nrend;
/** Decorations.
*/
private Renderable[] rends = new Renderable[10];
boolean rsorted = false;
private int maxdepth = 0;
public void add(Renderable r) {
// Check: if it happens to be a flob, then put
// it as a flob.
if(r instanceof Flob) {
add((Flob)r);
return;
}
if(r.d > maxdepth) maxdepth = r.d;
if(nrend >= rends.length) {
Renderable[] n = new Renderable[nrend + 50];
System.arraycopy(rends, 0, n, 0, nrend);
rends = n;
}
rends[nrend++] = r;
rsorted = false;
}
/** Add a flob into the flobset.
* Note that flobPath might not be set yet.
* It is therefore used only when the flobs are being sorted.
*/
public void add(Flob f) {
// p("AddFlob "+f.x+" "+f.y+" "+f.w+" "+f.h+" "+f.d);
if(f.d <= 0)
throw new ZZError("Negative or zero depth for flob!");
if(f.d > maxdepth) maxdepth = f.d;
// if(f.c != null)
// getPH(f.flobPath).put(f.c, f);
if(nflobs >= flobs.length) {
Flob[] n = new Flob[nflobs + 100];
System.arraycopy(flobs, 0, n, 0, nflobs);
flobs = n;
}
flobs[nflobs++] = f;
fsorted = false;
ftagged = false;
if(sflob != null && f instanceof SceneFlob)
((SceneFlob)f).parent = sflob;
}
public final void tag() {
if(ftagged) return;
c2ph = new Hashtable(); nph = new Hashtable();
for(int i=0; i<nflobs; i++) {
Flob f = flobs[i];
if(f.c != null) {
Hashtable h = getPH(f.getParent());
Object o = h.get(f.c);
if(o == null) {
h.put(f.c, f);
} else if(o instanceof Flob) {
Vector v = new Vector();
v.addElement(o);
v.addElement(f);
h.put(f.c, v);
} else {
((Vector)o).addElement(f);
}
}
}
ftagged = true;
}
public final void sort() { sortf(); sortr(); }
public final void sortf() {
if(fsorted) return;
// pa("SORTING");
// dump();
Renderable.depthSort(flobs, nflobs);
fsorted = true;
// dump();
}
public final void sortr() {
if(rsorted) return;
Renderable.depthSort(rends, nrend);
rsorted = true;
}
protected void depthColor(Graphics g, int depth) {
// XXX Foreground adjustable?
if(depth > maxdepth)
throw new ZZError("Too strange. "+depth+" "+maxdepth);
int fract = (256*(depth-1)) / (maxdepth + maxdepth / 10);
Color ncol = ZZUtil.mix(fg, bg, fract);
g.setColor(ncol);
// p("Color: "+fract+" "+d+" "+maxdepth+" "+ncol);
}
public void render(Graphics g) {
render(g, g);
}
public void render(Graphics g, Graphics orig) {
// ZZDrawing.instance.setAlpha(g, (float)0.5);
ZZDrawing.instance.setDefaults(g);
ZZDrawing.instance.setQuality(g);
int f=nflobs-1;
int r=nrend-1;
int oldd = -1;
sort();
// p("StartColors");
while(f >= 0 || r >= 0) {
// Stagger the two arrays. Always render decorations of the same
// depth last
while(f >= 0 &&
( r < 0 || rends[r].d <= flobs[f].d)) {
if(flobs[f].d != oldd)
depthColor(g, oldd = flobs[f].d);
if(!flobs[f].needsBox())
flobs[f--].render(g, orig);
else {
Flob fl = flobs[f--];
box.renderBg(g, fl);
fl.render(g, orig);
box.renderFrame(g, fl);
}
}
while(r >= 0 &&
( f < 0 || rends[r].d > flobs[f].d)) {
if(rends[r].d != oldd)
depthColor(g, oldd = rends[r].d);
rends[r--].render(g, orig);
}
}
renderDC(g);
}
FlobSet interpPrepared = null;
public void renderInterp(Graphics g, ZZScene other0,
float fract) {
ZZDrawing.instance.setDefaults(g);
sort();
FlobSet other = (FlobSet)other0;
if(interpPrepared != other) {
prepareInterp(other);
}
renderInterp(g, fract);
}
public void renderInterp(Graphics g, float fract) {
int oldd = -1;
for(int i=nflobs-1; i>=0; i--) {
if(flobs[i].d != oldd)
depthColor(g, oldd = flobs[i].d);
if(flobs[i].interpTo == null || !flobs[i].needsBox())
flobs[i].renderInterp(g, fract);
else {
// XXX the interpolation path isn't necessarily linear!
box.renderBg(g, flobs[i], fract);
flobs[i].renderInterp(g, fract);
box.renderFrame(g, flobs[i], fract);
}
}
}
public boolean isInterpUseful(ZZScene other0) {
FlobSet other = (FlobSet)other0;
return prepareInterp(other);
}
/** Find flobs for this parent and cell.
* @returns null if no flobs are found (empty array would be inefficient)
*/
public Flob[] findFlobs(Flob parent, ZZCell c) {
tag();
Hashtable hash = getPH(parent);
Object o = hash.get(c);
if(o == null) return null;
else if(o instanceof Flob) return new Flob[] { (Flob)o };
else if(o instanceof Flob[]) return (Flob[])o;
// Now, we have a Vector. Convert to array.
Vector v = (Vector)o;
Flob[] res = new Flob[v.size()];
for(int i=0; i<res.length; i++) res[i] = (Flob)v.elementAt(i);
// tag() only puts Vectors. Now put the converted array.
hash.put(c, res);
return res;
}
/** True if from's center is nearer to test's than other's. */
static boolean isNearer(Flob from, Flob test, Flob other) {
int fx = from.x + from.w/2, fy = from.y + from.h/2;
int tx = test.x + test.w/2, ty = test.y + test.h/2;
int ox = other.x + other.w/2, oy = other.y + other.h/2;
return ((fx-tx)*(fx-tx) + (fy-ty)*(fy-ty))
< ((fx-ox)*(fx-ox) + (fy-oy)*(fy-oy));
}
/** Find the flob in this flobset which is nearest to a flob in another
* flobset -- i.e., f is supposed NOT to be in this flobset. Distances
* are measured center to center.
* @param f The flob to search from -- should NOT be in this set.
* @param parent The parent of the flob to find -- must be in THIS set.
*/
public Flob findNearest(Flob f, Flob parent) {
Flob[] flobs = findFlobs(parent, f.c);
if(flobs == null) return null;
Flob result = null;
for(int i=0; i<flobs.length; i++) {
Flob g = flobs[i];
if(result == null || isNearer(f, g, result))
result = g;
}
if(result != null) return result;
else return null;
}
/** For compatibility
* deprecated Use findFlobs, findNearest or something.
*/
public Flob findFlob(String path, ZZCell c) {
Flob[] flobs = findFlobs(null, c);
if(flobs == null) return null;
for(int i=0; i<flobs.length; i++)
if(flobs[i].flobPath.equals(path))
return flobs[i];
return null;
}
/** Prepare for interpolation
* with another flobset. Usually
* used only internally.
*/
boolean prepareInterp(FlobSet f2) {
if(interpPrepared == f2) return true;
// p("Flobset: prepareInterp "+this+" "+f2);
boolean useful = false;
for(int i=0; i<f2.nflobs; i++)
f2.flobs[i].interpTo = null;
// First set to null -- avoid animation errors
for(int i=0; i<nflobs; i++) flobs[i].interpTo = null;
for(int iter=0; iter<5; iter++) {
for(int i=0; i<nflobs; i++) {
if(flobs[i].c == null) continue;
Flob parent = flobs[i].getParent();
Flob f = f2.findNearest(flobs[i],
parent != null ? parent.interpTo : null);
if(f==null ||
(f.interpTo != null && isNearer(f, f.interpTo, flobs[i])) ||
(parent != null && parent.interpTo == null)) continue;
flobs[i].interpTo = f;
f.interpTo = flobs[i];
useful = (useful || flobs[i].isInterpUseful());
}
}
f2.interpPrepared = this;
interpPrepared = f2;
return useful;
}
/** Prepare for interpolation with another flobset,
* but only moving given flobs.
* Used to effect level-of-detail for SceneFlobs.
* Note that this also only modifies the current flobset
* and gives the current flobset the pointers...
*/
public void prepareInterp(FlobSet f2, Flob[] which) {
// p("Flobset: prepareInterp LIMITED "+this+" "+f2+" "+which);
interpPrepared = f2;
for(int i=0; i<nflobs; i++) flobs[i].interpTo = null;
for(int i=0; i<which.length; i++) {
if(which[i].c == null) continue;
// Parents not used here...
Flob f = f2.findNearest(which[i], null);
if(f==null) continue;
which[i].interpTo = f;
}
}
public Object getObjectAt(int x, int y) {
return getObjectAt(x, y, null);
}
public Object getObjectAt(int x, int y, Flob[] fres) {
sortf();
for(int i=0; i<nflobs; i++) {
Object o = flobs[i].hit(x, y);
if(o != null) {
if(fres != null) fres[0] = flobs[i];
return o;
}
}
return null;
}
public void renderXOR(Graphics g, int x, int y) {
Flob[] which = new Flob[1];
Object co = getObjectAt(x, y, which);
if(co == null) return;
which[0].renderXOR(g, x, y);
}
public void dump() {
pa("FlobSet dump: "+nflobs+" "+nrend);
for(int i=0; i<flobs.length; i++) {
if(flobs[i] == null) {
pa(" Flob null!");
continue;
}
pa(" Flob "+flobs[i].x+" "+flobs[i].y+" "+
flobs[i].w+" "+flobs[i].h+" "+flobs[i].d+" "+flobs[i]);
}
for(int i=0; i<rends.length; i++) {
if(rends[i] == null) {
pa(" Renderable null!");
continue;
}
pa(" Renderable "+ rends[i].d+" "+rends[i]);
}
}
/** A callback interface for iterating over the Flobs
* in a FlobSet in depth order.
*/
public static abstract class DepthIter {
public void act(Flob[] flobs, int start, int n) {}
/* @param in The scene flob all these flobs are in. */
public void act(Flob[] flobs, int start, int n, SceneFlob in) {
act(flobs, start, n);
}
}
/** Iterate a routine over blocks of same-depth flobs.
* @param flat Whether to include flobs inside SceneFlobs.
*/
public void iterDepth(DepthIter di, boolean frontFirst, boolean flat) {
if(nflobs <= 0) return;
if(flobs == null) throw new Error("NULL FLOBS");
if(flobs[0] == null) throw new Error("NULL FIRST FLOB");
sortf();
if(flobs == null) throw new Error("NULL FLOBS AFTER SORT");
if(flobs[0] == null) throw new Error("NULL FIRST FLOB AFTER SORT");
if(frontFirst) {
int cur = 0; int curd = flobs[0].d;
for(int i=0; i<nflobs; i++) {
if(flat && flobs[i] instanceof SceneFlob) {
di.act(flobs, cur, i-cur, sflob);
((SceneFlob)flobs[i]).getFlobSet().iterDepth(di, true, true);
cur = i; curd = flobs[i].d;
} else if(curd != flobs[i].d ) {
di.act(flobs, cur, i-cur, sflob);
cur = i;
curd = flobs[i].d;
}
}
di.act(flobs, cur, nflobs-cur);
} else {
int cur = nflobs-1; int curd = flobs[nflobs-1].d;
for(int i=nflobs-1; i>=0; i--) {
if(flat && flobs[i] instanceof SceneFlob) {
di.act(flobs, i+1, cur-i, sflob);
((SceneFlob)flobs[i]).getFlobSet().iterDepth(di, true, true);
cur = i; curd = flobs[i].d;
} if(curd != flobs[i].d) {
di.act(flobs, i+1, cur-i, sflob);
cur = i;
curd = flobs[i].d;
}
}
di.act(flobs, 0, cur+1);
}
}
/** Iterate a routine over blocks of same-depth flobs.
* Does not include flobs inside SceneFlobs.
*/
public void iterDepth(DepthIter di, boolean frontFirst) {
iterDepth(di, frontFirst, false);
}
DragCursor dc; int dcx, dcy;
public void setDragCursor(DragCursor dc, int x, int y) {
this.dc = dc; this.dcx = x; this.dcy = y;
}
public interface DragCursor {
boolean accept(Object o);
}
/** Render the current dragCursor.
*/
private void renderDC(Graphics g) {
if(dc == null) return;
Flob[] which = new Flob[1];
Object co = getObjectAt(dcx, dcy, which);
if(co == null) return;
if(!dc.accept(co)) return;
which[0].renderXOR(g, dcx, dcy);
}
public int fetch(FlobSet from, int x, int y, int d) {
return fetch(from, x, y, d, null);
}
/** Fetch the contents of another FlobSet and translate coordinates.
* Takes all flobs and rends, adds x, y and do to their coordinates,
* and puts them in this set. This is used to combine views.
* @param Whenever a flob's applitude field contains null, it is set
* to this value (which may be null in itself).
* @returns The highest depth used (or d, if there weren't any flobs).
*/
public int fetch(FlobSet from, int x, int y, int d, ZZCell applitude) {
int res = d;
for(int i=0; i<from.nflobs; i++) {
Flob f = from.flobs[i];
f.x += x; f.y += y; f.d += d;
if(f.d > res) res = f.d;
if(f.applitude == null) f.applitude = applitude;
add(f);
}
for(int i=0; i<from.nrend; i++) {
Renderable r = from.rends[i];
if(!r.translate(x, y)) continue;
r.d += d;
if(r.d > res) res = r.d;
add(r);
}
return res;
}
/** Get a new FlobSet like this, just with a different size.
* Used to combine views.
*/
public FlobSet create(Dimension size) {
return new FlobSet(size, fg, bg, cpt);
}
}

57
Java/flob/FlobView.java Normal file
View File

@@ -0,0 +1,57 @@
/*
FlobRaster.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
/** A fairly general interface for drawing a structure
* on the screen using flobs.
* The parameters have been read through the ZOb interface so
* we don't need to worry about those here.
*/
public interface FlobView {
String rcsid = "$Id$";
/** Draw a representation of the structure into the FlobSet.
* An implementation of this routine will usually place a number
* of Flobs and Renderables into
* The parameters dims and accursed are redundant but since they
* are used so often, it's just good to have them.
* @param into The FlobSet to place the flobs and decorations into.
* @param fact A factory for constructing flobs. This may be used
* or ignored by the FlobRaster. In general, it should
* be used to draw the "run-of-the-mill" flobs.
* @param view The viewspecs cell in the structure.
* @param dims Three first dims
* @param accursed The cell that the cursor is on
* @see Flob
* @see Renderable
* @see FlobSet
* @see RasterFlobFactory
*/
void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed);
}

51
Java/flob/GridGeom.java Normal file
View File

@@ -0,0 +1,51 @@
/*
GridGeom.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
/** An object that describes the geometry of a rectangular grid.
* The grid is assumed to have a center cell i.e. to have an odd
* number of cells.
*/
public abstract class GridGeom {
String rcsid = "$Id: GridGeom.java,v 1.1 2000/10/21 23:07:35 tjl Exp $";
/** Initialize the sizes of this grid.
* @param normalcell The size of a "normal" cell.
* @param canvas The size of the whole rectangle this grid is placed
* into
* @return the number of cells in the grid in X and Y directions.
*/
public abstract Dimension setSizes(Dimension normalcell, Dimension canvas);
/** Returns the rectangle corresponding to the given cell.
*/
public final Rectangle getCell(int x, int y) {
return getCell(x, y, new Rectangle());
}
/** Returns the rectangle corresponding to the given cell,
* placed into the given Rectangle object.
*/
public abstract Rectangle getCell(int x, int y, Rectangle rect);
}
// vim: set syntax=java :

71
Java/flob/ICView.zob Normal file
View File

@@ -0,0 +1,71 @@
/*
ICView.zob
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
/** An integrated-circuit view. Currently we show only
* dimensions.
*/
public class ICView implements FlobView, ZOb {
public static final String rcsid = "$Id: ICView.zob,v 1.3 2000/11/07 12:38:27 ajk Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
}
public void raster(FlobSet into, FlobFactory fact, ZZCell view,
String[]vds, ZZCell accursed) {
Dimension d = into.getSize();
Dimension c = fact.getSize(null, 1);
int cw = c.width;
int ch = c.height;
ZZCell dimhead = ZZCursorReal.get(view.s("d.dims")).h("d.2");
fact.makeFlob(into, accursed, accursed, 1,
(d.width-cw) / 2, 0, 1, cw, ch);
int cury = ch+2;
p("ic loop");
for(ZZCell cur = dimhead; cur != null; ) {
if(accursed.s(cur.t()) != null ||
accursed.s(cur.t(),-1) != null) {
fact.makeFlob(into, cur, cur, 1, (d.width-cw) / 2,
cury, 1, cw, ch);
cury += ch+2;
}
cur = cur.s("d.2");
if(cur == dimhead) break;
p("ic "+cur);
}
p("Out of ic");
}
}
// vim: set syntax=java :

View File

@@ -0,0 +1,98 @@
/*
IdiosyncraticFlobFactory.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A flob factory that shows each cell with its own view, if
* desired.
* The view should be connected negwards of the cell on
* <code>d.cellview</code>, as a FlobFactory (CellView) ZOb.
*/
public class IdiosyncraticFlobFactory implements FlobFactory, ZOb {
public static final String rcsid = "$Id: IdiosyncraticFlobFactory.zob,v 1.5 2001/03/18 10:38:26 bfallenstein Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
STRUCTPARAMS {
ZOb def
= null;
}
public FlobFactory getIdiosyncraticCellView(ZZCell c) {
ZZCell h = c.getRootclone().h("d.cellview", true);
if(h == null) return null;
// XXX We *WILL* need a cache of ZObs...
return (FlobFactory)ZZDefaultSpace.readZOb(h);
}
/** Get the idiosyncratic or default cell view.
* Never returns null.
*/
public FlobFactory getCellView(ZZCell c) {
FlobFactory cv = getIdiosyncraticCellView(c);
if(cv == null) cv = (FlobFactory)def;
if(cv == null)
throw new ZZError("No default view!");
return cv;
}
public Dimension getSize(ZZCell c, float fract) {
if(c == null)
return ((FlobFactory)def).getSize(null, fract);
return getCellView(c).getSize(c, fract);
}
public Flob makeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int d, int w, int h) {
return getCellView(c).makeFlob(into, c, handleCell,
fract, x, y, d, w, h);
}
public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int depth,
float xfract, float yfract) {
return getCellView(c).placeFlob(into, c, handleCell,
fract, x, y, depth, xfract, yfract);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign,
int depth, Dimension d) {
return getCellView(c).centerFlob(into, c, handleCell, fract, p,
xalign, yalign, depth, d);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign, int depth) {
return getCellView(c).centerFlob(into, c, handleCell, fract, p,
xalign, yalign, depth);
}
}
// vim: set syntax=java :

193
Java/flob/Level.java Normal file
View File

@@ -0,0 +1,193 @@
/*
Level.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag.module;
import org.gzigzag.*;
import java.awt.*;
/** Primitive actions for use with LevelRaster.
* XXX join with LevelRaster?
*/
public class Level {
public static final String rcsid = "$Id: Level.java,v 1.6 2000/11/07 12:38:27 ajk Exp $";
public static boolean dbg = false;
static void p(String s) { if(dbg) System.out.println(s); }
static void pa(String s) { System.out.println(s); }
// A "direction" in the ZZ space
static class DimVector {
String dim;
int dir;
DimVector rev; // The reverse vector
DimVector(String dim, int dir) {
this.dim = dim; this.dir = dir; rev = new DimVector(this);
}
DimVector(DimVector rev) { dim=rev.dim; dir=-rev.dir; this.rev=rev; }
ZZCell get(ZZCell c) { return c.s(dim, dir); }
ZZCell end(ZZCell c) { return c.h(dim, dir); }
ZZCell end(ZZCell c, boolean ensuremove) {
return c.h(dim, dir, ensuremove);
}
ZZCell create(ZZCell c) { return c.N(dim, dir); }
ZZCell[] rank(ZZCell c, boolean includeThis) {
return c.readRank(dim, dir, includeThis);
}
}
/** A set of dimension vectors: linkdim, targetdim and tunneldim.
*/
static class DimSet {
DimVector linkdim;
DimVector targetdim;
DimVector tunneldim;
DimSet rev;
DimSet(String dims[]) {
linkdim = new DimVector(dims[0], 1);
targetdim = new DimVector(dims[1], 1);
tunneldim = new DimVector(dims[2], 1);
rev = new DimSet(this);
}
DimSet(DimSet rev) {
linkdim = rev.targetdim.rev;
targetdim = rev.linkdim.rev;
tunneldim = rev.tunneldim.rev;
this.rev = rev;
}
DimSet(ZZCell viewc) {
ZZCell[] dimcurs = viewc.readRank("d.dims", 1, false);
linkdim = new DimVector(
ZZCursorReal.get(dimcurs[0]).getText(), 1);
targetdim = new DimVector(
ZZCursorReal.get(dimcurs[1]).getText(), 1);
tunneldim = new DimVector(
ZZCursorReal.get(dimcurs[2]).getText(), 1);
rev = new DimSet(this);
}
boolean islink(ZZCell c) {
return targetdim.get(c) != null || rev.targetdim.get(c) != null;
}
}
static class Performer {
ZZCell viewc, c;
DimSet ds;
boolean lnk;
String act;
Performer(ZZCell viewc) {
this.viewc = viewc; c = ZZCursorReal.get(viewc);
ds = new DimSet(viewc);
lnk = ds.islink(c);
// XXX why doesn't this work:
// act = ZZDefaultSpace.getDirActionWaitingAndClear(viewc);
ZZCell nac = ZZDefaultSpace
.findOnClientlist(c.getSpace(), "NextAction", true);
nac = nac.getOrNewCell("d.1", 1, null);
act = nac.getText();
nac.setText("");
}
public void perf(ZZCell to, DimVector dim) { perf(to, dim, c); }
public void perf(ZZCell to, DimVector dim, ZZCell from) {
// XXX Extend to HOP and NEW!
// HOP just uses dim; NEW needs to check if link AFTER INSERT
if(act.equals(""))
ZZCursorReal.set(viewc, to);
else if(act.equals("HOP")) {
if(!lnk || dim == null) return;
to.insert(dim.dim, dim.dir, from);
} else if(act.equals("NEW")) {
if(dim == null) return;
ZZCell nc = dim.create(from);
if(ds.islink(nc)) {
if(ds.targetdim.get(nc) == null) ds.targetdim.create(nc);
else ds.rev.targetdim.create(nc);
}
} else
System.out.println("Level module can't do "+act);
}
public void dir(int d, int b) {
DimSet ds = d < 0 ? this.ds.rev : this.ds;
ZZCell to;
if(lnk) {
if(b == 0) { perf(ds.targetdim.end(c), null); return; }
else if(b < 0) {
to = ds.targetdim.get(c);
if(to != null && ds.targetdim.get(to) != null)
perf(to, ds.targetdim);
} else {
to = ds.targetdim.rev.get(c);
if(to != null) perf(to, ds.targetdim.rev);
}
} else {
if(b < 0) {
perf(ds.linkdim.get(c), ds.linkdim);
} else if(b == 0) {
to = ds.tunneldim.get(c);
ZZCell[] rnk = ds.linkdim.rank(c, false);
if(to == null && rnk.length > 0)
to = rnk[rnk.length / 2];
perf(to, ds.tunneldim);
} else {
to = ds.linkdim.end(c);
perf(to, ds.linkdim, to);
}
}
}
}
static public ZZModule module = new ZZModule() {
public void action(String id,
ZZCell code,
ZZCell target,
ZZView view, ZZView cview, String key, Point pt, ZZScene xi) {
Performer p = new Performer(view.getViewcell());
if(id.equals("UpLeft")) p.dir(-1, -1);
else if(id.equals("Up")) p.dir(-1, 0);
else if(id.equals("UpRight")) p.dir(-1, 1);
else if(id.equals("DownLeft")) p.dir(1, -1);
else if(id.equals("Down")) p.dir(1, 0);
else if(id.equals("DownRight")) p.dir(1, 1);
else System.out.println("Level module: Unknown code '"+id+"'");
}
public ZOb newZOb(String id) {
if(id.equals("Raster")) return new LevelView();
return null;
}
};
}

492
Java/flob/LevelView.zob Normal file
View File

@@ -0,0 +1,492 @@
/*
LevelRaster.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag;
import java.awt.*;
import java.util.*;
/** A raster for multiple-level structures.
* Interprets two dimensions as many-to-many relationship. Also interprets
* third dimension as one-to-one relationships which are shown the same way
* as the many-to-many relationships. For many-to-many relationships with
* link cells, shows the link cells.
*/
/* Some XXX'es:
- fix the damn occupiedbreadth bug!!!
- should move the parentlinks in the right place
- primitive actions for leveled visualization (including move)
- loose linking so that new links can be created? or: new link creates
new target, too? or maybe: in loose mode, links w/o target are shown as
that, links w/o target? yeah, way to go. (anyways, should new link also
create new target or not? pbly yes, eh?)
- gaps that shrink; think depthwise gapping through again
*/
public class LevelView implements FlobView, ZOb {
public static final String rcsid = "$Id$";
public static boolean dbg = false ;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** The size factor applied to cells. */
float initmul
= (float)1.6;
/** How many recursion levels shall we render (on both sides of the
* root)? */
int maxdepth
= 4;
/** The breadth distance between neigbouring cells. */
int bgap
= 15;
/** The depth distance between a cell and a link */
int dgap
= 10;
/** The factor of enlargement of cells as they move away
depthwise from the accursed cell. Element 0 is
horizontal, element 1 is vertical. */
float shrink
= (float)0.7;
/** The enlargement factor applied to link cells. Think linkshrink! */
float linkshrink
= (float)0.25;
/** Should the tree be shown "depthhorizontal", ie. depth rightwards? */
boolean depthhorizontal
= false;
/** Should the headcell be used on both dimensions?
* Normally on target dim, tailcell is used. */
boolean bothhead
= false;
/** Are links without targets interpreted as targets?
* If two elements are given, the first is used for upstream- and the
* second for downstream connections. */
boolean[] loose // 1..2
= new boolean[] { false, false };
}
INITIALIZE {
if(loose.length == 1)
loose = new boolean[] { loose[0], loose[0] };
}
DimVector[] dims;
Coordinates treegap; // gap converted to a Coordinates instance
Coordinates linkgap; // same with linkshrink applied
Coordinates[] cellsizes;
boolean looseup, loosedown; // XXX ???
// A "direction" in the ZZ space
static class DimVector {
String dim;
int dir;
DimVector rev; // The reverse vector
DimVector(String dim, int dir) {
this.dim = dim; this.dir = dir; rev = new DimVector(this);
}
DimVector(DimVector rev) { dim=rev.dim; dir=-rev.dir; this.rev=rev; }
ZZCell get(ZZCell c) { return c.s(dim, dir); }
ZZCell end(ZZCell c) { return c.h(dim, dir); }
ZZCell end(ZZCell c, boolean ensuremove) {
return c.h(dim, dir, ensuremove);
}
ZZCell[] rank(ZZCell c, boolean includeThis) {
return c.readRank(dim, dir, includeThis);
}
}
class Coordinates {
public int breadth;
public int depth;
public int x() { return depthhorizontal ? depth : breadth; }
public int y() { return depthhorizontal ? breadth : depth; }
public void set(int setx, int sety) {
if(depthhorizontal) {
depth = setx; breadth = sety;
} else {
breadth = setx; depth = sety;
}
}
Coordinates(Dimension d) { set(d.width, d.height); }
Coordinates(int b, int d) { breadth = b; depth = d; }
Coordinates(int i, int j, boolean treecoords) {
if(treecoords) { breadth = i; depth = j; }
else set(i, j);
}
Coordinates(Coordinates c, float fract) {
breadth = (int) (c.breadth * fract);
depth = (int) (c.depth * fract);
}
}
DimVector[] directeddims(boolean upwards) {
return new DimVector[] {
upwards ? dims[1].rev : dims[0],
upwards ? dims[0].rev : dims[1],
upwards ? dims[2].rev : dims[2]
};
}
// STEP 1: Tree generation. This may be overridden
// Note that "children" are cells away from root, and "parents" are
// cells towards root. Only the links to the parents are drawn.
CellInfo connectCell(ZZCell c, ZZCell linkc, ZZCell parentc,
int steps, boolean upwards) {
CellInfo r = new CellInfo(c, linkc, parentc, steps, upwards);
boolean more = steps < maxdepth - 1;
DimVector[] ds = directeddims(upwards);
DimVector linkdim = ds[0];
DimVector targetdim = ds[1];
DimVector tunneldim = ds[2];
ZZCell target, parent;
if((target=tunneldim.get(c)) != null && more)
r.childinfo.addElement(connectCell(target, null, c,
steps+1, upwards));
if((parent=tunneldim.rev.get(c)) != null)
r.parentlinks.addElement(parent);
ZZCell[] links = linkdim.rank(c, true);
for(int i=0; more && i<links.length; i++) {
target = targetdim.end(links[i], !loose[upwards ? 0 : 1]);
if(target == null) continue;
if(target == links[i])
r.childinfo.addElement(connectCell(target, null, c,
steps+1, upwards));
else
r.childinfo.addElement(connectCell(target, links[i], c,
steps+1, upwards));
}
if((parent=linkdim.rev.end(c)) != null && parent != c)
r.parentlinks.addElement(parent);
ZZCell[] parentlinks = targetdim.rev.rank(c, false);
for(int i=0; i<parentlinks.length; i++)
if(loose[upwards?1:0] || linkdim.rev.get(parentlinks[i]) != null)
r.parentlinks.addElement(parentlinks[i]);
return r;
}
class CellInfo {
// Stuff set in step 1 (tree generation)
ZZCell c, linkc, parentc; // Linkcell CAN be null
Vector childinfo = new Vector();
Vector parentlinks = new Vector(); // can include linkless parents
int steps; // from root
boolean upwards;
// Stuff set in step 2 (size & breadth computing)
Coordinates size;
int occupiedbreadth = 0;
CellInfo(ZZCell c, ZZCell linkc, ZZCell parentc, int steps,
boolean upwards) {
this.c = c; this.linkc = linkc; this.parentc = parentc;
this.steps = steps; this.upwards = upwards;
}
// STEP 2: Compute the size of cell and breadth of tree part
public int computesize() {
size = cellsizes[steps];
for(Enumeration e = childinfo.elements(); e.hasMoreElements();)
occupiedbreadth += ((CellInfo) e.nextElement()).computesize()
+ treegap.breadth;
if(occupiedbreadth < size.breadth)
occupiedbreadth = size.breadth;
return occupiedbreadth;
}
// STEP 3: Put the cell and its parentlinks into a continuum
public void putall(Continuum co, int bstart, int dstart) {
int bcoord=bstart, dcoord=dstart;
if(upwards) dcoord -= size.depth;
Coordinates pos = new Coordinates(
bcoord + occupiedbreadth/2 - size.breadth/2,
dcoord);
boolean newlypositioned = co.put(c, pos, size, steps, false);
if(parentc != null) {
if(upwards) co.putlink(c, linkc, parentc);
else co.putlink(parentc, linkc, c);
}
if(!newlypositioned && parentc != null) return;
int childdcoord = dcoord + treegap.depth * (upwards ? -1 : 1);
if(!upwards) childdcoord += size.depth;
bcoord += treegap.breadth / 2;
for(Enumeration e = childinfo.elements(); e.hasMoreElements();) {
CellInfo ci = (CellInfo)e.nextElement();
ci.putall(co, bcoord, childdcoord);
bcoord += ci.occupiedbreadth + treegap.breadth;
}
if(parentc == null) return;
int bmiddle = pos.breadth + size.breadth/2;
Coordinates linksize = new Coordinates(size, linkshrink);
int plnkbreadth = linkgap.breadth + linksize.breadth;
bcoord = bmiddle - (int)(plnkbreadth * parentlinks.size() / 2);
bcoord += linkgap.breadth / 2;
dcoord += linkgap.depth * (upwards ? 1 : -2);
dcoord += size.depth * (upwards ? 1 : 0);
for(Enumeration e = parentlinks.elements(); e.hasMoreElements();) {
Coordinates lpos = new Coordinates(bcoord, dcoord);
ZZCell plinkc = (ZZCell)e.nextElement();
if(co.put(plinkc, lpos, linksize, steps, true))
co.putsmalllink(c, plinkc, upwards);
bcoord += linksize.breadth + linkgap.breadth;
}
}
}
class Continuum {
class Link { ZZCell fromc, linkc, toc; }
// Information used for rastering
Hashtable posns = new Hashtable(); // POSitionNS
Hashtable sizes = new Hashtable();
Hashtable depths = new Hashtable();
Vector links = new Vector();
Hashtable linksmalls = new Hashtable();
// Information used only while generating the continuum
Hashtable smalls = new Hashtable();
Hashtable linkbigs = new Hashtable();
Coordinates getpos(ZZCell c) { return (Coordinates)posns.get(c); }
Coordinates getsize(ZZCell c) { return (Coordinates)sizes.get(c); }
int getdepth(ZZCell c) { return ((Integer)depths.get(c)).intValue(); }
// Return false if the cell has already been positioned
public boolean put(ZZCell c, Coordinates pos, Coordinates size,
int steps, boolean small) {
if(posns.containsKey(c) && (small || !smalls.containsKey(c)))
return false;
posns.put(c, pos);
sizes.put(c, size);
depths.put(c, new Integer(steps+1));
if(small) smalls.put(c, c);
return true;
}
public void putsmalllink(ZZCell fromc, ZZCell linkc, boolean up) {
if(linkbigs.containsKey(linkc)) return;
Link link = new Link(); link.linkc = linkc;
if(up) { link.fromc = fromc; link.toc = linkc; }
else { link.fromc = linkc; link.toc = fromc; }
linksmalls.put(linkc, link);
}
public void putlink(ZZCell fromc, ZZCell linkc, ZZCell toc) {
Link link = new Link();
link.fromc = fromc; link.linkc = linkc; link.toc = toc;
links.addElement(link);
if(linkc != null && linksmalls.containsKey(linkc))
linksmalls.remove(linkc);
if(linkc != null) linkbigs.put(linkc, link);
}
// STEP 4: Position link cells
public void positionlinkcells() {
for(Enumeration e = links.elements(); e.hasMoreElements();) {
Link link = (Link)e.nextElement();
if(link.linkc == null) continue; // only draw a line
int fdepth = getdepth(link.fromc);
int tdepth = getdepth(link.toc);
int depth = fdepth > tdepth ? fdepth : tdepth;
Coordinates size = new Coordinates(cellsizes[depth-1],
linkshrink);
Coordinates fpos = getpos(link.fromc);
Coordinates fsize = getsize(link.fromc);
Coordinates tpos = getpos(link.toc);
Coordinates tsize = getsize(link.toc);
Coordinates pos = new Coordinates(
(fpos.breadth + (fsize.breadth/2) +
tpos.breadth + (tsize.breadth/2) - size.breadth) / 2,
(fpos.depth + fsize.depth + tpos.depth - size.depth) / 2);
boolean succ = put(link.linkc, pos, size, depth, false);
p((succ ? "S" : "Uns")+"uccessfully positioned link cell: "+
link.linkc.getText());
}
}
// STEP 5: Raster the continuum into a flob set
public void raster(FlobSet into, FlobFactory fact, ZZCell view) {
for(Enumeration e = posns.keys(); e.hasMoreElements();) {
ZZCell c = (ZZCell)e.nextElement();
Coordinates pos = getpos(c);
Coordinates size = getsize(c);
int depth = getdepth(c);
fact.makeFlob(into, c, c, 1, pos.x(), pos.y(), depth,
size.x(), size.y());
}
for(Enumeration e = linksmalls.elements(); e.hasMoreElements();) {
Link link = (Link)e.nextElement();
putlink(link.fromc, null, link.toc);
}
for(Enumeration e = links.elements(); e.hasMoreElements();) {
Link link = (Link)e.nextElement();
int fdepth = getdepth(link.fromc);
int tdepth = getdepth(link.toc);
int depth = fdepth > tdepth ? fdepth : tdepth;
Coordinates fpos = getpos(link.fromc);
Coordinates fsize = getsize(link.fromc);
Coordinates tpos = getpos(link.toc);
Coordinates tsize = getsize(link.toc);
Coordinates from = new Coordinates(
fpos.breadth + fsize.breadth/2, fpos.depth + fsize.depth);
Coordinates to = new Coordinates(
tpos.breadth + tsize.breadth/2, tpos.depth);
into.add(new LineDecor(from.x(), from.y(), to.x(), to.y(),
Color.red, depth));
}
}
}
public void initdims(String[] dims) {
this.dims = new DimVector[] {
new DimVector(dims[0], 1),
new DimVector(dims[1], bothhead ? -1 : 1),
new DimVector(dims[2], 1),
};
}
public ZZCell look(ZZCell c, int x, int y) {
Coordinates co = new Coordinates(x, y, false);
DimVector d=null, t=null;
if(co.depth == 0)
return null;
else if(co.depth < 0) {
d = dims[0];
t = dims[3];
} else {
d = dims[1].rev;
t = dims[3].rev;
}
if(co.breadth < 0)
return d.get(c);
else if(co.breadth > 0)
return d.end(c, true);
else {
if(t.get(c) != null) return t.get(c);
ZZCell[] rank = d.rank(c, false);
if(rank.length == 0) return null;
return rank[rank.length / 2];
}
}
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell c) {
Dimension cs = fact.getSize(null, initmul);
cellsizes = new Coordinates[maxdepth];
cellsizes[0] = new Coordinates(cs);
for(int i=1; i<maxdepth; i++)
cellsizes[i] = new Coordinates(cellsizes[i-1], shrink);
treegap = new Coordinates(bgap, cellsizes[0].depth + dgap*4);
linkgap = new Coordinates(bgap/4, dgap);
Coordinates fs = new Coordinates(into.getSize());
p("Prepared canvas size");
initdims(dims);
DimVector linkdim = this.dims[0], targetdim = this.dims[1],
tunneldim = this.dims[2];
p("Prepared DimVectors");
CellInfo uproot, downroot;
boolean islink;
// CALL 1: Tree generation. This may be overridden
p("Starting LevelRaster call one");
if(linkdim.rev.get(c) != null && targetdim.get(c) != null) {
islink = true;
uproot = connectCell(linkdim.rev.end(c), null, c, 1, true);
downroot = connectCell(targetdim.end(c), null, c, 1, false);
} else {
islink = false;
uproot = connectCell(c, null, null, 0, true);
downroot = connectCell(c, null, null, 0, false);
}
// CALL 2: Compute the size of cell and breadth of tree part
p("Starting LevelRaster call two");
uproot.computesize(); downroot.computesize();
// CALL 3: Put the cell and its parentlinks into a continuum
p("Starting LevelRaster call three");
Continuum co = new Continuum();
int upbstart = (fs.breadth - uproot.occupiedbreadth) / 2;
int downbstart = (fs.breadth - downroot.occupiedbreadth) / 2;
int updstart = (fs.depth + cellsizes[0].depth) / 2;
int downdstart = (fs.depth - cellsizes[0].depth) / 2;
if(islink) {
co.put(c, new Coordinates((fs.breadth - cellsizes[0].breadth) / 2,
downdstart), cellsizes[0],
0, false);
updstart -= treegap.depth/4*3; //+ cellsizes[0].depth;
downdstart += treegap.depth/4*3;
}
downroot.putall(co, downbstart, downdstart);
uproot.putall(co, upbstart, updstart);
// CALL 4: Position link cells
p("Starting LevelRaster call four");
co.positionlinkcells();
// CALL 5: Raster the continuum into a flob set
p("Starting LevelRaster call five");
co.raster(into, fact, view);
}
}
// vim: set syntax=java :

101
Java/flob/LineDecor.java Normal file
View File

@@ -0,0 +1,101 @@
/*
LineDecor.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class LineDecor extends CoordDecor {
public static final String rcsid = "$Id: LineDecor.java,v 1.9 2000/10/26 18:15:58 tjl Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
Color color;
/** A simple class that knows how to efficiently build
* these things.
*/
static public class Builder extends CoordDecor.Builder {
Color col;
public Builder(FlobSet into, Color col) {
super(into);
this.col = col;
}
/** Make a line.
*/
public final void l(int x0, int y0, int x1, int y1) {
makeRoom(4);
p[curp] = x0;
p[curp+1] = y0;
p[curp+2] = x1;
p[curp+3] = y1;
curp += 4;
}
protected Renderable create() {
p("Create linedecor "+p+" "+curp+" "+col+" "+d);
return new LineDecor(p, curp, col, d);
}
}
public LineDecor(int[] coords, int n, int d) {
this(coords, n, null, d);
}
/** Usual constructor.
* @param coords The coordinates for the lines, given as
* quadruplets x1, y1, x2, y2.
*/
public LineDecor(int[] coords, int n, Color color, int d) {
super(coords, n, d);
this.color = color;
}
public LineDecor(int x1, int y1, int x2, int y2, Color color, int d) {
super(null, 4, d);
this.coords = new int[] {
x1, y1, x2, y2
};
this.color = color;
this.d = d;
}
public void render(Graphics g) {
Color old = null;
if(color != null) {
old = g.getColor();
g.setColor(color);
}
for(int i=0; i+3<n; i+=4) {
g.drawLine(coords[i], coords[i+1],
coords[i+2], coords[i+3]);
}
if(old != null)
g.setColor(old);
}
}

112
Java/flob/MagGrid.zob Normal file
View File

@@ -0,0 +1,112 @@
/*
MagGrid.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
/** A grid magnified from the center.
*/
public class MagGrid extends GridGeom implements ZOb {
public static final String rcsid = "$Id: MagGrid.zob,v 1.2.10.1 2001/08/24 19:58:24 bfallenstein Exp $";
STRUCTPARAMS {
float[] shrink // 2..2
= new float[] {(float)1, (float)1};
float[] initmul // 2..2
= new float[] {(float)1.4, (float)1.55};
int[] gap // 2..2
= new int[] {6, 6};
/** Whether to fit all cells into view or leave
* edges hanging outside.
*/
boolean fit
= false;
}
int[] xs;
int[] ys;
public Dimension setSizes(Dimension normalcell, Dimension canvas) {
Dimension ret = new Dimension();
ret.width = 1;
int cur = (int)(normalcell.width * initmul[0]);
int xw;
for(xw = cur; xw <= canvas.width && cur > 1; xw += 2*cur+2*gap[0]) {
ret.width +=2;
cur = (int)(cur * shrink[0]);
}
if(fit) {
xw -= 2*cur+2*gap[0];
ret.width -= 2;
}
xs = new int[ret.width + 1];
cur = (int)(normalcell.width * initmul[0]);
xs[ret.width / 2] = cur;
for(int i=1; i<ret.width/2+1; i++) {
cur = (int)(cur * shrink[0]);
xs[ret.width/2-i] = xs[ret.width/2+i] = cur;
}
cur = (canvas.width - xw)/2;
for(int i=0; i<xs.length; i++) {
int l = xs[i];
xs[i] = cur;
cur += l;
}
cur = (int)(normalcell.height * initmul[1]);
int yw;
for(yw = cur; yw <= canvas.height && cur > 1; yw += 2*cur+2*gap[1]) {
ret.height +=2;
cur = (int)(cur * shrink[1]);
}
if(fit) {
yw -= 2*cur+2*gap[1];
ret.height -= 2;
}
ys = new int[ret.height + 1];
cur = (int)(normalcell.height * initmul[1]);
ys[ret.height / 2] = cur;
for(int i=1; i<ret.height/2+1; i++) {
cur = (int)(cur * shrink[1]);
ys[ret.height/2-i] = ys[ret.height/2+i] = cur;
}
cur = (canvas.height - yw)/2;
for(int i=0; i<ys.length; i++) {
int l = ys[i];
ys[i] = cur;
cur += l;
}
return ret;
}
public Rectangle getCell(int x, int y, Rectangle rect) {
rect.x = xs[x];
rect.y = ys[y];
rect.width = xs[x+1]-xs[x] - gap[0];
rect.height = ys[y+1]-ys[y] - gap[1];
return rect;
}
}
// vim: set syntax=java :

View File

@@ -0,0 +1,282 @@
/*
ManyToManyRaster.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka and Tuukka Hastrup
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class ManyToManyView implements FlobView, ZOb {
public static final String rcsid = "$Id$";
public static final boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
// Following are the parameters out of which the constructor
// is created.
STRUCTPARAMS {
/** The factor to shrink the cells with when moving away from
* center.
*/
float[] shrink // 2..2
= new float[] {(float)0.75, (float)0.95};
/** The factor the center cell is enlarged with from default.
*/
float initmul
= (float)1.0;
/** The distance between neighbouring cells.
*/
int[] gap // 2..2
= new int[] {0, 0};
}
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
Dimension fs = into.getSize();
Dimension maxsz = fact.getSize(null, initmul);
// Calculate number of X and Y divisions.
// There are two of each cell size. Go on until that is
// too much.
int nx = 0;
float curl = maxsz.width;
for(int xw = 0; xw <= fs.width - maxsz.width && curl>2; nx++) {
xw += 2 * (int)curl;
curl *= shrink[0];
}
int ny = 0;
curl = maxsz.height;
for(int yw = 0; yw <= fs.height - maxsz.height && curl>2; ny++) {
yw += 2 * (int)curl;
curl *= shrink[1];
}
nx *= 2;
ny *= 2;
ZZCell[][] grid = new ZZCell[nx][ny];
int[] xsz = new int[nx+1];
int[] ysz = new int[ny+1];
xsz[0] = maxsz.width / 2;
xsz[1] = maxsz.width;
ysz[0] = 2*maxsz.height;
ysz[1] = maxsz.height;
curl = maxsz.width;
for(int i=0; i<nx/2; i++) {
xsz[nx/2-i + 1] = xsz[nx/2+i + 1] = (int)curl;
curl *= shrink[0];
}
curl = maxsz.height;
for(int i=0; i<ny/2; i++) {
ysz[ny/2-i + 1] = ysz[ny/2+i + 1] = (int)curl;
curl *= shrink[1];
}
int curi = 0;
for(int i=0; i<nx+1; i++) { curi += xsz[i]; xsz[i] = curi; }
curi = 0;
for(int i=0; i<ny+1; i++) { curi += ysz[i]; ysz[i] = curi; }
int cx = nx / 2;
int cy = ny / 2;
// Find which flobs to place where.
grid[cx][cy] = accursed;
// XXX x expanded / y expanded!!!
// Negwards. Take headcells first.
Hashtable heads = new Hashtable();
ZZCell xhead = grid[0][cy] = accursed.h(dims[0], -1);
ZZCell yhead = grid[cx][0] = accursed.h(dims[1], -1);
heads.put(yhead, new Integer(cx));
heads.put(xhead, new Integer(0));
LoopDetector ld = new LoopDetector();
ZZCell cur = accursed;
for(int x = cx-1; x > 0 && cur != null; x--) { ld.detect(cur);
cur = cur.s(dims[0], -1); if(cur == xhead) break;
grid[x][cy] = cur;
}
ld.reset();
cur = accursed;
for(int y = cy-1; y > 0 && cur != null; y--) { ld.detect(cur);
cur = cur.s(dims[1], -1); if(cur == yhead) break;
grid[cx][y] = cur;
}
// Poswards
ld.reset();
cur = accursed;
for(int x = cx+1; x < nx && cur != null; x++) { ld.detect(cur);
grid[x][cy] = cur = cur.s(dims[0], 1);
}
ld.reset();
cur = accursed;
for(int y = cy+1; y < ny && cur != null; y++) { ld.detect(cur);
grid[cx][y] = cur = cur.s(dims[1], 1);
}
// Other headcells
for(int x = 1; x < nx; x ++)
if(grid[x][cy] != null) {
grid[x][0] = grid[x][cy].h(dims[1], -1);
if(grid[x][0]!=null)
heads.put(grid[x][0], new Integer(x));
}
for(int y = 1; y < ny; y ++)
if(grid[cx][y] != null) {
ZZCell c = grid[0][y] = grid[cx][y].h(dims[0], -1);
if(c!=null)
heads.put(c, new Integer(0));
c = c.s(dims[0], 1);
ld.reset();
while(c!=null) { // Show other intersections
ld.detect(c);
Integer xpos = (Integer)heads.get(c.h(dims[1], -1));
if(xpos!=null)
grid[xpos.intValue()][y] = c;
c = c.s(dims[0], 1);
}
}
LineDecor.Builder bdline = new LineDecor.Builder(into, Color.red);
bdline.startl(400, 1);
// Find out which cells are shown
Hashtable shown = new Hashtable();
for(int x = 0; x < nx; x++) {
for( int y = 0; y < ny; y++) {
if(grid[x][y]!=null)
shown.put(grid[x][y], grid[x][y]);
}
}
// Render the flobs
for(int x = 0; x < nx; x ++) {
for( int y = 0; y < ny; y ++) {
if(grid[x][y] == null) continue;
int xcoord = xsz[x];
int ycoord = ysz[y];
int width = xsz[x+1] - xcoord;
int height = ysz[y+1] - ycoord;
if(x != 0 && y != 0 && heads.get(grid[x][y])!=null)
continue;
Flob fl = fact.makeFlob(into, grid[x][y], grid[x][y],
initmul * height / (float)maxsz.height,
xcoord, ycoord, 1, width, height);
/* if(x == 0 || y == 0)
fl.flobPath="headcell";*/
// Place a red line if the neighbour isn't shown
ZZCell c = grid[x][y];
for(int dx=-1;dx<=1;dx+=2) {
ZZCell n = c.s(dims[0], dx);
if(n!=null && shown.get(n)==null
&& (y!=0 || (x+dx>0 && x+dx<nx && grid[x+dx][y]==null))){
int xc = xcoord + (width+dx*width)/2;
int y1c = ycoord;
int y2c = ycoord + height;
bdline.l(xc, y1c, xc, y2c);
bdline.l(xc+dx, y1c, xc+dx, y2c);
}
}
for(int dy=-1;dy<=1;dy+=2) {
ZZCell n = c.s(dims[1], dy);
if(n!=null && shown.get(n)==null
&& (x!=0 || (y+dy>0 && y+dy<ny && grid[x][y+dy]==null))){
int x1c = xcoord;
int x2c = xcoord + width;
int yc = ycoord + (height+dy*height)/2;
bdline.l(x1c, yc, x2c, yc);
bdline.l(x1c, yc+dy, x2c, yc+dy);
}
}
// Place red lines where the structure was collapsed
/* if(x+1 < nx) {
ZZCell c = grid[x][y];
ZZCell cp = grid[x+1][y];
if(cp != null && c.s(dims[0], 1)!=cp)
bdline.l(xcoord+width, ycoord, xcoord+width, ycoord+height);
}
if(y+1 < ny) {
ZZCell c = grid[x][y];
ZZCell cp = grid[x][y+1];
if(cp != null && c.s(dims[1], 1)!=cp)
bdline.l(xcoord, ycoord+height, xcoord+width, ycoord+height);
}*/
/* // Show continuing ranks on edges
if(x == 0 && grid[x][y].s(dims[0], -1)!=null)
bdline.l(xcoord,ycoord,xcoord,ycoord+height);
if(x+1 == nx && grid[x][y].s(dims[0], 1)!=null)
bdline.l(xcoord+width,ycoord,xcoord+width,ycoord+height);
if(y == 0 && grid[x][y].s(dims[1], -1)!=null)
bdline.l(xcoord,ycoord,xcoord+width,ycoord);
if(y+1 == ny && grid[x][y].s(dims[1], 1)!=null)
bdline.l(xcoord,ycoord+height,xcoord+width,ycoord+height);*/
}
}
bdline.endl();
// Do the dimensions.
if(true)
ZZUtil.showFlobDims(into, fact, view, 2);
}
}
// vim: set syntax=java :

90
Java/flob/MultiView.zob Normal file
View File

@@ -0,0 +1,90 @@
/*
MultiView.zob
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag;
import java.awt.*;
import java.util.*;
/** A view that brings together different applitudes.
*/
public class MultiView implements FlobView, ZOb {
public static final String rcsid = "$Id: MultiView.zob,v 1.2 2000/12/28 22:46:02 bfallenstein Exp $";
/** Should we print out debugging info? */
public static boolean dbg = false;
static final void p(String s) { if(dbg) pa(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {}
public void raster(final FlobSet into, final FlobFactory fact,
final ZZCell win, final String[] dims,
final ZZCell accursed) {
final Hashtable had = new Hashtable();
ZZCell choice = null;
ZZCell[] accapps = ApplitudeMgr.getApplitudes(accursed);
ZZCell pref = ApplitudeMgr.getWindowApp(win);
if(accapps.length == 0)
choice = ApplitudeMgr.getFallback(win.getSpace());
else {
for(int i=0; i<accapps.length; i++) {
if(accapps[i].equals(pref)) {
choice = pref; break;
}
}
if(choice == null)
choice = accapps[0];
}
final ZZCell app = choice;
final Dimension size = new Dimension(into.getSize());
fact.centerFlob(into, pref, pref, (float)1.5,
new Point(size.width, size.height), 1, 1, 1);
FlobView view0 = ApplitudeMgr.getView(app);
FlobSet set0 = into.create(size);
view0.raster(set0, fact, win, dims, accursed);
into.fetch(set0, 0, 0, 0, app);
set0.iterDepth(new FlobSet.DepthIter() {
public void act(Flob[] flobs, int start, int n) {
for(int i=start; i<start+n; i++) {
Flob f = flobs[i];
if(f.c == null || had.get(f.c) != null) continue;
had.put(f.c, f.c);
Point fc = f.getCenter();
ZZCell[] apps = ApplitudeMgr.getApplitudes(f.c);
for(int j=0; j<apps.length; j++) {
if(apps[j].equals(app)) continue;
FlobSet set = into.create(size);
FlobView view = ApplitudeMgr.getView(apps[j]);
view.raster(set, fact, win, dims, f.c);
Flob g = set.findNearest(f, null);
Point gc = g.getCenter();
into.fetch(set, fc.x - gc.x + j, fc.y - gc.y + j,
f.d+1, apps[j]);
}
}
}
}, true);
}
}

41
Java/flob/NullView.zob Normal file
View File

@@ -0,0 +1,41 @@
/*
NullRaster.zob
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Antti-Juhani Kaijanaho
*/
package org.gzigzag;
/** A flobraster that just bails out (the default raster in case an
unknown raster was requested). */
public class NullView implements FlobView {
public static final String rcsid = "$Id$";
/** Should we print out debugging info? */
public static boolean dbg = false;
static final void p(String s) { if(dbg) pa(s); }
static final void pa(String s) { System.out.println("(flob)NullRaster: " + s); }
STRUCTPARAMS {}
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
throw new ZZError("null view invoked (please change view)");
}
}

View File

@@ -0,0 +1,138 @@
/*
ParallelTextView.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A text cloud.
*/
public class ParallelTextView implements FlobView, ZOb {
public static final String rcsid = "$Id: ParallelTextView.zob,v 1.6 2000/12/11 09:03:03 raulir Exp $";
public static boolean dbg = false;
static void p(String s) { if(dbg) System.out.println(s); }
static void pa(String s) { System.out.println(s); }
static RankTextView vr;
STRUCTPARAMS {
}
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, final String[] dims, ZZCell accursed) {
Dimension d = into.getSize();
int cy = d.height / 2;
int width = d.width / 4;
int xspace = width / 2;
if(vr == null) {
vr = new RankTextView();
vr.readParams(null);
}
vr.dim = dims[1];
vr.width = width;
ZZCell[] streams = new ZZCell[] {
accursed.s(dims[0], -1),
accursed,
accursed.s(dims[0], 1),
};
int offs = ZZCursorReal.getOffs(view);
if(offs == ZZCursorReal.NO_OFFSET) offs = 0;
for(int i=0; i < 3; i++) {
if(streams[i] == null) continue;
int x = i * (width + xspace);
vr.raster(into, streams[i], i==1 ? offs : 0, false, x, cy);
}
// Now, the links
final FlobSet f = (FlobSet)into; // XXX
final LineDecor.Builder ldb = new LineDecor.Builder(f, Color.red);
final Hashtable flobtable = new Hashtable();
f.iterDepth(new FlobSet.DepthIter() {
public void act(Flob[] flobs, int start, int n) {
for(int i=start; i<start+n; i++) {
Flob flb = flobs[i];
if(flb.c == null) continue;
// if(((SpanFlob)flb).getPrev() != null) continue;
Vector fs = (Vector) flobtable.get(flb.c);
if(fs == null) {
fs = new Vector();
flobtable.put(flb.c, fs);
}
fs.addElement(flb);
}
}
}, true);
f.iterDepth(new FlobSet.DepthIter() {
public void act(Flob[] flobs, int start, int n) {
ldb.startl(2*n, flobs[start].d + 1);
for(int i=start; i<start+n; i++) {
Flob cur = flobs[i];
ZZCell c = cur.c;
p(" cell: "+c+" "+(c!=null?c.getText():""));
if(!(cur instanceof SpanFlob)) continue;
p(" is span flob");
if(c == null) continue;
SpanFlob spanf = (SpanFlob)cur;
// if(spanf.getPrev() != null) continue;
p(" doesn't have prev");
{ // XXX dedent
ZZCell neigh = c.s(dims[0], 1);
p(" Neigh: "+neigh+" "+
(neigh!=null?neigh.getText():""));
if(neigh == null) continue;
Vector nflbs = (Vector) flobtable.get(neigh);
if(nflbs == null) continue;
// XXX show connections to non-shown cells!
for(Enumeration e = nflbs.elements();
e.hasMoreElements();) {
Flob nf = (Flob) e.nextElement();
SpanFlob nsf = (SpanFlob) nf;
Flob from=cur, to=nf;
ldb.l(
from.x + from.w,
from.y + from.h / 2,
to.x,
to.y + to.h / 2
);
}
}
}
ldb.endl();
}
}, true);
}
}
// vim: set syntax=java :

307
Java/flob/RankTextView.zob Normal file
View File

@@ -0,0 +1,307 @@
/*
VStreamRaster.zob
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A raster of flowing text.
* The FlobRaster is implemented mostly for testing purposes - this class
* would mostly be called from another raster.
*/
public class RankTextView implements FlobView, ZOb {
public static final String rcsid = "$Id$";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** The width of the flowing text at maximum. Negative value
means that the width of the window should be used. */
int width
= 300;
/** The font for the maximal line. */
ScalableFont font
= new ScalableFont("SansSerif", Font.PLAIN, 16);
/** The half-width of the bulge. */
int bulge
= 10;
/** Whether to show cuts. */
boolean cuts
= true;
/** Which dimension to use. */
String dim
= "d.2";
/** Whether to billow the text. */
boolean billow
= true;
/** Whether to show XOR cursors. */
boolean xor
= true;
/** The backround colour for all flobs (or null if determined
from the cursors. */
Color bgcolor
= null;
}
protected Font getfont(int scale) {
return font.getFont(scale);
}
protected FontMetrics getfontmet(int scale) {
return font.getFontMetrics(scale);
}
SimpleLineInfo.Layout layb = new LayBillow();
SimpleLineInfo.Layout layf = new LayFlat();
SimpleLineBreaker brk = new SimpleLineBreaker();
protected int getFontScale(int line, boolean doBillow) {
int w = (doBillow ? layb : layf).getWidth(line);
return (1000*w)/width;
}
class LayBillow implements SimpleLineInfo.Layout {
public final FontMetrics getFontMetrics(int line) {
return getfontmet(getFontScale(line, true));
}
public final int getWidth(int line) {
if(bulge <= 0) return width;
float bfunc = (float)(
1.0/ ( 1 + (line * (float)line) / (bulge * bulge) ) );
return (int)(bfunc * width);
}
public final int getCenterLine() {
return 0;
}
}
class LayFlat implements SimpleLineInfo.Layout {
public final FontMetrics getFontMetrics(int line) {
return getfontmet(1000);
}
public final int getWidth(int line) {
return width;
}
public final int getCenterLine() {
return 0;
}
}
/** Raster an area.
* Returns a bounding rectangle for the text plotted.
*/
public Rectangle raster(FlobSet into, ZZCell c, int offs, boolean doBillow,
int startx, int starty, int xormode) {
if (width < 0) width = into.getSize().width;
Rectangle res = new Rectangle();
// read the whole string first
int soffs = -1;
StringBuffer s = new StringBuffer();
ZZCell head = c.h(dim, -1);
boolean first = true;
for(ZZCell h = head;
h != null && (first || h!=head); h = h.s(dim, 1)) {
first = false;
if(h == c)
soffs = offs + s.length();
s.append(h.getText());
}
if(soffs < 0)
throw new ZZError("??? ARGH");
String txt = s.toString();
SimpleLineInfo sli = new SimpleLineInfo(txt, soffs,
(doBillow?layb:layf));
int[] linestops = brk.breakLines(sli);
p("Breaklines: "+offs);
for(int i=0; i<linestops.length; i++)
p("Line: "+linestops[i]);
for(int i=-10; i<=10; i++) {
p("WFM: "+layb.getWidth(i)+" "+getFontScale(i, doBillow));
}
int ctr = - linestops[0];
/** Current Y offset for the loop. */
int cury = starty;
// Calculate the starting Y coordinate
for(int i = ctr; i>=0; i--) {
cury -= getfontmet(getFontScale(i-ctr, doBillow)).getHeight();
}
res.x = startx; res.width = width;
res.y = cury;
// Downwards from center.
// start-splitcellflob needs very careful attention.
/** Current offset in the whole string.
*/
int curoffs = 0;
/** Current line.
*/
int curline = 0;
/** Current X-coordinate.
*/
int curx = startx;
int fi = getFontScale(curline - ctr, doBillow);
Font f = getfont(fi);
FontMetrics fm = getfontmet(fi);
SplitCellFlob1 latest = null;
first = true;
for(ZZCell h = head;
h != null && (first || h != head); h = h.s(dim, 1)) {
first = false;
final String st = h.getText();
final int len = st.length();
int nth = 0;
SplitCellFlob1 parent = null;
// Find the cursors on this cell. Only one is shown.
int curs = ZZCursorReal.NO_OFFSET;
ZZCell ccurs = h;
while((ccurs = ccurs.s("d.cursor", 1))!=null) {
curs = ZZCursorReal.getOffs(ccurs);
if(curs != ZZCursorReal.NO_OFFSET) break;
}
if(h.s("d.cut", 1) != null) {
// There was a cut.
into.add(new LineDecor(curx, cury, curx, cury+fm.getHeight(),
Color.red, 1));
}
while(curoffs + len - nth > linestops[curline+1]) {
p("Parent: "+nth+" "+len+" "+curline+" "+linestops[curline+1]);
SplitCellFlob1 cur = new SplitCellFlob1(
curx, cury, 100, fm.stringWidth(st.substring(nth,
nth+
(linestops[curline+1] - curoffs))),
fm.getHeight(), h, f, fm, parent,
nth, linestops[curline+1]-curoffs, xormode, bgcolor);
if(bgcolor == null) cur.showCursor();
cur.setPrev(latest); latest = cur;
if(curs != ZZCursorReal.NO_OFFSET)
addCurs(into, cur, curs);
parent = cur;
into.add(cur);
// Split it.
nth += linestops[curline+1] - curoffs;
curoffs = linestops[curline+1];
curline ++;
cury += fm.getHeight();
curx = startx;
fi = getFontScale(curline - ctr, doBillow);
f = getfont(fi);
fm = getfontmet(fi);
if(curline >= linestops.length - 1) {
p("LAST LINE: ALL OUT");
break;
}
}
if(curline >= linestops.length - 1)
break;
p("Last: "+nth+" "+len+" "+curline+" "+linestops[curline+1]+" "+
st.length());
int w = 0;
String substr = st.substring(nth, len);
p("Substr: "+substr);
SplitCellFlob1 last = new SplitCellFlob1(
curx, cury, 100,
(w = fm.stringWidth(substr)),
fm.getHeight(), h, f, fm, parent, nth, len-nth, xormode, bgcolor);
if(bgcolor == null) last.showCursor();
last.setPrev(latest); latest = last;
if(curs != ZZCursorReal.NO_OFFSET)
addCurs(into, last, curs);
curoffs += len-nth;
curx += w;
into.add(last);
}
p("FINISHED");
res.height = cury - res.y + fm.getHeight();
return res;
}
public Rectangle raster(FlobSet into, ZZCell c, int offs, boolean doBillow,
int startx, int starty) {
return raster(into, c, offs, doBillow, startx, starty,
SplitCellFlob1.XOR_NO);
}
private void addCurs(FlobSet into, SplitCellFlob1 sf, int ind) {
if(!(ind >= sf.start && ind <= sf.start + sf.n))
return;
int x = sf.getStrX(ind);
if(x >= 0)
into.add(new LineDecor(x, sf.y, x, sf.y+sf.h,
Color.black, sf.d));
}
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
ZZCell c = ZZCursorReal.get(view);
int offs = ZZCursorReal.getOffs(view);
int xormode = SplitCellFlob1.XOR_LINE;
if(offs == ZZCursor.NO_OFFSET) {
offs = 0;
xormode = SplitCellFlob1.XOR_SOLID;
}
if(!xor) xormode = SplitCellFlob1.XOR_NO;
Dimension d = into.getSize();
int cy = d.height / 2;
raster(into, c, offs, billow, 0, cy, xormode);
}
// public VStreamRaster() { }
}
// vim: set syntax=java :

88
Java/flob/Renderable.java Normal file
View File

@@ -0,0 +1,88 @@
/*
Renderable.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
public abstract class Renderable {
public static final String rcsid = "$Id: Renderable.java,v 1.10 2001/03/17 20:13:08 bfallenstein Exp $";
public int d;
/** Render this thing.
*/
abstract public void render(Graphics g);
/** Render this thing.
* Simply calls render(g).
* @param orig The top-level graphics object without translations,
* clippings, rotations, etc.
*/
public void render(Graphics g, Graphics orig) { render(g); }
/** Translate the coordinates of this Renderable by (x, y)
* I.e., add x from the x-coordinate and y from the y-coordinate.
* This is used to translate between coordinate systems.
* @returns False if translating is not supported.
*/
public boolean translate(int x, int y) {
return false;
}
/** Do a stable depth-sort of renderables.
* Of two renderables on the same depth, the relative order remains.
* Uses radix sort for extreme speed.
*/
static public void depthSort(Renderable[] it, int nit) {
Renderable[][] ftmp = new Renderable[][] { it, new Renderable[nit] };
Renderable[][] ftmp2 = new Renderable[2][nit];
Renderable[][] fs;
int[] n = new int[] { nit, 0 };
int[] newn = new int[2];
int[] nex = null;
int mx = 0;
for(int i=0; i<nit; i++) {
if(it[i].d > mx) mx = it[i].d;
}
for(int bit = 1; mx >= bit && bit!=0; bit <<= 1) {
for(int bin=0; bin<2; bin++) {
for(int i=0; i<n[bin]; i++) {
if(ftmp[bin][i] == null) continue;
int ind = (((ftmp[bin][i].d & bit) == 0) ? 0 : 1);
ftmp2[ind][newn[ind]++] = ftmp[bin][i];
}
}
fs = ftmp2; ftmp2 = ftmp; ftmp = fs;
nex = n; n = newn; newn = nex;
newn[0] = newn[1] = 0;
}
for(int i=0; i<nit-n[0]; i++)
ftmp[0][n[0]+i] = ftmp[1][i];
if(it != ftmp[0]) {
System.arraycopy(ftmp[0], 0, it, 0, nit);
}
}
}

125
Java/flob/RowColView.zob Normal file
View File

@@ -0,0 +1,125 @@
/*
RowColRaster.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.util.*;
public class RowColView implements FlobView, ZOb {
public static final String rcsid = "$Id$";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
boolean repeat
= false;
boolean row
= false;
ZOb geom
= new MagGrid();
}
void place(FlobFactory fact,
FlobSet f, ZZCell c, Dimension ideal, Rectangle where) {
float fract = (float)(where.height / (float)ideal.height);
fact.makeFlob(f, c, c, fract, where.x, where.y, 1, where.width,
where.height);
}
FlobDecorator linker = new StdLinks();
public void raster(final FlobSet into, final FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
final GridGeom geom = (GridGeom)this.geom;
final Dimension ideal = fact.getSize(null, 1);
final Dimension gs = geom.setSizes(ideal, into.getSize());
final Hashtable done = new Hashtable();
final Rectangle rect = new Rectangle();
final int cx = gs.width / 2;
final int cy = gs.height / 2;
final ZZCell[] col = new ZZCell[row ? gs.height : gs.width];
final int cmain = (row ? cy : cx);
final int cother = (row ? cx : cy);
// Do the dimensions.
// Must do these first so that they get to be shown on top.
if(true)
ZZUtil.showFlobDims(into, fact, view, 3);
// Do the single row/column
ZZIter.alternate(accursed, true, dims[(row ? 1 : 0)], 1,
new ZZIter.NIter() {
public boolean go(ZZCell c, int nth) {
nth += cmain;
if(nth < 0 || nth >= col.length) return false;
if(!repeat && done.get(c) != null) return false;
col[nth] = c;
done.put(c, c);
if(row)
geom.getCell(cother, nth, rect);
else
geom.getCell(nth, cother, rect);
place(fact, into, c, ideal, rect);
return true;
}
});
final int lother = (row ? gs.width : gs.height);
for(int i = 0; i<col.length; i++) {
final int coord = i;
ZZIter.alternate(col[i], false, dims[(row ? 0 : 1)], 1,
new ZZIter.NIter() {
public boolean go(ZZCell c, int nth) {
nth += cother;
if(nth < 0 || nth >= lother) return false;
if(!repeat && done.get(c) != null) return false;
done.put(c, c);
if(row)
geom.getCell(nth, coord, rect);
else
geom.getCell(coord, nth, rect);
place(fact, into, c, ideal, rect);
return true;
}
});
}
linker.decorate(into, "", view);
}
}
// vim: set syntax=java :

148
Java/flob/SceneFlob.java Normal file
View File

@@ -0,0 +1,148 @@
/*
SceneFlob.java
*
* Copyright (c) 2001, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** Flob which contains flobset, possibly transformed.
* This is subclassed by e.g. ZZDrawingJ2D.
*/
public abstract class SceneFlob extends BoxedFlob {
public static final String rcsid = "$Id: SceneFlob.java,v 1.8 2001/03/18 17:50:16 bfallenstein Exp $";
public static final boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
FlobSet sc;
public SceneFlob(int x, int y, int d, int w, int h, ZZCell c, FlobSet sc) {
super(x,y,d,w,h,c);
this.sc = sc;
sc.sflob = this;
}
/** The flobs that are important to interpolate
* even when level-of-detail is small
*/
Flob[] important;
/** Set the important-to-interpolate flobs.
*/
public void setImportant(Flob[] what) {
important = what;
}
/** Whether this is a focused sceneflob, i.e.whether level-of-detail
* is high.
*/
boolean focus;
public void setFocus(boolean focus) {
this.focus = focus;
}
/** The other sceneflob we are currently prepared to interpolate to.
*/
SceneFlob interpPrep;
/** The scene flob this one is in.
* This is needed to convert coordinates to top-level; and that is needed
* to create connections between windows.
*/
SceneFlob parent;
/** Transform the given points between the internal and external coordinates.
* @param toExt Whether to transform internal to external or vice versa.
*/
public abstract void transform(double[] srcPtr, double[]dstPts, boolean toExt);
/** Transform the given point between the internal and external coordinates.
* @param toExt Whether to transform internal to external or vice versa.
*/
public abstract Point transform(Point src, Point dst, boolean toExt);
/** Transform the given points between the internal and top-level coordinates.
* @param toTop Whether to transform internal to top-level or vice versa.
*/
public void transformTop(double[] srcPtr, double[] dstPts, boolean toTop) {
if(toTop) transform(srcPtr, dstPts, true);
if(parent != null)
parent.transformTop(srcPtr, dstPts, toTop);
if(!toTop) transform(srcPtr, dstPts, false);
}
/** Transform the given point between the internal and top-level coordinates.
* @param toTop Whether to transform internal to top-level or vice versa.
*/
public Point transformTop(Point src, Point dst, boolean toTop) {
if(toTop) transform(src, dst, true);
if(parent != null)
parent.transformTop(src, dst, toTop);
if(!toTop) transform(src, dst, false);
return dst;
}
/** Make this graphics so that we can render into it with the correct
* transformation.
*/
abstract void prepareGraphics(Graphics g, float interpFract);
public void render(Graphics g0) { render(g0, g0); }
public void render(Graphics g0, Graphics orig) {
Graphics g = g0.create();
prepareGraphics(g, 0);
sc.render(g, orig);
g.dispose();
}
public void renderInterp(Graphics g0, float fract) {
if(!(interpTo instanceof SceneFlob)) return;
// p("sceneflob renderinterp");
// Here we test the level-of-detail stuff.
if(interpTo != interpPrep) {
interpPrep = (SceneFlob)interpTo;
// p("Prepinterp sceneflob: "+focus+" "+interpPrep.focus+" "+important);
if(focus || interpPrep.focus || important == null)
sc.prepareInterp(interpPrep.sc);
else
sc.prepareInterp(interpPrep.sc, important);
}
Graphics g = g0.create();
prepareGraphics(g, fract);
sc.renderInterp(g, ((SceneFlob)interpTo).sc, fract);
g.dispose();
}
public boolean isInterpUseful() { return true; }
public Object hit(int x, int y) {
Point p = new Point(x,y);
Point d = new Point();
transform(p,d, false);
return sc.getObjectAt(d.x, d.y);
}
public FlobSet getFlobSet(){ return sc;}
}

256
Java/flob/SimpleBeamer.zob Normal file
View File

@@ -0,0 +1,256 @@
/*
SimpleBeamer.zob
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A decorator which draws beams between overlapping SpanFlobs.
* This is a tricky job: among other things, we are responsible for
* the overall aesthetic effect of beams.
* Currently, we try to draw the beams between the topmost
* flobs last so that the beams have a consistent ordering w.r.t.
* the Z axis. This is <em>not</em> trivial, since we also have to
* draw neighbouring beams using the same color.
*/
public class SimpleBeamer implements FlobDecorator {
public static final String rcsid = "$Id: SimpleBeamer.zob,v 1.7 2000/09/19 10:31:59 ajk Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** The depth where to put the beam graphics.
*/
int depth
= 1000;
}
// Used for checking whether the connection between two spans
// is handled already.
private class Pair {
Object a; Object b;
public Pair(Object a, Object b) {
this.a = a;
this.b = b;
}
public int hashCode() {
return a.hashCode() ^ b.hashCode();
}
public boolean equals(Object o) {
Pair p = (Pair)o;
return (a==p.a && b==p.b) || (b==p.a && a==p.b);
}
}
static public Color getSpanColor() {
return new Color(
(float)(Math.random() + 1) / 2,
(float)(Math.random() + 1) / 2,
(float)(Math.random() + 1) / 2
);
}
int[] xy = new int[16];
protected void putBeam(BeamDecor.Builder bb,
SpanFlob[] sfs, Span[] sps,
Color c) {
p("Putbeam");
int ssep = (int)(sps[0].getStartOffs() - sps[1].getStartOffs());
int esep = (int)(sps[0].getEndOffs() - sps[1].getEndOffs());
int x0=0, x1=0, w0=(int)sps[0].length(), w1=(int)sps[1].length();
if(ssep > 0) x1 = ssep;
else x0 = -ssep;
if(esep > 0) w0 -= esep;
else w1 += esep;
Rectangle r0 = sfs[0].getRectangle(x0, w0);
Rectangle r1 = sfs[1].getRectangle(x1, w1);
// Then, some difficult manipulation to get the points.
Rectangle a=null;
// left side
if(r0.x < r1.x) { a = r0; } else { a = r1; }
xy[0] = a.x; xy[8] = a.y;
xy[1] = a.x; xy[9] = a.y+a.height;
// bottom side
if(r0.y+r0.height > r1.y+r1.height) { a = r0; } else { a = r1; }
xy[2] = a.x; xy[10] = a.y+a.height;
xy[3] = a.x+a.width; xy[11] = a.y+a.height;
// right side
if(r0.x+r0.width > r1.x+r1.width) { a = r0; } else { a = r1; }
xy[4] = a.x+a.width; xy[12] = a.y+a.height;
xy[5] = a.x+a.width; xy[13] = a.y;
// top
if(r0.y < r1.y) { a = r0; } else { a = r1; }
xy[6] = a.x+a.width; xy[14] = a.y;
xy[7] = a.x; xy[15] = a.y;
bb.b(xy, c);
}
/** Return: whether to continue.
*/
static boolean moveBack( SpanFlob[] sfs,
Span[] spans) {
long l1 = spans[0].getStartOffs();
long l2 = spans[1].getStartOffs();
if(l1 == l2) {
// Check if previous spans end at same point.
sfs[0] = sfs[0].getPrev(); if(sfs[0] == null) return false;
sfs[1] = sfs[1].getPrev(); if(sfs[1] == null) return false;
spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false;
spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false;
if(spans[0].getEndOffs() != spans[1].getEndOffs()) return false;
return true;
}
if(l1 > l2) {
Span tmp = spans[0];
sfs[0] = sfs[0].getPrev(); if(sfs[0] == null) return false;
spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false;
return spans[0].isAppendable(tmp);
} else {
Span tmp = spans[1];
sfs[1] = sfs[1].getPrev(); if(sfs[1] == null) return false;
spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false;
return spans[1].isAppendable(tmp);
}
}
static boolean moveForw( SpanFlob[] sfs,
Span[] spans) {
long l1 = spans[0].getEndOffs();
long l2 = spans[1].getEndOffs();
if(l1 == l2) {
// Check if previous spans end at same point.
sfs[0] = sfs[0].getNext(); if(sfs[0] == null) return false;
sfs[1] = sfs[1].getNext(); if(sfs[1] == null) return false;
spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false;
spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false;
if(spans[0].getStartOffs() != spans[1].getStartOffs()) return false;
return true;
}
if(l1 < l2) {
Span tmp = spans[0];
sfs[0] = sfs[0].getNext(); if(sfs[0] == null) return false;
spans[0] = sfs[0].getSpan(); if(spans[0] == null) return false;
return tmp.isAppendable(spans[0]);
} else {
Span tmp = spans[1];
sfs[1] = sfs[1].getNext(); if(sfs[1] == null) return false;
spans[1] = sfs[1].getSpan(); if(spans[1] == null) return false;
return tmp.isAppendable(spans[1]);
}
}
public void decorate(final FlobSet into, final String path,
final ZZCell view) {
p("Putting beams...");
final BeamDecor.Builder bb = new BeamDecor.Builder(into);
final SpanSet ss = new SpanTree();
final Hashtable done = new Hashtable();
final SpanFlob[] sfs = new SpanFlob[2];
final Span[] sps = new Span[2];
final Span[] sps0 = new Span[2];
// Starts from the surface, goes deeper.
// BeamDecor renders first-put ones last, which is
// exactly right for this.
// XXX WRONG!
// ss gets added things so that the span gets
// drawn when the deeper one is reached, not earlier.
// hmm...
into.iterDepth(new FlobSet.DepthIter() {
public void act(Flob[] flobs, int start, int n) {
bb.startl((n+8)*4, depth);
for(int f = start; f<start+n; f++) {
Flob cur = flobs[f];
if(!(cur instanceof SpanFlob)) continue;
SpanFlob sf = (SpanFlob)cur;
Span sp = sf.getSpan();
p("SF: "+sf+" "+sp);
if(sp == null) continue;
if(sp.length() == 0) continue;
Object[] ovs = ss.overlaps(sp);
ss.addSpan(sp, sf);
p("Objs: "+ovs+" "+ovs.length);
if(ovs.length > 0) {
p("Obj: "+ovs[0]);
} else continue;
for(int i=0; i<ovs.length; i++) {
Pair pa = new Pair(sf, ovs[i]);
if(done.get(pa) != null)
continue;
Color c = getSpanColor();
sfs[0] = sf; sps[0] = sfs[0].getSpan();
sfs[1] = (SpanFlob)ovs[i]; sps[1] = sfs[1].getSpan();
sps0[0] = sps[0]; sps0[1] = sps[1];
putBeam(bb, sfs, sps, c);
done.put(pa, pa);
while(moveBack(sfs, sps)) {
putBeam(bb, sfs, sps, c);
done.put(new Pair(sfs[0], sfs[1]), pa);
}
sfs[0] = sf; sps[0] = sps0[0];
sfs[1] = (SpanFlob)ovs[i]; sps[1] = sps0[1];
while(moveForw(sfs, sps)) {
putBeam(bb, sfs, sps, c);
done.put(new Pair(sfs[0], sfs[1]), pa);
}
}
}
}}, false);
bb.endl();
p("Beams finished.");
}
}
// vim: set syntax=java :

View File

@@ -0,0 +1,66 @@
/*
SimpleBoxType.java
*
* Copyright (c) 1999-2001, Ted Nelson and Tuomas Lukka
* Copyright (c) 2001, Benja Fallenstein
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka, BoxType adaption by Benja Fallenstein
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A simple BoxType looking like the old CellBgFlobs.
* Draws a filled (possibly with several colors) background rectangle,
* surrounded by a rectangle of the current foreground color.
*/
public class SimpleBoxType extends BoxType {
public static final String rcsid = "$Id: SimpleBoxType.java,v 1.2 2001/03/18 17:50:16 bfallenstein Exp $";
public static final boolean dbg = true;
// static final void p(String s) { if(dbg) System.out.println(s); }
// static final void pa(String s) { System.out.println(s); }
public void renderBg(Graphics g, BoxedFlob f, int mx, int my,
int md, int mw, int mh) {
Color oldfg = g.getColor();
if(f.solids != null) {
for(int i=0; i<f.nsolids; i++) {
g.setColor(f.solids[i]);
g.fillRect(mx+(mw*i)/f.nsolids, my, mw/f.nsolids+1, mh);
}
} else {
g.setColor(bg);
g.fillRect(mx, my, mw, mh);
}
g.setColor(oldfg);
}
public void renderFrame(Graphics g, BoxedFlob f, int mx, int my,
int md, int mw, int mh) {
g.drawRect(mx-1, my-1, mw, mh);
if(mh >= 14) {
g.drawRect(mx-2, my-2, mw+2, mh+2);
}
}
}

View File

@@ -0,0 +1,109 @@
/*
SimpleFlobConnector.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A simple but powerful raster which uses flob coordinates.
* Z is the selection dimension, X and Y are the flob dimension
* specifications.
*/
public class SimpleFlobConnector implements FlobDecorator, ZOb {
public static final String rcsid = "$Id: SimpleFlobConnector.zob,v 1.9 2000/09/19 10:31:59 ajk Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** Whether the selection dimension is always d.2 or
* whether it is the Z dimension.
*/
boolean selectd2
= true;
/** The path from one handle cell to another.
*/
ZZPath connection
= null;
}
int count;
// public SimpleFlobConnector() { }
// Always middle - to - middle.
public void decorate(final FlobSet f, final String path,
final ZZCell view) {
p("SIMPLEFLOBCNNETOR DECORATE!");
count = 0;
final Hashtable done = new Hashtable();
if(connection == null)
throw new ZZError("Must provide value for FlobConnector connection");
final ConnectionLineDecor.Builder clb = new
ConnectionLineDecor.Builder(f, null);
clb.startl(100, 1);
f.iterDepth(new FlobSet.DepthIter() {
public void act(Flob[] flobs, int start, int n) {
for(int i=start; i<start+n; i++) {
Flob cur = flobs[i];
if(cur.c == null || !cur.flobPath.equals(path))
continue;
// Now, cur.c is the HANDLE cell. So we know
// we can go from it to another handle and
// search the flobset for that.
// XXX Should also show non-existing parents or
// children as stubs.. ???
ZZCell ohandle = connection.readFrom(cur.c, false);
if(ohandle == null) continue;
Flob parent = f.findFlob(path, ohandle);
if(parent == null) continue;
count++;
clb.l(parent, 128, 128, cur, 128, 128);
}
}
}, true);
p("SIMPLEFLOBCNNETOR DECORATED "+count);
clb.endl();
}
}
// vim: set syntax=java :

View File

@@ -0,0 +1,153 @@
/*
SimpleFlobRaster.zob
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A simple but powerful raster which uses flob coordinates.
* Z is the selection dimension, X and Y are the flob dimension
* specifications.
*/
public class SimpleFlobView implements FlobView, ZOb {
public static final String rcsid = "$Id$";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** Whether the selection dimension is always d.2 or
* whether it is the Z dimension.
*/
boolean selectd2
= true;
/** The connectors.
*/
ZOb decorator
= null;
}
Component comp;
static class FlobDim {
String name;
ZZPath num;
ZZPath txt;
FlobDim(ZZCell c) {
name = c.getText();
c = c.s("d.1", 1);
if(c==null) throw new ZZError("Invalid flobdim 1");
ZZCell ps = c.s("d.2", 1);
if(ps==null) throw new ZZError("Invalid flobdim 2");
num = ZZPath.createFromStructure1(ps);
c = c.s("d.1", 1);
if(c==null) throw new ZZError("Invalid flobdim 3");
ps = c.s("d.2", 1);
if(ps==null) throw new ZZError("Invalid flobdim 4");
txt = ZZPath.createFromStructure1(ps);
}
/** Find the zoom record for this dimension and use
* it to scale the output coordinates.
*/
public void findZoom(ZZCell c) {
}
float ozero = 0, omax = 1;
int zero, max;
public void setFinalRange(int zero, int max) {
this.zero = zero; this.max = max;
}
public int getNO(ZZCell c) {
ZZCell r = num.readFrom(c, false);
if(r == null)
return -1;
float f = Float.valueOf(r.getText()).floatValue();
return (int)(((f-ozero)/omax) * max + zero);
}
}
public SimpleFlobView() { }
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
Dimension size = into.getSize();
FlobDim x, y;
String z = null;
ZZCell di = view.s("d.dims", 1);
x = new FlobDim(ZZCursorReal.get(di));
di = di.s("d.dims", 1);
y = new FlobDim(ZZCursorReal.get(di));
if(selectd2)
z = "d.2";
else {
di = di.s("d.dims", 1);
z = ZZCursorReal.get(di).getText();
}
// Find ZOOM factors
ZZCell fz = ZZDefaultSpace.findInheritableParam(view, "FlobZoom");
if(fz == null) {
fz = view.N("d.2", 1);
fz.setText("FlobZoom");
fz.N("d.1", 1);
}
ZZCell zl = fz.s("d.1", 1);
x.findZoom(zl); x.setFinalRange(0, size.width);
y.findZoom(zl); y.setFinalRange(0, size.height);
// XXX better
// This is all our cells.
ZZCell[] cells = accursed.h(z, -1).readRank(z, 1, true);
final int w = 4;
final int h = 4;
// Now get the coordinates.
for(int i=0; i<cells.length; i++) {
ZZCell c = cells[i].h("d.ref", -1);
int xc = x.getNO(c);
int yc = y.getNO(c);
p("C: "+xc+" "+yc);
fact.makeFlob(into, cells[i], c,
1, xc-w/2, yc-h/2, 1, w, h);
}
if(decorator != null) {
if(!(decorator instanceof FlobDecorator))
throw new ZZError("FlobDim decorator must be FlobDecorator: "+
decorator);
((FlobDecorator)decorator).decorate(into, "", view);
}
}
}
// vim: set syntax=java :

View File

@@ -0,0 +1,88 @@
/*
SceneFlob.java
*
* Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benja Fallenstein
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A simple SceneFlob which just draws the given FlobSet, untransformed.
*/
public class SimpleSceneFlob extends SceneFlob {
public static final String rcsid = "$Id: SimpleSceneFlob.java,v 1.4 2001/03/18 17:50:16 bfallenstein Exp $";
public static final boolean dbg = true;
// static final void p(String s) { if(dbg) System.out.println(s); }
// static final void pa(String s) { System.out.println(s); }
public SimpleSceneFlob(int x, int y, int d, int w, int h, ZZCell c, FlobSet sc) {
super(x,y,d,w,h,c,sc);
}
/** Transform the given points between the internal and external coordinates.
* @param toExt Whether to transform internal to external or vice versa.
*/
public void transform(double[] srcPtr, double[]dstPts, boolean toExt) {
if(toExt)
for(int i=0; i<srcPtr.length; i+=2) {
dstPts[i] = srcPtr[i]-x;
dstPts[i+1] = srcPtr[i+1]-y;
}
else
for(int i=0; i<srcPtr.length; i+=2) {
dstPts[i] = srcPtr[i]+x;
dstPts[i+1] = srcPtr[i+1]+y;
}
}
/** Transform the given point between the internal and external coordinates.
* @param toExt Whether to transform internal to external or vice versa.
*/
public Point transform(Point src, Point dst, boolean toExt) {
if(toExt) {
dst.x = src.x + x;
dst.y = src.y + y;
} else {
dst.x = src.x - x;
dst.y = src.y - y;
}
return dst;
}
/** Make this graphics so that we can render into it with the correct
* transformation.
*/
void prepareGraphics(Graphics g, float interpFract) {
if(interpFract == 0) {
g.translate(x, y);
g.setClip(0, 0, w, h);
} else {
g.translate(
(int)(x + interpFract*(interpTo.x-x)),
(int)(y + interpFract*(interpTo.y-y))
);
g.setClip(0, 0,
(int)(w + interpFract*(interpTo.w-w)),
(int)(h + interpFract*(interpTo.h-h))
);
}
}
}

View File

@@ -0,0 +1,84 @@
/*
SimpleTextView.zob
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A view with the text of a single cell, layoutet as an FText.
*/
public class SimpleTextView implements FlobView, ZOb {
public static final String rcsid = "$Id: SimpleTextView.zob,v 1.8 2001/04/02 20:02:51 bfallenstein Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** The font to use. */
Font font
= new Font("SansSerif", Font.PLAIN, 16);
Color fgcolor
= Color.black;
Color bgcolor
= Color.white;
ZOb ftextlayouter
= new FTextLayouter();
}
FontMetrics fm;
INITIALIZE {
fm = FONTMETRICS(font);
}
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
FText ftxt;
if(bgcolor != null) {
ftxt = new FText(new FText.Part[] {
new FText.CellPart(accursed, 0, -1, font, fm, bgcolor, fgcolor)
});
} else {
ftxt = new FText(new FText.Part[] {
new FText.CursorCellPart(accursed, 0, -1, font, fm, null, fgcolor)
});
}
Dimension size = into.getSize();
Rectangle rect = new Rectangle(0, 0, size.width, size.height);
((FTextLayouter)ftextlayouter).place(into, ftxt, rect,
0, rect.y+rect.height/2,
ZZCursorReal.getVisualTextOffset(view),
true, null);
}
}
// vim: set syntax=java :

58
Java/flob/SpanFlob.java Normal file
View File

@@ -0,0 +1,58 @@
/*
SpanFlob.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** An interface to Flobs that contain a single span.
*/
public interface SpanFlob {
String rcsid = "$Id: SpanFlob.java,v 1.5 2000/09/19 10:32:00 ajk Exp $";
/** The previous and following spanflobs.
* These are used for coloring beams: if a beam is being drawn
* between vstreams with a lot of the same content, then
* the beam should have just one color. These fields enable
* the beam drawer to see what the vstream actually is.
* These are to be set by the routine that puts the spanflobs in the
* flobset.
*/
SpanFlob getPrev();
SpanFlob getNext();
void setNext(SpanFlob sf);
/** The span this flob contains. Might not be the same as
* flob.c.getSpan() since this might be just a piece of the cell.
* Can return null.
*/
Span getSpan();
/** Get the rectangle corresponding to the given span. The offs and end
* are given as substring indices to the span returned by getSpan(),
* i.e. the characters offs...end-1 are included.
*/
Rectangle getRectangle(int offs, int end);
}

View File

@@ -0,0 +1,354 @@
/*
SplitCellFlob1.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A cell, possibly split over a line break.
* The broken parts are chained as a linked list.
* The cell of this flob is zero if this is not the first in chain.
* The text is rendered in the lowest part, just so that all of it
* is inside the rectangle.
* <p>
* XXX Rework the nextPart, parent, next, prev relation!
*/
public class SplitCellFlob1 extends Flob implements SpanFlob {
public static final String rcsid = "$Id: SplitCellFlob1.java,v 1.36 2001/04/02 20:21:43 bfallenstein Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
// The XOR modes.
static public final int XOR_NO = 0;
static public final int XOR_LINE = 1;
static public final int XOR_FRAME = 2;
static public final int XOR_SOLID = 3;
public int xormode = XOR_NO;
/** Whether to clip before drawing the contents of this flob. */
public boolean doClip = false;
/** The next part of this flob. */
SplitCellFlob1 nextPart;
/** The first of this chain. */
public SplitCellFlob1 parent;
/** Index of first character. */
public int start;
/** Number of characters. */
public int n;
/** The text in this flob (substring of c.getText()).
* This text is allowed to be modified from outside to allow e.g. for
* firstcap. Doing that in any way that does not retain the number
* and offsets of characters <em>will</em> screw up beams and many other
* things so don't do that ;)
*/
public String txt;
public SpanFlob prev, next;
public SpanFlob getPrev() { return prev; }
public SpanFlob getNext() { return next; }
public void setPrev(SpanFlob sf) {
prev = sf;
if(prev != null) prev.setNext(this);
}
public void setNext(SpanFlob sf) { next = sf; }
public Color bg, fg = Color.black;
Font f;
FontMetrics fm;
/** Set the background of this flob to the color of the topmost cursor. */
public void showCursor() {
// Only take topmost cursor's color
ZZCell curs = getCell().s("d.cursor", 1);
if(curs != null) {
bg = ZZCursorReal.getColor(curs);
if(bg == null)
pa("No cursor color!");
} else
p("No cursors on this cell.");
}
static boolean intostr = false;
public String toString() {
if(intostr) return super.toString();
intostr = true;
String ret = super.toString() + "(SPLCF1 bg="+bg+
"Parent: ("+parent+") stn: "+start+" "+n+" Txt:'"+txt+"' Cell:"+c
+" next: "+nextPart
+ " )";
intostr = false;
return ret;
}
public SplitCellFlob1(int x, int y, int d, int w, int h,
ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent,
int start, int n) {
this(x, y, d, w, h, c, f, fm, parent, start, n, null);
}
public SplitCellFlob1(int x, int y, int d, int w, int h,
ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent,
int start, int n, Color bg) {
this(x, y, d, w, h, c,
c.getText().substring(start, start+n),
f, fm, parent, start, n, bg);
}
public SplitCellFlob1(int x, int y, int d, int w, int h,
ZZCell c, String txt, Font f, FontMetrics fm, SplitCellFlob1 parent,
int start, int n, Color bg) {
super(x, y, d, w, h, (parent==null ? c : null));
p("SplitCellFlob: "+x+" "+y+" "+d+" "+w+" "+h+" "+c+" "+f+" "+
fm+" "+parent+" "+start+" "+n+" "+bg);
this.f = f; this.fm = fm;
if(parent != null) {
if(!parent.c.equals(c))
throw new ZZError(
"Parent and child splitcellflob must have same cell: "+c+
" "+parent.c);
SplitCellFlob1 prev = parent;
while(prev.nextPart != null) prev = prev.nextPart;
prev.nextPart = this;
this.parent = (parent.parent == null ? parent : parent.parent);
}
this.start = start; this.n = n;
this.txt = txt;
this.bg = bg;
p("Created splitcellflob: "+this);
}
public SplitCellFlob1(int x, int y, int d, int w, int h,
ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent,
int start, int n, int xormode) {
this(x, y, d, w, h, c, f, fm, parent, start, n);
}
public SplitCellFlob1(int x, int y, int d, int w, int h,
ZZCell c, Font f, FontMetrics fm, SplitCellFlob1 parent,
int start, int n, int xormode, Color bg) {
this(x, y, d, w, h, c, f, fm, parent, start, n, bg);
this.xormode = xormode;
}
public final ZZCell getCell() {
return (parent==null ? c : parent.c);
}
public Span getSpan() {
Span sp = getCell().getSpan();
if(sp == null) return null;
// XXX test for samity
return sp.subSpan(start, start+n);
}
public Rectangle getRectangle(Span s) {
Span t = getCell().getSpan();
int so = (int)(s.getStart().getOffs() - t.getStart().getOffs());
int eo = (int)(s.getEnd().getOffs() - t.getStart().getOffs());
int sw = fm.stringWidth(txt.substring(0, so));
int ew = fm.stringWidth(txt.substring(0, eo));
return new Rectangle(x + sw, y, ew-sw, h);
}
public Rectangle getRectangle(int offs, int end) {
int sw = fm.stringWidth(txt.substring(0, offs));
int ew = fm.stringWidth(txt.substring(0, end));
return new Rectangle(x + sw, y, ew-sw, h);
}
/* Very quick hack to interpolate from and to non-span flobs:
* let this read render(g0, x, y, d, w, h) instead of render(g0). Not at
* all what the interpolation SHOULD look like, but better than the
* nothing we've had before.
*/
public void render(Graphics g0, int x, int y, int d, int w, int h) {
int my = y + h - fm.getDescent();
// p("SpliCellFlob drawString: '"+txt+"' "+x+" "+my+" "+fg+" "+bg);
Graphics g = g0.create();
Color bu = g.getColor();
if (doClip) g.clipRect(x, y, w, h);
g.setFont(f);
if(bg != null) {
g.setColor(bg);
g.fillRect(x, y, w, h);
}
if(fg != null) g.setColor(fg);
else g.setColor(bu);
p("SpliCellFlob drawString: '"+txt+"' "+x+" "+my+" "+fg+" "+bg);
g.drawString(txt, x, my);
g.dispose();
if(nextPart != null)
nextPart.render(g0);
}
/** Render an interpolated version.
* This is the trickiest routine of this class since we <em>do</em>
* want to get the interpolation behaviour just right so that all text
* pieces flow to where they are supposed to.
*/
public void renderInterp(Graphics g0, float fract) {
if(interpTo==null) return;
if(!(interpTo instanceof SplitCellFlob1)) {
super.renderInterp(g0, fract);
return;
}
SplitCellFlob1 t = this;
SplitCellFlob1 r = (SplitCellFlob1)interpTo;
Graphics g = g0.create();
Shape clip = g.getClip();
if(fg != null) g.setColor(fg);
// Render the correct fragment of the two and advance.
while(t!=null && r!=null) {
if(t.start+t.n < r.start) { t = t.nextPart; continue; }
if(t.start > r.start+r.n) { r = r.nextPart; continue; }
int st = 0;
int en = 0;
if(t.start < r.start) st = r.start;
else st = t.start;
if(t.start+t.n < r.start+r.n) en = t.start+t.n;
else en = r.start+r.n;
int tx = t.getStrX(st);
int rx = r.getStrX(st);
int x = (int)(tx + (rx-tx)*fract);
int ty = t.y + t.h - t.fm.getDescent();
int ry = r.y + r.h - r.fm.getDescent();
int y = (int)(ty + (ry-ty)*fract);
int tw = t.getStrX(en) - tx;
int rw = r.getStrX(en) - rx;
int w = (int)(tw + (rw-tw)*fract);
int realy = (int)(t.y + (r.y-t.y)*fract);
if (doClip) {
g.clipRect(x, realy, w, t.h);
}
if(bg != null) {
Color col = g.getColor();
g.setColor(bg);
g.fillRect(x, realy, tw, t.h);
g.setColor(col);
}
g.setFont(t.f);
g.drawString(t.txt.substring(st-t.start, en-t.start), x, y);
if (doClip) g.setClip(clip);
if(t.start+t.n < r.start+r.n) t = t.nextPart;
else r = r.nextPart;
}
g.dispose();
}
public boolean renderXORLine(Graphics g, int cx, int cy) {
ZZCursorVirtual vc = (ZZCursorVirtual)hit(cx, cy);
if(vc==null) return false;
g.setColor(Color.black);
g.setXORMode(Color.white);
int xo = fm.stringWidth(txt.substring(0, vc.getOffs()-start));
g.drawLine(x+xo, y, x+xo, y+h);
return true;
}
public void renderXORFrame(Graphics g, boolean left, boolean right) {
// XXX instead of using f.h-1 & f.y+1, just don't create overlapping
// XXX SplitCellFlobs any more?
g.setColor(Color.black);
g.setXORMode(Color.white);
SplitCellFlob1 f = parent != null ? parent : this;
if(left) g.drawLine(f.x, f.y+1, f.x, f.y+f.h-1);
while(true) {
g.drawLine(f.x, f.y+1, f.x+f.w, f.y+1);
g.drawLine(f.x, f.y+f.h-1, f.x+f.w, f.y+f.h-1);
if(f.nextPart != null) f = f.nextPart;
else break;
}
if(right) g.drawLine(f.x+f.w, f.y+1, f.x+f.w, f.y+f.h-1);
}
public void renderXORSolid(Graphics g) {
g.setColor(Color.black);
g.setXORMode(Color.white);
SplitCellFlob1 f = parent != null ? parent : this;
for(; f != null; f = f.nextPart) {
g.fillRect(f.x, f.y, f.w, f.h);
}
}
public boolean renderXOR(Graphics g, int cx, int cy) {
if(!insideRect(cx, cy)) return false;
if(xormode == XOR_NO) return true; // XXX or false?
else if(xormode == XOR_LINE) return renderXORLine(g, cx, cy);
else if(xormode == XOR_FRAME) renderXORFrame(g, true, true);
else if(xormode == XOR_SOLID) renderXORSolid(g);
else throw new ZZError("SplitCellFlob1: Unknown XOR mode");
return true;
}
/** Get the x-coordinate of a given letter.
* @param ind The index, given as starting from the beginning of the cell.
* Must satisfy start &lt;= ind &lt;= start+n
*/
public int getStrX(int ind) {
ind -= start;
return x + fm.stringWidth(txt.substring(0,ind));
}
public Object hit(int x, int y) {
if(!insideRect(x, y)) return null;
if(xormode == XOR_FRAME || xormode == XOR_SOLID)
return new ZZCursorVirtual(getCell(), ZZCursorVirtual.NO_OFFSET);
int ind = ZZUtil.findStringHit(txt, x-this.x, fm) + start;
return new ZZCursorVirtual(getCell(), ind);
}
/** Add a line cursor at the given index into the given flobset.
*/
public void addCurs(FlobSet into, int ind, Color c) {
if(parent != null)
parent.addCurs0(into, ind, c);
else
addCurs0(into, ind, c);
}
private void addCurs0(FlobSet into, int ind, Color c) {
if(ind >= start && ind <= start + n) {
int x = getStrX(ind) - 1;
into.add(new LineDecor(x, y, x, y+h,
c, d));
}
if(nextPart != null)
nextPart.addCurs0(into, ind, c);
}
}

78
Java/flob/SplitView.zob Normal file
View File

@@ -0,0 +1,78 @@
/*
SplitView.zob
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benjamin Fallenstein
*/
package org.gzigzag;
import java.awt.*;
/** A view that shows the ctrl and data windows in one. */
public class SplitView implements FlobView, ZOb {
public static final String rcsid = "$Id: SplitView.zob,v 1.1 2000/12/26 15:20:42 bfallenstein Exp $";
/** Should we print out debugging info? */
public static boolean dbg = false;
static final void p(String s) { if(dbg) pa(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {}
public void raster(FlobSet into, FlobFactory fact,
ZZCell win, String[] dims, ZZCell accursed) {
Dimension size = new Dimension(into.getSize());
size.width = size.width / 2;
FlobSet set = into.create(size), otherset = into.create(size);
FlobView view = new VanishingView();
view.raster(set, fact, win, dims, accursed);
boolean isctrl = false;
ZZCell otherwin = win.s("d.ctrlview", -1);
if(otherwin == null) { otherwin=win.s("d.ctrlview"); isctrl=true; }
if(otherwin == null)
throw new ZZError("SplitView invoked for a window which is " +
"not in a control/data pair!");
String[] otherdims = ZZDefaultSpace.getDimList(otherwin);
ZZCell otheracc = ZZCursorReal.get(otherwin);
ZZCell c = ZZDefaultSpace.findInheritableParam(otherwin, "View");
ZZCell rastname = ZZCursorReal.get(c);
ZOb frz = ZZDefaultSpace.readZOb(rastname);
FlobView otherview = null;
if(frz != null && frz instanceof FlobView) {
otherview = (FlobView)frz ;
} else {
System.out.println("getScene: invalid type: "+frz);
otherview = new NullView();
}
otherview.raster(otherset, fact, otherwin, otherdims, otheracc);
if(isctrl) {
FlobSet tmp = set;
set = otherset;
otherset = tmp;
}
into.fetch(otherset, 0, 0, 0);
into.fetch(set, size.width, 0, 0);
}
}

208
Java/flob/StdLinks.zob Normal file
View File

@@ -0,0 +1,208 @@
/*
StdLinks.zob
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class StdLinks implements FlobDecorator {
public static final String rcsid = "$Id: StdLinks.zob,v 1.13.10.1 2002/03/07 21:02:41 bfallenstein Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
STRUCTPARAMS {
/** Whether to draw badly directioned links as splines.
*/
boolean splines
= true;
/** Spline radius.
*/
float splinvec
= 50;
/** Whether the tight-brick mode is used for cells with
* non-shown links.
*/
boolean tightDefault
= false;
/** Whether to draw the links the old way, between corners.
*/
boolean useCorners
= false;
}
static int[] xoffs = new int[] {1, 0, 1};
static int[] yoffs = new int[] {0, 1, 1};
public void decorate(final FlobSet f, final String path,
final ZZCell view) {
final String[] dims = ZZDefaultSpace.getDimList(view);
p("DECORATE STDLINKS");
// Cells whose connections were done.
final Hashtable done = new Hashtable();
final Point p1 = new Point(), p2 = new Point();
final LineDecor.Builder ldb = new LineDecor.Builder(f, null);
f.iterDepth(new FlobSet.DepthIter() {
public void act(Flob[] flobs, int start, int n) {
p("STDLINKS ACT "+start+" "+n+" "+flobs[start].d);
ldb.startl(4*n, flobs[start].d+1);
for(int i=start; i<start+n; i++) {
Flob cur = flobs[i] ;
// p("Do flob ");
if(cur.c == null || !cur.flobPath.equals(path))
continue;
p("Do flob.");
p(" path: "+cur.flobPath);
ZZCell c = cur.c;
p(" cell: "+c);
for(int d=0; d<dims.length; d++) {
if(d >= xoffs.length) break;
// p(" Dim: "+dims[d]);
for(int dir=-1; dir<=1; dir += 2) {
ZZCell neigh = c.s(dims[d], dir);
p(" Neigh: "+neigh+" "+
(neigh!=null?neigh.getText():"")+
" "+(neigh==null?
"nothing" : done.get(neigh)));
if(neigh == null ||
done.get(neigh) != null) continue;
Flob nfl = f.findFlob(path, neigh);
p(" Found: "+nfl);
if(nfl != null)
p(" ...path: "+nfl.flobPath);
// show connections to non-shown cells
// XXX: is this tight-brick? if so, this should be
// made conditional
if(nfl == null) {
// XXX UseCorners!!!
int xo = xoffs[d];
int yo = yoffs[d];
int xh = (xo==0 ? 1 : 0);
int yh = (yo==0 ? 1 : 0);
int df = (dir > 0 ? 1 : 0);
int x1 = cur.x + ((2*xo + xh)*cur.w) / 2;
int y1 = cur.y + ((2*yo + yh)*cur.h) / 2;
int len = 1; // Stub length
int wid = 5; // Stub width
if (dir < 0) {
int cx = cur.x + cur.w / 2;
int cy = cur.y + cur.h / 2;
x1 = x1 - 2 * (x1 - cx) + dir*xo;
y1 = y1 - 2 * (y1 - cy) + dir*yo;
}
int x2 = x1 + dir * xo * len ;
int y2 = y1 + dir * yo * len ;
ldb.l(x1, y1, x2, y2);
ldb.l(x2+dir*yo*wid/2, y2-dir*xo*wid/2,
x2-dir*yo*wid/2, y2+dir*xo*wid/2);
continue;
}
// Now, find line coordinates.
Flob from=null, to=null;
if(dir > 0) {
from = cur; to = nfl;
} else {
from = nfl; to = cur;
}
if(useCorners) {
int xo = xoffs[d];
int yo = yoffs[d];
int xh = (xo==0 ? 1 : 0);
int yh = (yo==0 ? 1 : 0);
ldb.l(
from.x + (2*xo + xh)*from.w / 2,
from.y + (2*yo + yh)*from.h / 2,
to.x + (xh)*to.w / 2,
to.y + (yh)*to.h / 2
);
} else {
from.getCenter(p1);
to.getCenter(p2);
// Check the direction.
// XXX abstract out!
int dx = p2.x - p1.x;
int dy = p2.y - p1.y;
boolean curve = false;
if(splines) {
if(d == 0) { // X
curve = (dx/(2*dy+1) == 0 || dx < 0);
} else if(d == 1) { // Y
curve = (dy/(2*dx+1) == 0 || dy < 0);
} else if(d == 2) { // Z
curve = (
dx / (2*dy+1) != 0 ||
dy / (2*dx+1) != 0 ||
dx < 0 ||
dy < 0
);
}
}
if(curve) {
p("SPLINE! "+d+" "+dx+" "+dy);
int aw = from.w + to.w;
int ah = from.h + to.h;
aw *= 2;
ah *= 2;
int[] curv = ZZUtil.bulgeCurve(
p1.x, p1.y,
xoffs[d] * aw, yoffs[d] * ah,
p2.x, p2.y, -xoffs[d] * aw,
-yoffs[d] * ah,
9
);
for(int p=2; p<curv.length-1; p+=2) {
p(curv[p-2]+" "+curv[p-1]);
ldb.l(curv[p-2], curv[p-1],
curv[p], curv[p+1]);
}
} else
ldb.l(p1.x, p1.y, p2.x, p2.y);
}
}
}
done.put(c, c);
}
ldb.endl();
}
},false);
p("DECORATED STDLINKS");
}
}
// vim: set syntax=java :

73
Java/flob/TextDecor.java Normal file
View File

@@ -0,0 +1,73 @@
/*
TextDecor.java
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuukka Hastrup
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class TextDecor extends Renderable {
public static final String rcsid = "$Id: TextDecor.java,v 1.4 2000/09/19 10:32:00 ajk Exp $";
public static final boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
int[] x;
int[] y;
String[] txt;
Color color;
Font font;
public TextDecor(int x, int y, String txt, Color color, Font font) {
this(new int[] {x}, new int[] {y}, new String[] {txt}, color, font);
}
/** Usual constructor.
*/
public TextDecor(int[] x, int[] y, String[] txt, Color color, Font font) {
this.x = x;
this.y = y;
this.txt = txt;
this.color = color;
this.font = font;
}
public void render(Graphics g) {
Color oldc = null;
if(color != null) {
oldc = g.getColor();
g.setColor(color);
}
Font oldf = null;
if(font != null) {
oldf = g.getFont();
g.setFont(font);
}
for(int i=0;i<txt.length;i++)
g.drawString(txt[i], x[i], y[i]);
if(oldc != null)
g.setColor(oldc);
if(oldf != null)
g.setFont(oldf);
}
}

492
Java/flob/TreeView.zob Normal file
View File

@@ -0,0 +1,492 @@
/*
TreeRaster.zob
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Antti-Juhani Kaijanaho
*/
package org.gzigzag;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import java.util.NoSuchElementException;
/** A flobraster showing the ZZ space as a tree-like structure. */
public class TreeView implements FlobView, ZOb {
public static final String rcsid = "$Id$";
/** Should we print out debugging info? */
public static boolean dbg = false;
static final void p(String s) { if(dbg) pa(s); }
static final void pa(String s) { System.out.println("(flob)TreeRaster: " + s); }
STRUCTPARAMS {
/** The size factor applied to cells. */
float initmul
= (float)1.6;
/** How many recursion levels shall we render (half up, half
down depthwise)? */
int maxdepth
= 4;
/** The distance between neigbouring cells.
*/
int[] gap // 2..2
= new int[] {3, 6};
/** The factor of enlargement of cells as they move away
depthwise from the accursed cell. Element 0 is
horizontal, element 1 is vertical. */
float[] shrink
= new float[] {(float) 0.7, (float) 0.8};
/** Should the tree lines be drawn at all? */
boolean treelines
= true;
/** Should the tree be shown "depthhorizontal", ie. depth rightwards? */
boolean depthhorizontal
= false;
}
int recdepth;
public TreeView() { recdepth = 0; }
/** A dimension vector in the ZZ space. A dimension vector is
immutable. */
private static final class DimVector {
/** The dimension along which this vector goes. */
private String dim;
/** The direction (poswards or negwards) along the dimension. */
private int dir;
/** Constructor from dimension and direction. */
public DimVector(String dim, int dir) {
this.dim = dim;
this.dir = dir;
if (dir == 0) throw new IllegalArgumentException("Direction must be nonzero.");
}
/** Get the dimension along which this vector goes. */
public String getDimension() { return dim; }
/** Get the direction along the dimension. */
public int getDirection() { return dir; }
/** Find a cell's successor along this vector. The successor
of a cell is defined as the neighbour of that cell on the
vector's dimension and direction.
@param c A cell whose successor is wanted.
@return Cell which lies along the vector's dimension and
direction from the parameter cell*/
public ZZCell getCellSuccessor(ZZCell c) {
return c.s(dim, dir);
}
/** Find a cell's predecessor along this vector. The
predecessor of a cell is defined as the neighbour of that
cell on the vector's dimension and negated direction. For
example, if the vector is "poswards along d.1", then a
cell's predecessor is its neighbour negwards along d.1.
@param c A cell whose predecessor is wanted.
@return Cell which lies along the vector's dimension and
negated direction from the parameter cell*/
public ZZCell getCellPredecessor(ZZCell c) {
return c.s(dim, -dir);
}
}
/** Decider of a cell's size on canvas. */
private static final class CellSizeDecider {
/** A precomputed prototype size of a cell. This dimension is
scaled to reach the size of a cell. */
Dimension proto;
/** Get a cell's size with an enlargement factor. */
public Dimension getCellSize(ZZCell c, double frac) {
Dimension rv = new Dimension (proto);
rv.width *= frac;
rv.height *= frac;
return rv;
}
/** Creates an instance from a RasterFlobFactory instance.
The decisions made by CellSizeDecider will be based on the
RasterFlobFactory's decisions. */
public CellSizeDecider(FlobFactory fact) {
proto = fact.getSize(null, 1);
}
}
public class PositionDecider {
private Hashtable cellpos = new Hashtable();
private Hashtable celldepth = new Hashtable();
private Hashtable cellsize = new Hashtable();
private Hashtable extracells = new Hashtable();
private Hashtable cellchildren = new Hashtable();
private int canvaswidth;
private ZZCell accursed;
/** The current breadth coordinate. */
private int currbcoord = 0;
private DimVector breadth;
private DimVector depth;
private Dimension[] gaps;
private Dimension[] csize;
private Dimension[] smcsize; // size of "small" cells
/** Depth coordinates for given depths. */
private int[] dcoord;
private final void py(String s) {
p("PositionDecider(" + currdepth + "): " + s);
}
private int currdepth = 0;
/** Place tree cells.
@return A vector containing the children of this root.
*/
public Vector place_tree_cells(ZZCell root) {
if (currdepth + 1 >= maxdepth) return new Vector();
++currdepth;
Vector rv = new Vector();
py("start");
if (root == null) {
py("root is null");
} else {
py("root is " + root.getID());
}
// position a cell not in the tree that lies left from the root
ZZCell cell = root == null ? null : breadth.getCellPredecessor(root);
if (cell != null && !cellpos.containsKey(cell)) {
Dimension s = smcsize[currdepth];
Dimension pos = new Dimension();
pos.width = currbcoord;
pos.height = dcoord[currdepth]
+ csize[currdepth].height / 2 - s.height / 2;
cellpos.put(cell, pos);
celldepth.put(cell, new Integer(maxdepth + 1));
cellsize.put(cell, s);
extracells.put(cell, cell);
currbcoord += s.width + gaps[currdepth].width;
}
if (root != null && cellpos.containsKey(root)) py("root is known");
int count = 0;
for (cell = root;
cell != null && (!cellpos.containsKey(cell)
|| extracells.containsKey(cell));
cell = breadth.getCellSuccessor(cell)) {
if (extracells.containsKey(cell)) extracells.remove(cell);
py("cell " + cell.getID());
cellpos.put(cell, new Dimension());
rv.addElement(cell);
int startbcoord = currbcoord;
Vector children = place_tree_cells(depth.getCellSuccessor(cell));
int endbcoord = currbcoord;
cellchildren.put(cell, children);
Dimension cs = csize[currdepth];
int dcorr = 0;
// contain too many siblings so that
// eg. d.cellcreation as breadth does not hang;
// however, we must go on until the accursed cell is
// with us.
if (count > canvaswidth / csize[currdepth].width
&& cellpos.containsKey(accursed) && cell != accursed) {
cs = smcsize[currdepth];
dcorr = csize[currdepth].height / 2 - cs.height / 2;
extracells.put(cell, cell);
}
cellsize.put(cell, cs);
Dimension cpos = new Dimension((startbcoord + endbcoord - cs.width) / 2,
dcoord[currdepth] + dcorr);
if (cpos.width < startbcoord) cpos.width = startbcoord;
py("positioning cell " + cell.getID() + " at (" + cpos.width + "," + cpos.height + ")");
cellpos.put(cell, cpos);
celldepth.put(cell, new Integer(currdepth));
if (currbcoord < cpos.width + cs.width + gaps[currdepth].width)
currbcoord = cpos.width + cs.width + gaps[currdepth].width;
// position a cell not in the tree that lies up from the root
ZZCell up = depth.getCellPredecessor(cell);
if (up != null && !cellpos.containsKey(up)) {
Dimension s = smcsize[currdepth];
Dimension pos = new Dimension();
pos.width = cpos.width + csize[currdepth].width / 2 - s.width / 2;
pos.height = cpos.height - s.height - gaps[currdepth].width / 2;
cellpos.put(up, pos);
celldepth.put(up, new Integer(maxdepth + 1));
cellsize.put(up, s);
extracells.put(up, up);
}
if (extracells.containsKey(cell)) break;
count++;
}
py("finish");
--currdepth;
return rv;
}
public PositionDecider(DimVector breadth, DimVector depth,
Dimension fs, FlobFactory fact,
ZZCell accursed) {
this.breadth = breadth;
this.depth = depth;
this.canvaswidth = fs.width;
this.accursed = accursed;
py("created");
gaps = new Dimension[maxdepth];
csize = new Dimension[maxdepth];
smcsize = new Dimension[maxdepth];
dcoord = new int[maxdepth];
gaps[maxdepth/2] = new Dimension(gap[0], gap[1]);
csize[maxdepth/2] = new Dimension(fact.getSize(null, initmul));
if (depthhorizontal) {
int tmp = csize[maxdepth/2].width;
csize[maxdepth/2].width = csize[maxdepth/2].height;
csize[maxdepth/2].height = tmp;
}
dcoord[maxdepth/2] = (depthhorizontal ? fs.width : fs.height) / 2;
for (int i = maxdepth / 2 - 1; i >= 0; i--) {
gaps[i] = new Dimension((int)(gaps[i+1].width * shrink[0]),
(int)(gaps[i+1].height * shrink[1]));
csize[i] = new Dimension((int)(csize[i+1].width * shrink[0]),
(int)(csize[i+1].height * shrink[1]));
dcoord[i] = dcoord[i+1] - (csize[i+1].height + gaps[i+1].height);
}
for (int i = maxdepth / 2 + 1; i < maxdepth; i++) {
gaps[i] = gaps[maxdepth - 1 - i];
csize[i] = csize[maxdepth - 1 - i];
dcoord[i] = dcoord[i-1] + csize[i-1].height + gaps[i-1].height;
}
for (int i = 0; i < maxdepth; i++) {
smcsize[i] = new Dimension(csize[i].width / 4,
csize[i].height / 4);
}
}
public Enumeration getCells() { return cellpos.keys(); }
public Dimension getCellPosition(ZZCell c) {
return new Dimension((Dimension)cellpos.get(c));
}
public int getCellDepth(ZZCell c) {
return ((Integer) celldepth.get(c)).intValue();
}
public Dimension getCellSize(ZZCell c) {
return new Dimension((Dimension)cellsize.get(c));
}
public boolean existCell(ZZCell c) {
return cellpos.containsKey(c);
}
public Enumeration getCellChildren(ZZCell c) {
Object o = cellchildren.get(c);
Vector v;
if (o == null) v = new Vector(); else v = (Vector)o;
return v.elements();
}
}
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
DimVector breadth = new DimVector(dims[0], 1);
DimVector depth = new DimVector(dims[1], 1);
if (depthhorizontal) {
DimVector tmp = breadth;
breadth = depth;
depth = tmp;
}
p("finding the root cell");
ZZCell root;
{
ZZCell cell = accursed;
int count = 0;
Hashtable seen = new Hashtable();
do {
root = cell;
seen.put(root, root);
cell = depth.getCellPredecessor(root);
boolean up = true;
if (cell == null) {
cell = breadth.getCellPredecessor(root);
up = false;
}
if (cell != null && seen.containsKey(cell)) cell = null;
if (cell != null && up) count++;
} while (cell != null && count < maxdepth / 2);
p("done finding the root cell");
}
PositionDecider pd = new PositionDecider(breadth, depth,
into.getSize(),
fact, accursed);
pd.place_tree_cells(root);
Dimension acpos;
if (pd.existCell(accursed)) {
acpos = pd.getCellPosition(accursed);
} else {
pa("FIXME: accursed cell not in modeled tree");
acpos = into.getSize();
acpos.width /= 2;
acpos.height /= 2;
}
int bcorr = acpos.width - (depthhorizontal
? into.getSize().height
: into.getSize().width) / 2;
for (Enumeration e = pd.getCells(); e.hasMoreElements();) {
ZZCell cell = (ZZCell) e.nextElement();
Dimension pos = pd.getCellPosition(cell);
pos.width -= bcorr;
if (depthhorizontal) {
int tmp = pos.width;
pos.width = pos.height;
pos.height = tmp;
}
Dimension cs = pd.getCellSize(cell);
if (depthhorizontal) {
int tmp = cs.width;
cs.width = cs.height;
cs.height = tmp;
}
int d = pd.getCellDepth(cell);
fact.makeFlob(into, cell, cell, 1, pos.width, pos.height,
d, cs.width, cs.height);
// draw tree lines
if (treelines) {
for (Enumeration f = pd.getCellChildren(cell);
f.hasMoreElements();) {
ZZCell child = (ZZCell) f.nextElement();
Dimension cpos = pd.getCellPosition(child);
cpos.width -= bcorr;
if (depthhorizontal) {
int tmp = cpos.width;
cpos.width = cpos.height;
cpos.height = tmp;
}
Dimension chs = pd.getCellSize(child);
if (depthhorizontal) {
int tmp = chs.width;
chs.width = chs.height;
chs.height = tmp;
}
if (depthhorizontal) {
into.add(new LineDecor(pos.width + cs.width,
pos.height + cs.height / 2,
cpos.width,
cpos.height + cs.height / 2,
Color.red,
(pd.getCellDepth(child) + d) / 2));
} else {
into.add(new LineDecor(pos.width + cs.width / 2,
pos.height + cs.height,
cpos.width + chs.width / 2,
cpos.height,
Color.red,
(pd.getCellDepth(child) + d) / 2));
}
}
}
}
// XXX This should be a structparam later on.
(new StdLinks()).decorate(into, "", view);
// Do the dimensions. XXX strings or cells?
if (true) {
Dimension s = fact.getSize(null, 1);
ZZCell bdim = ZZCursorReal.get(view.s("d.dims", 1));
ZZCell ddim = ZZCursorReal.get(view.s("d.dims", 1).s("d.dims", 1));
if (bdim == null || ddim == null) {
throw new ZZError("no dimensions");
}
Flob bfl = fact.makeFlob(into, bdim, bdim, 1, s.width, 0,
1, s.width, s.height);
Flob dfl = fact.makeFlob(into, ddim, ddim, 1, 0, s.height,
1, s.width, s.height);
bfl.flobPath = "dim";
dfl.flobPath = "dim";
int wh = s.width / 2;
int hh = s.height / 2;
into.add(new LineDecor(new int[] { wh, hh, wh, s.height,
wh, hh, s.width, hh },
8, Color.red, 1));
}
}
}
// vim: set syntax=java :

317
Java/flob/VanishingView.zob Normal file
View File

@@ -0,0 +1,317 @@
/*
VanishingView.zob
*
* Copyright (c) 1999-2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/** A reimplementation of the vanishing raster.
* Much simpler than the original one since this one does not try
* to do the hard rasters as well.
*/
public class VanishingView implements FlobView, ZOb {
public static final String rcsid = "$Id: VanishingView.zob,v 1.9 2000/12/11 02:54:44 tjl Exp $";
public static boolean dbg = false;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
// Following are the parameters out of which the constructor
// is created.
STRUCTPARAMS {
/** The factor to shrink the cells with when moving away from
* center.
*/
float[] shrink // 2..2
= new float[] {(float)0.9, (float)0.9};
/** The factor the center cell is enlarged with from default.
*/
float[] initmul // 2..2
= new float[] {(float)1.6, (float)1.6};
/** The factor to enlarge the center cell on top of initmul.
* This only has an effect on the center cell whereas initmul
* affects all cells.
*/
float[] centermul // 2..2
= new float[] {(float)1.0, (float)1.0};
/** The distance between neighbouring cells.
*/
int[] gap // 2..2
= new int[] {5, 5};
/** The depth to raster to.
*/
int depth
= 5;
/** The precedence order of dimensions.
*/
int[] pref // 2..5
= new int[] {0, 1, 2};
/** Whether to allow cell sizes to vary.
*/
boolean varsize
= false;
/** Whether alignment around visual flob center is to be used.
* If true, halign is ignored.
*/
boolean centeralign
= true;
/** Distance reverse perspective.
*/
float revper
= (float)1.00;
/** Horizontal alignment.
* 0 = center, -1 = left, 1 = right.
*/
int halign
= 0;
}
// XXX This should be a structparam later on.
FlobDecorator linker = new StdLinks();
// Offsets of x and y
static int[] xoffs = new int[] {1, 0, 1};
static int[] yoffs = new int[] {0, 1, 1};
public void raster(FlobSet into, FlobFactory fact,
ZZCell view, String[] dims, ZZCell accursed) {
Dimension fs = into.getSize();
// Precalculate sizes and gaps.
int[] xgap = new int[depth];
int[] ygap = new int[depth];
int[] xsize = new int[depth+1];
int[] ysize = new int[depth+1];
float[] sizfact = new float[depth+1];
float xf = initmul[0];
float yf = initmul[1];
Dimension d0 = fact.getSize(null, yf);
Dimension d = (varsize ? fact.getSize(accursed, yf) : d0);
xsize[0] = d.width;
ysize[0] = d.height;
sizfact[0] = yf;
float yf0 = yf, xf0=xf;
for(int i=0; i<depth; i++) {
xf *= shrink[0];
yf *= shrink[1];
xsize[i+1] = (int)(d.width * xf/xf0);
ysize[i+1] = (int)(d.height * yf/yf0);
sizfact[i+1] = yf;
xgap[i] = (int)(gap[0] * xf);
ygap[i] = (int)(gap[1] * yf);
p("D: "+i+" "+xsize[i+1]+" "+xgap[i]);
}
xsize[0] *= centermul[0];
ysize[0] *= centermul[1];
// flob depth multiplier and offset.
// flob depth = d1 + dm*depth
int d1 = 1;
int dm = 10;
int maxd = d1 + dm * depth;
// The set of cells already put into the flobset
Hashtable cellsDone = new Hashtable();
// The set of flobs for which the given dimensions have been finished
// XXX ndims
Hashtable []did = new Hashtable[] {
new Hashtable(),
new Hashtable(),
new Hashtable()
};
// The index up to which the cells have been done
// for the given dimension
// XXX ndims
int dimdone[] = new int[] { 0, 0, 0 };
// The storage of all flobs put.
// Relevant only up to min(dimdone).
Vector cur = new Vector();
int cx = fs.width/2-(1+halign)*xsize[0]/2 + halign * d0.width / 2;
int cy = fs.height/2-ysize[0]/2;
Flob flob = fact.makeFlob(into, accursed, accursed,
sizfact[0] , cx, cy, d1, xsize[0], ysize[0]);
cur.addElement(flob);
cellsDone.put(accursed, accursed);
// p("Van Start: "+isGrid+" "+shrink[0]+" "+gap[0]+" "+xgap[0]);
Flob[] curFlob = new Flob[2];
Point aligned = new Point();
for(int dim = 0; dim < pref.length; dim++) {
boolean added = false;
int start = dimdone[dim];
dimdone[dim] = cur.size();
for(int i=start; i<cur.size(); i++) {
curFlob[0] = curFlob[1] = (Flob)cur.elementAt(i);
if(curFlob[0].d >= maxd) continue;
if(did[dim].get(curFlob[0].c) != null) continue;
did[dim].put(curFlob[0].c, curFlob[0].c);
// Current depth
int curd = (curFlob[0].d - d1) / dm;
ZZIter.NEnum rank = ZZIter.alternate(curFlob[0].c, false, dims[pref[dim]], 1);
ZZCell next;
while((next = rank.nextCell()) != null) {
int curind = (rank.nth() < 0 ? 0 : 1);
int dir = curind * 2 - 1;
int xdep = (rank.nth() < 0 ? -rank.nth() : rank.nth());
Flob f = curFlob[curind];
if(cellsDone.get(next) != null ||
curd + xdep >= depth) {
rank.stop();
continue;
}
cellsDone.put(next, next);
if(centeralign) {
// First, determine alignment.
int xalign = dir * xoffs[pref[dim]];
int yalign = dir * yoffs[pref[dim]];
// Then, find alignment point in last cell,
// centered on center of screen
f.getPoint(aligned, xalign, yalign);
// Using that, find alignment point
// in the next cell.
aligned.x -= fs.width / 2;
aligned.x *= revper;
aligned.x += fs.width / 2;
aligned.y -= fs.height / 2;
aligned.y *= revper;
aligned.y += fs.height / 2;
aligned.x += xalign*xgap[curd+xdep-1];
aligned.y += yalign*ygap[curd+xdep-1];
Dimension size = new Dimension(xsize[curd+xdep],
ysize[curd+xdep]);
f = curFlob[curind] = fact.centerFlob(into, next, next,
sizfact[curd+xdep], aligned, -xalign, -yalign,
d1 + dm * (curd + xdep), varsize ? null : size);
} else {
int x=0, y=0, w=0, h=0;
if(varsize) {
Dimension dvar = fact.getSize(next, sizfact[curd+xdep]);
w = dvar.width;
h = dvar.height;
} else {
w = xsize[curd+xdep];
h = ysize[curd+xdep];
}
// A bit tricky due to flob coords being
// UL corner.
// First, find alignment point in last cell,
// centered on center of screen
int alignedX =
f.x + (halign+1)*f.w/2 - fs.width/2;
int alignedY =
f.y + f.h/2 - fs.height/2;
// Then, using that, find alignment point
// in the next cell.
int xof = xoffs[pref[dim]];
alignedX += dir * xof * (
xgap[curd+xdep-1] + (1-dir*halign) * f.w/2
+ (1+dir*halign) * w/2
);
alignedY += dir * yoffs[pref[dim]] * (
ygap[curd+xdep-1] + f.h/2 + h/2
);
// Expand the coordinate system around the
// origin
alignedX *= revper;
alignedY *= revper;
// Finally, find upper left corner of next cell.
x = alignedX - (halign+1)*w/2 + fs.width/2;
y = alignedY - h/2 + fs.height/2;
p("Vanishing: puttig "+next+
x+" "+y+" "+w+" "+h);
f = curFlob[curind] = fact.makeFlob(into, next, next,
sizfact[curd+xdep], x, y,
d1 + dm * (curd + xdep), w, h);
}
cur.addElement(f);
did[dim].put(f.c, f.c);
added = true;
}
}
// If we added cells, and we're not doing a hard
// raster, start doing dimensions all over again.
if(added) dim = -1;
}
linker.decorate(into, "", view);
// Do the dimensions.
if(true)
ZZUtil.showFlobDims(into, fact, view, 3);
}
}
// vim: set syntax=java :

73
Java/flob/VobSet.java Normal file
View File

@@ -0,0 +1,73 @@
/*
VobSet.java
*
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Tuomas Lukka
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A draft for a new interface to FlobSet.
* The point is that this interface can be implemented by several
* things and we can make dfferent views interact in interesting
* ways.
* <p>
* A VobSet can be thought of as a window in some ways...
*/
abstract public class VobSet implements ZZScene {
public static final String rcsid = "$Id: VobSet.java,v 1.1 2000/12/11 02:54:10 tjl Exp $";
public static final boolean dbg = true;
static final void p(String s) { if(dbg) System.out.println(s); }
static final void pa(String s) { System.out.println(s); }
abstract public Rectangle getBounds();
abstract public int getDepth();
// XXX Make it use ZZDrawing2D to get the bg paint.
abstract public Color getBackground();
abstract public void add(Renderable r);
abstract public void add(Flob f);
// ??? protected void depthColor(Graphics g, int depth) {
abstract public void dump();
/** A callback interface for iterating over the Flobs
* in a FlobSet in depth order.
*/
public interface DepthIter {
void act(Flob[] flobs, int start, int n);
}
/** Iterate a routine over a blocks of same-depth flobs.
*/
abstract public void iterDepth(DepthIter di, boolean frontFirst);
// XXX Spanset?
// abstract public SpanFlob[] findFlobs(Span s);
// abstract public
}

View File

@@ -0,0 +1,129 @@
/*
ClockCellView.zob
*
* Copyright (c) 2000-2001, Ted Nelson and Tuomas Lukka
* Copyright (c) 2001, Benja Fallenstein
*
* You may use and distribute under the terms of either the GNU Lesser
* General Public License, either version 2 of the license or,
* at your choice, any later version. Alternatively, you may use and
* distribute under the terms of the XPL.
*
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
* the licenses.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
* file for more details.
*
*/
/*
* Written by Benja Fallenstein
*/
package org.gzigzag;
import java.util.*;
import java.awt.*;
/** A cell view that shows the contents of a window.
* Use this ZOb as the headcell on d.cellview from the window's cursor cell,
* and that cell will appear as the window's contents.
*/
public class WindowCellView implements FlobFactory, ZOb {
public static final String rcsid = "$Id: WindowCellView.zob,v 1.3 2001/03/18 17:50:16 bfallenstein Exp $";
public static boolean dbg = false;
private static void p(String s) { if(dbg) ZZLogger.log(s); }
private static void pa(String s) { ZZLogger.log(s); }
STRUCTPARAMS {
}
public Dimension getSize(ZZCell c, float fract) {
// XXX use the bounds as specified in the structure
return new Dimension((int)(500*fract), (int)(300*fract));
}
public Flob makeFlob(FlobSet into, ZZCell c0, ZZCell handleCell,
float fract,
int x, int y, int d, int w, int h) {
FlobSet sc = into.create(new Dimension(w, h));
SceneFlob sf = new SimpleSceneFlob(x, y, d, w, h, c0, sc);
CellFlobFactory1.addSolidColors(into, sf, sf);
into.add(sf);
if(w+h < 100) return sf;
ZZCell view = c0.getRootclone();
ZZCell c = ZZDefaultSpace.findInheritableParam(view, "View");
ZZCell rastname = ZZCursorReal.get(c);
ZOb frz = ZZDefaultSpace.readZOb(rastname);
FlobView fr = null;
if(frz != null && frz instanceof FlobView) {
fr = (FlobView)frz ;
} else {
System.out.println("getScene: invalid type: "+frz);
fr = new NullView();
}
// XXX Signal error
c = ZZDefaultSpace.findInheritableParam(view, "CellView");
FlobFactory rff = null;
if(c != null) {
ZZCell cfact = ZZCursorReal.get(c);
ZOb ffzob = ZZDefaultSpace.readZOb(cfact);
rff = (FlobFactory) ffzob;
}
p("WindowCellView: prepare view");
fr.raster(sc, rff, view, ZZDefaultSpace.getDimList(view),
ZZCursorReal.get(view));
p("WindowCellView: view prepared");
if(rff != null) {
Flob rn = rff.placeFlob(sc, rastname, rastname, (float)1.5, w, 0, 1, 1, 0);
rn.flobPath="rastname";
}
return sf;
}
public Flob placeFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract,
int x, int y, int depth,
float xfract, float yfract) {
Dimension d = getSize(c, fract);
return makeFlob(into, c, handleCell, fract,
(int)(x-xfract*d.width),
(int)(y-yfract*d.height),
depth, d.width, d.height);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign,
int depth, Dimension d) {
if(d == null) d = getSize(c, fract);
int x, y;
x = p.x - d.width/2; y = p.y - d.height/2;
if(xalign < 0) x = p.x;
if(xalign > 0) x = p.x - d.width;
if(yalign < 0) y = p.y;
if(yalign > 0) y = p.y - d.height;
p("centerFlob "+p+" "+d+" at "+x+" "+y+" align "+xalign+" "+yalign);
return makeFlob(into, c, handleCell, fract, x, y,
depth, d.width, d.height);
}
public Flob centerFlob(FlobSet into, ZZCell c, ZZCell handleCell,
float fract, Point p, int xalign, int yalign, int depth) {
return centerFlob(into, c, handleCell, fract, p, xalign, yalign,
depth, null);
}
}
// vim: set syntax=java :