ImGui window accepting dropped file from external source
Version/Branch of Dear ImGui:
Version 1.91
Back-ends:
imgui_impl_iWin32.cpp
Compiler, OS:
Window10
Full config/build information:
No response
Details:
Background
- I am trying to make a robot project, using imgui to replace the ui system of mujoco
- If imgui window accpet the file dragging from system file browser, it will be more convinient
https://github.com/user-attachments/assets/e99f6c75-f23f-4a0e-b865-9c021b140d97
How to do this
- First change the window property
- Then add WM_DROPFILES window message
case WM_DROPFILES:
{
HDROP hDrop = reinterpret_cast<HDROP>(wParam);
char filename[MAX_PATH];
UINT count = DragQueryFileA(hDrop, -1, NULL, 0);
for (UINT i = 0; i < count; ++i)
{
if (DragQueryFileA(hDrop, i, filename, MAX_PATH))
{
printf("%s\n", filename);
}
}
DragFinish(hDrop);
return 0;
}
- Add the code here
- ⚠︎ Don't forget #include <shellapi.h>
- After modify the win32 backend, imgui window now can accpet drag files
https://github.com/user-attachments/assets/2be1d57c-cbf0-4ed8-8059-f4f89cddb9b0
Can it be a feature
- Drag file is really common operation for interaction
- I search for glfw window and it support such feature
- As imgui use glfw window system in linux
// code generate by coploit
#include <GLFW/glfw3.h>
#include <iostream>
// File drop callback function
void drop_callback(GLFWwindow* window, int count, const char** paths) {
for (int i = 0; i < count; i++) {
std::cout << "Dropped file: " << paths[i] << std::endl;
}
}
int main() {
// Initialize GLFW
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
return -1;
}
// Create a windowed mode window and its OpenGL context
GLFWwindow* window = glfwCreateWindow(800, 600, "GLFW Drag and Drop Example", NULL, NULL);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
// Set the file drop callback
glfwSetDropCallback(window, drop_callback);
// Main loop
while (!glfwWindowShouldClose(window)) {
// Poll for and process events
glfwPollEvents();
// Rendering code (if any)
// ...
// Swap front and back buffers
glfwSwapBuffers(window);
}
// Clean up and exit
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
- I am considering add this to imgui dock branch
- I found when creating a new window by viewport_flag in dock branch
- And a callback for user to handle the file path like ImGuiSizeCallback
// Callback and functions types
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText()
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints()
typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
typedef int (*ImGuiDropFile)(char* file_path);
- This won't affect user's code and can be easily implement by other backends.
Screenshots/Video:
No response
Minimal, Complete and Verifiable Example code:
No response
case WM_DROPFILES: { HDROP hDrop = reinterpret_cast<HDROP>(wParam); char filename[MAX_PATH]; UINT count = DragQueryFileA(hDrop, -1, NULL, 0); for (UINT i = 0; i < count; ++i) { if (DragQueryFileA(hDrop, i, filename, MAX_PATH)) { printf("%s\n", filename); } } DragFinish(hDrop); return 0; }
Please note that there are a few things that could be improved here:
- Use
DragQueryFileWinstead ofDragQueryFileA, because this window is created with theWversion ofCreateWindowEx - Do not use a hardcoded
MAX_PATH, but queryDragQueryFileWfor the required length
I am not 100% sure there is value is handling this on our side. It may be done on user/app side just as well: your WM_DROPFILES event handler can be in app code without modifying the backend.
If we add some support then we need to do it and maintain it for all backends. I suppose it would be good to add it as a helper, but it doesn't seem like a very important thing, and I worry it could grow into a more complex thing if we try to design a generic version of it: It's quite unusual API design for us to use a callback for this, ideally we would expose it as a sort of getter then user is free to handle the event when they like in the frame. Also some people would like to connect this to BeginDragDropSource() with ImGuiDragDropFlags_SourceExtern, some people may want to query it differently. It's not something we can do without careful design.
Also see #2602
- Thanks for your reply
- Careful design indeed the most important part
- I rethinked of that when I was laying on my bed last night
- It is truely better to work with BeginDragDropSource() and put the file name in the payload
- I will try it in my project, and search for better way for all platform