imgui icon indicating copy to clipboard operation
imgui copied to clipboard

Drag'n Drop: How to tell in the DragDropSource, if payload has been delivered?

Open Bizzarrus opened this issue 1 year ago • 2 comments

Version/Branch of Dear ImGui:

Version 1.91.5, Branch: docking

Back-ends:

custom

Compiler, OS:

Windows 11 / MSVC 2022

Full config/build information:

No response

Details:

My Question:

During a BeginDragDropSource/EndDragDropSource, how can I tell, if the payload has been delivered? This is, an AcceptDragDropPayload has successfully returned in a different place?

The use case for this would be, if a drag'n'drop is intended to move some data from one storage to another. Let's say, for example, I have two separate and independent lists of items, and I want to be able to move items from one to the other through drag and drop. Ideally, it would be the responsibility of the DragDropSource to remove the item from the previous storage, while the DragDropTarget is adding it to the new storage - but, obviously, the DragDropSource should only remove the item from the storage, if it actually has actually been delivered to another storage, and not when the drag'n'drop has been canceled.

I know that, as a work around, the DragDropTarget can do both the remove and the add operation. However, if there are multiple possible DragDropSources and DragDropTargets (which might be implemented in different classes/using a different internal data structure) for the same type of data, this can quickly become quite messy. So I'm looking for a cleaner and more general solution to this.

Thank you in advance :)

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

static std::vector<int> data = { 0, 1, 2 };

ImGui::Button("Test");
if(!data.empty() && ImGui::BeginDragDropSource())
{
    int value = data.back();
    ImGui::SetDragDropPayload("MY_ITEM", &value, sizeof(value));
    
    //if(ImGui::WasDragDropDelivered())  // <-- Something like this ???
    //    data.pop_back();

    ImGui::EndDragDropSource();
}


Bizzarrus avatar Dec 12 '24 00:12 Bizzarrus

Drag&drop can get very complex, the operations you may want to perform can depend on the type of drag source, the type of drop target or a combination of both. Therefore how to best handle drag&drop very much depends on the application.

Handling it at the target is usually the best way. If you split removal at the source and insertion at the target, you might end up with an invalid state (element inserted at the target but not yet removed at the source) between frames. Probably not a problem with integers, but with more complex objects it might be.

If I understand you correctly, you have different source containers and potentially different types of source containers. If it is just different containers of the same type, you could set a pointer to the vector as the payload and handle removal at the drop target. With different types of containers, you could specify an interface class, derive several classes that handle container type specific retrieval and removal of data from containers and set a pointer to a persistent interface as a payload. At the target you can then just call a virtual method and don't have to worry about the source container type.

GamingMinds-DanielC avatar Dec 12 '24 11:12 GamingMinds-DanielC

Consider that the source item is not guaranteed to exist or visible while the payload is dropped (because e.g. you might may changing a visible tab while dragging the payload), so it would be dangerous to rely on both side performing their actions.

I agree that the best solution may be to include all the required data inside your payload. And then every drop target can execute a same function to process that payload and perform the move.

ocornut avatar Dec 12 '24 12:12 ocornut