From 688ca01b1b135454d89d6c4fd10c9fb641cafe74 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 26 Mar 2021 21:43:24 +0100 Subject: [PATCH] ux: Added undo and redo option --- plugins/builtin/source/lang/de_DE.cpp | 2 ++ plugins/builtin/source/lang/en_US.cpp | 2 ++ plugins/builtin/source/lang/it_IT.cpp | 2 ++ .../include/hex/providers/provider.hpp | 9 +++++ .../libimhex/source/providers/provider.cpp | 34 +++++++++++++++++-- source/providers/file_provider.cpp | 9 ++--- source/views/view_hexeditor.cpp | 11 ++++++ 7 files changed, 61 insertions(+), 8 deletions(-) diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index 9f7ff3499..7f74a743e 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -182,6 +182,8 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.goto.offset.end", "Ende" }, { "hex.view.hexeditor.error.read_only", "Schreibzugriff konnte nicht erlangt werden. Datei wurde im Lesemodus geöffnet." }, { "hex.view.hexeditor.error.open", "Öffnen der Datei fehlgeschlagen!" }, + { "hex.view.hexeditor.menu.edit.undo", "Rückgängig" }, + { "hex.view.hexeditor.menu.edit.redo", "Wiederholen" }, { "hex.view.hexeditor.menu.edit.copy", "Kopieren als..." }, { "hex.view.hexeditor.copy.bytes", "Bytes" }, { "hex.view.hexeditor.copy.hex", "Hex String" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index c194a97d5..91a6f0c16 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -182,6 +182,8 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.goto.offset.end", "End" }, { "hex.view.hexeditor.error.read_only", "Couldn't get write access. File opened in read-only mode." }, { "hex.view.hexeditor.error.open", "Failed to open file!" }, + { "hex.view.hexeditor.menu.edit.undo", "Undo" }, + { "hex.view.hexeditor.menu.edit.redo", "Redo" }, { "hex.view.hexeditor.menu.edit.copy", "Copy as..." }, { "hex.view.hexeditor.copy.bytes", "Bytes" }, { "hex.view.hexeditor.copy.hex", "Hex String" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 21c4f0a8a..97eb06750 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -182,6 +182,8 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.goto.offset.end", "Fine" }, { "hex.view.hexeditor.error.read_only", "Impossibile scrivere sul File. File aperto solo in modalità lettura" }, { "hex.view.hexeditor.error.open", "Impossibile aprire il File!" }, + // { "hex.view.hexeditor.menu.edit.undo", "" }, + // { "hex.view.hexeditor.menu.edit.redo", "" }, { "hex.view.hexeditor.menu.edit.copy", "Copia come..." }, { "hex.view.hexeditor.copy.bytes", "Bytes" }, { "hex.view.hexeditor.copy.hex", "Stringa esadecimale" }, diff --git a/plugins/libimhex/include/hex/providers/provider.hpp b/plugins/libimhex/include/hex/providers/provider.hpp index 6a52d43c7..9df85fe74 100644 --- a/plugins/libimhex/include/hex/providers/provider.hpp +++ b/plugins/libimhex/include/hex/providers/provider.hpp @@ -50,10 +50,19 @@ namespace hex::prv { virtual std::vector> getDataInformation() = 0; + void addPatch(u64 offset, const void *buffer, size_t size); + + void undo(); + void redo(); + + bool canUndo(); + bool canRedo(); + protected: u32 m_currPage = 0; u64 m_baseAddress = 0; + u32 m_patchTreeOffset = 0; std::vector> m_patches; std::list m_overlays; }; diff --git a/plugins/libimhex/source/providers/provider.cpp b/plugins/libimhex/source/providers/provider.cpp index 049085cf3..ae0706bd8 100644 --- a/plugins/libimhex/source/providers/provider.cpp +++ b/plugins/libimhex/source/providers/provider.cpp @@ -40,11 +40,11 @@ namespace hex::prv { std::map& Provider::getPatches() { - return this->m_patches.back(); + return *(this->m_patches.end() - 1 - this->m_patchTreeOffset); } void Provider::applyPatches() { - for (auto &[patchAddress, patch] : this->m_patches.back()) + for (auto &[patchAddress, patch] : getPatches()) this->writeRaw(patchAddress, &patch, 1); } @@ -98,4 +98,34 @@ namespace hex::prv { return page; } + void Provider::addPatch(u64 offset, const void *buffer, size_t size) { + if (this->m_patchTreeOffset > 0) { + this->m_patches.erase(this->m_patches.end() - this->m_patchTreeOffset, this->m_patches.end()); + this->m_patchTreeOffset = 0; + } + + this->m_patches.push_back(getPatches()); + + for (u64 i = 0; i < size; i++) + getPatches()[offset + this->getBaseAddress() + i] = reinterpret_cast(buffer)[i]; + } + + void Provider::undo() { + if (canUndo()) + this->m_patchTreeOffset++; + } + + void Provider::redo() { + if (canRedo()) + this->m_patchTreeOffset--; + } + + bool Provider::canUndo() { + return this->m_patchTreeOffset < this->m_patches.size() - 1; + } + + bool Provider::canRedo() { + return this->m_patchTreeOffset > 0; + } + } \ No newline at end of file diff --git a/source/providers/file_provider.cpp b/source/providers/file_provider.cpp index ca330d46f..2bd9d2f79 100644 --- a/source/providers/file_provider.cpp +++ b/source/providers/file_provider.cpp @@ -131,8 +131,8 @@ namespace hex::prv { std::memcpy(buffer, reinterpret_cast(this->m_mappedFile) + PageSize * this->m_currPage + offset, size); for (u64 i = 0; i < size; i++) - if (this->m_patches.back().contains(offset + i)) - reinterpret_cast(buffer)[i] = this->m_patches.back()[offset + PageSize * this->m_currPage + i]; + if (getPatches().contains(offset + i)) + reinterpret_cast(buffer)[i] = getPatches()[offset + PageSize * this->m_currPage + i]; if (overlays) this->applyOverlays(offset, buffer, size); @@ -142,10 +142,7 @@ namespace hex::prv { if ((offset + size) > this->getSize() || buffer == nullptr || size == 0) return; - this->m_patches.push_back(this->m_patches.back()); - - for (u64 i = 0; i < size; i++) - this->m_patches.back()[offset + this->getBaseAddress() + i] = reinterpret_cast(buffer)[i]; + addPatch(offset, buffer, size); } void FileProvider::readRaw(u64 offset, void *buffer, size_t size) { diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index 7176b3957..cb4e651f5 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -508,6 +508,12 @@ namespace hex { saveAs(); return true; } else if (mods == GLFW_MOD_CONTROL && key == 'Z') { + if (SharedData::currentProvider != nullptr) + SharedData::currentProvider->undo(); + } else if (mods == GLFW_MOD_CONTROL && key == 'Y') { + if (SharedData::currentProvider != nullptr) + SharedData::currentProvider->redo(); + } else if (mods == GLFW_MOD_CONTROL && key == 'F') { View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.search"_lang); }); return true; } else if (mods == GLFW_MOD_CONTROL && key == 'G') { @@ -1060,6 +1066,11 @@ R"( } void ViewHexEditor::drawEditPopup() { + if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.undo", "CTRL + Z", false, SharedData::currentProvider != nullptr)) + SharedData::currentProvider->undo(); + if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.redo", "CTRL + Y", false, SharedData::currentProvider != nullptr)) + SharedData::currentProvider->redo(); + if (ImGui::BeginMenu("hex.view.hexeditor.menu.edit.copy"_lang, this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) { if (ImGui::MenuItem("hex.view.hexeditor.copy.bytes"_lang, "CTRL + ALT + C")) this->copyBytes();