feat: Added drag-n-drop overlay for windows

This commit is contained in:
WerWolv 2024-01-10 23:46:50 +01:00
parent 1c17ec5599
commit 3449525ead
5 changed files with 157 additions and 27 deletions

View file

@ -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);

View file

@ -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

View file

@ -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]));
}
});

View file

@ -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));

View file

@ -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() {