srecord noeq JG22NetworkPort(G22Utils g22utils, JG22NetworkElement element, G22NetworkElement.Port port) > JPanel { int size = 10; Color outputColor() { ret Color.green; } Color inputColor() { ret Color.red; } void init { bindChangeListenerToComponent(this, port, l0 update); componentPopupMenuItems(this, "Show value", rThread showValue, "Disconnect", rThread disconnect, "Delete port", rThread delete); onMouseDown(this, event -> { var dragger = new ComponentDragger(this, event); dragger.updatePosition = (x, y) -> { Pt p = pt(x, y); Rect r = toRect(main getBounds(element.visualize())); double dTop = distancePointToLineSegment(pt(r.x, r.y), pt(r.x2(), r.y), p); double dBottom = distancePointToLineSegment(pt(r.x, r.y2()), pt(r.x2(), r.y2()), p); double dLeft = distancePointToLineSegment(pt(r.x, r.y), pt(r.x, r.y2()), p); double dRight = distancePointToLineSegment(pt(r.x2(), r.y), pt(r.x2(), r.y2()), p); double min = doubleMin(dTop, dBottom, dLeft, dRight); DoublePt pos = doublePt( clampZeroToOne(doubleRatio(x-r.x, r.w)), clampZeroToOne(doubleRatio(y-r.y, r.h))); if (min == dTop) pos.y = 0; else if (min == dBottom) pos.y = 1; else if (min == dLeft) pos.x = 0; else pos.x = 1; port.position(pos); }; dragger.bringToFront(true).start(); }); update(); } void update { _print("Updating port " + port); setOpaque(true); setBackground(port.isOutput() ? outputColor() : inputColor()); setSize(size, size); // TODO: merge with backend computation Rect r = toRect(main getBounds(element.visualize())); r = growRectTopAndLeft(r, size); setLocation(r.x+iround(port.position.x*r.w), r.y+iround(port.position.y*r.h)); setToolTip(this, str(port)); _print("Port " + port.name + " : " + getBounds()); } void showValue { G22NetworkElement e; if (port.isOutput()) e = port.element(); else e = port.cable.from.element(); var value = element.parent.networkInstance.getObjectForBlueprint(e); showFrame("Port value", G22JavaObjectVisualizer(g22utils, value)); } void disconnect { port.disconnect(); } void delete { port.delete(); } }