354 lines
9.6 KiB
Plaintext
354 lines
9.6 KiB
Plaintext
|
|
/*
|
||
|
|
TextCloud.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.module;
|
||
|
|
import org.gzigzag.*;
|
||
|
|
import java.util.*;
|
||
|
|
import java.awt.*;
|
||
|
|
import java.io.*;
|
||
|
|
|
||
|
|
/** A text cloud.
|
||
|
|
*/
|
||
|
|
|
||
|
|
public class TextCloud implements FlobView, FlobSet.DragCursor, ZOb {
|
||
|
|
public static final String rcsid = "$Id: TextCloud.zob,v 1.7 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;
|
||
|
|
static SimpleBeamer bmr;
|
||
|
|
|
||
|
|
STRUCTPARAMS {
|
||
|
|
}
|
||
|
|
|
||
|
|
/** The horizontal and vertical offsets of the insertion cursor when
|
||
|
|
* dragging.
|
||
|
|
*/
|
||
|
|
static final int vcursx = -16, vcursy = -16;
|
||
|
|
|
||
|
|
static ZZCell dragItem;
|
||
|
|
static int dragXOffs; static int dragYOffs;
|
||
|
|
|
||
|
|
|
||
|
|
public boolean accept(Object o) {
|
||
|
|
if(!(o instanceof ZZCursor)) return false;
|
||
|
|
ZZCursor c = (ZZCursor) o;
|
||
|
|
if(c.getOffs() == c.NO_OFFSET) return false;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void raster(FlobSet into, FlobFactory fact,
|
||
|
|
ZZCell view, String[] dims, ZZCell accursed) {
|
||
|
|
if(vr == null) {
|
||
|
|
vr = new RankTextView();
|
||
|
|
vr.readParams(null);
|
||
|
|
|
||
|
|
bmr = new SimpleBeamer();
|
||
|
|
bmr.readParams(null);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ZZAbstractView
|
||
|
|
ZZCell cloudmain = ZZCursorReal.get(view);
|
||
|
|
ZZCell curs = ZZCursorReal.get(cloudmain);
|
||
|
|
// p("TEXTCLOUD RASTER");
|
||
|
|
if(cloudmain == null) return;
|
||
|
|
for(ZZCell item = cloudmain.s("d.1", 1);
|
||
|
|
item != null;
|
||
|
|
item = item.s("d.1", 1)) {
|
||
|
|
int[] c = ZZDefaultSpace.paramIntA(item, "Coords", null, 2);
|
||
|
|
if(c==null) {
|
||
|
|
p("NULL COORDS!");
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
ZZCell vstream =
|
||
|
|
item.s("d.2", 1).s("d.1",1);
|
||
|
|
VStream.check(vstream);
|
||
|
|
|
||
|
|
vr.raster(into, vstream, 0, false, c[0], c[1]);
|
||
|
|
if(item == dragItem) {
|
||
|
|
// Draw the arrow
|
||
|
|
|
||
|
|
into.add(new ArrowDecor(c[0], c[1],
|
||
|
|
c[0]+vcursx, c[1]+vcursy, Color.red, 1));
|
||
|
|
into.setDragCursor(this, c[0]+vcursx, c[1]+vcursy);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bmr.decorate(into, "", null);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void stopdrag(ZZScene xi) {
|
||
|
|
p("StopDrag: "+dragItem);
|
||
|
|
if(dragItem == null) return;
|
||
|
|
// Check if the virtual cursor falls on something.
|
||
|
|
// Use itemcoords to get the UL corner of the item
|
||
|
|
// instead of mouse.
|
||
|
|
Point it = itemCoords(dragItem);
|
||
|
|
if(it == null || xi == null) { // Something went out from under us
|
||
|
|
dragItem = null;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Object ob = xi.getObjectAt(it.x+vcursx, it.y+vcursy);
|
||
|
|
p("StopDrag item: "+ob);
|
||
|
|
if(!(ob instanceof ZZCursor)) return;
|
||
|
|
|
||
|
|
// YES! INSERT! Delete the dragged item first.
|
||
|
|
ZZCursor p = (ZZCursor)ob;
|
||
|
|
ZZCell vstr = itemVStream(dragItem);
|
||
|
|
dragItem.delete();
|
||
|
|
dragItem = null;
|
||
|
|
|
||
|
|
VStream.assimilate(p, vstr);
|
||
|
|
|
||
|
|
// XXX Should surround the inserted piece with cuts
|
||
|
|
// so that it's easy to take out again.
|
||
|
|
}
|
||
|
|
|
||
|
|
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) {
|
||
|
|
|
||
|
|
ZZCell viewCell = view.getViewcell();
|
||
|
|
ZZCell cloudmain = ZZCursorReal.get(viewCell);
|
||
|
|
ZZCell viewCursor = null;
|
||
|
|
if(cloudmain!=null) viewCursor = ZZCursorReal.get(viewCell);
|
||
|
|
|
||
|
|
Object ob = null;
|
||
|
|
if(pt != null && xi != null)
|
||
|
|
ob = xi.getObjectAt(pt.x, pt.y);
|
||
|
|
|
||
|
|
|
||
|
|
if(!id.equals("Dragged")) stopdrag(xi);
|
||
|
|
|
||
|
|
p("Text action! '"+id+"' key: "+key);
|
||
|
|
if(id.equals("NEWITEM")) {
|
||
|
|
} else if(id.equals("TESTWIN")) {
|
||
|
|
|
||
|
|
|
||
|
|
ZZCell cloudhome = code.getHomeCell().N("d.2", -1);
|
||
|
|
cloudhome.setText("TextCloud");
|
||
|
|
ZZCell n = newItem(cloudhome, 50,50, null);
|
||
|
|
ZZCell vs1 = n.s("d.2", 1).s("d.1", 1);
|
||
|
|
ZZCursor p = VStream.start(vs1);
|
||
|
|
VStream.insert(p,"TESTTEXT 1");
|
||
|
|
p = VStream.start(vs1);
|
||
|
|
p = VStream.add(p, 4);
|
||
|
|
VStream.insert(p,"FOO");
|
||
|
|
|
||
|
|
ZZCell rc = code.getHomeCell().N("d.2", -1);
|
||
|
|
ZZCell rl = rc.N("d.1", 1);
|
||
|
|
rl.connect("d.2", 1, rl);
|
||
|
|
rl.setText("Textcloud");
|
||
|
|
ZZCell rastname = rl.N("d.1", 1);
|
||
|
|
rastname.setText("TextCloud.Normal");
|
||
|
|
|
||
|
|
// Bindings
|
||
|
|
ZZCell bindhome = code.getHomeCell().N("d.2", -1);
|
||
|
|
bindhome.setText("TCBind");
|
||
|
|
bindhome = bindhome.N("d.1", 1);
|
||
|
|
ZZDefaultSpace.mkCorner(bindhome, actions);
|
||
|
|
|
||
|
|
|
||
|
|
ZZCell v = ZZDefaultSpace.newToplevelView(rc.getSpace(),
|
||
|
|
"textcloud", 100, 100, 600, 600,
|
||
|
|
rl, bindhome,
|
||
|
|
null, null,
|
||
|
|
null,
|
||
|
|
new Color(0xFFFFB1));
|
||
|
|
ZZCursorReal.set(v,cloudhome);
|
||
|
|
ZZCursorReal.set(cloudhome,vs1);
|
||
|
|
|
||
|
|
} else
|
||
|
|
|
||
|
|
// Now, the real actions
|
||
|
|
if(id.equals("NewOrCurs")) {
|
||
|
|
// Now, ob is either a Point or a ZZCursor - for other
|
||
|
|
// things we don't care.
|
||
|
|
// XXX This should be more OO!!!
|
||
|
|
if(ob == null && pt != null) {
|
||
|
|
p("Vc: "+viewCursor);
|
||
|
|
p("CM: "+cloudmain);
|
||
|
|
ZZCell item = newItem(cloudmain, pt.x, pt.y, null);
|
||
|
|
ZZCursor p = itemVStreamStart(item);
|
||
|
|
VStream.setCursorFromPos(cloudmain, p);
|
||
|
|
} else if(ob instanceof ZZCursor) {
|
||
|
|
VStream.setCursorFromPos(cloudmain, (ZZCursor) ob);
|
||
|
|
} else
|
||
|
|
p("Strange xi param "+ob);
|
||
|
|
|
||
|
|
} else if(id.equals("Insert")) {
|
||
|
|
if(key == null) return;
|
||
|
|
if(key.length() > 1) {
|
||
|
|
p("Composite key: "+key);
|
||
|
|
return ;
|
||
|
|
}
|
||
|
|
VStream.insert(VStream.posFromCursor(cloudmain), key);
|
||
|
|
} else if(id.equals("StartDrag")
|
||
|
|
|| id.equals("StartDragCopy")) {
|
||
|
|
if(!(ob instanceof ZZCursor)) {
|
||
|
|
dragItem = null;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
ZZCursor pos = (ZZCursor)ob;
|
||
|
|
// Now, if we can cut, we cut!
|
||
|
|
ZZCell nvstream = null;
|
||
|
|
if(id.equals("StartDragCopy"))
|
||
|
|
nvstream = VStream.separateCopy(pos);
|
||
|
|
else
|
||
|
|
nvstream = VStream.separate(pos);
|
||
|
|
if(nvstream != null) {
|
||
|
|
ZZCell item = newItem(cloudmain, pt.x-10, pt.y-10, nvstream);
|
||
|
|
// We did cut out a part. Whew!
|
||
|
|
dragXOffs = 0;
|
||
|
|
dragYOffs = 0;
|
||
|
|
dragItem = item;
|
||
|
|
} else {
|
||
|
|
dragItem = itemFromVStream(pos.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
Point ip = itemCoords(dragItem);
|
||
|
|
if(ip==null) { p("No item coord"); return; }
|
||
|
|
if(pt==null) { p("No startdrag coord"); return; }
|
||
|
|
dragXOffs = ip.x - pt.x;;
|
||
|
|
dragYOffs = ip.y - pt.y;;
|
||
|
|
} else if(id.equals("Dragged")) {
|
||
|
|
if(dragItem == null) return;
|
||
|
|
if(pt==null) { p("No drag coord"); return; }
|
||
|
|
setItemCoords(dragItem, pt.x + dragXOffs, pt.y + dragYOffs);
|
||
|
|
|
||
|
|
} else if(id.equals("StopDrag")) {
|
||
|
|
stopdrag(xi);
|
||
|
|
return;
|
||
|
|
} else if(id.equals("Cut")) {
|
||
|
|
if(!(ob instanceof ZZCursor)) return;
|
||
|
|
// Put in a cut mark. XXX HOW?
|
||
|
|
VStream.cut((ZZCursor)ob);
|
||
|
|
} else if(id.equals("Backspace")) {
|
||
|
|
VStream.backspace(VStream.posFromCursor(cloudmain));
|
||
|
|
} else if(id.equals("ClearCuts")) {
|
||
|
|
VStream.clearcuts(VStream.posFromCursor(cloudmain));
|
||
|
|
// p("Clear cuts: "+ob);
|
||
|
|
// if(!(ob instanceof ZZCursor)) return;
|
||
|
|
// VStream.clearcuts((ZZCursor)ob);
|
||
|
|
} else if(id.equals("DeleteItem")) {
|
||
|
|
if(!(ob instanceof ZZCursor)) return;
|
||
|
|
ZZCell item = itemFromVStream(((ZZCursor)ob).get());
|
||
|
|
item.delete();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
public ZOb newZOb(String id) {
|
||
|
|
if(id.equals("Normal")) {
|
||
|
|
return new TextCloud();
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
static String[][] actions = {
|
||
|
|
{ "MouseClicked1", "TextCloud.NewOrCurs" },
|
||
|
|
{ "MouseClicked3", "TextCloud.Cut" },
|
||
|
|
{ "Ctrl-MouseClicked3", "TextCloud.DeleteItem" },
|
||
|
|
{ "MouseStartDrag", "TextCloud.StartDrag" },
|
||
|
|
{ "Shift-MouseStartDrag", "TextCloud.StartDragCopy" },
|
||
|
|
{ "MouseDragged1", "TextCloud.Dragged" },
|
||
|
|
{ "Shift-MouseDragged1", "TextCloud.Dragged" },
|
||
|
|
{ "MouseReleased1", "TextCloud.StopDrag" },
|
||
|
|
{ "Shift-MouseReleased1", "TextCloud.StopDrag" },
|
||
|
|
{ "Backspace", "TextCloud.Backspace" },
|
||
|
|
{ "Esc", "TextCloud.ClearCuts" },
|
||
|
|
{ "DEFAULT", "TextCloud.Insert" }
|
||
|
|
};
|
||
|
|
|
||
|
|
static public ZZCell newItem(ZZCell cloud, int x, int y, ZZCell vstream) {
|
||
|
|
ZZCell item = cloud.N("d.1", 1);
|
||
|
|
ZZCell c = item.N("d.2", 1);
|
||
|
|
c.setText("Coords");
|
||
|
|
ZZCell n1 = c.N("d.1", 1);
|
||
|
|
n1.setText(""+x); n1 = n1.N("d.1", 1);
|
||
|
|
n1.setText(""+y);
|
||
|
|
// Note now going up
|
||
|
|
c = c.N("d.2", -1);
|
||
|
|
Scroll s = cloud.getSpace().getStringScroll();
|
||
|
|
// Width 0 - I wonder how this will work..
|
||
|
|
if(vstream != null) {
|
||
|
|
c.connect("d.1", 1, vstream);
|
||
|
|
} else {
|
||
|
|
VStream.create(c, "d.1", 1, Span.create(
|
||
|
|
Address.scrollOffs(s, 1),
|
||
|
|
Address.scrollOffs(s, 0)
|
||
|
|
));
|
||
|
|
}
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
|
||
|
|
static Point itemCoords(ZZCell item) {
|
||
|
|
int[] c = ZZDefaultSpace.paramIntA(item, "Coords", null, 2);
|
||
|
|
if(c==null) {
|
||
|
|
p("NULL COORDS!");
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
return new Point(c[0], c[1]);
|
||
|
|
}
|
||
|
|
static void setItemCoords(ZZCell item, int x, int y) {
|
||
|
|
ZZCell c = ZZDefaultSpace.findInheritableParam(item, "Coords");
|
||
|
|
c = c.s("d.1", 1); c.setText(""+x);
|
||
|
|
c = c.s("d.1", 1); c.setText(""+y);
|
||
|
|
}
|
||
|
|
|
||
|
|
static public ZZCell itemVStream(ZZCell item) {
|
||
|
|
return item.s("d.2", 1).s("d.1", 1);
|
||
|
|
}
|
||
|
|
static public ZZCursor itemVStreamStart(ZZCell item) {
|
||
|
|
return VStream.start(itemVStream(item));
|
||
|
|
}
|
||
|
|
static public ZZCell itemFromVStream(ZZCell c) {
|
||
|
|
return c.h("d.2", -1)
|
||
|
|
.h("d.1", -1)
|
||
|
|
.h("d.2", -1);
|
||
|
|
}
|
||
|
|
|
||
|
|
static public ZZCell cloudHomeFromVStream(ZZCell c) {
|
||
|
|
ZZCell cloudmain = c.h("d.2", -1)
|
||
|
|
.h("d.1", -1)
|
||
|
|
.h("d.2", -1)
|
||
|
|
.h("d.1", -1);
|
||
|
|
if(! cloudmain.getText().equals("TextCloud")) {
|
||
|
|
p("NOT CLOUD!");
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
return cloudmain;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// vim: set syntax=java :
|