Download

[UMG] Drag and Drop Inventory?

Hey,

i’m nearly getting mad. I’m trying to get a simple drag and drop event to work on my Inventory for almost 6-8 hours now.
I created this all a year ago in the Canvas and needed to calculate all the position myself.

Now in UMG i thought Drag and Drop would help me create these inventories faster and easier, but it seems like DragAndDrop is
not working the way i thought.

My setup so far is/was:

Having one Widget called “Inventory” that has Slots for the Items. (Only displaying, because adding an item to a real slot and not the canvas completely
breaks the drag and drop, because it either doesn’t move at all or is limited to the parent widget slot).
One widget called Inventory Item, that shows the icon etc of an item.

Now, displaying this works perfectly, but as soon as i want to use drag and drop, it is a whole mess.
I looked through the examples on the forum and HUB, but no one is really explaining how this should work.

Capturing if my left mouse button was pressed is working. I tried to test if i’m hovering over a SLOT and, since the indices
of Slot and Item Array match, drag the Item Widget. Although that this works, i can’t move the widget as soon as my mouse overlaps
another item. The dragged item just stops. I doen’t matter what visibility settings the item widget has, as soon as my mouse overlaps
one of the other items, the dragged item won’t move until i leave the area again.

I don’t need to have the widget swap the places, i just need the slot which i’m releasingmy mouse button over. I will then just provide
my inventory function with the dragged slot number and the dropped slot number, but with the item not moving further, i think i’m doing
this wrong again. There are so many event for drag and drop and even something like “Create Drag and Drop bla”, i have no idea how to do
this.

I mean, there are marketplace projects where this is working in BP only, so it needs to work somehow, but i don’t get any idea on how to start
and how this whole thing should work.

Maybe someone can help me here getting started. For now i only need to able to drag an item and release it on another slot. Doing this should
give me the slot i am over.

So, 2 hours later i still have problems. I managed to drag an icon around and reset it by letting loose of my left mouse key.
But i still can’t figure out how to get a widget that lies behind another one. When i’m dragging one item, it is in front of all others.
There is no function to get underlying widgets and “is hovered” isn’t called because the item getting dragged consumes it.

EDIT: Ok, seems like setting the visibility of the dragged item to hit test, lets it pass the hovered event. Let’s see if i get my inventory to work like that.
EDIT2: Nope, doesn’t really help me. Although i can now get the Widget behind this one, i can’t let go of my dragged widget if i’m not on another slot, since nothing
will call the Mouse Button Up event anymore.

There are separate functions for drag enter/over/leave. IsHovered is not a legal call to make during drag drop as mouse enter events are not being called during a drag operation. You need to have a widget to begin the drag on, which you appear to have, and you need slot widgets that override and listen for the Drag Enter/Leave and Drop calls. You can’t have the inventory be a single user widget, it needs to have each slot be its own user widget that understands how to manage its own slot state.

Ok so, to get some more words on this. (i really want and need to understand this whole logic).

I have a Widget that represents the COMPLETE Inventory. So a widget that has a CanvasPanel and a 500x500 unit overlay where the Slots will be in.
Now i have a Widget called “InventorySlot”, which is (for this example) 100x100 units. Here either a THIRD widget will go in, that represents my Item
or this already represents my item. First part where i stuck on.

Now my Inventory Widget spawns 25 InventorySlot widgets, that i would want to place in a grid. Maybe even using the “UniFormGridPanel” instead of the 500x500 overlay and
place the IntentorySlots in them.

Let say in my inventory, i have an event that goes through my real inventory, and for each valid item, it spawns a widget for this item in the correct InventorySlot.
It will be only a visible factor, so no hit detection for the ItemWidget.

So the hierarchy till now is “InventoryWidget with UniformGridPanel”->“25 InventorySlots Widgets inside 25 slots of the UniformGridPanel”->“ItemWidgets placed set as child of the InventorySlots as they are in the inventory”.

