This code, taken from MovableLinkApp and extended, allows Alt-mouse-down over white space to snap a “Start Link” from the nearest port.
New code highlighted in blue.
[Serializable]
public class LinkingNewTool : GoToolLinkingNew {
public LinkingNewTool(GoView v) : base(v) {}
public override IGoPort PickNearestPort(PointF dc) {
IGoPort iport = base.PickNearestPort(dc);
if (this.EndPort != null && this.EndPort.GoObject is GoPort) {
if (iport != null) {
myLastNearestPort = (GoPort)this.EndPort.GoObject;
myLastNearestPort.Style = GoPortStyle.Rectangle;
myLastNearestPort.Pen = LinkingNewTool.HighlightPen;
myLastNearestPort.Brush = LinkingNewTool.HighlightBrush;
} else if (myLastNearestPort != null) {
myLastNearestPort.Style = GoPortStyle.None;
myLastNearestPort = null;
}
}
return iport;
}
public override IGoPort PickPort(PointF dc) {
IGoPort port = base.PickPort(dc);
if (port != null) return port;
// find a close port to start the link if Alt key is down
if (!this.FirstInput.Alt) return null;
return PickNearbyStartPort(dc);
}
private IGoPort PickNearbyStartPort(PointF dc) {
IGoPort bestPort = null;
float dist = this.View.PortGravity;
// get the region for all ports that we might care about
RectangleF scope = new RectangleF(dc.X - dist, dc.Y - dist, dist * 2, dist * 2);
float bestDist = dist * dist; // square here so don't need to sqrt later
foreach (GoLayer layer in this.View.Layers.Backwards) {
if (!layer.IsInDocument) continue;
if (!layer.CanViewObjects()) continue;
foreach (GoObject obj in layer.Backwards) {
bestPort = pickNearbyPort1(obj, dc, bestPort, ref bestDist);
}
}
return bestPort;
}
private IGoPort pickNearbyPort1(GoObject obj, PointF dc, IGoPort bestPort, ref float bestDist) {
// remember that it's possible some object will implement both IGoPort and GoGroup
IGoPort port = obj as IGoPort;
if (port != null && port.CanLinkFrom()) {
PointF toPoint = PortPoint(port, dc);
float dx = dc.X - toPoint.X;
float dy = dc.Y - toPoint.Y;
float dist = dx * dx + dy * dy; // don't bother taking sqrt
if (dist < bestDist) { // closest so far
bestPort = port;
bestDist = dist;
}
}
GoGroup group = obj as GoGroup;
if (group != null) {
foreach (GoObject child in group.GetEnumerator()) {
bestPort = pickNearbyPort1(child, dc, bestPort, ref bestDist);
}
}
return bestPort;
}
public override void Stop() {
base.Stop();
if (myLastNearestPort != null) {
myLastNearestPort.Style = GoPortStyle.None;
myLastNearestPort = null;
}
}
public static readonly Pen HighlightPen = new Pen(Color.Red, 2);
public static readonly Brush HighlightBrush = null;
private GoPort myLastNearestPort = null;
}