/* 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 :