Now lets say i have the MouseButtonDown Event in my InventorySlot. Clicking on it, and dragging will now call the “OnDragDetect” and this will spawn a copy of my ItemWidget (if this slot has one) which i give the DragAndDrop option as a Drag Visual (maybe an extra widget that only has the image) and the ItemWidget itself as the Payload. Do i need to hide the Payload? Do i need special visibility settings for the Drag Visual?

Going on, i would now have an “OnDrop” event in the InventorySlot Widget and this gets called as soon as let loose of my left mouse button over one of these widgets. Here i can take the Payload and place it, or for my kind of a system,
i would take a slot number that i saved in the ItemWidget and in the InventorySlot and take both to tell my server to switch these (or place the item) in the real Inventory array and update the widget again.

Is thats the way? Because i tried so many different things now ):

Just for the record: While patiently waiting, i’m trying to set up what i wrote here. Right now it “feels” correct. Let’s see how the drag and drop now will work:
These are 3 widgets right now.

That all sounds right except I’d probably put the MouseButtonDown/OnDragDetect logic on the ItemWidget, as that’s the thing you’re actually doing the drag on.

In the example I linked I used the ItemWidget (or spell widget in my case) as the payload, but that’s not what I would recommend, I did that solely for brevity of the example. The payload can be any UObject, so if I were doing it for reals in a game, I’d make the payload UInventoryItem or whatever as the payload. But it wont hurt to use the widget as the payload, you can also use the string field if you just want to attach some string data, perhaps in the future I can make that field a variant, so it can more or less be any primitive type (string, int, bool…). Int in particular would work really well for inventories.

Ok, so i moved the ButtonDown and DragDetect into the ItemWidget. But it is not receiving ANY ButtonDown info. It is the top most (as you can see in the picture above) and all components ,even the root, is set to be visible.
As you suggested in the post you linked, the Roots of both the Draggable and the Droppable Widgets are set to Visible. Is there anything else i need to consider?

Thanks for your help so far.

EDIT: To maybe help you understanding what i may do wrong:

InventoryWidget with Grid, all set to Hit Test:

InventorySlot with Background Image (white), all set to visible:

ItemWidget, with Image that is bind to the Item Ref, all set to visible:

OnDrop in InventorySlot calling my ServerFunction:

OnMouseButtonDown in the ItemWidget:

OnDragDetected in the ItemWidget:

Open the widget reflector (Ctrl+Shift+W). Enable widget picking hover over the item, and hit escape then look at what widget you’re actually hit testing. I’d bet you’ve got some invisible something in front of the widget. Also, you’ve got a ton of extra canvas panels you don’t need, if all you have an image, you can just make that the first widget, don’t have to nest things in a canvas. Likewise, you don’t need, Canvas > Overlay > Image for a background, just have a Border, they can have any content you want and function as the background.

You need things to be more than visually visible, they need to be hit test visible. Lots of widgets are Self Hit Test Invisible, meaning they are visually visible, but they themselves are not hit test visible (children may be, but not them). So make sure the ItemWidget’s Root’s visibility is set to straight up Visible, not Self Hit Test Invisible, which is the default for all User Widgets.

Thanks for the tipp with the Canvas, is there a way to set the min size of the Border to 100x100? It only “stretches” when it has a child.

But that aside, i tested the HUD with the widget reflector and it marks the Viewport. So not another widget but just the whole viewport. I just set my input to “Game and UI” and gave it the Inventory as a focus. Also enabled my mouse with the Controller Bool. Am i missing something? I’m working a few hours on this now. Could be that i missed something stupidly easy.

This is what i meant with visible. I have my roots set straight to visible.
And i also have the childs at visible.

EDIT: The main Inventory, that has the Grid as a child (and the grid as the Slots and Items as a child) is set to hittest. Do i need to set this main inventory to Visible too?

EDIT2: Ok i got it to work somehow. This is my setup so far (just for the fact to recreate this):

