GetPoint drag behavior + exit when clicking outside viewport

Hi,

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.

Thanks.

Hi @Ethan_Roy_Lanouette,

Without thinking about this too much, you might be able to hook the mouse, on Windows, and check to see there the mouse down occurred.

Something to explore.

– Dale

@dale Thank you for your time,

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)