mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-30 13:05:25 -05:00
Added Plugin support (#102)
* Build refactoring and initial plugin support * Possibly fixed linux / mac build * Added libdl to libglad build script * Add glfw to imgui dependencies * Refactored common functionality into "libimhex" for plugins * Added plugin loading and example plugin * Added proper API for creating a custom view and a custom tools entry with plugins
This commit is contained in:
16
plugins/example/CMakeLists.txt
Normal file
16
plugins/example/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(example)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libimhex ${CMAKE_CURRENT_BINARY_DIR}/plugins/libimhex)
|
||||
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "plugin")
|
||||
|
||||
add_library(example SHARED
|
||||
source/plugin_example.cpp
|
||||
)
|
||||
|
||||
target_include_directories(example PUBLIC include)
|
||||
target_link_libraries(example imgui libimhex)
|
||||
33
plugins/example/source/plugin_example.cpp
Normal file
33
plugins/example/source/plugin_example.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <views/view.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
class ViewExample : public hex::View {
|
||||
public:
|
||||
ViewExample() : hex::View("Example") {}
|
||||
~ViewExample() override {}
|
||||
|
||||
void drawContent() override {
|
||||
if (ImGui::Begin("Example")) {
|
||||
ImGui::Text("Custom plugin window");
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
};
|
||||
|
||||
IMHEX_PLUGIN {
|
||||
|
||||
View* createView() {
|
||||
return new ViewExample();
|
||||
}
|
||||
|
||||
void drawToolsEntry() {
|
||||
if (ImGui::CollapsingHeader("Example Tool")) {
|
||||
ImGui::Text("Custom Plugin tool");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
19
plugins/libimhex/CMakeLists.txt
Normal file
19
plugins/libimhex/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(libimhex)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if (TARGET libimhex)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui)
|
||||
endif()
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
|
||||
add_library(libimhex STATIC
|
||||
source/helpers/event.cpp
|
||||
source/providers/provider.cpp
|
||||
source/views/view.cpp
|
||||
)
|
||||
|
||||
target_include_directories(libimhex PUBLIC include)
|
||||
target_link_libraries(libimhex PRIVATE imgui)
|
||||
41
plugins/libimhex/include/helpers/event.hpp
Normal file
41
plugins/libimhex/include/helpers/event.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace hex {
|
||||
|
||||
enum class Events {
|
||||
FileLoaded,
|
||||
DataChanged,
|
||||
PatternChanged,
|
||||
FileDropped,
|
||||
WindowClosing,
|
||||
RegionSelected,
|
||||
|
||||
SelectionChangeRequest,
|
||||
|
||||
AddBookmark,
|
||||
AppendPatternLanguageCode,
|
||||
|
||||
ProjectFileStore,
|
||||
ProjectFileLoad
|
||||
};
|
||||
|
||||
struct EventHandler {
|
||||
void *owner;
|
||||
Events eventType;
|
||||
std::function<void(const void*)> callback;
|
||||
};
|
||||
|
||||
class EventManager {
|
||||
public:
|
||||
void post(Events eventType, const void *userData);
|
||||
void subscribe(Events eventType, void *owner, std::function<void(const void*)> callback);
|
||||
void unsubscribe(Events eventType, void *sender);
|
||||
|
||||
private:
|
||||
std::vector<EventHandler> m_eventHandlers;
|
||||
};
|
||||
|
||||
}
|
||||
32
plugins/libimhex/include/hex.hpp
Normal file
32
plugins/libimhex/include/hex.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
using u128 = __uint128_t;
|
||||
|
||||
using s8 = std::int8_t;
|
||||
using s16 = std::int16_t;
|
||||
using s32 = std::int32_t;
|
||||
using s64 = std::int64_t;
|
||||
using s128 = __int128_t;
|
||||
|
||||
extern int mainArgc;
|
||||
extern char **mainArgv;
|
||||
|
||||
#define IMHEX_PLUGIN namespace hex::plugin::internal { \
|
||||
void setImGuiContext(ImGuiContext *ctx) { \
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
} \
|
||||
} \
|
||||
namespace hex::plugin
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
#define MAGIC_PATH_SEPARATOR ";"
|
||||
#else
|
||||
#define MAGIC_PATH_SEPARATOR ":"
|
||||
#endif
|
||||
49
plugins/libimhex/include/providers/provider.hpp
Normal file
49
plugins/libimhex/include/providers/provider.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
class Provider {
|
||||
public:
|
||||
constexpr static size_t PageSize = 0x1000'0000;
|
||||
|
||||
Provider();
|
||||
virtual ~Provider() = default;
|
||||
|
||||
virtual bool isAvailable() = 0;
|
||||
virtual bool isReadable() = 0;
|
||||
virtual bool isWritable() = 0;
|
||||
|
||||
virtual void read(u64 offset, void *buffer, size_t size);
|
||||
virtual void write(u64 offset, const void *buffer, size_t size);
|
||||
|
||||
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
|
||||
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
|
||||
virtual size_t getActualSize() = 0;
|
||||
|
||||
std::map<u64, u8>& getPatches();
|
||||
void applyPatches();
|
||||
|
||||
u32 getPageCount();
|
||||
u32 getCurrentPage() const;
|
||||
void setCurrentPage(u32 page);
|
||||
|
||||
virtual size_t getBaseAddress();
|
||||
virtual size_t getSize();
|
||||
virtual std::optional<u32> getPageOfAddress(u64 address);
|
||||
|
||||
virtual std::vector<std::pair<std::string, std::string>> getDataInformation() = 0;
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
|
||||
std::vector<std::map<u64, u8>> m_patches;
|
||||
};
|
||||
|
||||
}
|
||||
71
plugins/libimhex/include/views/view.hpp
Normal file
71
plugins/libimhex/include/views/view.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include "helpers/event.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace hex {
|
||||
|
||||
class View {
|
||||
public:
|
||||
View(std::string viewName);
|
||||
virtual ~View() = default;
|
||||
|
||||
virtual void drawContent() = 0;
|
||||
virtual void drawMenu();
|
||||
virtual bool handleShortcut(int key, int mods);
|
||||
|
||||
static std::vector<std::function<void()>>& getDeferedCalls();
|
||||
|
||||
static void postEvent(Events eventType, const void *userData = nullptr);
|
||||
|
||||
static void drawCommonInterfaces();
|
||||
|
||||
static void showErrorPopup(std::string_view errorMessage);
|
||||
|
||||
static void setWindowPosition(s32 x, s32 y);
|
||||
|
||||
static const ImVec2& getWindowPosition();
|
||||
|
||||
static void setWindowSize(s32 width, s32 height);
|
||||
|
||||
static const ImVec2& getWindowSize();
|
||||
|
||||
virtual bool hasViewMenuItemEntry();
|
||||
virtual ImVec2 getMinSize();
|
||||
virtual ImVec2 getMaxSize();
|
||||
|
||||
bool& getWindowOpenState();
|
||||
|
||||
const std::string getName() const;
|
||||
|
||||
protected:
|
||||
void subscribeEvent(Events eventType, std::function<void(const void*)> callback);
|
||||
|
||||
void unsubscribeEvent(Events eventType);
|
||||
|
||||
void doLater(std::function<void()> &&function);
|
||||
|
||||
protected:
|
||||
void confirmButtons(const char *textLeft, const char *textRight, std::function<void()> leftButtonFn, std::function<void()> rightButtonFn);
|
||||
private:
|
||||
std::string m_viewName;
|
||||
bool m_windowOpen = false;
|
||||
|
||||
static inline EventManager s_eventManager;
|
||||
static inline std::vector<std::function<void()>> s_deferedCalls;
|
||||
|
||||
static inline std::string s_errorMessage;
|
||||
|
||||
static inline ImVec2 s_windowPos;
|
||||
static inline ImVec2 s_windowSize;
|
||||
};
|
||||
|
||||
}
|
||||
25
plugins/libimhex/source/helpers/event.cpp
Normal file
25
plugins/libimhex/source/helpers/event.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "helpers/event.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
void EventManager::post(Events eventType, const void *userData) {
|
||||
for (auto &handler : this->m_eventHandlers)
|
||||
if (eventType == handler.eventType)
|
||||
handler.callback(userData);
|
||||
}
|
||||
|
||||
void EventManager::subscribe(Events eventType, void *owner, std::function<void(const void*)> callback) {
|
||||
for (auto &handler : this->m_eventHandlers)
|
||||
if (eventType == handler.eventType && owner == handler.owner)
|
||||
return;
|
||||
|
||||
this->m_eventHandlers.push_back(EventHandler { owner, eventType, callback });
|
||||
}
|
||||
|
||||
void EventManager::unsubscribe(Events eventType, void *sender) {
|
||||
std::erase_if(this->m_eventHandlers, [&eventType, &sender](EventHandler handler) {
|
||||
return eventType == handler.eventType && sender == handler.owner;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
66
plugins/libimhex/source/providers/provider.cpp
Normal file
66
plugins/libimhex/source/providers/provider.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "providers/provider.hpp"
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
Provider::Provider() {
|
||||
this->m_patches.emplace_back();
|
||||
}
|
||||
|
||||
void Provider::read(u64 offset, void *buffer, size_t size) {
|
||||
this->readRaw(offset, buffer, size);
|
||||
}
|
||||
|
||||
void Provider::write(u64 offset, const void *buffer, size_t size) {
|
||||
this->writeRaw(offset, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
std::map<u64, u8>& Provider::getPatches() {
|
||||
return this->m_patches.back();
|
||||
}
|
||||
|
||||
void Provider::applyPatches() {
|
||||
for (auto &[patchAddress, patch] : this->m_patches.back())
|
||||
this->writeRaw(patchAddress, &patch, 1);
|
||||
}
|
||||
|
||||
u32 Provider::getPageCount() {
|
||||
return std::ceil(this->getActualSize() / double(PageSize));
|
||||
}
|
||||
|
||||
u32 Provider::getCurrentPage() const {
|
||||
return this->m_currPage;
|
||||
}
|
||||
|
||||
void Provider::setCurrentPage(u32 page) {
|
||||
if (page < getPageCount())
|
||||
this->m_currPage = page;
|
||||
}
|
||||
|
||||
|
||||
size_t Provider::getBaseAddress() {
|
||||
return PageSize * this->m_currPage;
|
||||
}
|
||||
|
||||
size_t Provider::getSize() {
|
||||
return std::min(this->getActualSize() - PageSize * this->m_currPage, PageSize);
|
||||
}
|
||||
|
||||
std::optional<u32> Provider::getPageOfAddress(u64 address) {
|
||||
u32 page = std::floor(address / double(PageSize));
|
||||
|
||||
if (page >= this->getPageCount())
|
||||
return { };
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
}
|
||||
107
plugins/libimhex/source/views/view.cpp
Normal file
107
plugins/libimhex/source/views/view.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include "views/view.hpp"
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
||||
View::View(std::string viewName) : m_viewName(viewName) { }
|
||||
|
||||
void View::drawMenu() { }
|
||||
bool View::handleShortcut(int key, int mods) { return false; }
|
||||
|
||||
std::vector<std::function<void()>>& View::getDeferedCalls() {
|
||||
return View::s_deferedCalls;
|
||||
}
|
||||
|
||||
void View::postEvent(Events eventType, const void *userData) {
|
||||
View::s_eventManager.post(eventType, userData);
|
||||
}
|
||||
|
||||
void View::drawCommonInterfaces() {
|
||||
if (ImGui::BeginPopupModal("Error", nullptr, ImGuiWindowFlags_NoResize)) {
|
||||
ImGui::NewLine();
|
||||
if (ImGui::BeginChild("##scrolling", ImVec2(300, 100))) {
|
||||
ImGui::SetCursorPosX((300 - ImGui::CalcTextSize(View::s_errorMessage.c_str(), nullptr, false).x) / 2.0F);
|
||||
ImGui::TextWrapped("%s", View::s_errorMessage.c_str());
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::NewLine();
|
||||
ImGui::SetCursorPosX(75);
|
||||
if (ImGui::Button("Okay", ImVec2(150, 20)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void View::showErrorPopup(std::string_view errorMessage) {
|
||||
View::s_errorMessage = errorMessage;
|
||||
|
||||
ImGui::OpenPopup("Error");
|
||||
}
|
||||
|
||||
void View::setWindowPosition(s32 x, s32 y) {
|
||||
View::s_windowPos = ImVec2(x, y);
|
||||
}
|
||||
|
||||
const ImVec2& View::getWindowPosition() {
|
||||
return View::s_windowPos;
|
||||
}
|
||||
|
||||
void View::setWindowSize(s32 width, s32 height) {
|
||||
View::s_windowSize = ImVec2(width, height);
|
||||
}
|
||||
|
||||
const ImVec2& View::getWindowSize() {
|
||||
return View::s_windowSize;
|
||||
}
|
||||
|
||||
bool View::hasViewMenuItemEntry() {
|
||||
return true;
|
||||
}
|
||||
|
||||
ImVec2 View::getMinSize() {
|
||||
return ImVec2(480, 720);
|
||||
}
|
||||
|
||||
ImVec2 View::getMaxSize() {
|
||||
return ImVec2(FLT_MAX, FLT_MAX);
|
||||
}
|
||||
|
||||
|
||||
bool& View::getWindowOpenState() {
|
||||
return this->m_windowOpen;
|
||||
}
|
||||
|
||||
const std::string View::getName() const {
|
||||
return this->m_viewName;
|
||||
}
|
||||
|
||||
void View::subscribeEvent(Events eventType, std::function<void(const void*)> callback) {
|
||||
View::s_eventManager.subscribe(eventType, this, callback);
|
||||
}
|
||||
|
||||
void View::unsubscribeEvent(Events eventType) {
|
||||
View::s_eventManager.unsubscribe(eventType, this);
|
||||
}
|
||||
|
||||
void View::doLater(std::function<void()> &&function) {
|
||||
View::s_deferedCalls.push_back(function);
|
||||
}
|
||||
|
||||
void View::confirmButtons(const char *textLeft, const char *textRight, std::function<void()> leftButtonFn, std::function<void()> rightButtonFn) {
|
||||
auto width = ImGui::GetWindowWidth();
|
||||
ImGui::SetCursorPosX(width / 9);
|
||||
if (ImGui::Button(textLeft, ImVec2(width / 3, 0)))
|
||||
leftButtonFn();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(width / 9 * 5);
|
||||
if (ImGui::Button(textRight, ImVec2(width / 3, 0)))
|
||||
rightButtonFn();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user