!include once #1007377 // Traits for CAL extend WebNode { double x, y; // placement on screen } sclass WebToCAL { BufferedImage img = newBufferedImage(20, 20, Color.white); new CirclesAndLines cal; new Map map; //new Map, Line> lines; S makeLabel(Lisp lisp) { ret web.useCLParse ? conceptLanguageToEnglish(clUnparse(lisp)) : lisp.head; } void convert(final Web web) { L nodes = web.nodes; nodes = listMinusSet(nodes, values(web.relations)); for (WebNode node : nodes) { double x = node.x, y = node.y; if (x == 0 && y == 0) { x = cal_randomCircleCoord(); y = cal_randomCircleCoord(); } Circle c = cal.circle(img, x, y, makeLabel(first(node.labels))); map.put(node, c); for (Lisp l : dropFirst(node.labels)) c.addTrait(makeLabel(l)); } for (Pair p : keys(web.relations)) { WebNode rel = web.relations.get(p); Circle a = map.get(p.a), b = map.get(p.b); if (a == null || b == null) { warn("webToCAL: Circle not found"); continue; } if (a == b) continue; // TODO /*Line line = lines.get(p); if (line == null) lines.put(p,*/ Line line = cal.arrow(a, makeLabel(first(rel.labels)), b); for (Lisp l : dropFirst(rel.labels)) line.addTrait(makeLabel(l)); } cal.onUserMadeCircle = voidfunc(Circle c) { map.put(web.newNode(c.text), c); }; cal.onUserMadeArrow = voidfunc(Arrow a) { web.getRelation(reverseLookup(map, a.a), reverseLookup(map, a.b)).addLabel(a.text); }; cal.onLayoutChange = voidfunc(Circle c) { WebNode node = reverseLookup(map, c); //print("layout change: " + c.text + " " + (node != null)); updateLayout(node); }; cal.onFullLayoutChange = r { //print("full layout change"); for (WebNode web : keys(map)) updateLayout(web); }; } void updateLayout(WebNode node) { if (node == null) ret; Circle c = map.get(node); if (c == null) ret; node.x = c.x; node.y = c.y; // TODO: persist? } } static CirclesAndLines webToCAL(Web web) { new WebToCAL wtc; wtc.convert(web); ret wtc.cal; } static void webToCAL(Web web, CirclesAndLines cal, Canvas canvas) { copyCAL(webToCAL(web), cal); canvas.update(); }