persistable sclass G22NetworkElement > MetaWithChangeListeners { // network element belongs to settable G22Network network; // position in visual representation settable Rect bounds; // identifier in network (optional) settableWithVar S identifier; // script code to adapt element and to create instance settableWithVar S code; // general properties map depending on element type Map properties = syncMap(); // Is code panel visible in GUI settableWithVar bool codeVisible = true; { onChange(-> { network?.change(); }); } class Port extends MetaWithChangeListeners is IUnstructured { // position on element's border (0 to 1, 0 to 1) settableWithVar DoublePt position; // name of port within element settableWithVar S name; // cable attached to this port (optional) settableWithVar G22NetworkCable cable; // is it output or input? settableWithVar bool isOutput; // type of object sent through port settableWithVar Class dataType; G22NetworkElement element() { ret G22NetworkElement.this; } toString { ret (isOutput ? "Output" : "Input") + " port" + " " + quote(name) + " of type " + shortClassName(dataType); } Rect bounds() { int size = 10; Rect r = element().bounds; if (r == null) null; r = growRectTopAndLeft(r, size); ret rect(r.x+iround(position.x*r.w), r.y+iround(position.y*r.h), size, size); } void delete() { disconnect(); ports.remove(this); change(); } void disconnect { cable?.remove(); } bool isConnected() { ret cable != null; } public void _doneLoading { onChange(-> element().change()); } } L ports = syncL(); LASCompileResult newCompileResult() { ret new LASCompileResult; } transient LASCompileResult compileResult; LASCompileResult compile(G22Utils g22utils) { S code = unnull(this.code); //if (code == null) null; var cr = compileResult; if (cr != null && eq(cr.script, code)) ret cr; cr = newCompileResult(); var parser = g22utils.leftArrowParser(); configureParser(parser); cr.script(code).parser(parser).compile(); ret compileResult = cr; } void configureParser(GazelleV_LeftArrowScriptParser parser) { parser.addVar("blueprint"); parser.addVar("instance"); } GazelleV_LeftArrowScript.Script compileScript(G22Utils g22utils) { var compiled = compile(g22utils); if (compiled == null) null; if (!compiled.runnable()) null; ret compiled!; } void configureBlueprint(G22Utils g22utils) { var script = compileScript(g22utils); if (script == null) ret; new FlexibleVarContext ctx; var f = script.getFunction("configure"); if (f != null) f.call(ctx, this); } O makeInstance(G22Utils g22utils, G22NetworkInstance networkInstance) { var script = compileScript(g22utils); if (script == null) null; new FlexibleVarContext ctx; for (port : ports) if (!port.isOutput() && port.cable != null) { var outputPort = port.cable.from; if (outputPort != null) ctx.set(port.name, networkInstance.getObjectForBlueprint(outputPort.element())); } ret script.get(ctx); } // Nodes that we directly depend on Set upstreamNodes() { new Set set; for (port : ports) if (!port.isOutput() && port.cable != null) { var outputPort = port.cable.from; if (outputPort != null) set.add(outputPort.element()); } ret set; } // Nodes that directly depend on this one Set downstreamNodes() { new Set set; for (port : ports) if (port.isOutput() && port.cable != null) { var outputPort = port.cable.to; if (outputPort != null) set.add(outputPort.element()); } ret set; } toString { ret or2(identifier(), "Unnamed element"); } Port getPort(S name) { ret firstThat(ports, p -> eq(p.name, name)); } void addPort(Port port) { port.onChange(l0 change); ports.add(port); } void addPort aka addSlot(S name, DoublePt etc position) { printFunctionCall("addPort", +name, +position); Port p = getPort(name); if (p != null) ret; addPort(new Port().name(name).position(position)); change(); } void addInputPort(S name, DoublePt etc position, Class type) { Port p = getPort(name); if (p != null) ret; addPort(new Port().name(name).position(position) .isOutput(false).dataType(type)); change(); } void addOutputPort(S name, DoublePt etc position, Class type) { Port p = getPort(name); if (p != null) ret; p = new Port().name(name).position(position) .isOutput(true).dataType(type); addPort(p); print("Made port " + p); change(); } void removePorts aka deletePorts aka removeSlots aka deleteSlots() { while (nempty(ports)) last(ports).delete(); } void removeOutputPorts { for (p : filter(ports, p -> p.isOutput())) p.delete(); } void removeInputPorts { for (p : antiFilter(ports, p -> p.isOutput())) p.delete(); } L ports() { ret cloneList(ports); } // key and value must be persistable! void setProperty(O key, O value) { properties.put(key, value); change(); } O getProperty(O key) { ret properties.get(key); } void autoCreateOutputPort(G22NetworkInstance.Value myValue) { if (myValue == null) ret; removeOutputPorts(); O o = myValue.object(); Class type = or(_getClass(o), O); addOutputPort("output", 1, 0.5, type); } void autoCreateInputPorts(G22Utils g22utils) { removeInputPorts(); var script = compile(g22utils)!; int n = l(script.params); int i = 0; fOr (name, valueDescriptor : script.params) { double y = doubleRatio(++i, (n+1)); addInputPort(name, 0, y, or(valueDescriptor.javaClass(), O)); } } selfType defaultName(S name) { if (empty(identifier())) identifier(name); this; } }