Hello! I’m working on drag and drop functionality for an inventory system. I want to SetMouseCursorWidget to the widget of an item if you’ve clicked it and dragged, however it instead just hides the cursor and only shows the widget when I release the mouse click.
It functions correctly if I use this line in the NativeOnMouseButtonDown of the widget it clicked and dragged on:
FReply::Handled().CaptureMouse(TakeWidget());
instead of
FReply::Handled();
However if the mouse is captured it doesn’t register the NativeOnMouseButtonUp that I need called on a different widget.
I don’t know much about mouse capturing so I apologize if this is a silly question, but I can’t find an answer online.
I’m not using the built in drag and drop functionality, I’m doing it myself. From what I understand, the built in system would move the widget itself, when I want to keep the widget we selected in the same position and instead create a new widget that is assigned to the cursor. And only after NativeOnMouseUp does the original widget, along with the one on our cursor, disappear.
its been a while since ive done it so i can only point you in the direction but i believe CaptureMouse returns a handle that you can save and use. So rather than OnMouseUp you use the handle, or maybe OnMouseUp->IsHandleValid->Release
if that doesnt help ill see if i can find my old code
I’m sorry I’m not quite sure I understand. To save the handle do I broadcast the FReply to the widget I need to receive the input? How can I use a handle instead of OnMouseUp?
I can’t seem to find much documentation on this mouse stuff.
I think there might be a misunderstanding about how Unreal’s native UMG Drag & Drop system works.
It doesn’t force you to move the original widget, what happens visually and logically is completely under your control.
For instance, during a drag operation you can:
Keep the original widget untouched in its original slot.
Create a lightweight “ghost” widget that follows the cursor as a preview.
Temporarily grey out, hide, or change the icon of the source widget.
Spawn a completely custom visual element without altering the underlying UI structure.
Here is how the native UMG workflow handles mouse routing and drop detection automatically:
NativeOnMouseButtonDown: Instead of manually capturing the mouse, you return FReply::Handled().DetectDrag(TakeWidget(), EKeys::LeftMouseButton);.
NativeOnDragDetected: Called when the engine detects mouse movement after the click. Here you create a UDragDropOperation and set your custom ghost/preview widget to DefaultDragVisual.
UDragDropOperation: Acts as a container to carry any custom payload data (e.g., Item ID, slot index, quantity) from the source to the target widget.
NativeOnDrop: Called automatically on the receiving widget where the mouse button is released. It receives the UDragDropOperation payload so you can execute whatever logic you need (swapping items, dropping items, updating slots, etc.).
Using this native flow solves your mouse capture issue completely because Slate handles routing the drop event to whichever widget is under the cursor when the drag ends.
I’d also recommend checking out this official guide (unfortunatly Blueprint only but the concept is the same in c++) Creating Drag and Drop UI
In that example, the widget is moved, but as you can see, it’s only moved because the tutorial author explicitly chose to do so in their logic, not because Unreal forces that behavior natively.
You are correct, I did misunderstand it and I will be switching to using the built in drag and drop system. I still would love to know what about my system was causing such an odd bug, just for peace of mind. Regardless, I believe drag and drop will fix it, thank you!
Regarding your issue with SetMouseCursorWidget, the behavior you’re seeing is caused by how Slate handles Mouse Capture and input routing:
When you call CaptureMouse(TakeWidget()), Slate routes all subsequent mouse events (movement, button up, mouse enter/leave) exclusively to the widget that initiated the capture. Because that widget holds full ownership of the mouse, no other widget under the cursor will ever receive NativeOnMouseButtonUp.
SetMouseCursorWidget depends on Slate’s active widget context. When you press and hold the mouse button without mouse capture (or without an active Drag & Drop framework operation), Slate considers the mouse clicked on the initial widget. As soon as the cursor leaves that widget’s bounds, Slate stops updating that widget’s software cursor, causing it to hide until you release the click and input focus resets.
So basically, it’s not a bug, it’s just working as intended by Slate’s design.