My Inventory, so the top most Widget that has a Grid Widget:

Root - Visible
CanvasPanel - Visible
UniformGridPanel - SelfHitTest

The Inventory Slot, that is a Child of the UniformGridPanel:

Root - Visible
Overlay - Visible
Image - Visible

The ItemWidget, which is a Child of the Overlay of the InventorySlot:

Root - Visible
Overlay - Visible
Image - Visible

If there is anything to “improve”, please let me know, otherwise i’m very happy that you spend your time helping me here. I though i would never get this to work.

Size Box, can be used to force a specific size to be maintained, it’s a lot better than doing things through canvas because it has the ability to set a minimum size for real, and not what canvas does which is enforce a size override entirely. So for an inventory slot, I’d just have it be Border > Size Box, and then insert my item widgets into the sizebox when i create the item widget for a slot.

Thanks, i’m currently rewriting my C++ function to handle the inventory itself.
This is exactly what i searched for. An easy to use Drag and Drop system that automatically recognizes the slot under the mouse release. Awesome job Nick! Thank you very much!

Hm Nick, i ran into another “problem”. When dropping the Item, i want to check if someone is pressing the SHIFT key. I found this:

Is this not working yet or do i have to enable input somehow? (Input Mode is UI and Game). Is the Game maybe “consuming” the shift key?

The modifier key state is set on the pointer/mouse event at the slate application level when the event is created. There’s no user work that need be done, you should use Is Shift Down though, expecting a specific shift button to be pressed is sketch.

Yeah ok, but even with only the “SHIFT” key, i always get “false”. So again, am i missing something or did i not understand your last post correctly? If i understood your last post correctly, you said that this should work out of the box, or?

EDIT: For a “work around” i just used the Shift Key of the Controller. Seems to work since i have UI and Game input on.

Should work out of the box

Hm ok, not for me. The bool is always falls. But the Controller Shift Key is working.

I also tried to get the Mouse Position in the OnDrop event, but it is always (0, 0). ):

EDIT: Seems like the “GetMousePosition” function returns false, so there is no
associated mouse device. How can this happen :open_mouth:

Hey Nick,

i got my Inventory PRETTY far, but i’m stuck on checking what Widget is underneath my Drag operation. I want to be able to detect if i let the Item go outside of the Overlay, over the Canvaspanel.
The IsHovered is detecting exactly the space i want to use, but as you said, hovered isn’t working while dragging.

There is “Drag Over”, but i need a way to check exactly the Canvas. Otherwise i would need to work around by adding a second widget that is only detecting this and spawning it behind my MainUI.

PS: For now i will use the work around with the additional widget.

I’m also fighting with D&D for a whole day right know.
As a programmer I know it is not so easy to do that in a convenient way. But it’s possible.
This is by far the most complicated way I’ve ever seen to expose D&D to the user.
D&D should be a flag in the UserWidget, exposed via checkBox. If it is enabled, D&D happens automatically and all Events (OnStartDrag(), OnDrag(), OnEndDrag()) are send.
This would be an easy and convenient way to work with it.
On Actor (in 3D world) there could be a D&D component that does the same.
Too bad it’s such a hassle.

By the way… is it normal that every post must be review by a moderator before being published?
Seemed to be true for my last post.

Hey,

no, only the first post of every user is moderated by us. Also please don’t make doubleposts. And wait 4 days before you bump threads that haven’t received any new answer.

After Nick explained it to me here, i find it rather simple to use Drag And Drop in UMG.
You just need to a Container for the OnDrop and a Widget for the OnDrag and the MouseButtonDown Event.

Everything else works pretty much out of the box. And the possibility to add every UObject that i want as a payload is also nice.

Hey Exi,
thanks for replying.
Just wrote that in a state of frustration. Worked with lots of middleware before and things are not user friendly in UE, but no offense.
But support seems to be great. With Nick Darnell’s and your help here I can fumble something together ;-). Thanks for that.
Also this thread shows up almost on top when googling.