Handles.RectangeHandleCap not reacting on EventType.mouseMove in EditorWindow

Hi!

I want the rectangle to be drawn under the cursor.(I need something else but to test if the behaviour is working I could do what I need). I subscribed to OnSceneGUI and trying to draw the rectange in a following way:

Handles.RectangleHandleCap(0, GetSceneMousePosition(), Quaternion.identity, 100, EventType.mouseMove);

However I see nothing.

If I change the event from mouseMove to repaint, the square is present, however it does not follow the cursor. When I move cursor the square remains on the same position that it was before moving. If I stop moving the square will appear at the cursor position. Looks like Repaint event comes and Repaint event never comes when you move the mouse. I tried even to generate Repaint event manually:

I set wantsMouseMove to true, and put this code into OnGUI:

if (Event.current.type == EventType.MouseMove)
            Repaint ();

But nothing has changed.

How could I make the rectange to follow the cursor ?

Thank you in advance.

There seems to be several things wrong here. First of all the event type parameter tells the method which Event it should process with this call. A handle cap function can only draw. It doesn’t react to any other events besides the repaint and the layout event. Though if you don’t want to use it as actual handle you only need the repaint event.

However you can’t just pass the repaint event to the method when you like but when Unity is actually in the repaint state. OnGUI / OnSceneGUI is called for several different event. So the usual procedure is to pass Event.current.type as event type parameter in order to draw it.

Second you should keep in mind that handles are actually drawn in 3d. That means you have to pass a 3d worldspace position. For the same reason you usually want to multiply your “size” by HandleUtility.GetHandleSize. It returns a scaling factor so the handle will always have the same size on screen, no matter how far it is drawn from the camera.

You shouldn’t use hardcoded controlIDs. Use GUIUtility.GetControlID to obtain a control ID

You said you set “wantsMouseMove” to true, but on which window? If you want the sceneview to receive mousemove events you have to set that variable on the sceneview.

You said you have that MouseMove check inside OnGUI. Which OnGUI do you refer to? You should do that check inside the sceneview gui callback. Also make sure you actually repaint the sceneview and not some other window.

To which kind of class does your code actually belong to?

Here’s an example class which will register a sceneview callback to draw a rectangle around the mouse cursor

using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public class SceneViewCursor
{
	static SceneViewCursor()
    {
        SceneView.onSceneGUIDelegate += OnSceneViewGUI;
        foreach(SceneView sv in SceneView.sceneViews)
        {
            sv.wantsMouseMove = true;
        }
	}
	
	static void OnSceneViewGUI (SceneView aView)
    {
        Event e = Event.current;
        if (e.type == EventType.MouseMove || e.type == EventType.MouseDrag)
            aView.Repaint();

        int id = GUIUtility.GetControlID(FocusType.Passive);
        Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
        Vector3 pos = ray.GetPoint(10);
        float size = 0.2f * HandleUtility.GetHandleSize(pos);
        Handles.RectangleHandleCap(id, pos, aView.camera.transform.rotation, size, e.type);
	}
}

Note that the orientation of the rectangle in 3d space is also relative to worldspace. That’s why i used the scenview camera’s rotation. If you use Quaternion.identity the rect will always face the world z axis.

Also this script doesn’t notice when a new SceneView gets opened. That means “wantsMouseMove” of a newly opened SceneView wouldn’t be set to true. However as soon as any script get compiled the Mono environment is reloaded which would take care of that.