feat: Added drag-n-drop overlay for windows
This commit is contained in:
parent
1c17ec5599
commit
3449525ead
@ -253,6 +253,9 @@ namespace hex {
|
||||
EVENT_DEF(EventSearchBoxClicked, u32);
|
||||
EVENT_DEF(EventViewOpened, View*);
|
||||
|
||||
EVENT_DEF(EventFileDragged, bool);
|
||||
EVENT_DEF(EventFileDropped, std::fs::path);
|
||||
|
||||
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
||||
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
||||
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <shobjidl.h>
|
||||
#include <wrl/client.h>
|
||||
#include <fcntl.h>
|
||||
#include <oleidl.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
@ -294,10 +295,94 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
class DropManager : public IDropTarget {
|
||||
public:
|
||||
DropManager() = default;
|
||||
virtual ~DropManager() = default;
|
||||
|
||||
ULONG AddRef() override { return 1; }
|
||||
ULONG Release() override { return 0; }
|
||||
|
||||
HRESULT QueryInterface(REFIID riid, void **ppvObject) override {
|
||||
if (riid == IID_IDropTarget) {
|
||||
*ppvObject = this;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppvObject = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DragEnter(
|
||||
IDataObject *,
|
||||
DWORD,
|
||||
POINTL,
|
||||
DWORD *pdwEffect) override
|
||||
{
|
||||
EventFileDragged::post(true);
|
||||
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DragOver(
|
||||
DWORD,
|
||||
POINTL,
|
||||
DWORD *pdwEffect) override
|
||||
{
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DragLeave() override
|
||||
{
|
||||
EventFileDragged::post(false);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Drop(
|
||||
IDataObject *pDataObj,
|
||||
DWORD,
|
||||
POINTL,
|
||||
DWORD *pdwEffect) override
|
||||
{
|
||||
FORMATETC fmte = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
||||
STGMEDIUM stgm;
|
||||
|
||||
if (SUCCEEDED(pDataObj->GetData(&fmte, &stgm))) {
|
||||
auto hdrop = HDROP(stgm.hGlobal);
|
||||
auto fileCount = DragQueryFile(hdrop, 0xFFFFFFFF, nullptr, 0);
|
||||
|
||||
for (UINT i = 0; i < fileCount; i++) {
|
||||
WCHAR szFile[MAX_PATH];
|
||||
UINT cch = DragQueryFileW(hdrop, i, szFile, MAX_PATH);
|
||||
if (cch > 0 && cch < MAX_PATH) {
|
||||
EventFileDropped::post(szFile);
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseStgMedium(&stgm);
|
||||
}
|
||||
|
||||
EventFileDragged::post(false);
|
||||
|
||||
*pdwEffect &= DROPEFFECT_NONE;
|
||||
return S_OK;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
void Window::setupNativeWindow() {
|
||||
// Setup borderless window
|
||||
auto hwnd = glfwGetWin32Window(m_window);
|
||||
|
||||
OleInitialize(nullptr);
|
||||
|
||||
static DropManager dm;
|
||||
RegisterDragDrop(hwnd, &dm);
|
||||
|
||||
bool borderlessWindowMode = ImHexApi::System::isBorderlessWindowModeEnabled();
|
||||
|
||||
// Set up the correct window procedure based on the borderless window mode state
|
||||
|
@ -565,11 +565,6 @@ namespace hex {
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
if (ImGui::BeginDragDropTargetCustom(ImGui::GetCurrentWindow()->MenuBarRect(), ImGui::GetCurrentWindow()->ID)) {
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
this->beginNativeWindowFrame();
|
||||
|
||||
if (ImHexApi::Provider::isValid() && isAnyViewOpen()) {
|
||||
@ -1156,29 +1151,8 @@ namespace hex {
|
||||
|
||||
// Register file drop callback
|
||||
glfwSetDropCallback(m_window, [](GLFWwindow *, int count, const char **paths) {
|
||||
// Loop over all dropped files
|
||||
for (int i = 0; i < count; i++) {
|
||||
auto path = std::fs::path(reinterpret_cast<const char8_t *>(paths[i]));
|
||||
|
||||
// Check if a custom file handler can handle the file
|
||||
bool handled = false;
|
||||
for (const auto &[extensions, handler] : ContentRegistry::FileHandler::impl::getEntries()) {
|
||||
for (const auto &extension : extensions) {
|
||||
if (path.extension() == extension) {
|
||||
// Pass the file to the handler and check if it was successful
|
||||
if (!handler(path)) {
|
||||
log::error("Handler for extensions '{}' failed to process file!", extension);
|
||||
break;
|
||||
}
|
||||
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no custom handler was found, just open the file regularly
|
||||
if (!handled)
|
||||
RequestOpenFile::post(path);
|
||||
EventFileDropped::post(reinterpret_cast<const char8_t *>(paths[i]));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/api/achievement_manager.hpp>
|
||||
|
||||
@ -172,6 +173,28 @@ namespace hex::plugin::builtin {
|
||||
ImHexApi::HexEditor::impl::setCurrentSelection(region);
|
||||
});
|
||||
|
||||
EventFileDropped::subscribe([](const std::fs::path &path) {
|
||||
// Check if a custom file handler can handle the file
|
||||
bool handled = false;
|
||||
for (const auto &[extensions, handler] : ContentRegistry::FileHandler::impl::getEntries()) {
|
||||
for (const auto &extension : extensions) {
|
||||
if (path.extension() == extension) {
|
||||
// Pass the file to the handler and check if it was successful
|
||||
if (!handler(path)) {
|
||||
log::error("Handler for extensions '{}' failed to process file!", extension);
|
||||
break;
|
||||
}
|
||||
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no custom handler was found, just open the file regularly
|
||||
if (!handled)
|
||||
RequestOpenFile::post(path);
|
||||
});
|
||||
|
||||
fs::setFileBrowserErrorCallback([](const std::string& errMsg){
|
||||
#if defined(NFD_PORTAL)
|
||||
ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg));
|
||||
|
@ -54,8 +54,53 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
static bool s_drawDragDropOverlay = false;
|
||||
static void drawDragNDropOverlay() {
|
||||
if (!s_drawDragDropOverlay)
|
||||
return;
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
drawList->PushClipRectFullScreen();
|
||||
{
|
||||
const auto windowPos = ImHexApi::System::getMainWindowPosition();
|
||||
const auto windowSize = ImHexApi::System::getMainWindowSize();
|
||||
const auto center = windowPos + (windowSize / 2.0F) - scaled({ 0, 50 });
|
||||
|
||||
// Draw background
|
||||
{
|
||||
const ImVec2 margin = scaled({ 15, 15 });
|
||||
drawList->AddRectFilled(windowPos, windowPos + windowSize, ImGui::GetColorU32(ImGuiCol_WindowBg, 200.0/255.0));
|
||||
drawList->AddRect(windowPos + margin, (windowPos + windowSize) - margin, ImGuiExt::GetCustomColorU32(ImGuiCustomCol_Highlight), 10_scaled, ImDrawFlags_None, 7.5_scaled);
|
||||
}
|
||||
|
||||
// Draw drag n drop icon
|
||||
{
|
||||
const ImVec2 iconSize = scaled({ 64, 64 });
|
||||
const auto offset = scaled({ 15, 15 });
|
||||
const auto margin = scaled({ 20, 20 });
|
||||
|
||||
const auto text = "Drop files here to open them...";
|
||||
const auto textSize = ImGui::CalcTextSize(text);
|
||||
|
||||
drawList->AddShadowRect(center - ImVec2(textSize.x, iconSize.y + 40_scaled) / 2.0F - offset - margin, center + ImVec2(textSize.x, iconSize.y + 75_scaled) / 2.0F + offset + ImVec2(0, textSize.y) + margin, ImGui::GetColorU32(ImGuiCol_WindowShadow), 20_scaled, ImVec2(), ImDrawFlags_None, 10_scaled);
|
||||
drawList->AddRectFilled(center - ImVec2(textSize.x, iconSize.y + 40_scaled) / 2.0F - offset - margin, center + ImVec2(textSize.x, iconSize.y + 75_scaled) / 2.0F + offset + ImVec2(0, textSize.y) + margin, ImGui::GetColorU32(ImGuiCol_MenuBarBg, 10), 1_scaled, ImDrawFlags_None);
|
||||
drawList->AddRect(center - iconSize / 2.0F - offset, center + iconSize / 2.0F - offset, ImGui::GetColorU32(ImGuiCol_Text), 5_scaled, ImDrawFlags_None, 7.5_scaled);
|
||||
drawList->AddRect(center - iconSize / 2.0F + offset, center + iconSize / 2.0F + offset, ImGui::GetColorU32(ImGuiCol_Text), 5_scaled, ImDrawFlags_None, 7.5_scaled);
|
||||
|
||||
drawList->AddText(center + ImVec2(-textSize.x / 2, 85_scaled), ImGui::GetColorU32(ImGuiCol_Text), text);
|
||||
}
|
||||
}
|
||||
drawList->PopClipRect();
|
||||
}
|
||||
|
||||
void addGlobalUIItems() {
|
||||
EventFrameEnd::subscribe(drawGlobalPopups);
|
||||
EventFrameEnd::subscribe(drawDragNDropOverlay);
|
||||
|
||||
EventFileDragged::subscribe([](bool entered) {
|
||||
s_drawDragDropOverlay = entered;
|
||||
});
|
||||
}
|
||||
|
||||
void addFooterItems() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user