Attaching a node to the cursor

I’m working on a ‘sketch’ mode for user input. Basically if the user clicks on the background, it drops a new node, creates a phantom ‘hovering’ node, links the dropped node to the hovering mode, and attaches the hovering node to the cursor. The next time the user clicks, it would drop this hovering node instead of creating a new node.

What is the best way to get the hovering node to follow the cursor?

It’s almost the same behavior as your default link creation behavior via dragging from a port, where you hover an invisible port linked to the anchor node. I don’t think you used an ActionObject to do this…

You need to define a new mouse state for your subclass of JGoView.
There are some examples of this, such as in ProcessView of the Processor sample. Note how the MouseStateRoutingLink state implements a mode where the end of the currently-being-constructed link moves along with the mouse pointer, and new Points are added to the link stroke on each mouse click.

OK this is working very well. I made my own state independent of JGoView.setState (as per the demo) because that got really nasty really fast, but no worries.

Now while the node is attached to the pointer in the view (not the document) I want it to snap to existing nodes (ports really). The problem is that this code is intermittent (!!), which tells me that the problem is in the manner that I create the nodes. Sometimes it snaps to the nodes, sometimes it doesn’t. From a breakpoint I can tell that ‘closePort’ is often null when it should not be.

Since I can’t step through the implementation of pickDocObject, can you tell me what circumstances might cause it not to recognize a node within the port gravity distance, so I can inspect for these circumstances?

I’ll post the code anyway as a sanity check:

public boolean doMouseMove(int modifiers, Point dc, Point vc) { if (sketcher.isSketching()) { JGoPort closePort = pickNearestPort(dc); if (closePort==null) { sketcher.moveFutureNodeTo(dc); } else { sketcher.snapFutureNodeTo(closePort); } return true; } else return super.doMouseMove(modifiers, dc, vc); }

Well, there are benefits to being a customer, such as being able to step through the souce code.
Are the ports very large objects? I think it’s measuring the distance to the center of the port, which for very large ports might be too far for the current port gravity distance.

no, they are mostly unchanged JGoBasicNodes.

i’ll soon be a customer. the expense request etc is taking a while due to corporate bs :( I guess I’ll just wait.

It’s probably that you can’t really use JGoView.pickNearestPort by itself, since it depends on valid link checking that it caches during the normal linking process. I suggest you define your own method which you can adapt from JGoView.pickNearestPort:
public JGoPort pickNearestPort(Point dc)
{
JGoPort currentBestPort = null;
double currentMaxDist = getPortGravity();
currentMaxDist = currentMaxDist; // square here so don’t need to sqrt later
JGoLayer layer = getFirstLayer();
while (layer != null) {
if (layer.isVisible()) {
JGoListPosition pos = layer.getFirstObjectPos();
Point toPoint = new Point(0, 0);
while (pos != null) {
JGoObject obj = layer.getObjectAtPos(pos);
pos = layer.getNextObjectPos(pos);
if (obj instanceof JGoPort) {
JGoPort port = (JGoPort)obj;
if (port.isValidLink()) {
toPoint = port.getLinkPoint(JGoObject.Center, toPoint);
double dx = dc.x - toPoint.x;
double dy = dc.y - toPoint.y;
double dist = dx
dx + dy*dy; // don’t bother taking sqrt
if (dist <= currentMaxDist) {
currentBestPort = port;
currentMaxDist = dist;
}
}
}
}
}
layer = getNextLayer(layer);
}
return currentBestPort;
}
You’ll need to replace the call to JGoPort.isValidLink() with your own predicate. I suppose you could override JGoPort.isValidLink, but that would probably break the standard linking mechanisms.