Improved events API
This commit is contained in:
parent
f0ab13ebc3
commit
a641f27b7e
2
external/ImGui/include/imgui_memory_editor.h
vendored
2
external/ImGui/include/imgui_memory_editor.h
vendored
@ -193,7 +193,7 @@ struct MemoryEditor
|
||||
{
|
||||
if (DataPreviewAddr != DataPreviewAddrOld || DataPreviewAddrEnd != DataPreviewAddrEndOld) {
|
||||
hex::Region selectionRegion = { std::min(DataPreviewAddr, DataPreviewAddrEnd), std::max(DataPreviewAddr, DataPreviewAddrEnd) - std::min(DataPreviewAddr, DataPreviewAddrEnd) };
|
||||
hex::View::postEvent(hex::Events::RegionSelected, &selectionRegion);
|
||||
hex::View::postEvent(hex::Events::RegionSelected, selectionRegion);
|
||||
}
|
||||
|
||||
DataPreviewAddrOld = DataPreviewAddr;
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <any>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@ -33,13 +34,13 @@ namespace hex {
|
||||
struct EventHandler {
|
||||
void *owner;
|
||||
Events eventType;
|
||||
std::function<void(const void*)> callback;
|
||||
std::function<std::any(const std::any&)> callback;
|
||||
};
|
||||
|
||||
class EventManager {
|
||||
public:
|
||||
static void post(Events eventType, const void *userData);
|
||||
static void subscribe(Events eventType, void *owner, std::function<void(const void*)> callback);
|
||||
static std::vector<std::any> post(Events eventType, const std::any &userData);
|
||||
static void subscribe(Events eventType, void *owner, std::function<std::any(const std::any&)> callback);
|
||||
static void unsubscribe(Events eventType, void *sender);
|
||||
};
|
||||
|
||||
|
@ -152,7 +152,7 @@ namespace hex::lang {
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
Region selectRegion = { this->getOffset(), this->getSize() };
|
||||
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
|
||||
View::postEvent(Events::SelectionChangeRequest, selectRegion);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", this->getVariableName().c_str());
|
||||
@ -703,7 +703,7 @@ namespace hex::lang {
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
Region selectRegion = { this->getOffset(), this->getSize() };
|
||||
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
|
||||
View::postEvent(Events::SelectionChangeRequest, selectRegion);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", this->getVariableName().c_str());
|
||||
|
@ -15,16 +15,17 @@ namespace hex {
|
||||
|
||||
class View {
|
||||
public:
|
||||
View(std::string viewName);
|
||||
explicit View(std::string viewName);
|
||||
virtual ~View() = default;
|
||||
|
||||
virtual void drawContent() = 0;
|
||||
virtual void drawMenu();
|
||||
virtual bool handleShortcut(int key, int mods);
|
||||
|
||||
static void doLater(std::function<void()> &&function);
|
||||
static std::vector<std::function<void()>>& getDeferedCalls();
|
||||
|
||||
static void postEvent(Events eventType, const void *userData = nullptr);
|
||||
static std::vector<std::any> postEvent(Events eventType, const std::any &userData = { });
|
||||
|
||||
static void drawCommonInterfaces();
|
||||
|
||||
@ -36,17 +37,17 @@ namespace hex {
|
||||
|
||||
bool& getWindowOpenState();
|
||||
|
||||
const std::string getName() const;
|
||||
std::string_view getName() const;
|
||||
|
||||
protected:
|
||||
void subscribeEvent(Events eventType, std::function<void(const void*)> callback);
|
||||
void subscribeEvent(Events eventType, const std::function<std::any(const std::any&)> &callback);
|
||||
void subscribeEvent(Events eventType, const std::function<void(const std::any&)> &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);
|
||||
void confirmButtons(const char *textLeft, const char *textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn);
|
||||
|
||||
private:
|
||||
std::string m_viewName;
|
||||
|
@ -4,13 +4,16 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
void EventManager::post(Events eventType, const void *userData) {
|
||||
std::vector<std::any> EventManager::post(Events eventType, const std::any &userData) {
|
||||
std::vector<std::any> results;
|
||||
for (auto &handler : SharedData::eventHandlers)
|
||||
if (eventType == handler.eventType)
|
||||
handler.callback(userData);
|
||||
results.push_back(handler.callback(userData));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
void EventManager::subscribe(Events eventType, void *owner, std::function<void(const void*)> callback) {
|
||||
void EventManager::subscribe(Events eventType, void *owner, std::function<std::any(const std::any&)> callback) {
|
||||
for (auto &handler : SharedData::eventHandlers)
|
||||
if (eventType == handler.eventType && owner == handler.owner)
|
||||
return;
|
||||
|
@ -17,7 +17,7 @@ namespace hex {
|
||||
|
||||
entry.color = color;
|
||||
|
||||
EventManager::post(Events::AddBookmark, &entry);
|
||||
EventManager::post(Events::AddBookmark, entry);
|
||||
}
|
||||
|
||||
void ImHexApi::Bookmarks::add(u64 addr, size_t size, std::string_view name, std::string_view comment, u32 color) {
|
||||
|
@ -20,8 +20,8 @@ namespace hex {
|
||||
return SharedData::deferredCalls;
|
||||
}
|
||||
|
||||
void View::postEvent(Events eventType, const void *userData) {
|
||||
EventManager::post(eventType, userData);
|
||||
std::vector<std::any> View::postEvent(Events eventType, const std::any &userData) {
|
||||
return EventManager::post(eventType, userData);
|
||||
}
|
||||
|
||||
void View::drawCommonInterfaces() {
|
||||
@ -63,14 +63,18 @@ namespace hex {
|
||||
return this->m_windowOpen;
|
||||
}
|
||||
|
||||
const std::string View::getName() const {
|
||||
std::string_view View::getName() const {
|
||||
return this->m_viewName;
|
||||
}
|
||||
|
||||
void View::subscribeEvent(Events eventType, std::function<void(const void*)> callback) {
|
||||
void View::subscribeEvent(Events eventType, const std::function<std::any(const std::any&)> &callback) {
|
||||
EventManager::subscribe(eventType, this, callback);
|
||||
}
|
||||
|
||||
void View::subscribeEvent(Events eventType, const std::function<void(const std::any&)> &callback) {
|
||||
EventManager::subscribe(eventType, this, [callback](auto userData) -> std::any { callback(userData); return { }; });
|
||||
}
|
||||
|
||||
void View::unsubscribeEvent(Events eventType) {
|
||||
EventManager::unsubscribe(eventType, this);
|
||||
}
|
||||
@ -79,7 +83,7 @@ namespace hex {
|
||||
SharedData::deferredCalls.push_back(function);
|
||||
}
|
||||
|
||||
void View::confirmButtons(const char *textLeft, const char *textRight, std::function<void()> leftButtonFn, std::function<void()> rightButtonFn) {
|
||||
void View::confirmButtons(const char *textLeft, const char *textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn) {
|
||||
auto width = ImGui::GetWindowWidth();
|
||||
ImGui::SetCursorPosX(width / 9);
|
||||
if (ImGui::Button(textLeft, ImVec2(width / 3, 0)))
|
||||
|
@ -8,8 +8,8 @@
|
||||
namespace hex {
|
||||
|
||||
ViewBookmarks::ViewBookmarks() : View("Bookmarks") {
|
||||
View::subscribeEvent(Events::AddBookmark, [this](const void *userData) {
|
||||
auto bookmark = *reinterpret_cast<const ImHexApi::Bookmarks::Entry*>(userData);
|
||||
View::subscribeEvent(Events::AddBookmark, [](auto userData) {
|
||||
auto bookmark = std::any_cast<ImHexApi::Bookmarks::Entry>(userData);
|
||||
bookmark.comment.resize(0xF'FFFF);
|
||||
|
||||
if (bookmark.name.empty()) {
|
||||
@ -29,10 +29,10 @@ namespace hex {
|
||||
ProjectFile::markDirty();
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [](const void*) {
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [](auto) {
|
||||
SharedData::bookmarkEntries = ProjectFile::getBookmarks();
|
||||
});
|
||||
View::subscribeEvent(Events::ProjectFileStore, [](const void*) {
|
||||
View::subscribeEvent(Events::ProjectFileStore, [](auto) {
|
||||
ProjectFile::setBookmarks(SharedData::bookmarkEntries);
|
||||
});
|
||||
}
|
||||
@ -90,7 +90,7 @@ namespace hex {
|
||||
ImGui::TextColored(ImColor(0xFF9BC64D), bytesString.c_str());
|
||||
}
|
||||
if (ImGui::Button("Jump to"))
|
||||
View::postEvent(Events::SelectionChangeRequest, ®ion);
|
||||
View::postEvent(Events::SelectionChangeRequest, region);
|
||||
ImGui::SameLine(0, 15);
|
||||
|
||||
if (ImGui::Button("Remove"))
|
||||
|
@ -12,8 +12,8 @@ namespace hex {
|
||||
using NumberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle;
|
||||
|
||||
ViewDataInspector::ViewDataInspector() : View("Data Inspector") {
|
||||
View::subscribeEvent(Events::RegionSelected, [this](const void* userData) {
|
||||
Region region = *static_cast<const Region*>(userData);
|
||||
View::subscribeEvent(Events::RegionSelected, [this](auto userData) {
|
||||
auto region = std::any_cast<Region>(userData);
|
||||
|
||||
auto provider = SharedData::currentProvider;
|
||||
|
||||
|
@ -10,12 +10,12 @@ using namespace std::literals::string_literals;
|
||||
namespace hex {
|
||||
|
||||
ViewDisassembler::ViewDisassembler() : View("Disassembler") {
|
||||
View::subscribeEvent(Events::DataChanged, [this](const void*){
|
||||
View::subscribeEvent(Events::DataChanged, [this](auto){
|
||||
this->m_shouldInvalidate = true;
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::RegionSelected, [this](const void *userData) {
|
||||
Region region = *static_cast<const Region*>(userData);
|
||||
View::subscribeEvent(Events::RegionSelected, [this](auto userData) {
|
||||
auto region = std::any_cast<Region>(userData);
|
||||
|
||||
if (this->m_shouldMatchSelection) {
|
||||
this->m_codeRegion[0] = region.address;
|
||||
@ -260,7 +260,7 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##DisassemblyLine"s + std::to_string(i)).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
Region selectRegion = { this->m_disassembly[i].offset, this->m_disassembly[i].size };
|
||||
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
|
||||
View::postEvent(Events::SelectionChangeRequest, selectRegion);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("0x%llx", this->m_disassembly[i].address);
|
||||
|
@ -11,12 +11,12 @@
|
||||
namespace hex {
|
||||
|
||||
ViewHashes::ViewHashes() : View("Hashes") {
|
||||
View::subscribeEvent(Events::DataChanged, [this](const void*){
|
||||
View::subscribeEvent(Events::DataChanged, [this](auto) {
|
||||
this->m_shouldInvalidate = true;
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::RegionSelected, [this](const void *userData) {
|
||||
Region region = *static_cast<const Region*>(userData);
|
||||
View::subscribeEvent(Events::RegionSelected, [this](auto userData) {
|
||||
auto region = std::any_cast<const Region>(userData);
|
||||
|
||||
if (this->m_shouldMatchSelection) {
|
||||
this->m_hashRegion[0] = region.address;
|
||||
|
@ -93,15 +93,15 @@ namespace hex {
|
||||
ImGui::EndTooltip();
|
||||
};
|
||||
|
||||
View::subscribeEvent(Events::FileDropped, [this](const void *userData) {
|
||||
auto filePath = static_cast<const char*>(userData);
|
||||
View::subscribeEvent(Events::FileDropped, [this](auto userData) {
|
||||
auto filePath = std::any_cast<const char*>(userData);
|
||||
|
||||
if (filePath != nullptr)
|
||||
this->openFile(filePath);
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::SelectionChangeRequest, [this](const void *userData) {
|
||||
const Region ®ion = *reinterpret_cast<const Region*>(userData);
|
||||
View::subscribeEvent(Events::SelectionChangeRequest, [this](auto userData) {
|
||||
const Region ®ion = std::any_cast<Region>(userData);
|
||||
|
||||
auto provider = SharedData::currentProvider;
|
||||
auto page = provider->getPageOfAddress(region.address);
|
||||
@ -112,15 +112,15 @@ namespace hex {
|
||||
this->m_memoryEditor.GotoAddr = region.address;
|
||||
this->m_memoryEditor.DataPreviewAddr = region.address;
|
||||
this->m_memoryEditor.DataPreviewAddrEnd = region.address + region.size - 1;
|
||||
View::postEvent(Events::RegionSelected, ®ion);
|
||||
View::postEvent(Events::RegionSelected, region);
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [this](const void *userData) {
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [this](auto) {
|
||||
this->openFile(ProjectFile::getFilePath());
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::WindowClosing, [this](const void *userData) {
|
||||
auto window = const_cast<GLFWwindow*>(static_cast<const GLFWwindow*>(userData));
|
||||
View::subscribeEvent(Events::WindowClosing, [this](auto userData) {
|
||||
auto window = std::any_cast<GLFWwindow*>(userData);
|
||||
|
||||
if (ProjectFile::hasUnsavedChanges()) {
|
||||
glfwSetWindowShouldClose(window, GLFW_FALSE);
|
||||
@ -129,7 +129,7 @@ namespace hex {
|
||||
}
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::PatternChanged, [this](const void *userData) {
|
||||
View::subscribeEvent(Events::PatternChanged, [this](auto) {
|
||||
this->m_highlightedBytes.clear();
|
||||
|
||||
for (const auto &pattern : this->m_patternData)
|
||||
@ -169,7 +169,7 @@ namespace hex {
|
||||
provider->setCurrentPage(provider->getCurrentPage() - 1);
|
||||
|
||||
Region dataPreview = { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 };
|
||||
View::postEvent(Events::RegionSelected, &dataPreview);
|
||||
View::postEvent(Events::RegionSelected, dataPreview);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
@ -178,7 +178,7 @@ namespace hex {
|
||||
provider->setCurrentPage(provider->getCurrentPage() + 1);
|
||||
|
||||
Region dataPreview = { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 };
|
||||
View::postEvent(Events::RegionSelected, &dataPreview);
|
||||
View::postEvent(Events::RegionSelected, dataPreview);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
@ -14,7 +14,7 @@
|
||||
namespace hex {
|
||||
|
||||
ViewInformation::ViewInformation() : View("Information") {
|
||||
View::subscribeEvent(Events::DataChanged, [this](const void*) {
|
||||
View::subscribeEvent(Events::DataChanged, [this](auto) {
|
||||
this->m_dataValid = false;
|
||||
this->m_highestBlockEntropy = 0;
|
||||
this->m_blockEntropy.clear();
|
||||
|
@ -12,13 +12,13 @@ using namespace std::literals::string_literals;
|
||||
namespace hex {
|
||||
|
||||
ViewPatches::ViewPatches() : View("Patches") {
|
||||
View::subscribeEvent(Events::ProjectFileStore, [this](const void*) {
|
||||
View::subscribeEvent(Events::ProjectFileStore, [](auto) {
|
||||
auto provider = SharedData::currentProvider;
|
||||
if (provider != nullptr)
|
||||
ProjectFile::setPatches(provider->getPatches());
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [this](const void*) {
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [](auto) {
|
||||
auto provider = SharedData::currentProvider;
|
||||
if (provider != nullptr)
|
||||
provider->getPatches() = ProjectFile::getPatches();
|
||||
@ -53,7 +53,7 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##patchLine" + std::to_string(index)).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
Region selectRegion = { address, 1 };
|
||||
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
|
||||
View::postEvent(Events::SelectionChangeRequest, selectRegion);
|
||||
}
|
||||
if (ImGui::IsMouseReleased(1) && ImGui::IsItemHovered()) {
|
||||
ImGui::OpenPopup("PatchContextMenu");
|
||||
|
@ -80,23 +80,23 @@ namespace hex {
|
||||
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
|
||||
this->m_textEditor.SetShowWhitespaces(false);
|
||||
|
||||
View::subscribeEvent(Events::ProjectFileStore, [this](const void*) {
|
||||
View::subscribeEvent(Events::ProjectFileStore, [this](auto) {
|
||||
ProjectFile::setPattern(this->m_textEditor.GetText());
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [this](const void*) {
|
||||
View::subscribeEvent(Events::ProjectFileLoad, [this](auto) {
|
||||
this->m_textEditor.SetText(ProjectFile::getPattern());
|
||||
this->parsePattern(this->m_textEditor.GetText().data());
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::AppendPatternLanguageCode, [this](const void *userData) {
|
||||
const char *code = static_cast<const char*>(userData);
|
||||
View::subscribeEvent(Events::AppendPatternLanguageCode, [this](auto userData) {
|
||||
auto code = std::any_cast<const char*>(userData);
|
||||
|
||||
this->m_textEditor.InsertText("\n");
|
||||
this->m_textEditor.InsertText(code);
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::FileLoaded, [this](const void* userData) {
|
||||
View::subscribeEvent(Events::FileLoaded, [this](auto) {
|
||||
if (this->m_textEditor.GetText().find_first_not_of(" \f\n\r\t\v") != std::string::npos)
|
||||
return;
|
||||
|
||||
@ -185,7 +185,7 @@ namespace hex {
|
||||
return false;
|
||||
});
|
||||
|
||||
View::subscribeEvent(Events::SettingsChanged, [this](const void*) {
|
||||
View::subscribeEvent(Events::SettingsChanged, [this](auto) {
|
||||
int theme = ContentRegistry::Settings::getSettingsData()[SettingsCategoryInterface][SettingColorTheme];
|
||||
|
||||
switch (theme) {
|
||||
|
@ -24,7 +24,7 @@ namespace hex {
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
ImGui::SameLine();
|
||||
if (callback(ContentRegistry::Settings::getSettingsData()[category][name]))
|
||||
View::postEvent(Events::SettingsChanged, nullptr);
|
||||
View::postEvent(Events::SettingsChanged);
|
||||
ImGui::NewLine();
|
||||
}
|
||||
ImGui::NewLine();
|
||||
|
@ -12,7 +12,7 @@ using namespace std::literals::string_literals;
|
||||
namespace hex {
|
||||
|
||||
ViewStrings::ViewStrings() : View("Strings") {
|
||||
View::subscribeEvent(Events::DataChanged, [this](const void*){
|
||||
View::subscribeEvent(Events::DataChanged, [this](auto){
|
||||
this->m_foundStrings.clear();
|
||||
});
|
||||
|
||||
@ -149,7 +149,7 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##StringLine"s + std::to_string(i)).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
Region selectRegion = { foundString.offset, foundString.size };
|
||||
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
|
||||
View::postEvent(Events::SelectionChangeRequest, selectRegion);
|
||||
}
|
||||
ImGui::PushID(i + 1);
|
||||
createStringContextMenu(foundString);
|
||||
|
@ -27,7 +27,7 @@ namespace hex {
|
||||
|
||||
void ImHexSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler *handler, void *, const char* line) {
|
||||
for (auto &view : ContentRegistry::Views::getEntries()) {
|
||||
std::string format = view->getName() + "=%d";
|
||||
std::string format = std::string(view->getName()) + "=%d";
|
||||
sscanf(line, format.c_str(), &view->getWindowOpenState());
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@ namespace hex {
|
||||
buf->appendf("[%s][General]\n", handler->TypeName);
|
||||
|
||||
for (auto &view : ContentRegistry::Views::getEntries()) {
|
||||
buf->appendf("%s=%d\n", view->getName().c_str(), view->getWindowOpenState());
|
||||
buf->appendf("%s=%d\n", view->getName().data(), view->getWindowOpenState());
|
||||
}
|
||||
|
||||
buf->append("\n");
|
||||
@ -49,7 +49,7 @@ namespace hex {
|
||||
hex::SharedData::mainArgv = argv;
|
||||
|
||||
ContentRegistry::Settings::load();
|
||||
View::postEvent(Events::SettingsChanged, nullptr);
|
||||
View::postEvent(Events::SettingsChanged);
|
||||
|
||||
this->initGLFW();
|
||||
this->initImGui();
|
||||
@ -153,7 +153,7 @@ namespace hex {
|
||||
if (ImGui::BeginMenu("View")) {
|
||||
for (auto &view : ContentRegistry::Views::getEntries()) {
|
||||
if (view->hasViewMenuItemEntry())
|
||||
ImGui::MenuItem((view->getName() + " View").c_str(), "", &view->getWindowOpenState());
|
||||
ImGui::MenuItem((std::string(view->getName()) + " View").c_str(), "", &view->getWindowOpenState());
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user