From 9d6c44fd25c16c507a41d9c99745a3322e9808ff Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 13 Jan 2024 16:59:05 -0600 Subject: [PATCH] Migrate all of menubar to new widgets, clean up dead code --- mm/2s2h/BenGui.cpp | 155 +------------ mm/2s2h/BenGui.hpp | 38 +-- mm/2s2h/BenMenuBar.cpp | 508 +++++++++++------------------------------ mm/2s2h/BenMenuBar.h | 12 +- mm/2s2h/BenPort.cpp | 6 +- mm/2s2h/UIWidgets.cpp | 86 +------ mm/2s2h/UIWidgets.hpp | 265 ++++++++++++++++++++- 7 files changed, 422 insertions(+), 648 deletions(-) diff --git a/mm/2s2h/BenGui.cpp b/mm/2s2h/BenGui.cpp index f6dac4ed4..d2b6ec5e8 100644 --- a/mm/2s2h/BenGui.cpp +++ b/mm/2s2h/BenGui.cpp @@ -1,11 +1,4 @@ -// -// SohGui.cpp -// soh -// -// Created by David Chavez on 24.08.22. -// - -#include "SohGui.hpp" +#include "BenGui.hpp" #include #include @@ -13,6 +6,7 @@ #include #include #include +#include "UIWidgets.hpp" #ifdef __APPLE__ #include "graphic/Fast3D/gfx_metal.h" @@ -22,116 +16,34 @@ #include #endif -//#include "UIWidgets.hpp" #include "include/global.h" #include "include/z64audio.h" -//#include "soh/SaveManager.h" -//#include "OTRGlobals.h" -//#include "soh/Enhancements/presets.h" -//#include "2s2h/resource/type/Skeleton.h" #include "libultraship/libultraship.h" -//#ifdef ENABLE_CROWD_CONTROL -//#include "Enhancements/crowd-control/CrowdControl.h" -//#endif - -//#include "Enhancements/game-interactor/GameInteractor.h" -//#include "Enhancements/cosmetics/authenticGfxPatches.h" - bool ShouldClearTextureCacheAtEndOfFrame = false; -bool isBetaQuestEnabled = false; - -extern "C" { - void enableBetaQuest() { isBetaQuestEnabled = true; } - void disableBetaQuest() { isBetaQuestEnabled = false; } -} - - -namespace SohGui { - - // MARK: - Properties - - static const char* chestSizeAndTextureMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" }; - static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" }; - static const char* allPowers[9] = { - "Vanilla (1x)", - "Double (2x)", - "Quadruple (4x)", - "Octuple (8x)", - "Foolish (16x)", - "Ridiculous (32x)", - "Merciless (64x)", - "Pure Torture (128x)", - "OHKO (256x)" }; - static const char* subPowers[8] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6], allPowers[7] }; - static const char* subSubPowers[7] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6] }; - static const char* zFightingOptions[3] = { "Disabled", "Consistent Vanish", "No Vanish" }; - static const char* autosaveLabels[6] = { "Off", "New Location + Major Item", "New Location + Any Item", "New Location", "Major Item", "Any Item" }; - static const char* FastFileSelect[5] = { "File N.1", "File N.2", "File N.3", "Zelda Map Select (require OoT Debug Mode)", "File select" }; - static const char* bonkDamageValues[8] = { - "No Damage", - "0.25 Heart", - "0.5 Heart", - "1 Heart", - "2 Hearts", - "4 Hearts", - "8 Hearts", - "OHKO" - }; - - static const inline std::vector> audioBackends = { -#ifdef _WIN32 - { "wasapi", "Windows Audio Session API" }, -#endif -#if defined(__linux) - { "pulse", "PulseAudio" }, -#endif - { "sdl", "SDL Audio" } - }; - - - // MARK: - Helpers - - std::string GetWindowButtonText(const char* text, bool menuOpen) { - char buttonText[100] = ""; - if (menuOpen) { - strcat(buttonText, ICON_FA_CHEVRON_RIGHT " "); - } - strcat(buttonText, text); - if (!menuOpen) { strcat(buttonText, " "); } - return buttonText; - } - +namespace BenGui { // MARK: - Delegates - std::shared_ptr mSohMenuBar; + std::shared_ptr mBenMenuBar; std::shared_ptr mConsoleWindow; std::shared_ptr mStatsWindow; std::shared_ptr mInputEditorWindow; std::shared_ptr mGfxDebuggerWindow; - //std::shared_ptr mAudioEditorWindow; - //std::shared_ptr mGameControlEditorWindow; - //std::shared_ptr mCosmeticsEditorWindow; - //std::shared_ptr mActorViewerWindow; - //std::shared_ptr mColViewerWindow; std::shared_ptr mSaveEditorWindow; - //std::shared_ptr mDLViewerWindow; - //std::shared_ptr mGameplayStatsWindow; - //std::shared_ptr mCheckTrackerSettingsWindow; - //std::shared_ptr mCheckTrackerWindow; - //std::shared_ptr mEntranceTrackerWindow; - //std::shared_ptr mItemTrackerSettingsWindow; - //std::shared_ptr mItemTrackerWindow; - //std::shared_ptr mRandomizerSettingsWindow; void SetupGuiElements() { auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); - mSohMenuBar = std::make_shared("gOpenMenuBar", CVarGetInteger("gOpenMenuBar", 0)); - gui->SetMenuBar(std::reinterpret_pointer_cast(mSohMenuBar)); + auto& style = ImGui::GetStyle(); + style.FramePadding = ImVec2(4.0f, 6.0f); + style.ItemSpacing = ImVec2(8.0f, 6.0f); + style.Colors[ImGuiCol_MenuBarBg] = UIWidgets::Colors::DarkGray; + + mBenMenuBar = std::make_shared("gOpenMenuBar", CVarGetInteger("gOpenMenuBar", 0)); + gui->SetMenuBar(std::reinterpret_pointer_cast(mBenMenuBar)); if (gui->GetMenuBar() && !gui->GetMenuBar()->IsVisible()) { #if defined(__SWITCH__) || defined(__WIIU__) @@ -163,55 +75,12 @@ namespace SohGui { mSaveEditorWindow = std::make_shared("gSaveEditorEnabled", "Save Editor"); gui->AddGuiWindow(mSaveEditorWindow); - - /* - mAudioEditorWindow = std::make_shared("gAudioEditor.WindowOpen", "Audio Editor"); - gui->AddGuiWindow(mAudioEditorWindow); - mGameControlEditorWindow = std::make_shared("gGameControlEditorEnabled", "Game Control Editor"); - gui->AddGuiWindow(mGameControlEditorWindow); - mCosmeticsEditorWindow = std::make_shared("gCosmeticsEditorEnabled", "Cosmetics Editor"); - gui->AddGuiWindow(mCosmeticsEditorWindow); - mActorViewerWindow = std::make_shared("gActorViewerEnabled", "Actor Viewer"); - gui->AddGuiWindow(mActorViewerWindow); - mColViewerWindow = std::make_shared("gCollisionViewerEnabled", "Collision Viewer"); - gui->AddGuiWindow(mColViewerWindow); - mDLViewerWindow = std::make_shared("gDLViewerEnabled", "Display List Viewer"); - gui->AddGuiWindow(mDLViewerWindow); - mGameplayStatsWindow = std::make_shared("gGameplayStatsEnabled", "Gameplay Stats"); - gui->AddGuiWindow(mGameplayStatsWindow); - mCheckTrackerWindow = std::make_shared("gCheckTrackerEnabled", "Check Tracker"); - gui->AddGuiWindow(mCheckTrackerWindow); - mCheckTrackerSettingsWindow = std::make_shared("gCheckTrackerSettingsEnabled", "Check Tracker Settings"); - gui->AddGuiWindow(mCheckTrackerSettingsWindow); - mEntranceTrackerWindow = std::make_shared("gEntranceTrackerEnabled","Entrance Tracker"); - gui->AddGuiWindow(mEntranceTrackerWindow); - mItemTrackerWindow = std::make_shared("gItemTrackerEnabled", "Item Tracker"); - gui->AddGuiWindow(mItemTrackerWindow); - mItemTrackerSettingsWindow = std::make_shared("gItemTrackerSettingsEnabled", "Item Tracker Settings"); - gui->AddGuiWindow(mItemTrackerSettingsWindow); - mRandomizerSettingsWindow = std::make_shared("gRandomizerSettingsEnabled", "Randomizer Settings"); - gui->AddGuiWindow(mRandomizerSettingsWindow); - */ } void Destroy() { - //mRandomizerSettingsWindow = nullptr; - //mItemTrackerWindow = nullptr; - //mItemTrackerSettingsWindow = nullptr; - //mEntranceTrackerWindow = nullptr; - //mCheckTrackerWindow = nullptr; - //mCheckTrackerSettingsWindow = nullptr; - //mGameplayStatsWindow = nullptr; - //mDLViewerWindow = nullptr; mSaveEditorWindow = nullptr; - //mColViewerWindow = nullptr; - //mActorViewerWindow = nullptr; - //mCosmeticsEditorWindow = nullptr; - //mGameControlEditorWindow = nullptr; - //mAudioEditorWindow = nullptr; - //mInputEditorWindow = nullptr; mStatsWindow = nullptr; mConsoleWindow = nullptr; - mSohMenuBar = nullptr; + mBenMenuBar = nullptr; } } diff --git a/mm/2s2h/BenGui.hpp b/mm/2s2h/BenGui.hpp index daee855e8..80bb04fbd 100644 --- a/mm/2s2h/BenGui.hpp +++ b/mm/2s2h/BenGui.hpp @@ -1,43 +1,15 @@ -// -// SohGui.hpp -// soh -// -// Created by David Chavez on 24.08.22. -// - -#ifndef SohGui_hpp -#define SohGui_hpp +#ifndef BenGui_hpp +#define BenGui_hpp #include -#include "SohMenuBar.h" +#include "BenMenuBar.h" #include "DeveloperTools/SaveEditor.h" -//#include "Enhancements/audio/AudioEditor.h" -//#include "Enhancements/controls/GameControlEditor.h" -//#include "Enhancements/cosmetics/CosmeticsEditor.h" -//#include "Enhancements/debugger/actorViewer.h" -//#include "Enhancements/debugger/colViewer.h" -//#include "Enhancements/debugger/debugSaveEditor.h" -//#include "Enhancements/debugger/dlViewer.h" -//#include "Enhancements/gameplaystatswindow.h" -//#include "Enhancements/randomizer/randomizer_check_tracker.h" -//#include "Enhancements/randomizer/randomizer_entrance_tracker.h" -//#include "Enhancements/randomizer/randomizer_item_tracker.h" -//#include "Enhancements/randomizer/randomizer_settings_window.h" -#ifdef __cplusplus -extern "C" { -#endif - void enableBetaQuest(); - void disableBetaQuest(); -#ifdef __cplusplus -} -#endif - -namespace SohGui { +namespace BenGui { void SetupHooks(); void SetupGuiElements(); void Draw(); void Destroy(); } -#endif /* SohGui_hpp */ +#endif /* BenGui_hpp */ diff --git a/mm/2s2h/BenMenuBar.cpp b/mm/2s2h/BenMenuBar.cpp index 9b509de5b..0edf018ae 100644 --- a/mm/2s2h/BenMenuBar.cpp +++ b/mm/2s2h/BenMenuBar.cpp @@ -1,35 +1,13 @@ -#include "SohMenuBar.h" +#include "BenMenuBar.h" #include "ImGui/imgui.h" #include "public/bridge/consolevariablebridge.h" #include #include "UIWidgets.hpp" -//#include "include/z64audio.h" -//#include "OTRGlobals.h" +#include +#include #include "z64.h" -//#include "Enhancements/game-interactor/GameInteractor.h" -//#include "soh/Enhancements/presets.h" -//#include "soh/Enhancements/mods.h" -//#include "Enhancements/cosmetics/authenticGfxPatches.h" -#ifdef ENABLE_CROWD_CONTROL -#include "Enhancements/crowd-control/CrowdControl.h" -#endif - - -//#include "Enhancements/audio/AudioEditor.h" -//#include "Enhancements/controls/GameControlEditor.h" -//#include "Enhancements/cosmetics/CosmeticsEditor.h" -//#include "Enhancements/debugger/actorViewer.h" -//#include "Enhancements/debugger/colViewer.h" -//#include "Enhancements/debugger/debugSaveEditor.h" -//#include "Enhancements/debugger/dlViewer.h" -//#include "Enhancements/gameplaystatswindow.h" -//#include "Enhancements/randomizer/randomizer_check_tracker.h" -//#include "Enhancements/randomizer/randomizer_entrance_tracker.h" -//#include "Enhancements/randomizer/randomizer_item_tracker.h" -//#include "Enhancements/randomizer/randomizer_settings_window.h" extern bool ShouldClearTextureCacheAtEndOfFrame; -extern bool isBetaQuestEnabled; extern "C" PlayState* gPlayState; @@ -41,130 +19,62 @@ enum SeqPlayers { /* 4 */ SEQ_MAX }; -std::string GetWindowButtonText(const char* text, bool menuOpen) { - char buttonText[100] = ""; - if (menuOpen) { - strcat(buttonText, ICON_FA_CHEVRON_RIGHT " "); - } - strcat(buttonText, text); - if (!menuOpen) { strcat(buttonText, " "); } - return buttonText; -} +static const std::unordered_map textureFilteringMap = { + { FILTER_THREE_POINT, "Three-Point" }, + { FILTER_LINEAR, "Linear" }, + { FILTER_NONE, "None" }, +}; - static const char* filters[3] = { -#ifdef __WIIU__ - "", -#else - "Three-Point", -#endif - "Linear", "None" - }; +static const std::unordered_map audioBackendsMap = { + { LUS::AudioBackend::WASAPI, "Windows Audio Session API" }, + { LUS::AudioBackend::PULSE, "PulseAudio" }, + { LUS::AudioBackend::SDL, "SDL" }, +}; - static const char* chestStyleMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" }; - static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" }; - static const char* mirroredWorldModes[9] = { - "Disabled", "Always", "Random", "Random (Seeded)", "Dungeons", - "Dungeons (Vanilla)", "Dungeons (MQ)", "Dungeons Random", "Dungeons Random (Seeded)", - }; - static const char* enemyRandomizerModes[3] = { "Disabled", "Random", "Random (Seeded)" }; - static const char* allPowers[9] = { - "Vanilla (1x)", - "Double (2x)", - "Quadruple (4x)", - "Octuple (8x)", - "Foolish (16x)", - "Ridiculous (32x)", - "Merciless (64x)", - "Pure Torture (128x)", - "OHKO (256x)" }; - static const char* subPowers[8] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6], allPowers[7] }; - static const char* subSubPowers[7] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6] }; - static const char* zFightingOptions[3] = { "Disabled", "Consistent Vanish", "No Vanish" }; - static const char* autosaveLabels[6] = { "Off", "New Location + Major Item", "New Location + Any Item", "New Location", "Major Item", "Any Item" }; - static const char* DebugSaveFileModes[3] = { "Off", "Vanilla", "Maxed" }; - static const char* FastFileSelect[5] = { "File N.1", "File N.2", "File N.3", "Zelda Map Select (require OoT Debug Mode)", "File select" }; - static const char* DekuStickCheat[3] = { "Normal", "Unbreakable", "Unbreakable + Always on Fire" }; - static const char* bonkDamageValues[8] = { - "No Damage", - "0.25 Heart", - "0.5 Heart", - "1 Heart", - "2 Hearts", - "4 Hearts", - "8 Hearts", - "OHKO" - }; - static const char* timeTravelOptions[3] = { "Disabled", "Ocarina of Time", "Any Ocarina" }; +static std::unordered_map windowBackendsMap = { + { LUS::WindowBackend::DX11, "DirectX" }, + { LUS::WindowBackend::SDL_OPENGL, "OpenGL" }, + { LUS::WindowBackend::SDL_METAL, "Metal" }, + { LUS::WindowBackend::GX2, "GX2" } +}; -extern "C" SaveContext gSaveContext; - -namespace SohGui { - -void DrawMenuBarIcon() { - static bool gameIconLoaded = false; - if (!gameIconLoaded) { - LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTexture("Game_Icon", "textures/icons/gIcon.png"); - gameIconLoaded = true; - } - - if (LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon")) { -#ifdef __SWITCH__ - ImVec2 iconSize = ImVec2(20.0f, 20.0f); - float posScale = 1.0f; -#elif defined(__WIIU__) - ImVec2 iconSize = ImVec2(16.0f * 2, 16.0f * 2); - float posScale = 2.0f; -#else - ImVec2 iconSize = ImVec2(16.0f, 16.0f); - float posScale = 1.0f; -#endif - ImGui::SetCursorPos(ImVec2(5, 2.5f) * posScale); - ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon"), iconSize); - ImGui::SameLine(); - ImGui::SetCursorPos(ImVec2(25, 0) * posScale); - } -} - -void DrawShipMenu() { - if (ImGui::BeginMenu("Ship")) { - if (ImGui::MenuItem("Hide Menu Bar", +namespace BenGui { +void DrawBenMenu() { + if (UIWidgets::BeginMenu("Game")) { + if (UIWidgets::MenuItem("Hide Menu Bar", #if !defined(__SWITCH__) && !defined(__WIIU__) - "F1" + "F1" #else - "[-]" + "[-]" #endif - )) { + )) { LUS::Context::GetInstance()->GetWindow()->GetGui()->GetMenuBar()->ToggleVisibility(); } - UIWidgets::Spacer(0); #if !defined(__SWITCH__) && !defined(__WIIU__) - if (ImGui::MenuItem("Toggle Fullscreen", "F11")) { + if (UIWidgets::MenuItem("Toggle Fullscreen", "F11")) { LUS::Context::GetInstance()->GetWindow()->ToggleFullscreen(); } - UIWidgets::Spacer(0); #endif - if (ImGui::MenuItem("Reset", + if (UIWidgets::MenuItem("Reset", #ifdef __APPLE__ - "Command-R" + "Command-R" #elif !defined(__SWITCH__) && !defined(__WIIU__) - "Ctrl+R" + "Ctrl+R" #else - "" + "" #endif - )) { + )) { std::reinterpret_pointer_cast( LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) ->Dispatch("reset"); } #if !defined(__SWITCH__) && !defined(__WIIU__) - UIWidgets::Spacer(0); - if (ImGui::MenuItem("Open App Files Folder")) { + if (UIWidgets::MenuItem("Open App Files Folder")) { std::string filesPath = LUS::Context::GetInstance()->GetAppDirectoryPath(); SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); } - UIWidgets::Spacer(0); - if (ImGui::MenuItem("Quit")) { + if (UIWidgets::MenuItem("Quit")) { LUS::Context::GetInstance()->GetWindow()->Close(); } #endif @@ -173,109 +83,67 @@ void DrawShipMenu() { } extern std::shared_ptr mInputEditorWindow; -// extern std::shared_ptr mGameControlEditorWindow; void DrawSettingsMenu() { - if (ImGui::BeginMenu("Settings")) { - if (ImGui::BeginMenu("Audio")) { - UIWidgets::PaddedEnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, - 1.0f, "", 1.0f, true, true, false, true); - if (UIWidgets::PaddedEnhancementSliderFloat("Main Music Volume: %d %%", "##Main_Music_Vol", - "gMainMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, - true)) { - // Audio_SetGameVolume(SEQ_BGM_MAIN, CVarGetFloat("gMainMusicVolume", 1.0f)); + if (UIWidgets::BeginMenu("Settings")) { + if (UIWidgets::BeginMenu("Audio")) { + UIWidgets::CVarSliderFloat("Master Volume: %.0f %%", "gSettings.Audio.MasterVolume", 0.0f, 1.0f, 1.0f, { .isPercentage = true, .showButtons = false, .format = "" }); + + if (UIWidgets::CVarSliderFloat("Main Music Volume: %.0f %%", "gSettings.Audio.MainMusicVolume", 0.0f, 1.0f, 1.0f, { .isPercentage = true, .showButtons = false, .format = "" })) { + // Audio_SetGameVolume(SEQ_BGM_MAIN, CVarGetFloat("gSettings.Audio.MainMusicVolume", 1.0f)); } - if (UIWidgets::PaddedEnhancementSliderFloat("Sub Music Volume: %d %%", "##Sub_Music_Vol", "gSubMusicVolume", - 0.0f, 1.0f, "", 1.0f, true, true, false, true)) { - // Audio_SetGameVolume(SEQ_BGM_SUB, CVarGetFloat("gSubMusicVolume", 1.0f)); + if (UIWidgets::CVarSliderFloat("Sub Music Volume: %.0f %%", "gSettings.Audio.SubMusicVolume", 0.0f, 1.0f, 1.0f, { .isPercentage = true, .showButtons = false, .format = "" })) { + // Audio_SetGameVolume(SEQ_BGM_SUB, CVarGetFloat("gSettings.Audio.SubMusicVolume", 1.0f)); } - if (UIWidgets::PaddedEnhancementSliderFloat("Sound Effects Volume: %d %%", "##Sound_Effect_Vol", - "gSFXMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, - true)) { - // Audio_SetGameVolume(SEQ_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); + if (UIWidgets::CVarSliderFloat("Sound Effects Volume: %.0f %%", "gSettings.Audio.SoundEffectsVolume", 0.0f, 1.0f, 1.0f, { .isPercentage = true, .showButtons = false, .format = "" })) { + // Audio_SetGameVolume(SEQ_SFX, CVarGetFloat("gSettings.Audio.SoundEffectsVolume", 1.0f)); } - if (UIWidgets::PaddedEnhancementSliderFloat("Fanfare Volume: %d %%", "##Fanfare_Vol", "gFanfareVolume", - 0.0f, 1.0f, "", 1.0f, true, true, false, true)) { - // Audio_SetGameVolume(SEQ_FANFARE, CVarGetFloat("gFanfareVolume", 1.0f)); + if (UIWidgets::CVarSliderFloat("Fanfare Volume: %.0f %%", "gSettings.Audio.FanfareVolume", 0.0f, 1.0f, 1.0f, { .isPercentage = true, .showButtons = false, .format = "" })) { + // Audio_SetGameVolume(SEQ_FANFARE, CVarGetFloat("gSettings.Audio.FanfareVolume", 1.0f)); } - static std::unordered_map audioBackendNames = { - { LUS::AudioBackend::WASAPI, "Windows Audio Session API" }, - { LUS::AudioBackend::PULSE, "PulseAudio" }, - { LUS::AudioBackend::SDL, "SDL" }, - }; - - ImGui::Text("Audio API (Needs reload)"); auto currentAudioBackend = LUS::Context::GetInstance()->GetAudio()->GetAudioBackend(); - - if (LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { - UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); - } - if (ImGui::BeginCombo("##AApi", audioBackendNames[currentAudioBackend])) { - for (uint8_t i = 0; i < LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size(); - i++) { - auto backend = LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->data()[i]; - if (ImGui::Selectable(audioBackendNames[backend], backend == currentAudioBackend)) { - LUS::Context::GetInstance()->GetAudio()->SetAudioBackend(backend); - } - } - ImGui::EndCombo(); - } - if (LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { - UIWidgets::ReEnableComponent(""); + if (UIWidgets::Combobox("Audio API", ¤tAudioBackend, audioBackendsMap, { + .disabled = LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1, + .tooltip = "Sets the audio API used by the game. Requires a relaunch to take effect.", + .disabledTooltip = "Only one audio API is available on this platform." + })) { + LUS::Context::GetInstance()->GetAudio()->SetAudioBackend(currentAudioBackend); } ImGui::EndMenu(); } - UIWidgets::Spacer(0); - - if (ImGui::BeginMenu("Controller")) { - //ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); - //ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.0f)); - //ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - //ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + if (UIWidgets::BeginMenu("Controller")) { if (mInputEditorWindow) { - if (ImGui::Button( - GetWindowButtonText("Controller Mapping", CVarGetInteger("gControllerConfigurationEnabled", 0)) - .c_str(), - ImVec2(-1.0f, 0.0f))) { - mInputEditorWindow->ToggleVisibility(); - } + UIWidgets::WindowButton("Controller Mapping", "gWindows.InputEditor", mInputEditorWindow); } - // if (mGameControlEditorWindow) { - // if (ImGui::Button(GetWindowButtonText("Additional Controller Options", - // CVarGetInteger("gGameControlEditorEnabled", 0)).c_str(), ImVec2(-1.0f, 0.0f))) { - // mGameControlEditorWindow->ToggleVisibility(); - //} - - ImGui::EndMenu(); - + ImGui::EndMenu(); } - UIWidgets::PaddedSeparator(); - //ImGui::PopStyleColor(1); - //ImGui::PopStyleVar(3); #ifndef __SWITCH__ - UIWidgets::EnhancementCheckbox("Menubar Controller Navigation", "gControlNav"); - UIWidgets::Tooltip("Allows controller navigation of the SOH menu bar (Settings, Enhancements,...)\nCAUTION: " - "This will disable game inputs while the menubar is visible.\n\nD-pad to move between " - "items, A to select, and X to grab focus on the menu bar"); + UIWidgets::CVarCheckbox("Menubar Controller Navigation", "gControlNav", { + .tooltip = "Allows controller navigation of the SOH menu bar (Settings, Enhancements,...)\nCAUTION: " + "This will disable game inputs while the menubar is visible.\n\nD-pad to move between " + "items, A to select, and X to grab focus on the menu bar" + }); #endif - UIWidgets::PaddedEnhancementCheckbox("Show Inputs", "gInputEnabled", true, false); - UIWidgets::Tooltip("Shows currently pressed inputs on the bottom right of the screen"); - UIWidgets::PaddedEnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, - false, true, true, false); - UIWidgets::Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting"); - UIWidgets::PaddedEnhancementSliderInt("Simulated Input Lag: %d frames", "##SimulatedInputLag", - "gSimulatedInputLag", 0, 6, "", 0, true, true, false); - UIWidgets::Tooltip("Buffers your inputs to be executed a specified amount of frames later"); + UIWidgets::CVarCheckbox("Show Inputs", "gInputEnabled", { + .tooltip = "Shows currently pressed inputs on the bottom right of the screen" + }); + UIWidgets::CVarSliderFloat("Input Scale: %.1f", "gInputScale", 1.0f, 3.0f, 1.0f, { + .showButtons = false, + .format = "", + .tooltip = "Sets the on screen size of the displayed inputs from the Show Inputs setting" + }); + UIWidgets::CVarSliderInt("Simulated Input Lag: %d frames", "gSimulatedInputLag", 0, 6, 0, { + .tooltip = "Buffers your inputs to be executed a specified amount of frames later" + }); ImGui::EndMenu(); } - UIWidgets::Spacer(0); - - if (ImGui::BeginMenu("Graphics")) { + if (UIWidgets::BeginMenu("Graphics")) { + /* // #region 2S2H [Todo] None of this works yet #ifndef __APPLE__ if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, "", 1.0f, true)) { @@ -346,240 +214,122 @@ void DrawSettingsMenu() { } UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); + // #endregion */ - static std::unordered_map windowBackendNames = { - { LUS::WindowBackend::DX11, "DirectX" }, - { LUS::WindowBackend::SDL_OPENGL, "OpenGL" }, - { LUS::WindowBackend::SDL_METAL, "Metal" }, - { LUS::WindowBackend::GX2, "GX2" } - }; - - ImGui::Text("Renderer API (Needs reload)"); LUS::WindowBackend runningWindowBackend = LUS::Context::GetInstance()->GetWindow()->GetWindowBackend(); LUS::WindowBackend configWindowBackend; - int configWindowBackendId = LUS::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1); - if (configWindowBackendId != -1 && - configWindowBackendId < static_cast(LUS::WindowBackend::BACKEND_COUNT)) { + int32_t configWindowBackendId = LUS::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1); + if (configWindowBackendId != -1 && configWindowBackendId < static_cast(LUS::WindowBackend::BACKEND_COUNT)) { configWindowBackend = static_cast(configWindowBackendId); } else { configWindowBackend = runningWindowBackend; } - if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) { - UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + auto availableWindowBackends = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends(); + std::unordered_map availableWindowBackendsMap; + for (auto& backend : *availableWindowBackends) { + availableWindowBackendsMap[backend] = windowBackendsMap[backend]; } - if (ImGui::BeginCombo("##RApi", windowBackendNames[configWindowBackend])) { - for (size_t i = 0; i < LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size(); - i++) { - auto backend = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->data()[i]; - if (ImGui::Selectable(windowBackendNames[backend], backend == configWindowBackend)) { - LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast(backend)); - LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", - windowBackendNames[backend]); - LUS::Context::GetInstance()->GetConfig()->Save(); - } - } - ImGui::EndCombo(); - } - if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) { - UIWidgets::ReEnableComponent(""); + + if (UIWidgets::Combobox("Renderer API (Needs reload)", &configWindowBackend, availableWindowBackendsMap, { + .disabled = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1, + .tooltip = "Sets the renderer API used by the game. Requires a relaunch to take effect.", + .disabledTooltip = "Only one renderer API is available on this platform." + })) { + LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast(configWindowBackend)); + LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", windowBackendsMap.at(configWindowBackend)); + LUS::Context::GetInstance()->GetConfig()->Save(); } if (LUS::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) { - UIWidgets::PaddedEnhancementCheckbox("Enable Vsync", "gVsyncEnabled", true, false); + UIWidgets::CVarCheckbox("Enable Vsync", "gVsyncEnabled"); } if (LUS::Context::GetInstance()->GetWindow()->SupportsWindowedFullscreen()) { - UIWidgets::PaddedEnhancementCheckbox("Windowed fullscreen", "gSdlWindowedFullscreen", true, false); + UIWidgets::CVarCheckbox("Windowed fullscreen", "gSdlWindowedFullscreen"); } if (LUS::Context::GetInstance()->GetWindow()->GetGui()->SupportsViewports()) { - UIWidgets::PaddedEnhancementCheckbox("Allow multi-windows", "gEnableMultiViewports", true, false, false, "", - UIWidgets::CheckboxGraphics::Cross, true); - UIWidgets::Tooltip("Allows windows to be able to be dragged off of the main game window. Requires a reload " - "to take effect."); + UIWidgets::CVarCheckbox("Allow multi-windows", "gEnableMultiViewports", { + .tooltip = "Allows multiple windows to be opened at once. Requires a reload to take effect." + }); } - // If more filters are added to LUS, make sure to add them to the filters list here - ImGui::Text("Texture Filter (Needs reload)"); + UIWidgets::CVarCombobox("Texture Filter (Needs reload)", "gTextureFilter", textureFilteringMap); - UIWidgets::EnhancementCombobox("gTextureFilter", filters, FILTER_THREE_POINT); - - UIWidgets::Spacer(0); - - LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->DrawSettings(); + // Currently this only has "Overlays Text Font", it doesn't use our new UIWidgets so it stands out + // LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->DrawSettings(); ImGui::EndMenu(); } - - UIWidgets::Spacer(0); - - if (ImGui::BeginMenu("Languages")) { - UIWidgets::PaddedEnhancementCheckbox("Translate Title Screen", "gTitleScreenTranslation"); - if (UIWidgets::EnhancementRadioButton("English", "gLanguages", LANGUAGE_ENG)) { - // GameInteractor::Instance->ExecuteHooks(); - } - if (UIWidgets::EnhancementRadioButton("German", "gLanguages", LANGUAGE_GER)) { - // GameInteractor::Instance->ExecuteHooks(); - } - // if (UIWidgets::EnhancementRadioButton("French", "gLanguages", LANGUAGE_FRA)) { - // GameInteractor::Instance->ExecuteHooks(); - //} - ImGui::EndMenu(); - } - - UIWidgets::Spacer(0); - - if (ImGui::BeginMenu("Accessibility")) { -#if defined(_WIN32) || defined(__APPLE__) - UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); - UIWidgets::Tooltip("Enables text to speech for in game dialog"); -#endif - UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); - UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); - - ImGui::EndMenu(); - } - - //ImGui::EndMenu(); } extern std::shared_ptr mStatsWindow; extern std::shared_ptr mConsoleWindow; extern std::shared_ptr mGfxDebuggerWindow; extern std::shared_ptr mSaveEditorWindow; -// extern std::shared_ptr mColViewerWindow; -// extern std::shared_ptr mActorViewerWindow; -// extern std::shared_ptr mDLViewerWindow; void DrawDeveloperToolsMenu() { - if (ImGui::BeginMenu("Developer Tools")) { - UIWidgets::EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); - UIWidgets::Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad " - "Right, and open the debug menu with L on the pause screen"); - if (CVarGetInteger("gDebugEnabled", 0)) { - ImGui::Text("Debug Save File Mode:"); - UIWidgets::EnhancementCombobox("gDebugSaveFileMode", DebugSaveFileModes, 1); - UIWidgets::Tooltip("Changes the behaviour of debug file select creation (creating a save file on slot 1 " - "with debug mode on)\n" - "- Off: The debug save file will be a normal savefile\n" - "- Vanilla: The debug save file will be the debug save file from the original game\n" - "- Maxed: The debug save file will be a save file with all of the items & upgrades"); - } - UIWidgets::PaddedEnhancementCheckbox("OoT Skulltula Debug", "gSkulltulaDebugEnabled", true, false); - UIWidgets::Tooltip("Enables Skulltula Debug, when moving the cursor in the menu above various map icons (boss " - "key, compass, map screen locations, etc) will set the GS bits in that area.\nUSE WITH " - "CAUTION AS IT DOES NOT UPDATE THE GS COUNT."); - UIWidgets::PaddedEnhancementCheckbox("Fast File Select", "gSkipLogoTitle", true, false); - UIWidgets::Tooltip( - "Load the game to the selected menu or file\n\"Zelda Map Select\" require debug mode else you will " - "fallback to File choose menu\nUsing a file number that don't have save will create a save file only if " - "you toggle on \"Create a new save if none ?\" else it will bring you to the File choose menu"); - if (CVarGetInteger("gSkipLogoTitle", 0)) { - ImGui::Text("Loading:"); - UIWidgets::EnhancementCombobox("gSaveFileID", FastFileSelect, 0); - }; - UIWidgets::PaddedEnhancementCheckbox("Better Debug Warp Screen", "gBetterDebugWarpScreen", true, false); - UIWidgets::Tooltip("Optimized debug warp screen, with the added ability to chose entrances and time of day"); - UIWidgets::PaddedEnhancementCheckbox("Debug Warp Screen Translation", "gDebugWarpScreenTranslation", true, - false, false, "", UIWidgets::CheckboxGraphics::Cross, true); - UIWidgets::Tooltip("Translate the Debug Warp Screen based on the game language"); + if (UIWidgets::BeginMenu("Developer Tools", UIWidgets::Colors::Yellow)) { + UIWidgets::CVarCheckbox("OoT Debug Mode", "gDebugEnabled", { + .tooltip = "Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad " + "Right, and open the debug menu with L on the pause screen" + }); + UIWidgets::CVarCheckbox("No Clip", "gDeveloperTools.NoClip"); if (gPlayState != NULL) { UIWidgets::PaddedSeparator(); - ImGui::Checkbox("Frame Advance##frameAdvance", (bool*)&gPlayState->frameAdvCtx.enabled); - UIWidgets::Tooltip("This allows you to advance through the game one frame at a time on command. " - "To advance a frame, hold Z and tap R on the second controller. Holding Z " - "and R will advance a frame every half second. You can also use the buttons below."); + UIWidgets::Checkbox("Frame Advance", (bool*)&gPlayState->frameAdvCtx.enabled, { + .tooltip = "This allows you to advance through the game one frame at a time on command. " + "To advance a frame, hold Z and tap R on the second controller. Holding Z " + "and R will advance a frame every half second. You can also use the buttons below." + }); if (gPlayState->frameAdvCtx.enabled) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0,0)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); - if (ImGui::Button("Advance 1", ImVec2(90.0f, 0.0f))) { + if (UIWidgets::Button("Advance 1", { .size = UIWidgets::Sizes::Inline })) { CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); } ImGui::SameLine(); - ImGui::Button("Advance (Hold)"); + UIWidgets::Button("Advance (Hold)", { .size = UIWidgets::Sizes::Inline }); if (ImGui::IsItemActive()) { CVarSetInteger("gDeveloperTools.FrameAdvanceTick", 1); } - ImGui::PopStyleVar(3); - ImGui::PopStyleColor(1); } } UIWidgets::PaddedSeparator(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); - ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); if (mStatsWindow) { - if (ImGui::Button(GetWindowButtonText("Stats", CVarGetInteger("gStatsEnabled", 0)).c_str(), - ImVec2(-1.0f, 0.0f))) { - mStatsWindow->ToggleVisibility(); - } - UIWidgets::Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on"); + UIWidgets::WindowButton("Stats", "gWindows.Stats", mStatsWindow, { + .tooltip = "Shows the stats window, with your FPS and frametimes, and the OS you're playing on" + }); } - UIWidgets::Spacer(0); if (mConsoleWindow) { - if (ImGui::Button(GetWindowButtonText("Console", CVarGetInteger("gConsoleEnabled", 0)).c_str(), - ImVec2(-1.0f, 0.0f))) { - mConsoleWindow->ToggleVisibility(); - } - UIWidgets::Tooltip( - "Enables the console window, allowing you to input commands, type help for some examples"); + UIWidgets::WindowButton("Console", "gWindows.Console", mConsoleWindow, { + .tooltip = "Enables the console window, allowing you to input commands, type help for some examples" + }); } - UIWidgets::Spacer(0); if (mGfxDebuggerWindow) { - if (ImGui::Button(GetWindowButtonText("Gfx Debugger", CVarGetInteger("gGfxDebuggerEnabled", 0)).c_str(), - ImVec2(-1.0f, 0.0f))) { - mGfxDebuggerWindow->ToggleVisibility(); - } - UIWidgets::Tooltip( - "Enables the Gfx Debugger window, allowing you to input commands, type help for some examples"); + UIWidgets::WindowButton("Gfx Debugger", "gWindows.GfxDebugger", mGfxDebuggerWindow, { + .tooltip = "Enables the Gfx Debugger window, allowing you to input commands, type help for some examples" + }); } - UIWidgets::Spacer(0); - if (mSaveEditorWindow) { - if (ImGui::Button(GetWindowButtonText("Save Editor", CVarGetInteger("gSaveEditorEnabled", 0)).c_str(), ImVec2(-1.0f, 0.0f))) { - mSaveEditorWindow->ToggleVisibility(); - } + UIWidgets::WindowButton("Save Editor", "gWindows.SaveEditor", mSaveEditorWindow, { + .tooltip = "Enables the Save Editor window, allowing you to edit your save file" + }); } - // UIWidgets::Spacer(0); - // if (mColViewerWindow) { - // if (ImGui::Button(GetWindowButtonText("Collision Viewer", CVarGetInteger("gCollisionViewerEnabled", - // 0)).c_str(), ImVec2(-1.0f, 0.0f))) { - // //mColViewerWindow->ToggleVisibility(); - // } - // } - // UIWidgets::Spacer(0); - // if (mActorViewerWindow) { - // if (ImGui::Button(GetWindowButtonText("Actor Viewer", CVarGetInteger("gActorViewerEnabled", 0)).c_str(), - // ImVec2(-1.0f, 0.0f))) { - // //mActorViewerWindow->ToggleVisibility(); - // } - // } - // UIWidgets::Spacer(0); - // if (mDLViewerWindow) { - // if (ImGui::Button(GetWindowButtonText("Display List Viewer", CVarGetInteger("gDLViewerEnabled", - // 0)).c_str(), ImVec2(-1.0f, 0.0f))) { - // //mDLViewerWindow->ToggleVisibility(); - // } - // } - - ImGui::PopStyleVar(3); - ImGui::PopStyleColor(1); - ImGui::EndMenu(); } } -void SohMenuBar::DrawElement() { +void BenMenuBar::DrawElement() { if (ImGui::BeginMenuBar()) { static ImVec2 sWindowPadding(8.0f, 8.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, sWindowPadding); ImGui::SetCursorPosY(0.0f); + + DrawBenMenu(); + + ImGui::SetCursorPosY(0.0f); + DrawSettingsMenu(); ImGui::SetCursorPosY(0.0f); @@ -593,4 +343,4 @@ void SohMenuBar::DrawElement() { } } } - // namespace SohGui \ No newline at end of file + // namespace BenGui \ No newline at end of file diff --git a/mm/2s2h/BenMenuBar.h b/mm/2s2h/BenMenuBar.h index 3d0759943..a36d5308e 100644 --- a/mm/2s2h/BenMenuBar.h +++ b/mm/2s2h/BenMenuBar.h @@ -1,12 +1,12 @@ -#pragma once +#ifndef BenMenuBar_h +#define BenMenuBar_h -//#include #include "window/gui/GuiMenuBar.h" #include "window/gui/GuiElement.h" #include "DeveloperTools/SaveEditor.h" -namespace SohGui { -class SohMenuBar : public LUS::GuiMenuBar { +namespace BenGui { +class BenMenuBar : public LUS::GuiMenuBar { public: using LUS::GuiMenuBar::GuiMenuBar; protected: @@ -14,4 +14,6 @@ class SohMenuBar : public LUS::GuiMenuBar { void InitElement() override {}; void UpdateElement() override {}; }; -} // namespace SohGui \ No newline at end of file +} // namespace BenGui + +#endif // BenMenuBar_h \ No newline at end of file diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp index 38991c254..1c03aa311 100644 --- a/mm/2s2h/BenPort.cpp +++ b/mm/2s2h/BenPort.cpp @@ -50,7 +50,7 @@ CrowdControl* CrowdControl::Instance; #endif #include -#include +#include #include "Enhancements/controls/SohInputEditorWindow.h" @@ -299,7 +299,7 @@ extern "C" void InitOTR() { #endif OTRGlobals::Instance = new OTRGlobals(); - SohGui::SetupGuiElements(); + BenGui::SetupGuiElements(); clearMtx = (uintptr_t)&gMtxClear; //OTRMessage_Init(); @@ -340,7 +340,7 @@ extern "C" void DeinitOTR() { // Destroying gui here because we have shared ptrs to LUS objects which output to SPDLOG which is destroyed before // these shared ptrs. - //SohGui::Destroy(); + //BenGui::Destroy(); OTRGlobals::Instance->context = nullptr; } diff --git a/mm/2s2h/UIWidgets.cpp b/mm/2s2h/UIWidgets.cpp index b3810e6e6..0bec31fee 100644 --- a/mm/2s2h/UIWidgets.cpp +++ b/mm/2s2h/UIWidgets.cpp @@ -10,6 +10,8 @@ #define IMGUI_DEFINE_MATH_OPERATORS #include #include +#include +#include #include //#include "soh/Enhancements/cosmetics/CosmeticsEditor.h" @@ -733,6 +735,7 @@ namespace UIWidgets { bool BeginMenu(const char* label, const ImVec4& color) { bool dirty = false; PushStyleMenu(color); + ImGui::SetNextWindowSizeConstraints(ImVec2(200.0f, 0.0f), ImVec2(FLT_MAX, FLT_MAX)); if (ImGui::BeginMenu(label)) { dirty = true; } @@ -906,89 +909,6 @@ namespace UIWidgets { ImGui::PopStyleColor(9); } - bool Combobox(const char* label, uint8_t* value, std::span comboArray, const ComboboxOptions& options) { - bool dirty = false; - float startX = ImGui::GetCursorPosX(); - std::string invisibleLabelStr = "##" + std::string(label); - const char* invisibleLabel = invisibleLabelStr.c_str(); - ImGui::PushID(label); - ImGui::BeginGroup(); - ImGui::BeginDisabled(options.disabled); - PushStyleCombobox(options.color); - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Above) { - ImGui::Text(label); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } else if (options.labelPosition == LabelPosition::Near) { - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().ItemSpacing.x * 2); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { - ImGui::SetNextItemWidth(ImGui::CalcTextSize(comboArray[*value]).x + ImGui::GetStyle().FramePadding.x * 4 + ImGui::GetStyle().ItemSpacing.x); - } - } else if (options.alignment == ComponentAlignment::Right) { - if (options.labelPosition == LabelPosition::Above) { - ImGui::NewLine(); - ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); - ImGui::Text(label); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } else if (options.labelPosition == LabelPosition::Near) { - ImGui::SameLine(ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x * 2); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { - float width = ImGui::CalcTextSize(comboArray[*value]).x + ImGui::GetStyle().FramePadding.x * 4; - ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - } - } - if (ImGui::BeginCombo(invisibleLabel, comboArray[*value], options.flags)) { - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f)); - for (uint8_t i = 0; i < comboArray.size(); i++) { - if (strlen(comboArray[i]) > 1) { - if (ImGui::Selectable(comboArray[i], i == *value)) { - *value = i; - dirty = true; - } - } - } - ImGui::PopStyleVar(); - ImGui::EndCombo(); - } - if (options.alignment == ComponentAlignment::Left) { - if (options.labelPosition == LabelPosition::Near) { - ImGui::SameLine(); - ImGui::Text(label); - } else if (options.labelPosition == LabelPosition::Far) { - ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); - ImGui::Text(label); - } - } else if (options.alignment == ComponentAlignment::Right) { - if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { - ImGui::SameLine(startX); - ImGui::Text(label); - } - } - PopStyleCombobox(); - ImGui::EndDisabled(); - ImGui::EndGroup(); - if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { - ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); - } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { - ImGui::SetTooltip("%s", WrappedText(options.tooltip)); - } - ImGui::PopID(); - return dirty; - } - - bool CVarCombobox(const char* label, const char* cvarName, std::span comboArray, const ComboboxOptions& options) { - bool dirty = false; - uint8_t value = (uint8_t)CVarGetInteger(cvarName, options.defaultIndex); - if (Combobox(label, &value, comboArray, options)) { - CVarSetInteger(cvarName, value); - LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); - dirty = true; - } - return dirty; - } - void PushStyleSlider(const ImVec4& color) { ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(color.x, color.y, color.z, 1.0f)); diff --git a/mm/2s2h/UIWidgets.hpp b/mm/2s2h/UIWidgets.hpp index 6015dcd3b..524a5d373 100644 --- a/mm/2s2h/UIWidgets.hpp +++ b/mm/2s2h/UIWidgets.hpp @@ -15,6 +15,7 @@ #define IMGUI_DEFINE_MATH_OPERATORS #include #include +#include namespace UIWidgets { @@ -181,8 +182,268 @@ namespace UIWidgets { void PushStyleCombobox(const ImVec4& color = Colors::Indigo); void PopStyleCombobox(); - bool Combobox(const char* label, uint8_t* value, std::span comboArray, const ComboboxOptions& options = {}); - bool CVarCombobox(const char* label, const char* cvarName, std::span comboArray, const ComboboxOptions& options = {}); + + template + bool Combobox(const char* label, T* value, const std::unordered_map& comboMap, const ComboboxOptions& options = {}) { + bool dirty = false; + float startX = ImGui::GetCursorPosX(); + std::string invisibleLabelStr = "##" + std::string(label); + const char* invisibleLabel = invisibleLabelStr.c_str(); + ImGui::PushID(label); + ImGui::BeginGroup(); + ImGui::BeginDisabled(options.disabled); + PushStyleCombobox(options.color); + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().ItemSpacing.x * 2); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + ImGui::SetNextItemWidth(ImGui::CalcTextSize(comboMap.at(*value)).x + ImGui::GetStyle().FramePadding.x * 4 + ImGui::GetStyle().ItemSpacing.x); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::NewLine(); + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x * 2); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + float width = ImGui::CalcTextSize(comboMap.at(*value)).x + ImGui::GetStyle().FramePadding.x * 4; + ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } + } + if (ImGui::BeginCombo(invisibleLabel, comboMap.at(*value), options.flags)) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f)); + for (const auto& pair : comboMap) { + if (strlen(pair.second) > 1) { + if (ImGui::Selectable(pair.second, pair.first == *value)) { + *value = pair.first; + dirty = true; + } + } + } + ImGui::PopStyleVar(); + ImGui::EndCombo(); + } + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(); + ImGui::Text(label); + } else if (options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(startX); + ImGui::Text(label); + } + } + PopStyleCombobox(); + ImGui::EndDisabled(); + ImGui::EndGroup(); + if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); + } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.tooltip)); + } + ImGui::PopID(); + return dirty; + } + + template + bool Combobox(const char* label, T* value, const std::vector& comboVector, const ComboboxOptions& options = {}) { + bool dirty = false; + float startX = ImGui::GetCursorPosX(); + size_t currentValueIndex = static_cast(*value); + std::string invisibleLabelStr = "##" + std::string(label); + const char* invisibleLabel = invisibleLabelStr.c_str(); + ImGui::PushID(label); + ImGui::BeginGroup(); + ImGui::BeginDisabled(options.disabled); + PushStyleCombobox(options.color); + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().ItemSpacing.x * 2); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + ImGui::SetNextItemWidth(ImGui::CalcTextSize(comboVector.at(currentValueIndex)).x + ImGui::GetStyle().FramePadding.x * 4 + ImGui::GetStyle().ItemSpacing.x); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::NewLine(); + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x * 2); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + float width = ImGui::CalcTextSize(comboVector.at(currentValueIndex)).x + ImGui::GetStyle().FramePadding.x * 4; + ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } + } + if (ImGui::BeginCombo(invisibleLabel, comboVector.at(currentValueIndex), options.flags)) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f)); + for (size_t i = 0; i < comboVector.size(); ++i) { + auto newValue = static_cast(i); + if (strlen(comboVector.at(i)) > 1) { + if (ImGui::Selectable(comboVector.at(i), newValue == *value)) { + *value = newValue; + dirty = true; + } + } + } + ImGui::PopStyleVar(); + ImGui::EndCombo(); + } + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(); + ImGui::Text(label); + } else if (options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(startX); + ImGui::Text(label); + } + } + PopStyleCombobox(); + ImGui::EndDisabled(); + ImGui::EndGroup(); + if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); + } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.tooltip)); + } + ImGui::PopID(); + return dirty; + } + + template + bool Combobox(const char* label, T* value, const char* (&comboArray)[N], const ComboboxOptions& options = {}) { + bool dirty = false; + float startX = ImGui::GetCursorPosX(); + size_t currentValueIndex = static_cast(*value); + if (currentValueIndex >= N) { + currentValueIndex = 0; + } + std::string invisibleLabelStr = "##" + std::string(label); + const char* invisibleLabel = invisibleLabelStr.c_str(); + ImGui::PushID(label); + ImGui::BeginGroup(); + ImGui::BeginDisabled(options.disabled); + PushStyleCombobox(options.color); + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().ItemSpacing.x * 2); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + ImGui::SetNextItemWidth(ImGui::CalcTextSize(comboArray[currentValueIndex]).x + ImGui::GetStyle().FramePadding.x * 4 + ImGui::GetStyle().ItemSpacing.x); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::NewLine(); + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x * 2); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + float width = ImGui::CalcTextSize(comboArray[currentValueIndex]).x + ImGui::GetStyle().FramePadding.x * 4; + ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } + } + if (ImGui::BeginCombo(invisibleLabel, comboArray[currentValueIndex], options.flags)) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f)); + for (size_t i = 0; i < N; ++i) { + auto newValue = static_cast(i); + if (strlen(comboArray[i]) > 1) { + if (ImGui::Selectable(comboArray[i], newValue == *value)) { + *value = newValue; + dirty = true; + } + } + } + ImGui::PopStyleVar(); + ImGui::EndCombo(); + } + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(); + ImGui::Text(label); + } else if (options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(startX); + ImGui::Text(label); + } + } + PopStyleCombobox(); + ImGui::EndDisabled(); + ImGui::EndGroup(); + if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); + } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.tooltip)); + } + ImGui::PopID(); + return dirty; + } + + template + bool CVarCombobox(const char* label, const char* cvarName, const std::unordered_map& comboMap, const ComboboxOptions& options = {}) { + bool dirty = false; + int32_t value = CVarGetInteger(cvarName, options.defaultIndex); + if (Combobox(label, &value, comboMap, options)) { + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + return dirty; + } + + template + bool CVarCombobox(const char* label, const char* cvarName, const std::vector& comboVector, const ComboboxOptions& options = {}) { + bool dirty = false; + int32_t value = CVarGetInteger(cvarName, options.defaultIndex); + if (Combobox(label, &value, comboVector, options)) { + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + return dirty; + } + + template + bool CVarCombobox(const char* label, const char* cvarName, const char* (&comboArray)[N], const ComboboxOptions& options = {}) { + bool dirty = false; + int32_t value = CVarGetInteger(cvarName, options.defaultIndex); + if (Combobox(label, &value, comboArray, options)) { + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + return dirty; + } struct IntSliderOptions { const ImVec4 color = Colors::Gray;