sclass JG22Network is Swingable { G22Utils g22utils; new MainPanel mainPanel; new G22Network network; Map elementToComponent = syncMap(); ReliableSingleThread rstUpdate = rstWithPreDelay(0.25, l0 updateImpl); JCheckBox cbAutoCalculate; settable int maxMagneticDistance = 100; settable double autoCalcInterval = 0.1; // example instance of the network so we can test it immediately settable volatile G22NetworkInstance networkInstance; // margin on bottom/right transient int margin = 50; // The MainPanel holds the network elements class MainPanel extends JPanel { *() { super(null); } // no layout manager // to allow overlapping components public bool isOptimizedDrawingEnabled() { false; } public Dimension getPreferredSize() { Rect r = combinedChildBounds(this); if (r == null) r = rect(0, 0, 0, 0); //_print("JG22Network.getPreferredSize = " + r); ret new Dimension(r.x2()+margin, r.y2()+margin); } void revalidateMe() { //_print("JG22Network.revalidateMe"); //awtLater(0.5, -> { revalidateIncludingFullCenterContainer(this); repaint(); //}); } public void paintComponent(Graphics g) { cast g to Graphics2D; fillRect(g, 0, 0, getWidth(), getHeight(), Color.white); for (cable : network.allCables()) { Rect r1 = cable.from.bounds(); Rect r2 = cable.to.bounds(); drawLine(g, center(r1), center(r2), Color.black); } } } *(G22Utils *g22utils, G22Network *network) { network.onChangeAndNow(l0 networkChanged); for (element : network.elements) visualizeElement(element); } void networkChanged { rstUpdate.trigger(); } void updateImpl { if (networkInstance == null) makeInstance(); visualizePorts(); } void visualizePorts { awt { Map visualizations = new Map; for (port : directChildrenOfType(mainPanel, JG22NetworkPort)) visualizations.put(port.port, port); // Create new ones for (e : network.elements) { var c = elementToComponent.get(e); if (c == null) print("No component for " + e); else for (port : e.ports) { //print("Visualizing port " + port); var p = visualizations.get(port); if (p != null) { p.update(); visualizations.remove(port); } else { p = new JG22NetworkPort(g22utils, c, port); p.init(); mainPanel.add(p); } } } // Remove old visualizations for (port : values(visualizations)) removeFromParent(port); mainPanel.repaint(); }} void makeInstance { var networkInstance = new G22NetworkInstance(network); networkInstance.onDirtyStatesChanged(l0 dirtyStatesChanged); networkInstance.init(g22utils); networkInstance(networkInstance); dirtyStatesChanged(); print("Network instance made"); } void dirtyStatesChanged { for (component : values(elementToComponent)) component.updateDirtyFlag(); } void visualizeElement(G22NetworkElement element) swing { var c = new JG22NetworkElement(g22utils, this, element); elementToComponent.put(element, c); var component = c.visualize(); mainPanel.add(component); mainPanel.revalidateMe(); componentToFront(component); } void newInstance { networkInstance = null; rstUpdate.trigger(); } void newElement { new G22NetworkElement element; element.network(network); network.elements.add(element); network.change(); visualizeElement(element); } void deleteElement(JG22NetworkElement element) { network.elements.remove(element.element); network.change(); mainPanel.remove(element.visualize()); mainPanel.repaint(); } void doMagneticConnections { var newCables = network.doMagneticConnections(); fOr (cable : newCables) networkInstance.invalidateNode(cable.to().element()); mainPanel.repaint(); } void configureNodes { for (element : network.elements) element.configureBlueprint(g22utils); } void calculationStep { var node = networkInstance?.calculateOneNode(g22utils); if (node == null) ret; elementToComponent.get(node).visualizeNode(); } cachedVisualize { cbAutoCalculate = jVarCheckBox("Auto-calculate", network.varAutoCalculate()); awtCalcEvery(mainPanel, autoCalcInterval, -> { if (isChecked(cbAutoCalculate)) calculationStep(); }); var magneticDistanceSlider = jLiveValueSlider_int_bothWays(0, maxMagneticDistance, network.varMagneticDistance()); ret withRightAlignedButtons(/*jscroll_center_borderless*/jscroll(mainPanel), cbAutoCalculate, withLabel("Magnetic auto-connect distance:", jMinWidth(maxMagneticDistance, magneticDistanceSlider)), "Do magnetic connections", rThread doMagneticConnections, "Configure nodes", rThread configureNodes, "New instance", rThread newInstance, "New node", rThread newElement); } }