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(EventSearchBoxClicked, u32);
|
||||||
EVENT_DEF(EventViewOpened, View*);
|
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(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
||||||
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
||||||
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <shobjidl.h>
|
#include <shobjidl.h>
|
||||||
#include <wrl/client.h>
|
#include <wrl/client.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <oleidl.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#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() {
|
void Window::setupNativeWindow() {
|
||||||
// Setup borderless window
|
// Setup borderless window
|
||||||
auto hwnd = glfwGetWin32Window(m_window);
|
auto hwnd = glfwGetWin32Window(m_window);
|
||||||
|
|
||||||
|
OleInitialize(nullptr);
|
||||||
|
|
||||||
|
static DropManager dm;
|
||||||
|
RegisterDragDrop(hwnd, &dm);
|
||||||
|
|
||||||
bool borderlessWindowMode = ImHexApi::System::isBorderlessWindowModeEnabled();
|
bool borderlessWindowMode = ImHexApi::System::isBorderlessWindowModeEnabled();
|
||||||
|
|
||||||
// Set up the correct window procedure based on the borderless window mode state
|
// Set up the correct window procedure based on the borderless window mode state
|
||||||
|
@ -565,11 +565,6 @@ namespace hex {
|
|||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginDragDropTargetCustom(ImGui::GetCurrentWindow()->MenuBarRect(), ImGui::GetCurrentWindow()->ID)) {
|
|
||||||
|
|
||||||
ImGui::EndDragDropTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->beginNativeWindowFrame();
|
this->beginNativeWindowFrame();
|
||||||
|
|
||||||
if (ImHexApi::Provider::isValid() && isAnyViewOpen()) {
|
if (ImHexApi::Provider::isValid() && isAnyViewOpen()) {
|
||||||
@ -1156,29 +1151,8 @@ namespace hex {
|
|||||||
|
|
||||||
// Register file drop callback
|
// Register file drop callback
|
||||||
glfwSetDropCallback(m_window, [](GLFWwindow *, int count, const char **paths) {
|
glfwSetDropCallback(m_window, [](GLFWwindow *, int count, const char **paths) {
|
||||||
// Loop over all dropped files
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
auto path = std::fs::path(reinterpret_cast<const char8_t *>(paths[i]));
|
EventFileDropped::post(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);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <hex/api/event_manager.hpp>
|
#include <hex/api/event_manager.hpp>
|
||||||
|
|
||||||
#include <hex/api/localization_manager.hpp>
|
#include <hex/api/localization_manager.hpp>
|
||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
#include <hex/api/project_file_manager.hpp>
|
#include <hex/api/project_file_manager.hpp>
|
||||||
#include <hex/api/achievement_manager.hpp>
|
#include <hex/api/achievement_manager.hpp>
|
||||||
|
|
||||||
@ -172,6 +173,28 @@ namespace hex::plugin::builtin {
|
|||||||
ImHexApi::HexEditor::impl::setCurrentSelection(region);
|
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){
|
fs::setFileBrowserErrorCallback([](const std::string& errMsg){
|
||||||
#if defined(NFD_PORTAL)
|
#if defined(NFD_PORTAL)
|
||||||
ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg));
|
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() {
|
void addGlobalUIItems() {
|
||||||
EventFrameEnd::subscribe(drawGlobalPopups);
|
EventFrameEnd::subscribe(drawGlobalPopups);
|
||||||
|
EventFrameEnd::subscribe(drawDragNDropOverlay);
|
||||||
|
|
||||||
|
EventFileDragged::subscribe([](bool entered) {
|
||||||
|
s_drawDragDropOverlay = entered;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFooterItems() {
|
void addFooterItems() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user