mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-30 21:05:56 -05:00
impr: Merge in script loader structure improvements from python branch
This commit is contained in:
14
plugins/script_loader/support/c/CMakeLists.txt
Normal file
14
plugins/script_loader/support/c/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
project(c_api)
|
||||
|
||||
add_library(c_api OBJECT
|
||||
source/script_api/v1/bookmarks.cpp
|
||||
source/script_api/v1/logger.cpp
|
||||
source/script_api/v1/mem.cpp
|
||||
source/script_api/v1/ui.cpp
|
||||
)
|
||||
|
||||
target_include_directories(c_api PUBLIC
|
||||
include
|
||||
)
|
||||
target_link_libraries(c_api PRIVATE libimhex ui)
|
||||
target_compile_definitions(c_api PRIVATE IMHEX_PROJECT_NAME="Script")
|
||||
7
plugins/script_loader/support/c/include/script_api.hpp
Normal file
7
plugins/script_loader/support/c/include/script_api.hpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define CONCAT_IMPL(x, y) x##y
|
||||
#define CONCAT(x, y) CONCAT_IMPL(x, y)
|
||||
|
||||
#define SCRIPT_API_IMPL(VERSION, ReturnAndName, ...) extern "C" [[maybe_unused, gnu::visibility("default")]] CONCAT(ReturnAndName, VERSION) (__VA_ARGS__)
|
||||
#define SCRIPT_API(ReturnAndName, ...) SCRIPT_API_IMPL(VERSION, ReturnAndName, __VA_ARGS__)
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <script_api.hpp>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
#define VERSION V1
|
||||
|
||||
SCRIPT_API(void createBookmark, u64 address, u64 size, u32 color, const char *name, const char *description) {
|
||||
hex::ImHexApi::Bookmarks::add(address, size, name, description, color);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#include <script_api.hpp>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#define VERSION V1
|
||||
|
||||
SCRIPT_API(void logPrint, const char *message) {
|
||||
hex::log::print("{}", message);
|
||||
}
|
||||
|
||||
SCRIPT_API(void logPrintln, const char *message) {
|
||||
hex::log::println("{}", message);
|
||||
}
|
||||
|
||||
SCRIPT_API(void logDebug, const char *message) {
|
||||
hex::log::debug("{}", message);
|
||||
}
|
||||
|
||||
SCRIPT_API(void logInfo, const char *message) {
|
||||
hex::log::info("{}", message);
|
||||
}
|
||||
|
||||
SCRIPT_API(void logWarn, const char *message) {
|
||||
hex::log::warn("{}", message);
|
||||
}
|
||||
|
||||
SCRIPT_API(void logError, const char *message) {
|
||||
hex::log::error("{}", message);
|
||||
}
|
||||
|
||||
SCRIPT_API(void logFatal, const char *message) {
|
||||
hex::log::fatal("{}", message);
|
||||
}
|
||||
113
plugins/script_loader/support/c/source/script_api/v1/mem.cpp
Normal file
113
plugins/script_loader/support/c/source/script_api/v1/mem.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include <script_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#define VERSION V1
|
||||
|
||||
SCRIPT_API(void readMemory, u64 address, size_t size, void *buffer) {
|
||||
auto provider = hex::ImHexApi::Provider::get();
|
||||
|
||||
if (provider == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
provider->read(address, buffer, size);
|
||||
}
|
||||
|
||||
SCRIPT_API(void writeMemory, u64 address, size_t size, const void *buffer) {
|
||||
auto provider = hex::ImHexApi::Provider::get();
|
||||
|
||||
if (provider == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
provider->write(address, buffer, size);
|
||||
}
|
||||
|
||||
SCRIPT_API(u64 getBaseAddress) {
|
||||
return hex::ImHexApi::Provider::get()->getBaseAddress();
|
||||
}
|
||||
|
||||
SCRIPT_API(u64 getDataSize) {
|
||||
return hex::ImHexApi::Provider::get()->getSize();
|
||||
}
|
||||
|
||||
SCRIPT_API(bool getSelection, u64 *start, u64 *end) {
|
||||
if (start == nullptr || end == nullptr)
|
||||
return false;
|
||||
|
||||
if (!hex::ImHexApi::Provider::isValid())
|
||||
return false;
|
||||
|
||||
if (!hex::ImHexApi::HexEditor::isSelectionValid())
|
||||
return false;
|
||||
|
||||
auto selection = hex::ImHexApi::HexEditor::getSelection();
|
||||
|
||||
*start = selection->getStartAddress();
|
||||
*end = selection->getEndAddress();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class ScriptDataProvider : public hex::prv::Provider {
|
||||
public:
|
||||
using ReadFunction = void(*)(u64, void*, u64);
|
||||
using WriteFunction = void(*)(u64, const void*, u64);
|
||||
using GetSizeFunction = u64(*)();
|
||||
using GetNameFunction = std::string(*)();
|
||||
|
||||
bool open() override { return true; }
|
||||
void close() override { }
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override { return true; }
|
||||
[[nodiscard]] bool isReadable() const override { return true; }
|
||||
[[nodiscard]] bool isWritable() const override { return true; }
|
||||
[[nodiscard]] bool isResizable() const override { return true; }
|
||||
[[nodiscard]] bool isSavable() const override { return true; }
|
||||
[[nodiscard]] bool isDumpable() const override { return true; }
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override {
|
||||
m_readFunction(offset, buffer, size);
|
||||
}
|
||||
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override {
|
||||
m_writeFunction(offset, const_cast<void*>(buffer), size);
|
||||
}
|
||||
|
||||
void setFunctions(ReadFunction readFunc, WriteFunction writeFunc, GetSizeFunction getSizeFunc) {
|
||||
m_readFunction = readFunc;
|
||||
m_writeFunction = writeFunc;
|
||||
m_getSizeFunction = getSizeFunc;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getActualSize() const override { return m_getSizeFunction(); }
|
||||
|
||||
void setTypeName(std::string typeName) { m_typeName = std::move(typeName);}
|
||||
void setName(std::string name) { m_name = std::move(name);}
|
||||
[[nodiscard]] std::string getTypeName() const override { return m_typeName; }
|
||||
[[nodiscard]] std::string getName() const override { return m_name; }
|
||||
|
||||
private:
|
||||
ReadFunction m_readFunction = nullptr;
|
||||
WriteFunction m_writeFunction = nullptr;
|
||||
GetSizeFunction m_getSizeFunction = nullptr;
|
||||
|
||||
std::string m_typeName, m_name;
|
||||
};
|
||||
|
||||
SCRIPT_API(void registerProvider, const char *typeName, const char *name, ScriptDataProvider::ReadFunction readFunc, ScriptDataProvider::WriteFunction writeFunc, ScriptDataProvider::GetSizeFunction getSizeFunc) {
|
||||
auto typeNameString = std::string(typeName);
|
||||
auto nameString = std::string(name);
|
||||
|
||||
hex::ContentRegistry::Provider::impl::add(typeNameString, [typeNameString, nameString, readFunc, writeFunc, getSizeFunc] -> std::unique_ptr<hex::prv::Provider> {
|
||||
auto provider = std::make_unique<ScriptDataProvider>();
|
||||
provider->setTypeName(typeNameString);
|
||||
provider->setName(nameString);
|
||||
provider->setFunctions(readFunc, writeFunc, getSizeFunc);
|
||||
return provider;
|
||||
});
|
||||
hex::ContentRegistry::Provider::impl::addProviderName(typeNameString);
|
||||
}
|
||||
187
plugins/script_loader/support/c/source/script_api/v1/ui.cpp
Normal file
187
plugins/script_loader/support/c/source/script_api/v1/ui.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#include <script_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <hex/ui/popup.hpp>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <popups/popup_notification.hpp>
|
||||
#include <toasts/toast_notification.hpp>
|
||||
|
||||
using namespace hex;
|
||||
|
||||
#define VERSION V1
|
||||
|
||||
static std::optional<std::string> s_inputTextBoxResult;
|
||||
static std::optional<bool> s_yesNoQuestionBoxResult;
|
||||
|
||||
class PopupYesNo : public Popup<PopupYesNo> {
|
||||
public:
|
||||
PopupYesNo(std::string title, std::string message)
|
||||
: hex::Popup<PopupYesNo>(std::move(title), false),
|
||||
m_message(std::move(message)) { }
|
||||
|
||||
void drawContent() override {
|
||||
ImGuiExt::TextFormattedWrapped("{}", m_message.c_str());
|
||||
ImGui::NewLine();
|
||||
ImGui::Separator();
|
||||
|
||||
auto width = ImGui::GetWindowWidth();
|
||||
ImGui::SetCursorPosX(width / 9);
|
||||
if (ImGui::Button("hex.ui.common.yes"_lang, ImVec2(width / 3, 0))) {
|
||||
s_yesNoQuestionBoxResult = true;
|
||||
this->close();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(width / 9 * 5);
|
||||
if (ImGui::Button("hex.ui.common.no"_lang, ImVec2(width / 3, 0)) || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
s_yesNoQuestionBoxResult = false;
|
||||
this->close();
|
||||
}
|
||||
|
||||
ImGui::SetWindowPos((ImHexApi::System::getMainWindowSize() - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
|
||||
}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
|
||||
return ImGuiWindowFlags_AlwaysAutoResize;
|
||||
}
|
||||
|
||||
[[nodiscard]] ImVec2 getMinSize() const override {
|
||||
return scaled({ 400, 100 });
|
||||
}
|
||||
|
||||
[[nodiscard]] ImVec2 getMaxSize() const override {
|
||||
return scaled({ 600, 300 });
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
class PopupInputText : public Popup<PopupInputText> {
|
||||
public:
|
||||
PopupInputText(std::string title, std::string message, size_t maxSize)
|
||||
: hex::Popup<PopupInputText>(std::move(title), false),
|
||||
m_message(std::move(message)), m_maxSize(maxSize) { }
|
||||
|
||||
void drawContent() override {
|
||||
ImGuiExt::TextFormattedWrapped("{}", m_message.c_str());
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::SetItemDefaultFocus();
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
bool submitted = ImGui::InputText("##input", m_input, ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
if (m_input.size() > m_maxSize)
|
||||
m_input.resize(m_maxSize);
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::Separator();
|
||||
|
||||
auto width = ImGui::GetWindowWidth();
|
||||
ImGui::SetCursorPosX(width / 9);
|
||||
ImGui::BeginDisabled(m_input.empty());
|
||||
if (ImGui::Button("hex.ui.common.okay"_lang, ImVec2(width / 3, 0)) || submitted) {
|
||||
s_inputTextBoxResult = m_input;
|
||||
this->close();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(width / 9 * 5);
|
||||
if (ImGui::Button("hex.ui.common.cancel"_lang, ImVec2(width / 3, 0)) || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
s_inputTextBoxResult = "";
|
||||
this->close();
|
||||
}
|
||||
|
||||
ImGui::SetWindowPos((ImHexApi::System::getMainWindowSize() - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
|
||||
}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
|
||||
return ImGuiWindowFlags_AlwaysAutoResize;
|
||||
}
|
||||
|
||||
[[nodiscard]] ImVec2 getMinSize() const override {
|
||||
return scaled({ 400, 100 });
|
||||
}
|
||||
|
||||
[[nodiscard]] ImVec2 getMaxSize() const override {
|
||||
return scaled({ 600, 300 });
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_message;
|
||||
std::string m_input;
|
||||
size_t m_maxSize;
|
||||
};
|
||||
|
||||
SCRIPT_API(void showMessageBox, const char *message) {
|
||||
ui::PopupInfo::open(message);
|
||||
}
|
||||
|
||||
SCRIPT_API(void showInputTextBox, const char *title, const char *message, char *buffer, u32 bufferSize) {
|
||||
PopupInputText::open(std::string(title), std::string(message), bufferSize - 1);
|
||||
|
||||
while (!s_inputTextBoxResult.has_value()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
auto &value = s_inputTextBoxResult.value();
|
||||
std::memcpy(buffer, value.c_str(), std::min<size_t>(value.size() + 1, bufferSize));
|
||||
s_inputTextBoxResult.reset();
|
||||
}
|
||||
|
||||
SCRIPT_API(void showYesNoQuestionBox, const char *title, const char *message, bool *result) {
|
||||
PopupYesNo::open(std::string(title), std::string(message));
|
||||
|
||||
while (!s_yesNoQuestionBoxResult.has_value()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
*result = s_yesNoQuestionBoxResult.value();
|
||||
s_yesNoQuestionBoxResult.reset();
|
||||
}
|
||||
|
||||
SCRIPT_API(void showToast, const char *message, u32 type) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
ui::ToastInfo::open(message);
|
||||
break;
|
||||
case 1:
|
||||
ui::ToastWarning::open(message);
|
||||
break;
|
||||
case 2:
|
||||
ui::ToastError::open(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SCRIPT_API(void* getImGuiContext) {
|
||||
return ImGui::GetCurrentContext();
|
||||
}
|
||||
|
||||
class ScriptView : public View::Window {
|
||||
public:
|
||||
using DrawFunction = void(*)();
|
||||
ScriptView(const char *icon, const char *name, DrawFunction function) : View::Window(UnlocalizedString(name), icon), m_drawFunction(function) { }
|
||||
void drawContent() override {
|
||||
m_drawFunction();
|
||||
}
|
||||
|
||||
private:
|
||||
DrawFunction m_drawFunction;
|
||||
};
|
||||
|
||||
SCRIPT_API(void registerView, const char *icon, const char *name, void *drawFunction) {
|
||||
ContentRegistry::Views::add<ScriptView>(icon, name, ScriptView::DrawFunction(drawFunction));
|
||||
}
|
||||
|
||||
SCRIPT_API(void addMenuItem, const char *icon, const char *menuName, const char *itemName, void *function) {
|
||||
using MenuFunction = void(*)();
|
||||
ContentRegistry::Interface::addMenuItem({ menuName, itemName }, icon, 9999, Shortcut::None, reinterpret_cast<MenuFunction>(function));
|
||||
}
|
||||
Reference in New Issue
Block a user