I’m working on a custom keypoint move tool in Python using RhinoCommon. It runs inside a GetPoint with DynamicDraw, so geometry updates continuously while the mouse moves.
What I’m trying to do is make it behave more like a drag tool: click, drag, release, done.
Aslo if the user clicks outside the viewport, GetPoint just keeps waiting. I’d like the command to immediately exit when the user clicks outside the viewport, instead of staying in the modal loop. Esc works, but clicking outside doesn’t end it.
Is there a Rhino-native way to detect that while inside GetPoint? Or is using a MouseCallback the intended approach for this kind of behavior?
The other way I have been trying is to recreate that environment my self but that keeps bringing me to essentially grab inputs directly from windows and attempt to extrapolate that onto the rhino grid which is slow and very bug prone.
Yes so we have already been using something similar to this to bypass rhinos get point, and that structure works quite well, but where we started seeing issues is when we started to update the display.
In get point dynamic draw these refresh seem to be a lot faster and less demanding. When using our windows input bypass we haven’t been able to make use of dynamic draw in the same way and so purely updating geometry based on our python code and a redraw is much slower.
Here’s a preview there’s a lot more logic then this but I think that’s enough for context:
while True: #-------------------------------------------------------------------------------------------- Listener based keypoints
Fullbreak = False
lastx = 0
prev_mouse_down = Listener.mouse_state()
dragging = False
last_valid_point = None
while True:
inside, x, y, z = Listener.mouse_window_position()
mouse_down = Listener.mouse_state()
key = Listener.key_pressed()
if inside:
current_point = Rhino.Geometry.Point3d(x, y, z)
last_valid_point = current_point
if mouse_down:
if lastx != x:
rs.EnableRedraw(True)
#rs.Redraw()
rs.EnableRedraw(False)
else:
current_point = None
if mouse_down:
Fullbreak = True
break
lastx = x
# Exit on Esc / Enter / Space
if key in ["esc", "enter", "space"]:
if do_add_point and last_valid_point is not None and keypoint_layer in rs.LayerNames():
ctrl_pts = rs.ObjectsByLayer(keypoint_layer) or []
remove_nearest_point_from_list(ctrl_pts, last_valid_point)
podBuilder_variable = layernames.layername_to_variable[keypoint_layer]
podBuilder_data = getattr(self.podBuilder.keypoints, podBuilder_variable)
remove_nearest_point_from_list(podBuilder_data, last_valid_point)
Fullbreak = True
layernames.lock_all_layers()
return
# Mouse drag
elif mouse_down and prev_mouse_down and dragging:
if not inside:
break
# emulate old DynamicDraw behavior
self.move_object_to_target(self.keypoint_object, current_point)
This is where we end up moving the points and refreshing are various nurbs curve and other geometry with constraints: self.move_object_to_target(self.keypoint_object, current_point)