mirror of https://github.com/WerWolv/ImHex
feat: Initial work rework current project system
This commit is contained in:
parent
b3d208e6e6
commit
efe0928fc6
|
|
@ -22,6 +22,9 @@ set(LIBIMHEX_SOURCES
|
||||||
source/data_processor/link.cpp
|
source/data_processor/link.cpp
|
||||||
source/data_processor/node.cpp
|
source/data_processor/node.cpp
|
||||||
|
|
||||||
|
source/project/project.cpp
|
||||||
|
source/project/project_manager.cpp
|
||||||
|
|
||||||
source/helpers/utils.cpp
|
source/helpers/utils.cpp
|
||||||
source/helpers/utils_linux.cpp
|
source/helpers/utils_linux.cpp
|
||||||
source/helpers/fs.cpp
|
source/helpers/fs.cpp
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex.hpp>
|
||||||
|
#include <hex/api/localization_manager.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace hex::proj {
|
||||||
|
|
||||||
|
class Content {
|
||||||
|
public:
|
||||||
|
explicit Content(UnlocalizedString type, std::string name)
|
||||||
|
: m_type(std::move(type)), m_name(std::move(name)) { }
|
||||||
|
|
||||||
|
void setData(std::string data) { m_data = std::move(data); }
|
||||||
|
const std::string& getData() const { return m_data; }
|
||||||
|
|
||||||
|
const std::string& getName() const { return m_name; }
|
||||||
|
void setName(std::string name) { m_name = std::move(name); }
|
||||||
|
|
||||||
|
const UnlocalizedString& getType() const { return m_type; }
|
||||||
|
|
||||||
|
bool isOpen() const { return m_open; }
|
||||||
|
void setOpen(bool open) { m_open = open; }
|
||||||
|
|
||||||
|
bool isEmpty() const { return m_data.empty(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
UnlocalizedString m_type;
|
||||||
|
std::string m_name;
|
||||||
|
std::string m_data;
|
||||||
|
bool m_open = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Project {
|
||||||
|
public:
|
||||||
|
explicit Project(std::string name) : m_name(std::move(name)) {}
|
||||||
|
Project(const Project &) = delete;
|
||||||
|
Project(Project &&) = delete;
|
||||||
|
~Project();
|
||||||
|
|
||||||
|
Project &operator=(const Project &) = delete;
|
||||||
|
Project &operator=(Project &&) = delete;
|
||||||
|
|
||||||
|
const std::string &getName() const { return m_name; }
|
||||||
|
|
||||||
|
void addContent(UnlocalizedString type);
|
||||||
|
const std::list<std::unique_ptr<Content>>& getContents() const { return m_contents; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
std::list<std::unique_ptr<Content>> m_contents;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex.hpp>
|
||||||
|
#include <hex/project/project.hpp>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace hex::proj {
|
||||||
|
|
||||||
|
class ProjectManager {
|
||||||
|
ProjectManager() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void createProject(std::string name);
|
||||||
|
static void loadProject(const std::filesystem::path &path);
|
||||||
|
static void removeProject(const Project &project);
|
||||||
|
|
||||||
|
using LoadFunction = std::function<void(const Content&)>;
|
||||||
|
using StoreFunction = std::function<void(Content&)>;
|
||||||
|
|
||||||
|
struct ContentHandler {
|
||||||
|
UnlocalizedString type;
|
||||||
|
bool allowMultiple = false;
|
||||||
|
LoadFunction load;
|
||||||
|
StoreFunction store;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void registerContentHandler(ContentHandler handler);
|
||||||
|
static const std::list<ContentHandler>& getContentHandlers();
|
||||||
|
static const ContentHandler* getContentHandler(const UnlocalizedString &typeName);
|
||||||
|
|
||||||
|
static const std::list<std::unique_ptr<Project>> &getProjects();
|
||||||
|
|
||||||
|
static void storeContent(Content &content);
|
||||||
|
static void loadContent(Content &content);
|
||||||
|
|
||||||
|
static Content* getLoadedContent(const UnlocalizedString &type);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <hex/project/project.hpp>
|
||||||
|
#include <hex/project/project_manager.hpp>
|
||||||
|
|
||||||
|
namespace hex::proj {
|
||||||
|
|
||||||
|
Project::~Project() {
|
||||||
|
for (auto &content : m_contents) {
|
||||||
|
ProjectManager::storeContent(*content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Project::addContent(UnlocalizedString type) {
|
||||||
|
const auto &content = m_contents.emplace_back(
|
||||||
|
std::make_unique<Content>(
|
||||||
|
type,
|
||||||
|
fmt::format("Unnamed {}", Lang(type))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const auto loadedContent = ProjectManager::getLoadedContent(type);
|
||||||
|
ProjectManager::storeContent(loadedContent == nullptr ? *content : *loadedContent);
|
||||||
|
|
||||||
|
ProjectManager::loadContent(*content);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include <hex/helpers/auto_reset.hpp>
|
||||||
|
#include <hex/project/project_manager.hpp>
|
||||||
|
|
||||||
|
namespace hex::proj {
|
||||||
|
|
||||||
|
static AutoReset<std::list<std::unique_ptr<Project>>> s_projects;
|
||||||
|
static AutoReset<std::list<ProjectManager::ContentHandler>> s_contentHandlers;
|
||||||
|
|
||||||
|
void ProjectManager::createProject(std::string name) {
|
||||||
|
s_projects->emplace_back(std::make_unique<Project>(std::move(name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectManager::loadProject(const std::filesystem::path &path) {
|
||||||
|
std::ignore = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectManager::removeProject(const Project &projectToClose) {
|
||||||
|
std::erase_if(*s_projects, [&](const std::unique_ptr<Project> &project) {
|
||||||
|
return project.get() == &projectToClose;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::list<std::unique_ptr<Project>> &ProjectManager::getProjects() {
|
||||||
|
return *s_projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::list<ProjectManager::ContentHandler> &ProjectManager::getContentHandlers() {
|
||||||
|
return *s_contentHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectManager::registerContentHandler(ContentHandler handler) {
|
||||||
|
s_contentHandlers->emplace_back(std::move(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectManager::ContentHandler* ProjectManager::getContentHandler(const UnlocalizedString &typeName) {
|
||||||
|
for (const auto &handler : getContentHandlers()) {
|
||||||
|
if (handler.type == typeName) {
|
||||||
|
return &handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectManager::storeContent(Content &content) {
|
||||||
|
const auto *handler = getContentHandler(content.getType());
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->store(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectManager::loadContent(Content &content) {
|
||||||
|
const auto *handler = getContentHandler(content.getType());
|
||||||
|
|
||||||
|
if (handler != nullptr) {
|
||||||
|
if (!handler->allowMultiple) {
|
||||||
|
for (const auto &project : getProjects()) {
|
||||||
|
for (const auto &projectContent : project->getContents()) {
|
||||||
|
if (projectContent->isOpen() && projectContent->getType() == content.getType()) {
|
||||||
|
storeContent(*projectContent);
|
||||||
|
projectContent->setOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handler->type == content.getType()) {
|
||||||
|
handler->load(content);
|
||||||
|
content.setOpen(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Content* ProjectManager::getLoadedContent(const UnlocalizedString& type) {
|
||||||
|
for (const auto &project : getProjects()) {
|
||||||
|
for (const auto &projectContent : project->getContents()) {
|
||||||
|
if (projectContent->isOpen() && projectContent->getType() == type) {
|
||||||
|
return projectContent.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,8 @@ add_imhex_plugin(
|
||||||
|
|
||||||
source/content/helpers/demangle.cpp
|
source/content/helpers/demangle.cpp
|
||||||
|
|
||||||
|
source/content/sidebar/project_explorer.cpp
|
||||||
|
|
||||||
source/content/data_processor_nodes/basic_nodes.cpp
|
source/content/data_processor_nodes/basic_nodes.cpp
|
||||||
source/content/data_processor_nodes/control_nodes.cpp
|
source/content/data_processor_nodes/control_nodes.cpp
|
||||||
source/content/data_processor_nodes/decode_nodes.cpp
|
source/content/data_processor_nodes/decode_nodes.cpp
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ namespace hex::plugin::builtin {
|
||||||
private:
|
private:
|
||||||
std::string m_currFilter;
|
std::string m_currFilter;
|
||||||
|
|
||||||
PerProvider<std::list<Bookmark>> m_bookmarks;
|
std::list<Bookmark> m_bookmarks;
|
||||||
PerProvider<u64> m_currBookmarkId;
|
u64 m_currBookmarkId;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ namespace hex::plugin::builtin {
|
||||||
void reloadCustomNodes();
|
void reloadCustomNodes();
|
||||||
void updateNodePositions();
|
void updateNodePositions();
|
||||||
|
|
||||||
std::vector<Workspace*> &getWorkspaceStack() { return *m_workspaceStack; }
|
std::vector<Workspace*> &getWorkspaceStack() { return m_workspaceStack; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void drawContextMenus(ViewDataProcessor::Workspace &workspace);
|
void drawContextMenus(ViewDataProcessor::Workspace &workspace);
|
||||||
|
|
@ -76,8 +76,8 @@ namespace hex::plugin::builtin {
|
||||||
|
|
||||||
std::vector<CustomNode> m_customNodes;
|
std::vector<CustomNode> m_customNodes;
|
||||||
|
|
||||||
PerProvider<Workspace> m_mainWorkspace;
|
Workspace m_mainWorkspace;
|
||||||
PerProvider<std::vector<Workspace*>> m_workspaceStack;
|
std::vector<Workspace*> m_workspaceStack;
|
||||||
TaskHolder m_evaluationTask;
|
TaskHolder m_evaluationTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,10 @@
|
||||||
"hex.builtin.popup.save_layout.title": "Save Layout",
|
"hex.builtin.popup.save_layout.title": "Save Layout",
|
||||||
"hex.builtin.popup.save_layout.desc": "Enter a name under which to save the current layout.",
|
"hex.builtin.popup.save_layout.desc": "Enter a name under which to save the current layout.",
|
||||||
"hex.builtin.popup.waiting_for_tasks.desc": "There are still tasks running in the background.\nImHex will close after they are finished.",
|
"hex.builtin.popup.waiting_for_tasks.desc": "There are still tasks running in the background.\nImHex will close after they are finished.",
|
||||||
|
"hex.builtin.project.content_type.pattern": "Pattern Source Code",
|
||||||
|
"hex.builtin.project.content_type.bookmarks": "Bookmarks",
|
||||||
|
"hex.builtin.project.content_type.data_processor": "Data Processor Nodes",
|
||||||
|
"hex.builtin.project.free_items": "Free Items",
|
||||||
"hex.builtin.provider.rename": "Rename",
|
"hex.builtin.provider.rename": "Rename",
|
||||||
"hex.builtin.provider.rename.desc": "Enter a name for this provider.",
|
"hex.builtin.provider.rename.desc": "Enter a name for this provider.",
|
||||||
"hex.builtin.provider.tooltip.show_more": "Hold SHIFT for more information",
|
"hex.builtin.provider.tooltip.show_more": "Hold SHIFT for more information",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
|
#include <fonts/vscode_icons.hpp>
|
||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
#include <hex/api/task_manager.hpp>
|
||||||
|
|
||||||
|
#include <hex/project/project.hpp>
|
||||||
|
#include <hex/project/project_manager.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void drawContent(proj::Content &content) {
|
||||||
|
static proj::Content *rightClickedContent = nullptr;
|
||||||
|
static proj::Content *renamingContent = nullptr;
|
||||||
|
static std::string renameText;
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
if (renamingContent != &content) {
|
||||||
|
ImGui::Selectable(content.getName().c_str(), content.isOpen(), ImGuiSelectableFlags_SpanAllColumns);
|
||||||
|
} else {
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||||
|
if (ImGui::InputText("##ContentName", renameText)) {
|
||||||
|
renamingContent->setName(renameText);
|
||||||
|
}
|
||||||
|
ImGui::SetKeyboardFocusHere(-1);
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter)) {
|
||||||
|
renamingContent->setName(renameText);
|
||||||
|
renamingContent = nullptr;
|
||||||
|
}
|
||||||
|
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||||
|
renamingContent = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||||
|
proj::ProjectManager::loadContent(content);
|
||||||
|
}
|
||||||
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
|
||||||
|
rightClickedContent = &content;
|
||||||
|
ImGui::OpenPopup("ContentContextMenu");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && renamingContent == &content)
|
||||||
|
renamingContent = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted(Lang(content.getType()));
|
||||||
|
|
||||||
|
if (rightClickedContent == &content) {
|
||||||
|
if (ImGui::BeginPopup("ContentContextMenu")) {
|
||||||
|
if (ImGui::MenuItemEx("Open", ICON_VS_OPEN_PREVIEW)) {
|
||||||
|
proj::ProjectManager::loadContent(content);
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItemEx("Rename", ICON_VS_DIFF_RENAMED)) {
|
||||||
|
renamingContent = &content;
|
||||||
|
renameText = content.getName();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawProject(proj::Project &project) {
|
||||||
|
static proj::Project *rightClickedProject = nullptr;
|
||||||
|
|
||||||
|
bool open = ImGui::TreeNodeEx(project.getName().c_str(), ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanAllColumns);
|
||||||
|
|
||||||
|
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||||
|
rightClickedProject = &project;
|
||||||
|
ImGui::OpenPopup("ProjectContextMenu");
|
||||||
|
}
|
||||||
|
if (rightClickedProject == &project) {
|
||||||
|
if (ImGui::BeginPopup("ProjectContextMenu")) {
|
||||||
|
if (ImGui::BeginMenuEx("Add", ICON_VS_FILE_ADD)) {
|
||||||
|
for (const auto &handler : proj::ProjectManager::getContentHandlers()) {
|
||||||
|
if (ImGui::MenuItem(Lang(handler.type))) {
|
||||||
|
rightClickedProject->addContent(handler.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItemEx("Close", ICON_VS_CLOSE)) {
|
||||||
|
TaskManager::doLater([project = rightClickedProject] {
|
||||||
|
proj::ProjectManager::removeProject(*project);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open) {
|
||||||
|
for (const auto &content : project.getContents()) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::PushID(content.get());
|
||||||
|
|
||||||
|
drawContent(*content);
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerProjectExplorer() {
|
||||||
|
ContentRegistry::Interface::addSidebarItem(ICON_VS_PROJECT, [] {
|
||||||
|
if (ImGui::BeginTable("Projects", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) {
|
||||||
|
ImGui::TableSetupColumn("##Icon", ImGuiTableColumnFlags_WidthFixed, 20_scaled);
|
||||||
|
ImGui::TableSetupColumn("##Name", ImGuiTableColumnFlags_WidthStretch, 20_scaled);
|
||||||
|
ImGui::TableSetupColumn("##Type", ImGuiTableColumnFlags_WidthFixed, 100_scaled);
|
||||||
|
for (auto &project : proj::ProjectManager::getProjects()) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::PushID(project.get());
|
||||||
|
drawProject(*project);
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
ImGui::NewLine();
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
proj::ProjectManager::createProject("Project 1");
|
||||||
|
proj::ProjectManager::createProject("Project 2");
|
||||||
|
proj::ProjectManager::createProject("Free Items");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <content/providers/view_provider.hpp>
|
#include <content/providers/view_provider.hpp>
|
||||||
|
|
||||||
#include <fonts/vscode_icons.hpp>
|
#include <fonts/vscode_icons.hpp>
|
||||||
|
#include <hex/project/project_manager.hpp>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
|
@ -45,16 +46,16 @@ namespace hex::plugin::builtin {
|
||||||
bookmarkId
|
bookmarkId
|
||||||
};
|
};
|
||||||
|
|
||||||
m_bookmarks->emplace_back(std::move(bookmark), true);
|
m_bookmarks.emplace_back(std::move(bookmark), true);
|
||||||
|
|
||||||
ImHexApi::Provider::markDirty();
|
ImHexApi::Provider::markDirty();
|
||||||
|
|
||||||
EventBookmarkCreated::post(m_bookmarks->back().entry);
|
EventBookmarkCreated::post(m_bookmarks.back().entry);
|
||||||
EventHighlightingChanged::post();
|
EventHighlightingChanged::post();
|
||||||
});
|
});
|
||||||
|
|
||||||
RequestRemoveBookmark::subscribe([this](u64 id) {
|
RequestRemoveBookmark::subscribe([this](u64 id) {
|
||||||
std::erase_if(m_bookmarks.get(), [id](const auto &bookmark) {
|
std::erase_if(m_bookmarks, [id](const auto &bookmark) {
|
||||||
return bookmark.entry.id == id;
|
return bookmark.entry.id == id;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -65,7 +66,7 @@ namespace hex::plugin::builtin {
|
||||||
|
|
||||||
// Check all bookmarks for potential overlaps with the current address
|
// Check all bookmarks for potential overlaps with the current address
|
||||||
std::optional<ImColor> color;
|
std::optional<ImColor> color;
|
||||||
for (const auto &bookmark : *m_bookmarks) {
|
for (const auto &bookmark : m_bookmarks) {
|
||||||
if (!bookmark.highlightVisible)
|
if (!bookmark.highlightVisible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -82,7 +83,7 @@ namespace hex::plugin::builtin {
|
||||||
std::ignore = data;
|
std::ignore = data;
|
||||||
|
|
||||||
// Loop over all bookmarks
|
// Loop over all bookmarks
|
||||||
for (const auto &[bookmark, highlightVisible] : *m_bookmarks) {
|
for (const auto &[bookmark, highlightVisible] : m_bookmarks) {
|
||||||
if (!highlightVisible)
|
if (!highlightVisible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -158,7 +159,7 @@ namespace hex::plugin::builtin {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end());
|
auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end());
|
||||||
m_bookmarks.get(provider).clear();
|
m_bookmarks.clear();
|
||||||
return this->importBookmarks(provider, data);
|
return this->importBookmarks(provider, data);
|
||||||
},
|
},
|
||||||
.store = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) -> bool {
|
.store = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) -> bool {
|
||||||
|
|
@ -170,11 +171,26 @@ namespace hex::plugin::builtin {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
proj::ProjectManager::registerContentHandler({
|
||||||
|
.type = "hex.builtin.project.content_type.bookmarks",
|
||||||
|
.load = [this](const proj::Content &content) {
|
||||||
|
m_bookmarks.clear();
|
||||||
|
|
||||||
|
const auto data = content.isEmpty() ? nlohmann::json() : nlohmann::json::parse(content.getData());
|
||||||
|
this->importBookmarks(ImHexApi::Provider::get(), data);
|
||||||
|
EventHighlightingChanged::post();
|
||||||
|
},
|
||||||
|
.store = [this](proj::Content &content) {
|
||||||
|
nlohmann::json data;
|
||||||
|
this->exportBookmarks(ImHexApi::Provider::get(), data);
|
||||||
|
content.setData(data.dump(4));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ContentRegistry::Reports::addReportProvider([this](prv::Provider *provider) -> std::string {
|
ContentRegistry::Reports::addReportProvider([this](prv::Provider *provider) -> std::string {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
const auto &bookmarks = m_bookmarks.get(provider);
|
const auto &bookmarks = m_bookmarks;
|
||||||
if (bookmarks.empty())
|
if (bookmarks.empty())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
|
@ -252,7 +268,7 @@ namespace hex::plugin::builtin {
|
||||||
void ViewBookmarks::drawDropTarget(std::list<Bookmark>::iterator it, float height) {
|
void ViewBookmarks::drawDropTarget(std::list<Bookmark>::iterator it, float height) {
|
||||||
height = std::max(height, 1.0F);
|
height = std::max(height, 1.0F);
|
||||||
|
|
||||||
if (it != m_bookmarks->begin()) {
|
if (it != m_bookmarks.begin()) {
|
||||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - height);
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - height);
|
||||||
} else {
|
} else {
|
||||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + height);
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + height);
|
||||||
|
|
@ -261,7 +277,7 @@ namespace hex::plugin::builtin {
|
||||||
ImGui::InvisibleButton("##DropTarget", ImVec2(ImGui::GetContentRegionAvail().x, height * 2.0F));
|
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));
|
const auto dropTarget = ImRect(ImGui::GetItemRectMin(), ImVec2(ImGui::GetItemRectMax().x, ImGui::GetItemRectMin().y + 2_scaled));
|
||||||
|
|
||||||
if (it == m_bookmarks->begin()) {
|
if (it == m_bookmarks.begin()) {
|
||||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - height);
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -274,13 +290,13 @@ namespace hex::plugin::builtin {
|
||||||
u64 droppedBookmarkId = *static_cast<const u64*>(payload->Data);
|
u64 droppedBookmarkId = *static_cast<const u64*>(payload->Data);
|
||||||
|
|
||||||
// Find the correct bookmark with that id
|
// Find the correct bookmark with that id
|
||||||
auto droppedIter = std::ranges::find_if(m_bookmarks->begin(), m_bookmarks->end(), [droppedBookmarkId](const auto &bookmarkItem) {
|
auto droppedIter = std::ranges::find_if(m_bookmarks.begin(), m_bookmarks.end(), [droppedBookmarkId](const auto &bookmarkItem) {
|
||||||
return bookmarkItem.entry.id == droppedBookmarkId;
|
return bookmarkItem.entry.id == droppedBookmarkId;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Swap the two bookmarks
|
// Swap the two bookmarks
|
||||||
if (droppedIter != m_bookmarks->end()) {
|
if (droppedIter != m_bookmarks.end()) {
|
||||||
m_bookmarks->splice(it, m_bookmarks, droppedIter);
|
m_bookmarks.splice(it, m_bookmarks, droppedIter);
|
||||||
|
|
||||||
EventHighlightingChanged::post();
|
EventHighlightingChanged::post();
|
||||||
}
|
}
|
||||||
|
|
@ -298,18 +314,18 @@ namespace hex::plugin::builtin {
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
if (ImGui::BeginChild("##bookmarks")) {
|
if (ImGui::BeginChild("##bookmarks")) {
|
||||||
if (m_bookmarks->empty()) {
|
if (m_bookmarks.empty()) {
|
||||||
ImGuiExt::TextOverlay("hex.builtin.view.bookmarks.no_bookmarks"_lang, ImGui::GetWindowPos() + ImGui::GetWindowSize() / 2, ImGui::GetWindowWidth() * 0.7);
|
ImGuiExt::TextOverlay("hex.builtin.view.bookmarks.no_bookmarks"_lang, ImGui::GetWindowPos() + ImGui::GetWindowSize() / 2, ImGui::GetWindowWidth() * 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bookmarkToRemove = m_bookmarks->end();
|
auto bookmarkToRemove = m_bookmarks.end();
|
||||||
const auto defaultItemSpacing = ImGui::GetStyle().ItemSpacing.y;
|
const auto defaultItemSpacing = ImGui::GetStyle().ItemSpacing.y;
|
||||||
|
|
||||||
ImGui::Dummy({ ImGui::GetContentRegionAvail().x, 0 });
|
ImGui::Dummy({ ImGui::GetContentRegionAvail().x, 0 });
|
||||||
drawDropTarget(m_bookmarks->begin(), defaultItemSpacing);
|
drawDropTarget(m_bookmarks.begin(), defaultItemSpacing);
|
||||||
|
|
||||||
// Draw all bookmarks
|
// Draw all bookmarks
|
||||||
for (auto it = m_bookmarks->begin(); it != m_bookmarks->end(); ++it) {
|
for (auto it = m_bookmarks.begin(); it != m_bookmarks.end(); ++it) {
|
||||||
auto &[bookmark, highlightVisible] = *it;
|
auto &[bookmark, highlightVisible] = *it;
|
||||||
auto &[region, name, comment, color, locked, bookmarkId] = bookmark;
|
auto &[region, name, comment, color, locked, bookmarkId] = bookmark;
|
||||||
|
|
||||||
|
|
@ -529,15 +545,15 @@ namespace hex::plugin::builtin {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the bookmark that was marked for removal
|
// Remove the bookmark that was marked for removal
|
||||||
if (bookmarkToRemove != m_bookmarks->end()) {
|
if (bookmarkToRemove != m_bookmarks.end()) {
|
||||||
m_bookmarks->erase(bookmarkToRemove);
|
m_bookmarks.erase(bookmarkToRemove);
|
||||||
EventHighlightingChanged::post();
|
EventHighlightingChanged::post();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViewBookmarks::importBookmarks(prv::Provider *provider, const nlohmann::json &json) {
|
bool ViewBookmarks::importBookmarks(prv::Provider *, const nlohmann::json &json) {
|
||||||
if (!json.contains("bookmarks"))
|
if (!json.contains("bookmarks"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -549,30 +565,32 @@ namespace hex::plugin::builtin {
|
||||||
if (!region.contains("address") || !region.contains("size"))
|
if (!region.contains("address") || !region.contains("size"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_bookmarks.get(provider).push_back({
|
m_bookmarks.push_back({
|
||||||
{
|
{
|
||||||
.region = { region["address"], region["size"] },
|
.region = { region["address"], region["size"] },
|
||||||
.name = bookmark["name"],
|
.name = bookmark["name"],
|
||||||
.comment = bookmark["comment"],
|
.comment = bookmark["comment"],
|
||||||
.color = bookmark["color"],
|
.color = bookmark["color"],
|
||||||
.locked = bookmark["locked"],
|
.locked = bookmark["locked"],
|
||||||
.id = bookmark.contains("id") ? bookmark["id"].get<u64>() : m_currBookmarkId.get(provider),
|
.id = bookmark.contains("id") ? bookmark["id"].get<u64>() : m_currBookmarkId,
|
||||||
},
|
},
|
||||||
bookmark.contains("highlightVisible") ? bookmark["highlightVisible"].get<bool>() : true,
|
bookmark.contains("highlightVisible") ? bookmark["highlightVisible"].get<bool>() : true,
|
||||||
});
|
});
|
||||||
if (bookmark.contains("id"))
|
if (bookmark.contains("id"))
|
||||||
m_currBookmarkId.get(provider) = std::max<u64>(m_currBookmarkId.get(provider), bookmark["id"].get<i64>() + 1);
|
m_currBookmarkId = std::max<u64>(m_currBookmarkId, bookmark["id"].get<i64>() + 1);
|
||||||
else
|
else
|
||||||
m_currBookmarkId.get(provider) += 1;
|
m_currBookmarkId += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EventHighlightingChanged::post();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ViewBookmarks::exportBookmarks(prv::Provider *provider, nlohmann::json &json) {
|
bool ViewBookmarks::exportBookmarks(prv::Provider *, nlohmann::json &json) {
|
||||||
json["bookmarks"] = nlohmann::json::array();
|
json["bookmarks"] = nlohmann::json::array();
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
for (const auto &[bookmark, highlightVisible] : m_bookmarks.get(provider)) {
|
for (const auto &[bookmark, highlightVisible] : m_bookmarks) {
|
||||||
json["bookmarks"][index] = {
|
json["bookmarks"][index] = {
|
||||||
{ "name", bookmark.name },
|
{ "name", bookmark.name },
|
||||||
{ "comment", bookmark.comment },
|
{ "comment", bookmark.comment },
|
||||||
|
|
@ -627,7 +645,7 @@ namespace hex::plugin::builtin {
|
||||||
wolv::io::File(path, wolv::io::File::Mode::Create).writeString(json.dump(4));
|
wolv::io::File(path, wolv::io::File::Mode::Create).writeString(json.dump(4));
|
||||||
});
|
});
|
||||||
}, [this]{
|
}, [this]{
|
||||||
return ImHexApi::Provider::isValid() && !m_bookmarks->empty();
|
return ImHexApi::Provider::isValid() && !m_bookmarks.empty();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <imnodes.h>
|
#include <imnodes.h>
|
||||||
#include <imnodes_internal.h>
|
#include <imnodes_internal.h>
|
||||||
|
#include <hex/project/project_manager.hpp>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <wolv/io/file.hpp>
|
#include <wolv/io/file.hpp>
|
||||||
|
|
@ -361,28 +362,39 @@ namespace hex::plugin::builtin {
|
||||||
ProjectFile::registerPerProviderHandler({
|
ProjectFile::registerPerProviderHandler({
|
||||||
.basePath = "data_processor.json",
|
.basePath = "data_processor.json",
|
||||||
.required = false,
|
.required = false,
|
||||||
.load = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) {
|
.load = [this](prv::Provider *, const std::fs::path &basePath, const Tar &tar) {
|
||||||
std::string save = tar.readString(basePath);
|
std::string save = tar.readString(basePath);
|
||||||
|
|
||||||
ViewDataProcessor::loadNodes(m_mainWorkspace.get(provider), nlohmann::json::parse(save));
|
this->loadNodes(m_mainWorkspace, nlohmann::json::parse(save));
|
||||||
m_updateNodePositions = true;
|
m_updateNodePositions = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
.store = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) {
|
.store = [this](prv::Provider *, const std::fs::path &basePath, const Tar &tar) {
|
||||||
tar.writeString(basePath, ViewDataProcessor::saveNodes(m_mainWorkspace.get(provider)).dump(4));
|
tar.writeString(basePath, this->saveNodes(m_mainWorkspace).dump(4));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
proj::ProjectManager::registerContentHandler({
|
||||||
|
.type = "hex.builtin.project.content_type.data_processor",
|
||||||
|
.load = [this](const proj::Content &content) {
|
||||||
|
const nlohmann::json data = content.isEmpty() ? nlohmann::json() : nlohmann::json::parse(content.getData());
|
||||||
|
this->loadNodes(m_mainWorkspace, data);
|
||||||
|
m_updateNodePositions = true;
|
||||||
|
},
|
||||||
|
.store = [this](proj::Content &content) {
|
||||||
|
content.setData(this->saveNodes(m_mainWorkspace).dump(4));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
EventProviderOpened::subscribe(this, [this](auto *provider) {
|
EventProviderOpened::subscribe(this, [this](auto *) {
|
||||||
m_mainWorkspace.get(provider) = { };
|
m_mainWorkspace = { };
|
||||||
m_workspaceStack.get(provider).push_back(&m_mainWorkspace.get(provider));
|
m_workspaceStack.push_back(&m_mainWorkspace);
|
||||||
});
|
});
|
||||||
|
|
||||||
EventProviderChanged::subscribe(this, [this](const auto *, const auto *) {
|
EventProviderChanged::subscribe(this, [this](const auto *, const auto *) {
|
||||||
for (auto *workspace : *m_workspaceStack) {
|
for (auto *workspace : m_workspaceStack) {
|
||||||
for (auto &node : workspace->nodes) {
|
for (auto &node : workspace->nodes) {
|
||||||
node->setCurrentOverlay(nullptr);
|
node->setCurrentOverlay(nullptr);
|
||||||
}
|
}
|
||||||
|
|
@ -399,7 +411,7 @@ namespace hex::plugin::builtin {
|
||||||
[&](const std::fs::path &path) {
|
[&](const std::fs::path &path) {
|
||||||
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||||
if (file.isValid()) {
|
if (file.isValid()) {
|
||||||
ViewDataProcessor::loadNodes(*m_mainWorkspace, nlohmann::json::parse(file.readString()));
|
ViewDataProcessor::loadNodes(m_mainWorkspace, nlohmann::json::parse(file.readString()));
|
||||||
m_updateNodePositions = true;
|
m_updateNodePositions = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -411,17 +423,17 @@ namespace hex::plugin::builtin {
|
||||||
[&, this](const std::fs::path &path) {
|
[&, this](const std::fs::path &path) {
|
||||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||||
if (file.isValid())
|
if (file.isValid())
|
||||||
file.writeString(ViewDataProcessor::saveNodes(*m_mainWorkspace).dump(4));
|
file.writeString(ViewDataProcessor::saveNodes(m_mainWorkspace).dump(4));
|
||||||
});
|
});
|
||||||
}, [this]{
|
}, [this]{
|
||||||
return !m_workspaceStack->empty() && !m_workspaceStack->back()->nodes.empty() && ImHexApi::Provider::isValid();
|
return !m_workspaceStack.empty() && !m_workspaceStack.back()->nodes.empty() && ImHexApi::Provider::isValid();
|
||||||
});
|
});
|
||||||
|
|
||||||
ContentRegistry::FileHandler::add({ ".hexnode" }, [this](const auto &path) {
|
ContentRegistry::FileHandler::add({ ".hexnode" }, [this](const auto &path) {
|
||||||
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||||
if (!file.isValid()) return false;
|
if (!file.isValid()) return false;
|
||||||
|
|
||||||
ViewDataProcessor::loadNodes(*m_mainWorkspace, file.readString());
|
ViewDataProcessor::loadNodes(m_mainWorkspace, file.readString());
|
||||||
m_updateNodePositions = true;
|
m_updateNodePositions = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -884,7 +896,7 @@ namespace hex::plugin::builtin {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewDataProcessor::drawContent() {
|
void ViewDataProcessor::drawContent() {
|
||||||
auto &workspace = *m_workspaceStack->back();
|
auto &workspace = *m_workspaceStack.back();
|
||||||
|
|
||||||
ImGui::BeginDisabled(m_evaluationTask.isRunning());
|
ImGui::BeginDisabled(m_evaluationTask.isRunning());
|
||||||
|
|
||||||
|
|
@ -962,7 +974,7 @@ namespace hex::plugin::builtin {
|
||||||
ImGuiExt::TextFormattedCentered("{}", "hex.builtin.view.data_processor.help_text"_lang);
|
ImGuiExt::TextFormattedCentered("{}", "hex.builtin.view.data_processor.help_text"_lang);
|
||||||
|
|
||||||
// Draw a close button if there is more than one workspace on the stack
|
// Draw a close button if there is more than one workspace on the stack
|
||||||
if (m_workspaceStack->size() > 1) {
|
if (m_workspaceStack.size() > 1) {
|
||||||
ImGui::SetCursorPos(ImVec2(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 1.5F, ImGui::GetTextLineHeightWithSpacing() * 0.2F));
|
ImGui::SetCursorPos(ImVec2(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 1.5F, ImGui::GetTextLineHeightWithSpacing() * 0.2F));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0F, 4.0F));
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0F, 4.0F));
|
||||||
if (ImGuiExt::DimmedIconButton(ICON_VS_CLOSE, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
|
if (ImGuiExt::DimmedIconButton(ICON_VS_CLOSE, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
|
||||||
|
|
@ -1079,7 +1091,7 @@ namespace hex::plugin::builtin {
|
||||||
|
|
||||||
// Remove the top-most workspace from the stack if requested
|
// Remove the top-most workspace from the stack if requested
|
||||||
if (popWorkspace) {
|
if (popWorkspace) {
|
||||||
m_workspaceStack->pop_back();
|
m_workspaceStack.pop_back();
|
||||||
m_updateNodePositions = true;
|
m_updateNodePositions = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@
|
||||||
|
|
||||||
#include <content/global_actions.hpp>
|
#include <content/global_actions.hpp>
|
||||||
#include <fonts/fonts.hpp>
|
#include <fonts/fonts.hpp>
|
||||||
|
#include <hex/project/project.hpp>
|
||||||
|
#include <hex/project/project_manager.hpp>
|
||||||
#include <ui/menu_items.hpp>
|
#include <ui/menu_items.hpp>
|
||||||
|
|
||||||
namespace hex::plugin::builtin {
|
namespace hex::plugin::builtin {
|
||||||
|
|
@ -333,9 +335,9 @@ namespace hex::plugin::builtin {
|
||||||
const auto availableSize = g.CurrentWindow->Size;
|
const auto availableSize = g.CurrentWindow->Size;
|
||||||
const auto windowPosition = ImGui::GetCursorScreenPos();
|
const auto windowPosition = ImGui::GetCursorScreenPos();
|
||||||
auto textEditorSize = availableSize;
|
auto textEditorSize = availableSize;
|
||||||
textEditorSize.y *= 3.5 / 5.0;
|
textEditorSize.y *= 3.5F / 5.0F;
|
||||||
textEditorSize.y -= ImGui::GetTextLineHeightWithSpacing();
|
textEditorSize.y -= ImGui::GetTextLineHeightWithSpacing();
|
||||||
textEditorSize.y = std::clamp(textEditorSize.y + height,200.0F, availableSize.y-200.0F);
|
textEditorSize.y = std::clamp(textEditorSize.y + height, 200.0F, availableSize.y - 200.0F);
|
||||||
|
|
||||||
if (g.NavWindow != nullptr) {
|
if (g.NavWindow != nullptr) {
|
||||||
std::string name = g.NavWindow->Name;
|
std::string name = g.NavWindow->Name;
|
||||||
|
|
@ -1425,7 +1427,7 @@ namespace hex::plugin::builtin {
|
||||||
const auto &currScope = evaluator->getScope(-m_debuggerScopeIndex);
|
const auto &currScope = evaluator->getScope(-m_debuggerScopeIndex);
|
||||||
if (ImGui::BeginCombo("##scope", displayValue(currScope.parent, m_debuggerScopeIndex).c_str())) {
|
if (ImGui::BeginCombo("##scope", displayValue(currScope.parent, m_debuggerScopeIndex).c_str())) {
|
||||||
for (size_t i = 0; i < evaluator->getScopeCount(); i++) {
|
for (size_t i = 0; i < evaluator->getScopeCount(); i++) {
|
||||||
auto &scope = evaluator->getScope(-i);
|
auto &scope = evaluator->getScope(-i32(i));
|
||||||
|
|
||||||
if (ImGui::Selectable(displayValue(scope.parent, i).c_str(), i == size_t(m_debuggerScopeIndex))) {
|
if (ImGui::Selectable(displayValue(scope.parent, i).c_str(), i == size_t(m_debuggerScopeIndex))) {
|
||||||
m_debuggerScopeIndex = i;
|
m_debuggerScopeIndex = i;
|
||||||
|
|
@ -2299,6 +2301,16 @@ namespace hex::plugin::builtin {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
proj::ProjectManager::registerContentHandler({
|
||||||
|
.type = "hex.builtin.project.content_type.pattern",
|
||||||
|
.load = [this](const proj::Content &content) {
|
||||||
|
m_textEditor.SetText(content.getData());
|
||||||
|
},
|
||||||
|
.store = [this](proj::Content &content) {
|
||||||
|
content.setData(wolv::util::trim(m_textEditor.GetText()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ShortcutManager::addShortcut(this, CTRLCMD + Keys::G + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.goto_line", [this] {
|
ShortcutManager::addShortcut(this, CTRLCMD + Keys::G + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.goto_line", [this] {
|
||||||
m_openGotoLinePopUp = true;
|
m_openGotoLinePopUp = true;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ namespace hex::plugin::builtin {
|
||||||
void registerReportGenerators();
|
void registerReportGenerators();
|
||||||
void registerTutorials();
|
void registerTutorials();
|
||||||
void registerDataInformationSections();
|
void registerDataInformationSections();
|
||||||
|
void registerProjectExplorer();
|
||||||
void loadWorkspaces();
|
void loadWorkspaces();
|
||||||
|
|
||||||
void addWindowDecoration();
|
void addWindowDecoration();
|
||||||
|
|
@ -140,6 +141,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||||
registerReportGenerators();
|
registerReportGenerators();
|
||||||
registerTutorials();
|
registerTutorials();
|
||||||
registerDataInformationSections();
|
registerDataInformationSections();
|
||||||
|
registerProjectExplorer();
|
||||||
loadWorkspaces();
|
loadWorkspaces();
|
||||||
addWindowDecoration();
|
addWindowDecoration();
|
||||||
createWelcomeScreen();
|
createWelcomeScreen();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue