interface drawable{
int render(int x ,int y);
 
}
 
 
class lineToken implements drawable{
 
String txt;
int col = 0;
lineToken(String txt, int col){
this.txt = txt;
this.col = col;
Integer tmp = (Integer)colorings.get(txt);
if (tmp != null) this.col = tmp.intValue();
 
}
int render(int x, int y){
fill(col);
 
text(txt,x,y);
return txt.length();
}
 
}
class graphicToken implements drawable{
 
Vector sketch;
int col = color(128);
int anchorLine;
String rep;
graphicToken(Vector sketch, int anchorLine){
 
this.sketch = sketch;
this.anchorLine = anchorLine;
rep = toString();
 
}
int render(int x, int y){
fill(col);
//find out if this has moved and readjust accordingly
int currLine = y/fontHeight;
pushMatrix();
translate(0,(currLine-anchorLine) * fontHeight);
renderSketch(sketch);
popMatrix();
text("<>",x,y);
//text(rep,x,y);
return 0;
}
String toString(){
StringBuffer toRet = new StringBuffer();
toRet.append("//SGSketch " + anchorLine + " ");
Object obj;
Tuple2f temp;
for (int i =1; i < sketch.size(); i++){
if (sketch.elementAt(i) instanceof Tuple2f){
temp = (Tuple2f)sketch.elementAt(i);
toRet.append(temp.toString());
}
else{
toRet.append((String)sketch.elementAt(i));
}
toRet.append(" ");
}
return toRet.toString();
}
 
}
class Page{
 
Vector lines;
String name;
 
public Page(String name, Vector lines){
this.name = name;
this.lines = lines;
}
 
 
}
 
void populateHash(){
 
Integer resJava = new Integer(color(150,0,0));
Integer resProcessing = new Integer(color(150,0,0));
Integer resScreamy = new Integer(color(150,60,0));
Integer primitive = new Integer(color(0,0,150));
colorings.put("int",primitive);
colorings.put("float",primitive);
 
colorings.put("new",resJava);
colorings.put("void",resJava);
colorings.put("Vector",resJava);
colorings.put("public",resJava);
colorings.put("private",resJava);
colorings.put("protected",resJava);
colorings.put("import",resJava);
colorings.put("if",resJava);
colorings.put("this",resJava);
 
colorings.put("PImage",resProcessing);
colorings.put("size",resProcessing);
colorings.put("frameRate",resProcessing);
colorings.put("PFont",resProcessing);
colorings.put("setup",resProcessing);
colorings.put("loadFont",resProcessing);
colorings.put("textFont",resProcessing);
colorings.put("draw",resProcessing);
colorings.put("vertex",resProcessing);
 
colorings.put("SGCamera",resScreamy);
colorings.put("SGBackground",resScreamy);
colorings.put("SGQuickVar",resScreamy);
colorings.put("Tuple",resScreamy);
colorings.put("Gradient",resScreamy);
}
//created=02 Apr 08
//description=Vector graphics to augment source code
//title=Source
//titlebar=Sketching in Code
//publish=false
 
 
import Tuple.*;
import InterpolatedVar.*;
import SGPlanarCam.*;
import java.util.Hashtable;
import java.util.List;
import SGImplify.*;
import javax.swing.*;
 
static final int DRAW_LINE = 0;
static final int TRANSLATE = 1;
 
int mouseMode = 1;
 
SGPlanarCam cam;
 
Vector pages = new Vector();
 
Vector lines = new Vector();
Vector lineTokens = new Vector();
 
PFont font;
 
int leftMargin = 10;
int topMargin = 10;
int fontHeight = 13;
int fontWidth = 7;
 
int offSet = 0;
int carX,carY = 5;
 
Vector currentStroke = null;
 
Hashtable colorings = new Hashtable();
 
 
String scriptFile = null;
String workingFile;
//String scriptFile = "c:\\SGWeb\\sketchableSource\\src\\tgtd.zip";
 
void setup(){
 
populateHash();
 
size(550,550);
frameRate(60);
font = loadFont("mono12.vlw");
 
 
if (online){
 
URL base = getDocumentBase();
URL root = getCodeBase();
StringTokenizer st = new StringTokenizer(base.toString(),"#");
if (st.countTokens() > 1){
st.nextToken();
scriptFile = root + "//src
println("opening" + scriptFile);
}
}
 
 
cam = new SGPlanarCam(this,new FOLagInterpolatedVar(this,0,2),new FOLagInterpolatedVar(this,0,2),new FOLagInterpolatedVar(this,1,2),new FOLagInterpolatedVar(this,0,4));
cam.cx.setVal(width/2);
cam.cy.setVal(height/2);
cam.setMouseMode(RIGHT,SGPlanarCam.TRANSLATE);
smooth();
 
}
 
 
void draw(){
 
if (scriptFile != null){
parseFile(scriptFile);
 
}
 
background(255);
cam.feed();
 
textFont(font);
 
 
//which lines will fit on the screen?
 
//bottom screen coord
Tuple2f bottom = cam.screenToWorld(0,height);
Tuple2f top = cam.screenToWorld(0,0);
//convert world coords to textspace -- which line would be at that worldspace
//add one to prevent pop in
int bottomLine = (int)bottom.y/fontHeight + 1;
int topLine = (int)top.y/fontHeight;
 
 
//draw the lines
for (int i =0; i < constrain(bottomLine,0,lines.size()); i++){
lineRender((Vector)lineTokens.elementAt(i),i);
}
 
 
if (currentStroke != null) renderSketch(currentStroke);
}
 
