From 531c049bb03c87124a71dd5587268178c0f9518f Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 9 Jun 2024 20:11:55 +0200 Subject: [PATCH] impr: Improve bookmark drag-n-drop logic Fixes #1745 --- .../include/content/views/view_bookmarks.hpp | 18 +++-- .../source/content/views/view_bookmarks.cpp | 81 +++++++++++++------ 2 files changed, 66 insertions(+), 33 deletions(-) diff --git a/plugins/builtin/include/content/views/view_bookmarks.hpp b/plugins/builtin/include/content/views/view_bookmarks.hpp index 8874a0b21..c323d5acf 100644 --- a/plugins/builtin/include/content/views/view_bookmarks.hpp +++ b/plugins/builtin/include/content/views/view_bookmarks.hpp @@ -16,18 +16,22 @@ namespace hex::plugin::builtin { void drawContent() override; private: - bool importBookmarks(hex::prv::Provider *provider, const nlohmann::json &json); - bool exportBookmarks(hex::prv::Provider *provider, nlohmann::json &json); - - void registerMenuItems(); - private: - std::string m_currFilter; - struct Bookmark { ImHexApi::Bookmarks::Entry entry; TextEditor editor; }; + private: + void drawDropTarget(std::list::iterator it, float height); + + bool importBookmarks(hex::prv::Provider *provider, const nlohmann::json &json); + bool exportBookmarks(hex::prv::Provider *provider, nlohmann::json &json); + + void registerMenuItems(); + + private: + std::string m_currFilter; + PerProvider> m_bookmarks; PerProvider m_currBookmarkId; }; diff --git a/plugins/builtin/source/content/views/view_bookmarks.cpp b/plugins/builtin/source/content/views/view_bookmarks.cpp index d6d735d32..6f7aba49b 100644 --- a/plugins/builtin/source/content/views/view_bookmarks.cpp +++ b/plugins/builtin/source/content/views/view_bookmarks.cpp @@ -240,22 +240,64 @@ namespace hex::plugin::builtin { EventHighlightingChanged::post(); } - void ViewBookmarks::drawContent() { - auto provider = ImHexApi::Provider::get(); + void ViewBookmarks::drawDropTarget(std::list::iterator it, float height) { + height = std::max(height, 1.0F); + if (it != m_bookmarks->begin()) { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - height); + } else { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + height); + } + + ImGui::InvisibleButton("##DropTarget", ImVec2(ImGui::GetContentRegionAvail().x, height * 2.0F)); + const auto dropTarget = ImRect(ImGui::GetItemRectMin(), ImVec2(ImGui::GetItemRectMax().x, ImGui::GetItemRectMin().y + 2_scaled)); + + if (it == m_bookmarks->begin()) { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - height); + } + + ImGui::PushStyleColor(ImGuiCol_DragDropTarget, 0x00); + if (ImGui::BeginDragDropTarget()) { + ImGui::GetWindowDrawList()->AddRectFilled(dropTarget.Min, dropTarget.Max, ImGui::GetColorU32(ImGuiCol_ButtonActive)); + + if (auto payload = ImGui::AcceptDragDropPayload("BOOKMARK_PAYLOAD"); payload != nullptr) { + // Receive the bookmark id from the payload + u64 droppedBookmarkId = *static_cast(payload->Data); + + // Find the correct bookmark with that id + auto droppedIter = std::ranges::find_if(m_bookmarks->begin(), m_bookmarks->end(), [droppedBookmarkId](const auto &bookmarkItem) { + return bookmarkItem.entry.id == droppedBookmarkId; + }); + + // Swap the two bookmarks + if (droppedIter != m_bookmarks->end()) { + m_bookmarks->splice(it, m_bookmarks, droppedIter); + + EventHighlightingChanged::post(); + } + } + + ImGui::EndDragDropTarget(); + } + ImGui::PopStyleColor(); + } + + void ViewBookmarks::drawContent() { // Draw filter input ImGui::PushItemWidth(-1); ImGuiExt::InputTextIcon("##filter", ICON_VS_FILTER, m_currFilter); ImGui::PopItemWidth(); - - ImGui::NewLine(); - + if (ImGui::BeginChild("##bookmarks")) { if (m_bookmarks->empty()) { ImGuiExt::TextFormattedCentered("hex.builtin.view.bookmarks.no_bookmarks"_lang); } auto bookmarkToRemove = m_bookmarks->end(); + const auto defaultItemSpacing = ImGui::GetStyle().ItemSpacing.y; + + ImGui::Dummy({ ImGui::GetContentRegionAvail().x, 0 }); + drawDropTarget(m_bookmarks->begin(), defaultItemSpacing); // Draw all bookmarks for (auto it = m_bookmarks->begin(); it != m_bookmarks->end(); ++it) { @@ -285,7 +327,10 @@ namespace hex::plugin::builtin { bool notDeleted = true; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2()); auto expanded = ImGui::CollapsingHeader(hex::format("{}###bookmark", name).c_str(), ¬Deleted); + ImGui::PopStyleVar(); + if (!expanded) { // Handle dragging bookmarks up and down when they're collapsed @@ -307,27 +352,6 @@ namespace hex::plugin::builtin { ImGui::EndDragDropSource(); } - - if (ImGui::BeginDragDropTarget()) { - - if (auto payload = ImGui::AcceptDragDropPayload("BOOKMARK_PAYLOAD"); payload != nullptr) { - // Receive the bookmark id from the payload - u64 droppedBookmarkId = *static_cast(payload->Data); - - // Find the correct bookmark with that id - auto droppedIter = std::ranges::find_if(m_bookmarks->begin(), m_bookmarks->end(), [droppedBookmarkId](const auto &bookmarkItem) { - return bookmarkItem.entry.id == droppedBookmarkId; - }); - - // Swap the two bookmarks - if (droppedIter != m_bookmarks->end()) { - std::iter_swap(it, droppedIter); - EventHighlightingChanged::post(); - } - } - - ImGui::EndDragDropTarget(); - } } auto nextPos = ImGui::GetCursorPos(); @@ -345,6 +369,7 @@ namespace hex::plugin::builtin { // Draw open in new view button if (ImGuiExt::DimmedIconButton(ICON_VS_GO_TO_FILE, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { + auto provider = ImHexApi::Provider::get(); TaskManager::doLater([region, provider, name]{ auto newProvider = ImHexApi::Provider::createProvider("hex.builtin.provider.view", true); if (auto *viewProvider = dynamic_cast(newProvider); viewProvider != nullptr) { @@ -361,6 +386,10 @@ namespace hex::plugin::builtin { ImGui::SetItemTooltip("%s", "hex.builtin.view.bookmarks.tooltip.open_in_view"_lang.get().c_str()); } + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2()); + drawDropTarget(std::next(it), defaultItemSpacing); + ImGui::PopStyleVar(); + ImGui::SetCursorPos(nextPos); ImGui::Dummy({});