From 8d2c1e7a66611248d771faa149bfd5db931c064d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 7 Aug 2026 22:40:05 +0200 Subject: [PATCH] Make the ImDebugger a bit less crash prone outside of games --- Core/HLE/AtracCtx.cpp | 2 +- UI/ImDebugger/ImDebugger.cpp | 428 +++++++++++++++++++---------------- UI/NativeApp.cpp | 25 +- ext/imgui/imgui_extras.cpp | 22 ++ ext/imgui/imgui_extras.h | 4 +- 5 files changed, 258 insertions(+), 223 deletions(-) diff --git a/Core/HLE/AtracCtx.cpp b/Core/HLE/AtracCtx.cpp index 5c274d7fb7..bcd730347e 100644 --- a/Core/HLE/AtracCtx.cpp +++ b/Core/HLE/AtracCtx.cpp @@ -969,7 +969,7 @@ int Atrac::EnqueueForSas(u32 bufPtr, u32 bytesToAdd) { if (addbytes < 0) addbytes = 0; if (addbytes > 0) { - Memory::Memcpy(dataBuf_ + destOffset, bufPtr, (size_t)addbytes, "AtracAddStreamData"); + Memory::Memcpy(dataBuf_ + destOffset, bufPtr, (u32)addbytes, "AtracAddStreamData"); } first_.size += bytesToAdd; if (first_.size >= track_.fileSize) { diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index c9d1a91e79..548912c655 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -10,6 +10,7 @@ #include "Common/Data/Text/StringWriter.h" #include "Common/Log/LogManager.h" #include "Common/TimeUtil.h" +#include "Common/Data/Text/I18n.h" #include "Core/Config.h" #include "Core/System.h" #include "Core/SaveState.h" @@ -2383,6 +2384,34 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: ImControl control{}; if (ImGui::BeginMainMenuBar()) { + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("Load")) { + System_BrowseForFile(reqToken_, "Load", BrowseFileType::BOOTABLE, [this](std::string_view responseString, int) { + Path path(responseString); + System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, path.ToString()); + }); + } + ImGui::Separator(); + if (ImGui::MenuItem("Exit")) { + System_ExitApp(); + } + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Emulation")) { + if (ImGui::MenuItem("Pause")) { + System_PostUIMessage(UIMessage::REQUEST_GAME_PAUSE); + } + if (ImGui::MenuItem("Stop")) { + System_PostUIMessage(UIMessage::REQUEST_GAME_STOP); + } + if (ImGui::MenuItem("Reset")) { + System_PostUIMessage(UIMessage::REQUEST_GAME_RESET); + } + ImGui::Separator(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Debug")) { switch (coreState) { case CoreState::CORE_STEPPING_CPU: @@ -2399,9 +2428,9 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: break; } ImGui::Separator(); + ImGui::MenuItemInverted("Break on load", nullptr, &g_Config.bAutoRun); ImGui::MenuItem("Ignore bad memory accesses", nullptr, &g_Config.bIgnoreBadMemAccess); ImGui::MenuItem("Break on frame timeout", nullptr, &g_Config.bBreakOnFrameTimeout); - ImGui::MenuItem("Don't break on start", nullptr, &g_Config.bAutoRun); // should really invert this bool! ImGui::MenuItem("Fast memory", nullptr, &g_Config.bFastMemory); ImGui::Separator(); if (ImGui::MenuItem("Take screenshot")) { @@ -2422,121 +2451,128 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: } ImGui::EndMenu(); } - if (ImGui::BeginMenu("Core")) { - ImGui::MenuItem("Scheduler", nullptr, &cfg_.schedulerOpen); - ImGui::MenuItem("Time", nullptr, &cfg_.timeOpen); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("CPU")) { - ImGui::MenuItem("CPU debugger", nullptr, &cfg_.disasmOpen); - ImGui::MenuItem("GPR regs", nullptr, &cfg_.gprOpen); - ImGui::MenuItem("FPR regs", nullptr, &cfg_.fprOpen); - ImGui::MenuItem("VFPU regs", nullptr, &cfg_.vfpuOpen); - ImGui::Separator(); - ImGui::MenuItem("Callstacks", nullptr, &cfg_.callstackOpen); - ImGui::MenuItem("Breakpoints", nullptr, &cfg_.breakpointsOpen); - ImGui::MenuItem("Watch", nullptr, &cfg_.watchOpen); - ImGui::MenuItem("JIT viewer", nullptr, &cfg_.jitViewerOpen); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Symbols")) { - ImGui::MenuItem("Symbol browser", nullptr, &cfg_.symbolsOpen); - ImGui::Separator(); - if (ImGui::MenuItem("Load .ppmap...")) { - System_BrowseForFile(reqToken_, "Load PPSSPP symbol map", BrowseFileType::SYMBOL_MAP, [this](std::string_view responseString, int) { - Path path(responseString); - if (!g_symbolMap->LoadSymbolMap(path)) { - ERROR_LOG(Log::Common, "Failed to load symbol map"); - } + if (PSP_IsInited()) { + + if (ImGui::BeginMenu("Core")) { + ImGui::MenuItem("Scheduler", nullptr, &cfg_.schedulerOpen); + ImGui::MenuItem("Time", nullptr, &cfg_.timeOpen); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("CPU")) { + ImGui::MenuItem("CPU debugger", nullptr, &cfg_.disasmOpen); + ImGui::MenuItem("GPR regs", nullptr, &cfg_.gprOpen); + ImGui::MenuItem("FPR regs", nullptr, &cfg_.fprOpen); + ImGui::MenuItem("VFPU regs", nullptr, &cfg_.vfpuOpen); + ImGui::Separator(); + ImGui::MenuItem("Callstacks", nullptr, &cfg_.callstackOpen); + ImGui::MenuItem("Breakpoints", nullptr, &cfg_.breakpointsOpen); + ImGui::MenuItem("Watch", nullptr, &cfg_.watchOpen); + ImGui::MenuItem("JIT viewer", nullptr, &cfg_.jitViewerOpen); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Symbols")) { + ImGui::MenuItem("Symbol browser", nullptr, &cfg_.symbolsOpen); + ImGui::Separator(); + + if (ImGui::MenuItem("Load .ppmap...")) { + System_BrowseForFile(reqToken_, "Load PPSSPP symbol map", BrowseFileType::SYMBOL_MAP, [this](std::string_view responseString, int) { + Path path(responseString); + if (!g_symbolMap->LoadSymbolMap(path)) { + ERROR_LOG(Log::Common, "Failed to load symbol map"); + } + disasm_.DirtySymbolMap(); + }); + } + if (ImGui::MenuItem("Save .ppmap...")) { + System_BrowseForFileSave(reqToken_, "Save PPSSPP symbol map", "symbols.ppmap", BrowseFileType::SYMBOL_MAP, [](std::string_view responseString, int) { + Path path(responseString); + if (!g_symbolMap->SaveSymbolMap(path)) { + ERROR_LOG(Log::Common, "Failed to save symbol map"); + } + }); + } + if (ImGui::MenuItem("Load No$ .sym...")) { + System_BrowseForFile(reqToken_, "Load No$ symbol map", BrowseFileType::SYMBOL_MAP, [this](std::string_view responseString, int) { + Path path(responseString); + if (!g_symbolMap->LoadNocashSym(path)) { + ERROR_LOG(Log::Common, "Failed to load No$ symbol map"); + } + disasm_.DirtySymbolMap(); + }); + } + if (ImGui::MenuItem("Save No$ .sym...")) { + System_BrowseForFileSave(reqToken_, "Save No$ symbol map", "symbols.sym", BrowseFileType::SYMBOL_MAP, [](std::string_view responseString, int) { + Path path(responseString); + if (!g_symbolMap->SaveNocashSym(path)) { + ERROR_LOG(Log::Common, "Failed to save No$ symbol map"); + } + }); + } + ImGui::Separator(); + ImGui::MenuItem("Compress .ppmap files", nullptr, &g_Config.bCompressSymbols); + if (ImGui::MenuItem("Reset symbol map")) { + g_symbolMap->Clear(); disasm_.DirtySymbolMap(); - }); + // NotifyDebuggerMapLoaded(); + } + ImGui::EndMenu(); } - if (ImGui::MenuItem("Save .ppmap...")) { - System_BrowseForFileSave(reqToken_, "Save PPSSPP symbol map", "symbols.ppmap", BrowseFileType::SYMBOL_MAP, [](std::string_view responseString, int) { - Path path(responseString); - if (!g_symbolMap->SaveSymbolMap(path)) { - ERROR_LOG(Log::Common, "Failed to save symbol map"); - } - }); + if (ImGui::BeginMenu("Memory")) { + for (int i = 0; i < 4; i++) { + char title[64]; + snprintf(title, sizeof(title), "Memory %d", i + 1); + ImGui::MenuItem(title, nullptr, &cfg_.memViewOpen[i]); + } + ImGui::MenuItem("Memory Dumper", nullptr, &cfg_.memDumpOpen); + ImGui::EndMenu(); } - if (ImGui::MenuItem("Load No$ .sym...")) { - System_BrowseForFile(reqToken_, "Load No$ symbol map", BrowseFileType::SYMBOL_MAP, [this](std::string_view responseString, int) { - Path path(responseString); - if (!g_symbolMap->LoadNocashSym(path)) { - ERROR_LOG(Log::Common, "Failed to load No$ symbol map"); - } - disasm_.DirtySymbolMap(); - }); + if (ImGui::BeginMenu("OS HLE")) { + ImGui::MenuItem("HLE module browser", nullptr, &cfg_.hleModulesOpen); + ImGui::MenuItem("File System Browser", nullptr, &cfg_.filesystemBrowserOpen); + ImGui::MenuItem("Kernel Objects", nullptr, &cfg_.kernelObjectsOpen); + ImGui::MenuItem("Threads", nullptr, &cfg_.threadsOpen); + ImGui::MenuItem("Modules", nullptr, &cfg_.modulesOpen); + ImGui::MenuItem("Utility Modules", nullptr, &cfg_.utilityModulesOpen); + ImGui::EndMenu(); } - if (ImGui::MenuItem("Save No$ .sym...")) { - System_BrowseForFileSave(reqToken_, "Save No$ symbol map", "symbols.sym", BrowseFileType::SYMBOL_MAP, [](std::string_view responseString, int) { - Path path(responseString); - if (!g_symbolMap->SaveNocashSym(path)) { - ERROR_LOG(Log::Common, "Failed to save No$ symbol map"); - } - }); + if (ImGui::BeginMenu("Graphics")) { + ImGui::MenuItem("GE Debugger", nullptr, &cfg_.geDebuggerOpen); + ImGui::MenuItem("GE State", nullptr, &cfg_.geStateOpen); + ImGui::MenuItem("GE Vertices", nullptr, &cfg_.geVertsOpen); + ImGui::MenuItem("Display Output", nullptr, &cfg_.displayOpen); + ImGui::MenuItem("Textures", nullptr, &cfg_.texturesOpen); + ImGui::MenuItem("Framebuffers", nullptr, &cfg_.framebuffersOpen); + ImGui::MenuItem("Pixel Viewer", nullptr, &cfg_.pixelViewerOpen); + // More to come here... + ImGui::EndMenu(); } - ImGui::Separator(); - ImGui::MenuItem("Compress .ppmap files", nullptr, &g_Config.bCompressSymbols); - if (ImGui::MenuItem("Reset symbol map")) { - g_symbolMap->Clear(); - disasm_.DirtySymbolMap(); - // NotifyDebuggerMapLoaded(); + if (ImGui::BeginMenu("Audio/Video")) { + ImGui::MenuItem("SasAudio mixer", nullptr, &cfg_.sasAudioOpen); + ImGui::MenuItem("Raw audio channels", nullptr, &cfg_.audioChannelsOpen); + ImGui::MenuItem("AV Decoder contexts", nullptr, &cfg_.mediaDecodersOpen); + ImGui::Separator(); + ImGui::MenuItem("Audio output / buffer", nullptr, &cfg_.audioOutOpen); + ImGui::EndMenu(); } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Memory")) { - for (int i = 0; i < 4; i++) { - char title[64]; - snprintf(title, sizeof(title), "Memory %d", i + 1); - ImGui::MenuItem(title, nullptr, &cfg_.memViewOpen[i]); + if (ImGui::BeginMenu("Network")) { + ImGui::MenuItem("ApCtl", nullptr, &cfg_.apctlOpen); + ImGui::MenuItem("Sockets", nullptr, &cfg_.socketsOpen); + ImGui::MenuItem("NP", nullptr, &cfg_.npOpen); + ImGui::MenuItem("AdHoc", nullptr, &cfg_.adhocOpen); + ImGui::EndMenu(); } - ImGui::MenuItem("Memory Dumper", nullptr, &cfg_.memDumpOpen); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("OS HLE")) { - ImGui::MenuItem("HLE module browser", nullptr, &cfg_.hleModulesOpen); - ImGui::MenuItem("File System Browser", nullptr, &cfg_.filesystemBrowserOpen); - ImGui::MenuItem("Kernel Objects", nullptr, &cfg_.kernelObjectsOpen); - ImGui::MenuItem("Threads", nullptr, &cfg_.threadsOpen); - ImGui::MenuItem("Modules", nullptr, &cfg_.modulesOpen); - ImGui::MenuItem("Utility Modules",nullptr, &cfg_.utilityModulesOpen); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Graphics")) { - ImGui::MenuItem("GE Debugger", nullptr, &cfg_.geDebuggerOpen); - ImGui::MenuItem("GE State", nullptr, &cfg_.geStateOpen); - ImGui::MenuItem("GE Vertices", nullptr, &cfg_.geVertsOpen); - ImGui::MenuItem("Display Output", nullptr, &cfg_.displayOpen); - ImGui::MenuItem("Textures", nullptr, &cfg_.texturesOpen); - ImGui::MenuItem("Framebuffers", nullptr, &cfg_.framebuffersOpen); - ImGui::MenuItem("Pixel Viewer", nullptr, &cfg_.pixelViewerOpen); - // More to come here... - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Audio/Video")) { - ImGui::MenuItem("SasAudio mixer", nullptr, &cfg_.sasAudioOpen); - ImGui::MenuItem("Raw audio channels", nullptr, &cfg_.audioChannelsOpen); - ImGui::MenuItem("AV Decoder contexts", nullptr, &cfg_.mediaDecodersOpen); - ImGui::Separator(); - ImGui::MenuItem("Audio output / buffer", nullptr, &cfg_.audioOutOpen); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("Network")) { - ImGui::MenuItem("ApCtl", nullptr, &cfg_.apctlOpen); - ImGui::MenuItem("Sockets", nullptr, &cfg_.socketsOpen); - ImGui::MenuItem("NP", nullptr, &cfg_.npOpen); - ImGui::MenuItem("AdHoc", nullptr, &cfg_.adhocOpen); - ImGui::EndMenu(); } + if (ImGui::BeginMenu("Tools")) { ImGui::MenuItem("Lua Console", nullptr, &cfg_.luaConsoleOpen); ImGui::MenuItem("Log", nullptr, &cfg_.logOpen); ImGui::MenuItem("Log channels", nullptr, &cfg_.logConfigOpen); ImGui::MenuItem("Debug stats", nullptr, &cfg_.debugStatsOpen); ImGui::Separator(); - ImGui::MenuItem("ParamSFO viewer", nullptr, &cfg_.paramSFOOpen); + if (PSP_IsInited()) { + ImGui::MenuItem("ParamSFO viewer", nullptr, &cfg_.paramSFOOpen); + } ImGui::MenuItem("Struct viewer", nullptr, &cfg_.structViewerOpen); ImGui::MenuItem("Atrac Tool", nullptr, &cfg_.atracToolOpen); ImGui::EndMenu(); @@ -2575,97 +2611,89 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: ImGui::ShowStyleEditor(); } - if (cfg_.disasmOpen) { - disasm_.Draw(mipsDebug, cfg_, control, coreState); - } - - if (cfg_.gprOpen) { - DrawGPRs(cfg_, control, mipsDebug, snapshot_); - } - - if (cfg_.fprOpen) { - DrawFPRs(cfg_, control, mipsDebug, snapshot_); - } - - if (cfg_.vfpuOpen) { - DrawVFPU(cfg_, control, mipsDebug, snapshot_); - } - - if (cfg_.breakpointsOpen) { - DrawBreakpointsView(mipsDebug, cfg_); - } - - if (cfg_.filesystemBrowserOpen) { - DrawFilesystemBrowser(cfg_); - } - - if (cfg_.audioChannelsOpen) { - DrawAudioChannels(cfg_, control); - } - - if (cfg_.audioOutOpen) { - DrawAudioOut(cfg_, control); - } - - if (cfg_.sasAudioOpen) { - DrawSasAudio(cfg_); - } - - if (cfg_.kernelObjectsOpen) { - DrawKernelObjects(cfg_); - } - - if (cfg_.threadsOpen) { - DrawThreadView(cfg_, control); - } - - if (cfg_.callstackOpen) { - DrawCallStacks(mipsDebug, cfg_, control); - } - - if (cfg_.modulesOpen) { - DrawModules(mipsDebug, cfg_, control); - } - - if (cfg_.symbolsOpen) { - DrawSymbols(mipsDebug, cfg_, control); - } - - if (cfg_.utilityModulesOpen) { - DrawUtilityModules(cfg_, control); - } - - if (cfg_.mediaDecodersOpen) { - DrawMediaDecodersView(cfg_, control); - } - - if (cfg_.hleModulesOpen) { - DrawHLEModules(cfg_); - } - - if (cfg_.atracToolOpen) { - atracToolWindow_.Draw(cfg_); - } - - if (gpuDebug) { - if (cfg_.framebuffersOpen) { - DrawFramebuffersWindow(cfg_, gpuDebug->GetFramebufferManagerCommon()); - } - - if (cfg_.texturesOpen) { - DrawTexturesWindow(cfg_, gpuDebug->GetTextureCacheCommon()); - } - } - - if (cfg_.logConfigOpen) { - DrawLogConfig(cfg_); - } - - if (cfg_.logOpen) { - logWindow_.Draw(cfg_); - } - if (PSP_IsInited()) { + if (cfg_.disasmOpen) { + disasm_.Draw(mipsDebug, cfg_, control, coreState); + } + + if (cfg_.gprOpen) { + DrawGPRs(cfg_, control, mipsDebug, snapshot_); + } + + if (cfg_.fprOpen) { + DrawFPRs(cfg_, control, mipsDebug, snapshot_); + } + + if (cfg_.vfpuOpen) { + DrawVFPU(cfg_, control, mipsDebug, snapshot_); + } + + if (cfg_.breakpointsOpen) { + DrawBreakpointsView(mipsDebug, cfg_); + } + + if (cfg_.filesystemBrowserOpen) { + DrawFilesystemBrowser(cfg_); + } + + if (cfg_.audioChannelsOpen) { + DrawAudioChannels(cfg_, control); + } + + if (cfg_.audioOutOpen) { + DrawAudioOut(cfg_, control); + } + + if (cfg_.sasAudioOpen) { + DrawSasAudio(cfg_); + } + + if (cfg_.kernelObjectsOpen) { + DrawKernelObjects(cfg_); + } + + if (cfg_.threadsOpen) { + DrawThreadView(cfg_, control); + } + + if (cfg_.callstackOpen) { + DrawCallStacks(mipsDebug, cfg_, control); + } + + if (cfg_.modulesOpen) { + DrawModules(mipsDebug, cfg_, control); + } + + if (cfg_.symbolsOpen) { + DrawSymbols(mipsDebug, cfg_, control); + } + + if (cfg_.utilityModulesOpen) { + DrawUtilityModules(cfg_, control); + } + + if (cfg_.mediaDecodersOpen) { + DrawMediaDecodersView(cfg_, control); + } + + if (cfg_.hleModulesOpen) { + DrawHLEModules(cfg_); + } + + if (cfg_.atracToolOpen) { + atracToolWindow_.Draw(cfg_); + } + + if (gpuDebug) { + if (cfg_.framebuffersOpen) { + DrawFramebuffersWindow(cfg_, gpuDebug->GetFramebufferManagerCommon()); + } + + if (cfg_.texturesOpen) { + DrawTexturesWindow(cfg_, gpuDebug->GetTextureCacheCommon()); + } + } + if (cfg_.jitViewerOpen) { jitViewer_.Draw(cfg_, control); } @@ -2677,13 +2705,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: if (cfg_.debugStatsOpen) { DrawDebugStatsWindow(cfg_); } - } - if (cfg_.structViewerOpen) { - structViewer_.Draw(cfg_, control, mipsDebug); - } - - if (PSP_IsInited()) { if (cfg_.paramSFOOpen) { DrawParamSFO(cfg_, control); } @@ -2743,6 +2765,18 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUCommon *gpuDebug, Draw: } } + if (cfg_.logConfigOpen) { + DrawLogConfig(cfg_); + } + + if (cfg_.logOpen) { + logWindow_.Draw(cfg_); + } + + if (cfg_.structViewerOpen) { + structViewer_.Draw(cfg_, control, mipsDebug); + } + if (cfg_.internalsOpen) { DrawInternals(cfg_); } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 7860c7691f..3d5a07acf4 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -413,29 +413,6 @@ void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name, boo *version = PPSSPP_GIT_VERSION; } -#if defined(USING_WIN_UI) && !PPSSPP_PLATFORM(UWP) -static bool CheckFontIsUsable(const wchar_t *fontFace) { - wchar_t actualFontFace[1024] = { 0 }; - - HFONT f = CreateFont(0, 0, 0, 0, FW_LIGHT, 0, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, fontFace); - if (f != nullptr) { - HDC hdc = CreateCompatibleDC(nullptr); - if (hdc != nullptr) { - SelectObject(hdc, f); - GetTextFace(hdc, 1024, actualFontFace); - DeleteDC(hdc); - } - DeleteObject(f); - } - - // If we were able to get the font name, did it load? - if (actualFontFace[0] != 0) { - return wcsncmp(actualFontFace, fontFace, ARRAY_SIZE(actualFontFace)) == 0; - } - return false; -} -#endif - void PostLoadConfig() { if (g_Config.currentDirectory.empty()) { g_Config.currentDirectory = g_Config.defaultCurrentDirectory; @@ -1293,7 +1270,7 @@ void NativeFrame(GraphicsContext *graphicsContext) { g_screenManager->getUIContext()->SetTintSaturation(g_Config.fUITint, g_Config.fUISaturation); - // All actual rendering (and also emulation) happens in here. + // All actual rendering (and also emulation) happens in this render() call. ScreenRenderFlags renderFlags = g_screenManager->render(); if (g_screenManager->getUIContext()->Text()) { g_screenManager->getUIContext()->Text()->OncePerFrame(); diff --git a/ext/imgui/imgui_extras.cpp b/ext/imgui/imgui_extras.cpp index 423ba19188..c89b89b21e 100644 --- a/ext/imgui/imgui_extras.cpp +++ b/ext/imgui/imgui_extras.cpp @@ -63,4 +63,26 @@ bool CollapsingHeaderWithCount(const char *title, int count, ImGuiTreeNodeFlags return ImGui::CollapsingHeader(temp, flags); } +bool CheckboxInverted(const char* label, bool* v) { + bool value = !(*v); + if (ImGui::Checkbox(label, &value)) { + *v = !value; + return true; + } + return false; +} + +bool MenuItemInverted(const char* label, const char* shortcut, bool* p_selected, bool enabled) { + if (p_selected) { + bool value = !(*p_selected); + if (ImGui::MenuItem(label, shortcut, &value, enabled)) { + *p_selected = !value; + return true; + } + } else { + return ImGui::MenuItem(label, shortcut, nullptr, enabled); + } + return false; +} + } // namespace ImGui diff --git a/ext/imgui/imgui_extras.h b/ext/imgui/imgui_extras.h index 8829aba841..5c3fd5888e 100644 --- a/ext/imgui/imgui_extras.h +++ b/ext/imgui/imgui_extras.h @@ -10,8 +10,10 @@ inline void TextUnformatted(std::string_view str) { } bool RepeatButton(const char *title); -int RepeatButtonShift(const char* label, float repeatRate = 0.05f); +int RepeatButtonShift(const char *label, float repeatRate = 0.05f); bool CollapsingHeaderWithCount(const char *title, int count, ImGuiTreeNodeFlags flags = 0); +bool CheckboxInverted(const char *label, bool *v); +bool MenuItemInverted(const char* label, const char* shortcut = nullptr, bool* p_selected = nullptr, bool enabled = true); } // namespace ImGui