// line is the text
// index is lineNumber
void lineRender(Vector line, int index){
int uy = index*fontHeight;
 
//if this is the current line, highlight it
if (index == carY){
 
noStroke();
fill(240,240,255,255);
rect(0,uy+2,width,fontHeight);
 
//draw the caret
stroke(0);
line(carX*fontWidth,uy+2,carX*fontWidth,uy+2 + fontHeight);
 
}
fill(0);
stroke(0);
 
 
int dx = 0;
for (int i =0; i < line.size(); i++){
dx += ((drawable)line.elementAt(i)).render(dx*fontWidth,uy + fontHeight);
}
 
 
}
 
 
 
 
//take the text representation of a line and return the renderable tokenized vector of it
Vector parseLine(String line){
Vector tmp = new Vector(5);
 
//first, check if it is a sketch...
if (line.startsWith("//SGSketch")){
StringTokenizer bn = new StringTokenizer(line," []");
bn.nextToken(); //trash the identifier
int anchorLine = new Integer(bn.nextToken()).intValue();
Vector sketch = new Vector();
String st;
while (bn.hasMoreTokens()){
st = bn.nextToken();
if (!st.contains(":")){
sketch.add(st);
}
else{
sketch.add(new Tuple2f(st));
}
}
tmp.add(new graphicToken(sketch,anchorLine));
return tmp;
}
else{
//check for comments
String splt [] = (line).split("//");
 
//check for reserved word
StringTokenizer bn = new StringTokenizer(splt[0]," ()[].",true);
 
while (bn.hasMoreTokens()){
tmp.add(new lineToken(bn.nextToken(),0));
}
 
 
if (splt.length > 1) tmp.add(new lineToken("//" + splt[1],color(128)));
 
return tmp;
}
}
 
 
void mousePressed(){
 
if (currentStroke == null && mouseMode == DRAW_LINE){
currentStroke = new Vector();
currentStroke.add("//SGSketch ");
currentStroke.add(cam.screenToWorld(mouseX,mouseY));
 
}
//carY = (mouseY-topMargin)/fontHeight + (int)offSet;
 
}
 
void mouseReleased(){
 
if (mouseMode == DRAW_LINE && mouseButton == LEFT) currentStroke.add("break");
 
}
 
void mouseDragged(){
 
//don't draw the line if the viewcamera ate it
if (!mouseEvent.isConsumed()){
if (currentStroke != null) currentStroke.add(cam.screenToWorld(mouseX,mouseY));
}
 
}
 
