Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions backends/imgui_impl_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,51 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA
bd->WantUpdateHasGamepad = true;
#endif
return 0;

case WM_DROPFILES:
{
// Process dropped files
HDROP hDrop = (HDROP)wParam;
UINT fileCount = ::DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0);

// Start drag and drop operation with external source flag
ImGuiContext* ctx = ImGui::GetCurrentContext();
if (ctx != nullptr)
{
ImGuiPayload& payload = ctx->DragDropPayload;
if (!payload.SourceId)
{
// Begin drag drop source with external flag
ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceExtern);

// Add payload for each dropped file
for (UINT i = 0; i < fileCount; i++)
{
// Get file path
wchar_t filePath[MAX_PATH];
::DragQueryFile(hDrop, i, filePath, MAX_PATH);

// Convert to UTF-8
int utf8Length = ::WideCharToMultiByte(CP_UTF8, 0, filePath, -1, nullptr, 0, nullptr, nullptr);
if (utf8Length > 0)
{
std::vector<char> utf8FilePath(utf8Length);
::WideCharToMultiByte(CP_UTF8, 0, filePath, -1, utf8FilePath.data(), utf8Length, nullptr, nullptr);

// Add payload item with file path
ImGui::AddDragDropPayload("DND_FILE_PATH", utf8FilePath.data(), utf8FilePath.size() - 1);
}
}

// End drag drop source
ImGui::EndDragDropSource();
}
}

// Release drop handle
::DragFinish(hDrop);
return 0;
}
}
return 0;
}
Expand Down Expand Up @@ -962,6 +1007,12 @@ void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
}
}

void ImGui_ImplWin32_EnableDragDropAcceptFiles(void* hwnd, bool enabled)
{
IM_ASSERT(hwnd != NULL);
::DragAcceptFiles((HWND)hwnd, enabled ? TRUE : FALSE);
}

//---------------------------------------------------------------------------------------------------------

#if defined(__GNUC__)
Expand Down
1 change: 1 addition & 0 deletions backends/imgui_impl_win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@ IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); //
// - Use to enable alpha compositing transparency with the desktop.
// - Use together with e.g. clearing your framebuffer with zero-alpha.
IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDragDropAcceptFiles(void* hwnd, bool enabled); // HWND hwnd

#endif // #ifndef IMGUI_DISABLE
79 changes: 64 additions & 15 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14697,6 +14697,44 @@ void ImGui::EndDragDropSource()
}

// Use 'cond' to choose to submit payload on drag start or every frame
bool ImGui::AddDragDropPayload(const char* type, const void* data, size_t data_size)
{
ImGuiContext& g = *GImGui;
ImGuiPayload& payload = g.DragDropPayload;

IM_ASSERT(type != NULL);
IM_ASSERT(ImStrlen(type) < IM_ARRAYSIZE(ImGuiPayloadItem::DataType) && "Payload type can be at most 32 characters long");
IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
IM_ASSERT(payload.DataFrameCount != -1); // SetDragDropPayload() must be called first

// Create new payload item
ImGuiPayloadItem item;
ImStrncpy(item.DataType, type, IM_ARRAYSIZE(item.DataType));

// Copy data
if (data_size > 0)
{
// Store in heap
void* item_data = g.DragDropPayloadBufHeap.Data + g.DragDropPayloadBufHeap.Size;
g.DragDropPayloadBufHeap.resize(g.DragDropPayloadBufHeap.Size + (int)data_size);
memcpy(item_data, data, data_size);
item.Data = item_data;
item.DataSize = (int)data_size;
}
else
{
item.Data = NULL;
item.DataSize = 0;
}

// Add item to payload
payload.Items.push_back(item);

// Return whether the payload has been accepted
return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
}

bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
{
ImGuiContext& g = *GImGui;
Expand All @@ -14705,35 +14743,39 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s
cond = ImGuiCond_Always;

IM_ASSERT(type != NULL);
IM_ASSERT(ImStrlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
IM_ASSERT(ImStrlen(type) < IM_ARRAYSIZE(ImGuiPayloadItem::DataType) && "Payload type can be at most 32 characters long");
IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()

if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
{
// Copy payload
ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
// Clear existing payload items
payload.Items.clear();
g.DragDropPayloadBufHeap.resize(0);
if (data_size > sizeof(g.DragDropPayloadBufLocal))

// Create first payload item
ImGuiPayloadItem item;
ImStrncpy(item.DataType, type, IM_ARRAYSIZE(item.DataType));

// Copy data
if (data_size > 0)
{
// Store in heap
g.DragDropPayloadBufHeap.resize((int)data_size);
payload.Data = g.DragDropPayloadBufHeap.Data;
memcpy(payload.Data, data, data_size);
}
else if (data_size > 0)
{
// Store locally
memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
payload.Data = g.DragDropPayloadBufLocal;
memcpy(payload.Data, data, data_size);
item.Data = g.DragDropPayloadBufHeap.Data;
memcpy(item.Data, data, data_size);
item.DataSize = (int)data_size;
}
else
{
payload.Data = NULL;
item.Data = NULL;
item.DataSize = 0;
}
payload.DataSize = (int)data_size;

// Add item to payload and set as current for backward compatibility
payload.Items.push_back(item);
payload.CurrentItem = &payload.Items[0];
}
payload.DataFrameCount = g.FrameCount;

Expand Down Expand Up @@ -14868,6 +14910,13 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
RenderDragDropTargetRectForItem(r);
}

// Set current item for backward compatibility
payload.CurrentItem = NULL;
if (type != NULL)
payload.CurrentItem = payload.GetItemByType(type);
else if (!payload.Items.empty())
payload.CurrentItem = &payload.Items[0];

g.DragDropAcceptFrameCount = g.FrameCount;
if ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) && g.DragDropMouseButton == -1)
payload.Delivery = was_accepted_previously && (g.DragDropSourceFrameCount < g.FrameCount);
Expand Down
28 changes: 23 additions & 5 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -967,11 +967,13 @@ namespace ImGui
// - An item can be both drag source and drop target.
IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call after submitting an item which may be dragged. when this return true, you can call SetDragDropPayload() + EndDragDropSource()
IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui. Return true when payload has been accepted.
IMGUI_API bool AddDragDropPayload(const char* type, const void* data, size_t sz); // Add another payload item to the current drag and drop operation. Return true when payload has been accepted.
IMGUI_API void EndDragDropSource(); // only call EndDragDropSource() if BeginDragDropSource() returns true!
IMGUI_API bool BeginDragDropTarget(); // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget()
IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0); // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released.
IMGUI_API void EndDragDropTarget(); // only call EndDragDropTarget() if BeginDragDropTarget() returns true!
IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. returns NULL when drag and drop is finished or inactive. use ImGuiPayload::IsDataType() to test for the payload type.
IMGUI_API bool AddDragDropPayload(const char* type, const void* data, size_t sz); // Add another payload item to the current drag and drop operation. Return true when payload has been accepted.

// Disabling [BETA API]
// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors)
Expand Down Expand Up @@ -2654,26 +2656,42 @@ struct ImGuiSizeCallbackData
ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing.
};

// Data payload item for Drag and Drop operations
struct ImGuiPayloadItem
{
void* Data; // Data (copied and owned by dear imgui)
int DataSize; // Data size
char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max)

ImGuiPayloadItem() { Clear(); }
void Clear() { Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); }
bool IsDataType(const char* type) const { return strcmp(type, DataType) == 0; }
};

// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload()
struct ImGuiPayload
{
// Members
void* Data; // Data (copied and owned by dear imgui)
int DataSize; // Data size
ImVector<ImGuiPayloadItem> Items; // Multiple payload items
const ImGuiPayloadItem* CurrentItem; // Current item for backward compatibility

// [Internal]
ImGuiID SourceId; // Source item id
ImGuiID SourceParentId; // Source parent id (if available)
int DataFrameCount; // Data timestamp
char DataType[32 + 1]; // Data type tag (short user-supplied string, 32 characters max)
bool Preview; // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets)
bool Delivery; // Set when AcceptDragDropPayload() was called and mouse button is released over the target item.

ImGuiPayload() { Clear(); }
void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; }
bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; }
void Clear() { SourceId = SourceParentId = 0; Items.clear(); CurrentItem = NULL; DataFrameCount = -1; Preview = Delivery = false; }
bool IsDataType(const char* type) const { for (int i = 0; i < Items.Size; i++) if (Items[i].IsDataType(type)) return true; return false; }
const ImGuiPayloadItem* GetItemByType(const char* type) const { for (int i = 0; i < Items.Size; i++) if (Items[i].IsDataType(type)) return &Items[i]; return NULL; }
bool IsPreview() const { return Preview; }
bool IsDelivery() const { return Delivery; }
// Backward compatibility
const void* GetData() const { return CurrentItem ? CurrentItem->Data : NULL; }
int GetDataSize() const { return CurrentItem ? CurrentItem->DataSize : 0; }
const char* GetDataType() const { return CurrentItem ? CurrentItem->DataType : NULL; }
};

//-----------------------------------------------------------------------------
Expand Down