void renderSketch(Vector cStroke){
 
Tuple2f a,b;
stroke(50);
strokeWeight(2.5);
a = ( Tuple2f)cStroke.elementAt(1);
for(int j = 2; j < cStroke.size();j++ ){
 
if (cStroke.elementAt(j) instanceof Tuple2f){
 
b = ( Tuple2f)cStroke.elementAt(j);
line(b.x,b.y,a.x,a.y);
a = b;
}
else if (cStroke.size() > j+1){
j++;
a = ( Tuple2f)cStroke.elementAt(j);
}
}
 
}
 
 
void keyPressed(){
println(keyCode);
if (keyCode == DOWN){
carY++;
String st = (String)lines.elementAt(carY);
if (carX > st.length()) carX = st.length();
}
else if (keyCode == UP){
if (carY > 0){
carY--;
String st = (String)lines.elementAt(carY);
if (carX > st.length()) carX = st.length();
}
}
else if (keyCode == RIGHT){
carX++;
}
else if (keyCode == LEFT){
carX--;
}
else if (keyCode == SHIFT){
println("shiftkey");
}
 
//F2
else if (keyCode == 113){
openFileDialog();
}
//F3
else if (keyCode == 114){
saveFileDialog();
}
 
//F1
else if (keyCode == 112){
if (mouseMode == TRANSLATE){
mouseMode = DRAW_LINE;
 
}
else{
mouseMode = TRANSLATE;
 
//simplify this line
Tuple2f [] artmp = new Tuple2f[currentStroke.size()-1];
int begin = 1, end = 1;
List sub;
Vector path = new Vector();
path.add("//SGSketch ");
for (int i =1; i < currentStroke.size(); i++){
if (currentStroke.elementAt(i) instanceof String){
end = i;
 
//simplify this segment
sub = currentStroke.subList(begin,end);
 
//call sgimplify to reduce the complexity of the line
Tuple2f [] brg = (Tuple2f [])sub.toArray(new Tuple2f[0]);
path.addAll(Arrays.asList(SGImplify.simplifyLine2D(3,brg)));
begin = i + 1;
path.add(" break ");
}
 
//artmp[i] = (Tuple2f)currentStroke.elementAt(i);
}
/*
currentStroke = new Vector();
currentStroke.addAll(Arrays.asList(SGImplify.simplifyLine2D(5,artmp)));
*/
//create new line for this to go on
Vector tmp = new Vector();
graphicToken gt = new graphicToken(path,carY);
tmp.add(gt);
currentStroke = null;
 
lines.insertElementAt(gt.toString(),carY);
lineTokens.insertElementAt(tmp,carY);
 
}
}
else if (keyCode == ENTER){
lines.insertElementAt("",carY);
lineTokens.insertElementAt(new Vector(),carY);
carY++;
}
else if (keyCode == BACKSPACE){
//are they trying to delete the line?
if (carX == 0){
String modLine = (String)lines.elementAt(carY-1);
carX = modLine.length();
 
modLine = modLine + (String)lines.elementAt(carY);
 
lines.removeElementAt(carY-1);
lines.insertElementAt(modLine,carY-1);
 
lines.removeElementAt(carY);
lineTokens.removeElementAt(carY);
 
lineTokens.removeElementAt(carY-1);
lineTokens.insertElementAt(parseLine(modLine),carY-1);
carY--;
 
}
else{
String modLine = (String)lines.elementAt(carY);
modLine = modLine.substring(0,carX-1) + modLine.substring(carX,modLine.length());
lines.removeElementAt(carY);
lines.insertElementAt(modLine,carY);
 
//tokenize the line
lineTokens.removeElementAt(carY);
lineTokens.insertElementAt(parseLine(modLine),carY);
carX--;
}
}
 
 
 
else {
String modLine = (String)lines.elementAt(carY);
modLine = modLine.substring(0,carX) + key + modLine.substring(carX,modLine.length());
lines.removeElementAt(carY);
lines.insertElementAt(modLine,carY);
 
//tokenize the line
lineTokens.removeElementAt(carY);
lineTokens.insertElementAt(parseLine(modLine),carY);
carX++;
 
}
 
carX = constrain(carX,0,1000);
}
 
 
void openFileDialog(){
 
 
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
JFileChooser fc = new JFileChooser();
// fc.setFileFilter(new GlideFilter());
int returnVal = fc.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File selFile = fc.getSelectedFile();
if (selFile != null){
 
scriptFile = selFile.getPath();
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
);
 
 
}
 
void saveFileDialog(){
 
//doesn't work -- inserts brackets around figures. do manually
saveStrings(workingFile,(String [])lines.toArray( new String[lines.size()]));
 
/*
String [] tmp = new String[lines.size()];
for (int i =0; i < lines.size(); i++){
tmp[i] = (String)lines.elementAt(i);
}
*/
//saveStrings("c:
 
/*
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
JFileChooser fc = new JFileChooser();
// fc.setFileFilter(new GlideFilter());
int returnVal = fc.showSaveDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File selFile = fc.getSelectedFile();
if (selFile != null){
String outName = selFile.getAbsolutePath();
print(outName);
if (outName.toLowerCase().endsWith(".gld") ){
//writeOut(outName);
}
else{
//writeOut(outName+".gld");
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
);
*/
}
 
void loadFile(String filename){
 
try{
 
URL base = new URL(getCodeBase(),"./src/" + filename);
scriptFile = base.toString();
 
}
catch (Exception e){
println("couldn't open file." + e );
 
}
}
 
void parseFile(String file){
 
//pages = new Vector();
lines = new Vector();
if (file.endsWith(".zip")){
 
try{
 
URL url = new URL(file);
InputStream stream = url.openStream();
ZipInputStream in = new ZipInputStream(stream);
ZipEntry entry = in.getNextEntry();
 
while(entry != null){
 
println(entry.getName());
BufferedReader read = new BufferedReader(new InputStreamReader(in));
 
while(read.ready()){
lines.add(read.readLine());
}
entry = in.getNextEntry();
}
}
catch(Exception e){
println(e);
}
}
else{
 
lines = new Vector(Arrays.asList(loadStrings(file)));
 
}
 
lineTokens = new Vector();
//parse the lines
for (int i=0; i < lines.size(); i++){
lineTokens.add(parseLine((String)lines.elementAt(i)));
}
workingFile = scriptFile;
scriptFile = null;
}