Modern Menu (#5116)

* Add menu files, hook menu up to window system.
Temporarily rename new menu's UIWidgets to UIWidgets2 to allow both menu systems to coexist temporarily.

* Finish implementing new menu.
Rename 2ship UIWidgets to UIWidgets2 to complete facilitation of both menus working for now.

* More preliminary setup

* More prepwork, begin on settings options

* Finish settings, add enhancements windows

* Fix search function not looking past first columns.

* Add dev tool windows

* Finish dev tools

* Add about window

* Fully replace about window

* Remove moved menu items from menubar, add more windows to new menu

* Implement WindowButtonOptions.
Add ability to not embed popout windows when not popped out.
Add ability to hide the button for WindowButtons.
Fix Entrance Tracker from showing when not enabled.

* Fix entrance tracker settings embedded display.
Fix entrance tracker settings window original size declaration.

* Initial implementation of themed radio button widget.

* Move "About" section to second column of general.
Fix sidebar sections starting in second column.

* Restore Entrance Tracker `Draw()` to allow for custom styling.

* Fix combobox positioning formatting.
Fix color picker end spacing.
Convert everything in check tracker settings to UIWidgets2 (except color pickers and section headers).
Make all tracker windows not embed.

* Minor cleanup

* Fix main volume defaults & mirror jitter fix removal on dev

* Improve color picker with RGB/RGBA options. Not finished.

* Finish creating CVarColorPicker and implement for Check Tracker background color.
Fix tracker and network prefixes.

* Finish check tracker settings and convert check tracker.

* Port all Cheats menu except for Beta Quest

* Port over Beta Quest to new menu

* Remove old cheats menu

* Port cutscene skips to modern menu

* Port Timesaver Enhancements to new menu

* Port the Items and Item Count Messages submenu

* Port Difficulty Options to new Menu

* Removes options that have been ported thus far.

* Port "Reduced Clutter" options to new menu

* Add forgotten callbacks to Hyper Enemies/Bosses

* Copy StateButton to UIWidgets2, and implement custom padding for them in the tracker.

* Ports some pause menu related settinga

* Change tracker window active title color.
Make state buttons smaller in tracker to get more info on screen.

* Convert window title active theming to all windows.

* Port the rest of Enhancements->Gameplay to new menu

* Port the "Graphics" Enhancements to new menu

* Ports Fixes over to the Modern Menu

* Ported Restorations to Modern Menu

* Ported Extra Modes to new menu

* Port Autosave and Boot Sequence to modern menu

* Cleans up some leftover data for ported buttons

* Ports Enhancement Presets to new menu

* Port Additional timers to new menu. Removes Enhancements from old menu

* Cleans up some unused stuff

* Ports Randomizer Enhancements to modern menu

* Convert Item Tracker Settings. Something's wrong with the comboboxes in a second column of a table.

* Fix combobox alignment and label position calculations.

* Convert Entrance Tracker window.

* Save Editor Info tab finished.
Added `PushStyleInput` and `PushStyleTabs` for Info tab.
Fixed some indentation in entrance tracker source.
Added font push to tracker windows.

* Increase size of all icons in save editor.

* Convert flag groups to child windows for automatic sizing and border drawing.

* Flags tab completed.
Finished inventory tab.

* Convert save editor help hover to UIWidgets2.

* Various fixes and corrections

* Start cosmetics editor, fix theme colors not updating

* Cosmetics editor conversion progress

* Remove Mac internal resolution restrictions.

* Copy over advanced resolution partial and enable most options as a custom widget.

* Add size to float sliders, more cosmetics editor progress

* Fix incorrect cvar for notifications

* Radio button & header color options, more cosmetics editor progress

* Finish cosmetics editor conversion

* Create and apply THEME_COLOR macro. Resides in SohGui for easy access to mSohMenu.

* Move ResolutionEditor to SohGui directory.

* Add labels to build info.
Fix slider width calculations.

* Fix some advanced resolution widget hiding.

* Fully implement Advanced Resolution options.
Fix graphics settings formatting.
Improve slider label position calculations.
Implement Clamp options on sliders.

* Finish save editor.
Convert save editor code to `using namespace UIWidgets2`.
Fix search crashing on time splits window.
Remove `SetLastItemHoverText` from `UIWidgets2`.

* Unify cvar sectioning in time splits.

* Add InputString and InputInt widgets, and corresponding CVar Widgets

* Adds Widget Type for Inputs, not currently used.

* Convert Sail to modern menu

* Add Combobox that takes a vector of std::strings

* Convert checkbox and combobx to new widgets

* Add Tristate checkbox

* Convert sliders and tristate checkboxes

* Convert top half of Rando window

* remove/replace remainder of UIWidgets usage in option.cpp

* Converts tricks, locations, and removes old UIWidgets refs

* Fix windows build errors

* Remove Tri-State checkboxes

* Use PushStyleInput instead of PushStyleSlider

lol oops didn't realize it was a thing in Ship.

* Rebase and address review comments

* Convert Crowd Control to modern menu.

* Fix build error

* Audio editor progress

* Re-add CVar SaveOnNextFrame calls to Resolution Editor.
Remove old Resolution Editor files.

* Convert TimeSplits to new menu.
Fix a few enum warnings.

* Decrease padding on Arrow Buttons

* Audio editor + gameplay stats done

* Give Randomizer Menu more screen real-estate

* Port plandomizer menu

* Fix slider width calculation and allow combobox LabelPosition::None

* Fix None labelPos and slider width for inline labels

* Fix all slider value label insertions.
Convert Collision Viewer.

* Minor Collision Viewer enum change.
Convert Actor Viewer.

* Theme/convert Message Viewer.

* Add font to Message Viewer.
Theme Value Viewer.

* DL Viewer and SohModals themed.

* Convert Input Viewer.

* Missed some color settings in Input Viewer.
Removed UIWidgets references from Controller Config, and restored SoH version.

* Remove UIWidgets.hpp include from multiple files.

* Completely remove old UIWidgets.
Rename UIWidgets2 to UIWidgets.
Move Accessibility and Language options to new menu.

* Fix Gfx Debugger not showing up.
Remove menubar registration.

* Fix clearCvars references.

* Fix passing std::string to const char* argument.

* enum name spacing

---------

Co-authored-by: aMannus <mannusmenting@gmail.com>
Co-authored-by: Christopher Leggett <chris@leggett.dev>
This commit is contained in:
Malkierian 2025-03-15 16:11:30 -07:00 committed by GitHub
commit 7e392e63a8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
70 changed files with 9652 additions and 5777 deletions

View file

@ -53,7 +53,10 @@ execute_process(
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(CMAKE_PROJECT_GIT_COMMIT_HASH "${GIT_COMMIT_HASH}" CACHE STRING "Git commit hash" FORCE)
# Get only the first 7 characters of the hash
string(SUBSTRING "${GIT_COMMIT_HASH}" 0 7 SHORT_COMMIT_HASH)
set(CMAKE_PROJECT_GIT_COMMIT_HASH "${SHORT_COMMIT_HASH}" CACHE STRING "Git commit hash" FORCE)
execute_process(
COMMAND git describe --tags --abbrev=0 --exact-match HEAD

Binary file not shown.

Binary file not shown.

View file

@ -45,12 +45,12 @@ extern "C"
extern OSViContext* __osViNext;
extern OSViMode osViModeFpalLan1;
extern u32 __additional_scanline;
extern u8 gBuildVersion[];
extern const char gBuildVersion[];
extern u16 gBuildVersionMajor;
extern u16 gBuildVersionMinor;
extern u16 gBuildVersionPatch;
extern u8 gGitBranch[];
extern u8 gGitCommitHash[];
extern const char gGitBranch[];
extern const char gGitCommitHash[];
extern u8 gGitCommitTag[];
extern u8 gBuildTeam[];
extern u8 gBuildDate[];

View file

@ -1,103 +0,0 @@
#include "AboutWindow.h"
#include <imgui.h>
#include <soh/GameVersions.h>
#include "soh/ResourceManagerHelpers.h"
extern "C" {
#include "variables.h"
}
AboutWindow::~AboutWindow() {
SPDLOG_TRACE("destruct about window");
}
void AboutWindow::InitElement() {
mIsTaggedVersion = gGitCommitTag[0] != 0;
strncpy(mGitCommitHashTruncated, (char*)gGitCommitHash, 7);
mGitCommitHashTruncated[7] = 0;
}
void AboutWindow::Draw() {
if (!IsVisible()) {
return;
}
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoDocking |
ImGuiWindowFlags_NoScrollWithMouse |
ImGuiWindowFlags_NoScrollbar;
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(16 * ImGui::GetIO().FontGlobalScale, 8 * ImGui::GetIO().FontGlobalScale));
if (!ImGui::Begin(GetName().c_str(), &mIsVisible, windowFlags)) {
ImGui::End();
} else {
DrawElement();
ImGui::End();
}
ImGui::PopStyleVar();
// Sync up the IsVisible flag if it was changed by ImGui
SyncVisibilityConsoleVariable();
}
const char* AboutWindow::GetGameVersionString(uint32_t index) {
uint32_t gameVersion = ResourceMgr_GetGameVersion(index);
switch (gameVersion) {
case OOT_NTSC_US_10:
return "NTSC-U 1.0";
case OOT_NTSC_US_11:
return "NTSC-U 1.1";
case OOT_NTSC_US_12:
return "NTSC-U 1.2";
case OOT_PAL_10:
return "PAL 1.0";
case OOT_PAL_11:
return "PAL 1.1";
case OOT_PAL_GC:
return "PAL GC";
case OOT_PAL_MQ:
return "PAL MQ";
case OOT_PAL_GC_DBG1:
case OOT_PAL_GC_DBG2:
return "PAL GC-D";
case OOT_PAL_GC_MQ_DBG:
return "PAL MQ-D";
case OOT_IQUE_CN:
return "IQUE CN";
case OOT_IQUE_TW:
return "IQUE TW";
default:
return "UNKNOWN";
}
}
void AboutWindow::DrawElement() {
// The icon is already padded - adjust for that
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
cursorPos.x -= 16 * ImGui::GetIO().FontGlobalScale;
ImGui::SetCursorScreenPos(cursorPos);
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon"), ImVec2(64.0f * ImGui::GetIO().FontGlobalScale, 64.0f * ImGui::GetIO().FontGlobalScale));
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Text("Ship of Harkinian");
if (mIsTaggedVersion) {
ImGui::Text("%s", gBuildVersion);
} else {
ImGui::Text("%s", gGitBranch);
ImGui::Text("%s", mGitCommitHashTruncated);
}
ImGui::EndGroup();
ImGui::Dummy(ImVec2(0, 2 * ImGui::GetIO().FontGlobalScale));
ImGui::Text("Game Archives:");
for (uint32_t i = 0; i < ResourceMgr_GetNumGameVersions(); i++) {
ImGui::BulletText(GetGameVersionString(i));
}
}

View file

@ -1,20 +0,0 @@
#pragma once
#include <libultraship/libultraship.h>
class AboutWindow : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
~AboutWindow();
private:
void InitElement() override;
void Draw() override;
void DrawElement() override;
void UpdateElement() override {};
const char* GetGameVersionString(uint32_t index);
bool mIsTaggedVersion;
char mGitCommitHashTruncated[8];
};

View file

@ -13,20 +13,20 @@ class TimeDisplayWindow : public Ship::GuiWindow {
void TimeDisplayUpdateDisplayOptions();
void TimeDisplayInitSettings();
typedef enum {
typedef enum TimerDisplay {
DISPLAY_IN_GAME_TIMER,
DISPLAY_TIME_OF_DAY,
DISPLAY_CONDITIONAL_TIMER,
DISPLAY_NAVI_TIMER
};
} TimerDisplay;
typedef enum {
typedef enum NaviTimerValues {
NAVI_PREPARE = 600,
NAVI_ACTIVE = 3000,
NAVI_COOLDOWN = 25800,
DAY_BEGINS = 17759,
NIGHT_BEGINS = 49155
};
} NaviTimerValues;
typedef struct {
uint32_t timeID;

View file

@ -12,6 +12,7 @@
#include "soh/cvar_prefixes.h"
#include <utils/StringHelper.h>
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "AudioCollection.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
@ -165,13 +166,20 @@ void DrawPreviewButton(uint16_t sequenceId, std::string sfxKey, SeqType sequence
const std::string previewButton = ICON_FA_PLAY + hiddenKey;
if (CVarGetInteger(CVAR_AUDIO("Playing"), 0) == sequenceId) {
if (ImGui::Button(stopButton.c_str())) {
if (UIWidgets::Button(stopButton.c_str(), UIWidgets::ButtonOptions()
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(10.0f, 6.0f))
.Tooltip("Stop Preview")
.Color(THEME_COLOR))) {
func_800F5C2C();
CVarSetInteger(CVAR_AUDIO("Playing"), 0);
}
UIWidgets::Tooltip("Stop Preview");
} else {
if (ImGui::Button(previewButton.c_str())) {
if (UIWidgets::Button(previewButton.c_str(), UIWidgets::ButtonOptions()
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(10.0f, 6.0f))
.Tooltip("Play Preview")
.Color(THEME_COLOR))) {
if (CVarGetInteger(CVAR_AUDIO("Playing"), 0) != 0) {
func_800F5C2C();
CVarSetInteger(CVAR_AUDIO("Playing"), 0);
@ -188,11 +196,10 @@ void DrawPreviewButton(uint16_t sequenceId, std::string sfxKey, SeqType sequence
}
}
}
UIWidgets::Tooltip("Play Preview");
}
}
void Draw_SfxTab(const std::string& tabId, SeqType type) {
void Draw_SfxTab(const std::string& tabId, SeqType type, const std::string& tabName) {
const std::map<u16, SequenceInfo>& map = AudioCollection::Instance->GetAllSequences();
const std::string hiddenTabId = "##" + tabId;
@ -200,7 +207,10 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
const std::string randomizeAllButton = "Randomize All" + hiddenTabId;
const std::string lockAllButton = "Lock All" + hiddenTabId;
const std::string unlockAllButton = "Unlock All" + hiddenTabId;
if (ImGui::Button(resetAllButton.c_str())) {
ImGui::SeparatorText(tabName.c_str());
if (UIWidgets::Button(resetAllButton.c_str(),
UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR))) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
ResetGroup(map, type);
@ -211,7 +221,8 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
}
}
ImGui::SameLine();
if (ImGui::Button(randomizeAllButton.c_str())) {
if (UIWidgets::Button(randomizeAllButton.c_str(),
UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR))) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
RandomizeGroup(type);
@ -222,7 +233,8 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
}
}
ImGui::SameLine();
if (ImGui::Button(lockAllButton.c_str())) {
if (UIWidgets::Button(lockAllButton.c_str(),
UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR))) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
LockGroup(map, type);
@ -233,7 +245,8 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
}
}
ImGui::SameLine();
if (ImGui::Button(unlockAllButton.c_str())) {
if (UIWidgets::Button(unlockAllButton.c_str(),
UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR))) {
auto currentBGM = func_800FA0B4(SEQ_PLAYER_BGM_MAIN);
auto prevReplacement = AudioCollection::Instance->GetReplacementSequence(currentBGM);
UnlockGroup(map, type);
@ -244,10 +257,12 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
}
}
// Longest text in Audio Editor
ImVec2 columnSize = ImGui::CalcTextSize("Navi - Look/Hey/Watchout (Target Enemy)");
ImGui::BeginTable(tabId.c_str(), 3, ImGuiTableFlags_SizingFixedFit);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, columnSize.x + 30);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, columnSize.x + 30);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 160.0f);
for (const auto& [defaultValue, seqData] : map) {
if (~(seqData.category) & type) {
continue;
@ -273,6 +288,7 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
ImGui::TableNextColumn();
ImGui::PushItemWidth(-FLT_MIN);
const int initialValue = map.contains(currentValue) ? currentValue : defaultValue;
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo(hiddenKey.c_str(), map.at(initialValue).label.c_str())) {
for (const auto& [value, seqData] : map) {
// If excluded as a replacement sequence, don't show in other dropdowns except the effect's own dropdown.
@ -293,22 +309,30 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
ImGui::EndCombo();
}
UIWidgets::PopStyleCombobox();
ImGui::TableNextColumn();
ImGui::PushItemWidth(-FLT_MIN);
DrawPreviewButton((type == SEQ_SFX || type == SEQ_VOICE || type == SEQ_INSTRUMENT) ? defaultValue : currentValue, seqData.sfxKey, type);
auto locked = CVarGetInteger(cvarLockKey.c_str(), 0) == 1;
ImGui::SameLine();
ImGui::PushItemWidth(-FLT_MIN);
if (ImGui::Button(resetButton.c_str())) {
if (UIWidgets::Button(resetButton.c_str(), UIWidgets::ButtonOptions()
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(10.0f, 6.0f))
.Tooltip("Reset to default")
.Color(THEME_COLOR))) {
CVarClear(cvarKey.c_str());
CVarClear(cvarLockKey.c_str());
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
UpdateCurrentBGM(defaultValue, seqData.category);
}
UIWidgets::Tooltip("Reset to default");
ImGui::SameLine();
ImGui::PushItemWidth(-FLT_MIN);
if (ImGui::Button(randomizeButton.c_str())) {
if (UIWidgets::Button(randomizeButton.c_str(), UIWidgets::ButtonOptions()
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(10.0f, 6.0f))
.Tooltip("Randomize this sound")
.Color(THEME_COLOR))) {
std::vector<SequenceInfo*> validSequences = {};
for (const auto seqInfo : AudioCollection::Instance->GetIncludedSequences()) {
if (seqInfo->category & type) {
@ -327,10 +351,14 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
UpdateCurrentBGM(defaultValue, type);
}
}
UIWidgets::Tooltip("Randomize this sound");
ImGui::SameLine();
ImGui::PushItemWidth(-FLT_MIN);
if (ImGui::Button(locked ? lockedButton.c_str() : unlockedButton.c_str())) {
if (UIWidgets::Button(locked ? lockedButton.c_str() : unlockedButton.c_str(),
UIWidgets::ButtonOptions()
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(10.0f, 6.0f))
.Tooltip(locked ? "Sound locked" : "Sound unlocked")
.Color(THEME_COLOR))) {
if (locked) {
CVarClear(cvarLockKey.c_str());
} else {
@ -338,7 +366,6 @@ void Draw_SfxTab(const std::string& tabId, SeqType type) {
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
UIWidgets::Tooltip(locked ? "Sound locked" : "Sound unlocked");
}
ImGui::EndTable();
}
@ -401,10 +428,11 @@ ImVec4 GetSequenceTypeColor(SeqType type) {
}
}
void DrawTypeChip(SeqType type) {
void DrawTypeChip(SeqType type, std::string sequenceName) {
ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, GetSequenceTypeColor(type));
ImGui::SmallButton(GetSequenceTypeName(type).c_str());
std::string buttonLabel = GetSequenceTypeName(type) + "##" + sequenceName;
ImGui::Button(buttonLabel.c_str());
ImGui::PopStyleColor();
ImGui::EndDisabled();
}
@ -425,56 +453,68 @@ void AudioEditor::InitElement() {
void AudioEditor::DrawElement() {
AudioCollection::Instance->InitializeShufflePool();
float buttonSegments = ImGui::GetContentRegionAvail().x / 4;
if (ImGui::Button("Randomize All Groups", ImVec2(buttonSegments, 30.0f))) {
UIWidgets::Separator();
if (UIWidgets::Button("Randomize All Groups",
UIWidgets::ButtonOptions()
.Size(ImVec2(230.0f, 0.0f))
.Color(THEME_COLOR)
.Tooltip("Randomizes all unlocked music and sound effects across tab groups"))) {
AudioEditor_RandomizeAll();
}
UIWidgets::Tooltip("Randomizes all unlocked music and sound effects across tab groups");
ImGui::SameLine();
if (ImGui::Button("Reset All Groups", ImVec2(buttonSegments, 30.0f))) {
if (UIWidgets::Button("Reset All Groups",
UIWidgets::ButtonOptions()
.Size(ImVec2(230.0f, 0.0f))
.Color(THEME_COLOR)
.Tooltip("Resets all unlocked music and sound effects across tab groups"))) {
AudioEditor_ResetAll();
}
UIWidgets::Tooltip("Resets all unlocked music and sound effects across tab groups");
ImGui::SameLine();
if (ImGui::Button("Lock All Groups", ImVec2(buttonSegments, 30.0f))) {
if (UIWidgets::Button("Lock All Groups", UIWidgets::ButtonOptions()
.Size(ImVec2(230.0f, 0.0f))
.Color(THEME_COLOR)
.Tooltip("Locks all music and sound effects across tab groups"))) {
AudioEditor_LockAll();
}
UIWidgets::Tooltip("Locks all music and sound effects across tab groups");
ImGui::SameLine();
if (ImGui::Button("Unlock All Groups", ImVec2(buttonSegments, 30.0f))) {
if (UIWidgets::Button("Unlock All Groups",
UIWidgets::ButtonOptions()
.Size(ImVec2(230.0f, 0.0f))
.Color(THEME_COLOR)
.Tooltip("Unlocks all music and sound effects across tab groups"))) {
AudioEditor_UnlockAll();
}
UIWidgets::Tooltip("Unlocks all music and sound effects across tab groups");
UIWidgets::Separator();
UIWidgets::PushStyleTabs(THEME_COLOR);
if (ImGui::BeginTabBar("SfxContextTabBar", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
if (ImGui::BeginTabItem("Background Music")) {
Draw_SfxTab("backgroundMusic", SEQ_BGM_WORLD);
Draw_SfxTab("backgroundMusic", SEQ_BGM_WORLD, "Background Music");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Fanfares")) {
Draw_SfxTab("fanfares", SEQ_FANFARE);
Draw_SfxTab("fanfares", SEQ_FANFARE, "Fanfares");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Events")) {
Draw_SfxTab("event", SEQ_BGM_EVENT);
Draw_SfxTab("event", SEQ_BGM_EVENT, "Events");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Battle Music")) {
Draw_SfxTab("battleMusic", SEQ_BGM_BATTLE);
Draw_SfxTab("battleMusic", SEQ_BGM_BATTLE, "Battle Music");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Ocarina")) {
Draw_SfxTab("instrument", SEQ_INSTRUMENT);
Draw_SfxTab("ocarina", SEQ_OCARINA);
Draw_SfxTab("instrument", SEQ_INSTRUMENT, "Instruments");
Draw_SfxTab("ocarina", SEQ_OCARINA, "Ocarina");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Sound Effects")) {
Draw_SfxTab("sfx", SEQ_SFX);
Draw_SfxTab("sfx", SEQ_SFX, "Sound Effects");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Voices")) {
Draw_SfxTab("voice", SEQ_VOICE);
Draw_SfxTab("voice", SEQ_VOICE, "Voices");
ImGui::EndTabItem();
}
@ -486,53 +526,63 @@ void AudioEditor::DrawElement() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::BeginChild("SfxOptions", ImVec2(0, -8))) {
ImGui::PushItemWidth(-FLT_MIN);
UIWidgets::EnhancementCheckbox("Disable Enemy Proximity Music", CVAR_AUDIO("EnemyBGMDisable"));
UIWidgets::InsertHelpHoverText(
"Disables the music change when getting close to enemies. Useful for hearing "
"your custom music for each scene more often.");
UIWidgets::EnhancementCheckbox("Disable Leading Music in Lost Woods", CVAR_AUDIO("LostWoodsConsistentVolume"));
UIWidgets::InsertHelpHoverText(
"Disables the volume shifting in the Lost Woods. Useful for hearing "
UIWidgets::CVarCheckbox(
"Disable Enemy Proximity Music", CVAR_AUDIO("EnemyBGMDisable"),
UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Disables the music change when getting close to enemies. Useful for hearing "
"your custom music for each scene more often."));
UIWidgets::CVarCheckbox(
"Disable Leading Music in Lost Woods", CVAR_AUDIO("LostWoodsConsistentVolume"),
UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Disables the volume shifting in the Lost Woods. Useful for hearing "
"your custom music in the Lost Woods if you don't need the navigation assitance "
"the volume changing provides. If toggling this while in the Lost Woods, reload "
"the area for the effect to kick in."
);
UIWidgets::EnhancementCheckbox("Display Sequence Name on Overlay", CVAR_AUDIO("SeqNameOverlay"));
UIWidgets::InsertHelpHoverText(
"Displays the name of the current sequence in the corner of the screen whenever a new sequence "
"is loaded to the main sequence player (does not apply to fanfares or enemy BGM)."
);
"the area for the effect to kick in."));
UIWidgets::CVarCheckbox(
"Display Sequence Name on Overlay", CVAR_AUDIO("SeqNameOverlay"),
UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Displays the name of the current sequence in the corner of the screen whenever a new "
"sequence "
"is loaded to the main sequence player (does not apply to fanfares or enemy BGM)."));
UIWidgets::CVarSliderInt("Overlay Duration: %d seconds", CVAR_AUDIO("SeqNameOverlayDuration"),
UIWidgets::IntSliderOptions()
.Min(1)
.Max(10)
.DefaultValue(5)
.Size(ImVec2(300.0f, 0.0f))
.Color(THEME_COLOR));
UIWidgets::CVarSliderFloat("Link's voice pitch multiplier",
CVAR_AUDIO("LinkVoiceFreqMultiplier"),
UIWidgets::FloatSliderOptions()
.IsPercentage()
.Min(0.4f)
.Max(2.5f)
.DefaultValue(1.0f)
.Size(ImVec2(300.0f, 0.0f))
.Color(THEME_COLOR));
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
UIWidgets::EnhancementSliderInt("Overlay Duration: %d seconds", "##SeqNameOverlayDuration",
CVAR_AUDIO("SeqNameOverlayDuration"), 1, 10, "", 5);
ImGui::PopItemWidth();
ImGui::NewLine();
ImGui::PopItemWidth();
UIWidgets::EnhancementSliderFloat("Link's voice pitch multiplier: %.1f %%", "##linkVoiceFreqMultiplier",
CVAR_AUDIO("LinkVoiceFreqMultiplier"), 0.4, 2.5, "", 1.0, true, true);
ImGui::SameLine();
const std::string resetButton = "Reset##linkVoiceFreqMultiplier";
if (ImGui::Button(resetButton.c_str())) {
ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 40.f);
if (UIWidgets::Button("Reset##linkVoiceFreqMultiplier",
UIWidgets::ButtonOptions().Size(ImVec2(80, 36)).Padding(ImVec2(5.0f, 0.0f)))) {
CVarSetFloat(CVAR_AUDIO("LinkVoiceFreqMultiplier"), 1.0f);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::NewLine();
UIWidgets::EnhancementCheckbox("Randomize All Music and Sound Effects on New Scene", CVAR_AUDIO("RandomizeAllOnNewScene"));
UIWidgets::Tooltip("Enables randomizing all unlocked music and sound effects when you enter a new scene.");
ImGui::NewLine();
ImGui::PushItemWidth(-FLT_MIN);
UIWidgets::PaddedSeparator();
UIWidgets::PaddedText("The following options are experimental and may cause music\nto sound odd or have other undesireable effects.");
UIWidgets::EnhancementCheckbox("Lower Octaves of Unplayable High Notes", CVAR_AUDIO("ExperimentalOctaveDrop"));
UIWidgets::InsertHelpHoverText("Some custom sequences may have notes that are too high for the game's audio "
UIWidgets::CVarCheckbox(
"Randomize All Music and Sound Effects on New Scene", CVAR_AUDIO("RandomizeAllOnNewScene"),
UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip(
"Enables randomizing all unlocked music and sound effects when you enter a new scene."));
UIWidgets::CVarCheckbox(
"Lower Octaves of Unplayable High Notes", CVAR_AUDIO("ExperimentalOctaveDrop"),
UIWidgets::CheckboxOptions()
.Color(THEME_COLOR)
.Tooltip("Some custom sequences may have notes that are too high for the game's audio "
"engine to play. Enabling this checkbox will cause these notes to drop a "
"couple of octaves so they can still harmonize with the other notes of the "
"sequence.");
ImGui::PopItemWidth();
"sequence."));
}
ImGui::EndChild();
ImGui::EndTable();
@ -564,9 +614,12 @@ void AudioEditor::DrawElement() {
std::set<SequenceInfo*> seqsToExclude = {};
static ImGuiTextFilter sequenceSearch;
UIWidgets::PushStyleInput(THEME_COLOR);
sequenceSearch.Draw("Filter (inc,-exc)", 490.0f);
UIWidgets::PopStyleInput();
ImGui::SameLine();
if (ImGui::Button("Exclude All")) {
if (UIWidgets::Button("Exclude All",
UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR))) {
for (auto seqInfo : AudioCollection::Instance->GetIncludedSequences()) {
if (sequenceSearch.PassFilter(seqInfo->label.c_str()) && showType[seqInfo->category]) {
seqsToExclude.insert(seqInfo);
@ -574,7 +627,8 @@ void AudioEditor::DrawElement() {
}
}
ImGui::SameLine();
if (ImGui::Button("Include All")) {
if (UIWidgets::Button("Include All",
UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR))) {
for (auto seqInfo : AudioCollection::Instance->GetExcludedSequences()) {
if (sequenceSearch.PassFilter(seqInfo->label.c_str()) && showType[seqInfo->category]) {
seqsToInclude.insert(seqInfo);
@ -643,13 +697,17 @@ void AudioEditor::DrawElement() {
ImGui::BeginChild("ChildIncludedSequences", ImVec2(0, -8));
for (auto seqInfo : AudioCollection::Instance->GetIncludedSequences()) {
if (sequenceSearch.PassFilter(seqInfo->label.c_str()) && showType[seqInfo->category]) {
if (ImGui::Button(std::string(ICON_FA_TIMES "##" + seqInfo->sfxKey).c_str())) {
if (UIWidgets::Button(std::string(ICON_FA_TIMES "##" + seqInfo->sfxKey).c_str(),
UIWidgets::ButtonOptions()
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(9.0f, 6.0f))
.Color(THEME_COLOR))) {
seqsToExclude.insert(seqInfo);
}
ImGui::SameLine();
DrawPreviewButton(seqInfo->sequenceId, seqInfo->sfxKey, seqInfo->category);
ImGui::SameLine();
DrawTypeChip(seqInfo->category);
DrawTypeChip(seqInfo->category, seqInfo->label);
ImGui::SameLine();
ImGui::Text("%s", seqInfo->label.c_str());
}
@ -667,13 +725,17 @@ void AudioEditor::DrawElement() {
ImGui::BeginChild("ChildExcludedSequences", ImVec2(0, -8));
for (auto seqInfo : AudioCollection::Instance->GetExcludedSequences()) {
if (sequenceSearch.PassFilter(seqInfo->label.c_str()) && showType[seqInfo->category]) {
if (ImGui::Button(std::string(ICON_FA_PLUS "##" + seqInfo->sfxKey).c_str())) {
if (UIWidgets::Button(std::string(ICON_FA_PLUS "##" + seqInfo->sfxKey).c_str(),
UIWidgets::ButtonOptions()
.Size(UIWidgets::Sizes::Inline)
.Padding(ImVec2(9.0f, 6.0f))
.Color(THEME_COLOR))) {
seqsToInclude.insert(seqInfo);
}
ImGui::SameLine();
DrawPreviewButton(seqInfo->sequenceId, seqInfo->sfxKey, seqInfo->category);
ImGui::SameLine();
DrawTypeChip(seqInfo->category);
DrawTypeChip(seqInfo->category, seqInfo->sfxKey);
ImGui::SameLine();
ImGui::Text("%s", seqInfo->label.c_str());
}
@ -695,6 +757,7 @@ void AudioEditor::DrawElement() {
ImGui::EndTabBar();
}
UIWidgets::PopStyleTabs();
}
std::vector<SeqType> allTypes = { SEQ_BGM_WORLD, SEQ_BGM_EVENT, SEQ_BGM_BATTLE, SEQ_OCARINA, SEQ_FANFARE, SEQ_INSTRUMENT, SEQ_SFX, SEQ_VOICE };

View file

@ -10,31 +10,25 @@
#include <cmath>
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
using namespace UIWidgets;
// Text colors
static ImVec4 textColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
static ImVec4 range1Color = ImVec4(1.0f, 0.7f, 0, 1.0f);
static ImVec4 range2Color = ImVec4(0, 1.0f, 0, 1.0f);
static Color_RGBA8 textColorDefault = { 255, 255, 255, 255 };
static Color_RGBA8 range1ColorDefault = { 255, 178, 0, 255 };
static Color_RGBA8 range2ColorDefault = { 0, 255, 0, 255 };
static const char* buttonOutlineOptions[4] = { "Always Shown", "Shown Only While Not Pressed",
"Shown Only While Pressed", "Always Hidden" };
static const char* buttonOutlineOptionsVerbose[4] = { "Outline Always Shown", "Outline Shown Only While Not Pressed",
"Outline Shown Only While Pressed", "Outline Always Hidden" };
static std::unordered_map<int32_t, const char*> buttonOutlineOptions =
{{ BUTTON_OUTLINE_ALWAYS_SHOWN, "Always Shown" }, { BUTTON_OUTLINE_NOT_PRESSED, "Shown Only While Not Pressed" },
{ BUTTON_OUTLINE_PRESSED, "Shown Only While Pressed" }, { BUTTON_OUTLINE_ALWAYS_HIDDEN, "Always Hidden" }};
static std::unordered_map<int32_t, const char*> buttonOutlineOptionsVerbose =
{{ BUTTON_OUTLINE_ALWAYS_SHOWN, "Outline Always Shown" }, { BUTTON_OUTLINE_NOT_PRESSED, "Outline Shown Only While Not Pressed" },
{ BUTTON_OUTLINE_PRESSED, "Outline Shown Only While Pressed" }, { BUTTON_OUTLINE_ALWAYS_HIDDEN, "Outline Always Hidden" }};
static const char* stickModeOptions[3] = { "Always", "While In Use", "Never" };
static Color_RGBA8 vec2Color(ImVec4 vec) {
Color_RGBA8 color;
color.r = vec.x * 255.0;
color.g = vec.y * 255.0;
color.b = vec.z * 255.0;
color.a = vec.w * 255.0;
return color;
}
static ImVec4 color2Vec(Color_RGBA8 color) {
return ImVec4(color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0);
}
static std::unordered_map<int32_t, const char*> stickModeOptions =
{{ STICK_MODE_ALWAYS_SHOWN, "Always" }, { STICK_MODE_HIDDEN_IN_DEADZONE, "While In Use" }, { STICK_MODE_ALWAYS_HIDDEN, "Never" }};
InputViewer::~InputViewer() {
SPDLOG_TRACE("destruct input viewer");
@ -399,17 +393,17 @@ void InputViewer::DrawElement() {
(rSquared >= (range1Min * range1Min)) && (rSquared < (range1Max * range1Max))) {
ImGui::PushStyleColor(
ImGuiCol_Text,
color2Vec(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color"), vec2Color(range1Color))));
VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color.Value"), range1ColorDefault)));
}
else if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"), 0) &&
(rSquared >= (range2Min * range2Min)) && (rSquared < (range2Max * range2Max))) {
ImGui::PushStyleColor(
ImGuiCol_Text,
color2Vec(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color"), vec2Color(range2Color))));
VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color.Value"), range2ColorDefault)));
}
else {
ImGui::PushStyleColor(ImGuiCol_Text, color2Vec(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.TextColor"),
vec2Color(textColor))));
ImGui::PushStyleColor(ImGuiCol_Text, VecFromRGBA8(CVarGetColor(CVAR_INPUT_VIEWER("AnalogAngles.TextColor.Value"),
textColorDefault)));
}
// Render text
@ -434,250 +428,217 @@ InputViewerSettingsWindow::~InputViewerSettingsWindow() {
}
void InputViewerSettingsWindow::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
// gInputViewer.Scale
UIWidgets::EnhancementSliderFloat("Input Viewer Scale: %.2f", "##Input", CVAR_INPUT_VIEWER("Scale"), 0.1f, 5.0f, "",
1.0f, false, true);
UIWidgets::Tooltip("Sets the on screen size of the input viewer");
CVarSliderFloat("Input Viewer Scale: %.2f", CVAR_INPUT_VIEWER("Scale"),
FloatSliderOptions().Color(THEME_COLOR).DefaultValue(1.0f).Min(0.1f).Max(5.0f).ShowButtons(true).Tooltip("Sets the on screen size of the input viewer"));
// gInputViewer.EnableDragging
UIWidgets::EnhancementCheckbox("Enable Dragging", CVAR_INPUT_VIEWER("EnableDragging"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Enable Dragging", CVAR_INPUT_VIEWER("EnableDragging"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
UIWidgets::PaddedSeparator(true, true);
// gInputViewer.ShowBackground
UIWidgets::EnhancementCheckbox("Show Background Layer", CVAR_INPUT_VIEWER("ShowBackground"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show Background Layer", CVAR_INPUT_VIEWER("ShowBackground"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
UIWidgets::PaddedSeparator(true, true);
PushStyleHeader(THEME_COLOR);
if (ImGui::CollapsingHeader("Buttons")) {
// gInputViewer.ButtonOutlineMode
UIWidgets::PaddedText("Button Outlines/Backgrounds", true, false);
UIWidgets::EnhancementCombobox(
CVAR_INPUT_VIEWER("ButtonOutlineMode"), buttonOutlineOptions, BUTTON_OUTLINE_NOT_PRESSED,
!CVarGetInteger(CVAR_INPUT_VIEWER("UseGlobalButtonOutlineMode"), 1), "",
CVarGetInteger(CVAR_INPUT_VIEWER("ButtonOutlineMode"), BUTTON_OUTLINE_NOT_PRESSED));
UIWidgets::Tooltip(
"Sets the desired visibility behavior for the button outline/background layers. Useful for "
"custom input viewers.");
CVarCombobox("Button Outlines/Backgrounds", CVAR_INPUT_VIEWER("ButtonOutlineMode"), buttonOutlineOptions,
ComboboxOptions({{ .disabled = !CVarGetInteger(CVAR_INPUT_VIEWER("UseGlobalButtonOutlineMode"), 1), .disabledTooltip = "Disabled because Global Button Outline is off" }})
.Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED)
.Tooltip("Sets the desired visibility behavior for the button outline/background layers. Useful for "
"custom input viewers."));
// gInputViewer.UseGlobalButtonOutlineMode
UIWidgets::EnhancementCheckbox("Use for all buttons", CVAR_INPUT_VIEWER("UseGlobalButtonOutlineMode"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Use for all buttons", CVAR_INPUT_VIEWER("UseGlobalButtonOutlineMode"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
UIWidgets::PaddedSeparator();
bool useIndividualOutlines = !CVarGetInteger(CVAR_INPUT_VIEWER("UseGlobalButtonOutlineMode"), 1);
// gInputViewer.ABtn
UIWidgets::EnhancementCheckbox("Show A-Button Layers", CVAR_INPUT_VIEWER("ABtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show A-Button Layers", CVAR_INPUT_VIEWER("ABtn"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("ABtn"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("ABtnOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##ABtnOutline", CVAR_INPUT_VIEWER("ABtnOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.BBtn
UIWidgets::EnhancementCheckbox("Show B-Button Layers", CVAR_INPUT_VIEWER("BBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show B-Button Layers", CVAR_INPUT_VIEWER("BBtn"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("BBtn"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("BBtnOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##BBtnOutline", CVAR_INPUT_VIEWER("BBtnOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.CUp
UIWidgets::EnhancementCheckbox("Show C-Up Layers", CVAR_INPUT_VIEWER("CUp"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show C-Up Layers", CVAR_INPUT_VIEWER("CUp"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("CUp"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("CUpOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##CUpOutline", CVAR_INPUT_VIEWER("CUpOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.CRight
UIWidgets::EnhancementCheckbox("Show C-Right Layers", CVAR_INPUT_VIEWER("CRight"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show C-Right Layers", CVAR_INPUT_VIEWER("CRight"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("CRight"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("CRightOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##CRightOutline", CVAR_INPUT_VIEWER("CRightOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.CDown
UIWidgets::EnhancementCheckbox("Show C-Down Layers", CVAR_INPUT_VIEWER("CDown"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show C-Down Layers", CVAR_INPUT_VIEWER("CDown"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("CDown"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("CDownOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##CDownOutline", CVAR_INPUT_VIEWER("CDownOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.CLeft
UIWidgets::EnhancementCheckbox("Show C-Left Layers", CVAR_INPUT_VIEWER("CLeft"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show C-Left Layers", CVAR_INPUT_VIEWER("CLeft"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("CLeft"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("CLeftOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##CLeftOutline", CVAR_INPUT_VIEWER("CLeftOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.LBtn
UIWidgets::EnhancementCheckbox("Show L-Button Layers", CVAR_INPUT_VIEWER("LBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show L-Button Layers", CVAR_INPUT_VIEWER("LBtn"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("LBtn"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("LBtnOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##LBtnOutline", CVAR_INPUT_VIEWER("LBtnOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.RBtn
UIWidgets::EnhancementCheckbox("Show R-Button Layers", CVAR_INPUT_VIEWER("RBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show R-Button Layers", CVAR_INPUT_VIEWER("RBtn"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("RBtn"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("RBtnOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##RBtnOutline", CVAR_INPUT_VIEWER("RBtnOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.ZBtn
UIWidgets::EnhancementCheckbox("Show Z-Button Layers", CVAR_INPUT_VIEWER("ZBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show Z-Button Layers", CVAR_INPUT_VIEWER("ZBtn"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("ZBtn"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("ZBtnOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##ZBtnOutline", CVAR_INPUT_VIEWER("ZBtnOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.StartBtn
UIWidgets::EnhancementCheckbox("Show Start Button Layers", CVAR_INPUT_VIEWER("StartBtn"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, true);
CVarCheckbox("Show Start Button Layers", CVAR_INPUT_VIEWER("StartBtn"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("StartBtn"), 1)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("StartBtnOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##StartBtnOutline", CVAR_INPUT_VIEWER("StartBtnOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.Dpad
UIWidgets::EnhancementCheckbox("Show D-Pad Layers", CVAR_INPUT_VIEWER("Dpad"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, false);
CVarCheckbox("Show D-Pad Layers", CVAR_INPUT_VIEWER("Dpad"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("Dpad"), 0)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("DpadOutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##DpadOutline", CVAR_INPUT_VIEWER("DpadOutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.Mod1
UIWidgets::EnhancementCheckbox("Show Modifier Button 1 Layers", CVAR_INPUT_VIEWER("Mod1"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, false);
CVarCheckbox("Show Modifier Button 1 Layers", CVAR_INPUT_VIEWER("Mod1"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("Mod1"), 0)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("Mod1OutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##Mmod1Outline", CVAR_INPUT_VIEWER("Mod1OutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
// gInputViewer.Mod2
UIWidgets::EnhancementCheckbox("Show Modifier Button 2 Layers", CVAR_INPUT_VIEWER("Mod2"), false, "",
UIWidgets::CheckboxGraphics::Checkmark, false);
CVarCheckbox("Show Modifier Button 2 Layers", CVAR_INPUT_VIEWER("Mod2"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true));
if (useIndividualOutlines && CVarGetInteger(CVAR_INPUT_VIEWER("Mod2"), 0)) {
ImGui::Indent();
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("Mod2OutlineMode"), buttonOutlineOptionsVerbose,
BUTTON_OUTLINE_NOT_PRESSED);
CVarCombobox("##Mod2Outline", CVAR_INPUT_VIEWER("Mod2OutlineMode"), buttonOutlineOptionsVerbose,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(BUTTON_OUTLINE_NOT_PRESSED));
ImGui::Unindent();
}
UIWidgets::PaddedSeparator(true, true);
UIWidgets:PaddedSeparator(true, true);
}
if (ImGui::CollapsingHeader("Analog Stick")) {
// gInputViewer.AnalogStick.VisibilityMode
UIWidgets::PaddedText("Analog Stick Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("AnalogStick.VisibilityMode"), stickModeOptions,
STICK_MODE_ALWAYS_SHOWN);
UIWidgets::Tooltip(
"Determines the conditions under which the moving layer of the analog stick texture is visible.");
CVarCombobox("Analog Stick Visibility", CVAR_INPUT_VIEWER("AnalogStick.VisibilityMode"), stickModeOptions,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(STICK_MODE_ALWAYS_SHOWN)
.Tooltip("Determines the conditions under which the moving layer of the analog stick texture is visible."));
// gInputViewer.AnalogStick.OutlineMode
UIWidgets::PaddedText("Analog Stick Outline/Background Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("AnalogStick.OutlineMode"), stickModeOptions,
STICK_MODE_ALWAYS_SHOWN);
UIWidgets::Tooltip(
"Determines the conditions under which the analog stick outline/background texture is visible.");
CVarCombobox("Analog Stick Outline/Background Visibility", CVAR_INPUT_VIEWER("AnalogStick.OutlineMode"), stickModeOptions,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(STICK_MODE_ALWAYS_SHOWN)
.Tooltip("Determines the conditions under which the analog stick outline/background texture is visible."));
// gInputViewer.AnalogStick.Movement
UIWidgets::EnhancementSliderInt("Analog Stick Movement: %dpx", "##AnalogMovement",
CVAR_INPUT_VIEWER("AnalogStick.Movement"), 0, 200, "", 12, true);
UIWidgets::Tooltip(
"Sets the distance to move the analog stick in the input viewer. Useful for custom input viewers.");
CVarSliderInt("Analog Stick Movement: %dpx", CVAR_INPUT_VIEWER("AnalogStick.Movement"), IntSliderOptions().Color(THEME_COLOR).Min(0).Max(200).DefaultValue(12).ShowButtons(true)
.Tooltip("Sets the distance to move the analog stick in the input viewer. Useful for custom input viewers."));
UIWidgets::PaddedSeparator(true, true);
}
if (ImGui::CollapsingHeader("Additional (\"Right\") Stick")) {
// gInputViewer.RightStick.VisibilityMode
UIWidgets::PaddedText("Right Stick Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("RightStick.VisibilityMode"), stickModeOptions,
STICK_MODE_HIDDEN_IN_DEADZONE);
UIWidgets::Tooltip(
"Determines the conditions under which the moving layer of the right stick texture is visible.");
CVarCombobox("Right Stick Visibility", CVAR_INPUT_VIEWER("RightStick.VisibilityMode"), stickModeOptions,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(STICK_MODE_ALWAYS_SHOWN)
.Tooltip("Determines the conditions under which the moving layer of the right stick texture is visible."));
// gInputViewer.RightStick.OutlineMode
UIWidgets::PaddedText("Right Stick Outline/Background Visibility", true, false);
UIWidgets::EnhancementCombobox(CVAR_INPUT_VIEWER("RightStick.OutlineMode"), stickModeOptions,
STICK_MODE_HIDDEN_IN_DEADZONE);
UIWidgets::Tooltip(
"Determines the conditions under which the right stick outline/background texture is visible.");
CVarCombobox("Right Stick Outline/Background Visibility", CVAR_INPUT_VIEWER("RightStick.OutlineMode"), stickModeOptions,
ComboboxOptions().Color(THEME_COLOR).DefaultIndex(STICK_MODE_ALWAYS_SHOWN)
.Tooltip("Determines the conditions under which the right stick outline/background texture is visible."));
// gInputViewer.RightStick.Movement
UIWidgets::EnhancementSliderInt("Right Stick Movement: %dpx", "##RightMovement",
CVAR_INPUT_VIEWER("RightStick.Movement"), 0, 200, "", 7, true);
UIWidgets::Tooltip(
"Sets the distance to move the right stick in the input viewer. Useful for custom input viewers.");
CVarSliderInt("Right Stick Movement: %dpx", CVAR_INPUT_VIEWER("RightStick.Movement"), IntSliderOptions().Color(THEME_COLOR).Min(0).Max(200).DefaultValue(7).ShowButtons(true)
.Tooltip("Sets the distance to move the right stick in the input viewer. Useful for custom input viewers."));
UIWidgets::PaddedSeparator(true, true);
}
if (ImGui::CollapsingHeader("Analog Angle Values")) {
// gAnalogAngles
UIWidgets::EnhancementCheckbox("Show Analog Stick Angle Values", CVAR_INPUT_VIEWER("AnalogAngles.Enabled"));
UIWidgets::Tooltip("Displays analog stick angle values in the input viewer");
CVarCheckbox("Show Analog Stick Angle Values", CVAR_INPUT_VIEWER("AnalogAngles.Enabled"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Displays analog stick angle values in the input viewer"));
if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Enabled"), 0)) {
// gInputViewer.AnalogAngles.TextColor
if (ImGui::ColorEdit4("Text Color", (float*)&textColor)) {
CVarSetColor(CVAR_INPUT_VIEWER("AnalogAngles.TextColor"), vec2Color(textColor));
}
CVarColorPicker("Text Color", CVAR_INPUT_VIEWER("AnalogAngles.TextColor"), textColorDefault,
true, ColorPickerRandomButton | ColorPickerResetButton);
// gAnalogAngleScale
UIWidgets::EnhancementSliderFloat("Angle Text Scale: %.2f%%", "##AnalogAngleScale",
CVAR_INPUT_VIEWER("AnalogAngles.Scale"), 0.1f, 5.0f, "", 1.0f, true, true);
CVarSliderFloat("Angle Text Scale: %.2f%%", CVAR_INPUT_VIEWER("AnalogAngles.Scale"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.1f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
// gInputViewer.AnalogAngles.Offset
UIWidgets::EnhancementSliderInt("Angle Text Offset: %dpx", "##AnalogAngleOffset",
CVAR_INPUT_VIEWER("AnalogAngles.Offset"), 0, 400, "", 0, true);
CVarSliderInt("Angle Text Offset: %dpx", CVAR_INPUT_VIEWER("AnalogAngles.Offset"), IntSliderOptions().Color(THEME_COLOR).Min(0).Max(400).DefaultValue(0).ShowButtons(true)
.Tooltip("Sets the distance to move the right stick in the input viewer. Useful for custom input viewers."));
UIWidgets::PaddedSeparator(true, true);
// gInputViewer.AnalogAngles.Range1.Enabled
UIWidgets::EnhancementCheckbox("Highlight ESS Position", CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"));
UIWidgets::Tooltip(
"Highlights the angle value text when the analog stick is in ESS position (on flat ground)");
CVarCheckbox("Highlight ESS Position", CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Highlights the angle value text when the analog stick is in ESS position (on flat ground)"));
if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Enabled"), 0)) {
// gInputViewer.AnalogAngles.Range1.Color
if (ImGui::ColorEdit4("ESS Color", (float*)&range1Color)) {
CVarSetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color"), vec2Color(range1Color));
}
CVarColorPicker("ESS Color", CVAR_INPUT_VIEWER("AnalogAngles.Range1.Color"), range1ColorDefault,
true, ColorPickerRandomButton | ColorPickerResetButton);
}
UIWidgets::PaddedSeparator(true, true);
// gInputViewer.AnalogAngles.Range2.Enabled
UIWidgets::EnhancementCheckbox("Highlight Walking Speed Angles",
CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"));
UIWidgets::Tooltip("Highlights the angle value text when the analog stick is at an angle that would "
CVarCheckbox("Highlight Walking Speed Angles", CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Highlights the angle value text when the analog stick is at an angle that would "
"produce a walking speed (on flat ground)\n\n"
"Useful for 1.0 Empty Jumpslash Quick Put Away");
"Useful for 1.0 Empty Jumpslash Quick Put Away"));
if (CVarGetInteger(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Enabled"), 0)) {
// gInputViewer.AnalogAngles.Range2.Color
if (ImGui::ColorEdit4("Walking Speed Color", (float*)&range2Color)) {
CVarSetColor(CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color"), vec2Color(range2Color));
}
CVarColorPicker("Walking Speed Color", CVAR_INPUT_VIEWER("AnalogAngles.Range2.Color"), range2ColorDefault,
true, ColorPickerRandomButton | ColorPickerResetButton);
}
}
}
PopStyleHeader();
ImGui::PopFont();
}

View file

@ -2,6 +2,7 @@
#include <utils/StringHelper.h>
#include "soh/OTRGlobals.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "z64.h"
#include "soh/cvar_prefixes.h"
#ifndef __WIIU__
@ -10,6 +11,8 @@
#define SCALE_IMGUI_SIZE(value) ((value / 13.0f) * ImGui::GetFontSize())
using namespace UIWidgets;
SohInputEditorWindow::~SohInputEditorWindow() {
}
@ -1062,17 +1065,16 @@ void SohInputEditorWindow::DrawLEDSection(uint8_t port) {
}
// todo: clean this up, probably just hardcode to LED_COLOR_SOURCE_GAME and use SoH options only here
if (mapping->GetColorSource() == LED_COLOR_SOURCE_GAME) {
static const char* ledSources[] = {
static std::vector<const char*> ledSources = {
"Original Tunic Colors", "Cosmetics Tunic Colors", "Health Colors",
"Original Navi Targeting Colors", "Cosmetics Navi Targeting Colors", "Custom"
};
UIWidgets::PaddedText("Source");
UIWidgets::EnhancementCombobox(CVAR_SETTING("LEDColorSource"), ledSources, LED_SOURCE_TUNIC_ORIGINAL);
UIWidgets::Tooltip("Health\n- Red when health critical (13-20% depending on max health)\n- Yellow when "
CVarCombobox("Source", CVAR_SETTING("LEDColorSource"), ledSources, UIWidgets::ComboboxOptions().Color(THEME_COLOR).DefaultIndex(LED_SOURCE_TUNIC_ORIGINAL)
.Tooltip("Health\n- Red when health critical (13-20% depending on max health)\n- Yellow when "
"health < 40%. Green otherwise.\n\n"
"Tunics: colors will mirror currently equipped tunic, whether original or the current "
"values in Cosmetics Editor.\n\n"
"Custom: single, solid color");
"Custom: single, solid color"));
if (CVarGetInteger(CVAR_SETTING("LEDColorSource"), 1) == LED_SOURCE_CUSTOM) {
UIWidgets::Spacer(3);
auto port1Color = CVarGetColor24(CVAR_SETTING("LEDPort1Color"), { 255, 255, 255 });
@ -1090,14 +1092,13 @@ void SohInputEditorWindow::DrawLEDSection(uint8_t port) {
ImGui::SameLine();
ImGui::Text("Custom Color");
}
UIWidgets::PaddedEnhancementSliderFloat("Brightness: %.1f %%", "##LED_Brightness", CVAR_SETTING("LEDBrightness"), 0.0f,
1.0f, "", 1.0f, true, true);
UIWidgets::Tooltip("Sets the brightness of controller LEDs. 0% brightness = LEDs off.");
UIWidgets::PaddedEnhancementCheckbox(
"Critical Health Override", CVAR_SETTING("LEDCriticalOverride"), true, true,
CVarGetInteger(CVAR_SETTING("LEDColorSource"), LED_SOURCE_TUNIC_ORIGINAL) == LED_SOURCE_HEALTH,
"Override redundant for health source.", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Shows red color when health is critical, otherwise displays according to color source.");
CVarSliderFloat("Brightness: %.1f %%", CVAR_SETTING("LEDBrightness"),
FloatSliderOptions().IsPercentage().Min(0.0f).Max(1.0f).DefaultValue(1.0f).ShowButtons(true)
.Tooltip("Sets the brightness of controller LEDs. 0% brightness = LEDs off."));
CVarCheckbox("Critical Health Override", CVAR_SETTING("LEDCriticalOverride"),
CheckboxOptions({{ .disabled = CVarGetInteger(CVAR_SETTING("LEDColorSource"), LED_SOURCE_TUNIC_ORIGINAL) == LED_SOURCE_HEALTH,
.disabledTooltip = "Override redundant for health source."}}).DefaultValue(true)
.Tooltip("Shows red color when health is critical, otherwise displays according to color source."));
}
ImGui::TreePop();
}
@ -1281,7 +1282,6 @@ void SohInputEditorWindow::DrawMapping(CustomButtonMap& mapping, float labelWidt
preview = "Unknown";
}
UIWidgets::Spacer(0);
ImVec2 cursorPos = ImGui::GetCursorPos();
ImVec2 textSize = ImGui::CalcTextSize(mapping.label);
ImGui::SetCursorPosY(cursorPos.y + textSize.y / 4);
@ -1303,16 +1303,16 @@ void SohInputEditorWindow::DrawMapping(CustomButtonMap& mapping, float labelWidt
}
ImGui::EndCombo();
}
UIWidgets::Spacer(0);
}
void SohInputEditorWindow::DrawOcarinaControlPanel() {
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x, cursor.y + 5));
UIWidgets::EnhancementCheckbox("Dpad Ocarina Playback", CVAR_SETTING("CustomOcarina.Dpad"));
UIWidgets::EnhancementCheckbox("Right Stick Ocarina Playback", CVAR_SETTING("CustomOcarina.RightStick"));
UIWidgets::EnhancementCheckbox("Customize Ocarina Controls", CVAR_SETTING("CustomOcarina.Enabled"));
CheckboxOptions checkOpt = CheckboxOptions().Color(THEME_COLOR);
CVarCheckbox("Dpad Ocarina Playback", CVAR_SETTING("CustomOcarina.Dpad"), checkOpt);
CVarCheckbox("Right Stick Ocarina Playback", CVAR_SETTING("CustomOcarina.RightStick"), checkOpt);
CVarCheckbox("Customize Ocarina Controls", CVAR_SETTING("CustomOcarina.Enabled"), checkOpt);
if (!CVarGetInteger(CVAR_SETTING("CustomOcarina.Enabled"), 0)) {
ImGui::BeginDisabled();
@ -1344,60 +1344,56 @@ void SohInputEditorWindow::DrawCameraControlPanel() {
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
Ship::GuiWindow::BeginGroupPanel("Aiming/First-Person Camera", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Right Stick Aiming", CVAR_SETTING("Controls.RightStickAim"));
UIWidgets::Tooltip("Allows for aiming with the right stick in:\n-First-Person/C-Up view\n-Weapon Aiming");
CVarCheckbox("Right Stick Aiming", CVAR_SETTING("Controls.RightStickAim"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Allows for aiming with the right stick in:\n-First-Person/C-Up view\n-Weapon Aiming"));
if (CVarGetInteger(CVAR_SETTING("Controls.RightStickAim"), 0)) {
UIWidgets::PaddedEnhancementCheckbox("Allow moving while in first person mode", CVAR_SETTING("MoveInFirstPerson"));
UIWidgets::Tooltip("Changes the left stick to move the player while in first person mode");
CVarCheckbox("Allow moving while in first person mode", CVAR_SETTING("MoveInFirstPerson"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Changes the left stick to move the player while in first person mode"));
}
UIWidgets::PaddedEnhancementCheckbox("Invert Aiming X Axis", CVAR_SETTING("Controls.InvertAimingXAxis"));
UIWidgets::Tooltip("Inverts the Camera X Axis in:\n-First-Person/C-Up view\n-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Invert Aiming Y Axis", CVAR_SETTING("Controls.InvertAimingYAxis"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-First-Person/C-Up view\n-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Invert Shield Aiming X Axis", CVAR_SETTING("Controls.InvertShieldAimingXAxis"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Shield Aiming X Axis");
UIWidgets::PaddedEnhancementCheckbox("Invert Shield Aiming Y Axis", CVAR_SETTING("Controls.InvertShieldAimingYAxis"));
UIWidgets::Tooltip("Inverts the Shield Aiming Y Axis");
UIWidgets::PaddedEnhancementCheckbox("Invert Z-Weapon Aiming Y Axis", CVAR_SETTING("Controls.InvertZAimingYAxis"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-Z-Weapon Aiming");
UIWidgets::PaddedEnhancementCheckbox("Disable Auto-Centering in First-Person View", CVAR_SETTING("DisableFirstPersonAutoCenterView"));
UIWidgets::Tooltip("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming");
if (UIWidgets::PaddedEnhancementCheckbox("Enable Custom Aiming/First-Person sensitivity", CVAR_SETTING("FirstPersonCameraSensitivity.Enabled"), true, false)) {
CVarCheckbox("Invert Aiming X Axis", CVAR_SETTING("Controls.InvertAimingXAxis"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Inverts the Camera X Axis in:\n-First-Person/C-Up view\n-Weapon Aiming"));
CVarCheckbox("Invert Aiming Y Axis", CVAR_SETTING("Controls.InvertAimingYAxis"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true)
.Tooltip("Inverts the Camera Y Axis in:\n-First-Person/C-Up view\n-Weapon Aiming"));
CVarCheckbox("Invert Shield Aiming X Axis", CVAR_SETTING("Controls.InvertShieldAimingXAxis"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true)
.Tooltip("Inverts the Shield Aiming X Axis"));
CVarCheckbox("Invert Shield Aiming Y Axis", CVAR_SETTING("Controls.InvertShieldAimingYAxis"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Inverts the Shield Aiming Y Axis"));
CVarCheckbox("Invert Z-Weapon Aiming Y Axis", CVAR_SETTING("Controls.InvertZAimingYAxis"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true)
.Tooltip("Inverts the Camera Y Axis in:\n-Z-Weapon Aiming"));
CVarCheckbox("Disable Auto-Centering in First-Person View", CVAR_SETTING("DisableFirstPersonAutoCenterView"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Prevents the C-Up view from auto-centering, allowing for Gyro Aiming"));
if (CVarCheckbox("Enable Custom Aiming/First-Person sensitivity", CVAR_SETTING("FirstPersonCameraSensitivity.Enabled"), CheckboxOptions().Color(THEME_COLOR))) {
if (!CVarGetInteger(CVAR_SETTING("FirstPersonCameraSensitivity.Enabled"), 0)) {
CVarClear(CVAR_SETTING("FirstPersonCameraSensitivity.X"));
CVarClear(CVAR_SETTING("FirstPersonCameraSensitivity.Y"));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
if (CVarGetInteger(CVAR_SETTING("FirstPersonCameraSensitivity.Enabled"), 0)) {
UIWidgets::EnhancementSliderFloat("Aiming/First-Person Horizontal Sensitivity: %.0f %%", "##FirstPersonSensitivity Horizontal",
CVAR_SETTING("FirstPersonCameraSensitivity.X"), 0.01f, 5.0f, "", 1.0f, true);
UIWidgets::EnhancementSliderFloat("Aiming/First-Person Vertical Sensitivity: %.0f %%", "##FirstPersonSensitivity Vertical",
CVAR_SETTING("FirstPersonCameraSensitivity.Y"), 0.01f, 5.0f, "", 1.0f, true);
CVarSliderFloat("Aiming/First-Person Horizontal Sensitivity: %.0f %%", CVAR_SETTING("FirstPersonCameraSensitivity.X"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.01f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
CVarSliderFloat("Aiming/First-Person Vertical Sensitivity: %.0f %%", CVAR_SETTING("FirstPersonCameraSensitivity.Y"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.01f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
}
UIWidgets::Spacer(0);
Ship::GuiWindow::EndGroupPanel(0);
UIWidgets::Spacer(0);
cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
Ship::GuiWindow::BeginGroupPanel("Third-Person Camera", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Free Look", CVAR_SETTING("FreeLook.Enabled"));
UIWidgets::Tooltip("Enables free look camera control\nNote: You must remap C buttons off of the right stick in the "
"controller config menu, and map the camera stick to the right stick.");
UIWidgets::PaddedEnhancementCheckbox("Invert Camera X Axis", CVAR_SETTING("FreeLook.InvertXAxis"));
UIWidgets::Tooltip("Inverts the Camera X Axis in:\n-Free look");
UIWidgets::PaddedEnhancementCheckbox("Invert Camera Y Axis", CVAR_SETTING("FreeLook.InvertYAxis"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Inverts the Camera Y Axis in:\n-Free look");
UIWidgets::Spacer(0);
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Horizontal Sensitivity: %.0f %%", "##ThirdPersonSensitivity Horizontal",
CVAR_SETTING("FreeLook.CameraSensitivity.X"), 0.01f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Third-Person Vertical Sensitivity: %.0f %%", "##ThirdPersonSensitivity Vertical",
CVAR_SETTING("FreeLook.CameraSensitivity.Y"), 0.01f, 5.0f, "", 1.0f, true, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Camera Distance: %d", "##CamDist",
CVAR_SETTING("FreeLook.MaxCameraDistance"), 100, 900, "", 185, true, false, true);
UIWidgets::PaddedEnhancementSliderInt("Camera Transition Speed: %d", "##CamTranSpeed",
CVAR_SETTING("FreeLook.TransitionSpeed"), 0, 900, "", 25, true, false, true);
CVarCheckbox("Free Look", CVAR_SETTING("FreeLook.Enabled"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Enables free look camera control\nNote: You must remap C buttons off of the right stick in the "
"controller config menu, and map the camera stick to the right stick."));
CVarCheckbox("Invert Camera X Axis", CVAR_SETTING("FreeLook.InvertXAxis"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Inverts the Camera X Axis in:\n-Free look"));
CVarCheckbox("Invert Camera Y Axis", CVAR_SETTING("FreeLook.InvertYAxis"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true)
.Tooltip("Inverts the Camera Y Axis in:\n-Free look"));
CVarSliderFloat("Third-Person Horizontal Sensitivity: %.0f %%", CVAR_SETTING("FreeLook.CameraSensitivity.X"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.01f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
CVarSliderFloat("Third-Person Vertical Sensitivity: %.0f %%", CVAR_SETTING("FreeLook.CameraSensitivity.Y"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.01f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
CVarSliderInt("Camera Distance: %d", CVAR_SETTING("FreeLook.MaxCameraDistance"), IntSliderOptions().Color(THEME_COLOR).Min(100).Max(900).DefaultValue(185).ShowButtons(true));
CVarSliderInt("Camera Transition Speed: %d", CVAR_SETTING("FreeLook.TransitionSpeed"), IntSliderOptions().Color(THEME_COLOR).Min(0).Max(900).DefaultValue(25).ShowButtons(true));
Ship::GuiWindow::EndGroupPanel(0);
}
@ -1405,17 +1401,17 @@ void SohInputEditorWindow::DrawDpadControlPanel() {
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
Ship::GuiWindow::BeginGroupPanel("D-Pad Options", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("D-pad Support on Pause Screen", CVAR_SETTING("DPadOnPause"));
UIWidgets::Tooltip("Navigate Pause with the D-pad\nIf used with \"D-pad as Equip Items\", you must hold C-Up to equip instead of navigate");
UIWidgets::PaddedEnhancementCheckbox("D-pad Support in Text Boxes", CVAR_SETTING("DpadInText"));
UIWidgets::Tooltip("Navigate choices in text boxes, shop item selection, and the file select / name entry screens with the D-pad");
CVarCheckbox("D-pad Support on Pause Screen", CVAR_SETTING("DPadOnPause"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Navigate Pause with the D-pad\nIf used with \"D-pad as Equip Items\", you must hold C-Up to equip instead of navigate"));
CVarCheckbox("D-pad Support in Text Boxes", CVAR_SETTING("DpadInText"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Navigate choices in text boxes, shop item selection, and the file select / name entry screens with the D-pad"));
if (!CVarGetInteger(CVAR_SETTING("DPadOnPause"), 0) && !CVarGetInteger(CVAR_SETTING("DpadInText"), 0)) {
ImGui::BeginDisabled();
}
UIWidgets::PaddedEnhancementCheckbox("D-pad hold change", CVAR_SETTING("DpadHoldChange"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("The cursor will only move a single space no matter how long a D-pad direction is held");
CVarCheckbox("D-pad hold change", CVAR_SETTING("DpadHoldChange"), CheckboxOptions().Color(THEME_COLOR).DefaultValue(true)
.Tooltip("The cursor will only move a single space no matter how long a D-pad direction is held"));
if (!CVarGetInteger(CVAR_SETTING("DPadOnPause"), 0) && !CVarGetInteger(CVAR_SETTING("DpadInText"), 0)) {
ImGui::EndDisabled();
@ -1536,30 +1532,24 @@ void SohInputEditorWindow::DrawLinkTab() {
DrawButtonLine("M2", portIndex, BTN_CUSTOM_MODIFIER2);
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
UIWidgets::PaddedEnhancementCheckbox("Enable speed modifiers", CVAR_SETTING("WalkModifier.Enabled"), true, false);
UIWidgets::Tooltip("Hold the assigned button to change the maximum walking or swimming speed");
CVarCheckbox("Enable speed modifiers", CVAR_SETTING("WalkModifier.Enabled"), CheckboxOptions().Color(THEME_COLOR)
.Tooltip("Hold the assigned button to change the maximum walking or swimming speed"));
if (CVarGetInteger(CVAR_SETTING("WalkModifier.Enabled"), 0)) {
UIWidgets::Spacer(5);
Ship::GuiWindow::BeginGroupPanel("Speed Modifier", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Toggle modifier instead of holding",
CVAR_SETTING("WalkModifier.SpeedToggle"), true, false);
CVarCheckbox("Toggle modifier instead of holding", CVAR_SETTING("WalkModifier.SpeedToggle"), CheckboxOptions().Color(THEME_COLOR));
Ship::GuiWindow::BeginGroupPanel("Walk Modifier", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementCheckbox("Don't affect jump distance/velocity",
CVAR_SETTING("WalkModifier.DoesntChangeJump"), true, false);
UIWidgets::PaddedEnhancementSliderFloat("Walk Modifier 1: %.0f %%", "##WalkMod1",
CVAR_SETTING("WalkModifier.Mapping1"), 0.0f, 5.0f, "", 1.0f,
true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Walk Modifier 2: %.0f %%", "##WalkMod2",
CVAR_SETTING("WalkModifier.Mapping2"), 0.0f, 5.0f, "", 1.0f,
true, true, false, true);
CVarCheckbox("Don't affect jump distance/velocity", CVAR_SETTING("WalkModifier.DoesntChangeJump"), CheckboxOptions().Color(THEME_COLOR));
CVarSliderFloat("Walk Modifier 1: %.0f %%", CVAR_SETTING("WalkModifier.Mapping1"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.0f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
CVarSliderFloat("Walk Modifier 2: %.0f %%", CVAR_SETTING("WalkModifier.Mapping2"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.0f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
Ship::GuiWindow::EndGroupPanel(0);
Ship::GuiWindow::BeginGroupPanel("Swim Modifier", ImGui::GetContentRegionAvail());
UIWidgets::PaddedEnhancementSliderFloat("Swim Modifier 1: %.0f %%", "##SwimMod1",
CVAR_SETTING("WalkModifier.SwimMapping1"), 0.0f, 5.0f, "", 1.0f,
true, true, false, true);
UIWidgets::PaddedEnhancementSliderFloat("Swim Modifier 2: %.0f %%", "##SwimMod2",
CVAR_SETTING("WalkModifier.SwimMapping2"), 0.0f, 5.0f, "", 1.0f,
true, true, false, true);
CVarSliderFloat("Swim Modifier 1: %.0f %%", CVAR_SETTING("WalkModifier.SwimMapping1"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.0f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
CVarSliderFloat("Swim Modifier 2: %.0f %%", CVAR_SETTING("WalkModifier.SwimMapping2"),
FloatSliderOptions().Color(THEME_COLOR).IsPercentage().Min(0.0f).Max(5.0f).DefaultValue(1.0f).ShowButtons(true));
Ship::GuiWindow::EndGroupPanel(0);
Ship::GuiWindow::EndGroupPanel(0);
}
@ -1659,9 +1649,7 @@ void SohInputEditorWindow::DrawDebugPortTab(uint8_t portIndex, std::string custo
UpdateBitmaskToMappingIds(portIndex);
UpdateStickDirectionToMappingIds(portIndex);
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.133f, 0.133f, 0.133f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
PushStyleHeader(THEME_COLOR);
if (ImGui::CollapsingHeader("Buttons", NULL, ImGuiTreeNodeFlags_DefaultOpen)) {
DrawButtonLine("A", portIndex, BTN_A, CHIP_COLOR_N64_BLUE);
@ -1690,19 +1678,20 @@ void SohInputEditorWindow::DrawDebugPortTab(uint8_t portIndex, std::string custo
DrawStickSection(portIndex, Ship::LEFT, 0);
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
PopStyleHeader();
ImGui::EndTabItem();
}
}
void SohInputEditorWindow::DrawClearAllButton(uint8_t portIndex) {
PushStyleButton(THEME_COLOR);
if (ImGui::Button("Clear All", ImGui::CalcTextSize("Clear All") * 2)) {
ImGui::OpenPopup("Clear All##clearAllPopup");
}
PopStyleButton();
if (ImGui::BeginPopupModal("Clear All##clearAllPopup", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("This will clear all mappings for port %d.\n\nContinue?", portIndex + 1);
PushStyleButton(THEME_COLOR);
if (ImGui::Button("Cancel")) {
ImGui::CloseCurrentPopup();
}
@ -1710,6 +1699,7 @@ void SohInputEditorWindow::DrawClearAllButton(uint8_t portIndex) {
Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->ClearAllMappings();
ImGui::CloseCurrentPopup();
}
PopStyleButton();
ImGui::EndPopup();
}
}
@ -1717,22 +1707,23 @@ void SohInputEditorWindow::DrawClearAllButton(uint8_t portIndex) {
void SohInputEditorWindow::DrawSetDefaultsButton(uint8_t portIndex) {
ImGui::SameLine();
auto popupId = StringHelper::Sprintf("setDefaultsPopup##%d", portIndex);
PushStyleButton(THEME_COLOR);
if (ImGui::Button(StringHelper::Sprintf("Set Defaults##%d", portIndex).c_str(),
ImVec2(ImGui::CalcTextSize("Set Defaults") * 2))) {
ImGui::OpenPopup(popupId.c_str());
}
PopStyleButton();
if (ImGui::BeginPopup(popupId.c_str())) {
bool shouldClose = false;
ImGui::PushStyleColor(ImGuiCol_Button, BUTTON_COLOR_KEYBOARD_BEIGE);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, BUTTON_COLOR_KEYBOARD_BEIGE_HOVERED);
PushStyleButton(BUTTON_COLOR_KEYBOARD_BEIGE);
if (ImGui::Button(StringHelper::Sprintf("%s Keyboard", ICON_FA_KEYBOARD_O).c_str())) {
ImGui::OpenPopup("Set Defaults for Keyboard");
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
PopStyleButton();
if (ImGui::BeginPopupModal("Set Defaults for Keyboard", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("This will clear all existing mappings for\nKeyboard on port %d.\n\nContinue?", portIndex + 1);
PushStyleButton(THEME_COLOR);
if (ImGui::Button("Cancel")) {
shouldClose = true;
ImGui::CloseCurrentPopup();
@ -1747,21 +1738,21 @@ void SohInputEditorWindow::DrawSetDefaultsButton(uint8_t portIndex) {
shouldClose = true;
ImGui::CloseCurrentPopup();
}
PopStyleButton();
ImGui::EndPopup();
}
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForDeviceType(Ship::PhysicalDeviceType::SDLGamepad, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
PushStyleButton(buttonColor);
if (ImGui::Button(StringHelper::Sprintf("%s %s", ICON_FA_GAMEPAD, "Gamepad (SDL)").c_str())) {
ImGui::OpenPopup("Set Defaults for Gamepad (SDL)");
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
PopStyleButton();
if (ImGui::BeginPopupModal("Set Defaults for Gamepad (SDL)", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("This will clear all existing mappings for\nGamepad (SDL) on port %d.\n\nContinue?", portIndex + 1);
PushStyleButton(THEME_COLOR);
if (ImGui::Button("Cancel")) {
shouldClose = true;
ImGui::CloseCurrentPopup();
@ -1776,12 +1767,15 @@ void SohInputEditorWindow::DrawSetDefaultsButton(uint8_t portIndex) {
shouldClose = true;
ImGui::CloseCurrentPopup();
}
PopStyleButton();
ImGui::EndPopup();
}
PushStyleButton(THEME_COLOR);
if (ImGui::Button("Cancel") || shouldClose) {
ImGui::CloseCurrentPopup();
}
PopStyleButton();
ImGui::EndPopup();
}

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,6 @@ static float TablesCellsWidth = 300.0f;
static ImGuiTableColumnFlags FlagsTable = ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV;
static ImGuiTableColumnFlags FlagsCell = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoSort;
ImVec4 GetRandomValue();
void CosmeticsEditor_RandomizeAll();
void CosmeticsEditor_RandomizeGroup(CosmeticGroup group);
void CosmeticsEditor_ResetAll();

View file

@ -1,6 +1,9 @@
#include "MessageViewer.h"
#include <soh/SohGui/UIWidgets.hpp>
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "soh/OTRGlobals.h"
#include <textures/message_static/message_static.h>
#include "../custom-message/CustomMessageManager.h"
@ -13,6 +16,8 @@
extern "C" u8 sMessageHasSetSfx;
using namespace UIWidgets;
void MessageViewer::InitElement() {
CustomMessageManager::Instance->AddCustomMessageTable(TABLE_ID);
mTableIdBuf = static_cast<char*>(calloc(MAX_STRING_SIZE, sizeof(char)));
@ -21,8 +26,10 @@ void MessageViewer::InitElement() {
}
void MessageViewer::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest);
ImGui::Text("Table ID");
ImGui::SameLine();
PushStyleInput(THEME_COLOR);
ImGui::InputText("##TableID", mTableIdBuf, MAX_STRING_SIZE, ImGuiInputTextFlags_CallbackCharFilter, UIWidgets::TextFilters::FilterAlphaNum);
UIWidgets::InsertHelpHoverText("Leave blank for vanilla table");
ImGui::Text("Text ID");
@ -38,6 +45,8 @@ void MessageViewer::DrawElement() {
UIWidgets::InsertHelpHoverText("Hexadecimal Text ID of the message to load. Hexadecimal digits only (0-9/A-F).");
break;
}
PopStyleInput();
PushStyleCheckbox(THEME_COLOR);
if (ImGui::RadioButton("Hexadecimal", &mTextIdBase, HEXADECIMAL)) {
memset(mTextIdBuf, 0, sizeof(char) * MAX_STRING_SIZE);
}
@ -45,8 +54,10 @@ void MessageViewer::DrawElement() {
if (ImGui::RadioButton("Decimal", &mTextIdBase, DECIMAL)) {
memset(mTextIdBuf, 0, sizeof(char) * MAX_STRING_SIZE);
}
PopStyleCheckbox();
ImGui::Text("Language");
ImGui::SameLine();
PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo("##Language", mLanguages[mLanguage])) {
// ReSharper disable CppDFAUnreachableCode
for (size_t i = 0; i < mLanguages.size(); i++) {
@ -58,7 +69,9 @@ void MessageViewer::DrawElement() {
}
ImGui::EndCombo();
}
PopStyleCombobox();
UIWidgets::InsertHelpHoverText("Which language to load from the selected text ID");
PushStyleButton(THEME_COLOR);
if (ImGui::Button("Display Message##ExistingMessage")) {
mDisplayExistingMessageClicked = true;
}
@ -66,11 +79,14 @@ void MessageViewer::DrawElement() {
UIWidgets::InsertHelpHoverText("Enter a string using Custom Message Syntax to preview it in-game. "
"Any newline (\\n) characters inserted by the Enter key will be stripped "
"from the output.");
PushStyleInput(THEME_COLOR);
ImGui::InputTextMultiline("##CustomMessage", mCustomMessageBuf, MAX_STRING_SIZE);
PopStyleInput();
if (ImGui::Button("Display Message##CustomMessage")) {
mDisplayCustomMessageClicked = true;
}
// ReSharper restore CppDFAUnreachableCode
PopStyleButton();
ImGui::PopFont();
}
void MessageViewer::UpdateElement() {

View file

@ -1,6 +1,7 @@
#include "actorViewer.h"
#include "../../util.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "soh/ActorDB.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/nametag.h"
@ -59,6 +60,8 @@ std::array<const char*, 12> acMapping = {
"Chest"
};
using namespace UIWidgets;
typedef enum {
ACTORVIEWER_NAMETAGS_NONE,
ACTORVIEWER_NAMETAGS_DESC,
@ -70,29 +73,18 @@ const std::string GetActorDescription(u16 id) {
return ActorDB::Instance->RetrieveEntry(id).entry.valid ? ActorDB::Instance->RetrieveEntry(id).entry.desc : "???";
}
template <typename T> void DrawGroupWithBorder(T&& drawFunc) {
template <typename T> void DrawGroupWithBorder(T&& drawFunc, std::string section) {
// First group encapsulates the inner portion and border
ImGui::BeginGroup();
ImVec2 padding = ImGui::GetStyle().FramePadding;
ImVec2 p0 = ImGui::GetCursorScreenPos();
ImGui::SetCursorScreenPos(ImVec2(p0.x + padding.x, p0.y + padding.y));
ImGui::BeginChild(std::string("##" + section).c_str(), ImVec2(0, 0),
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY);
// Second group encapsulates just the inner portion
ImGui::BeginGroup();
ImGui::AlignTextToFramePadding();
drawFunc();
ImGui::Dummy(padding);
ImGui::EndGroup();
ImVec2 p1 = ImGui::GetItemRectMax();
p1.x += padding.x;
ImVec4 borderCol = ImGui::GetStyle().Colors[ImGuiCol_Border];
ImGui::GetWindowDrawList()->AddRect(
p0, p1, IM_COL32(borderCol.x * 255, borderCol.y * 255, borderCol.z * 255, borderCol.w * 255));
ImGui::EndGroup();
ImGui::EndChild();
}
void PopulateActorDropdown(int i, std::vector<Actor*>& data) {
@ -938,10 +930,12 @@ void ActorViewerWindow::DrawElement() {
static std::string filler = "Please select";
static std::vector<Actor*> list;
static u16 lastSceneId = 0;
static char searchString[64] = "";
static std::string searchString = "";
static s16 currentSelectedInDropdown;
static std::vector<u16> actors;
ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest);
if (gPlayState != nullptr) {
needs_reset = lastSceneId != gPlayState->sceneNum;
if (needs_reset) {
@ -951,13 +945,13 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select";
list.clear();
needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
searchString = "";
currentSelectedInDropdown = -1;
actors.clear();
}
lastSceneId = gPlayState->sceneNum;
PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo("Actor Type", acMapping[category])) {
for (int i = 0; i < acMapping.size(); i++) {
if (ImGui::Selectable(acMapping[i])) {
@ -990,7 +984,9 @@ void ActorViewerWindow::DrawElement() {
}
ImGui::EndCombo();
}
PopStyleCombobox();
PushStyleHeader(THEME_COLOR);
if (ImGui::TreeNode("Selected Actor")) {
DrawGroupWithBorder([&]() {
ImGui::Text("Name: %s", ActorDB::Instance->RetrieveEntry(display->id).name.c_str());
@ -998,46 +994,52 @@ void ActorViewerWindow::DrawElement() {
ImGui::Text("Category: %s", acMapping[display->category]);
ImGui::Text("ID: %d", display->id);
ImGui::Text("Parameters: %d", display->params);
});
}, "Selected Actor");
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
DrawGroupWithBorder([&]() {
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
PushStyleInput(THEME_COLOR);
ImGui::Text("Actor Position");
ImGui::InputScalar("x pos", ImGuiDataType_Float, &display->world.pos.x);
ImGui::InputScalar("X##CurPos", ImGuiDataType_Float, &display->world.pos.x);
ImGui::InputScalar("Y##CurPos", ImGuiDataType_Float, &display->world.pos.y);
ImGui::InputScalar("Z##CurPos", ImGuiDataType_Float, &display->world.pos.z);
ImGui::PopItemWidth();
PopStyleInput();
}, "Actor Position");
ImGui::SameLine();
ImGui::InputScalar("y pos", ImGuiDataType_Float, &display->world.pos.y);
ImGui::SameLine();
ImGui::InputScalar("z pos", ImGuiDataType_Float, &display->world.pos.z);
});
DrawGroupWithBorder([&]() {
PushStyleInput(THEME_COLOR);
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
ImGui::Text("Actor Rotation");
ImGui::InputScalar("x rot", ImGuiDataType_S16, &display->world.rot.x);
ImGui::SameLine();
ImGui::InputScalar("y rot", ImGuiDataType_S16, &display->world.rot.y);
ImGui::SameLine();
ImGui::InputScalar("z rot", ImGuiDataType_S16, &display->world.rot.z);
});
ImGui::InputScalar("X##CurRot", ImGuiDataType_S16, &display->world.rot.x);
ImGui::InputScalar("Y##CurRot", ImGuiDataType_S16, &display->world.rot.y);
ImGui::InputScalar("Z##CurRot", ImGuiDataType_S16, &display->world.rot.z);
ImGui::PopItemWidth();
PopStyleInput();
}, "Actor Rotation");
if (display->category == ACTORCAT_BOSS || display->category == ACTORCAT_ENEMY) {
PushStyleInput(THEME_COLOR);
ImGui::InputScalar("Enemy Health", ImGuiDataType_U8, &display->colChkInfo.health);
PopStyleInput();
UIWidgets::InsertHelpHoverText("Some actors might not use this!");
}
DrawGroupWithBorder([&]() {
ImGui::Text("flags");
UIWidgets::DrawFlagArray32("flags", display->flags);
});
}, "flags");
ImGui::SameLine();
DrawGroupWithBorder([&]() {
ImGui::Text("bgCheckFlags");
UIWidgets::DrawFlagArray16("bgCheckFlags", display->bgCheckFlags);
});
}, "bgCheckFlags");
if (ImGui::Button("Refresh")) {
if (Button("Refresh", ButtonOptions().Color(THEME_COLOR))) {
PopulateActorDropdown(category, list);
switch (rm) {
case INTERACT:
@ -1053,13 +1055,13 @@ void ActorViewerWindow::DrawElement() {
}
}
if (ImGui::Button("Go to Actor")) {
if (Button("Go to Actor", ButtonOptions().Color(THEME_COLOR))) {
Player* player = GET_PLAYER(gPlayState);
Math_Vec3f_Copy(&player->actor.world.pos, &display->world.pos);
Math_Vec3f_Copy(&player->actor.home.pos, &player->actor.world.pos);
}
if (ImGui::Button("Fetch from Target")) {
if (Button("Fetch from Target", ButtonOptions().Color(THEME_COLOR).Tooltip("Grabs actor with target arrow above it. You might need C-Up for enemies"))) {
Player* player = GET_PLAYER(gPlayState);
fetch = player->talkActor;
if (fetch != NULL) {
@ -1069,8 +1071,7 @@ void ActorViewerWindow::DrawElement() {
rm = TARGET;
}
}
UIWidgets::InsertHelpHoverText("Grabs actor with target arrow above it. You might need C-Up for enemies");
if (ImGui::Button("Fetch from Held")) {
if (Button("Fetch from Held", ButtonOptions().Color(THEME_COLOR).Tooltip("Grabs actor that Link is holding"))) {
Player* player = GET_PLAYER(gPlayState);
fetch = player->heldActor;
if (fetch != NULL) {
@ -1080,8 +1081,7 @@ void ActorViewerWindow::DrawElement() {
rm = HELD;
}
}
UIWidgets::InsertHelpHoverText("Grabs actor that Link is holding");
if (ImGui::Button("Fetch from Interaction")) {
if (Button("Fetch from Interaction", ButtonOptions().Color(THEME_COLOR).Tooltip("Grabs actor from \"interaction range\""))) {
Player* player = GET_PLAYER(gPlayState);
fetch = player->interactRangeActor;
if (fetch != NULL) {
@ -1091,21 +1091,21 @@ void ActorViewerWindow::DrawElement() {
rm = INTERACT;
}
}
UIWidgets::InsertHelpHoverText("Grabs actor from \"interaction range\"");
ImGui::TreePop();
}
if (ImGui::TreeNode("New...")) {
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
//ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
if (ImGui::InputText("Search Actor", searchString, ARRAY_COUNT(searchString))) {
actors = GetActorsWithDescriptionContainingString(std::string(searchString));
if (InputString("Search Actor", &searchString, InputOptions().Color(THEME_COLOR))) {
actors = GetActorsWithDescriptionContainingString(searchString);
currentSelectedInDropdown = -1;
}
if (searchString[0] != 0 && !actors.empty()) {
if (!SohUtils::IsStringEmpty(searchString) && !actors.empty()) {
std::string preview = currentSelectedInDropdown == -1 ? "Please Select" : ActorDB::Instance->RetrieveEntry(actors[currentSelectedInDropdown]).desc;
PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo("Results", preview.c_str())) {
for (u8 i = 0; i < actors.size(); i++) {
if (ImGui::Selectable(
@ -1118,6 +1118,7 @@ void ActorViewerWindow::DrawElement() {
}
ImGui::EndCombo();
}
PopStyleCombobox();
}
ImGui::Text("%s", GetActorDescription(newActor.id).c_str());
@ -1125,44 +1126,51 @@ void ActorViewerWindow::DrawElement() {
newActor.params = 0;
}
UIWidgets::EnhancementCheckbox("Advanced mode", CVAR_DEVELOPER_TOOLS("ActorViewer.AdvancedParams"));
UIWidgets::InsertHelpHoverText("Changes the actor specific param menus with a direct input");
CVarCheckbox("Advanced mode", CVAR_DEVELOPER_TOOLS("ActorViewer.AdvancedParams"), CheckboxOptions().Tooltip("Changes the actor specific param menus with a direct input"));
if (CVarGetInteger(CVAR_DEVELOPER_TOOLS("ActorViewer.AdvancedParams"), 0)) {
PushStyleInput(THEME_COLOR);
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
PopStyleInput();
} else if (std::find(noParamsActors.begin(), noParamsActors.end(), newActor.id) == noParamsActors.end()) {
CreateActorSpecificData();
if (actorSpecificData.find(newActor.id) == actorSpecificData.end()) {
PushStyleInput(THEME_COLOR);
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
PopStyleInput();
} else {
DrawGroupWithBorder([&]() {
ImGui::Text("Actor Specific Data");
newActor.params = actorSpecificData[newActor.id](newActor.params);
});
}, "Actor Specific Data");
}
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
DrawGroupWithBorder([&]() {
PushStyleInput(THEME_COLOR);
ImGui::Text("New Actor Position");
ImGui::InputScalar("posX", ImGuiDataType_Float, &newActor.pos.x);
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
ImGui::InputScalar("X##NewPos", ImGuiDataType_Float, &newActor.pos.x);
ImGui::InputScalar("Y##NewPos", ImGuiDataType_Float, &newActor.pos.y);
ImGui::InputScalar("Z##NewPos", ImGuiDataType_Float, &newActor.pos.z);
ImGui::PopItemWidth();
PopStyleInput();
}, "New Actor Position");
ImGui::SameLine();
ImGui::InputScalar("posY", ImGuiDataType_Float, &newActor.pos.y);
ImGui::SameLine();
ImGui::InputScalar("posZ", ImGuiDataType_Float, &newActor.pos.z);
});
DrawGroupWithBorder([&]() {
PushStyleInput(THEME_COLOR);
ImGui::Text("New Actor Rotation");
ImGui::InputScalar("rotX", ImGuiDataType_S16, &newActor.rot.x);
ImGui::SameLine();
ImGui::InputScalar("rotY", ImGuiDataType_S16, &newActor.rot.y);
ImGui::SameLine();
ImGui::InputScalar("rotZ", ImGuiDataType_S16, &newActor.rot.z);
});
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
ImGui::InputScalar("X##NewRot", ImGuiDataType_S16, &newActor.rot.x);
ImGui::InputScalar("Y##NewRot", ImGuiDataType_S16, &newActor.rot.y);
ImGui::InputScalar("Z##NewRot", ImGuiDataType_S16, &newActor.rot.z);
ImGui::PopItemWidth();
PopStyleInput();
}, "New Actor Rotation");
if (ImGui::Button("Fetch from Link")) {
if (Button("Fetch from Link", ButtonOptions().Color(THEME_COLOR))) {
Player* player = GET_PLAYER(gPlayState);
Vec3f newPos = player->actor.world.pos;
Vec3s newRot = player->actor.world.rot;
@ -1170,7 +1178,7 @@ void ActorViewerWindow::DrawElement() {
newActor.rot = newRot;
}
if (ImGui::Button("Spawn")) {
if (Button("Spawn", ButtonOptions().Color(THEME_COLOR))) {
if (ActorDB::Instance->RetrieveEntry(newActor.id).entry.valid) {
Actor_Spawn(&gPlayState->actorCtx, gPlayState, newActor.id, newActor.pos.x, newActor.pos.y,
newActor.pos.z, newActor.rot.x, newActor.rot.y, newActor.rot.z, newActor.params, 0);
@ -1179,7 +1187,7 @@ void ActorViewerWindow::DrawElement() {
}
}
if (ImGui::Button("Spawn as Child")) {
if (Button("Spawn as Child", ButtonOptions().Color(THEME_COLOR))) {
Actor* parent = display;
if (parent != NULL) {
if (newActor.id >= 0 && newActor.id < ACTOR_ID_MAX &&
@ -1193,28 +1201,26 @@ void ActorViewerWindow::DrawElement() {
}
}
if (ImGui::Button("Reset")) {
if (Button("Reset", ButtonOptions().Color(THEME_COLOR))) {
newActor = { 0, 0, { 0, 0, 0 }, { 0, 0, 0 } };
}
ImGui::TreePop();
}
PopStyleHeader();
static const char* nameTagOptions[] = {
"None",
"Short Description",
"Actor ID",
"Both"
static std::unordered_map<int32_t, const char*> nameTagOptions = {
{ 0, "None" },
{ 1, "Short Description" },
{ 2, "Actor ID" },
{ 3, "Both" },
};
UIWidgets::Spacer(0);
ImGui::Text("Actor Name Tags");
if (UIWidgets::EnhancementCombobox(CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), nameTagOptions, ACTORVIEWER_NAMETAGS_NONE)) {
if (CVarCombobox("Actor Name Tags", CVAR_DEVELOPER_TOOLS("ActorViewer.NameTags"), nameTagOptions,
ComboboxOptions().Color(THEME_COLOR).Tooltip("Adds \"name tags\" above actors for identification"))) {
NameTag_RemoveAllByTag(DEBUG_ACTOR_NAMETAG_TAG);
ActorViewer_AddTagForAllActors();
}
UIWidgets::Tooltip("Adds \"name tags\" above actors for identification");
} else {
ImGui::Text("Global Context needed for actor info!");
if (needs_reset) {
@ -1223,13 +1229,12 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select";
list.clear();
needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
searchString = "";
currentSelectedInDropdown = -1;
actors.clear();
}
}
ImGui::PopFont();
}
void ActorViewerWindow::InitElement() {

View file

@ -1,6 +1,7 @@
#include "colViewer.h"
#include "../../frame_interpolation.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include <vector>
#include <string>
@ -19,12 +20,12 @@ extern "C" {
extern PlayState* gPlayState;
}
enum class ColRenderSetting { Disabled, Solid, Transparent };
typedef enum ColRenderSetting { ColRenderDisabled, ColRenderSolid, ColRenderTransparent } ColRenderSetting ;
static const char* ColRenderSettingNames[] = {
"Disabled",
"Solid",
"Transparent",
static std::unordered_map<int32_t, const char*> ColRenderSettingNames = {
{ ColRenderDisabled, "Disabled" },
{ ColRenderSolid, "Solid" },
{ ColRenderTransparent, "Transparent" },
};
ImVec4 scene_col;
@ -53,45 +54,69 @@ static std::vector<Vtx> cylinderVtx;
static std::vector<Gfx> sphereGfx;
static std::vector<Vtx> sphereVtx;
using namespace UIWidgets;
// Draws the ImGui window for the collision viewer
void ColViewerWindow::DrawElement() {
UIWidgets::EnhancementCheckbox("Enabled", CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"));
CheckboxOptions checkOpt = CheckboxOptions().Color(THEME_COLOR);
ComboboxOptions comboOpt = ComboboxOptions().Color(THEME_COLOR);
CVarCheckbox("Enabled", CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), checkOpt);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Scene", CVAR_DEVELOPER_TOOLS("ColViewer.Scene"), ColRenderSettingNames, COLVIEW_DISABLED);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Bg Actors", CVAR_DEVELOPER_TOOLS("ColViewer.BGActors"), ColRenderSettingNames, COLVIEW_DISABLED);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Col Check", CVAR_DEVELOPER_TOOLS("ColViewer.ColCheck"), ColRenderSettingNames, COLVIEW_DISABLED);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Waterbox", CVAR_DEVELOPER_TOOLS("ColViewer.Waterbox"), ColRenderSettingNames, COLVIEW_DISABLED);
CVarCombobox("Scene", CVAR_DEVELOPER_TOOLS("ColViewer.Scene"), ColRenderSettingNames, comboOpt);
CVarCombobox("Bg Actors", CVAR_DEVELOPER_TOOLS("ColViewer.BGActors"), ColRenderSettingNames, comboOpt);
CVarCombobox("Col Check", CVAR_DEVELOPER_TOOLS("ColViewer.ColCheck"), ColRenderSettingNames, comboOpt);
CVarCombobox("Waterbox", CVAR_DEVELOPER_TOOLS("ColViewer.Waterbox"), ColRenderSettingNames, comboOpt);
UIWidgets::EnhancementCheckbox("Apply as decal", CVAR_DEVELOPER_TOOLS("ColViewer.Decal"), false, "", UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::InsertHelpHoverText("Applies the collision as a decal display. This can be useful if there is z-fighting occuring "
"with the scene geometry, but can cause other artifacts.");
UIWidgets::EnhancementCheckbox("Shaded", CVAR_DEVELOPER_TOOLS("ColViewer.Shaded"));
UIWidgets::InsertHelpHoverText("Applies the scene's shading to the collision display.");
CVarCheckbox("Apply as decal", CVAR_DEVELOPER_TOOLS("ColViewer.Decal"),
checkOpt.DefaultValue(true).Tooltip("Applies the collision as a decal display. This can be useful if there is z-fighting occuring "
"with the scene geometry, but can cause other artifacts."));
CVarCheckbox("Shaded", CVAR_DEVELOPER_TOOLS("ColViewer.Shaded"), checkOpt.DefaultValue(false).Tooltip("Applies the scene's shading to the collision display."));
// This has to be duplicated in both code paths due to the nature of ImGui::IsItemHovered()
const std::string colorHelpText = "View and change the colors used for collision display.";
PushStyleHeader(THEME_COLOR);
if (ImGui::TreeNode("Colors")) {
UIWidgets::InsertHelpHoverText(colorHelpText);
UIWidgets::Tooltip(colorHelpText.c_str());
UIWidgets::EnhancementColor("Normal", CVAR_DEVELOPER_TOOLS("ColViewer.ColorNormal"), scene_col, ImVec4(255, 255, 255, 255), false);
UIWidgets::EnhancementColor("Hookshot", CVAR_DEVELOPER_TOOLS("ColViewer.ColorHookshot"), hookshot_col, ImVec4(128, 128, 255, 255),
false);
UIWidgets::EnhancementColor("Entrance", CVAR_DEVELOPER_TOOLS("ColViewer.ColorEntrance"), entrance_col, ImVec4(0, 255, 0, 255), false);
UIWidgets::EnhancementColor("Special Surface (Grass/Sand/Etc)", CVAR_DEVELOPER_TOOLS("ColViewer.ColorSpecialSurface"),
specialSurface_col, ImVec4(192, 255, 192, 255), false);
UIWidgets::EnhancementColor("Interactable (Vines/Crawlspace/Etc)", CVAR_DEVELOPER_TOOLS("ColViewer.ColorInteractable"),
interactable_col, ImVec4(192, 0, 192, 255), false);
UIWidgets::EnhancementColor("Slope", CVAR_DEVELOPER_TOOLS("ColViewer.ColorSlope"), slope_col, ImVec4(255, 255, 128, 255), false);
UIWidgets::EnhancementColor("Void", CVAR_DEVELOPER_TOOLS("ColViewer.ColorVoid"), void_col, ImVec4(255, 0, 0, 255), false);
UIWidgets::EnhancementColor("OC", CVAR_DEVELOPER_TOOLS("ColViewer.ColorOC"), oc_col, ImVec4(255, 255, 255, 255), false);
UIWidgets::EnhancementColor("AC", CVAR_DEVELOPER_TOOLS("ColViewer.ColorAC"), ac_col, ImVec4(0, 0, 255, 255), false);
UIWidgets::EnhancementColor("AT", CVAR_DEVELOPER_TOOLS("ColViewer.ColorAT"), at_col, ImVec4(255, 0, 0, 255), false);
UIWidgets::EnhancementColor("Waterbox", CVAR_DEVELOPER_TOOLS("ColViewer.ColorWaterbox"), waterbox_col, ImVec4(0, 0, 255, 255), false);
if (CVarColorPicker("Normal", CVAR_DEVELOPER_TOOLS("ColViewer.ColorNormal"), { 255, 255, 255, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
scene_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorNormal"), { 255, 255, 255, 255 }));
}
if (CVarColorPicker("Hookshot", CVAR_DEVELOPER_TOOLS("ColViewer.ColorHookshot"), { 128, 128, 255, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
hookshot_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorHookshot"), { 128, 128, 255, 255 }));
}
if (CVarColorPicker("Entrance", CVAR_DEVELOPER_TOOLS("ColViewer.ColorEntrance"), { 0, 255, 0, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
entrance_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorEntrance"), { 0, 255, 0, 255 }));
}
if (CVarColorPicker("Special Surface (Grass/Sand/Etc)", CVAR_DEVELOPER_TOOLS("ColViewer.ColorSpecialSurface"), { 192, 255, 192, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
specialSurface_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSpecialSurface"), { 192, 255, 192, 255 }));
}
if (CVarColorPicker("Interactable (Vines/Crawlspace/Etc)", CVAR_DEVELOPER_TOOLS("ColViewer.ColorInteractable"), { 192, 0, 192, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
interactable_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorInteractable"), { 192, 0, 192, 255 }));
}
if (CVarColorPicker("Slope", CVAR_DEVELOPER_TOOLS("ColViewer.ColorSlope"), { 255, 255, 128, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
slope_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSlope"), { 255, 255, 128, 255 }));
}
if (CVarColorPicker("Void", CVAR_DEVELOPER_TOOLS("ColViewer.ColorVoid"), { 255, 0, 0, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
void_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorVoid"), { 255, 0, 0, 255 }));
}
if (CVarColorPicker("OC", CVAR_DEVELOPER_TOOLS("ColViewer.ColorOC"), { 255, 255, 255, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
oc_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorOC"), { 255, 255, 255, 255 }));
}
if (CVarColorPicker("AC", CVAR_DEVELOPER_TOOLS("ColViewer.ColorAC"), { 0, 0, 255, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
ac_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAC"), { 0, 0, 255, 255 }));
}
if (CVarColorPicker("AT", CVAR_DEVELOPER_TOOLS("ColViewer.ColorAT"), { 255, 0, 0, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
at_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAT"), { 255, 0, 0, 255 }));
}
if (CVarColorPicker("Waterbox", CVAR_DEVELOPER_TOOLS("ColViewer.ColorWaterbox"), { 0, 0, 255, 255 }, false, ColorPickerResetButton | ColorPickerRandomButton, THEME_COLOR)) {
waterbox_col = VecFromRGBA8(CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorWaterbox"), { 0, 0, 255, 255 }));
}
ImGui::TreePop();
} else {
UIWidgets::InsertHelpHoverText(colorHelpText);
UIWidgets::Tooltip(colorHelpText.c_str());
}
PopStyleHeader();
}
// Calculates the normal for a triangle at the 3 specified points
@ -287,7 +312,7 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
uint64_t cm;
uint32_t gm;
if (setting == ColRenderSetting::Transparent) {
if (setting == ColRenderTransparent) {
rm = Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL;
blc1 = GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA);
blc2 = GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA);
@ -301,7 +326,7 @@ void InitGfx(std::vector<Gfx>& gfx, ColRenderSetting setting) {
if (CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Decal"), 1) != 0) {
rm |= ZMODE_DEC;
} else if (setting == ColRenderSetting::Transparent) {
} else if (setting == ColRenderTransparent) {
rm |= ZMODE_XLU;
} else {
rm |= ZMODE_OPA;
@ -340,21 +365,21 @@ void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
CollisionPoly* poly = &col->polyList[i];
if (SurfaceType_IsHookshotSurface(&gPlayState->colCtx, poly, bgId)) {
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorHookshot"), { 128, 128, 255, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorHookshot.Value"), { 128, 128, 255, 255 });
} else if (func_80041D94(&gPlayState->colCtx, poly, bgId) > 0x01) {
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorInteractable"), {192, 0, 192, 255});
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorInteractable.Value"), {192, 0, 192, 255});
} else if (func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x0C) {
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorVoid"), { 255, 0, 0, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorVoid.Value"), { 255, 0, 0, 255 });
} else if (SurfaceType_GetSceneExitIndex(&gPlayState->colCtx, poly, bgId) ||
func_80041E80(&gPlayState->colCtx, poly, bgId) == 0x05) {
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorEntrance"), { 0, 255, 0, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorEntrance.Value"), { 0, 255, 0, 255 });
} else if (func_80041D4C(&gPlayState->colCtx, poly, bgId) != 0 ||
SurfaceType_IsWallDamage(&gPlayState->colCtx, poly, bgId)) {
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSpecialSurface"), { 192, 255, 192, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSpecialSurface.Value"), { 192, 255, 192, 255 });
} else if (SurfaceType_GetSlope(&gPlayState->colCtx, poly, bgId) == 0x01) {
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSlope"), { 255, 255, 128, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorSlope.Value"), { 255, 255, 128, 255 });
} else {
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorNormal"), { 255, 255, 255, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorNormal.Value"), { 255, 255, 255, 255 });
}
if (color.r != lastColorR || color.g != lastColorG || color.b != lastColorB) {
@ -404,11 +429,11 @@ void DrawDynapoly(std::vector<Gfx>& dl, CollisionHeader* col, int32_t bgId) {
void DrawSceneCollision() {
ColRenderSetting showSceneColSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Scene"), COLVIEW_DISABLED);
if (showSceneColSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
if (showSceneColSetting == ColRenderDisabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return;
}
std::vector<Gfx>& dl = (showSceneColSetting == ColRenderSetting::Transparent) ? xluDl : opaDl;
std::vector<Gfx>& dl = (showSceneColSetting == ColRenderTransparent) ? xluDl : opaDl;
InitGfx(dl, showSceneColSetting);
dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH));
@ -418,11 +443,11 @@ void DrawSceneCollision() {
// Draws all Bg Actors
void DrawBgActorCollision() {
ColRenderSetting showBgActorSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.BGActors"), COLVIEW_DISABLED);
if (showBgActorSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
if (showBgActorSetting == ColRenderDisabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return;
}
std::vector<Gfx>& dl = (showBgActorSetting == ColRenderSetting::Transparent) ? xluDl : opaDl;
std::vector<Gfx>& dl = (showBgActorSetting == ColRenderTransparent) ? xluDl : opaDl;
InitGfx(dl, showBgActorSetting);
dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH));
@ -543,22 +568,22 @@ void DrawColCheckList(std::vector<Gfx>& dl, Collider** objects, int32_t count) {
// Draws all Col Check objects
void DrawColCheckCollision() {
ColRenderSetting showColCheckSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.ColCheck"), COLVIEW_DISABLED);
if (showColCheckSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
if (showColCheckSetting == ColRenderDisabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return;
}
std::vector<Gfx>& dl = (showColCheckSetting == ColRenderSetting::Transparent) ? xluDl : opaDl;
std::vector<Gfx>& dl = (showColCheckSetting == ColRenderTransparent) ? xluDl : opaDl;
InitGfx(dl, showColCheckSetting);
dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH));
CollisionCheckContext& col = gPlayState->colChkCtx;
Color_RGBA8 color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorOC"), { 255, 255, 255, 255 });
Color_RGBA8 color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorOC.Value"), { 255, 255, 255, 255 });
dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
DrawColCheckList(dl, col.colOC, col.colOCCount);
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAC"), { 0, 0, 255, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAC.Value"), { 0, 0, 255, 255 });
dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
DrawColCheckList(dl, col.colAC, col.colACCount);
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAT"), { 0, 0, 255, 255 });
color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorAT.Value"), { 0, 0, 255, 255 });
dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));
DrawColCheckList(dl, col.colAT, col.colATCount);
@ -595,15 +620,15 @@ extern "C" f32 zdWaterBoxMinY;
// Draws all waterboxes
void DrawWaterboxList() {
ColRenderSetting showWaterboxSetting = (ColRenderSetting)CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Waterbox"), COLVIEW_DISABLED);
if (showWaterboxSetting == ColRenderSetting::Disabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
if (showWaterboxSetting == ColRenderDisabled || !CVarGetInteger(CVAR_DEVELOPER_TOOLS("ColViewer.Enabled"), 0)) {
return;
}
std::vector<Gfx>& dl = (showWaterboxSetting == ColRenderSetting::Transparent) ? xluDl : opaDl;
std::vector<Gfx>& dl = (showWaterboxSetting == ColRenderTransparent) ? xluDl : opaDl;
InitGfx(dl, showWaterboxSetting);
dl.push_back(gsSPMatrix(&gMtxClear, G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH));
Color_RGBA8 color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorWaterbox"), { 0, 0, 255, 255 });
Color_RGBA8 color = CVarGetColor(CVAR_DEVELOPER_TOOLS("ColViewer.ColorWaterbox.Value"), { 0, 0, 255, 255 });
dl.push_back(gsDPSetPrimColor(0, 0, color.r, color.g, color.b, 255));

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
#include "actorViewer.h"
#include "soh/util.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "ResourceManager.h"
#include "DisplayList.h"
#include "soh/OTRGlobals.h"
@ -90,11 +91,14 @@ void PerformDisplayListSearch() {
}
void DLViewerWindow::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
// Debounce the search field as listing otr files is expensive
UIWidgets::PushStyleInput(THEME_COLOR);
if (ImGui::InputText("Search Display Lists", searchString, ARRAY_COUNT(searchString))) {
doSearch = true;
searchDebounceFrames = 30;
}
UIWidgets::PopStyleInput();
if (doSearch) {
if (searchDebounceFrames == 0) {
@ -105,6 +109,7 @@ void DLViewerWindow::DrawElement() {
searchDebounceFrames--;
}
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo("Active Display List", activeDisplayList.c_str())) {
for (size_t i = 0; i < displayListSearchResults.size(); i++) {
if (ImGui::Selectable(displayListSearchResults[i].c_str())) {
@ -114,8 +119,10 @@ void DLViewerWindow::DrawElement() {
}
ImGui::EndCombo();
}
UIWidgets::PopStyleCombobox();
if (activeDisplayList == "") {
ImGui::PopFont();
return;
}
@ -124,6 +131,7 @@ void DLViewerWindow::DrawElement() {
if (res->GetInitData()->Type != static_cast<uint32_t>(Fast::ResourceType::DisplayList)) {
ImGui::Text("Resource type is not a Display List. Please choose another.");
ImGui::PopFont();
return;
}
@ -144,6 +152,7 @@ void DLViewerWindow::DrawElement() {
ImGui::SameLine();
ImGui::PushItemWidth(175.0f);
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo(("CMD" + id).c_str(), cmdLabel.c_str())) {
if (ImGui::Selectable("gsDPSetPrimColor") && cmd != G_SETPRIMCOLOR) {
*gfx = gsDPSetPrimColor(0, 0, 0, 0, 0, 255);
@ -162,6 +171,7 @@ void DLViewerWindow::DrawElement() {
}
ImGui::EndCombo();
}
UIWidgets::PopStyleCombobox();
ImGui::PopItemWidth();
@ -194,9 +204,11 @@ void DLViewerWindow::DrawElement() {
if (cmd == G_SETGRAYSCALE) {
bool* state = (bool*)&gfx->words.w1;
ImGui::SameLine();
UIWidgets::PushStyleCheckbox(THEME_COLOR);
if (ImGui::Checkbox(("state" + id).c_str(), state)) {
//
}
UIWidgets::PopStyleCheckbox();
}
if (cmd == G_SETTILE) {
ImGui::SameLine();
@ -317,8 +329,10 @@ void DLViewerWindow::DrawElement() {
}
} catch (const std::exception& e) {
ImGui::Text("Error displaying DL instructions.");
ImGui::PopFont();
return;
}
ImGui::PopFont();
}
void DLViewerWindow::InitElement() {

View file

@ -1,5 +1,6 @@
#include "valueViewer.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "soh/OTRGlobals.h"
#include "soh/ShipInit.hpp"
@ -142,13 +143,15 @@ void RegisterValueViewerHooks() {
RegisterShipInitFunc initFunc(RegisterValueViewerHooks, { CVAR_NAME });
void ValueViewerWindow::DrawElement() {
UIWidgets::PaddedEnhancementCheckbox("Enable Printing", CVAR_NAME);
ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest);
UIWidgets::CVarCheckbox("Enable Printing", CVAR_NAME, UIWidgets::CheckboxOptions().Color(THEME_COLOR));
ImGui::BeginGroup();
static int selectedElement = -1;
std::string selectedElementText = (selectedElement == -1) ? "Select a value" : (
std::string(valueTable[selectedElement].name) + " (" + std::string(valueTable[selectedElement].path) + ")"
);
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo("##valueViewerElement", selectedElementText.c_str())) {
for (int i = 0; i < valueTable.size(); i++) {
if (valueTable[i].isActive) continue;
@ -165,20 +168,28 @@ void ValueViewerWindow::DrawElement() {
}
ImGui::EndCombo();
}
UIWidgets::PopStyleCombobox();
ImGui::SameLine();
UIWidgets::PushStyleButton(THEME_COLOR);
if (selectedElement != -1 && ImGui::Button("+")) {
valueTable[selectedElement].isActive = true;
selectedElement = -1;
}
UIWidgets::PopStyleButton();
ImGui::EndGroup();
for (int i = 0; i < valueTable.size(); i++) {
ValueTableElement& element = valueTable[i];
if (!element.isActive || (gPlayState == NULL && element.requiresPlayState)) continue;
if (ImGui::Button(("x##" + std::string(element.name)).c_str())) {
UIWidgets::PushStyleButton(THEME_COLOR);
UIWidgets::PushStyleCheckbox(THEME_COLOR);
ImGui::AlignTextToFramePadding();
if (ImGui::Button((ICON_FA_TIMES + std::string("##") + std::string(element.name)).c_str())) {
element.isActive = false;
element.isPrinted = false;
}
UIWidgets::PopStyleCheckbox();
UIWidgets::PopStyleButton();
ImGui::SameLine();
ImGui::Text("%s:", element.name);
ImGui::SameLine();
@ -212,7 +223,7 @@ void ValueViewerWindow::DrawElement() {
break;
}
ImGui::SameLine();
UIWidgets::PushStyleCheckbox(THEME_COLOR);
if (element.type <= TYPE_U32) {
ImGui::Checkbox(("Hex##" + std::string(element.name)).c_str(), &element.typeFormat);
ImGui::SameLine();
@ -220,23 +231,30 @@ void ValueViewerWindow::DrawElement() {
ImGui::Checkbox(("Trim##" + std::string(element.name)).c_str(), &element.typeFormat);
ImGui::SameLine();
}
UIWidgets::PopStyleCheckbox();
ImGui::BeginGroup();
if (CVarGetInteger(CVAR_DEVELOPER_TOOLS("ValueViewerEnablePrinting"), 0)) {
UIWidgets::PushStyleCheckbox(THEME_COLOR);
ImGui::Checkbox(("Print##" + std::string(element.name)).c_str(), &element.isPrinted);
UIWidgets::PopStyleCheckbox();
if (element.isPrinted) {
char* prefix = (char*)element.prefix.c_str();
ImGui::SameLine();
ImGui::SetNextItemWidth(80.0f);
UIWidgets::PushStyleInput(THEME_COLOR);
if (ImGui::InputText(("Prefix##" + std::string(element.name)).c_str(), prefix, 10)) {
element.prefix = prefix;
}
UIWidgets::PopStyleInput();
ImGui::SameLine();
ImGui::ColorEdit3(("##color" + std::string(element.name)).c_str(), (float*)&element.color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel);
ImGui::SameLine();
UIWidgets::PushStyleCheckbox(THEME_COLOR);
if (ImGui::Button(("Position##" + std::string(element.name)).c_str())) {
ImGui::OpenPopup(("Position Picker##" + std::string(element.name)).c_str());
}
UIWidgets::PopStyleCheckbox();
if (ImGui::BeginPopup(("Position Picker##" + std::string(element.name)).c_str())) {
ImGui::DragInt("X", (int*)&element.x, 1.0f, 0, 44);
ImGui::DragInt("Y", (int*)&element.y, 1.0f, 0, 29);
@ -246,6 +264,7 @@ void ValueViewerWindow::DrawElement() {
}
ImGui::EndGroup();
}
ImGui::PopFont();
}
void ValueViewerWindow::InitElement() {

View file

@ -39,7 +39,7 @@ typedef enum {
MIRRORED_WORLD_ALWAYS,
MIRRORED_WORLD_RANDOM,
MIRRORED_WORLD_RANDOM_SEEDED,
MIRRORED_WORLD_DUNGEONS_All,
MIRRORED_WORLD_DUNGEONS_ALL,
MIRRORED_WORLD_DUNGEONS_VANILLA,
MIRRORED_WORLD_DUNGEONS_MQ,
MIRRORED_WORLD_DUNGEONS_RANDOM,
@ -75,6 +75,18 @@ typedef enum {
BONK_DAMAGE_OHKO,
} BonkDamage;
typedef enum {
DAMAGE_VANILLA,
DAMAGE_DOUBLE,
DAMAGE_QUADRUPLE,
DAMAGE_OCTUPLE,
DAMAGE_FOOLISH,
DAMAGE_RIDICULOUS,
DAMAGE_MERCILESS,
DAMAGE_TORTURE,
DAMAGE_OHKO
} DamageMultType;
typedef enum {
DEKU_STICK_NORMAL,
DEKU_STICK_UNBREAKABLE,
@ -87,4 +99,16 @@ typedef enum {
SWORD_TOGGLE_BOTH_AGES,
} SwordToggleMode;
typedef enum {
TIME_TRAVEL_DISABLED,
TIME_TRAVEL_OOT,
TIME_TRAVEL_ANY
} TimeTravelType;
typedef enum {
WATERFALL_ALWAYS,
WATERFALL_ONCE,
WATERFALL_NEVER
} SleepingWaterfallType;
#endif

View file

@ -1,11 +1,11 @@
#include "gameplaystats.h"
#include "gameplaystatswindow.h"
#include "soh/SaveManager.h"
#include "functions.h"
#include "macros.h"
#include "soh/cvar_prefixes.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "soh/util.h"
#include <vector>
@ -376,14 +376,18 @@ void SaveStats(SaveContext* saveContext, int sectionID, bool fullSave) {
});
}
void GameplayStatsRow(const char* label, const std::string& value, ImVec4 color = COLOR_WHITE) {
void GameplayStatsRow(const char* label, const std::string& value, ImVec4 color = COLOR_WHITE,
const char* tooltip = "") {
ImGui::PushStyleColor(ImGuiCol_Text, color);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", label);
ImGui::SameLine(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize(value.c_str()).x - 8.0f));
ImGui::SameLine(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize(value.c_str()).x));
ImGui::Text("%s", value.c_str());
ImGui::PopStyleColor();
if (tooltip != "" && ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", tooltip);
}
}
bool compareTimestampInfoByTime(const TimestampInfo& a, const TimestampInfo& b) {
@ -527,8 +531,8 @@ void DrawGameplayStatsCountsTab() {
}
}
}
GameplayStatsRow("Rupees Collected:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_RUPEES_COLLECTED]));
UIWidgets::Tooltip("Includes rupees collected with a full wallet.");
GameplayStatsRow("Rupees Collected:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_RUPEES_COLLECTED]),
COLOR_WHITE, "Includes rupees collected with a full wallet.");
GameplayStatsRow("Rupees Spent:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_RUPEES_SPENT]));
GameplayStatsRow("Chests Opened:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_CHESTS_OPENED]));
GameplayStatsRow("Ammo Used:", formatIntGameplayStat(ammoUsed));
@ -606,26 +610,34 @@ void DrawGameplayStatsBreakdownTab() {
}
void DrawGameplayStatsOptionsTab() {
UIWidgets::PaddedEnhancementCheckbox("Show in-game total timer", CVAR_ENHANCEMENT("GameplayStats.ShowIngameTimer"), true, false);
UIWidgets::InsertHelpHoverText("Keep track of the timer as an in-game HUD element. The position of the timer can be changed in the Cosmetics Editor.");
UIWidgets::PaddedEnhancementCheckbox("Show latest timestamps on top", CVAR_ENHANCEMENT("GameplayStats.ReverseTimestamps"), true, false);
UIWidgets::PaddedEnhancementCheckbox("Room Breakdown", CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), true, false);
ImGui::SameLine();
UIWidgets::InsertHelpHoverText("Allows a more in-depth perspective of time spent in a certain map.");
UIWidgets::PaddedEnhancementCheckbox("RTA Timing on new files", CVAR_ENHANCEMENT("GameplayStats.RTATiming"), true, false);
ImGui::SameLine();
UIWidgets::InsertHelpHoverText(
"Timestamps are relative to starting timestamp rather than in game time, usually necessary for races/speedruns.\n\n"
UIWidgets::CVarCheckbox("Show in-game total timer", CVAR_ENHANCEMENT("GameplayStats.ShowIngameTimer"),
UIWidgets::CheckboxOptions()
.Tooltip("Keep track of the timer as an in-game HUD element. The position of the "
"timer can be changed in the Cosmetics Editor.")
.Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show latest timestamps on top", CVAR_ENHANCEMENT("GameplayStats.ReverseTimestamps"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Room Breakdown", CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"),
UIWidgets::CheckboxOptions()
.Tooltip("Allows a more in-depth perspective of time spent in a certain map.")
.Color(THEME_COLOR));
UIWidgets::CVarCheckbox("RTA Timing on new files", CVAR_ENHANCEMENT("GameplayStats.RTATiming"),
UIWidgets::CheckboxOptions()
.Tooltip("Timestamps are relative to starting timestamp rather than in game time, "
"usually necessary for races/speedruns.\n\n"
"Starting timestamp is on first non-c-up input after intro cutscene.\n\n"
"NOTE: THIS NEEDS TO BE SET BEFORE CREATING A FILE TO TAKE EFFECT"
);
UIWidgets::PaddedEnhancementCheckbox("Show additional detail timers", CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"), true, false);
UIWidgets::PaddedEnhancementCheckbox("Show Debug Info", CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo"));
"NOTE: THIS NEEDS TO BE SET BEFORE CREATING A FILE TO TAKE EFFECT")
.Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show additional detail timers", CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show Debug Info", CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo"),
UIWidgets::CheckboxOptions().Color(THEME_COLOR));
}
void GameplayStatsWindow::DrawElement() {
DrawGameplayStatsHeader();
UIWidgets::PushStyleTabs(THEME_COLOR);
if (ImGui::BeginTabBar("Stats", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
if (ImGui::BeginTabItem("Timestamps")) {
DrawGameplayStatsTimestampsTab();
@ -645,6 +657,7 @@ void GameplayStatsWindow::DrawElement() {
}
ImGui::EndTabBar();
}
UIWidgets::PopStyleTabs();
ImGui::Text("Note: Gameplay stats are saved to the current file and will be\nlost if you quit without saving.");
}

View file

@ -1,5 +1,4 @@
#include <libultraship/libultraship.h>
#include "gameplaystats.h"
class GameplayStatsWindow : public Ship::GuiWindow {
public:

View file

@ -463,7 +463,7 @@ void UpdateMirrorModeState(int32_t sceneNum) {
mirroredMode == MIRRORED_WORLD_ALWAYS ||
((mirroredMode == MIRRORED_WORLD_RANDOM || mirroredMode == MIRRORED_WORLD_RANDOM_SEEDED) && randomMirror) ||
// Dungeon modes
(inDungeon && (mirroredMode == MIRRORED_WORLD_DUNGEONS_All ||
(inDungeon && (mirroredMode == MIRRORED_WORLD_DUNGEONS_ALL ||
(mirroredMode == MIRRORED_WORLD_DUNGEONS_VANILLA && !ResourceMgr_IsSceneMasterQuest(sceneNum)) ||
(mirroredMode == MIRRORED_WORLD_DUNGEONS_MQ && ResourceMgr_IsSceneMasterQuest(sceneNum)) ||
((mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM || mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED) && randomMirror)))

View file

@ -3,8 +3,10 @@
#include <string>
#include <cstdint>
#include <libultraship/bridge.h>
#include "soh/SohGui/UIWidgets.hpp"
#include <libultraship/libultraship.h>
#include "soh/SohGui/MenuTypes.h"
#include "soh/SohGui/SohMenu.h"
#include "soh/SohGui/SohGui.hpp"
std::string FormatLocations(std::vector<RandomizerCheck> locs) {
std::string locString = "";
@ -30,6 +32,7 @@ void applyPreset(std::vector<PresetEntry> entries) {
CVarSetString(cvar, std::get<std::string>(value).c_str());
break;
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
@ -47,21 +50,22 @@ void DrawPresetSelector(PresetType presetTypeId) {
comboboxTooltip += std::string(iter->second.label) + " - " + std::string(iter->second.description);
}
UIWidgets::PaddedText("Presets", false, true);
ImGui::Text("Presets", false, true);
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (ImGui::BeginCombo("##PresetsComboBox", selectedPresetDef.label)) {
for ( auto iter = presetTypeDef.presets.begin(); iter != presetTypeDef.presets.end(); ++iter ) {
if (ImGui::Selectable(iter->second.label, iter->first == selectedPresetId)) {
CVarSetInteger(presetTypeCvar.c_str(), iter->first);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
ImGui::EndCombo();
}
UIWidgets::PopStyleCombobox();
UIWidgets::Tooltip(comboboxTooltip.c_str());
UIWidgets::Spacer(0);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6.0f, 4.0f));
UIWidgets::PushStyleButton(THEME_COLOR);
if (ImGui::Button(("Apply Preset##" + presetTypeCvar).c_str())) {
for(const char* block : presetTypeDef.blocksToClear) {
CVarClearBlock(block);
@ -75,5 +79,5 @@ void DrawPresetSelector(PresetType presetTypeId) {
Rando::Settings::GetInstance()->ReloadOptions();
}
}
ImGui::PopStyleVar(1);
UIWidgets::PopStyleButton();
}

View file

@ -1,4 +1,5 @@
#include "Plandomizer.h"
#include <soh/SohGui/SohGui.hpp>
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/util.h"
#include <vector>
@ -836,21 +837,9 @@ void PlandomizerDrawItemSlots(uint32_t index) {
void PlandomizerDrawShopSlider(uint32_t index) {
ImGui::PushID(index);
ImGui::Text("Price:");
ImGui::SameLine();
std::string MinusBTNName = " - ##Price";
if (ImGui::Button(MinusBTNName.c_str()) && plandoLogData[index].shopPrice > 0) {
plandoLogData[index].shopPrice--;
}
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - 40.0f);
ImGui::SliderInt("", &plandoLogData[index].shopPrice, 0, 999, "%d Rupees");
ImGui::PopItemWidth();
ImGui::SameLine();
std::string PlusBTNName = " + ##Price";
if (ImGui::Button(PlusBTNName.c_str()) && plandoLogData[index].shopPrice < 999) {
plandoLogData[index].shopPrice++;
}
UIWidgets::SliderInt("Price:", &plandoLogData[index].shopPrice, UIWidgets::IntSliderOptions()
.Color(THEME_COLOR).Format("%d Rupees").Min(0).Max(999).LabelPosition(UIWidgets::LabelPosition::Near)
.ComponentAlignment(UIWidgets::ComponentAlignment::Right).Size(UIWidgets::Sizes::Inline));
ImGui::PopID();
}
@ -883,13 +872,13 @@ void PlandomizerDrawIceTrapSetup(uint32_t index) {
ImGui::SameLine();
if (plandoLogData[index].iceTrapModel.GetRandomizerGet() != RG_NONE &&
plandoLogData[index].iceTrapModel.GetRandomizerGet() != RG_SOLD_OUT) {
if (ImGui::Button(randomizeButton.c_str())) {
if (UIWidgets::Button(randomizeButton.c_str(), UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline).Padding(ImVec2(10.f, 6.f)))) {
plandoLogData[index].iceTrapName =
GetIceTrapName(plandoLogData[index].iceTrapModel.GetRandomizerGet()).GetForLanguage(CVarGetInteger(CVAR_SETTING("Languages"), 0)).c_str();
}
ImGui::SameLine();
}
if (UIWidgets::InputString("##TrapName", &trapTextInput)) {
if (UIWidgets::InputString("##TrapName", &trapTextInput, UIWidgets::InputOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::None))) {
plandoLogData[index].iceTrapName = trapTextInput.c_str();
}
@ -900,39 +889,64 @@ void PlandomizerDrawIceTrapSetup(uint32_t index) {
ImGui::PopID();
}
static std::unordered_map<RandomizerCheckArea, const char*> rcAreaNameMap = {
{ RCAREA_KOKIRI_FOREST, "Kokiri Forest" },
{ RCAREA_LOST_WOODS, "Lost Woods" },
{ RCAREA_SACRED_FOREST_MEADOW, "Sacred Forest Meadow" },
{ RCAREA_HYRULE_FIELD, "Hyrule Field" },
{ RCAREA_LAKE_HYLIA, "Lake Hylia" },
{ RCAREA_GERUDO_VALLEY, "Gerudo Valley" },
{ RCAREA_GERUDO_FORTRESS, "Gerudo Fortress" },
{ RCAREA_WASTELAND, "Haunted Wasteland" },
{ RCAREA_DESERT_COLOSSUS, "Desert Colossus" },
{ RCAREA_MARKET, "Hyrule Market" },
{ RCAREA_HYRULE_CASTLE, "Hyrule Castle" },
{ RCAREA_KAKARIKO_VILLAGE, "Kakariko Village" },
{ RCAREA_GRAVEYARD, "Graveyard" },
{ RCAREA_DEATH_MOUNTAIN_TRAIL, "Death Mountain Trail" },
{ RCAREA_GORON_CITY, "Goron City" },
{ RCAREA_DEATH_MOUNTAIN_CRATER, "Death Mountain Crater" },
{ RCAREA_ZORAS_RIVER, "Zora's River" },
{ RCAREA_ZORAS_DOMAIN, "Zora's Domain" },
{ RCAREA_ZORAS_FOUNTAIN, "Zora's Fountain" },
{ RCAREA_LON_LON_RANCH, "Lon Lon Ranch" },
{ RCAREA_DEKU_TREE, "Deku Tree" },
{ RCAREA_DODONGOS_CAVERN, "Dodongo's Cavern" },
{ RCAREA_JABU_JABUS_BELLY, "Jabu Jabu's Belly" },
{ RCAREA_FOREST_TEMPLE, "Forest Temple" },
{ RCAREA_FIRE_TEMPLE, "Fire Temple" },
{ RCAREA_WATER_TEMPLE, "Water Temple" },
{ RCAREA_SPIRIT_TEMPLE, "Spirit Temple" },
{ RCAREA_SHADOW_TEMPLE, "Shadow Temple" },
{ RCAREA_BOTTOM_OF_THE_WELL, "Bottom of the Well" },
{ RCAREA_ICE_CAVERN, "Ice Cavern" },
{ RCAREA_GERUDO_TRAINING_GROUND, "Gerudo Training Ground" },
{ RCAREA_GANONS_CASTLE, "Ganon's Castle" },
{ RCAREA_INVALID, "All" },
};
void PlandomizerDrawOptions() {
if (ImGui::BeginTable("LoadSpoiler", 2)) {
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableNextColumn();
ImGui::SeparatorText("Load/Save Spoiler Log");
PlandomizerPopulateSeedList();
static size_t selectedList = 0;
if (existingSeedList.size() != 0) {
if (ImGui::BeginCombo("##JsonFiles", existingSeedList[selectedList].c_str())) {
for (size_t i = 0; i < existingSeedList.size(); i++) {
bool isSelected = (selectedList == i);
if (ImGui::Selectable(existingSeedList[i].c_str(), isSelected)) {
selectedList = i;
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
UIWidgets::Combobox("##JsonFiles", &selectedList, existingSeedList, UIWidgets::ComboboxOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::None));
}
else {
ImGui::Text("No Spoiler Logs found.");
}
ImGui::BeginDisabled(existingSeedList.empty());
if (ImGui::Button("Load")) {
if (UIWidgets::Button("Load", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
logTemp = existingSeedList[selectedList].c_str();
PlandomizerLoadSpoilerLog(logTemp.c_str());
}
ImGui::EndDisabled();
ImGui::BeginDisabled(spoilerLogData.empty());
ImGui::SameLine();
if (ImGui::Button("Save")) {
if (UIWidgets::Button("Save", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
PlandomizerSaveSpoilerLog();
}
ImGui::EndDisabled();
@ -1000,44 +1014,19 @@ void PlandomizerDrawOptions() {
}
if (getTabID == TAB_HINTS) {
if (ImGui::Button("Clear All Hints")) {
if (UIWidgets::Button("Clear All Hints", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
PlandomizerRemoveAllHints();
}
ImGui::SameLine();
if (ImGui::Button("Randomize All Hints")) {
if (UIWidgets::Button("Randomize All Hints", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
PlandomizerRandomizeHint(HINT_ALL, 0);
}
}
if (getTabID == TAB_LOCATIONS) {
if (plandoLogData.size() > 0) {
const char* comboLabel = rcAreaNames[selectedArea].c_str();
if (selectedArea == RCAREA_INVALID) {
comboLabel = "All";
}
ImGui::Text("Filter by Area:");
UIWidgets::Combobox("Filter by Area:##AreaFilter", &selectedArea, rcAreaNameMap, UIWidgets::ComboboxOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::Near).ComponentAlignment(UIWidgets::ComponentAlignment::Right));
ImGui::SameLine();
ImGui::PushItemWidth(300.0f);
if (ImGui::BeginCombo("##AreaFilter", comboLabel)) {
for (const auto& [area, name] : rcAreaNames) {
bool isSelected = (selectedArea == area);
const char* displayName = name.c_str();
if (area == RCAREA_INVALID) {
displayName = "All";
}
if (ImGui::Selectable(displayName, isSelected)) {
selectedArea = area;
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::PopItemWidth();
ImGui::SameLine();
if (ImGui::Button("Empty All Rewards")) {
if (UIWidgets::Button("Empty All Rewards", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline).Padding(ImVec2(10.f, 6.f)))) {
PlandomizerRemoveAllItems();
}
}
@ -1067,16 +1056,14 @@ void PlandomizerDrawHintsWindow() {
}
ImGui::Text("New Hint: ");
ImGui::SameLine();
if (ImGui::Button(randomizeButton.c_str())) {
if (UIWidgets::Button(randomizeButton.c_str(), UIWidgets::ButtonOptions().Color(THEME_COLOR).Padding(ImVec2(10.f, 6.f)).Size(UIWidgets::Sizes::Inline).Tooltip("Randomize Hint"))) {
PlandomizerRandomizeHint(HINT_SINGLE, index);
}
UIWidgets::Tooltip("Randomize Hint");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 10);
if (UIWidgets::InputString("##HintMessage", &hintInputText)) {
if (UIWidgets::InputString("##HintMessage", &hintInputText, UIWidgets::InputOptions().Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::None).Tooltip(plandomizerHintsTooltip().c_str()))) {
plandoHintData[index].hintText = hintInputText.c_str();
}
UIWidgets::Tooltip(plandomizerHintsTooltip().c_str());
index++;
ImGui::PopID();
}
@ -1133,6 +1120,7 @@ void PlandomizerDrawLocationsWindow(RandomizerCheckArea rcArea) {
void PlandomizerDrawSpoilerTable() {
ImGui::BeginChild("Main");
UIWidgets::PushStyleTabs(THEME_COLOR);
if (ImGui::BeginTabBar("Check Tabs")) {
if (ImGui::BeginTabItem("Gossip Stones")) {
getTabID = TAB_HINTS;
@ -1146,12 +1134,13 @@ void PlandomizerDrawSpoilerTable() {
}
}
ImGui::EndTabBar();
UIWidgets::PopStyleTabs();
ImGui::EndChild();
}
void PlandomizerWindow::DrawElement() {
PlandomizerDrawOptions();
UIWidgets::PaddedSeparator();
UIWidgets::Separator(true, true, 0.f, 0.f);
PlandomizerDrawSpoilerTable();
}

View file

@ -39,14 +39,14 @@ typedef struct {
std::string hintText;
} SpoilerHintObject;
typedef enum {
typedef enum PlandoTabs {
TAB_HINTS,
TAB_LOCATIONS
};
} PlandoTabs;
typedef enum {
typedef enum PlandoHints {
HINT_SINGLE,
HINT_ALL,
};
} PlandoHints;
#endif

View file

@ -2,7 +2,9 @@
#include "libultraship/bridge.h"
#include <Context.h>
#include <imgui.h>
#include "soh/SohGui/SohGui.hpp"
#include "soh/SohGui/UIWidgets.hpp"
#include <soh/cvar_prefixes.h>
namespace Rando {
Option Option::Bool(RandomizerSettingKey key_, std::string name_, std::vector<std::string> options_,
@ -130,11 +132,10 @@ void Option::Enable() {
disabled = false;
}
void Option::Disable(std::string text, const UIWidgets::CheckboxGraphics graphic) {
if (!disabled || disabledText != text || disabledGraphic != graphic) {
void Option::Disable(std::string text) {
if (!disabled || disabledText != text) {
disabled = true;
disabledText = std::move(text);
disabledGraphic = graphic;
}
}
@ -149,9 +150,6 @@ bool Option::RenderImGui() {
case WidgetType::Checkbox:
changed = RenderCheckbox();
break;
case WidgetType::TristateCheckbox:
changed = RenderTristateCheckbox();
break;
case WidgetType::Combobox:
changed = RenderCombobox();
break;
@ -159,7 +157,6 @@ bool Option::RenderImGui() {
changed = RenderSlider();
break;
}
UIWidgets::Spacer(0);
ImGui::EndGroup();
return changed;
}
@ -213,50 +210,19 @@ Option::Option(size_t key_, std::string name_, std::vector<std::string> options_
bool Option::RenderCheckbox() {
bool changed = false;
if (disabled) {
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
bool val = static_cast<bool>(CVarGetInteger(cvarName.c_str(), defaultOption));
if (CustomCheckbox(name.c_str(), &val, disabled, disabledGraphic)) {
UIWidgets::CheckboxOptions widgetOptions = static_cast<UIWidgets::CheckboxOptions>(UIWidgets::CheckboxOptions().Color(THEME_COLOR).Tooltip(description.c_str()));
widgetOptions.disabled = disabled;
if (UIWidgets::Checkbox(name.c_str(), &val, widgetOptions)) {
CVarSetInteger(cvarName.c_str(), val);
changed = true;
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
if (!description.empty()) {
UIWidgets::InsertHelpHoverText(description.c_str());
}
if (disabled) {
UIWidgets::ReEnableComponent(disabledText.c_str());
}
return changed;
}
bool Option::RenderTristateCheckbox() {
bool changed = false;
if (disabled) {
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
int val = CVarGetInteger(cvarName.c_str(), defaultOption);
if (CustomCheckboxTristate(name.c_str(), &val, disabled, disabledGraphic)) {
CVarSetInteger(cvarName.c_str(), val);
changed = true;
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
if (!description.empty()) {
UIWidgets::InsertHelpHoverText(description.c_str());
}
if (disabled) {
UIWidgets::ReEnableComponent(disabledText.c_str());
}
return changed;
}
bool Option::RenderCombobox() {
bool changed = false;
if (disabled) {
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
ImGui::Text("%s", name.c_str());
uint8_t selected = CVarGetInteger(cvarName.c_str(), defaultOption);
if (selected >= options.size()) {
selected = options.size();
@ -264,26 +230,16 @@ bool Option::RenderCombobox() {
changed = true;
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
if (!description.empty()) {
UIWidgets::InsertHelpHoverText(description.c_str());
UIWidgets::ComboboxOptions widgetOptions = UIWidgets::ComboboxOptions().Color(THEME_COLOR).Tooltip(description.c_str());
if (this->GetKey() == RSK_LOGIC_RULES) {
widgetOptions = widgetOptions.LabelPosition(UIWidgets::LabelPosition::None).ComponentAlignment(UIWidgets::ComponentAlignment::Right);
}
const std::string comboName = std::string("##") + std::string(cvarName);
if (ImGui::BeginCombo(comboName.c_str(), options[selected].c_str())) {
for (size_t i = 0; i < options.size(); i++) {
if (!options[i].empty()) {
if (ImGui::Selectable(options[i].c_str(), i == selected)) {
CVarSetInteger(cvarName.c_str(), static_cast<int>(i));
widgetOptions.disabled = disabled;
if(UIWidgets::Combobox(name.c_str(), &selected, options, widgetOptions)) {
CVarSetInteger(cvarName.c_str(), static_cast<int>(selected));
changed = true;
selected = i;
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
}
ImGui::EndCombo();
}
if (disabled) {
UIWidgets::ReEnableComponent(disabledText.c_str());
}
return changed;
}
@ -295,40 +251,11 @@ bool Option::RenderSlider() {
CVarSetInteger(cvarName.c_str(), val);
changed = true;
}
if (disabled) {
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
const std::string formatName = name + ": %s";
ImGui::Text(formatName.c_str(), options[val].c_str());
if (!description.empty()) {
UIWidgets::InsertHelpHoverText(description.c_str());
}
UIWidgets::Spacer(0);
ImGui::BeginGroup();
const std::string MinusBTNName = " - ##" + cvarName;
if (ImGui::Button(MinusBTNName.c_str())) {
val--;
UIWidgets::IntSliderOptions widgetOptions = UIWidgets::IntSliderOptions().Color(THEME_COLOR).Min(0).Max(options.size() - 1).Tooltip(description.c_str()).Format(options[val].c_str()).DefaultValue(defaultOption);
widgetOptions.disabled = disabled;
if (UIWidgets::SliderInt(name.c_str(), &val, widgetOptions)) {
changed = true;
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
ImGui::PushItemWidth(std::min(ImGui::GetContentRegionAvail().x - 30.0f, 260.0f));
const std::string id = "##Slider" + cvarName;
if (ImGui::SliderInt(id.c_str(), &val, 0, static_cast<int>(options.size()) - 1, "", ImGuiSliderFlags_AlwaysClamp)) {
changed = true;
}
ImGui::PopItemWidth();
const std::string PlusBTNName = " + ##" + cvarName;
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
if (ImGui::Button(PlusBTNName.c_str())) {
val++;
changed = true;
}
ImGui::EndGroup();
if (disabled) {
UIWidgets::ReEnableComponent(disabledText.c_str());
}
if (val < 0) {
val = 0;
changed = true;
@ -465,7 +392,7 @@ bool OptionGroup::RenderImGui() const { // NOLINT(*-no-recursion)
ImGui::TableSetColumnIndex(i);
ImGui::TableHeader(mSubGroups[i]->GetName().c_str());
if (!mSubGroups[i]->GetDescription().empty()) {
UIWidgets::SetLastItemHoverText(mSubGroups[i]->GetDescription().c_str());
UIWidgets::Tooltip(mSubGroups[i]->GetDescription().c_str());
}
}
ImGui::PopItemFlag();
@ -473,12 +400,10 @@ bool OptionGroup::RenderImGui() const { // NOLINT(*-no-recursion)
}
}
if (mContainerType == WidgetContainerType::SECTION && !mName.empty()) {
UIWidgets::PaddedSeparator();
ImGui::Text("%s", mName.c_str());
ImGui::SeparatorText(mName.c_str());
if (!mDescription.empty()) {
UIWidgets::InsertHelpHoverText(mDescription.c_str());
UIWidgets::Tooltip(mDescription.c_str());
}
UIWidgets::PaddedSeparator();
}
if (mContainerType == WidgetContainerType::COLUMN) {
ImGui::TableNextColumn();
@ -507,9 +432,6 @@ bool OptionGroup::RenderImGui() const { // NOLINT(*-no-recursion)
if (option->HasFlag(IMFLAG_UNINDENT)) {
ImGui::Unindent();
}
if (option->HasFlag(IMFLAG_SEPARATOR_BOTTOM)) {
UIWidgets::PaddedSeparator(false, true);
}
}
}
if (mContainerType == WidgetContainerType::COLUMN) {

View file

@ -1,6 +1,7 @@
#pragma once
#include "soh/SohGui/UIWidgets.hpp"
#ifndef RANDOPTION_H
#define RANDOPTION_H
#include <cstdint>
#include <set>
@ -35,7 +36,6 @@ enum class OptionCategory {
*/
enum class WidgetType {
Checkbox, /** Default for Bools, not compatible if options.size() > 2. */
TristateCheckbox, /** Compatible with U8s, not compatible if options.size() != 3. */
Combobox, /** Default for U8s, works with U8s and Bools. */
Slider, /** Compatible with U8s. If constructed with NumOpts, consider using this. Technically can be used for Bool or non-NumOpts options but it would be a bit weird semantically. */
};
@ -312,7 +312,7 @@ class Option {
* @param graphic What graphic to display in a disabled checkbox. Defaults to an
* "X" symbol.
*/
void Disable(std::string text, UIWidgets::CheckboxGraphics graphic = UIWidgets::CheckboxGraphics::Cross);
void Disable(std::string text);
bool IsCategory(OptionCategory category) const;
/**
@ -339,7 +339,6 @@ protected:
private:
bool RenderCheckbox();
bool RenderTristateCheckbox();
bool RenderCombobox();
bool RenderSlider();
void PopulateTextToNum();
@ -357,7 +356,6 @@ protected:
bool defaultHidden = false;
int imFlags = IMFLAG_NONE;
bool disabled = false;
UIWidgets::CheckboxGraphics disabledGraphic = UIWidgets::CheckboxGraphics::Cross;
std::string disabledText;
std::unordered_map<std::string, uint8_t> optionsTextToVar = {};
};
@ -547,3 +545,5 @@ class OptionGroup {
bool mDisabled = false;
};
} // namespace Rando
#endif //RANDOPTION_H

View file

@ -11,9 +11,8 @@
#include "3drando/rando_main.hpp"
#include "3drando/random.hpp"
#include "soh/ResourceManagerHelpers.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "3drando/custom_messages.hpp"
#include "soh/SohGui/UIWidgets.hpp"
#include <imgui.h>
#include <imgui_internal.h>
#include "../custom-message/CustomMessageTypes.h"
@ -27,6 +26,7 @@
#include <tuple>
#include <functional>
#include "draw.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "static_data.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include <boost_custom/container_hash/hash_32.hpp>
@ -1924,6 +1924,16 @@ bool GenerateRandomizer(std::string seed /*= ""*/) {
return false;
}
static const std::unordered_map<int32_t, const char*> randomizerPresetList = {
{ RANDOMIZER_PRESET_DEFAULT, "Default" },
{ RANDOMIZER_PRESET_SPOCK_RACE, "Spock Race" },
{ RANDOMIZER_PRESET_SPOCK_RACE_NO_LOGIC, "Spock Race (No Logic)" },
{ RANDOMIZER_PRESET_S6, "S6" },
{ RANDOMIZER_PRESET_HELL_MODE, "Hell Mode" },
{ RANDOMIZER_PRESET_BENCHMARK, "Benchmark" }
};
static int32_t randomizerPresetSelected = RANDOMIZER_PRESET_DEFAULT;
void RandomizerSettingsWindow::DrawElement() {
auto ctx = Rando::Context::GetInstance();
if (generated) {
@ -1931,30 +1941,62 @@ void RandomizerSettingsWindow::DrawElement() {
randoThread.join();
}
bool disableEditingRandoSettings = CVarGetInteger(CVAR_GENERAL("RandoGenerating"), 0) || CVarGetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 0);
if (disableEditingRandoSettings) {
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0) || disableEditingRandoSettings);
const PresetTypeDefinition presetTypeDef = presetTypes.at(PRESET_TYPE_RANDOMIZER);
std::string comboboxTooltip = "";
for (auto iter = presetTypeDef.presets.begin(); iter != presetTypeDef.presets.end(); ++iter) {
if (iter->first != 0) comboboxTooltip += "\n\n";
comboboxTooltip += std::string(iter->second.label) + " - " + std::string(iter->second.description);
}
const std::string presetTypeCvar = CVAR_GENERAL("SelectedPresets.") + std::to_string(PRESET_TYPE_RANDOMIZER);
randomizerPresetSelected = CVarGetInteger(presetTypeCvar.c_str(), RANDOMIZER_PRESET_DEFAULT);
if (UIWidgets::Combobox("Randomizer Presets", &randomizerPresetSelected, randomizerPresetList, UIWidgets::ComboboxOptions()
.DefaultIndex(RANDOMIZER_PRESET_DEFAULT)
.Tooltip(comboboxTooltip.c_str())
.Color(THEME_COLOR))
) {
CVarSetInteger(presetTypeCvar.c_str(), randomizerPresetSelected);
}
ImGui::SameLine();
ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 35.f);
if (UIWidgets::Button("Apply Preset##Randomizer", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline).Padding(ImVec2(10.f, 6.f)))) {
if (randomizerPresetSelected >= presetTypeDef.presets.size()) {
randomizerPresetSelected = 0;
}
const PresetDefinition selectedPresetDef = presetTypeDef.presets.at(randomizerPresetSelected);
for(const char* block : presetTypeDef.blocksToClear) {
CVarClearBlock(block);
}
if (randomizerPresetSelected != 0) {
applyPreset(selectedPresetDef.entries);
}
CVarSetInteger(presetTypeCvar.c_str(), randomizerPresetSelected);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
DrawPresetSelector(PRESET_TYPE_RANDOMIZER);
ImGui::EndDisabled();
UIWidgets::Spacer(0);
UIWidgets::EnhancementCheckbox("Manual seed entry", CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), false, "");
UIWidgets::CVarCheckbox("Manual seed entry", CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), UIWidgets::CheckboxOptions().Color(THEME_COLOR));
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0)) {
ImGui::Text("Seed");
UIWidgets::PushStyleInput(THEME_COLOR);
ImGui::InputText("##RandomizerSeed", seedString, MAX_SEED_STRING_SIZE, ImGuiInputTextFlags_CallbackCharFilter, UIWidgets::TextFilters::FilterAlphaNum);
UIWidgets::Tooltip(
"Characters from a-z, A-Z, and 0-9 are supported.\n"
"Character limit is 1023, after which the seed will be truncated.\n"
);
ImGui::SameLine();
if (ImGui::Button("New Seed")) {
if (strnlen(seedString, MAX_SEED_STRING_SIZE) == 0) {
ImGui::SameLine(17.0f);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "Leave blank for random seed");
}
UIWidgets::PopStyleInput();
ImGui::SameLine(0.f, 50.f);
if (UIWidgets::Button(ICON_FA_RANDOM, UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR).Padding(ImVec2(10.f, 6.f)).Tooltip(
"Creates a new random seed value to be used when generating a randomizer"
))) {
SohUtils::CopyStringToCharArray(seedString, std::to_string(rand() & 0xFFFFFFFF), MAX_SEED_STRING_SIZE);
}
UIWidgets::Tooltip("Creates a new random seed value to be used when generating a randomizer");
ImGui::SameLine();
if (ImGui::Button("Clear Seed")) {
if (UIWidgets::Button(ICON_FA_ERASER, UIWidgets::ButtonOptions().Size(UIWidgets::Sizes::Inline).Color(THEME_COLOR).Padding(ImVec2(10.f, 6.f)))) {
memset(seedString, 0, MAX_SEED_STRING_SIZE);
}
}
@ -1962,13 +2004,13 @@ void RandomizerSettingsWindow::DrawElement() {
UIWidgets::Spacer(0);
ImGui::BeginDisabled((CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0) && gSaveContext.gameMode != GAMEMODE_FILE_SELECT) ||
GameInteractor::IsSaveLoaded());
if (ImGui::Button("Generate Randomizer")) {
if (UIWidgets::Button("Generate Randomizer", UIWidgets::ButtonOptions().Size(ImVec2(250.f, 0.f)).Color(THEME_COLOR))) {
ctx->SetSpoilerLoaded(false);
GenerateRandomizer(CVarGetInteger(CVAR_RANDOMIZER_SETTING("ManualSeedEntry"), 0) ? seedString : "");
}
ImGui::EndDisabled();
UIWidgets::Spacer(0);
ImGui::SameLine();
if (!CVarGetInteger(CVAR_RANDOMIZER_SETTING("DontGenerateSpoiler"), 0)) {
std::string spoilerfilepath = CVarGetString(CVAR_GENERAL("SpoilerLog"), "");
ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str());
@ -1978,13 +2020,13 @@ void RandomizerSettingsWindow::DrawElement() {
// std::string presetfilepath = CVarGetString(CVAR_RANDOMIZER_SETTING("LoadedPreset"), "");
// ImGui::Text("Settings File: %s", presetfilepath.c_str());
UIWidgets::PaddedSeparator();
UIWidgets::Separator(true, true, 0.f, 0.f);
ImGui::BeginDisabled(CVarGetInteger(CVAR_SETTING("DisableChanges"), 0));
ImGuiWindow* window = ImGui::GetCurrentWindow();
static ImVec2 cellPadding(8.0f, 8.0f);
UIWidgets::PushStyleTabs(THEME_COLOR);
if (ImGui::BeginTabBar("Randomizer Settings", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
if (ImGui::BeginTabItem("World")) {
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cellPadding);
@ -2048,7 +2090,9 @@ void RandomizerSettingsWindow::DrawElement() {
window->DC.CurrLineTextBaseOffset = 0.0f;
static ImGuiTextFilter locationSearch;
UIWidgets::PushStyleInput(THEME_COLOR);
locationSearch.Draw();
UIWidgets::PopStyleInput();
ImGui::BeginChild("ChildIncludedLocations", ImVec2(0, -8));
for (auto& [rcArea, locations] : RandomizerCheckObjects::GetAllRCObjectsByArea()) {
@ -2068,7 +2112,7 @@ void RandomizerSettingsWindow::DrawElement() {
for (auto& location : locations) {
if (ctx->GetItemLocation(location)->IsVisible() && !excludedLocations.count(location) &&
locationSearch.PassFilter(Rando::StaticData::GetLocation(location)->GetName().c_str())) {
UIWidgets::PushStyleButton(THEME_COLOR, ImVec2(7.f, 5.f));
if (ImGui::ArrowButton(std::to_string(location).c_str(), ImGuiDir_Right)) {
excludedLocations.insert(location);
// todo: this efficently when we build out cvar array support
@ -2080,6 +2124,7 @@ void RandomizerSettingsWindow::DrawElement() {
CVarSetString(CVAR_RANDOMIZER_SETTING("ExcludedLocations"), excludedLocationString.c_str());
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
UIWidgets::PopStyleButton();
ImGui::SameLine();
ImGui::Text("%s", Rando::StaticData::GetLocation(location)->GetShortName().c_str());
}
@ -2110,6 +2155,7 @@ void RandomizerSettingsWindow::DrawElement() {
for (auto& location : locations) {
auto elfound = excludedLocations.find(location);
if (ctx->GetItemLocation(location)->IsVisible() && elfound != excludedLocations.end()) {
UIWidgets::PushStyleButton(THEME_COLOR, ImVec2(7.f, 5.f));
if (ImGui::ArrowButton(std::to_string(location).c_str(), ImGuiDir_Left)) {
excludedLocations.erase(elfound);
// todo: this efficently when we build out cvar array support
@ -2125,6 +2171,7 @@ void RandomizerSettingsWindow::DrawElement() {
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
UIWidgets::PopStyleButton();
ImGui::SameLine();
ImGui::Text("%s", Rando::StaticData::GetLocation(location)->GetShortName().c_str());
}
@ -2272,10 +2319,12 @@ void RandomizerSettingsWindow::DrawElement() {
//{ Rando::Tricks::Tag::GLITCH, false },
};
static ImGuiTextFilter trickSearch;
UIWidgets::PushStyleInput(THEME_COLOR);
trickSearch.Draw("Filter (inc,-exc)", 490.0f);
UIWidgets::PopStyleInput();
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("LogicRules"), RO_LOGIC_GLITCHLESS) != RO_LOGIC_NO_LOGIC) {
ImGui::SameLine();
if (ImGui::Button("Disable All")) {
if (UIWidgets::Button("Disable All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(250.f, 0.f)))) {
for (int i = 0; i < RT_MAX; i++) {
auto etfound = enabledTricks.find(static_cast<RandomizerTrick>(i));
if (etfound != enabledTricks.end()) {
@ -2291,7 +2340,7 @@ void RandomizerSettingsWindow::DrawElement() {
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::SameLine();
if (ImGui::Button("Enable All")) {
if (UIWidgets::Button("Enable All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(250.f, 0.f)))) {
for (int i = 0; i < RT_MAX; i++) {
if (!enabledTricks.count(static_cast<RandomizerTrick>(i))) {
enabledTricks.insert(static_cast<RandomizerTrick>(i));
@ -2334,19 +2383,19 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::TableNextColumn();
window->DC.CurrLineTextBaseOffset = 0.0f;
if (ImGui::Button("Collapse All##disabled")) {
if (UIWidgets::Button("Collapse All##disabled", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.f, 0.f)))) {
for (int i = 0; i < RA_MAX; i++) {
areaTreeDisabled[static_cast<RandomizerArea>(i)] = false;
}
}
ImGui::SameLine();
if (ImGui::Button("Open All##disabled")) {
if (UIWidgets::Button("Open All##disabled", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.f, 0.f)))) {
for (int i = 0; i < RA_MAX; i++) {
areaTreeDisabled[static_cast<RandomizerArea>(i)] = true;
}
}
ImGui::SameLine();
if (ImGui::Button("Enable Visible")) {
if (UIWidgets::Button("Enable Visible", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.f, 0.f)))) {
for (int i = 0; i < RT_MAX; i++) {
auto option = mSettings->GetTrickOption(static_cast<RandomizerTrick>(i));
if (!enabledTricks.count(static_cast<RandomizerTrick>(i)) &&
@ -2387,6 +2436,7 @@ void RandomizerSettingsWindow::DrawElement() {
!enabledTricks.count(rt) && Rando::Tricks::CheckTags(showTag, option.GetTags())) {
ImGui::TreeNodeSetOpen(ImGui::GetID((Rando::Tricks::GetAreaName(option.GetArea()) + "##disabled").c_str()), areaTreeDisabled[option.GetArea()]);
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
UIWidgets::PushStyleButton(THEME_COLOR, ImVec2(7.f, 5.f));
if (ImGui::ArrowButton(std::to_string(rt).c_str(), ImGuiDir_Right)) {
enabledTricks.insert(rt);
std::string enabledTrickString = "";
@ -2397,10 +2447,11 @@ void RandomizerSettingsWindow::DrawElement() {
CVarSetString(CVAR_RANDOMIZER_SETTING("EnabledTricks"), enabledTrickString.c_str());
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
Rando::Tricks::DrawTagChips(option.GetTags());
UIWidgets::PopStyleButton();
Rando::Tricks::DrawTagChips(option.GetTags(), option.GetName());
ImGui::SameLine();
ImGui::Text("%s", option.GetName().c_str());
UIWidgets::InsertHelpHoverText(option.GetDescription().c_str());
UIWidgets::Tooltip(option.GetDescription().c_str());
}
}
areaTreeDisabled[area] = true;
@ -2416,19 +2467,19 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::TableNextColumn();
window->DC.CurrLineTextBaseOffset = 0.0f;
if (ImGui::Button("Collapse All##enabled")) {
if (UIWidgets::Button("Collapse All##enabled", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.f, 0.f)))) {
for (int i = 0; i < RA_MAX; i++) {
areaTreeEnabled[static_cast<RandomizerArea>(i)] = false;
}
}
ImGui::SameLine();
if (ImGui::Button("Open All##enabled")) {
if (UIWidgets::Button("Open All##enabled", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.f, 0.f)))) {
for (int i = 0; i < RA_MAX; i++) {
areaTreeEnabled[static_cast<RandomizerArea>(i)] = true;
}
}
ImGui::SameLine();
if (ImGui::Button("Disable Visible")) {
if (UIWidgets::Button("Disable Visible", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.f, 0.f)))) {
for (int i = 0; i < RT_MAX; i++) {
auto option = mSettings->GetTrickOption(static_cast<RandomizerTrick>(i));
if (enabledTricks.count(static_cast<RandomizerTrick>(i)) &&
@ -2473,6 +2524,7 @@ void RandomizerSettingsWindow::DrawElement() {
enabledTricks.count(rt) && Rando::Tricks::CheckTags(showTag, option.GetTags())) {
ImGui::TreeNodeSetOpen(ImGui::GetID((Rando::Tricks::GetAreaName(option.GetArea()) + "##enabled").c_str()), areaTreeEnabled[option.GetArea()]);
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
UIWidgets::PushStyleButton(THEME_COLOR, ImVec2(7.f, 5.f));
if (ImGui::ArrowButton(std::to_string(rt).c_str(), ImGuiDir_Left)) {
enabledTricks.erase(rt);
std::string enabledTrickString = "";
@ -2487,10 +2539,11 @@ void RandomizerSettingsWindow::DrawElement() {
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
Rando::Tricks::DrawTagChips(option.GetTags());
UIWidgets::PopStyleButton();
Rando::Tricks::DrawTagChips(option.GetTags(), option.GetName());
ImGui::SameLine();
ImGui::Text("%s", option.GetName().c_str());
UIWidgets::InsertHelpHoverText(option.GetDescription().c_str());
UIWidgets::Tooltip(option.GetDescription().c_str());
}
}
areaTreeEnabled[area] = true;
@ -2532,12 +2585,10 @@ void RandomizerSettingsWindow::DrawElement() {
ImGui::EndTabBar();
}
UIWidgets::PopStyleTabs();
ImGui::EndDisabled();
if (disableEditingRandoSettings) {
UIWidgets::ReEnableComponent("");
}
ImGui::EndDisabled();
}
void RandomizerSettingsWindow::UpdateElement() {

View file

@ -7,6 +7,7 @@
#include "soh/SaveManager.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "dungeon.h"
#include "location_access.h"
@ -844,6 +845,39 @@ void SetAreaSpoiled(RandomizerCheckArea rcArea) {
}
void CheckTrackerWindow::DrawElement() {
Color_Background = CVarGetColor(CVAR_TRACKER_CHECK("BgColor.Value"), Color_Bg_Default);
Color_Area_Incomplete_Main = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.MainColor.Value"), Color_Main_Default);
Color_Area_Incomplete_Extra = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.ExtraColor.Value"), Color_Area_Incomplete_Extra_Default);
Color_Area_Complete_Main = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.MainColor.Value"), Color_Main_Default);
Color_Area_Complete_Extra = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.ExtraColor.Value"), Color_Area_Complete_Extra_Default);
Color_Unchecked_Main = CVarGetColor(CVAR_TRACKER_CHECK("Unchecked.MainColor.Value"), Color_Main_Default);
Color_Unchecked_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Unchecked.ExtraColor.Value"), Color_Unchecked_Extra_Default);
Color_Skipped_Main = CVarGetColor(CVAR_TRACKER_CHECK("Skipped.MainColor.Value"), Color_Main_Default);
Color_Skipped_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Skipped.ExtraColor.Value"), Color_Skipped_Extra_Default);
Color_Seen_Main = CVarGetColor(CVAR_TRACKER_CHECK("Seen.MainColor.Value"), Color_Main_Default);
Color_Seen_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Seen.ExtraColor.Value"), Color_Seen_Extra_Default);
Color_Hinted_Main = CVarGetColor(CVAR_TRACKER_CHECK("Hinted.MainColor.Value"), Color_Main_Default);
Color_Hinted_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Hinted.ExtraColor.Value"), Color_Hinted_Extra_Default);
Color_Collected_Main = CVarGetColor(CVAR_TRACKER_CHECK("Collected.MainColor.Value"), Color_Main_Default);
Color_Collected_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Collected.ExtraColor.Value"), Color_Collected_Extra_Default);
Color_Scummed_Main = CVarGetColor(CVAR_TRACKER_CHECK("Scummed.MainColor.Value"), Color_Main_Default);
Color_Scummed_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Scummed.ExtraColor.Value"), Color_Scummed_Extra_Default);
Color_Saved_Main = CVarGetColor(CVAR_TRACKER_CHECK("Saved.MainColor.Value"), Color_Main_Default);
Color_Saved_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Saved.ExtraColor.Value"), Color_Saved_Extra_Default);
hideUnchecked = CVarGetInteger(CVAR_TRACKER_CHECK("Unchecked.Hide"), 0);
hideScummed = CVarGetInteger(CVAR_TRACKER_CHECK("Scummed.Hide"), 0);
hideSeen = CVarGetInteger(CVAR_TRACKER_CHECK("Seen.Hide"), 0);
hideSkipped = CVarGetInteger(CVAR_TRACKER_CHECK("Skipped.Hide"), 0);
hideSaved = CVarGetInteger(CVAR_TRACKER_CHECK("Saved.Hide"), 0);
hideCollected = CVarGetInteger(CVAR_TRACKER_CHECK("Collected.Hide"), 0);
showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0);
mystery = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0);
showLogicTooltip = CVarGetInteger(CVAR_TRACKER_CHECK("ShowLogic"), 0);
hideShopUnshuffledChecks = CVarGetInteger(CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"), 1);
alwaysShowGS = CVarGetInteger(CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), 0);
ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger);
if (CVarGetInteger(CVAR_TRACKER_CHECK("WindowType"), TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) {
if (CVarGetInteger(CVAR_TRACKER_CHECK("ShowOnlyPaused"), 0) && (gPlayState == nullptr || gPlayState->pauseCtx.state == 0)) {
return;
@ -863,11 +897,11 @@ void CheckTrackerWindow::DrawElement() {
}
ImGui::SetNextWindowSize(ImVec2(400, 540), ImGuiCond_FirstUseEver);
BeginFloatWindows("Check Tracker", mIsVisible, ImGuiWindowFlags_NoScrollbar);
if (!GameInteractor::IsSaveLoaded() || !initialized) {
ImGui::Text("Waiting for file load..."); //TODO Language
ImGui::PopFont();
EndFloatWindows();
return;
}
@ -886,38 +920,40 @@ void CheckTrackerWindow::DrawElement() {
ImVec2 size = ImGui::GetContentRegionMax();
size.y -= headerHeight;
if (!ImGui::BeginTable("Check Tracker", 1, 0, size)) {
ImGui::PopFont();
EndFloatWindows();
return;
}
ImGui::TableNextRow(0, headerHeight);
ImGui::TableNextColumn();
UIWidgets::EnhancementCheckbox(
"Show Hidden Items", CVAR_TRACKER_CHECK("ShowHidden"), false,
"When active, items will show hidden checks by default when updated to this state.");
UIWidgets::CVarCheckbox(
"Show Hidden Items", CVAR_TRACKER_CHECK("ShowHidden"), UIWidgets::CheckboxOptions({{ .tooltip = "When active, items will show hidden checks by default when updated to this state." }})
.Color(THEME_COLOR));
UIWidgets::PaddedSeparator();
if (ImGui::Button("Expand All")) {
if (UIWidgets::Button("Expand All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
optCollapseAll = false;
optExpandAll = true;
doAreaScroll = true;
}
ImGui::SameLine();
if (ImGui::Button("Collapse All")) {
if (UIWidgets::Button("Collapse All", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
optExpandAll = false;
optCollapseAll = true;
}
ImGui::SameLine();
if (ImGui::Button("Clear")) {
if (UIWidgets::Button("Clear", UIWidgets::ButtonOptions({{ .tooltip = "Clear the search field" }}).Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
checkSearch.Clear();
UpdateFilters();
doAreaScroll = true;
}
UIWidgets::Tooltip("Clear the search field");
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (checkSearch.Draw()) {
UpdateFilters();
}
UIWidgets::PopStyleCombobox();
UIWidgets::PaddedSeparator();
ImGui::Separator();
ImGui::Text("Total Checks: %d / %d", totalChecksGotten, totalChecks);
@ -929,6 +965,7 @@ void CheckTrackerWindow::DrawElement() {
size = ImGui::GetContentRegionAvail();
if (!ImGui::BeginTable("CheckTracker##Checks", 1, ImGuiTableFlags_ScrollY, size)) {
ImGui::EndTable();
ImGui::PopFont();
EndFloatWindows();
return;
}
@ -946,16 +983,17 @@ void CheckTrackerWindow::DrawElement() {
bool doingCollapseOrExpand = optExpandAll || optCollapseAll;
bool isThisAreaSpoiled;
RandomizerCheckArea lastArea = RCAREA_INVALID;
Color_RGBA8 areaCompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.MainColor"), Color_Main_Default);
Color_RGBA8 areaIncompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.MainColor"), Color_Main_Default);
Color_RGBA8 extraCompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.ExtraColor"), Color_Area_Complete_Extra_Default);
Color_RGBA8 extraIncompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.ExtraColor"), Color_Area_Incomplete_Extra_Default);
Color_RGBA8 areaCompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.MainColor.Value"), Color_Main_Default);
Color_RGBA8 areaIncompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.MainColor.Value"), Color_Main_Default);
Color_RGBA8 extraCompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.ExtraColor.Value"), Color_Area_Complete_Extra_Default);
Color_RGBA8 extraIncompleteColor = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.ExtraColor.Value"), Color_Area_Incomplete_Extra_Default);
Color_RGBA8 mainColor;
Color_RGBA8 extraColor;
std::string stemp;
bool shouldHideFilteredAreas = CVarGetInteger(CVAR_TRACKER_CHECK("HideFilteredAreas"), 1);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0f, 3.0f));
for (auto& [rcArea, checks] : checksByArea) {
RandomizerCheckArea thisArea = currentArea;
@ -1039,9 +1077,11 @@ void CheckTrackerWindow::DrawElement() {
}
}
}
ImGui::PopStyleVar();
ImGui::EndTable(); //Checks Lead-out
ImGui::EndTable(); //Quick Options Lead-out
ImGui::PopFont();
EndFloatWindows();
if (doingCollapseOrExpand) {
optCollapseAll = false;
@ -1099,7 +1139,7 @@ void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flag
windowFlags |= ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar;
if (!CVarGetInteger(CVAR_TRACKER_CHECK("Draggable"), 0)) {
if (!CVarGetInteger(CVAR_TRACKER_CHECK("Draggable"), 1)) {
windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
}
}
@ -1468,54 +1508,54 @@ void DrawLocation(RandomizerCheck rc) {
}
mainColor =
!IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID()) && !IS_RANDO
? Color_Collected_Extra_Default
? Color_Collected_Extra
: Color_Collected_Main;
extraColor = Color_Collected_Extra_Default;
extraColor = Color_Collected_Extra;
} else if (status == RCSHOW_SAVED) {
if (!showHidden && hideSaved) {
return;
}
mainColor =
!IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID()) && !IS_RANDO
? Color_Saved_Extra_Default
? Color_Saved_Extra
: Color_Saved_Main;
extraColor = Color_Saved_Extra_Default;
extraColor = Color_Saved_Extra;
} else if (skipped) {
if (!showHidden && hideSkipped) {
return;
}
mainColor =
!IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID()) && !IS_RANDO
? Color_Skipped_Extra_Default
? Color_Skipped_Extra
: Color_Skipped_Main;
extraColor = Color_Skipped_Extra_Default;
extraColor = Color_Skipped_Extra;
} else if (status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED) {
if (!showHidden && hideSeen) {
return;
}
mainColor =
!IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID()) && !IS_RANDO
? Color_Seen_Extra_Default
? Color_Seen_Extra
: Color_Seen_Main;
extraColor = Color_Seen_Extra_Default;
extraColor = Color_Seen_Extra;
} else if (status == RCSHOW_SCUMMED) {
if (!showHidden && hideScummed) {
return;
}
mainColor =
!IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID()) && !IS_RANDO
? Color_Scummed_Extra_Default
? Color_Scummed_Extra
: Color_Scummed_Main;
extraColor = Color_Scummed_Extra_Default;
extraColor = Color_Scummed_Extra;
} else if (status == RCSHOW_UNCHECKED) {
if (!showHidden && hideUnchecked) {
return;
}
mainColor =
!IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID()) && !IS_RANDO
? Color_Unchecked_Extra_Default
? Color_Unchecked_Extra
: Color_Unchecked_Main;
extraColor = Color_Unchecked_Extra_Default;
extraColor = Color_Unchecked_Extra;
}
//Main Text
@ -1530,8 +1570,10 @@ void DrawLocation(RandomizerCheck rc) {
}
// Draw button - for Skipped/Seen/Scummed/Unchecked only
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {4.0f, 3.0f});
float sz = ImGui::GetFrameHeight();
if (status == RCSHOW_UNCHECKED || status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED || status == RCSHOW_SCUMMED || skipped) {
if (UIWidgets::StateButton(std::to_string(rc).c_str(), skipped ? ICON_FA_PLUS : ICON_FA_TIMES)) {
if (UIWidgets::StateButton(std::to_string(rc).c_str(), skipped ? ICON_FA_PLUS : ICON_FA_TIMES, ImVec2(sz, sz), UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
if (skipped) {
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(false);
areaChecksGotten[loc->GetArea()]--;
@ -1546,8 +1588,10 @@ void DrawLocation(RandomizerCheck rc) {
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
}
} else {
ImGui::Dummy(ImVec2(20.0f, 10.0f));
ImGui::Dummy(ImVec2(sz, sz));
}
ImGui::PopStyleVar();
ImGui::SameLine();
//Draw
@ -1621,7 +1665,7 @@ void DrawLocation(RandomizerCheck rc) {
if (locationInRegion.GetLocation() == rc) {
std::string conditionStr = locationInRegion.GetConditionStr();
if (conditionStr != "true") {
UIWidgets::InsertHelpHoverText(conditionStr);
UIWidgets::Tooltip(conditionStr.c_str());
}
return;
}
@ -1645,7 +1689,7 @@ int hue = 0;
void RainbowTick() {
float freqHue = hue * 2 * M_PI / (360 * CVarGetFloat(CVAR_COSMETIC("RainbowSpeed"), 0.6f));
for (auto& cvar : rainbowCVars) {
if (CVarGetInteger((cvar + "RBM").c_str(), 0) == 0) {
if (CVarGetInteger((cvar + ".Rainbow").c_str(), 0) == 0) {
continue;
}
@ -1655,7 +1699,7 @@ void RainbowTick() {
newColor.b = sin(freqHue + (4 * M_PI / 3)) * 127 + 128;
newColor.a = 255;
CVarSetColor(cvar.c_str(), newColor);
CVarSetColor((cvar + ".Value").c_str(), newColor);
}
hue++;
@ -1664,46 +1708,33 @@ void RainbowTick() {
void ImGuiDrawTwoColorPickerSection(const char* text, const char* cvarMainName, const char* cvarExtraName,
Color_RGBA8& main_color, Color_RGBA8& extra_color, Color_RGBA8& main_default_color,
Color_RGBA8& extra_default_color, const char* cvarHideName, const char* tooltip) {
Color_RGBA8& extra_default_color, const char* cvarHideName, const char* tooltip, UIWidgets::Colors theme) {
Color_RGBA8 cvarMainColor = CVarGetColor(cvarMainName, main_default_color);
Color_RGBA8 cvarExtraColor = CVarGetColor(cvarExtraName, extra_default_color);
main_color = cvarMainColor;
extra_color = cvarExtraColor;
UIWidgets::PushStyleCombobox(theme);
if (ImGui::CollapsingHeader(text)) {
if (*cvarHideName != '\0') {
std::string label = cvarHideName;
label += "##Hidden";
ImGui::PushID(label.c_str());
UIWidgets::EnhancementCheckbox("Hidden", cvarHideName, false,
"When active, checks will hide by default when updated to this state. Can "
"be overriden with the \"Show Hidden Items\" option.");
UIWidgets::CVarCheckbox("Hidden", cvarHideName,
UIWidgets::CheckboxOptions({{ .tooltip = "When active, checks will hide by default when updated to this state. Can "
"be overriden with the \"Show Hidden Items\" option." }}).Color(theme));
ImGui::PopID();
}
if (ImGui::BeginTable(text, 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV | ImGuiTableFlags_Hideable)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
if (UIWidgets::EnhancementColor("Check", cvarMainName,
ImVec4(main_color.r, main_color.g, main_color.b, main_color.a),
ImVec4(main_default_color.r, main_default_color.g, main_default_color.b, main_default_color.a)))
{
std::string mainLabel = "Name##" + std::string(cvarMainName);
if (UIWidgets::CVarColorPicker(mainLabel.c_str(), cvarMainName, main_default_color, false,
UIWidgets::ColorPickerRandomButton | UIWidgets::ColorPickerResetButton | UIWidgets::ColorPickerRainbowCheck, theme)) {
main_color = CVarGetColor(cvarMainName, main_default_color);
};
ImGui::PopItemWidth();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
if (UIWidgets::EnhancementColor("Details", cvarExtraName,
ImVec4(extra_color.r, extra_color.g, extra_color.b, extra_color.a),
ImVec4(extra_default_color.r, extra_default_color.g, extra_default_color.b, extra_default_color.a)))
{
extra_color = CVarGetColor(cvarExtraName, extra_default_color);
}
ImGui::PopItemWidth();
ImGui::EndTable();
std::string extraLabel = "Details##" + std::string(cvarExtraName);
if (UIWidgets::CVarColorPicker(extraLabel.c_str(), cvarExtraName, extra_default_color, false,
UIWidgets::ColorPickerRandomButton | UIWidgets::ColorPickerResetButton | UIWidgets::ColorPickerRainbowCheck, theme)) {
extra_color = CVarGetColor(cvarExtraName, extra_default_color);
}
}
if (tooltip != NULL && strlen(tooltip) != 0) {
@ -1711,6 +1742,7 @@ void ImGuiDrawTwoColorPickerSection(const char* text, const char* cvarMainName,
ImGui::Text(" ?");
UIWidgets::Tooltip(tooltip);
}
UIWidgets::PopStyleCombobox();
}
void CheckTrackerWindow::Draw() {
@ -1722,73 +1754,84 @@ void CheckTrackerWindow::Draw() {
SyncVisibilityConsoleVariable();
}
static const char* windowType[] = { "Floating", "Window" };
static const char* displayType[] = { "Always", "Combo Button Hold" };
static const char* buttonStrings[] = { "A Button", "B Button", "C-Up", "C-Down", "C-Left", "C-Right", "L Button",
"Z Button", "R Button", "Start", "D-Up", "D-Down", "D-Left", "D-Right" };
static std::unordered_map<int32_t, const char*> windowType = {{ TRACKER_WINDOW_FLOATING, "Floating" }, { TRACKER_WINDOW_WINDOW, "Window" }};
static std::unordered_map<int32_t, const char*> displayType = {{ 0, "Always" }, { 1, "Combo Button Hold" }};
static std::unordered_map<int32_t, const char*> buttonStrings = {
{ TRACKER_COMBO_BUTTON_A, "A Button" }, { TRACKER_COMBO_BUTTON_B, "B Button" }, { TRACKER_COMBO_BUTTON_C_UP, "C-Up" },
{ TRACKER_COMBO_BUTTON_C_DOWN, "C-Down" }, { TRACKER_COMBO_BUTTON_C_LEFT, "C-Left" }, { TRACKER_COMBO_BUTTON_C_RIGHT, "C-Right" },
{ TRACKER_COMBO_BUTTON_L, "L Button" }, { TRACKER_COMBO_BUTTON_Z, "Z Button" }, { TRACKER_COMBO_BUTTON_R, "R Button" },
{ TRACKER_COMBO_BUTTON_START, "Start" }, { TRACKER_COMBO_BUTTON_D_UP, "D-Up" }, { TRACKER_COMBO_BUTTON_D_DOWN, "D-Down" },
{ TRACKER_COMBO_BUTTON_D_LEFT, "D-Left" }, { TRACKER_COMBO_BUTTON_D_RIGHT, "D-Right" }};
void CheckTrackerSettingsWindow::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f });
ImGui::BeginTable("CheckTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV);
if (ImGui::BeginTable("CheckTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) {
ImGui::TableSetupColumn("General settings", ImGuiTableColumnFlags_WidthStretch, 200.0f);
ImGui::TableSetupColumn("Section settings", ImGuiTableColumnFlags_WidthStretch, 200.0f);
ImGui::TableHeadersRow();
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
if (UIWidgets::EnhancementColor("BG Color", CVAR_TRACKER_CHECK("BgColor"),
ImVec4(Color_Background.r, Color_Background.g, Color_Background.b, Color_Background.a),
ImVec4(Color_Bg_Default.r, Color_Bg_Default.g, Color_Bg_Default.b, Color_Bg_Default.a),
false, true))
{
Color_Background = CVarGetColor(CVAR_TRACKER_CHECK("BgColor"), Color_Bg_Default);
}
UIWidgets::CVarColorPicker("BG Color", CVAR_TRACKER_CHECK("BgColor"), Color_Bg_Default, true,
UIWidgets::ColorPickerResetButton | UIWidgets::ColorPickerRandomButton, THEME_COLOR);
ImGui::PopItemWidth();
UIWidgets::LabeledRightAlignedEnhancementCombobox("Window Type", CVAR_TRACKER_CHECK("WindowType"), windowType, TRACKER_WINDOW_WINDOW);
UIWidgets::CVarCombobox("Window Type", CVAR_TRACKER_CHECK("WindowType"), windowType,
UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right)
.Color(THEME_COLOR).DefaultIndex(TRACKER_WINDOW_WINDOW));
if (CVarGetInteger(CVAR_TRACKER_CHECK("WindowType"), TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) {
UIWidgets::EnhancementCheckbox("Enable Dragging", CVAR_TRACKER_CHECK("Draggable"));
UIWidgets::EnhancementCheckbox("Only enable while paused", CVAR_TRACKER_CHECK("ShowOnlyPaused"));
UIWidgets::LabeledRightAlignedEnhancementCombobox("Display Mode", CVAR_TRACKER_CHECK("DisplayType"), displayType, 0);
UIWidgets::CVarCheckbox("Enable Dragging", CVAR_TRACKER_CHECK("Draggable"), UIWidgets::CheckboxOptions().Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Only enable while paused", CVAR_TRACKER_CHECK("ShowOnlyPaused"), UIWidgets::CheckboxOptions().Color(THEME_COLOR));
UIWidgets::CVarCombobox("Display Mode", CVAR_TRACKER_CHECK("DisplayType"), displayType,
UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right)
.Color(THEME_COLOR).DefaultIndex(0));
if (CVarGetInteger(CVAR_TRACKER_CHECK("DisplayType"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_COMBO_BUTTON) {
UIWidgets::LabeledRightAlignedEnhancementCombobox("Combo Button 1", CVAR_TRACKER_CHECK("ComboButton1"), buttonStrings, TRACKER_COMBO_BUTTON_L);
UIWidgets::LabeledRightAlignedEnhancementCombobox("Combo Button 2", CVAR_TRACKER_CHECK("ComboButton2"), buttonStrings, TRACKER_COMBO_BUTTON_R);
UIWidgets::CVarCombobox("Combo Button 1", CVAR_TRACKER_CHECK("ComboButton1"), buttonStrings,
UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right)
.Color(THEME_COLOR).DefaultIndex(TRACKER_COMBO_BUTTON_L));
UIWidgets::CVarCombobox("Combo Button 2", CVAR_TRACKER_CHECK("ComboButton2"), buttonStrings,
UIWidgets::ComboboxOptions().LabelPosition(UIWidgets::LabelPosition::Far).ComponentAlignment(UIWidgets::ComponentAlignment::Right)
.Color(THEME_COLOR).DefaultIndex(TRACKER_COMBO_BUTTON_L));
}
}
UIWidgets::EnhancementCheckbox("Vanilla/MQ Dungeon Spoilers", CVAR_TRACKER_CHECK("MQSpoilers"));
UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.");
if (UIWidgets::EnhancementCheckbox("Hide unshuffled shop item checks", CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"), false, "", UIWidgets::CheckboxGraphics::Cross, false)) {
UIWidgets::CVarCheckbox("Vanilla/MQ Dungeon Spoilers", CVAR_TRACKER_CHECK("MQSpoilers"), UIWidgets::CheckboxOptions()
.Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.").Color(THEME_COLOR));
if (UIWidgets::CVarCheckbox("Hide unshuffled shop item checks", CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"),
UIWidgets::CheckboxOptions().Tooltip("If enabled, will prevent the tracker from displaying slots with non-shop-item shuffles.").Color(THEME_COLOR))) {
hideShopUnshuffledChecks = !hideShopUnshuffledChecks;
UpdateFilters();
}
UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots with non-shop-item shuffles.");
if (UIWidgets::EnhancementCheckbox("Always show gold skulltulas", CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), false, "")) {
if (UIWidgets::CVarCheckbox("Always show gold skulltulas", CVAR_TRACKER_CHECK("AlwaysShowGSLocs"),
UIWidgets::CheckboxOptions().Tooltip("If enabled, will show GS locations in the tracker regardless of tokensanity settings.").Color(THEME_COLOR))) {
alwaysShowGS = !alwaysShowGS;
UpdateFilters();
}
UIWidgets::Tooltip("If enabled, will show GS locations in the tracker regardless of tokensanity settings.");
UIWidgets::EnhancementCheckbox("Show Logic", "gCheckTrackerOptionShowLogic");
UIWidgets::Tooltip("If enabled, will show a check's logic when hovering over it.");
UIWidgets::CVarCheckbox("Show Logic", CVAR_TRACKER_CHECK("ShowLogic"),
UIWidgets::CheckboxOptions().Tooltip("If enabled, will show a check's logic when hovering over it.").Color(THEME_COLOR));
// Filtering settings
UIWidgets::PaddedSeparator();
UIWidgets::EnhancementCheckbox("Filter Empty Areas", CVAR_TRACKER_CHECK("HideFilteredAreas"), false, "", UIWidgets::CheckboxGraphics::Checkmark, true);
UIWidgets::Tooltip("If enabled, will hide area headers that have no locations matching filter");
UIWidgets::CVarCheckbox("Filter Empty Areas", CVAR_TRACKER_CHECK("HideFilteredAreas"),
UIWidgets::CheckboxOptions().Tooltip("If enabled, will hide area headers that have no locations matching filter").Color(THEME_COLOR).DefaultValue(true));
ImGui::TableNextColumn();
CheckTracker::ImGuiDrawTwoColorPickerSection("Area Incomplete", CVAR_TRACKER_CHECK("AreaIncomplete.MainColor"), CVAR_TRACKER_CHECK("AreaIncomplete.ExtraColor"), Color_Area_Incomplete_Main, Color_Area_Incomplete_Extra, Color_Main_Default, Color_Area_Incomplete_Extra_Default, CVAR_TRACKER_CHECK("AreaIncomplete.Hide"), "");
CheckTracker::ImGuiDrawTwoColorPickerSection("Area Complete", CVAR_TRACKER_CHECK("AreaComplete.MainColor"), CVAR_TRACKER_CHECK("AreaComplete.ExtraColor"), Color_Area_Complete_Main, Color_Area_Complete_Extra, Color_Main_Default, Color_Area_Complete_Extra_Default, CVAR_TRACKER_CHECK("AreaComplete.Hide"), "");
CheckTracker::ImGuiDrawTwoColorPickerSection("Unchecked", CVAR_TRACKER_CHECK("Unchecked.MainColor"), CVAR_TRACKER_CHECK("Unchecked.ExtraColor"), Color_Unchecked_Main, Color_Unchecked_Extra, Color_Main_Default, Color_Unchecked_Extra_Default, CVAR_TRACKER_CHECK("Unchecked.Hide"), "Checks you have not interacted with at all.");
CheckTracker::ImGuiDrawTwoColorPickerSection("Skipped", CVAR_TRACKER_CHECK("Skipped.MainColor"), CVAR_TRACKER_CHECK("Skipped.ExtraColor"), Color_Skipped_Main, Color_Skipped_Extra, Color_Main_Default, Color_Skipped_Extra_Default, CVAR_TRACKER_CHECK("Skipped.Hide"), "");
CheckTracker::ImGuiDrawTwoColorPickerSection("Seen", CVAR_TRACKER_CHECK("Seen.MainColor"), CVAR_TRACKER_CHECK("Seen.ExtraColor"), Color_Seen_Main, Color_Seen_Extra, Color_Main_Default, Color_Seen_Extra_Default, CVAR_TRACKER_CHECK("Seen.Hide"), "Used for shops. Shows item names for shop slots when walking in, and prices when highlighting them in buy mode.");
CheckTracker::ImGuiDrawTwoColorPickerSection("Scummed", CVAR_TRACKER_CHECK("Scummed.MainColor"), CVAR_TRACKER_CHECK("Scummed.ExtraColor"), Color_Scummed_Main, Color_Scummed_Extra, Color_Main_Default, Color_Scummed_Extra_Default, CVAR_TRACKER_CHECK("Scummed.Hide"), "Checks you collect, but then reload before saving so you no longer have them.");
//CheckTracker::ImGuiDrawTwoColorPickerSection("Hinted (WIP)", CVAR_TRACKER_CHECK("Hinted.MainColor"), CVAR_TRACKER_CHECK("Hinted.ExtraColor"), Color_Hinted_Main, Color_Hinted_Extra, Color_Main_Default, Color_Hinted_Extra_Default, CVAR_TRACKER_CHECK("Hinted.Hide"), "");
CheckTracker::ImGuiDrawTwoColorPickerSection("Collected", CVAR_TRACKER_CHECK("Collected.MainColor"), CVAR_TRACKER_CHECK("Collected.ExtraColor"), Color_Collected_Main, Color_Collected_Extra, Color_Main_Default, Color_Collected_Extra_Default, CVAR_TRACKER_CHECK("Collected.Hide"), "Checks you have collected without saving or reloading yet.");
CheckTracker::ImGuiDrawTwoColorPickerSection("Saved", CVAR_TRACKER_CHECK("Saved.MainColor"), CVAR_TRACKER_CHECK("Saved.ExtraColor"), Color_Saved_Main, Color_Saved_Extra, Color_Main_Default, Color_Saved_Extra_Default, CVAR_TRACKER_CHECK("Saved.Hide"), "Checks that you saved the game while having collected.");
CheckTracker::ImGuiDrawTwoColorPickerSection("Area Incomplete", CVAR_TRACKER_CHECK("AreaIncomplete.MainColor"), CVAR_TRACKER_CHECK("AreaIncomplete.ExtraColor"), Color_Area_Incomplete_Main, Color_Area_Incomplete_Extra, Color_Main_Default, Color_Area_Incomplete_Extra_Default, CVAR_TRACKER_CHECK("AreaIncomplete.Hide"), "", THEME_COLOR);
CheckTracker::ImGuiDrawTwoColorPickerSection("Area Complete", CVAR_TRACKER_CHECK("AreaComplete.MainColor"), CVAR_TRACKER_CHECK("AreaComplete.ExtraColor"), Color_Area_Complete_Main, Color_Area_Complete_Extra, Color_Main_Default, Color_Area_Complete_Extra_Default, CVAR_TRACKER_CHECK("AreaComplete.Hide"), "", THEME_COLOR);
CheckTracker::ImGuiDrawTwoColorPickerSection("Unchecked", CVAR_TRACKER_CHECK("Unchecked.MainColor"), CVAR_TRACKER_CHECK("Unchecked.ExtraColor"), Color_Unchecked_Main, Color_Unchecked_Extra, Color_Main_Default, Color_Unchecked_Extra_Default, CVAR_TRACKER_CHECK("Unchecked.Hide"), "Checks you have not interacted with at all.", THEME_COLOR);
CheckTracker::ImGuiDrawTwoColorPickerSection("Skipped", CVAR_TRACKER_CHECK("Skipped.MainColor"), CVAR_TRACKER_CHECK("Skipped.ExtraColor"), Color_Skipped_Main, Color_Skipped_Extra, Color_Main_Default, Color_Skipped_Extra_Default, CVAR_TRACKER_CHECK("Skipped.Hide"), "", THEME_COLOR);
CheckTracker::ImGuiDrawTwoColorPickerSection("Seen", CVAR_TRACKER_CHECK("Seen.MainColor"), CVAR_TRACKER_CHECK("Seen.ExtraColor"), Color_Seen_Main, Color_Seen_Extra, Color_Main_Default, Color_Seen_Extra_Default, CVAR_TRACKER_CHECK("Seen.Hide"), "Used for shops. Shows item names for shop slots when walking in, and prices when highlighting them in buy mode.", THEME_COLOR);
CheckTracker::ImGuiDrawTwoColorPickerSection("Scummed", CVAR_TRACKER_CHECK("Scummed.MainColor"), CVAR_TRACKER_CHECK("Scummed.ExtraColor"), Color_Scummed_Main, Color_Scummed_Extra, Color_Main_Default, Color_Scummed_Extra_Default, CVAR_TRACKER_CHECK("Scummed.Hide"), "Checks you collect, but then reload before saving so you no longer have them.", THEME_COLOR);
//CheckTracker::ImGuiDrawTwoColorPickerSection("Hinted (WIP)", CVAR_TRACKER_CHECK("Hinted.MainColor"), CVAR_TRACKER_CHECK("Hinted.ExtraColor"), Color_Hinted_Main, Color_Hinted_Extra, Color_Main_Default, Color_Hinted_Extra_Default, CVAR_TRACKER_CHECK("Hinted.Hide"), "", THEME_COLOR);
CheckTracker::ImGuiDrawTwoColorPickerSection("Collected", CVAR_TRACKER_CHECK("Collected.MainColor"), CVAR_TRACKER_CHECK("Collected.ExtraColor"), Color_Collected_Main, Color_Collected_Extra, Color_Main_Default, Color_Collected_Extra_Default, CVAR_TRACKER_CHECK("Collected.Hide"), "Checks you have collected without saving or reloading yet.", THEME_COLOR);
CheckTracker::ImGuiDrawTwoColorPickerSection("Saved", CVAR_TRACKER_CHECK("Saved.MainColor"), CVAR_TRACKER_CHECK("Saved.ExtraColor"), Color_Saved_Main, Color_Saved_Extra, Color_Main_Default, Color_Saved_Extra_Default, CVAR_TRACKER_CHECK("Saved.Hide"), "Checks that you saved the game while having collected.", THEME_COLOR);
ImGui::PopStyleVar(1);
}
ImGui::EndTable();
ImGui::PopFont();
}
void CheckTrackerWindow::InitElement() {
@ -1807,36 +1850,5 @@ void CheckTrackerWindow::InitElement() {
}
void CheckTrackerWindow::UpdateElement() {
Color_Background = CVarGetColor(CVAR_TRACKER_CHECK("BgColor"), Color_Bg_Default);
Color_Area_Incomplete_Main = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.MainColor"), Color_Main_Default);
Color_Area_Incomplete_Extra = CVarGetColor(CVAR_TRACKER_CHECK("AreaIncomplete.ExtraColor"), Color_Area_Incomplete_Extra_Default);
Color_Area_Complete_Main = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.MainColor"), Color_Main_Default);
Color_Area_Complete_Extra = CVarGetColor(CVAR_TRACKER_CHECK("AreaComplete.ExtraColor"), Color_Area_Complete_Extra_Default);
Color_Unchecked_Main = CVarGetColor(CVAR_TRACKER_CHECK("Unchecked.MainColor"), Color_Main_Default);
Color_Unchecked_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Unchecked.ExtraColor"), Color_Unchecked_Extra_Default);
Color_Skipped_Main = CVarGetColor(CVAR_TRACKER_CHECK("Skipped.MainColor"), Color_Main_Default);
Color_Skipped_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Skipped.ExtraColor"), Color_Skipped_Extra_Default);
Color_Seen_Main = CVarGetColor(CVAR_TRACKER_CHECK("Seen.MainColor"), Color_Main_Default);
Color_Seen_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Seen.ExtraColor"), Color_Seen_Extra_Default);
Color_Hinted_Main = CVarGetColor(CVAR_TRACKER_CHECK("Hinted.MainColor"), Color_Main_Default);
Color_Hinted_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Hinted.ExtraColor"), Color_Hinted_Extra_Default);
Color_Collected_Main = CVarGetColor(CVAR_TRACKER_CHECK("Collected.MainColor"), Color_Main_Default);
Color_Collected_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Collected.ExtraColor"), Color_Collected_Extra_Default);
Color_Scummed_Main = CVarGetColor(CVAR_TRACKER_CHECK("Scummed.MainColor"), Color_Main_Default);
Color_Scummed_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Scummed.ExtraColor"), Color_Scummed_Extra_Default);
Color_Saved_Main = CVarGetColor(CVAR_TRACKER_CHECK("Saved.MainColor"), Color_Main_Default);
Color_Saved_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Saved.ExtraColor"), Color_Saved_Extra_Default);
hideUnchecked = CVarGetInteger(CVAR_TRACKER_CHECK("Unchecked.Hide"), 0);
hideScummed = CVarGetInteger(CVAR_TRACKER_CHECK("Scummed.Hide"), 0);
hideSeen = CVarGetInteger(CVAR_TRACKER_CHECK("Seen.Hide"), 0);
hideSkipped = CVarGetInteger(CVAR_TRACKER_CHECK("Skipped.Hide"), 0);
hideSaved = CVarGetInteger(CVAR_TRACKER_CHECK("Saved.Hide"), 0);
hideCollected = CVarGetInteger(CVAR_TRACKER_CHECK("Collected.Hide"), 0);
showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0);
mystery = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0);
showLogicTooltip = CVarGetInteger("gCheckTrackerOptionShowLogic", 0);
hideShopUnshuffledChecks = CVarGetInteger(CVAR_TRACKER_CHECK("HideUnshuffledShopChecks"), 1);
alwaysShowGS = CVarGetInteger(CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), 0);
}
} // namespace CheckTracker

View file

@ -2,6 +2,7 @@
#include <nlohmann/json.hpp>
#include "randomizerTypes.h"
#include "randomizer_check_objects.h"
#include "soh/SohGui/UIWidgets.hpp"
#include <libultraship/libultraship.h>

View file

@ -1,7 +1,7 @@
#include "randomizer_entrance_tracker.h"
#include "soh/OTRGlobals.h"
#include "soh/cvar_prefixes.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include <map>
#include <string>
@ -659,65 +659,62 @@ void InitEntranceTrackingData() {
}
void EntranceTrackerSettingsWindow::DrawElement() {
if (ImGui::BeginTable("entranceTrackerSettings", 1, ImGuiTableFlags_BordersInnerH)) {
ImGui::TableNextColumn();
UIWidgets::Spacer(0);
ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger);
ImGui::TextWrapped("The entrance tracker will only track shuffled entrances");
UIWidgets::Spacer(0);
ImGui::TableNextColumn();
if (ImGui::BeginTable("entranceTrackerSubSettings", 2, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchProp)) {
ImGui::TableSetupColumn("column 1", ImGuiTableColumnFlags_WidthStretch, 150.0f);
ImGui::TableSetupColumn("column 2", ImGuiTableColumnFlags_WidthStretch, 150.0f);
ImGui::TableNextColumn();
ImGui::Text("Sort By");
UIWidgets::EnhancementRadioButton("To", CVAR_TRACKER_ENTRANCE("SortBy"), 0);
UIWidgets::Tooltip("Sort entrances by the original source entrance");
UIWidgets::EnhancementRadioButton("From", CVAR_TRACKER_ENTRANCE("SortBy"), 1);
UIWidgets::Tooltip("Sort entrances by the overrided destination");
UIWidgets::Spacer(2.0f);
UIWidgets::CVarRadioButton("To", CVAR_TRACKER_ENTRANCE("SortBy"), 0,
UIWidgets::RadioButtonsOptions()
.Color(THEME_COLOR)
.Tooltip("Sort entrances by the original source entrance"));
UIWidgets::CVarRadioButton("From", CVAR_TRACKER_ENTRANCE("SortBy"), 1,
UIWidgets::RadioButtonsOptions()
.Color(THEME_COLOR).Tooltip("Sort entrances by the overrided destination"));
ImGui::Text("List Items");
UIWidgets::PaddedEnhancementCheckbox("Auto scroll", CVAR_TRACKER_ENTRANCE("AutoScroll"), true, false);
UIWidgets::Tooltip("Automatically scroll to the first aviable entrance in the current scene");
UIWidgets::PaddedEnhancementCheckbox("Highlight previous", CVAR_TRACKER_ENTRANCE("HighlightPrevious"), true, false);
UIWidgets::Tooltip("Highlight the previous entrance that Link came from");
UIWidgets::PaddedEnhancementCheckbox("Highlight available", CVAR_TRACKER_ENTRANCE("HighlightAvailable"), true, false);
UIWidgets::Tooltip("Highlight available entrances in the current scene");
UIWidgets::PaddedEnhancementCheckbox("Hide undiscovered", CVAR_TRACKER_ENTRANCE("CollapseUndiscovered"), true, false);
UIWidgets::Tooltip("Collapse undiscovered entrances towards the bottom of each group");
UIWidgets::CVarCheckbox("Auto scroll", CVAR_TRACKER_ENTRANCE("AutoScroll"),
UIWidgets::CheckboxOptions().Tooltip("Automatically scroll to the first aviable entrance in the current scene").Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Highlight previous", CVAR_TRACKER_ENTRANCE("HighlightPrevious"),
UIWidgets::CheckboxOptions().Tooltip("Highlight the previous entrance that Link came from").Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Highlight available", CVAR_TRACKER_ENTRANCE("HighlightAvailable"),
UIWidgets::CheckboxOptions().Tooltip("Highlight available entrances in the current scene").Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Hide undiscovered", CVAR_TRACKER_ENTRANCE("CollapseUndiscovered"),
UIWidgets::CheckboxOptions().Tooltip("Collapse undiscovered entrances towards the bottom of each group").Color(THEME_COLOR));
bool disableHideReverseEntrances = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_DECOUPLED_ENTRANCES) == RO_GENERIC_ON;
static const char* disableHideReverseEntrancesText = "This option is disabled because \"Decouple Entrances\" is enabled.";
UIWidgets::PaddedEnhancementCheckbox("Hide reverse", CVAR_TRACKER_ENTRANCE("HideReverseEntrances"), true, false,
disableHideReverseEntrances, disableHideReverseEntrancesText, UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip("Hide reverse entrance transitions when Decouple Entrances is off");
UIWidgets::Spacer(0);
UIWidgets::CVarCheckbox("Hide reverse", CVAR_TRACKER_ENTRANCE("HideReverseEntrances"),
UIWidgets::CheckboxOptions({ {.disabled = disableHideReverseEntrances, .disabledTooltip = disableHideReverseEntrancesText }})
.Tooltip("Hide reverse entrance transitions when Decouple Entrances is off").DefaultValue(true).Color(THEME_COLOR));
ImGui::TableNextColumn();
ImGui::Text("Group By");
UIWidgets::EnhancementRadioButton("Area", CVAR_TRACKER_ENTRANCE("GroupBy"), 0);
UIWidgets::Tooltip("Group entrances by their area");
UIWidgets::EnhancementRadioButton("Type", CVAR_TRACKER_ENTRANCE("GroupBy"), 1);
UIWidgets::Tooltip("Group entrances by their entrance type");
UIWidgets::Spacer(2.0f);
UIWidgets::CVarRadioButton(
"Area", CVAR_TRACKER_ENTRANCE("GroupBy"), 0,
UIWidgets::RadioButtonsOptions().Color(THEME_COLOR).Tooltip("Group entrances by their area"));
UIWidgets::CVarRadioButton(
"Type", CVAR_TRACKER_ENTRANCE("GroupBy"), 1,
UIWidgets::RadioButtonsOptions().Color(THEME_COLOR).Tooltip("Group entrances by their entrance type"));
ImGui::Text("Spoiler Reveal");
UIWidgets::PaddedEnhancementCheckbox("Show Source", CVAR_TRACKER_ENTRANCE("ShowFrom"), true, false);
UIWidgets::Tooltip("Reveal the sourcefor undiscovered entrances");
UIWidgets::PaddedEnhancementCheckbox("Show Destination", CVAR_TRACKER_ENTRANCE("ShowTo"), true, false);
UIWidgets::Tooltip("Reveal the destination for undiscovered entrances");
UIWidgets::CVarCheckbox("Show Source", CVAR_TRACKER_ENTRANCE("ShowFrom"),
UIWidgets::CheckboxOptions().Tooltip("Reveal the sourcefor undiscovered entrances").Color(THEME_COLOR));
UIWidgets::CVarCheckbox("Show Destination", CVAR_TRACKER_ENTRANCE("ShowTo"),
UIWidgets::CheckboxOptions().Tooltip("Reveal the destination for undiscovered entrances").Color(THEME_COLOR));
ImGui::EndTable();
}
ImGui::TableNextColumn();
ImGui::SetNextItemOpen(false, ImGuiCond_Once);
if (ImGui::TreeNode("Legend")) {
ImGui::TextColored(ImColor(COLOR_ORANGE), "Last Entrance");
@ -725,11 +722,7 @@ void EntranceTrackerSettingsWindow::DrawElement() {
ImGui::TextColored(ImColor(COLOR_GRAY), "Undiscovered Entrances");
ImGui::TreePop();
}
UIWidgets::Spacer(0);
ImGui::EndTable();
}
ImGui::PopFont();
}
void EntranceTrackerWindow::Draw() {
@ -742,6 +735,7 @@ void EntranceTrackerWindow::Draw() {
}
void EntranceTrackerWindow::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger);
ImGui::SetNextWindowSize(ImVec2(600, 375), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Entrance Tracker", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
@ -752,24 +746,26 @@ void EntranceTrackerWindow::DrawElement() {
static ImGuiTextFilter locationSearch;
uint8_t nextTreeState = 0;
if (ImGui::Button("Collapse All")) {
if (UIWidgets::Button("Collapse All", UIWidgets::ButtonOptions({{ .tooltip = "Collapse all entrance groups" }})
.Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
nextTreeState = 1;
}
UIWidgets::Tooltip("Collapse all entrance groups");
ImGui::SameLine();
if (ImGui::Button("Expand All")) {
if (UIWidgets::Button("Expand All", UIWidgets::ButtonOptions({{ .tooltip = "Expand all entrance groups" }})
.Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
nextTreeState = 2;
}
UIWidgets::Tooltip("Expand all entrance groups");
ImGui::SameLine();
if (ImGui::Button("Clear")) {
if (UIWidgets::Button("Clear", UIWidgets::ButtonOptions({{ .tooltip = "Clear the search field" }})
.Color(THEME_COLOR).Size(UIWidgets::Sizes::Inline))) {
locationSearch.Clear();
}
UIWidgets::Tooltip("Clear the search field");
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (locationSearch.Draw()) {
nextTreeState = 2;
}
UIWidgets::PopStyleCombobox();
uint8_t destToggle = CVarGetInteger(CVAR_TRACKER_ENTRANCE("SortBy"), 0);
uint8_t groupToggle = CVarGetInteger(CVAR_TRACKER_ENTRANCE("GroupBy"), 0);
@ -940,8 +936,8 @@ void EntranceTrackerWindow::DrawElement() {
}
}
ImGui::EndChild();
ImGui::End();
ImGui::PopFont();
}
void EntranceTrackerWindow::InitElement() {

View file

@ -100,8 +100,8 @@ class EntranceTrackerSettingsWindow : public Ship::GuiWindow {
class EntranceTrackerWindow : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
void Draw() override;
void InitElement() override;
void DrawElement() override;
void UpdateElement() override {};

View file

@ -5,6 +5,7 @@
#include "soh/SaveManager.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/SohGui/SohGui.hpp"
#include "randomizerTypes.h"
#include <map>
@ -35,6 +36,8 @@ void DrawSong(ItemTrackerItem item);
int itemTrackerSectionId;
using namespace UIWidgets;
bool shouldUpdateVectors = true;
std::vector<ItemTrackerItem> mainWindowItems = {};
@ -616,7 +619,7 @@ void DrawEquip(ItemTrackerItem item) {
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasEquip && IsValidSaveFile() ? item.name : item.nameFaded),
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id));
Tooltip(SohUtils::GetItemName(item.id).c_str());
}
void DrawQuest(ItemTrackerItem item) {
@ -632,7 +635,7 @@ void DrawQuest(ItemTrackerItem item) {
ImGui::EndGroup();
UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(item.id));
Tooltip(SohUtils::GetQuestItemName(item.id).c_str());
};
void DrawItem(ItemTrackerItem item) {
@ -800,7 +803,7 @@ void DrawItem(ItemTrackerItem item) {
itemName = SohUtils::GetItemName(item.id);
}
UIWidgets::SetLastItemHoverText(itemName);
Tooltip(itemName.c_str());
}
void DrawBottle(ItemTrackerItem item) {
@ -815,7 +818,7 @@ void DrawBottle(ItemTrackerItem item) {
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem && IsValidSaveFile() ? item.name : item.nameFaded),
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id));
Tooltip(SohUtils::GetItemName(item.id).c_str());
};
void DrawDungeonItem(ItemTrackerItem item) {
@ -864,7 +867,7 @@ void DrawDungeonItem(ItemTrackerItem item) {
}
ImGui::EndGroup();
UIWidgets::SetLastItemHoverText(SohUtils::GetItemName(item.id));
Tooltip(SohUtils::GetItemName(item.id).c_str());
}
void DrawSong(ItemTrackerItem item) {
@ -874,7 +877,7 @@ void DrawSong(ItemTrackerItem item) {
ImGui::SetCursorScreenPos(ImVec2(p.x + 6, p.y));
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasSong && IsValidSaveFile() ? item.name : item.nameFaded),
ImVec2(iconSize / 1.5, iconSize), ImVec2(0, 0), ImVec2(1, 1));
UIWidgets::SetLastItemHoverText(SohUtils::GetQuestItemName(item.id));
Tooltip(SohUtils::GetQuestItemName(item.id).c_str());
}
void DrawNotes(bool resizeable = false) {
@ -931,7 +934,6 @@ void DrawTotalChecks() {
}
// Windowing stuff
ImVec4 ChromaKeyBackground = { 0, 0, 0, 0 }; // Float value, 1 = 255 in rgb value.
void BeginFloatingWindows(std::string UniqueName, ImGuiWindowFlags flags = 0) {
ImGuiWindowFlags windowFlags = flags;
@ -947,7 +949,7 @@ void BeginFloatingWindows(std::string UniqueName, ImGuiWindowFlags flags = 0) {
windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
}
}
ImGui::PushStyleColor(ImGuiCol_WindowBg, ChromaKeyBackground);
ImGui::PushStyleColor(ImGuiCol_WindowBg, VecFromRGBA8(CVarGetColor(CVAR_TRACKER_ITEM("BgColor.Value"), {0, 0, 0, 0})));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f);
ImGui::Begin(UniqueName.c_str(), nullptr, windowFlags);
@ -1220,6 +1222,7 @@ void ItemTrackerWindow::Draw() {
}
void ItemTrackerWindow::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger);
UpdateVectors();
int iconSize = CVarGetInteger(CVAR_TRACKER_ITEM("IconSize"), 36);
@ -1350,19 +1353,29 @@ void ItemTrackerWindow::DrawElement() {
EndFloatingWindows();
}
}
ImGui::PopFont();
}
static const char* itemTrackerCapacityTrackOptions[5] = { "No Numbers", "Current Capacity", "Current Ammo", "Current Capacity / Max Capacity", "Current Ammo / Current Capacity" };
static const char* itemTrackerKeyTrackOptions[3] = { "Collected / Max", "Current / Collected / Max", "Current / Max" };
static const char* itemTrackerTriforcePieceTrackOptions[2] = { "Collected / Required", "Collected / Required / Max" };
static const char* windowTypes[2] = { "Floating", "Window" };
static const char* displayModes[2] = { "Always", "Combo Button Hold" };
static const char* buttons[14] = { "A", "B", "C-Up", "C-Down", "C-Left", "C-Right", "L", "Z", "R", "Start", "D-Up", "D-Down", "D-Left", "D-Right" };
static const char* displayTypes[3] = { "Hidden", "Main Window", "Separate" };
static const char* extendedDisplayTypes[4] = { "Hidden", "Main Window", "Misc Window", "Separate" };
static const char* minimalDisplayTypes[2] = { "Hidden", "Separate" };
static std::unordered_map<int32_t, const char*> itemTrackerCapacityTrackOptions = {
{ ITEM_TRACKER_NUMBER_NONE, "No Numbers" }, { ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY, "Current Capacity" }, { ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY, "Current Ammo" },
{ ITEM_TRACKER_NUMBER_CAPACITY, "Current Capacity / Max Capacity" }, { ITEM_TRACKER_NUMBER_AMMO, "Current Ammo / Current Capacity" }};
static std::unordered_map<int32_t, const char*> itemTrackerKeyTrackOptions = {
{ KEYS_COLLECTED_MAX, "Collected / Max" }, { KEYS_CURRENT_COLLECTED_MAX, "Current / Collected / Max" }, { KEYS_CURRENT_MAX, "Current / Max" }};
static std::unordered_map<int32_t, const char*> itemTrackerTriforcePieceTrackOptions = {
{ TRIFORCE_PIECE_COLLECTED_REQUIRED, "Collected / Required" }, { TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX, "Collected / Required / Max" }};
static std::unordered_map<int32_t, const char*> windowTypes = {{ TRACKER_WINDOW_FLOATING, "Floating" }, { TRACKER_WINDOW_WINDOW, "Window" }};
static std::unordered_map<int32_t, const char*> displayModes = {{ TRACKER_DISPLAY_ALWAYS, "Always" }, { TRACKER_DISPLAY_COMBO_BUTTON, "Combo Button Hold" }};
static std::unordered_map<int32_t, const char*> buttons = {{ TRACKER_COMBO_BUTTON_A, "A" }, { TRACKER_COMBO_BUTTON_B, "B"}, { TRACKER_COMBO_BUTTON_C_UP, "C-Up"},
{ TRACKER_COMBO_BUTTON_C_DOWN, "C-Down" }, { TRACKER_COMBO_BUTTON_C_LEFT, "C-Left" }, { TRACKER_COMBO_BUTTON_C_RIGHT, "C-Right" }, { TRACKER_COMBO_BUTTON_L, "L" },
{ TRACKER_COMBO_BUTTON_Z, "Z" }, { TRACKER_COMBO_BUTTON_R, "R" }, { TRACKER_COMBO_BUTTON_START, "Start" }, { TRACKER_COMBO_BUTTON_D_UP, "D-Up" },
{ TRACKER_COMBO_BUTTON_D_DOWN, "D-Down" }, { TRACKER_COMBO_BUTTON_D_LEFT, "D-Left" }, { TRACKER_COMBO_BUTTON_D_RIGHT, "D-Right" }};
static std::unordered_map<int32_t, const char*> displayTypes = {{ SECTION_DISPLAY_HIDDEN, "Hidden" }, { SECTION_DISPLAY_MAIN_WINDOW, "Main Window" }, { SECTION_DISPLAY_SEPARATE, "Separate" }};
static std::unordered_map<int32_t, const char*> extendedDisplayTypes = {{ SECTION_DISPLAY_EXTENDED_HIDDEN, "Hidden" },
{ SECTION_DISPLAY_EXTENDED_MAIN_WINDOW, "Main Window" }, { SECTION_DISPLAY_EXTENDED_MISC_WINDOW, "Misc Window" }, { SECTION_DISPLAY_EXTENDED_SEPARATE, "Separate" }};
static std::unordered_map<int32_t, const char*> minimalDisplayTypes = {{ SECTION_DISPLAY_MINIMAL_HIDDEN, "Hidden" }, { SECTION_DISPLAY_MINIMAL_SEPARATE, "Separate" }};
void ItemTrackerSettingsWindow::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontStandardLarger);
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f });
ImGui::BeginTable("itemTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV);
ImGui::TableSetupColumn("General settings", ImGuiTableColumnFlags_WidthStretch, 200.0f);
@ -1370,154 +1383,168 @@ void ItemTrackerSettingsWindow::DrawElement() {
ImGui::TableHeadersRow();
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("BG Color");
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::ColorEdit4("BG Color##gItemTrackerBgColor", (float*)&ChromaKeyBackground, ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_NoLabel)) {
CVarSetFloat(CVAR_TRACKER_ITEM("BgColorR"), ChromaKeyBackground.x);
CVarSetFloat(CVAR_TRACKER_ITEM("BgColorG"), ChromaKeyBackground.y);
CVarSetFloat(CVAR_TRACKER_ITEM("BgColorB"), ChromaKeyBackground.z);
CVarSetFloat(CVAR_TRACKER_ITEM("BgColorA"), ChromaKeyBackground.w);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::PopItemWidth();
CVarColorPicker("Background Color##gItemTrackerBgColor", CVAR_TRACKER_ITEM("BgColor"), { 0, 0, 0, 0 }, true,
ColorPickerRandomButton | ColorPickerResetButton, THEME_COLOR);
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Window Type", CVAR_TRACKER_ITEM("WindowType"), windowTypes, TRACKER_WINDOW_FLOATING)) {
ImGui::PopItemWidth();
if (CVarCombobox("Window Type", CVAR_TRACKER_ITEM("WindowType"), windowTypes, ComboboxOptions()
.DefaultIndex(TRACKER_WINDOW_FLOATING).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (CVarGetInteger(CVAR_TRACKER_ITEM("WindowType"), TRACKER_WINDOW_FLOATING) == TRACKER_WINDOW_FLOATING) {
if (UIWidgets::PaddedEnhancementCheckbox("Enable Dragging", CVAR_TRACKER_ITEM("Draggable"))) {
if (CVarCheckbox("Enable Dragging", CVAR_TRACKER_ITEM("Draggable"), CheckboxOptions().Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::PaddedEnhancementCheckbox("Only enable while paused", CVAR_TRACKER_ITEM("ShowOnlyPaused"))) {
if (CVarCheckbox("Only enable while paused", CVAR_TRACKER_ITEM("ShowOnlyPaused"), CheckboxOptions().Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Display Mode", CVAR_TRACKER_ITEM("DisplayType.Main"), displayModes, TRACKER_DISPLAY_ALWAYS)) {
if (CVarCombobox("Display Mode", CVAR_TRACKER_ITEM("DisplayType.Main"), displayModes, ComboboxOptions()
.DefaultIndex(TRACKER_DISPLAY_ALWAYS).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_COMBO_BUTTON) {
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Combo Button 1", CVAR_TRACKER_ITEM("ComboButton1"), buttons, TRACKER_COMBO_BUTTON_L)) {
if (CVarCombobox("Combo Button 1", CVAR_TRACKER_ITEM("ComboButton1"), buttons, ComboboxOptions()
.DefaultIndex(TRACKER_COMBO_BUTTON_L).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Combo Button 2", CVAR_TRACKER_ITEM("ComboButton2"), buttons, TRACKER_COMBO_BUTTON_R)) {
if (CVarCombobox("Combo Button 2", CVAR_TRACKER_ITEM("ComboButton2"), buttons, ComboboxOptions()
.DefaultIndex(TRACKER_COMBO_BUTTON_R).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
}
}
UIWidgets::PaddedSeparator();
UIWidgets::EnhancementSliderInt("Icon size : %dpx", "##ITEMTRACKERICONSIZE", CVAR_TRACKER_ITEM("IconSize"), 25, 128, "", 36);
UIWidgets::EnhancementSliderInt("Icon margins : %dpx", "##ITEMTRACKERSPACING", CVAR_TRACKER_ITEM("IconSpacing"), -5, 50, "", 12);
UIWidgets::EnhancementSliderInt("Text size : %dpx", "##ITEMTRACKERTEXTSIZE", CVAR_TRACKER_ITEM("TextSize"), 1, 30, "", 13);
ImGui::Separator();
CVarSliderInt("Icon size : %dpx", CVAR_TRACKER_ITEM("IconSize"), IntSliderOptions().Min(25).Max(128).DefaultValue(36).Color(THEME_COLOR));
CVarSliderInt("Icon margins : %dpx", CVAR_TRACKER_ITEM("IconSpacing"), IntSliderOptions().Min(-5).Max(50).DefaultValue(12).Color(THEME_COLOR));
CVarSliderInt("Text size : %dpx", CVAR_TRACKER_ITEM("TextSize"), IntSliderOptions().Min(1).Max(30).DefaultValue(13).Color(THEME_COLOR));
UIWidgets::Spacer(0);
ImGui::Text("Ammo/Capacity Tracking");
UIWidgets::EnhancementCombobox(CVAR_TRACKER_ITEM("ItemCountType"), itemTrackerCapacityTrackOptions, ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY);
UIWidgets::InsertHelpHoverText("Customize what the numbers under each item are tracking."
"\n\nNote: items without capacity upgrades will track ammo even in capacity mode");
ImGui::NewLine();
CVarCombobox("Ammo/Capacity Tracking", CVAR_TRACKER_ITEM("ItemCountType"), itemTrackerCapacityTrackOptions, ComboboxOptions()
.DefaultIndex(ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY).ComponentAlignment(ComponentAlignment::Left)
.LabelPosition(LabelPosition::Above).Color(THEME_COLOR)
.Tooltip("Customize what the numbers under each item are tracking."
"\n\nNote: items without capacity upgrades will track ammo even in capacity mode"));
if (CVarGetInteger(CVAR_TRACKER_ITEM("ItemCountType"), ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY) == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY || CVarGetInteger(CVAR_TRACKER_ITEM("ItemCountType"), ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY) == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY) {
if (UIWidgets::PaddedEnhancementCheckbox("Align count to left side", CVAR_TRACKER_ITEM("ItemCountAlignLeft"))) {
if (CVarCheckbox("Align count to left side", CVAR_TRACKER_ITEM("ItemCountAlignLeft"), CheckboxOptions().Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
}
UIWidgets::Spacer(0);
CVarCombobox("Key Count Tracking", CVAR_TRACKER_ITEM("KeyCounts"), itemTrackerKeyTrackOptions, ComboboxOptions()
.DefaultIndex(KEYS_COLLECTED_MAX).ComponentAlignment(ComponentAlignment::Left)
.LabelPosition(LabelPosition::Above).Color(THEME_COLOR)
.Tooltip("Customize what numbers are shown for key tracking."));
ImGui::Text("Key Count Tracking");
UIWidgets::EnhancementCombobox(CVAR_TRACKER_ITEM("KeyCounts"), itemTrackerKeyTrackOptions, KEYS_COLLECTED_MAX);
UIWidgets::InsertHelpHoverText("Customize what numbers are shown for key tracking.");
UIWidgets::Spacer(0);
ImGui::Text("Triforce Piece Count Tracking");
UIWidgets::EnhancementCombobox(CVAR_TRACKER_ITEM("TriforcePieceCounts"), itemTrackerTriforcePieceTrackOptions, TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX);
UIWidgets::InsertHelpHoverText("Customize what numbers are shown for triforce piece tracking.");
CVarCombobox("Triforce Piece Count Tracking", CVAR_TRACKER_ITEM("TriforcePieceCounts"), itemTrackerTriforcePieceTrackOptions, ComboboxOptions()
.DefaultIndex(TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX).ComponentAlignment(ComponentAlignment::Left)
.LabelPosition(LabelPosition::Above).Color(THEME_COLOR)
.Tooltip("Customize what numbers are shown for triforce piece tracking."));
ImGui::TableNextColumn();
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Inventory", CVAR_TRACKER_ITEM("DisplayType.Inventory"), displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) {
if (CVarCombobox("Inventory", CVAR_TRACKER_ITEM("DisplayType.Inventory"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Equipment", CVAR_TRACKER_ITEM("DisplayType.Equipment"), displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) {
if (CVarCombobox("Equipment", CVAR_TRACKER_ITEM("DisplayType.Equipment"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Misc", CVAR_TRACKER_ITEM("DisplayType.Misc"), displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) {
if (CVarCombobox("Misc", CVAR_TRACKER_ITEM("DisplayType.Misc"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Dungeon Rewards", CVAR_TRACKER_ITEM("DisplayType.DungeonRewards"), displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) {
if (CVarCombobox("Dungeon Rewards", CVAR_TRACKER_ITEM("DisplayType.DungeonRewards"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.DungeonRewards"), SECTION_DISPLAY_MAIN_WINDOW) == SECTION_DISPLAY_SEPARATE) {
if (UIWidgets::PaddedEnhancementCheckbox("Circle display", CVAR_TRACKER_ITEM("DungeonRewardsLayout"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, false)) {
if (CVarCheckbox("Circle display", CVAR_TRACKER_ITEM("DungeonRewardsLayout"))) {
shouldUpdateVectors = true;
}
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Songs", CVAR_TRACKER_ITEM("DisplayType.Songs"), displayTypes, SECTION_DISPLAY_MAIN_WINDOW)) {
if (CVarCombobox("Songs", CVAR_TRACKER_ITEM("DisplayType.Songs"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_MAIN_WINDOW).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Dungeon Items", CVAR_TRACKER_ITEM("DisplayType.DungeonItems"), displayTypes, SECTION_DISPLAY_HIDDEN)) {
if (CVarCombobox("Dungeon Items", CVAR_TRACKER_ITEM("DisplayType.DungeonItems"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.DungeonItems"), SECTION_DISPLAY_HIDDEN) != SECTION_DISPLAY_HIDDEN) {
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.DungeonItems"), SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE) {
if (UIWidgets::PaddedEnhancementCheckbox("Horizontal display", CVAR_TRACKER_ITEM("DungeonItems.Layout"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true)) {
if (CVarCheckbox("Horizontal display", CVAR_TRACKER_ITEM("DungeonItems.Layout"), CheckboxOptions().DefaultValue(true).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
}
if (UIWidgets::PaddedEnhancementCheckbox("Maps and compasses", CVAR_TRACKER_ITEM("DungeonItems.DisplayMaps"), true, true, false, "", UIWidgets::CheckboxGraphics::Cross, true)) {
if (CVarCheckbox("Maps and compasses", CVAR_TRACKER_ITEM("DungeonItems.DisplayMaps"), CheckboxOptions().DefaultValue(true).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Greg", CVAR_TRACKER_ITEM("DisplayType.Greg"), extendedDisplayTypes, SECTION_DISPLAY_EXTENDED_HIDDEN)) {
if (CVarCombobox("Greg", CVAR_TRACKER_ITEM("DisplayType.Greg"), extendedDisplayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_EXTENDED_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Triforce Pieces", CVAR_TRACKER_ITEM("DisplayType.TriforcePieces"), displayTypes, SECTION_DISPLAY_HIDDEN)) {
if (CVarCombobox("Triforce Pieces", CVAR_TRACKER_ITEM("DisplayType.TriforcePieces"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Boss Souls", CVAR_TRACKER_ITEM("DisplayType.BossSouls"), displayTypes, SECTION_DISPLAY_HIDDEN)) {
if (CVarCombobox("Boss Souls", CVAR_TRACKER_ITEM("DisplayType.BossSouls"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Ocarina Buttons", CVAR_TRACKER_ITEM("DisplayType.OcarinaButtons"), displayTypes, SECTION_DISPLAY_HIDDEN)) {
if (CVarCombobox("Ocarina Buttons", CVAR_TRACKER_ITEM("DisplayType.OcarinaButtons"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Fishing Pole", CVAR_TRACKER_ITEM("DisplayType.FishingPole"), extendedDisplayTypes, SECTION_DISPLAY_EXTENDED_HIDDEN)) {
if (CVarCombobox("Fishing Pole", CVAR_TRACKER_ITEM("DisplayType.FishingPole"), extendedDisplayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_EXTENDED_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Total Checks", "gTrackers.ItemTracker.TotalChecks.DisplayType", minimalDisplayTypes, SECTION_DISPLAY_MINIMAL_HIDDEN)) {
if (CVarCombobox("Total Checks", "gTrackers.ItemTracker.TotalChecks.DisplayType", minimalDisplayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_MINIMAL_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
if (CVarGetInteger(CVAR_TRACKER_ITEM("DisplayType.Main"), TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) {
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Personal notes", CVAR_TRACKER_ITEM("DisplayType.Notes"), displayTypes, SECTION_DISPLAY_HIDDEN)) {
if (CVarCombobox("Personal notes", CVAR_TRACKER_ITEM("DisplayType.Notes"), displayTypes, ComboboxOptions()
.DefaultIndex(SECTION_DISPLAY_HIDDEN).ComponentAlignment(ComponentAlignment::Right)
.LabelPosition(LabelPosition::Far).Color(THEME_COLOR))) {
shouldUpdateVectors = true;
}
}
UIWidgets::EnhancementCheckbox("Show Hookshot Identifiers", CVAR_TRACKER_ITEM("HookshotIdentifier"));
UIWidgets::InsertHelpHoverText("Shows an 'H' or an 'L' to more easiely distinguish between Hookshot and Longshot.");
UIWidgets::Spacer(0);
CVarCheckbox("Show Hookshot Identifiers", CVAR_TRACKER_ITEM("HookshotIdentifier"), CheckboxOptions()
.Tooltip("Shows an 'H' or an 'L' to more easiely distinguish between Hookshot and Longshot.").Color(THEME_COLOR));
ImGui::PopStyleVar(1);
ImGui::EndTable();
ImGui::PopFont();
}
void ItemTrackerWindow::InitElement() {
float trackerBgR = CVarGetFloat(CVAR_TRACKER_ITEM("BgColorR"), 0);
float trackerBgG = CVarGetFloat(CVAR_TRACKER_ITEM("BgColorG"), 0);
float trackerBgB = CVarGetFloat(CVAR_TRACKER_ITEM("BgColorB"), 0);
float trackerBgA = CVarGetFloat(CVAR_TRACKER_ITEM("BgColorA"), 1);
ChromaKeyBackground = {
trackerBgR,
trackerBgG,
trackerBgB,
trackerBgA
}; // Float value, 1 = 255 in rgb value.
// Crashes when the itemTrackerNotes is empty, so add an empty character to it
if (itemTrackerNotes.empty()) {
itemTrackerNotes.push_back(0);

View file

@ -1,3 +1,5 @@
#pragma once
#include <libultraship/libultraship.h>
namespace Rando {

View file

@ -246,15 +246,15 @@ void Settings::CreateOptions() {
OPT_U8(RSK_LACS_OPTIONS, "GCBK LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LacsRewardOptions"), "", WidgetType::Combobox, RO_LACS_STANDARD_REWARD);
OPT_U8(RSK_KEYRINGS, "Key Rings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRings"), mOptionDescriptions[RSK_KEYRINGS], WidgetType::Combobox, RO_KEYRINGS_OFF);
OPT_U8(RSK_KEYRINGS_RANDOM_COUNT, "Keyring Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsRandomCount"), "", WidgetType::Slider, 8);
OPT_U8(RSK_KEYRINGS_GERUDO_FORTRESS, "Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_FOREST_TEMPLE, "Forest Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsForestTemple"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_FIRE_TEMPLE, "Fire Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsFireTemple"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_WATER_TEMPLE, "Water Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsWaterTemple"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_SPIRIT_TEMPLE, "Spirit Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsSpiritTemple"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_SHADOW_TEMPLE, "Shadow Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsShadowTemple"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_BOTTOM_OF_THE_WELL, "Bottom of the Well Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsBottomOfTheWell"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_GTG, "Gerudo Training Ground Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGTG"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_GANONS_CASTLE, "Ganon's Castle Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGanonsCastle"), "", WidgetType::TristateCheckbox, 0);
OPT_U8(RSK_KEYRINGS_GERUDO_FORTRESS, "Gerudo Fortress Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGerudoFortress"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_FOREST_TEMPLE, "Forest Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsForestTemple"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_FIRE_TEMPLE, "Fire Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsFireTemple"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_WATER_TEMPLE, "Water Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsWaterTemple"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_SPIRIT_TEMPLE, "Spirit Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsSpiritTemple"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_SHADOW_TEMPLE, "Shadow Temple Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsShadowTemple"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_BOTTOM_OF_THE_WELL, "Bottom of the Well Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsBottomOfTheWell"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_GTG, "Gerudo Training Ground Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGTG"), "", WidgetType::Combobox, 0);
OPT_U8(RSK_KEYRINGS_GANONS_CASTLE, "Ganon's Castle Keyring", {"No", "Random", "Yes"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleKeyRingsGanonsCastle"), "", WidgetType::Combobox, 0);
//Dummied out due to redundancy with TimeSavers.SkipChildStealth until such a time that logic needs to consider child stealth e.g. because it's freestanding checks are added to freestanding shuffle.
//To undo this dummying, readd this setting to an OptionGroup so it appears in the UI, then edit the timesaver check hooks to look at this, and the timesaver setting to lock itself as needed.
OPT_BOOL(RSK_SKIP_CHILD_STEALTH, "Skip Child Stealth", {"Don't Skip", "Skip"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SkipChildStealth"), mOptionDescriptions[RSK_SKIP_CHILD_STEALTH], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
@ -1674,7 +1674,7 @@ void Settings::UpdateOptionProperties() {
}
// Shuffle 100 GS Reward - Force-Enabled if Ganon's Boss Key is on the 100 GS Reward
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleGanonBossKey"), RO_GANON_BOSS_KEY_VANILLA) == RO_GANON_BOSS_KEY_KAK_TOKENS) {
mOptions[RSK_SHUFFLE_100_GS_REWARD].Disable("This option is force-enabled because \"Ganon's Boss Key\" is set to \"100 GS Reward.\"", UIWidgets::CheckboxGraphics::Checkmark);
mOptions[RSK_SHUFFLE_100_GS_REWARD].Disable("This option is force-enabled because \"Ganon's Boss Key\" is set to \"100 GS Reward.\"");
} else {
mOptions[RSK_SHUFFLE_100_GS_REWARD].Enable();
}

View file

@ -1,4 +1,5 @@
#include "tricks.h"
#include "soh/SohGui/UIWidgets.hpp"
#include <unordered_map>
namespace Rando {
@ -71,7 +72,6 @@ namespace Rando {
const ImVec4 Tricks::GetTextColor(const Tag tag) {
switch(tag) {
case Tag::EXPERIMENTAL:
case Tag::GLITCH:
return { 0.00f, 0.00f, 0.00f, 1.0f };
default:
@ -82,32 +82,33 @@ namespace Rando {
const ImVec4 Tricks::GetTagColor(const Tag tag) {
switch(tag) {
case Tag::NOVICE:
return { 0.09f, 0.55f, 0.37f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::Green);
case Tag::INTERMEDIATE:
return { 0.95f, 0.52f, 0.00f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::Orange);
case Tag::ADVANCED:
return { 0.00f, 0.29f, 0.71f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::Blue);
case Tag::EXPERT:
return { 0.53f, 0.05f, 0.14f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::Red);
case Tag::EXTREME:
return { 0.27f, 0.00f, 0.27f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::Purple);
case Tag::EXPERIMENTAL:
return { 0.00f, 1.00f, 1.00f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::LightBlue);
case Tag::GLITCH:
return { 1.00f, 1.00f, 1.00f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::White);
default:
assert(false);
return { 0.50f, 0.50f, 0.50f, 1.00f };
return UIWidgets::ColorValues.at(UIWidgets::Colors::Gray);
}
}
void Tricks::DrawTagChips(const std::set<Tag>& rtTags) {
void Tricks::DrawTagChips(const std::set<Tag>& rtTags, std::string trickName) {
for (const Tag rtTag : rtTags) {
std::string tagId = GetTagName(rtTag) + "##" + trickName;
ImGui::SameLine();
ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, GetTagColor(rtTag));
ImGui::SmallButton(GetTagName(rtTag).c_str());
ImGui::PopStyleColor();
UIWidgets::PushStyleButton(GetTagColor(rtTag));
ImGui::SmallButton(tagId.c_str());
UIWidgets::PopStyleButton();
ImGui::EndDisabled();
}
}

View file

@ -28,7 +28,7 @@ namespace Rando {
static const std::string GetTagName(Tag tag);
static const ImVec4 GetTextColor(Tag tag);
static const ImVec4 GetTagColor(Tag tag);
static void DrawTagChips(const std::set<Tag>& rtTags);
static void DrawTagChips(const std::set<Tag>& rtTags, std::string trickName = "");
};
}

View file

@ -1,489 +0,0 @@
#include "ResolutionEditor.h"
#include <imgui.h>
#include <libultraship/libultraship.h>
#include "soh/SohGui/UIWidgets.hpp"
#include <graphic/Fast3D/gfx_pc.h>
#include "soh/OTRGlobals.h"
#include "soh/cvar_prefixes.h"
/* Console Variables are grouped under gAdvancedResolution. (e.g. CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled")
The following cvars are used in Libultraship and can be edited here:
- Enabled - Turns Advanced Resolution Mode on.
- AspectRatioX, AspectRatioY - Aspect ratio controls. To toggle off, set either to zero.
- VerticalPixelCount, VerticalResolutionToggle - Resolution controls.
- PixelPerfectMode, IntegerScale.Factor - Pixel Perfect Mode a.k.a. integer scaling controls.
- IntegerScale.FitAutomatically - Automatic resizing for Pixel Perfect Mode.
- IntegerScale.NeverExceedBounds - Prevents manual resizing from exceeding screen bounds.
The following cvars are also implemented in LUS for niche use cases:
- IgnoreAspectCorrection - Stretch framebuffer to fill screen.
This is something of a power-user setting for niche setups that most people won't need or care about,
but may be useful if playing the Switch/Wii U ports on a 4:3 television.
- IntegerScale.ExceedBoundsBy - Offset the max screen bounds, usually by +1.
This isn't that useful at the moment, so it's unused here.
*/
namespace AdvancedResolutionSettings {
enum setting { UPDATE_aspectRatioX, UPDATE_aspectRatioY, UPDATE_verticalPixelCount };
const char* aspectRatioPresetLabels[] = {
"Off", "Custom", "Original (4:3)", "Widescreen (16:9)", "Nintendo 3DS (5:3)", "16:10 (8:5)", "Ultrawide (21:9)"
};
const float aspectRatioPresetsX[] = { 0.0f, 16.0f, 4.0f, 16.0f, 5.0f, 16.0f, 21.0f };
const float aspectRatioPresetsY[] = { 0.0f, 9.0f, 3.0f, 9.0f, 3.0f, 10.0f, 9.0f };
const int default_aspectRatio = 1; // Default combo list option
const char* pixelCountPresetLabels[] = { "Custom", "Native N64 (240p)", "2x (480p)", "3x (720p)", "4x (960p)",
"5x (1200p)", "6x (1440p)", "Full HD (1080p)", "4K (2160p)" };
const int pixelCountPresets[] = { 480, 240, 480, 720, 960, 1200, 1440, 1080, 2160 };
const int default_pixelCount = 0; // Default combo list option
// Resolution clamp values as hardcoded in LUS::Gui::ApplyResolutionChanges()
const uint32_t minVerticalPixelCount = SCREEN_HEIGHT;
const uint32_t maxVerticalPixelCount = 4320; // 18x native, or 8K TV resolution
const unsigned short default_maxIntegerScaleFactor = 6; // Default size of Integer scale factor slider.
enum messageType { MESSAGE_ERROR, MESSAGE_WARNING, MESSAGE_QUESTION, MESSAGE_INFO, MESSAGE_GRAY_75 };
const ImVec4 messageColor[]{
{ 0.85f, 0.0f, 0.0f, 1.0f }, // MESSAGE_ERROR
{ 0.85f, 0.85f, 0.0f, 1.0f }, // MESSAGE_WARNING
{ 0.0f, 0.85f, 0.85f, 1.0f }, // MESSAGE_QUESTION
{ 0.0f, 0.85f, 0.55f, 1.0f }, // MESSAGE_INFO
{ 0.75f, 0.75f, 0.75f, 1.0f } // MESSAGE_GRAY_75
};
const float enhancementSpacerHeight = 19.0f;
void AdvancedResolutionSettingsWindow::InitElement() {
}
void AdvancedResolutionSettingsWindow::DrawElement() {
// Initialise update flags.
bool update[3];
for (uint8_t i = 0; i < sizeof(update); i++)
update[i] = false;
// Initialise integer scale bounds.
short max_integerScaleFactor = default_maxIntegerScaleFactor; // default value, which may or may not get
// overridden depending on viewport res
short integerScale_maximumBounds = 1; // can change when window is resized
// This is mostly just for UX purposes, as Fit Automatically logic is part of LUS.
if (((float)gfx_current_game_window_viewport.width / gfx_current_game_window_viewport.height) >
((float)gfx_current_dimensions.width / gfx_current_dimensions.height)) {
// Scale to window height
integerScale_maximumBounds = gfx_current_game_window_viewport.height / gfx_current_dimensions.height;
} else {
// Scale to window width
integerScale_maximumBounds = gfx_current_game_window_viewport.width / gfx_current_dimensions.width;
}
// Lower-clamping maximum bounds value to 1 is no-longer necessary as that's accounted for in LUS.
// Letting it go below 1 in this Editor will even allow for checking if screen bounds are being exceeded.
if (default_maxIntegerScaleFactor < integerScale_maximumBounds) {
max_integerScaleFactor =
integerScale_maximumBounds + CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0);
}
// Combo List defaults
static int item_aspectRatio = CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.AspectRatio", 3);
static int item_pixelCount = CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.PixelCount", default_pixelCount);
// Stored Values for non-UIWidgets elements
static float aspectRatioX =
CVarGetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioX", aspectRatioPresetsX[item_aspectRatio]);
static float aspectRatioY =
CVarGetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioY", aspectRatioPresetsY[item_aspectRatio]);
static int verticalPixelCount =
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalPixelCount", pixelCountPresets[item_pixelCount]);
// Additional settings
static bool showHorizontalResField = false;
static int horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
// Disabling flags
const bool disabled_everything = !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled", 0);
const bool disabled_pixelCount = !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", 0);
#ifdef __APPLE__
// Display HiDPI warning. (Remove this once we can definitively say it's fixed.)
ImGui::TextColored(messageColor[MESSAGE_INFO],
ICON_FA_INFO_CIRCLE " These settings may behave incorrectly on Retina displays.");
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
#endif
if (ImGui::CollapsingHeader("Original Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
// The original resolution slider (for convenience)
const bool disabled_resolutionSlider = (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", 0) &&
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled", 0)) ||
CVarGetInteger(CVAR_LOW_RES_MODE, 0);
if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %.1f%%", "##IMul", CVAR_INTERNAL_RESOLUTION, 0.5f,
2.0f, "", 1.0f, true, true, disabled_resolutionSlider)) {
Ship::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(
CVarGetFloat(CVAR_INTERNAL_RESOLUTION, 1));
}
UIWidgets::Tooltip("Multiplies your output resolution by the value entered.");
// The original MSAA slider (also for convenience)
#ifndef __WIIU__
if (UIWidgets::PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", CVAR_MSAA_VALUE, 1, 8, "", 1, true, true,
false)) {
Ship::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger(CVAR_MSAA_VALUE, 1));
};
UIWidgets::Tooltip(
"Activates multi-sample anti-aliasing when above 1x, up to 8x for 8 samples for every pixel.\n\n"
" " ICON_FA_INFO_CIRCLE
" (Higher MSAA with low resolution can approximate an authentic \"real N64\" look!)");
#endif
// N64 Mode toggle (again for convenience)
// UIWidgets::PaddedEnhancementCheckbox("(Enhancements>Graphics) N64 Mode", CVAR_LOW_RES_MODE, false, false, false, "", UIWidgets::CheckboxGraphics::Cross, false);
}
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
// Activator
UIWidgets::PaddedEnhancementCheckbox("Enable advanced settings.", CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled", false, false,
false, "", UIWidgets::CheckboxGraphics::Cross, false);
// Error/Warning display
if (!CVarGetInteger(CVAR_LOW_RES_MODE, 0)) {
if (IsDroppingFrames()) { // Significant frame drop warning
ImGui::TextColored(messageColor[MESSAGE_WARNING],
ICON_FA_EXCLAMATION_TRIANGLE " Significant frame rate (FPS) drops may be occuring.");
UIWidgets::Spacer(2);
} else { // No warnings
UIWidgets::Spacer(enhancementSpacerHeight);
}
} else { // N64 Mode warning
ImGui::TextColored(messageColor[MESSAGE_QUESTION],
ICON_FA_QUESTION_CIRCLE " \"N64 Mode\" is overriding these settings.");
ImGui::SameLine();
if (ImGui::Button("Click to disable")) {
CVarSetInteger(CVAR_LOW_RES_MODE, 0);
CVarSave();
}
}
// Resolution visualiser
ImGui::Text("Viewport dimensions: %d x %d", gfx_current_game_window_viewport.width,
gfx_current_game_window_viewport.height);
ImGui::Text("Internal resolution: %d x %d", gfx_current_dimensions.width, gfx_current_dimensions.height);
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
if (disabled_everything) { // Hide aspect ratio controls.
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
// Aspect Ratio
ImGui::Text("Force aspect ratio:");
ImGui::SameLine();
ImGui::TextColored(messageColor[MESSAGE_GRAY_75], "(Select \"Off\" to disable.)");
// Presets
if (ImGui::Combo(" ", &item_aspectRatio, aspectRatioPresetLabels,
IM_ARRAYSIZE(aspectRatioPresetLabels)) &&
item_aspectRatio != default_aspectRatio) { // don't change anything if "Custom" is selected.
aspectRatioX = aspectRatioPresetsX[item_aspectRatio];
aspectRatioY = aspectRatioPresetsY[item_aspectRatio];
if (showHorizontalResField) {
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioX", aspectRatioX);
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioY", aspectRatioY);
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.AspectRatio", item_aspectRatio);
CVarSave();
}
// Hide aspect ratio input fields if using one of the presets.
if (item_aspectRatio == default_aspectRatio && !showHorizontalResField) {
// Declare input interaction bools outside of IF statement to prevent Y field from disappearing.
const bool input_X = ImGui::InputFloat("X", &aspectRatioX, 0.1f, 1.0f, "%.3f");
const bool input_Y = ImGui::InputFloat("Y", &aspectRatioY, 0.1f, 1.0f, "%.3f");
if (input_X || input_Y) {
item_aspectRatio = default_aspectRatio;
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
}
} else if (showHorizontalResField) { // Show calculated aspect ratio
if (item_aspectRatio) {
UIWidgets::Spacer(2);
const float resolvedAspectRatio = (float)gfx_current_dimensions.width / gfx_current_dimensions.height;
ImGui::Text("Aspect ratio: %.2f:1", resolvedAspectRatio);
} else {
UIWidgets::Spacer(enhancementSpacerHeight);
}
}
if (disabled_everything) { // Hide aspect ratio controls.
UIWidgets::ReEnableComponent("disabledTooltipText");
}
UIWidgets::Spacer(0);
// Vertical Resolution
UIWidgets::PaddedEnhancementCheckbox("Set fixed vertical resolution (disables Resolution slider)",
CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", true, false,
disabled_everything, "", UIWidgets::CheckboxGraphics::Cross, false);
UIWidgets::Tooltip(
"Override the resolution scale slider and use the settings below, irrespective of window size.");
if (disabled_pixelCount || disabled_everything) { // Hide pixel count controls.
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
if (ImGui::Combo("Pixel Count Presets", &item_pixelCount, pixelCountPresetLabels,
IM_ARRAYSIZE(pixelCountPresetLabels)) &&
item_pixelCount != default_pixelCount) { // don't change anything if "Custom" is selected.
verticalPixelCount = pixelCountPresets[item_pixelCount];
if (showHorizontalResField) {
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalPixelCount", verticalPixelCount);
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.PixelCount", item_pixelCount);
CVarSave();
}
// Horizontal Resolution, if visibility is enabled for it.
if (showHorizontalResField) {
// Only show the field if Aspect Ratio is being enforced.
if ((aspectRatioX > 0.0f) && (aspectRatioY > 0.0f)) {
// So basically we're "faking" this one by setting aspectRatioX instead.
if (ImGui::InputInt("Horiz. Pixel Count", &horizontalPixelCount, 8, 320)) {
item_aspectRatio = default_aspectRatio;
if (horizontalPixelCount < SCREEN_WIDTH) {
horizontalPixelCount = SCREEN_WIDTH;
}
aspectRatioX = horizontalPixelCount;
aspectRatioY = verticalPixelCount;
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
}
} else { // Display a notice instead.
ImGui::TextColored(messageColor[MESSAGE_QUESTION],
ICON_FA_QUESTION_CIRCLE " \"Force aspect ratio\" required.");
// ImGui::Text(" ");
ImGui::SameLine();
if (ImGui::Button("Click to resolve")) {
item_aspectRatio = default_aspectRatio; // Set it to Custom
aspectRatioX = aspectRatioPresetsX[2]; // but use the 4:3 defaults
aspectRatioY = aspectRatioPresetsY[2];
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
}
}
}
// Vertical Resolution part 2
if (ImGui::InputInt("Vertical Pixel Count", &verticalPixelCount, 8, 240)) {
item_pixelCount = default_pixelCount;
update[UPDATE_verticalPixelCount] = true;
// Account for the natural instinct to enter horizontal first.
// Ignore vertical resolutions that are below the lower clamp constant.
if (showHorizontalResField && !(verticalPixelCount < minVerticalPixelCount)) {
item_aspectRatio = default_aspectRatio;
aspectRatioX = horizontalPixelCount;
aspectRatioY = verticalPixelCount;
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
}
}
if (disabled_pixelCount || disabled_everything) { // Hide pixel count controls.
UIWidgets::ReEnableComponent("disabledTooltipText");
}
UIWidgets::Spacer(0);
// Integer scaling settings group (Pixel-perfect Mode)
static const ImGuiTreeNodeFlags IntegerScalingResolvedImGuiFlag =
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) ? ImGuiTreeNodeFlags_DefaultOpen
: ImGuiTreeNodeFlags_None;
if (ImGui::CollapsingHeader("Integer Scaling Settings", IntegerScalingResolvedImGuiFlag)) {
const bool disabled_pixelPerfectMode =
!CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) || disabled_everything;
// Pixel-perfect Mode
UIWidgets::PaddedEnhancementCheckbox("Pixel-perfect Mode", CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", true,
true, disabled_pixelCount || disabled_everything, "",
UIWidgets::CheckboxGraphics::Cross, false);
UIWidgets::Tooltip("Don't scale image to fill window.");
if (disabled_pixelCount && CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0)) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0);
CVarSave();
}
// Integer Scaling
UIWidgets::EnhancementSliderInt(
"Integer scale factor: %d", "##ARSIntScale", CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.Factor", 1,
max_integerScaleFactor, "%d", 1, true,
disabled_pixelPerfectMode || CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically", 0));
UIWidgets::Tooltip("Integer scales the image. Only available in pixel-perfect mode.");
// Display warning if size is being clamped or if framebuffer is larger than viewport.
if (!disabled_pixelPerfectMode &&
(CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.NeverExceedBounds", 1) &&
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.Factor", 1) > integerScale_maximumBounds)) {
ImGui::SameLine();
ImGui::TextColored(messageColor[MESSAGE_WARNING], ICON_FA_EXCLAMATION_TRIANGLE " Window exceeded.");
}
UIWidgets::PaddedEnhancementCheckbox(
"Automatically scale image to fit viewport", CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically", true,
true, disabled_pixelPerfectMode, "", UIWidgets::CheckboxGraphics::Cross, false);
UIWidgets::Tooltip("Automatically sets scale factor to fit window. Only available in pixel-perfect mode.");
if (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically", 0)) {
// This is just here to update the value shown on the slider.
// The function in LUS to handle this setting will ignore IntegerScaleFactor while active.
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.Factor", integerScale_maximumBounds);
// CVarSave();
}
} // End of integer scaling settings
UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
// Collapsible panel for additional settings
if (ImGui::CollapsingHeader("Additional Settings")) {
UIWidgets::Spacer(0);
#if defined(__SWITCH__) || defined(__WIIU__)
// Disable aspect correction, stretching the framebuffer to fill the viewport.
// This option is only really needed on systems limited to 16:9 TV resolutions, such as consoles.
// The associated cvar is still functional on PC platforms if you want to use it though.
UIWidgets::PaddedEnhancementCheckbox("Disable aspect correction and stretch the output image.\n"
"(Might be useful for 4:3 televisions!)\n"
"Not available in Pixel Perfect Mode.",
CVAR_PREFIX_ADVANCED_RESOLUTION ".IgnoreAspectCorrection", false, true,
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) ||
disabled_everything,
"", UIWidgets::CheckboxGraphics::Cross, false);
#else
if (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IgnoreAspectCorrection", 0)) {
// This setting is intentionally not exposed on PC platforms,
// but may be accidentally activated for varying reasons.
// Having this button should hopefully prevent support headaches.
ImGui::TextColored(messageColor[MESSAGE_QUESTION], ICON_FA_QUESTION_CIRCLE
" If the image is stretched and you don't know why, click this.");
if (ImGui::Button("Click to reenable aspect correction.")) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IgnoreAspectCorrection", 0);
CVarSave();
}
UIWidgets::Spacer(2);
}
#endif
// A requested addition; an alternative way of displaying the resolution field.
if (ImGui::Checkbox("Show a horizontal resolution field, instead of aspect ratio.", &showHorizontalResField)) {
if (!showHorizontalResField && (aspectRatioX > 0.0f)) { // when turning this setting off
// Refresh relevant values
aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
} else { // when turning this setting on
item_aspectRatio = default_aspectRatio;
if (aspectRatioX > 0.0f) {
// Refresh relevant values in the opposite order
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
}
}
update[UPDATE_aspectRatioX] = true;
}
// Beginning of Integer Scaling additional settings.
{
// UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
// Integer Scaling - Never Exceed Bounds.
const bool disabled_neverExceedBounds =
!CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) ||
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically", 0) || disabled_everything;
const bool checkbox_neverExceedBounds =
UIWidgets::PaddedEnhancementCheckbox("Prevent integer scaling from exceeding screen bounds.\n"
"(Makes screen bounds take priority over specified factor.)",
CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.NeverExceedBounds",
true, false, disabled_neverExceedBounds, "",
UIWidgets::CheckboxGraphics::Cross, true);
UIWidgets::Tooltip(
"Prevents integer scaling factor from exceeding screen bounds.\n\n"
"Enabled: Will clamp the scaling factor and display a gentle warning in the resolution editor.\n"
"Disabled: Will allow scaling to exceed screen bounds, for users who want to crop overscan.\n\n"
" " ICON_FA_INFO_CIRCLE
" Please note that exceeding screen bounds may show a scroll bar on-screen.");
// Initialise the (currently unused) "Exceed Bounds By" cvar if it's been changed.
if (checkbox_neverExceedBounds &&
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0)) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0);
CVarSave();
}
// Integer Scaling - Exceed Bounds By 1x/Offset.
// A popular feature in some retro frontends/upscalers, sometimes called "crop overscan" or "1080p 5x".
/*
UIWidgets::PaddedEnhancementCheckbox("Allow integer scale factor to go +1 above maximum screen bounds.", CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", false, false, !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) || disabled_everything, "", UIWidgets::CheckboxGraphics::Cross, false);
*/
// It does actually function as expected, but exceeding the bottom of the screen shows a scroll bar.
// I've ended up commenting this one out because of the scroll bar, and for simplicity.
// Display an info message about the scroll bar.
if (!CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.NeverExceedBounds", 1) ||
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0)) {
if (disabled_neverExceedBounds) { // Dim this help text accordingly
UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
ImGui::TextColored(messageColor[MESSAGE_INFO],
" " ICON_FA_INFO_CIRCLE
" A scroll bar may become visible if screen bounds are exceeded.");
if (disabled_neverExceedBounds) { // Dim this help text accordingly
UIWidgets::ReEnableComponent("disabledTooltipText");
}
// Another support helper button, to disable the unused "Exceed Bounds By" cvar.
// (Remove this button if uncommenting the checkbox.)
if (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0)) {
if (ImGui::Button("Click to reset a console variable that may be causing this.")) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0);
CVarSave();
}
}
} else {
ImGui::Text(" ");
}
// UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
} // End of Integer Scaling additional settings.
} // End of additional settings
// Clamp and update the cvars that don't use UIWidgets
if (update[UPDATE_aspectRatioX] || update[UPDATE_aspectRatioY] || update[UPDATE_verticalPixelCount]) {
if (update[UPDATE_aspectRatioX]) {
if (aspectRatioX < 0.0f) {
aspectRatioX = 0.0f;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioX", aspectRatioX);
}
if (update[UPDATE_aspectRatioY]) {
if (aspectRatioY < 0.0f) {
aspectRatioY = 0.0f;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioY", aspectRatioY);
}
if (update[UPDATE_verticalPixelCount]) {
// There's a upper and lower clamp on the Libultraship side too,
// so clamping it here is entirely visual, so the vertical resolution field reflects it.
if (verticalPixelCount < minVerticalPixelCount) {
verticalPixelCount = minVerticalPixelCount;
}
if (verticalPixelCount > maxVerticalPixelCount) {
verticalPixelCount = maxVerticalPixelCount;
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalPixelCount", verticalPixelCount);
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.AspectRatio", item_aspectRatio);
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.PixelCount", item_pixelCount);
CVarSave();
}
}
void AdvancedResolutionSettingsWindow::UpdateElement() {
}
bool AdvancedResolutionSettingsWindow::IsDroppingFrames() {
// a rather imprecise way of checking for frame drops.
// but it's mostly there to inform the player of large drops.
const short targetFPS = CVarGetInteger(CVAR_SETTING("InterpolationFPS"), 20);
const float threshold = targetFPS / 20.0f + 4.1f;
return ImGui::GetIO().Framerate < targetFPS - threshold;
}
} // namespace AdvancedResolutionSettings

View file

@ -1,16 +0,0 @@
#pragma once
#include <libultraship/libultraship.h>
namespace AdvancedResolutionSettings {
class AdvancedResolutionSettingsWindow : public Ship::GuiWindow {
private:
bool IsDroppingFrames();
public:
using GuiWindow::GuiWindow;
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
};
} // namespace AdvancedResolutionSettings

View file

@ -1,5 +1,4 @@
#include "TimeSplits.h"
#include "soh/SohGui/UIWidgets.hpp"
#include "soh/Enhancements/gameplaystats.h"
#include "soh/SaveManager.h"
#include "soh/util.h"
@ -14,12 +13,16 @@
#include "soh/Enhancements/debugger/debugSaveEditor.h"
#include "soh_assets.h"
#include "assets/textures/parameter_static/parameter_static.h"
#include <soh/SohGui/SohGui.hpp>
#include "soh/SohGui/UIWidgets.hpp"
extern "C" {
extern SaveContext gSaveContext;
extern PlayState* gPlayState;
}
using namespace UIWidgets;
// ImVec4 Colors
#define COLOR_WHITE ImVec4(1.00f, 1.00f, 1.00f, 1.00f)
#define COLOR_LIGHT_RED ImVec4(1.0f, 0.05f, 0.0f, 1.0f)
@ -636,7 +639,7 @@ void TimeSplitsDrawSplitsList() {
uint32_t dragIndex = 0;
ImGui::BeginChild("SplitTable", ImVec2(0.0f, ImGui::GetWindowHeight() - 128.0f));
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 0));
ImGui::BeginTable("Splits", 5, ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable);
if (ImGui::BeginTable("Splits", 5, ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable)) {
ImGui::TableSetupColumn("Item Image", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHeaderLabel, 34.0f);
ImGui::TableSetupColumn("Item Name");
ImGui::TableSetupColumn("Current Time");
@ -687,8 +690,9 @@ void TimeSplitsDrawSplitsList() {
TimeSplitsPostDragAndDrop();
ImGui::PopStyleVar(1);
ImGui::EndTable();
}
ImGui::PopStyleVar();
ImGui::EndChild();
}
@ -769,7 +773,7 @@ void TimeSplitsDrawItemList(uint32_t type) {
}
void TimeSplitsUpdateWindowSize() {
timeSplitsWindowSize = CVarGetFloat(CVAR_ENHANCEMENT("TimeSplits.WindowSize"), 0);
timeSplitsWindowSize = CVarGetFloat(CVAR_ENHANCEMENT("TimeSplits.WindowScale"), 0);
if (timeSplitsWindowSize < 1.0f) {
timeSplitsWindowSize = 1.0f;
}
@ -777,24 +781,13 @@ void TimeSplitsUpdateWindowSize() {
void TimeSplitsDrawOptionsMenu() {
ImGui::SeparatorText("Window Options");
if (ImGui::ColorEdit4("Background Color", (float*)&windowColor, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) {
Color_RGBA8 color;
color.r = windowColor.x * 255.0;
color.g = windowColor.y * 255.0;
color.b = windowColor.z * 255.0;
color.a = windowColor.w * 255.0;
CVarSetColor("TimeSplits.WindowColor", color);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::SameLine();
if (ImGui::Button("Reset")) {
windowColor = { 0.0f, 0.0f, 0.0f, 1.0f };
CVarSetColor("TimeSplits.WindowColor", {0, 0, 0, 1});
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
Color_RGBA8 defaultColor = { 0, 0, 0, 255 };
if (CVarColorPicker("Background Color", CVAR_ENHANCEMENT("TimeSplits.WindowColor"), defaultColor, true, 0, THEME_COLOR)) {
windowColor = VecFromRGBA8(CVarGetColor(CVAR_ENHANCEMENT("TimeSplits.WindowColor.Value"), defaultColor));
}
if (UIWidgets::PaddedEnhancementSliderFloat("Window Size: %.1fx", "##windowSize",
CVAR_ENHANCEMENT("TimeSplits.WindowSize"), 1.0f, 3.0f, "", 1.0f, false, true, true, false)) {
if (CVarSliderFloat("Window Scale", CVAR_ENHANCEMENT("TimeSplits.WindowScale"),
FloatSliderOptions().Min(1.0f).Max(3.0f).DefaultValue(1.0f).Format("%.1fx").Size({300.0f, 0.0f}).Step(0.1f).Color(THEME_COLOR))) {
TimeSplitsUpdateWindowSize();
}
@ -802,55 +795,44 @@ void TimeSplitsDrawOptionsMenu() {
ImGui::Text("New List Name: ");
ImGui::PushItemWidth(150.0f);
PushStyleInput(THEME_COLOR);
ImGui::InputText("##listName", listNameBuf, 25);
PopStyleInput();
ImGui::PopItemWidth();
ImGui::SameLine();
if (ImGui::Button("Create List")) {
if (Button("Create List", ButtonOptions().Color(THEME_COLOR).Size(Sizes::Inline))) {
TimeSplitsFileManagement(SPLIT_ACTION_SAVE, listNameBuf, splitList);
}
UIWidgets::PaddedSeparator();
TimeSplitsFileManagement(SPLIT_ACTION_COLLECT, "", emptyList);
static uint32_t selectedItem = 0;
static std::string listItem = keys[0];
ImGui::Text("Select List to Load: ");
ImGui::PushItemWidth(150.0f);
if (ImGui::BeginCombo("##listEntries", keys[selectedItem].c_str())) {
for (int i = 0; i < keys.size(); i++) {
bool isSelected = (selectedItem == i);
if (ImGui::Selectable(keys[i].c_str(), isSelected)) {
selectedItem = i;
listItem = keys[i].c_str();
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
Combobox("", &selectedItem, keys, ComboboxOptions().Color(THEME_COLOR).LabelPosition(LabelPosition::Near));
ImGui::PopItemWidth();
ImGui::SameLine();
if (ImGui::Button("Load List")) {
if (Button("Load List", ButtonOptions().Color(THEME_COLOR).Size(Sizes::Inline))) {
TimeSplitsFileManagement(SPLIT_ACTION_LOAD, keys[selectedItem].c_str(), emptyList);
}
ImGui::SameLine();
if (ImGui::Button("Save List")) {
if (Button("Save List", ButtonOptions().Color(THEME_COLOR).Size(Sizes::Inline))) {
TimeSplitsFileManagement(SPLIT_ACTION_SAVE, keys[selectedItem].c_str(), splitList);
}
ImGui::SameLine();
if (ImGui::Button("Delete List")) {
if (Button("Delete List", ButtonOptions().Color(THEME_COLOR).Size(Sizes::Inline))) {
TimeSplitsFileManagement(SPLIT_ACTION_DELETE, keys[selectedItem].c_str(), emptyList);
}
UIWidgets::PaddedSeparator();
UIWidgets::Separator(true, true, ImGui::GetStyle().ItemSpacing.y, ImGui::GetStyle().ItemSpacing.y);
if (ImGui::Button("New Attempt")) {
if (Button("New Attempt", ButtonOptions().Color(THEME_COLOR).Size(Sizes::Inline))) {
for (auto& data : splitList) {
data.splitTimeStatus = SPLIT_STATUS_INACTIVE;
}
splitList[0].splitTimeStatus = SPLIT_STATUS_ACTIVE;
}
ImGui::SameLine();
if (ImGui::Button("Update Splits")) {
if (Button("Update Splits", ButtonOptions().Color(THEME_COLOR).Size(Sizes::Inline))) {
TimeSplitsFileManagement(SPLIT_ACTION_UPDATE, keys[selectedItem].c_str(), splitList);
}
}
@ -864,8 +846,10 @@ void TimeSplitsRemoveSplitEntry(uint32_t index) {
void TimeSplitsDrawManageList() {
uint32_t index = 0;
ImGui::BeginTable("List Management", 2, ImGuiTableFlags_BordersInnerV);
ImGui::TableSetupColumn("Preview", ImGuiTableColumnFlags_WidthFixed, 60.0f);
ImGui::BeginChild("SplitTable", ImVec2(0.0f, ImGui::GetWindowHeight() - 128.0f));
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 0));
if (ImGui::BeginTable("List Management", 2, ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("Preview", ImGuiTableColumnFlags_WidthFixed, 120.0f);
ImGui::TableSetupColumn("Options", ImGuiTableColumnFlags_NoHeaderLabel);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
@ -933,6 +917,9 @@ void TimeSplitsDrawManageList() {
ImGui::EndTabBar();
ImGui::EndTable();
}
ImGui::PopStyleVar();
ImGui::EndChild();
}
void InitializeSplitDataFile() {
@ -954,14 +941,9 @@ static bool initialized = false;
void TimeSplitWindow::DrawElement() {
ImGui::SetWindowFontScale(timeSplitsWindowSize);
if (!initialized) {
Color_RGBA8 defaultColour = {0, 0, 0, 255};
Color_RGBA8 color = CVarGetColor("TimeSplits.WindowColor", defaultColour);
windowColor = {(float)color.r / 255.0f, (float)color.g / 255.0f, (float)color.b / 255.0f, (float)color.a / 255.0f};
InitializeSplitDataFile();
initialized = true;
}
ImGui::PushFont(OTRGlobals::Instance->fontMonoLargest);
PushStyleTabs(THEME_COLOR);
if (ImGui::BeginTabBar("Split Tabs")) {
if (ImGui::BeginTabItem("Splits")) {
TimeSplitsDrawSplitsList();
@ -977,6 +959,8 @@ void TimeSplitWindow::DrawElement() {
}
ImGui::EndTabBar();
}
PopStyleTabs();
ImGui::PopFont();
}
void TimeSplitWindow::InitElement() {
@ -984,6 +968,9 @@ void TimeSplitWindow::InitElement() {
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("SPECIAL_TRIFORCE_PIECE_WHITE", gWTriforcePieceTex, ImVec4(1, 1, 1, 1));
Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture("SPECIAL_SPLIT_ENTRANCE", gSplitEntranceTex, ImVec4(1, 1, 1, 1));
Color_RGBA8 defaultColour = {0, 0, 0, 255};
windowColor = VecFromRGBA8(CVarGetColor(CVAR_ENHANCEMENT("TimeSplits.WindowColor.Value"), defaultColour));
InitializeSplitDataFile();
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnTimestamp>([](u8 item) {
if (item != ITEM_SKULL_TOKEN) {

View file

@ -764,69 +764,4 @@ CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
return effect;
}
void CrowdControl::DrawMenu() {
ImGui::PushID("CrowdControl");
static std::string host = CVarGetString(CVAR_REMOTE_CROWD_CONTROL("Host"), "127.0.0.1");
static uint16_t port = CVarGetInteger(CVAR_REMOTE_CROWD_CONTROL("Port"), 43384);
bool isFormValid = !SohUtils::IsStringEmpty(host) && port > 1024 && port < 65535;
ImGui::SeparatorText("Crowd Control");
UIWidgets::Tooltip(
"Crowd Control is a platform that allows viewers to interact "
"with a streamer's game in real time.\n"
"\n"
"Click the question mark to copy the link to the Crowd Control "
"website to your clipboard."
);
if (ImGui::IsItemClicked()) {
ImGui::SetClipboardText("https://crowdcontrol.live");
}
ImGui::BeginDisabled(isEnabled);
ImGui::Text("Host & Port");
if (UIWidgets::InputString("##Host", &host)) {
CVarSetString(CVAR_REMOTE_CROWD_CONTROL("Host"), host.c_str());
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetFontSize() * 5);
if (ImGui::InputScalar("##Port", ImGuiDataType_U16, &port)) {
CVarSetInteger(CVAR_REMOTE_CROWD_CONTROL("Port"), port);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::PopItemWidth();
ImGui::EndDisabled();
ImGui::Spacing();
ImGui::BeginDisabled(!isFormValid);
const char* buttonLabel = isEnabled ? "Disable" : "Enable";
if (ImGui::Button(buttonLabel, ImVec2(-1.0f, 0.0f))) {
if (isEnabled) {
CVarClear(CVAR_REMOTE_CROWD_CONTROL("Enabled"));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
Disable();
} else {
CVarSetInteger(CVAR_REMOTE_CROWD_CONTROL("Enabled"), 1);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
Enable();
}
}
ImGui::EndDisabled();
if (isEnabled) {
ImGui::Spacing();
if (isConnected) {
ImGui::Text("Connected");
} else {
ImGui::Text("Connecting...");
}
}
ImGui::PopID();
}
#endif

View file

@ -84,7 +84,6 @@ class CrowdControl : public Network {
void OnIncomingJson(nlohmann::json payload);
void OnConnected();
void OnDisconnected();
void DrawMenu();
};
#endif // __cplusplus

View file

@ -501,72 +501,4 @@ void Sail::RegisterHooks() {
});
}
void Sail::DrawMenu() {
ImGui::PushID("Sail");
static std::string host = CVarGetString(CVAR_REMOTE_SAIL("Host"), "127.0.0.1");
static uint16_t port = CVarGetInteger(CVAR_REMOTE_SAIL("Port"), 43384);
bool isFormValid = !SohUtils::IsStringEmpty(host) && port > 1024 && port < 65535;
ImGui::SeparatorText("Sail");
UIWidgets::Tooltip(
"Sail is a networking protocol designed to facilitate remote "
"control of the Ship of Harkinian client. It is intended to "
"be utilized alongside a Sail server, for which we provide a "
"few straightforward implementations on our GitHub. The current "
"implementations available allow integration with Twitch chat "
"and SAMMI Bot, feel free to contribute your own!\n"
"\n"
"Click the question mark to copy the link to the Sail Github "
"page to your clipboard."
);
if (ImGui::IsItemClicked()) {
ImGui::SetClipboardText("https://github.com/HarbourMasters/sail");
}
ImGui::BeginDisabled(isEnabled);
ImGui::Text("Host & Port");
if (UIWidgets::InputString("##Host", &host)) {
CVarSetString(CVAR_REMOTE_SAIL("Host"), host.c_str());
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetFontSize() * 5);
if (ImGui::InputScalar("##Port", ImGuiDataType_U16, &port)) {
CVarSetInteger(CVAR_REMOTE_SAIL("Port"), port);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
ImGui::PopItemWidth();
ImGui::EndDisabled();
ImGui::Spacing();
ImGui::BeginDisabled(!isFormValid);
const char* buttonLabel = isEnabled ? "Disable" : "Enable";
if (ImGui::Button(buttonLabel, ImVec2(-1.0f, 0.0f))) {
if (isEnabled) {
CVarClear(CVAR_REMOTE_SAIL("Enabled"));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
Disable();
} else {
CVarSetInteger(CVAR_REMOTE_SAIL("Enabled"), 1);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
Enable();
}
}
ImGui::EndDisabled();
if (isEnabled) {
ImGui::Spacing();
if (isConnected) {
ImGui::Text("Connected");
} else {
ImGui::Text("Connecting...");
}
}
ImGui::PopID();
}
#endif // ENABLE_REMOTE_CONTROL

View file

@ -18,7 +18,6 @@ class Sail : public Network {
void OnIncomingJson(nlohmann::json payload);
void OnConnected();
void OnDisconnected();
void DrawMenu();
};
#endif // __cplusplus

View file

@ -40,6 +40,7 @@
#include "z64.h"
#include "macros.h"
#include "Fonts.h"
#include "window/gui/resource/Font.h"
#include <utils/StringHelper.h>
#include "Enhancements/custom-message/CustomMessageManager.h"
#include "Enhancements/presets.h"
@ -345,7 +346,7 @@ OTRGlobals::OTRGlobals() {
context->InitCrashHandler();
context->InitConsole();
auto sohInputEditorWindow = std::make_shared<SohInputEditorWindow>(CVAR_WINDOW("ControllerConfiguration"), "Controller Configuration");
auto sohInputEditorWindow = std::make_shared<SohInputEditorWindow>(CVAR_WINDOW("ControllerConfiguration"), "Configure Controller");
auto sohFast3dWindow = std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({sohInputEditorWindow}));
context->InitWindow(sohFast3dWindow);
@ -399,9 +400,14 @@ OTRGlobals::OTRGlobals() {
hasMasterQuest = hasOriginal = false;
previousImGuiScale = defaultImGuiScale;
defaultFontSmaller = CreateDefaultFontWithSize(10.0f);
defaultFontLarger = CreateDefaultFontWithSize(16.0f);
defaultFontLargest = CreateDefaultFontWithSize(20.0f);
fontMono = CreateFontWithSize(16.0f, "fonts/Inconsolata-Regular.ttf");
fontMonoLarger = CreateFontWithSize(20.0f, "fonts/Inconsolata-Regular.ttf");
fontMonoLargest = CreateFontWithSize(24.0f, "fonts/Inconsolata-Regular.ttf");
fontStandard = CreateFontWithSize(16.0f, "fonts/Montserrat-Regular.ttf");
fontStandardLarger = CreateFontWithSize(20.0f, "fonts/Montserrat-Regular.ttf");
fontStandardLargest = CreateFontWithSize(24.0f, "fonts/Montserrat-Regular.ttf");
ImGui::GetIO().FontDefault = fontMono;
ScaleImGui();
// Move the camera strings from read only memory onto the heap (writable memory)
@ -1390,9 +1396,12 @@ void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>
// Process window events for resize, mouse, keyboard events
wnd->HandleEvents();
UIWidgets::Colors themeColor = static_cast<UIWidgets::Colors>(CVarGetInteger(CVAR_SETTING("Menu.Theme"), UIWidgets::Colors::LightBlue));
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIWidgets::ColorValues.at(themeColor));
for (const auto& m : mtx_replacements) {
wnd->DrawAndRunGraphicsCommands(Commands, m);
}
ImGui::PopStyleColor();
}
// C->C++ Bridge
@ -1559,6 +1568,37 @@ extern "C" SoundFontSample* ReadCustomSample(const char* path) {
*/
}
ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath) {
auto mImGuiIo = &ImGui::GetIO();
ImFont* font;
if (fontPath == "") {
ImFontConfig fontCfg = ImFontConfig();
fontCfg.OversampleH = fontCfg.OversampleV = 1;
fontCfg.PixelSnapH = true;
fontCfg.SizePixels = size;
font = mImGuiIo->Fonts->AddFontDefault(&fontCfg);
} else {
auto initData = std::make_shared<Ship::ResourceInitData>();
initData->Format = RESOURCE_FORMAT_BINARY;
initData->Type = static_cast<uint32_t>(RESOURCE_TYPE_FONT);
initData->ResourceVersion = 0;
initData->Path = fontPath;
std::shared_ptr<Ship::Font> fontData = std::static_pointer_cast<Ship::Font>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, false, initData));
font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size);
}
// FontAwesome fonts need to have their sizes reduced by 2.0f/3.0f in order to align correctly
float iconFontSize = size * 2.0f / 3.0f;
static const ImWchar sIconsRanges[] = { ICON_MIN_FA, ICON_MAX_16_FA, 0 };
ImFontConfig iconsConfig;
iconsConfig.MergeMode = true;
iconsConfig.PixelSnapH = true;
iconsConfig.GlyphMinAdvanceX = iconFontSize;
mImGuiIo->Fonts->AddFontFromMemoryCompressedBase85TTF(fontawesome_compressed_data_base85, iconFontSize,
&iconsConfig, sIconsRanges);
return font;
}
std::filesystem::path GetSaveFile(std::shared_ptr<Ship::Config> Conf) {
const std::string fileName = Conf->GetString("Game.SaveName", Ship::Context::GetPathRelativeToAppDirectory("oot_save.sav"));
std::filesystem::path saveFile = std::filesystem::absolute(fileName);

View file

@ -54,6 +54,13 @@ class OTRGlobals {
ImFont* defaultFontLarger;
ImFont* defaultFontLargest;
ImFont* fontStandard;
ImFont* fontStandardLarger;
ImFont* fontStandardLargest;
ImFont* fontMono;
ImFont* fontMonoLarger;
ImFont* fontMonoLargest;
OTRGlobals();
~OTRGlobals();
@ -69,6 +76,7 @@ class OTRGlobals {
bool hasMasterQuest;
bool hasOriginal;
ImFont* CreateDefaultFontWithSize(float size);
ImFont* CreateFontWithSize(float size, std::string fontPath);
};
#endif

115
soh/soh/ShipUtils.cpp Normal file
View file

@ -0,0 +1,115 @@
#include "ShipUtils.h"
#include <libultraship/libultraship.h>
extern "C" {
#include "z64.h"
#include "functions.h"
#include "macros.h"
extern float OTRGetAspectRatio();
//extern f32 sNESFontWidths[160];
extern const char* fontTbl[156];
//extern TexturePtr gItemIcons[131];
//extern TexturePtr gQuestIcons[14];
//extern TexturePtr gBombersNotebookPhotos[24];
}
constexpr f32 fourByThree = 4.0f / 3.0f;
// Gets the additional ratio of the screen compared to the original 4:3 ratio, clamping to 1 if smaller
extern "C" f32 Ship_GetExtendedAspectRatioMultiplier() {
f32 currentRatio = OTRGetAspectRatio();
return MAX(currentRatio / fourByThree, 1.0f);
}
// Enables Extended Culling options on specific actors by applying an inverse ratio of the draw distance slider
// to the projected Z value of the actor. This tricks distance checks without having to replace hardcoded values.
// Requires that Ship_ExtendedCullingActorRestoreProjectedPos is called within the same function scope.
extern "C" void Ship_ExtendedCullingActorAdjustProjectedZ(Actor* actor) {
s32 multiplier = CVarGetInteger("gEnhancements.Graphics.IncreaseActorDrawDistance", 1);
multiplier = MAX(multiplier, 1);
if (multiplier > 1) {
actor->projectedPos.z /= multiplier;
}
}
// Enables Extended Culling options on specific actors by applying an inverse ratio of the widescreen aspect ratio
// to the projected X value of the actor. This tricks distance checks without having to replace hardcoded values.
// Requires that Ship_ExtendedCullingActorRestoreProjectedPos is called within the same function scope.
extern "C" void Ship_ExtendedCullingActorAdjustProjectedX(Actor* actor) {
if (CVarGetInteger("gEnhancements.Graphics.ActorCullingAccountsForWidescreen", 0)) {
f32 ratioAdjusted = Ship_GetExtendedAspectRatioMultiplier();
actor->projectedPos.x /= ratioAdjusted;
}
}
// Restores the projectedPos values on the actor after modifications from the Extended Culling hacks
//extern "C" void Ship_ExtendedCullingActorRestoreProjectedPos(PlayState* play, Actor* actor) {
// f32 invW = 0.0f;
// Actor_GetProjectedPos(play, &actor->world.pos, &actor->projectedPos, &invW);
//}
extern "C" bool Ship_IsCStringEmpty(const char* str) {
return str == NULL || str[0] == '\0';
}
// Build vertex coordinates for a quad command
// In order of top left, top right, bottom left, then bottom right
// Supports flipping the texture horizontally
extern "C" void Ship_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH) {
vtxList[0].v.ob[0] = xStart;
vtxList[0].v.ob[1] = yStart;
vtxList[0].v.tc[0] = (flippedH ? width : 0) << 5;
vtxList[0].v.tc[1] = 0 << 5;
vtxList[1].v.ob[0] = xStart + width;
vtxList[1].v.ob[1] = yStart;
vtxList[1].v.tc[0] = (flippedH ? width * 2 : width) << 5;
vtxList[1].v.tc[1] = 0 << 5;
vtxList[2].v.ob[0] = xStart;
vtxList[2].v.ob[1] = yStart + height;
vtxList[2].v.tc[0] = (flippedH ? width : 0) << 5;
vtxList[2].v.tc[1] = height << 5;
vtxList[3].v.ob[0] = xStart + width;
vtxList[3].v.ob[1] = yStart + height;
vtxList[3].v.tc[0] = (flippedH ? width * 2 : width) << 5;
vtxList[3].v.tc[1] = height << 5;
}
//extern "C" f32 Ship_GetCharFontWidthNES(u8 character) {
// u8 adjustedChar = character - ' ';
//
// if (adjustedChar >= ARRAY_COUNTU(sNESFontWidths)) {
// return 0.0f;
// }
//
// return sNESFontWidths[adjustedChar];
//}
//extern "C" TexturePtr Ship_GetCharFontTextureNES(u8 character) {
// u8 adjustedChar = character - ' ';
//
// if (adjustedChar >= ARRAY_COUNTU(sNESFontWidths)) {
// return (TexturePtr)gEmptyTexture;
// }
//
// return (TexturePtr)fontTbl[adjustedChar];
//}
//void LoadGuiTextures() {
// for (TexturePtr entry : gItemIcons) {
// const char* path = static_cast<const char*>(entry);
// Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1));
// }
// for (TexturePtr entry : gQuestIcons) {
// const char* path = static_cast<const char*>(entry);
// Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1));
// }
// for (TexturePtr entry : gBombersNotebookPhotos) {
// const char* path = static_cast<const char*>(entry);
// Ship::Context::GetInstance()->GetWindow()->GetGui()->LoadGuiTexture(path, path, ImVec4(1, 1, 1, 1));
// }
//}

31
soh/soh/ShipUtils.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef SHIP_UTILS_H
#define SHIP_UTILS_H
#include <libultraship/libultraship.h>
//#include "PR/ultratypes.h"
#ifdef __cplusplus
void LoadGuiTextures();
extern "C" {
#endif
struct PlayState;
struct Actor;
f32 Ship_GetExtendedAspectRatioMultiplier();
void Ship_ExtendedCullingActorAdjustProjectedZ(Actor* actor);
void Ship_ExtendedCullingActorAdjustProjectedX(Actor* actor);
void Ship_ExtendedCullingActorRestoreProjectedPos(PlayState* play, Actor* actor);
bool Ship_IsCStringEmpty(const char* str);
void Ship_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH);
f32 Ship_GetCharFontWidthNES(u8 character);
//TexturePtr Ship_GetCharFontTextureNES(u8 character);
#ifdef __cplusplus
}
#endif
#endif // SHIP_UTILS_H

819
soh/soh/SohGui/Menu.cpp Normal file
View file

@ -0,0 +1,819 @@
#include "Menu.h"
#include "UIWidgets.hpp"
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/controls/SohInputEditorWindow.h"
#include "window/gui/GuiMenuBar.h"
#include "window/gui/GuiElement.h"
#include <variant>
#include <spdlog/fmt/fmt.h>
#include "variables.h"
#include <tuple>
extern "C" {
#include "z64.h"
#include "functions.h"
extern PlayState* gPlayState;
}
std::vector<ImVec2> windowTypeSizes = { {} };
extern std::unordered_map<s16, const char*> warpPointSceneList;
extern void Warp();
namespace SohGui {}
namespace Ship {
std::string disabledTempTooltip;
const char* disabledTooltip;
bool disabledValue = false;
bool operator==(Color_RGB8 const& l, Color_RGB8 const& r) noexcept {
return l.r == r.r && l.g == r.g && l.b == r.b;
}
bool operator==(Color_RGBA8 const& l, Color_RGBA8 const& r) noexcept {
return l.r == r.r && l.g == r.g && l.b == r.b && l.a == r.a;
}
bool operator<(Color_RGB8 const& l, Color_RGB8 const& r) noexcept {
return (l.r < r.r && l.g <= r.g && l.b <= r.b) || (l.r <= r.r && l.g < r.g && l.b <= r.b) ||
(l.r <= r.r && l.g <= r.g && l.b < r.b);
}
bool operator<(Color_RGBA8 const& l, Color_RGBA8 const& r) noexcept {
return (l.r < r.r && l.g <= r.g && l.b <= r.b && l.a <= r.a) ||
(l.r <= r.r && l.g < r.g && l.b <= r.b && l.a <= r.a) ||
(l.r <= r.r && l.g <= r.g && l.b < r.b && l.a <= r.a) ||
(l.r <= r.r && l.g <= r.g && l.b <= r.b && l.a < r.a);
}
bool operator>(Color_RGB8 const& l, Color_RGB8 const& r) noexcept {
return (l.r > r.r && l.g >= r.g && l.b >= r.b) || (l.r >= r.r && l.g > r.g && l.b >= r.b) ||
(l.r >= r.r && l.g >= r.g && l.b > r.b);
}
bool operator>(Color_RGBA8 const& l, Color_RGBA8 const& r) noexcept {
return (l.r > r.r && l.g >= r.g && l.b >= r.b && l.a >= r.a) ||
(l.r >= r.r && l.g > r.g && l.b >= r.b && l.a >= r.a) ||
(l.r >= r.r && l.g >= r.g && l.b > r.b && l.a >= r.a) ||
(l.r >= r.r && l.g >= r.g && l.b >= r.b && l.a > r.a);
}
uint32_t GetVectorIndexOf(std::vector<std::string>& vector, std::string value) {
return std::distance(vector.begin(), std::find(vector.begin(), vector.end(), value));
}
void Menu::InsertSidebarSearch() {
menuEntries["Settings"].sidebars.emplace("Search", searchSidebarEntry);
uint32_t curIndex = 0;
if (!Ship_IsCStringEmpty(CVarGetString(menuEntries["Settings"].sidebarCvar, ""))) {
curIndex = GetVectorIndexOf(menuEntries["Settings"].sidebarOrder,
CVarGetString(menuEntries["Settings"].sidebarCvar, ""));
}
menuEntries["Settings"].sidebarOrder.insert(menuEntries["Settings"].sidebarOrder.begin() + searchSidebarIndex,
"Search");
if (curIndex > searchSidebarIndex) {
CVarSetString(menuEntries["Settings"].sidebarCvar, menuEntries["Settings"].sidebarOrder.at(curIndex).c_str());
}
}
void Menu::RemoveSidebarSearch() {
uint32_t curIndex =
GetVectorIndexOf(menuEntries["Settings"].sidebarOrder, CVarGetString(menuEntries["Settings"].sidebarCvar, "General"));
menuEntries["Settings"].sidebars.erase("Search");
std::erase_if(menuEntries["Settings"].sidebarOrder, [](std::string& name) { return name == "Search"; });
if (curIndex > searchSidebarIndex) {
curIndex--;
} else if (curIndex >= menuEntries["Settings"].sidebarOrder.size()) {
curIndex = menuEntries["Settings"].sidebarOrder.size() - 1;
}
CVarSetString(menuEntries["Settings"].sidebarCvar, menuEntries["Settings"].sidebarOrder.at(curIndex).c_str());
}
void Menu::UpdateWindowBackendObjects() {
Ship::WindowBackend runningWindowBackend = Ship::Context::GetInstance()->GetWindow()->GetWindowBackend();
int32_t configWindowBackendId = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1);
if (Ship::Context::GetInstance()->GetWindow()->IsAvailableWindowBackend(configWindowBackendId)) {
configWindowBackend = static_cast<Ship::WindowBackend>(configWindowBackendId);
} else {
configWindowBackend = runningWindowBackend;
}
availableWindowBackends = Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends();
for (auto& backend : *availableWindowBackends) {
availableWindowBackendsMap[backend] = windowBackendsMap.at(backend);
}
}
UIWidgets::Colors Menu::GetMenuThemeColor() {
return menuThemeIndex;
}
Menu::Menu(const std::string& cVar, const std::string& name, uint8_t searchSidebarIndex_,
UIWidgets::Colors defaultThemeIndex_)
: GuiWindow(cVar, name), searchSidebarIndex(searchSidebarIndex_), defaultThemeIndex(defaultThemeIndex_) {
}
void Menu::InitElement() {
popped = CVarGetInteger(CVAR_SETTING("Menu.Popout"), 0);
poppedSize.x = CVarGetInteger(CVAR_SETTING("Menu.PoppedWidth"), 1280);
poppedSize.y = CVarGetInteger(CVAR_SETTING("Menu.PoppedHeight"), 800);
poppedPos.x = CVarGetInteger(CVAR_SETTING("Menu.PoppedPos.x"), 0);
poppedPos.y = CVarGetInteger(CVAR_SETTING("Menu.PoppedPos.y"), 0);
UpdateWindowBackendObjects();
}
void Menu::UpdateElement() {
menuThemeIndex = static_cast<UIWidgets::Colors>(CVarGetInteger(CVAR_SETTING("Menu.Theme"), defaultThemeIndex));
}
bool ModernMenuSidebarEntry(std::string label) {
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = ImGui::GetStyle();
ImVec2 pos = window->DC.CursorPos;
const ImGuiID sidebarId = window->GetID(std::string(label + "##Sidebar").c_str());
ImVec2 labelSize = ImGui::CalcTextSize(label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
pos.y += style.FramePadding.y;
pos.x = window->WorkRect.GetCenter().x - labelSize.x / 2;
ImRect bb = { pos - style.FramePadding, pos + labelSize + style.FramePadding };
ImGui::ItemSize(bb, style.FramePadding.y);
ImGui::ItemAdd(bb, sidebarId);
bool hovered, held;
bool pressed = ImGui::ButtonBehavior(bb, sidebarId, &hovered, &held);
if (pressed) {
ImGui::MarkItemEdited(sidebarId);
}
window->DrawList->AddRectFilled(pos - style.FramePadding, pos + labelSize + style.FramePadding,
ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive
: hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button),
3.0f);
UIWidgets::RenderText(pos, label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
return pressed;
}
bool ModernMenuHeaderEntry(std::string label) {
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = ImGui::GetStyle();
ImVec2 pos = window->DC.CursorPos;
const ImGuiID headerId = window->GetID(std::string(label + "##Header").c_str());
ImVec2 labelSize = ImGui::CalcTextSize(label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
ImRect bb = { pos, pos + labelSize + style.FramePadding * 2 };
ImGui::ItemSize(bb, style.FramePadding.y);
ImGui::ItemAdd(bb, headerId);
bool hovered, held;
bool pressed = ImGui::ButtonBehavior(bb, headerId, &hovered, &held);
window->DrawList->AddRectFilled(bb.Min, bb.Max,
ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive
: hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button),
3.0f);
pos += style.FramePadding;
UIWidgets::RenderText(pos, label.c_str(), ImGui::FindRenderedTextEnd(label.c_str()), true);
return pressed;
}
uint32_t Menu::DrawSearchResults(std::string& menuSearchText) {
ImGui::BeginChild("Search Results");
int searchCount = 0;
for (auto& menuLabel : menuOrder) {
auto& menuEntry = menuEntries.at(menuLabel);
for (auto& sidebarLabel : menuEntry.sidebarOrder) {
auto& sidebar = menuEntry.sidebars[sidebarLabel];
for (int i = 0; i < sidebar.columnWidgets.size(); i++) {
auto& column = sidebar.columnWidgets.at(i);
for (auto& info : column) {
if (info.type == WIDGET_SEARCH || info.type == WIDGET_SEPARATOR || info.type == WIDGET_SEPARATOR_TEXT ||
info.isHidden) {
continue;
}
const char* tooltip = info.options->tooltip;
std::string widgetStr = std::string(info.name) + std::string(tooltip != NULL ? tooltip : "");
std::transform(menuSearchText.begin(), menuSearchText.end(), menuSearchText.begin(), ::tolower);
menuSearchText.erase(std::remove(menuSearchText.begin(), menuSearchText.end(), ' '),
menuSearchText.end());
std::transform(widgetStr.begin(), widgetStr.end(), widgetStr.begin(), ::tolower);
widgetStr.erase(std::remove(widgetStr.begin(), widgetStr.end(), ' '), widgetStr.end());
if (widgetStr.find(menuSearchText) != std::string::npos) {
MenuDrawItem(info, 90 / sidebar.columnCount, menuThemeIndex);
ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::ColorValues.at(UIWidgets::Colors::Gray));
std::string origin = fmt::format(" ({} -> {}, Col {})", menuEntry.label, sidebarLabel, i + 1);
ImGui::Text("%s", origin.c_str());
ImGui::PopStyleColor();
searchCount++;
}
}
}
}
}
return searchCount;
}
void Menu::AddMenuEntry(std::string entryName, const char* entryCvar) {
menuEntries.emplace(entryName, MainMenuEntry{ entryName, entryCvar });
menuOrder.push_back(entryName);
}
std::unordered_map<uint32_t, disabledInfo>& Menu::GetDisabledMap() {
return disabledMap;
}
void Menu::MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors menuThemeIndex) {
disabledTempTooltip = "This setting is disabled because: \n\n";
disabledValue = false;
disabledTooltip = " ";
if (widget.preFunc != nullptr) {
widget.ResetDisables();
widget.preFunc(widget);
if (widget.isHidden) {
return;
}
if (!widget.activeDisables.empty()) {
widget.options->disabled = true;
for (auto option : widget.activeDisables) {
disabledTempTooltip += std::string("- ") + disabledMap.at(option).reason + std::string("\n");
}
widget.options->disabledTooltip = disabledTempTooltip.c_str();
}
}
if (widget.sameLine) {
ImGui::SameLine();
}
try {
switch (widget.type) {
case WIDGET_CHECKBOX: {
bool* pointer = std::get<bool*>(widget.valuePointer);
if (pointer == nullptr) {
SPDLOG_ERROR("Checkbox Widget requires a value pointer, currently nullptr");
assert(false);
return;
}
auto options = std::static_pointer_cast<UIWidgets::CheckboxOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::Checkbox(UIWidgets::WrappedText(widget.name.c_str(), width).c_str(), pointer,
*options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
}
} break;
case WIDGET_CVAR_CHECKBOX: {
auto options = std::static_pointer_cast<UIWidgets::CheckboxOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::CVarCheckbox(UIWidgets::WrappedText(widget.name.c_str(), width).c_str(), widget.cVar,
*options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
};
} break;
case WIDGET_AUDIO_BACKEND: {
auto currentAudioBackend = Ship::Context::GetInstance()->GetAudio()->GetCurrentAudioBackend();
UIWidgets::ComboboxOptions options = {};
options.color = menuThemeIndex;
options.tooltip = "Sets the audio API used by the game. Requires a relaunch to take effect.";
options.disabled = Ship::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1;
options.disabledTooltip = "Only one audio API is available on this platform.";
if (UIWidgets::Combobox("Audio API", &currentAudioBackend, audioBackendsMap, options)) {
Ship::Context::GetInstance()->GetAudio()->SetCurrentAudioBackend(currentAudioBackend);
}
} break;
case WIDGET_VIDEO_BACKEND: {
UIWidgets::ComboboxOptions options = {};
options.color = menuThemeIndex;
options.tooltip = "Sets the renderer API used by the game.";
options.disabled = availableWindowBackends->size() <= 1;
options.disabledTooltip = "Only one renderer API is available on this platform.";
if (UIWidgets::Combobox("Renderer API (Needs reload)", &configWindowBackend, availableWindowBackendsMap,
options)) {
Ship::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id",
(int32_t)(configWindowBackend));
Ship::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name",
windowBackendsMap.at(configWindowBackend));
Ship::Context::GetInstance()->GetConfig()->Save();
UpdateWindowBackendObjects();
}
} break;
case WIDGET_SEPARATOR: {
ImGui::Separator();
} break;
case WIDGET_SEPARATOR_TEXT: {
if (widget.options->color != UIWidgets::Colors::NoColor) {
ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::ColorValues.at(widget.options->color));
}
ImGui::SeparatorText(widget.name.c_str());
if (widget.options->color != UIWidgets::Colors::NoColor) {
ImGui::PopStyleColor();
}
} break;
case WIDGET_TEXT: {
if (widget.options->color != UIWidgets::Colors::NoColor) {
ImGui::PushStyleColor(ImGuiCol_Text, UIWidgets::ColorValues.at(widget.options->color));
}
ImGui::AlignTextToFramePadding();
ImGui::TextWrapped("%s", widget.name.c_str());
if (widget.options->color != UIWidgets::Colors::NoColor) {
ImGui::PopStyleColor();
}
} break;
case WIDGET_COMBOBOX: {
int32_t* pointer = std::get<int32_t*>(widget.valuePointer);
if (pointer == nullptr) {
SPDLOG_ERROR("Combobox Widget requires a value pointer, currently nullptr");
assert(false);
return;
}
auto options = std::static_pointer_cast<UIWidgets::ComboboxOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::Combobox(widget.name.c_str(), pointer, options->comboMap, *options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
};
} break;
case WIDGET_CVAR_COMBOBOX: {
auto options = std::static_pointer_cast<UIWidgets::ComboboxOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::CVarCombobox(widget.name.c_str(), widget.cVar, options->comboMap, *options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
}
} break;
case WIDGET_SLIDER_INT: {
int32_t* pointer = std::get<int32_t*>(widget.valuePointer);
if (pointer == nullptr) {
SPDLOG_ERROR("int32 Slider Widget requires a value pointer, currently nullptr");
assert(false);
return;
}
auto options = std::static_pointer_cast<UIWidgets::IntSliderOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::SliderInt(widget.name.c_str(), pointer, *options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
};
} break;
case WIDGET_CVAR_SLIDER_INT: {
auto options = std::static_pointer_cast<UIWidgets::IntSliderOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::CVarSliderInt(widget.name.c_str(), widget.cVar, *options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
};
} break;
case WIDGET_SLIDER_FLOAT: {
float* pointer = std::get<float*>(widget.valuePointer);
if (pointer == nullptr) {
SPDLOG_ERROR("float Slider Widget requires a value pointer, currently nullptr");
assert(false);
return;
}
auto options = std::static_pointer_cast<UIWidgets::FloatSliderOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::SliderFloat(widget.name.c_str(), pointer, *options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
}
} break;
case WIDGET_CVAR_SLIDER_FLOAT: {
auto options = std::static_pointer_cast<UIWidgets::FloatSliderOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::CVarSliderFloat(widget.name.c_str(), widget.cVar, *options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
}
} break;
case WIDGET_BUTTON: {
auto options = std::static_pointer_cast<UIWidgets::ButtonOptions>(widget.options);
options->color = menuThemeIndex;
if (UIWidgets::Button(widget.name.c_str(), *options)) {
if (widget.callback != nullptr) {
widget.callback(widget);
}
}
} break;
case WIDGET_CUSTOM: {
if (widget.customFunction != nullptr) {
widget.customFunction(widget);
}
} break;
case WIDGET_WINDOW_BUTTON: {
if (widget.windowName == nullptr || widget.windowName[0] == '\0') {
std::string msg =
fmt::format("Error drawing window contents for {}: windowName not defined", widget.name);
SPDLOG_ERROR(msg.c_str());
break;
}
auto window = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow(widget.windowName);
if (!window) {
std::string msg =
fmt::format("Error drawing window contents: windowName {} does not exist", widget.windowName);
SPDLOG_ERROR(msg.c_str());
break;
}
auto options = std::static_pointer_cast<UIWidgets::WindowButtonOptions>(widget.options);
options->color = menuThemeIndex;
if (options->showButton) {
UIWidgets::WindowButton(widget.name.c_str(), widget.cVar, window, *options);
}
if (!window->IsVisible() && options->embedWindow) {
window->DrawElement();
}
} break;
case WIDGET_SEARCH: {
UIWidgets::PushStyleButton(menuThemeIndex);
if (ImGui::Button("Clear")) {
menuSearch.Clear();
}
ImGui::SameLine();
if (CVarGetInteger(CVAR_SETTING("Menu.SearchAutofocus"), 0) &&
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() &&
!ImGui::IsMouseClicked(0)) {
ImGui::SetKeyboardFocusHere(0);
}
UIWidgets::PushStyleCombobox(menuThemeIndex);
ImGui::PushStyleColor(ImGuiCol_Border, UIWidgets::ColorValues.at(menuThemeIndex));
menuSearch.Draw();
ImGui::PopStyleColor();
UIWidgets::PopStyleCombobox();
UIWidgets::PopStyleButton();
std::string menuSearchText(menuSearch.InputBuf);
if (menuSearchText == "") {
ImGui::Text("Start typing to see results.");
return;
}
DrawSearchResults(menuSearchText);
ImGui::EndChild();
} break;
default:
break;
}
if (widget.postFunc != nullptr) {
widget.postFunc(widget);
}
} catch (const std::bad_variant_access& e) {
SPDLOG_ERROR("Failed to draw menu item \"{}\" due to: {}", widget.name, e.what());
assert(false);
}
}
void Menu::Draw() {
if (!IsVisible()) {
return;
}
DrawElement();
// Sync up the IsVisible flag if it was changed by ImGui
SyncVisibilityConsoleVariable();
}
void Menu::DrawElement() {
for (auto& [reason, info] : disabledMap) {
info.active = info.evaluation(info);
}
windowHeight = ImGui::GetMainViewport()->WorkSize.y;
windowWidth = ImGui::GetMainViewport()->WorkSize.x;
auto windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
bool popout = CVarGetInteger(CVAR_SETTING("Menu.Popout"), 0) && allowPopout;
if (popout) {
windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoDocking;
}
if (popout != popped) {
if (popout) {
windowHeight = poppedSize.y;
windowWidth = poppedSize.x;
ImGui::SetNextWindowSize({ static_cast<float>(windowWidth), static_cast<float>(windowHeight) },
ImGuiCond_Always);
ImGui::SetNextWindowPos(poppedPos, ImGuiCond_Always);
} else if (popped) {
CVarSetFloat(CVAR_SETTING("Menu.PoppedWidth"), poppedSize.x);
CVarSetFloat(CVAR_SETTING("Menu.PoppedHeight"), poppedSize.y);
CVarSave();
}
}
popped = popout;
auto windowCond = ImGuiCond_Always;
if (!popout) {
ImGui::SetNextWindowSize({ static_cast<float>(windowWidth), static_cast<float>(windowHeight) }, windowCond);
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), windowCond, { 0.5f, 0.5f });
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
}
if (!ImGui::Begin("Main Menu", NULL, windowFlags)) {
if (!popout) {
ImGui::PopStyleVar();
}
ImGui::End();
return;
}
if (popped != popout) {
if (!popout) {
ImGui::PopStyleVar();
}
CVarSetInteger(CVAR_SETTING("Menu.Popout"), popped);
CVarSetFloat(CVAR_SETTING("Menu.PoppedWidth"), poppedSize.x);
CVarSetFloat(CVAR_SETTING("Menu.PoppedHeight"), poppedSize.y);
CVarSetFloat(CVAR_SETTING("Menu.PoppedPos.x"), poppedSize.x);
CVarSetFloat(CVAR_SETTING("Menu.PoppedPos.y"), poppedSize.y);
CVarSave();
ImGui::End();
return;
}
ImGui::PushFont(OTRGlobals::Instance->fontStandardLargest);
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStyle& style = ImGui::GetStyle();
windowHeight = window->WorkRect.GetHeight();
windowWidth = window->WorkRect.GetWidth();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f));
const char* headerCvar = CVAR_SETTING("Menu.ActiveHeader");
std::string headerIndex = CVarGetString(headerCvar, "Settings");
ImVec2 pos = window->DC.CursorPos;
float centerX = pos.x + windowWidth / 2 - (style.ItemSpacing.x * (menuEntries.size() + 1));
std::vector<ImVec2> headerSizes;
float headerWidth = style.ItemSpacing.x + 20;
bool headerSearch = !CVarGetInteger(CVAR_SETTING("Menu.SidebarSearch"), 0);
if (headerSearch) {
headerWidth += 200.0f + style.ItemSpacing.x + style.FramePadding.x;
}
for (auto& label : menuOrder) {
ImVec2 size = ImGui::CalcTextSize(label.c_str());
headerSizes.push_back(size);
headerWidth += size.x + style.FramePadding.x * 2;
if (label == headerIndex) {
headerWidth += style.ItemSpacing.x;
}
}
// Full screen menu with widths below 1280, heights below 800.
// Up to 100 pixel padding when up to 1700 width, 1050 height.
// Everything above that, fixed size of 1600x950.
ImVec2 menuSize = { std::fminf(1280, windowWidth), std::fminf(800, windowHeight) };
if (windowWidth > 1380) {
menuSize.x = std::fminf(1600, windowWidth - 100);
}
if (windowHeight > 900) {
menuSize.y = std::fminf(950, windowHeight - 100);
}
pos += window->WorkRect.GetSize() / 2 - menuSize / 2;
ImGui::SetNextWindowPos(pos);
ImGui::BeginChild("Menu Block", menuSize,
ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar);
std::unordered_map<std::string, SidebarEntry>* sidebar;
float headerHeight = headerSizes.at(0).y + style.FramePadding.y * 2;
ImVec2 buttonSize = ImGui::CalcTextSize(ICON_FA_TIMES_CIRCLE) + style.FramePadding * 2;
bool scrollbar = false;
if (headerWidth > menuSize.x - buttonSize.x * 3 - style.ItemSpacing.x * 3) {
headerHeight += style.ScrollbarSize;
scrollbar = true;
}
UIWidgets::ButtonOptions options = {};
options.size = UIWidgets::Sizes::Inline;
options.tooltip = "Close Menu (Esc)";
if (UIWidgets::Button(ICON_FA_TIMES_CIRCLE, options)) {
ToggleVisibility();
// Update gamepad navigation after close based on if other menus are still visible
auto mImGuiIo = &ImGui::GetIO();
if (CVarGetInteger(CVAR_IMGUI_CONTROLLER_NAV, 0) &&
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetMenuOrMenubarVisible()) {
mImGuiIo->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
} else {
mImGuiIo->ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
}
}
ImGui::SameLine();
ImGui::SetNextWindowSizeConstraints({ 0, headerHeight }, { headerWidth, headerHeight });
ImVec2 headerSelSize = { menuSize.x - buttonSize.x * 3 - style.ItemSpacing.x * 3, headerHeight };
if (scrollbar) {
headerSelSize.y += style.ScrollbarSize;
}
bool autoFocus = CVarGetInteger(CVAR_SETTING("Menu.SearchAutofocus"), 0);
ImGui::BeginChild("Header Selection", headerSelSize,
ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_HorizontalScrollbar);
uint8_t curIndex = 0;
for (auto& label : menuOrder) {
if (curIndex != 0) {
ImGui::SameLine();
}
auto& entry = menuEntries.at(label);
std::string nextIndex = label;
UIWidgets::PushStyleButton(menuThemeIndex);
if (headerIndex != label) {
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
}
if (ModernMenuHeaderEntry(entry.label)) {
if (headerSearch) {
menuSearch.Clear();
}
CVarSetString(headerCvar, label.c_str());
CVarSave();
nextIndex = label;
}
if (headerIndex != label) {
ImGui::PopStyleColor();
}
UIWidgets::PopStyleButton();
if (headerIndex == label) {
sidebar = &entry.sidebars;
}
if (nextIndex != label) {
headerIndex = nextIndex;
}
curIndex++;
}
std::string menuSearchText = "";
if (headerSearch) {
ImGui::SameLine();
if (autoFocus && ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() &&
!ImGui::IsMouseClicked(0)) {
ImGui::SetKeyboardFocusHere(0);
}
auto color = UIWidgets::ColorValues.at(menuThemeIndex);
color.w = 0.2f;
ImGui::PushStyleColor(ImGuiCol_FrameBg, color);
menuSearch.Draw("##search", 200.0f);
menuSearchText = menuSearch.InputBuf;
menuSearchText.erase(std::remove(menuSearchText.begin(), menuSearchText.end(), ' '), menuSearchText.end());
if (menuSearchText.length() < 1) {
ImGui::SameLine(headerWidth - 200.0f + style.ItemSpacing.x);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "Search...");
}
ImGui::PopStyleColor();
}
ImGui::EndChild();
ImGui::SameLine(menuSize.x - (buttonSize.x * 2) - style.ItemSpacing.x);
UIWidgets::ButtonOptions options2 = {};
options2.color = UIWidgets::Colors::Red;
options2.size = UIWidgets::Sizes::Inline;
options2.tooltip = "Reset"
#ifdef __APPLE__
" (Command-R)"
#elif !defined(__SWITCH__) && !defined(__WIIU__)
" (Ctrl+R)"
#else
""
#endif
;
if (UIWidgets::Button(ICON_FA_UNDO, options2)) {
std::reinterpret_pointer_cast<Ship::ConsoleWindow>(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))
->Dispatch("reset");
}
ImGui::SameLine();
UIWidgets::ButtonOptions options3 = {};
options3.color = UIWidgets::Colors::Red;
options3.size = UIWidgets::Sizes::Inline;
options3.tooltip = "Quit SoH";
if (UIWidgets::Button(ICON_FA_POWER_OFF, options3)) {
if (!popped) {
ToggleVisibility();
}
Ship::Context::GetInstance()->GetWindow()->Close();
}
ImGui::PopStyleVar();
pos.y += headerHeight + style.ItemSpacing.y;
pos.x = centerX - menuSize.x / 2 + (style.ItemSpacing.x * (menuEntries.size() + 1));
window->DrawList->AddRectFilled(pos, pos + ImVec2{ menuSize.x, 4 }, ImGui::GetColorU32({ 255, 255, 255, 255 }),
true, style.WindowRounding);
pos.y += style.ItemSpacing.y;
float sectionHeight = menuSize.y - headerHeight - 4 - style.ItemSpacing.y * 2;
float columnHeight = sectionHeight - style.ItemSpacing.y * 4;
ImGui::SetNextWindowPos(pos + style.ItemSpacing * 2);
float sidebarWidth = 200 - style.ItemSpacing.x;
const char* sidebarCvar = menuEntries.at(headerIndex).sidebarCvar;
std::string sectionIndex = CVarGetString(sidebarCvar, "");
if (!sidebar->contains(sectionIndex)) {
sectionIndex = sidebar->begin()->first;
}
float sectionCenterX = pos.x + (sidebarWidth / 2);
float topY = pos.y;
ImGui::SetNextWindowSizeConstraints({ sidebarWidth, 0 }, { sidebarWidth, columnHeight });
ImGui::BeginChild((menuEntries.at(headerIndex).label + " Section").c_str(), { sidebarWidth, columnHeight * 3 },
ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, ImGuiWindowFlags_NoTitleBar);
for (auto& sidebarLabel : menuEntries.at(headerIndex).sidebarOrder) {
std::string nextIndex = "";
UIWidgets::PushStyleButton(menuThemeIndex);
if (sectionIndex != sidebarLabel) {
ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 });
}
if (ModernMenuSidebarEntry(sidebarLabel)) {
if (headerSearch) {
menuSearch.Clear();
}
CVarSetString(sidebarCvar, sidebarLabel.c_str());
CVarSave();
nextIndex = sidebarLabel;
}
if (sectionIndex != sidebarLabel) {
ImGui::PopStyleColor();
}
UIWidgets::PopStyleButton();
if (nextIndex != "") {
sectionIndex = nextIndex;
}
}
ImGui::EndChild();
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
pos = ImVec2{ sectionCenterX + (sidebarWidth / 2), topY } + style.ItemSpacing * 2;
window->DrawList->AddRectFilled(pos, pos + ImVec2{ 4, sectionHeight - style.FramePadding.y * 2 },
ImGui::GetColorU32({ 255, 255, 255, 255 }), true, style.WindowRounding);
pos.x += 4 + style.ItemSpacing.x;
ImGui::SetNextWindowPos(pos + style.ItemSpacing);
float sectionWidth = menuSize.x - sidebarWidth - 4 - style.ItemSpacing.x * 4;
std::string sectionMenuId = sectionIndex + " Settings";
int columns = sidebar->at(sectionIndex).columnCount;
size_t columnFuncs = sidebar->at(sectionIndex).columnWidgets.size();
if (windowWidth < 800) {
columns = 1;
}
float columnWidth = (sectionWidth - style.ItemSpacing.x * columns) / columns;
bool useColumns = columns > 1;
if (!useColumns || (headerSearch && menuSearchText.length() > 0)) {
ImGui::SameLine();
ImGui::SetNextWindowSizeConstraints({ sectionWidth, 0 }, { sectionWidth, columnHeight });
ImGui::BeginChild(sectionMenuId.c_str(), { sectionWidth, windowHeight * 4 }, ImGuiChildFlags_AutoResizeY,
ImGuiWindowFlags_NoTitleBar);
}
if (headerSearch && menuSearchText.length() > 0) {
uint32_t searchCount = DrawSearchResults(menuSearchText);
if (searchCount == 0) {
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize("No results found").x) / 2);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 0.4f), "No results found");
}
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize("Clear Search").x) / 2 - 10.0f);
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
UIWidgets::ButtonOptions clearBtnOpts = {};
clearBtnOpts.size = UIWidgets::Sizes::Inline;
if (UIWidgets::Button("Clear Search", clearBtnOpts)) {
menuSearch.Clear();
}
ImGui::EndChild();
} else {
std::string menuLabel = menuEntries.at(headerIndex).label;
if (MenuInit::GetUpdateFuncs().contains(menuLabel)) {
if (MenuInit::GetUpdateFuncs()[menuLabel].contains(sectionIndex)) {
for (auto& updateFunc : MenuInit::GetUpdateFuncs()[menuLabel][sectionIndex]) {
updateFunc();
}
}
}
for (int i = 0; i < columnFuncs; i++) {
std::string sectionId = fmt::format("{} Column {}", sectionMenuId, i);
if (useColumns) {
ImGui::SetNextWindowSizeConstraints({ columnWidth, 0 }, { columnWidth, columnHeight });
ImGui::BeginChild(sectionId.c_str(), { columnWidth, windowHeight * 4 }, ImGuiChildFlags_AutoResizeY,
ImGuiWindowFlags_NoTitleBar);
}
// for (auto& entryName : sidebar->at(sectionIndex).sidebarOrder) {
for (auto& entry : sidebar->at(sectionIndex).columnWidgets.at(i)) {
MenuDrawItem(entry, 90 / sidebar->at(sectionIndex).columnCount, menuThemeIndex);
}
//}
if (useColumns) {
ImGui::EndChild();
}
if (i < columns - 1) {
ImGui::SameLine();
}
}
}
if (!useColumns || menuSearchText.length() > 0) {
ImGui::EndChild();
}
ImGui::PopFont();
ImGui::PopFont();
if (!popout) {
ImGui::PopStyleVar();
}
ImGui::EndChild();
if (popout) {
poppedSize = ImGui::GetWindowSize();
poppedPos = ImGui::GetWindowPos();
}
ImGui::End();
}
} // namespace Ship

65
soh/soh/SohGui/Menu.h Normal file
View file

@ -0,0 +1,65 @@
#ifndef MENU_H
#define MENU_H
#include <libultraship/libultraship.h>
#include "graphic/Fast3D/gfx_rendering_api.h"
#include "MenuTypes.h"
namespace Ship {
uint32_t GetVectorIndexOf(std::vector<std::string>& vector, std::string value);
class Menu : public GuiWindow {
public:
using GuiWindow::GuiWindow;
Menu(const std::string& cVar, const std::string& name, uint8_t searchSidebarIndex_ = 0,
UIWidgets::Colors menuThemeIndex_ = UIWidgets::Colors::LightBlue);
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
void Draw() override;
void InsertSidebarSearch();
void RemoveSidebarSearch();
void UpdateWindowBackendObjects();
UIWidgets::Colors GetMenuThemeColor();
void MenuDrawItem(WidgetInfo& widget, uint32_t width, UIWidgets::Colors menuThemeIndex);
void AddMenuEntry(std::string entryName, const char* entryCvar);
std::unordered_map<uint32_t, disabledInfo>& GetDisabledMap();
protected:
ImVec2 mOriginalSize;
std::string mName;
uint32_t mWindowFlags;
std::unordered_map<std::string, MainMenuEntry> menuEntries;
std::vector<std::string> menuOrder;
uint32_t DrawSearchResults(std::string& menuSearchText);
ImGuiTextFilter menuSearch;
uint8_t searchSidebarIndex;
UIWidgets::Colors defaultThemeIndex;
std::shared_ptr<std::vector<Ship::WindowBackend>> availableWindowBackends;
std::unordered_map<Ship::WindowBackend, const char*> availableWindowBackendsMap;
Ship::WindowBackend configWindowBackend;
std::unordered_map<uint32_t, disabledInfo> disabledMap;
std::vector<disabledInfo> disabledVector;
const SidebarEntry searchSidebarEntry = {
.columnCount = 1,
.columnWidgets = { { { .name = "Sidebar Search",
.type = WIDGET_SEARCH,
.options = std::make_shared<UIWidgets::WidgetOptions>(UIWidgets::WidgetOptions{}.Tooltip(
"Searches all menus for the given text, including tooltips.")) } } }
};
private:
bool allowPopout = true; // PortNote: should be set to false on small screen ports
bool popped;
ImVec2 poppedSize;
ImVec2 poppedPos;
float windowHeight;
float windowWidth;
UIWidgets::Colors menuThemeIndex;
};
} // namespace Ship
#endif // MENU_H

280
soh/soh/SohGui/MenuTypes.h Normal file
View file

@ -0,0 +1,280 @@
#ifndef MENUTYPES_H
#define MENUTYPES_H
#include <libultraship/libultraship.h>
#include "UIWidgets.hpp"
typedef enum {
DISABLE_FOR_NO_VSYNC,
DISABLE_FOR_NO_WINDOWED_FULLSCREEN,
DISABLE_FOR_NO_MULTI_VIEWPORT,
DISABLE_FOR_NOT_DIRECTX,
DISABLE_FOR_DIRECTX,
DISABLE_FOR_MATCH_REFRESH_RATE_ON,
DISABLE_FOR_ADVANCED_RESOLUTION_ON,
DISABLE_FOR_VERTICAL_RES_TOGGLE_ON,
DISABLE_FOR_LOW_RES_MODE_ON,
DISABLE_FOR_NULL_PLAY_STATE,
DISABLE_FOR_DEBUG_MODE_OFF,
DISABLE_FOR_FRAME_ADVANCE_OFF,
DISABLE_FOR_ADVANCED_RESOLUTION_OFF,
DISABLE_FOR_VERTICAL_RESOLUTION_OFF,
} DisableOption;
struct WidgetInfo;
struct disabledInfo;
using VoidFunc = void (*)();
using DisableInfoFunc = bool (*)(disabledInfo&);
using DisableVec = std::vector<DisableOption>;
using WidgetFunc = void (*)(WidgetInfo&);
typedef enum {
WIDGET_CHECKBOX,
WIDGET_COMBOBOX,
WIDGET_SLIDER_INT,
WIDGET_SLIDER_FLOAT,
WIDGET_CVAR_CHECKBOX,
WIDGET_CVAR_COMBOBOX,
WIDGET_CVAR_SLIDER_INT,
WIDGET_CVAR_SLIDER_FLOAT,
WIDGET_BUTTON,
WIDGET_INPUT,
WIDGET_CVAR_INPUT,
WIDGET_COLOR_24, // color picker without alpha
WIDGET_COLOR_32, // color picker with alpha
WIDGET_SEARCH,
WIDGET_SEPARATOR,
WIDGET_SEPARATOR_TEXT,
WIDGET_TEXT,
WIDGET_WINDOW_BUTTON,
WIDGET_AUDIO_BACKEND, // needed for special operations that can't be handled easily with the normal combobox widget
WIDGET_VIDEO_BACKEND, // same as above
WIDGET_CUSTOM,
} WidgetType;
typedef enum {
SECTION_COLUMN_1,
SECTION_COLUMN_2,
SECTION_COLUMN_3,
} SectionColumns;
typedef enum {
DEBUG_LOG_TRACE,
DEBUG_LOG_DEBUG,
DEBUG_LOG_INFO,
DEBUG_LOG_WARN,
DEBUG_LOG_ERROR,
DEBUG_LOG_CRITICAL,
DEBUG_LOG_OFF,
} DebugLogOption;
// holds the widget values for a widget, contains all CVar types available from LUS. int32_t is used for boolean
// evaluation
using CVarVariant = std::variant<int32_t, const char*, float, Color_RGBA8, Color_RGB8>;
using OptionsVariant =
std::variant<UIWidgets::ButtonOptions, UIWidgets::CheckboxOptions, UIWidgets::ComboboxOptions,
UIWidgets::FloatSliderOptions, UIWidgets::IntSliderOptions, UIWidgets::WidgetOptions,
UIWidgets::WindowButtonOptions>;
// All the info needed for display and search of all widgets in the menu.
// `name` is the label displayed,
// `cVar` is the string representation of the CVar used to store the widget value
// `tooltip` is what is displayed when hovering (except when disabled, more on that later)
// `type` is the WidgetType for the widget, which is what determines how the information is used in the draw func
// `options` is a variant that holds the UIWidgetsOptions struct for the widget type
// blank objects need to be initialized with specific typing matching the expected Options struct for the widget
// `callback` is a lambda used for running code on widget change. may need `SohGui::GetMenu()` for specific menu actions
// `preFunc` is a lambda called before drawing code starts. It can be used to determine a widget's status,
// whether disabled or hidden, as well as update pointers for non-CVar widget types.
// `postFunc` is a lambda called after all drawing code is finished, for reacting to states other than
// widgets having been changed, like holding buttons.
// All three lambdas accept a `widgetInfo` reference in case it needs information on the widget for these operations
// `activeDisables` is a vector of DisableOptions for specifying what reasons a widget is disabled, which are displayed
// in the disabledTooltip for the widget. Can display multiple reasons. Handling the reasons is done in `preFunc`.
// It is recommended to utilize `disabledInfo`/`DisableReason` to list out all reasons for disabling and isHidden so
// the info can be shown.
// `windowName` is what is displayed and searched for `windowButton` type and window interactions
// `isHidden` just prevents the widget from being drawn under whatever circumstances you specify in the `preFunc`
// `sameLine` allows for specifying that the widget should be on the same line as the previous widget
struct WidgetInfo {
std::string name; // Used by all widgets
const char* cVar; // Used by all widgets except
WidgetType type;
std::shared_ptr<UIWidgets::WidgetOptions> options;
std::variant<bool*, int32_t*, float*> valuePointer;
WidgetFunc callback = nullptr;
WidgetFunc preFunc = nullptr;
WidgetFunc postFunc = nullptr;
WidgetFunc customFunction = nullptr;
DisableVec activeDisables = {};
const char* windowName = "";
bool isHidden = false;
bool sameLine = false;
WidgetInfo& CVar(const char* cVar_) {
cVar = cVar_;
return *this;
}
WidgetInfo& Options(OptionsVariant options_) {
switch (type) {
case WIDGET_AUDIO_BACKEND:
case WIDGET_VIDEO_BACKEND:
case WIDGET_COMBOBOX:
case WIDGET_CVAR_COMBOBOX:
options = std::make_shared<UIWidgets::ComboboxOptions>(std::get<UIWidgets::ComboboxOptions>(options_));
break;
case WIDGET_CHECKBOX:
case WIDGET_CVAR_CHECKBOX:
options = std::make_shared<UIWidgets::CheckboxOptions>(std::get<UIWidgets::CheckboxOptions>(options_));
break;
case WIDGET_SLIDER_FLOAT:
case WIDGET_CVAR_SLIDER_FLOAT:
options =
std::make_shared<UIWidgets::FloatSliderOptions>(std::get<UIWidgets::FloatSliderOptions>(options_));
break;
case WIDGET_SLIDER_INT:
case WIDGET_CVAR_SLIDER_INT:
options =
std::make_shared<UIWidgets::IntSliderOptions>(std::get<UIWidgets::IntSliderOptions>(options_));
break;
case WIDGET_BUTTON:
options = std::make_shared<UIWidgets::ButtonOptions>(std::get<UIWidgets::ButtonOptions>(options_));
break;
case WIDGET_WINDOW_BUTTON:
options = std::make_shared<UIWidgets::WindowButtonOptions>(std::get<UIWidgets::WindowButtonOptions>(options_));
break;
case WIDGET_TEXT:
case WIDGET_SEPARATOR_TEXT:
case WIDGET_SEPARATOR:
default:
options = std::make_shared<UIWidgets::WidgetOptions>(std::get<UIWidgets::WidgetOptions>(options_));
}
return *this;
}
void ResetDisables() {
isHidden = false;
options->disabled = false;
options->disabledTooltip = "";
activeDisables.clear();
}
WidgetInfo& Options(std::shared_ptr<UIWidgets::WidgetOptions> options_) {
options = options_;
return *this;
}
WidgetInfo& Callback(WidgetFunc callback_) {
callback = callback_;
return *this;
}
WidgetInfo& PreFunc(WidgetFunc preFunc_) {
preFunc = preFunc_;
return *this;
}
WidgetInfo& PostFunc(WidgetFunc postFunc_) {
postFunc = postFunc_;
return *this;
}
WidgetInfo& WindowName(const char* windowName_) {
windowName = windowName_;
return *this;
}
WidgetInfo& ValuePointer(std::variant<bool*, int32_t*, float*> valuePointer_) {
valuePointer = valuePointer_;
return *this;
}
WidgetInfo& SameLine(bool sameLine_) {
sameLine = sameLine_;
return *this;
}
WidgetInfo& CustomFunction(WidgetFunc customFunction_) {
customFunction = customFunction_;
return *this;
}
};
struct WidgetPath {
std::string sectionName;
std::string sidebarName;
SectionColumns column;
};
// `disabledInfo` holds information on reasons for hiding or disabling a widget, as well as an evaluation lambda that
// is run once per frame to update its status (this is done to prevent dozens of redundant CVarGets in each frame loop)
// `evaluation` returns a bool which can be determined by whatever code you want that changes its status
// `reason` is the text displayed in the disabledTooltip when a widget is disabled by a particular DisableReason
// `active` is what's referenced when determining disabled status for a widget that uses this This can also be used to
// hold reasons to hide widgets so that their evaluations are also only run once per frame
struct disabledInfo {
DisableInfoFunc evaluation;
const char* reason;
bool active = false;
int32_t value = 0;
};
// Contains the name displayed in the sidebar (label), the number of columns to use in drawing (columnCount; for visual
// separation, 1-3), and nested vectors of the widgets, grouped by column (columnWidgets). The number of widget vectors
// added to the column groups does not need to match the specified columnCount, e.g. you can have one vector added to
// the sidebar, but still separate the window into 3 columns and display only in the first column
struct SidebarEntry {
uint32_t columnCount;
std::vector<std::vector<WidgetInfo>> columnWidgets;
};
// Contains entries for what's listed in the header at the top, including the name displayed on the top bar (label),
// a vector of the SidebarEntries for that header entry, and the name of the cvar used to track what sidebar entry is
// the last viewed for that header.
struct MainMenuEntry {
std::string label;
const char* sidebarCvar;
std::unordered_map<std::string, SidebarEntry> sidebars = {};
std::vector<std::string> sidebarOrder = {};
};
static const std::unordered_map<Ship::AudioBackend, const char*> audioBackendsMap = {
{ Ship::AudioBackend::WASAPI, "Windows Audio Session API" },
{ Ship::AudioBackend::SDL, "SDL" },
};
static const std::unordered_map<Ship::WindowBackend, const char*> windowBackendsMap = {
{ Ship::WindowBackend::FAST3D_DXGI_DX11, "DirectX" },
{ Ship::WindowBackend::FAST3D_SDL_OPENGL, "OpenGL" },
{ Ship::WindowBackend::FAST3D_SDL_METAL, "Metal" },
};
struct MenuInit {
static std::vector<std::function<void()>>& GetInitFuncs() {
static std::vector<std::function<void()>> menuInitFuncs;
return menuInitFuncs;
}
static std::unordered_map<std::string, std::unordered_map<std::string, std::vector<std::function<void()>>>>&
GetUpdateFuncs() {
static std::unordered_map<std::string, std::unordered_map<std::string, std::vector<std::function<void()>>>>
menuUpdateFuncs;
return menuUpdateFuncs;
}
static void InitAll() {
auto& menuInitFuncs = MenuInit::GetInitFuncs();
for (const auto& initFunc : menuInitFuncs) {
initFunc();
}
}
};
struct RegisterMenuInitFunc {
RegisterMenuInitFunc(std::function<void()> initFunc) {
auto& menuInitFuncs = MenuInit::GetInitFuncs();
menuInitFuncs.push_back(initFunc);
}
};
struct RegisterMenuUpdateFunc {
RegisterMenuUpdateFunc(std::function<void()> updateFunc, std::string sectionName, std::string sidebarName) {
auto& menuUpdateFuncs = MenuInit::GetUpdateFuncs();
menuUpdateFuncs[sectionName][sidebarName].push_back(updateFunc);
}
};
#endif // MENUTYPES_H

View file

@ -0,0 +1,528 @@
#include "ResolutionEditor.h"
#include <imgui.h>
#include <libultraship/libultraship.h>
#include "soh/SohGui/UIWidgets.hpp"
#include <graphic/Fast3D/gfx_pc.h>
#include "soh/OTRGlobals.h"
#include "soh/SohGui/SohMenu.h"
#include "soh/SohGui/SohGui.hpp"
/* Console Variables are grouped under gAdvancedResolution. (e.g. CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled")
The following cvars are used in Libultraship and can be edited here:
- Enabled - Turns Advanced Resolution Mode on.
- AspectRatioX, AspectRatioY - Aspect ratio controls. To toggle off, set either to zero.
- VerticalPixelCount, VerticalResolutionToggle - Resolution controls.
- PixelPerfectMode, IntegerScale.Factor - Pixel Perfect Mode a.k.a. integer scaling controls.
- IntegerScale.FitAutomatically - Automatic resizing for Pixel Perfect Mode.
- IntegerScale.NeverExceedBounds - Prevents manual resizing from exceeding screen bounds.
The following cvars are also implemented in LUS for niche use cases:
- IgnoreAspectCorrection - Stretch framebuffer to fill screen.
This is something of a power-user setting for niche setups that most people won't need or care about,
but may be useful if playing the Switch/Wii U ports on a 4:3 television.
- IntegerScale.ExceedBoundsBy - Offset the max screen bounds, usually by +1.
This isn't that useful at the moment, so it's unused here.
*/
namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
enum setting { UPDATE_aspectRatioX, UPDATE_aspectRatioY, UPDATE_verticalPixelCount };
std::unordered_map<int32_t, const char*> aspectRatioPresetLabels = { { 0, "Off" },
{ 1, "Custom" },
{ 2, "Original (4:3)" },
{ 3, "Widescreen (16:9)" },
{ 4, "Nintendo 3DS (5:3)" },
{ 5, "16:10 (8:5)" },
{ 6, "Ultrawide (21:9)" } };
const float aspectRatioPresetsX[] = { 0.0f, 16.0f, 4.0f, 16.0f, 5.0f, 16.0f, 21.0f };
const float aspectRatioPresetsY[] = { 0.0f, 9.0f, 3.0f, 9.0f, 3.0f, 10.0f, 9.0f };
const int default_aspectRatio = 1; // Default combo list option
const char* pixelCountPresetLabels[] = { "Custom", "Native N64 (240p)", "2x (480p)", "3x (720p)", "4x (960p)",
"5x (1200p)", "6x (1440p)", "Full HD (1080p)", "4K (2160p)" };
const int pixelCountPresets[] = { 480, 240, 480, 720, 960, 1200, 1440, 1080, 2160 };
const int default_pixelCount = 0; // Default combo list option
// Resolution clamp values as hardcoded in LUS::Gui::ApplyResolutionChanges()
const uint32_t minVerticalPixelCount = SCREEN_HEIGHT;
const uint32_t maxVerticalPixelCount = 4320; // 18x native, or 8K TV resolution
const unsigned short default_maxIntegerScaleFactor = 6; // Default size of Integer scale factor slider.
enum messageType { MESSAGE_ERROR, MESSAGE_WARNING, MESSAGE_QUESTION, MESSAGE_INFO, MESSAGE_GRAY_75 };
const ImVec4 messageColor[]{
{ 0.85f, 0.0f, 0.0f, 1.0f }, // MESSAGE_ERROR
{ 0.85f, 0.85f, 0.0f, 1.0f }, // MESSAGE_WARNING
{ 0.0f, 0.85f, 0.85f, 1.0f }, // MESSAGE_QUESTION
{ 0.0f, 0.85f, 0.55f, 1.0f }, // MESSAGE_INFO
{ 0.75f, 0.75f, 0.75f, 1.0f } // MESSAGE_GRAY_75
};
static const float enhancementSpacerHeight = 19.0f;
// Initialise update flags.
static bool update[3];
// Initialise integer scale bounds.
static short max_integerScaleFactor = default_maxIntegerScaleFactor; // default value, which may or may not get
// overridden depending on viewport res
static short integerScale_maximumBounds = 1; // can change when window is resized
// Combo List defaults
static int32_t item_aspectRatio;
static int32_t item_pixelCount;
// Stored Values for non-UIWidgets elements
static float aspectRatioX;
static float aspectRatioY;
static int32_t verticalPixelCount;
// Additional settings
static bool showHorizontalResField;
static int32_t horizontalPixelCount;
// Disabling flags
static bool disabled_everything;
static bool disabled_pixelCount;
using namespace UIWidgets;
void ResolutionCustomWidget(WidgetInfo& info) {
ImGui::BeginDisabled(disabled_everything);
// Vertical Resolution
UIWidgets::CVarCheckbox("Set fixed vertical resolution (disables Resolution slider)", CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle",
UIWidgets::CheckboxOptions({ {.disabled = disabled_everything} }).Tooltip("Override the resolution scale slider and use the settings below, irrespective of window size.")
.Color(THEME_COLOR));
//if (disabled_pixelCount || disabled_everything) { // Hide pixel count controls.
// UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
//}
UIWidgets::PushStyleCombobox(THEME_COLOR);
if (ImGui::Combo("Pixel Count Presets", &item_pixelCount, pixelCountPresetLabels,
IM_ARRAYSIZE(pixelCountPresetLabels)) &&
item_pixelCount != default_pixelCount) { // don't change anything if "Custom" is selected.
verticalPixelCount = pixelCountPresets[item_pixelCount];
if (showHorizontalResField) {
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalPixelCount", verticalPixelCount);
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.PixelCount", item_pixelCount);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
UIWidgets::PopStyleCombobox();
// Horizontal Resolution, if visibility is enabled for it.
if (showHorizontalResField) {
// Only show the field if Aspect Ratio is being enforced.
if ((aspectRatioX > 0.0f) && (aspectRatioY > 0.0f)) {
// So basically we're "faking" this one by setting aspectRatioX instead.
UIWidgets::PushStyleInput(THEME_COLOR);
if (ImGui::InputInt("Horiz. Pixel Count", &horizontalPixelCount, 8, 320)) {
item_aspectRatio = default_aspectRatio;
if (horizontalPixelCount < SCREEN_WIDTH) {
horizontalPixelCount = SCREEN_WIDTH;
}
aspectRatioX = horizontalPixelCount;
aspectRatioY = verticalPixelCount;
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
}
UIWidgets::PopStyleInput();
} else { // Display a notice instead.
ImGui::TextColored(messageColor[MESSAGE_QUESTION],
ICON_FA_QUESTION_CIRCLE " \"Force aspect ratio\" required.");
// ImGui::Text(" ");
ImGui::SameLine();
if (UIWidgets::Button("Click to resolve", UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
item_aspectRatio = default_aspectRatio; // Set it to Custom
aspectRatioX = aspectRatioPresetsX[2]; // but use the 4:3 defaults
aspectRatioY = aspectRatioPresetsY[2];
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
}
}
}
// Vertical Resolution part 2
UIWidgets::PushStyleInput(THEME_COLOR);
if (ImGui::InputInt("Vertical Pixel Count", &verticalPixelCount, 8, 240)) {
item_pixelCount = default_pixelCount;
update[UPDATE_verticalPixelCount] = true;
// Account for the natural instinct to enter horizontal first.
// Ignore vertical resolutions that are below the lower clamp constant.
if (showHorizontalResField && !(verticalPixelCount < minVerticalPixelCount)) {
item_aspectRatio = default_aspectRatio;
aspectRatioX = horizontalPixelCount;
aspectRatioY = verticalPixelCount;
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
}
}
ImGui::EndDisabled();
UIWidgets::PopStyleInput();
// Integer scaling settings group (Pixel-perfect Mode)
static const ImGuiTreeNodeFlags IntegerScalingResolvedImGuiFlag =
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) ? ImGuiTreeNodeFlags_DefaultOpen
: ImGuiTreeNodeFlags_None;
UIWidgets::PushStyleHeader(THEME_COLOR);
if (ImGui::CollapsingHeader("Integer Scaling Settings", IntegerScalingResolvedImGuiFlag)) {
const bool disabled_pixelPerfectMode =
!CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) || disabled_everything;
// Pixel-perfect Mode
UIWidgets::CVarCheckbox("Pixel-perfect Mode", CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode",
UIWidgets::CheckboxOptions({{ .disabled = disabled_pixelCount || disabled_everything }}).Tooltip("Don't scale image to fill window.")
.Color(THEME_COLOR));
if (disabled_pixelCount && CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0)) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
// Integer Scaling
UIWidgets::CVarSliderInt(fmt::format("Integer scale factor: {}", max_integerScaleFactor).c_str(), CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.Factor",
UIWidgets::IntSliderOptions({ {.disabled = disabled_pixelPerfectMode || CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically", 0)} })
.Min(1).Max(max_integerScaleFactor).DefaultValue(1).Tooltip("Integer scales the image. Only available in pixel-perfect mode.").Color(THEME_COLOR));
// Display warning if size is being clamped or if framebuffer is larger than viewport.
if (!disabled_pixelPerfectMode &&
(CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.NeverExceedBounds", 1) &&
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.Factor", 1) >
integerScale_maximumBounds)) {
ImGui::SameLine();
ImGui::TextColored(messageColor[MESSAGE_WARNING], ICON_FA_EXCLAMATION_TRIANGLE " Window exceeded.");
}
UIWidgets::CVarCheckbox("Automatically scale image to fit viewport", CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically",
UIWidgets::CheckboxOptions({ {.disabled = disabled_pixelPerfectMode} }).DefaultValue(true).Color(THEME_COLOR)
.Tooltip("Automatically sets scale factor to fit window. Only available in pixel-perfect mode."));
if (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically", 0)) {
// This is just here to update the value shown on the slider.
// The function in LUS to handle this setting will ignore IntegerScaleFactor while active.
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.Factor", integerScale_maximumBounds);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
} // End of integer scaling settings
UIWidgets::PopStyleHeader();
// Collapsible panel for additional settings
UIWidgets::PushStyleHeader(THEME_COLOR);
if (ImGui::CollapsingHeader("Additional Settings")) {
#if defined(__SWITCH__) || defined(__WIIU__)
// Disable aspect correction, stretching the framebuffer to fill the viewport.
// This option is only really needed on systems limited to 16:9 TV resolutions, such as consoles.
// The associated cvar is still functional on PC platforms if you want to use it though.
UIWidgets::CVarCheckbox("Disable aspect correction and stretch the output image.\n"
"(Might be useful for 4:3 televisions!)\n"
"Not available in Pixel Perfect Mode.",
CVAR_PREFIX_ADVANCED_RESOLUTION ".IgnoreAspectCorrection",
UIWidgets::CheckboxOptions({{ .disabled = CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) || disabled_everything}})
.Color(THEME_COLOR));
#else
if (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IgnoreAspectCorrection", 0)) {
// This setting is intentionally not exposed on PC platforms,
// but may be accidentally activated for varying reasons.
// Having this button should hopefully prevent support headaches.
ImGui::TextColored(messageColor[MESSAGE_QUESTION], ICON_FA_QUESTION_CIRCLE
" If the image is stretched and you don't know why, click this.");
if (ImGui::Button("Click to reenable aspect correction.")) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IgnoreAspectCorrection", 0);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
UIWidgets::Spacer(2);
}
#endif
// A requested addition; an alternative way of displaying the resolution field.
if (UIWidgets::Checkbox("Show a horizontal resolution field, instead of aspect ratio.",
&showHorizontalResField, UIWidgets::CheckboxOptions().Color(THEME_COLOR))) {
if (!showHorizontalResField && (aspectRatioX > 0.0f)) { // when turning this setting off
// Refresh relevant values
aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
} else { // when turning this setting on
item_aspectRatio = default_aspectRatio;
if (aspectRatioX > 0.0f) {
// Refresh relevant values in the opposite order
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
}
}
update[UPDATE_aspectRatioX] = true;
}
// Beginning of Integer Scaling additional settings.
{
// UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
// Integer Scaling - Never Exceed Bounds.
const bool disabled_neverExceedBounds =
!CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) ||
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.FitAutomatically", 0) ||
disabled_everything;
if (UIWidgets::CVarCheckbox("Prevent integer scaling from exceeding screen bounds.\n"
"(Makes screen bounds take priority over specified factor.)",
CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.NeverExceedBounds", UIWidgets::CheckboxOptions({{ .disabled = disabled_neverExceedBounds}})
.Tooltip(
"Prevents integer scaling factor from exceeding screen bounds.\n\n"
"Enabled: Will clamp the scaling factor and display a gentle warning in the resolution editor.\n"
"Disabled: Will allow scaling to exceed screen bounds, for users who want to crop overscan.\n\n"
" " ICON_FA_INFO_CIRCLE
" Please note that exceeding screen bounds may show a scroll bar on-screen.").Color(THEME_COLOR).DefaultValue(true))) {
// Initialise the (currently unused) "Exceed Bounds By" cvar if it's been changed.
if (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0)) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
// Integer Scaling - Exceed Bounds By 1x/Offset.
// A popular feature in some retro frontends/upscalers, sometimes called "crop overscan" or "1080p 5x".
UIWidgets::CVarCheckbox("Allow integer scale factor to go +1 above maximum screen bounds.",
CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy",
UIWidgets::CheckboxOptions({{ .disabled = !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".PixelPerfectMode", 0) || disabled_everything }}).Color(THEME_COLOR));
// It does actually function as expected, but exceeding the bottom of the screen shows a scroll bar.
// I've ended up commenting this one out because of the scroll bar, and for simplicity.
// Display an info message about the scroll bar.
if (!CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.NeverExceedBounds", 1) ||
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0)) {
ImGui::TextColored(messageColor[MESSAGE_INFO],
" " ICON_FA_INFO_CIRCLE
" A scroll bar may become visible if screen bounds are exceeded.");
// Another support helper button, to disable the unused "Exceed Bounds By" cvar.
// (Remove this button if uncommenting the checkbox.)
if (CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0)) {
if (UIWidgets::Button("Click to reset a console variable that may be causing this.", UIWidgets::ButtonOptions().Color(THEME_COLOR))) {
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
} else {
ImGui::Text(" ");
}
} // End of Integer Scaling additional settings.
} // End of additional settings
UIWidgets::PopStyleHeader();
// Clamp and update the cvars that don't use UIWidgets
if (update[UPDATE_aspectRatioX] || update[UPDATE_aspectRatioY] || update[UPDATE_verticalPixelCount]) {
if (update[UPDATE_aspectRatioX]) {
if (aspectRatioX < 0.0f) {
aspectRatioX = 0.0f;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioX", aspectRatioX);
}
if (update[UPDATE_aspectRatioY]) {
if (aspectRatioY < 0.0f) {
aspectRatioY = 0.0f;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioY", aspectRatioY);
}
if (update[UPDATE_verticalPixelCount]) {
// There's a upper and lower clamp on the Libultraship side too,
// so clamping it here is entirely visual, so the vertical resolution field reflects it.
if (verticalPixelCount < minVerticalPixelCount) {
verticalPixelCount = minVerticalPixelCount;
}
if (verticalPixelCount > maxVerticalPixelCount) {
verticalPixelCount = maxVerticalPixelCount;
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalPixelCount", verticalPixelCount);
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.AspectRatio", item_aspectRatio);
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.PixelCount", item_pixelCount);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
void RegisterResolutionWidgets() {
WidgetPath path = { "Settings", "Graphics", SECTION_COLUMN_2 };
// Resolution visualiser
mSohMenu->AddWidget(path, "Viewport dimensions: {} x {}", WIDGET_TEXT).PreFunc([](WidgetInfo& info) {
info.name = fmt::format("Viewport dimensions: {} x {}", gfx_current_game_window_viewport.width,
gfx_current_game_window_viewport.height);
});
mSohMenu->AddWidget(path, "Internal resolution: {} x {}", WIDGET_TEXT).PreFunc([](WidgetInfo& info) {
info.name =
fmt::format("Internal resolution: {} x {}", gfx_current_dimensions.width, gfx_current_dimensions.height);
});
// Activator
mSohMenu->AddWidget(path, "Enable advanced settings.", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled");
// Error/Warning display
mSohMenu
->AddWidget(path, ICON_FA_EXCLAMATION_TRIANGLE " Significant frame rate (FPS) drops may be occuring.",
WIDGET_TEXT)
.PreFunc(
[](WidgetInfo& info) { info.isHidden = !(!CVarGetInteger(CVAR_LOW_RES_MODE, 0) && IsDroppingFrames()); })
.Options(WidgetOptions().Color(Colors::Orange));
mSohMenu->AddWidget(path, ICON_FA_QUESTION_CIRCLE " \"N64 Mode\" is overriding these settings.", WIDGET_TEXT)
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_LOW_RES_MODE, 0); })
.Options(WidgetOptions().Color(Colors::LightBlue));
mSohMenu->AddWidget(path, "Click to disable N64 mode", WIDGET_BUTTON)
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_LOW_RES_MODE, 0); })
.Callback([](WidgetInfo& info) {
CVarSetInteger(CVAR_LOW_RES_MODE, 0);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
});
// Aspect Ratio
mSohMenu->AddWidget(path, "AspectSep", WIDGET_SEPARATOR)
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
}
});
mSohMenu->AddWidget(path, "Force aspect ratio:", WIDGET_TEXT)
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
}
});
mSohMenu->AddWidget(path, "(Select \"Off\" to disable.)", WIDGET_TEXT)
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
}
})
.SameLine(true)
.Options(WidgetOptions().Color(Colors::Gray));
// Presets
mSohMenu->AddWidget(path, "Aspect Ratio", WIDGET_COMBOBOX)
.ValuePointer(&item_aspectRatio)
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->GetDisabledMap().at(DISABLE_FOR_ADVANCED_RESOLUTION_OFF).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_OFF);
}
})
.Callback([](WidgetInfo& info) {
if (item_aspectRatio != default_aspectRatio) { // don't change anything if "Custom" is selected.
aspectRatioX = aspectRatioPresetsX[item_aspectRatio];
aspectRatioY = aspectRatioPresetsY[item_aspectRatio];
if (showHorizontalResField) {
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioX", aspectRatioX);
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioY", aspectRatioY);
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.AspectRatio", item_aspectRatio);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
})
.Options(ComboboxOptions().ComboMap(aspectRatioPresetLabels));
mSohMenu->AddWidget(path, "AspectRatioCustom", WIDGET_CUSTOM).CustomFunction([](WidgetInfo& info) {
// Hide aspect ratio input fields if using one of the presets.
if (item_aspectRatio == default_aspectRatio && !showHorizontalResField) {
// Declare input interaction bools outside of IF statement to prevent Y field from disappearing.
const bool input_X = UIWidgets::SliderFloat("X", &aspectRatioX,
UIWidgets::FloatSliderOptions({{ .disabled = disabled_everything }}).Min(0.1f).Max(32.0f).Step(0.001f).Format("%3f")
.Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::Near).ComponentAlignment(UIWidgets::ComponentAlignment::Right));
const bool input_Y = UIWidgets::SliderFloat("Y", &aspectRatioY,
UIWidgets::FloatSliderOptions({{ .disabled = disabled_everything }}).Min(0.1f).Max(24.0f).Step(0.001f).Format("%3f")
.Color(THEME_COLOR).LabelPosition(UIWidgets::LabelPosition::Near).ComponentAlignment(UIWidgets::ComponentAlignment::Right));
if (input_X || input_Y) {
item_aspectRatio = default_aspectRatio;
update[UPDATE_aspectRatioX] = true;
update[UPDATE_aspectRatioY] = true;
}
} else if (showHorizontalResField) { // Show calculated aspect ratio
if (item_aspectRatio) {
ImGui::Dummy({ 0, 2 });
const float resolvedAspectRatio = (float)gfx_current_dimensions.width / gfx_current_dimensions.height;
ImGui::Text("Aspect ratio: %.2f:1", resolvedAspectRatio);
}
}
});
mSohMenu->AddWidget(path, "MoreResolutionSettings", WIDGET_CUSTOM).CustomFunction(ResolutionCustomWidget);
}
void UpdateResolutionVars() {
// Clamp and update the cvars that don't use UIWidgets
if (update[UPDATE_aspectRatioX] || update[UPDATE_aspectRatioY] || update[UPDATE_verticalPixelCount]) {
if (update[UPDATE_aspectRatioX]) {
if (aspectRatioX < 0.0f) {
aspectRatioX = 0.0f;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioX", aspectRatioX);
}
if (update[UPDATE_aspectRatioY]) {
if (aspectRatioY < 0.0f) {
aspectRatioY = 0.0f;
}
CVarSetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioY", aspectRatioY);
}
if (update[UPDATE_verticalPixelCount]) {
// There's a upper and lower clamp on the Libultraship side too,
// so clamping it here is entirely visual, so the vertical resolution field reflects it.
if (verticalPixelCount < minVerticalPixelCount) {
verticalPixelCount = minVerticalPixelCount;
}
if (verticalPixelCount > maxVerticalPixelCount) {
verticalPixelCount = maxVerticalPixelCount;
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalPixelCount", verticalPixelCount);
}
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.AspectRatio", item_aspectRatio);
CVarSetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.PixelCount", item_pixelCount);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
// Initialise update flags.
for (uint8_t i = 0; i < sizeof(update); i++) {
update[i] = false;
}
// Initialise integer scale bounds.
short max_integerScaleFactor = default_maxIntegerScaleFactor; // default value, which may or may not get
// overridden depending on viewport res
short integerScale_maximumBounds = 1; // can change when window is resized
// This is mostly just for UX purposes, as Fit Automatically logic is part of LUS.
if (((float)gfx_current_game_window_viewport.width / gfx_current_game_window_viewport.height) >
((float)gfx_current_dimensions.width / gfx_current_dimensions.height)) {
// Scale to window height
integerScale_maximumBounds = gfx_current_game_window_viewport.height / gfx_current_dimensions.height;
} else {
// Scale to window width
integerScale_maximumBounds = gfx_current_game_window_viewport.width / gfx_current_dimensions.width;
}
// Lower-clamping maximum bounds value to 1 is no-longer necessary as that's accounted for in LUS.
// Letting it go below 1 in this Editor will even allow for checking if screen bounds are being exceeded.
if (default_maxIntegerScaleFactor < integerScale_maximumBounds) {
max_integerScaleFactor = integerScale_maximumBounds +
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".IntegerScale.ExceedBoundsBy", 0);
}
// Combo List defaults
item_aspectRatio = CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.AspectRatio", 3);
item_pixelCount = CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".UIComboItem.PixelCount", default_pixelCount);
// Stored Values for non-UIWidgets elements
aspectRatioX = CVarGetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioX", aspectRatioPresetsX[item_aspectRatio]);
aspectRatioY = CVarGetFloat(CVAR_PREFIX_ADVANCED_RESOLUTION ".AspectRatioY", aspectRatioPresetsY[item_aspectRatio]);
verticalPixelCount =
CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalPixelCount", pixelCountPresets[item_pixelCount]);
// Additional settings
showHorizontalResField = false;
horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
// Disabling flags
disabled_everything = !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled", 0);
disabled_pixelCount = !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", 0);
}
bool IsDroppingFrames() {
// a rather imprecise way of checking for frame drops.
// but it's mostly there to inform the player of large drops.
const short targetFPS = CVarGetInteger("gInterpolationFPS", 20);
const float threshold = targetFPS / 20.0f + 4.1f;
return ImGui::GetIO().Framerate < targetFPS - threshold;
}
static RegisterMenuUpdateFunc updateFunc(UpdateResolutionVars, "Settings", "Graphics");
static RegisterMenuInitFunc initFunc(RegisterResolutionWidgets);
} // namespace BenGui

View file

@ -0,0 +1,12 @@
#ifndef RESOLUTIONEDITOR_H
#define RESOLUTIONEDITOR_H
#include <libultraship/libultraship.h>
namespace SohGui {
bool IsDroppingFrames();
void RegisterResolutionWidgets();
void UpdateResolutionVars();
} // namespace BenGui
#endif // RESOLUTIONEDITOR_H

View file

@ -20,8 +20,7 @@
#ifdef __SWITCH__
#include <port/switch/SwitchImpl.h>
#endif
#include "UIWidgets.hpp"
#include "SohMenu.h"
#include "include/global.h"
#include "include/z64audio.h"
#include "soh/SaveManager.h"
@ -32,48 +31,14 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/cosmetics/authenticGfxPatches.h"
#include "soh/Enhancements/resolution-editor/ResolutionEditor.h"
#include "soh/Enhancements/debugger/MessageViewer.h"
#include "soh/Notification/Notification.h"
#include "soh/Enhancements/TimeDisplay/TimeDisplay.h"
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* bonkDamageValues[8] = {
"No Damage",
"0.25 Heart",
"0.5 Heart",
"1 Heart",
"2 Hearts",
"4 Hearts",
"8 Hearts",
"OHKO"
};
static const inline std::vector<std::pair<const char*, const char*>> audioBackends = {
#ifdef _WIN32
@ -98,7 +63,6 @@ namespace SohGui {
return buttonText;
}
// MARK: - Delegates
std::shared_ptr<SohMenuBar> mSohMenuBar;
@ -108,6 +72,7 @@ namespace SohGui {
std::shared_ptr<Ship::GuiWindow> mGfxDebuggerWindow;
std::shared_ptr<Ship::GuiWindow> mInputEditorWindow;
std::shared_ptr<SohMenu> mSohMenu;
std::shared_ptr<AudioEditor> mAudioEditorWindow;
std::shared_ptr<InputViewer> mInputViewer;
std::shared_ptr<InputViewerSettingsWindow> mInputViewerSettings;
@ -129,25 +94,30 @@ namespace SohGui {
std::shared_ptr<TimeSplitWindow> mTimeSplitWindow;
std::shared_ptr<PlandomizerWindow> mPlandomizerWindow;
std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow;
std::shared_ptr<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow> mAdvancedResolutionSettingsWindow;
std::shared_ptr<SohModalWindow> mModalWindow;
std::shared_ptr<Notification::Window> mNotificationWindow;
std::shared_ptr<TimeDisplayWindow> mTimeDisplayWindow;
std::shared_ptr<AboutWindow> mAboutWindow;
UIWidgets::Colors GetMenuThemeColor() {
return mSohMenu->GetMenuThemeColor();
}
void SetupGuiElements() {
auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui();
mSohMenuBar = std::make_shared<SohMenuBar>(CVAR_MENU_BAR_OPEN, CVarGetInteger(CVAR_MENU_BAR_OPEN, 0));
/*mSohMenuBar = std::make_shared<SohMenuBar>(CVAR_MENU_BAR_OPEN, CVarGetInteger(CVAR_MENU_BAR_OPEN, 0));
gui->SetMenuBar(std::reinterpret_pointer_cast<Ship::GuiMenuBar>(mSohMenuBar));
if (gui->GetMenuBar() && !gui->GetMenuBar()->IsVisible()) {
if (!gui->GetMenuBar() && !CVarGetInteger("gSettings.DisableMenuShortcutNotify", 0)) {
#if defined(__SWITCH__) || defined(__WIIU__)
Notification::Emit({ .message = "Press - to access enhancements menu", .remainingTime = 10.0f });
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press - to access enhancements menu");
#else
Notification::Emit({ .message = "Press F1 to access enhancements menu", .remainingTime = 10.0f });
gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press F1 to access enhancements menu");
#endif
}
}*/
mSohMenu = std::make_shared<SohMenu>(CVAR_WINDOW("Menu"), "Port Menu");
gui->SetMenu(mSohMenu);
mStatsWindow = gui->GetGuiWindow("Stats");
if (mStatsWindow == nullptr) {
@ -159,9 +129,9 @@ namespace SohGui {
SPDLOG_ERROR("Could not find console window");
}
mGfxDebuggerWindow = gui->GetGuiWindow("GfxDebuggerWindow");
mGfxDebuggerWindow = gui->GetGuiWindow("Gfx Debugger");
if (mGfxDebuggerWindow == nullptr) {
SPDLOG_ERROR("Could not find input GfxDebuggerWindow");
SPDLOG_ERROR("Could not find Gfx Debugger window");
}
mInputEditorWindow = gui->GetGuiWindow("Controller Configuration");
@ -185,7 +155,7 @@ namespace SohGui {
gui->AddGuiWindow(mSaveEditorWindow);
mHookDebuggerWindow = std::make_shared<HookDebuggerWindow>(CVAR_WINDOW("HookDebugger"), "Hook Debugger", ImVec2(1250, 850));
gui->AddGuiWindow(mHookDebuggerWindow);
mDLViewerWindow = std::make_shared<DLViewerWindow>(CVAR_WINDOW("DLViewer"), "Display List Viewer", ImVec2(520, 600));
mDLViewerWindow = std::make_shared<DLViewerWindow>(CVAR_WINDOW("DisplayListViewer"), "Display List Viewer", ImVec2(520, 600));
gui->AddGuiWindow(mDLViewerWindow);
mValueViewerWindow = std::make_shared<ValueViewerWindow>(CVAR_WINDOW("ValueViewer"), "Value Viewer", ImVec2(520, 600));
gui->AddGuiWindow(mValueViewerWindow);
@ -193,26 +163,24 @@ namespace SohGui {
gui->AddGuiWindow(mMessageViewerWindow);
mGameplayStatsWindow = std::make_shared<GameplayStatsWindow>(CVAR_WINDOW("GameplayStats"), "Gameplay Stats", ImVec2(480, 550));
gui->AddGuiWindow(mGameplayStatsWindow);
mCheckTrackerWindow = std::make_shared<CheckTracker::CheckTrackerWindow>(CVAR_WINDOW("CheckTracker"), "Check Tracker");
mCheckTrackerWindow = std::make_shared<CheckTracker::CheckTrackerWindow>(CVAR_WINDOW("CheckTracker"), "Check Tracker", ImVec2(400, 540));
gui->AddGuiWindow(mCheckTrackerWindow);
mCheckTrackerSettingsWindow = std::make_shared<CheckTracker::CheckTrackerSettingsWindow>(CVAR_WINDOW("CheckTrackerSettings"), "Check Tracker Settings", ImVec2(600, 375));
gui->AddGuiWindow(mCheckTrackerSettingsWindow);
mEntranceTrackerWindow = std::make_shared<EntranceTrackerWindow>(CVAR_WINDOW("EntranceTracker"), "Entrance Tracker");
mEntranceTrackerWindow = std::make_shared<EntranceTrackerWindow>(CVAR_WINDOW("EntranceTracker"), "Entrance Tracker", ImVec2(500, 750));
gui->AddGuiWindow(mEntranceTrackerWindow);
mEntranceTrackerSettingsWindow = std::make_shared<EntranceTrackerSettingsWindow>(CVAR_WINDOW("EntranceTrackerSettings"), "Entrance Tracker Settings", ImVec2(600, 375));
gui->AddGuiWindow(mEntranceTrackerSettingsWindow);
mItemTrackerWindow = std::make_shared<ItemTrackerWindow>(CVAR_WINDOW("ItemTracker"), "Item Tracker");
mItemTrackerWindow = std::make_shared<ItemTrackerWindow>(CVAR_WINDOW("ItemTracker"), "Item Tracker", ImVec2(350, 600));
gui->AddGuiWindow(mItemTrackerWindow);
mItemTrackerSettingsWindow = std::make_shared<ItemTrackerSettingsWindow>(CVAR_WINDOW("ItemTrackerSettings"), "Item Tracker Settings", ImVec2(733, 472));
gui->AddGuiWindow(mItemTrackerSettingsWindow);
mRandomizerSettingsWindow = std::make_shared<RandomizerSettingsWindow>(CVAR_WINDOW("RandomizerSettings"), "Randomizer Settings", ImVec2(920, 600));
gui->AddGuiWindow(mRandomizerSettingsWindow);
mTimeSplitWindow = std::make_shared<TimeSplitWindow>(CVAR_WINDOW("TimeSplitEnabled"), "Time Splits", ImVec2(450, 660));
mTimeSplitWindow = std::make_shared<TimeSplitWindow>(CVAR_WINDOW("TimeSplits"), "Time Splits", ImVec2(450, 660));
gui->AddGuiWindow(mTimeSplitWindow);
mPlandomizerWindow = std::make_shared<PlandomizerWindow>(CVAR_WINDOW("PlandomizerWindow"), "Plandomizer Editor", ImVec2(850, 760));
mPlandomizerWindow = std::make_shared<PlandomizerWindow>(CVAR_WINDOW("PlandomizerEditor"), "Plandomizer Editor", ImVec2(850, 760));
gui->AddGuiWindow(mPlandomizerWindow);
mAdvancedResolutionSettingsWindow = std::make_shared<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow>(CVAR_WINDOW("AdvancedResolutionEditor"), "Advanced Resolution Settings", ImVec2(497, 599));
gui->AddGuiWindow(mAdvancedResolutionSettingsWindow);
mModalWindow = std::make_shared<SohModalWindow>(CVAR_WINDOW("ModalWindow"), "Modal Window");
gui->AddGuiWindow(mModalWindow);
mModalWindow->Show();
@ -221,8 +189,6 @@ namespace SohGui {
mNotificationWindow->Show();
mTimeDisplayWindow = std::make_shared<TimeDisplayWindow>(CVAR_WINDOW("TimeDisplayEnabled"), "Additional Timers");
gui->AddGuiWindow(mTimeDisplayWindow);
mAboutWindow = std::make_shared<AboutWindow>(CVAR_WINDOW("AboutWindow"), "About");
gui->AddGuiWindow(mAboutWindow);
}
void Destroy() {
@ -231,7 +197,6 @@ namespace SohGui {
mNotificationWindow = nullptr;
mModalWindow = nullptr;
mAdvancedResolutionSettingsWindow = nullptr;
mRandomizerSettingsWindow = nullptr;
mItemTrackerWindow = nullptr;
mItemTrackerSettingsWindow = nullptr;
@ -259,7 +224,6 @@ namespace SohGui {
mTimeSplitWindow = nullptr;
mPlandomizerWindow = nullptr;
mTimeDisplayWindow = nullptr;
mAboutWindow = nullptr;
}
void RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function<void()> button1callback, std::function<void()> button2callback) {

View file

@ -26,18 +26,8 @@
#include "soh/Enhancements/randomizer/randomizer_settings_window.h"
#include "soh/Enhancements/timesplits/TimeSplits.h"
#include "soh/Enhancements/randomizer/Plandomizer.h"
#include "soh/AboutWindow.h"
#include "SohModals.h"
#ifdef __cplusplus
extern "C" {
#endif
void enableBetaQuest();
void disableBetaQuest();
#ifdef __cplusplus
}
#endif
namespace SohGui {
void SetupHooks();
void SetupGuiElements();
@ -45,6 +35,9 @@ namespace SohGui {
void Destroy();
void RegisterPopup(std::string title, std::string message, std::string button1 = "OK", std::string button2 = "", std::function<void()> button1callback = nullptr, std::function<void()> button2callback = nullptr);
void ShowRandomizerSettingsMenu();
UIWidgets::Colors GetMenuThemeColor();
}
#define THEME_COLOR SohGui::GetMenuThemeColor()
#endif /* SohGui_hpp */

168
soh/soh/SohGui/SohMenu.cpp Normal file
View file

@ -0,0 +1,168 @@
#include "SohMenu.h"
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/controls/SohInputEditorWindow.h"
#include "window/gui/GuiMenuBar.h"
#include "window/gui/GuiElement.h"
#include <variant>
#include "StringHelper.h"
#include <spdlog/fmt/fmt.h>
#include <tuple>
extern std::unordered_map<s16, const char*> warpPointSceneList;
namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
using namespace UIWidgets;
void SohMenu::AddSidebarEntry(std::string sectionName, std::string sidebarName, uint32_t columnCount) {
assert(!sectionName.empty());
assert(!sidebarName.empty());
menuEntries.at(sectionName).sidebars.emplace(sidebarName, SidebarEntry{ .columnCount = columnCount });
menuEntries.at(sectionName).sidebarOrder.push_back(sidebarName);
}
WidgetInfo& SohMenu::AddWidget(WidgetPath& pathInfo, std::string widgetName, WidgetType widgetType) {
assert(!widgetName.empty()); // Must be unique
assert(menuEntries.contains(pathInfo.sectionName)); // Section/header must already exist
assert(menuEntries.at(pathInfo.sectionName).sidebars.contains(pathInfo.sidebarName)); // Sidebar must already exist
std::unordered_map<std::string, SidebarEntry>& sidebar = menuEntries.at(pathInfo.sectionName).sidebars;
uint8_t column = pathInfo.column;
if (sidebar.contains(pathInfo.sidebarName)) {
while (sidebar.at(pathInfo.sidebarName).columnWidgets.size() < column + 1) {
sidebar.at(pathInfo.sidebarName).columnWidgets.push_back({});
}
}
SidebarEntry& entry = sidebar.at(pathInfo.sidebarName);
entry.columnWidgets.at(column).push_back({ .name = widgetName, .type = widgetType });
WidgetInfo& widget = entry.columnWidgets.at(column).back();
switch (widgetType) {
case WIDGET_CHECKBOX:
case WIDGET_CVAR_CHECKBOX:
widget.options = std::make_shared<CheckboxOptions>();
break;
case WIDGET_SLIDER_FLOAT:
case WIDGET_CVAR_SLIDER_FLOAT:
widget.options = std::make_shared<FloatSliderOptions>();
break;
case WIDGET_SLIDER_INT:
case WIDGET_CVAR_SLIDER_INT:
widget.options = std::make_shared<IntSliderOptions>();
break;
case WIDGET_COMBOBOX:
case WIDGET_CVAR_COMBOBOX:
case WIDGET_AUDIO_BACKEND:
case WIDGET_VIDEO_BACKEND:
widget.options = std::make_shared<ComboboxOptions>();
break;
case WIDGET_BUTTON:
widget.options = std::make_shared<ButtonOptions>();
break;
case WIDGET_WINDOW_BUTTON:
widget.options = std::make_shared<WindowButtonOptions>();
break;
case WIDGET_COLOR_24:
case WIDGET_COLOR_32:
break;
case WIDGET_SEARCH:
case WIDGET_SEPARATOR:
case WIDGET_SEPARATOR_TEXT:
case WIDGET_TEXT:
default:
widget.options = std::make_shared<WidgetOptions>();
}
return widget;
}
SohMenu::SohMenu(const std::string& consoleVariable, const std::string& name)
: Menu(consoleVariable, name, 0, UIWidgets::Colors::LightBlue) {
}
void SohMenu::InitElement() {
Ship::Menu::InitElement();
AddMenuSettings();
AddMenuEnhancements();
AddMenuRandomizer();
#ifdef ENABLE_REMOTE_CONTROL
AddMenuNetwork();
#endif
AddMenuDevTools();
if (CVarGetInteger(CVAR_SETTING("Menu.SidebarSearch"), 0)) {
InsertSidebarSearch();
}
for (auto& initFunc : MenuInit::GetInitFuncs()) {
initFunc();
}
disabledMap = {
{ DISABLE_FOR_NO_VSYNC,
{ [](disabledInfo& info) -> bool {
return !Ship::Context::GetInstance()->GetWindow()->CanDisableVerticalSync();
},
"Disabling VSync not supported" } },
{ DISABLE_FOR_NO_WINDOWED_FULLSCREEN,
{ [](disabledInfo& info) -> bool {
return !Ship::Context::GetInstance()->GetWindow()->SupportsWindowedFullscreen();
},
"Windowed Fullscreen not supported" } },
{ DISABLE_FOR_NO_MULTI_VIEWPORT,
{ [](disabledInfo& info) -> bool {
return !Ship::Context::GetInstance()->GetWindow()->GetGui()->SupportsViewports();
},
"Multi-viewports not supported" } },
{ DISABLE_FOR_NOT_DIRECTX,
{ [](disabledInfo& info) -> bool {
return Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() !=
Ship::WindowBackend::FAST3D_DXGI_DX11;
},
"Available Only on DirectX" } },
{ DISABLE_FOR_DIRECTX,
{ [](disabledInfo& info) -> bool {
return Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() ==
Ship::WindowBackend::FAST3D_DXGI_DX11;
},
"Not Available on DirectX" } },
{ DISABLE_FOR_MATCH_REFRESH_RATE_ON,
{ [](disabledInfo& info) -> bool { return CVarGetInteger(CVAR_SETTING("gMatchRefreshRate"), 0); },
"Match Refresh Rate is Enabled" } },
{ DISABLE_FOR_ADVANCED_RESOLUTION_ON,
{ [](disabledInfo& info) -> bool { return CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled", 0); },
"Advanced Resolution Enabled" } },
{ DISABLE_FOR_VERTICAL_RES_TOGGLE_ON,
{ [](disabledInfo& info) -> bool {
return CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", 0);
},
"Vertical Resolution Toggle Enabled" } },
{ DISABLE_FOR_LOW_RES_MODE_ON,
{ [](disabledInfo& info) -> bool { return CVarGetInteger(CVAR_LOW_RES_MODE, 0); }, "N64 Mode Enabled" } },
{ DISABLE_FOR_NULL_PLAY_STATE,
{ [](disabledInfo& info) -> bool { return gPlayState == NULL; }, "Save Not Loaded" } },
{ DISABLE_FOR_DEBUG_MODE_OFF,
{ [](disabledInfo& info) -> bool { return !CVarGetInteger("gDeveloperTools.DebugEnabled", 0); },
"Debug Mode is Disabled" } },
{ DISABLE_FOR_FRAME_ADVANCE_OFF,
{ [](disabledInfo& info) -> bool { return !(gPlayState != nullptr && gPlayState->frameAdvCtx.enabled); },
"Frame Advance is Disabled" } },
{ DISABLE_FOR_ADVANCED_RESOLUTION_OFF,
{ [](disabledInfo& info) -> bool { return !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".Enabled", 0); },
"Advanced Resolution is Disabled" } },
{ DISABLE_FOR_VERTICAL_RESOLUTION_OFF,
{ [](disabledInfo& info) -> bool { return !CVarGetInteger(CVAR_PREFIX_ADVANCED_RESOLUTION ".VerticalResolutionToggle", 0); },
"Vertical Resolution Toggle is Off" } },
};
}
void SohMenu::UpdateElement() {
Ship::Menu::UpdateElement();
}
void SohMenu::Draw() {
Ship::Menu::Draw();
}
void SohMenu::DrawElement() {
Ship::Menu::DrawElement();
}
} // namespace SohGui

227
soh/soh/SohGui/SohMenu.h Normal file
View file

@ -0,0 +1,227 @@
#ifndef SOHMENU_H
#define SOHMENU_H
#include <libultraship/libultraship.h>
#include "UIWidgets.hpp"
#include "Menu.h"
#include "graphic/Fast3D/gfx_rendering_api.h"
#include "soh/cvar_prefixes.h"
#include "soh/Enhancements/enhancementTypes.h"
#include "soh/Enhancements/presets.h"
extern "C" {
#include "z64.h"
#include "functions.h"
#include "variables.h"
#include "macros.h"
extern PlayState* gPlayState;
}
#ifdef __cplusplus
extern "C" {
#endif
void enableBetaQuest();
void disableBetaQuest();
#ifdef __cplusplus
}
#endif
namespace SohGui {
static const std::unordered_map<int32_t, const char*> menuThemeOptions = {
{ UIWidgets::Colors::Red, "Red" },
{ UIWidgets::Colors::DarkRed, "Dark Red" },
{ UIWidgets::Colors::Orange, "Orange" },
{ UIWidgets::Colors::Green, "Green" },
{ UIWidgets::Colors::DarkGreen, "Dark Green" },
{ UIWidgets::Colors::LightBlue, "Light Blue" },
{ UIWidgets::Colors::Blue, "Blue" },
{ UIWidgets::Colors::DarkBlue, "Dark Blue" },
{ UIWidgets::Colors::Indigo, "Indigo" },
{ UIWidgets::Colors::Violet, "Violet" },
{ UIWidgets::Colors::Purple, "Purple" },
{ UIWidgets::Colors::Brown, "Brown" },
{ UIWidgets::Colors::Gray, "Gray" },
{ UIWidgets::Colors::DarkGray, "Dark Gray" },
};
static const std::unordered_map<int32_t, const char*> textureFilteringMap = {
{ FILTER_THREE_POINT, "Three-Point" },
{ FILTER_LINEAR, "Linear" },
{ FILTER_NONE, "None" },
};
static const std::unordered_map<int32_t, const char*> logLevels = {
{ DEBUG_LOG_TRACE, "Trace" }, { DEBUG_LOG_DEBUG, "Debug" }, { DEBUG_LOG_INFO, "Info" },
{ DEBUG_LOG_WARN, "Warn" }, { DEBUG_LOG_ERROR, "Error" }, { DEBUG_LOG_CRITICAL, "Critical" },
{ DEBUG_LOG_OFF, "Off" },
};
static const std::unordered_map<int32_t, const char*> notificationPosition = {
{ 0, "Top Left" }, { 1, "Top Right" }, { 2, "Bottom Left" }, { 3, "Bottom Right" }, { 4, "Hidden" },
};
static const std::unordered_map<int32_t, const char*> dekuStickCheat = {
{ DEKU_STICK_NORMAL, "Normal" },
{ DEKU_STICK_UNBREAKABLE, "Unbreakable" },
{ DEKU_STICK_UNBREAKABLE_AND_ALWAYS_ON_FIRE, "Unbreakable + Always on Fire" }
};
static const std::unordered_map<int32_t, const char*> skipGetItemAnimationOptions = {
{ SGIA_DISABLED, "Disabled" },
{ SGIA_JUNK, "Junk Items" },
{ SGIA_ALL, "All Items" }
};
static const std::unordered_map<int32_t, const char*> chestStyleMatchesContentsOptions = {
{ CSMC_DISABLED, "Disabled" },
{ CSMC_BOTH, "Both" },
{ CSMC_TEXTURE, "Texture Only" },
{ CSMC_SIZE, "Size Only" }
};
static const std::unordered_map<int32_t, const char*> timeTravelOptions = {
{ TIME_TRAVEL_DISABLED, "Disabled" },
{ TIME_TRAVEL_OOT, "Ocarina of Time" },
{ TIME_TRAVEL_ANY, "Any Ocarina" }
};
static const std::unordered_map<int32_t, const char*> sleepingWaterfallOptions = {
{ WATERFALL_ALWAYS, "Always" },
{ WATERFALL_ONCE, "Once" },
{ WATERFALL_NEVER, "Never" }
};
static const std::unordered_map<int32_t, const char*> allPowers = {
{ DAMAGE_VANILLA, "Vanilla (1x)" },
{ DAMAGE_DOUBLE, "Double (2x)" },
{ DAMAGE_QUADRUPLE, "Quadruple (4x)" },
{ DAMAGE_OCTUPLE, "Octuple (8x)" },
{ DAMAGE_FOOLISH, "Foolish (16x)" },
{ DAMAGE_RIDICULOUS, "Ridiculous (32x)" },
{ DAMAGE_MERCILESS, "Merciless (64x)" },
{ DAMAGE_TORTURE, "Pure Torture (128x)" },
{ DAMAGE_OHKO, "OHKO (256x)" }
};
static const std::unordered_map<int32_t, const char*> subPowers = {
{ DAMAGE_VANILLA, "Vanilla (1x)" },
{ DAMAGE_DOUBLE, "Double (2x)" },
{ DAMAGE_QUADRUPLE, "Quadruple (4x)" },
{ DAMAGE_OCTUPLE, "Octuple (8x)" },
{ DAMAGE_FOOLISH, "Foolish (16x)" },
{ DAMAGE_RIDICULOUS, "Ridiculous (32x)" },
{ DAMAGE_MERCILESS, "Merciless (64x)" },
{ DAMAGE_TORTURE, "Pure Torture (128x)" },
};
static const std::unordered_map<int32_t, const char*> subSubPowers = {
{ DAMAGE_VANILLA, "Vanilla (1x)" },
{ DAMAGE_DOUBLE, "Double (2x)" },
{ DAMAGE_QUADRUPLE, "Quadruple (4x)" },
{ DAMAGE_OCTUPLE, "Octuple (8x)" },
{ DAMAGE_FOOLISH, "Foolish (16x)" },
{ DAMAGE_RIDICULOUS, "Ridiculous (32x)" },
{ DAMAGE_MERCILESS, "Merciless (64x)" },
};
static const std::unordered_map<int32_t, const char*> bonkDamageValues = {
{ BONK_DAMAGE_NONE, "No Damage" },
{ BONK_DAMAGE_QUARTER_HEART, "0.25 Hearts" },
{ BONK_DAMAGE_HALF_HEART, "0.5 Hearts" },
{ BONK_DAMAGE_1_HEART, "1 Heart" },
{ BONK_DAMAGE_2_HEARTS, "2 Hearts" },
{ BONK_DAMAGE_4_HEARTS, "4 Hearts" },
{ BONK_DAMAGE_8_HEARTS, "8 Hearts" },
{ BONK_DAMAGE_OHKO, "OHKO" }
};
static const std::unordered_map<int32_t, const char*> cursorAnywhereValues = {
{ PAUSE_ANY_CURSOR_RANDO_ONLY, "Only in Rando" },
{ PAUSE_ANY_CURSOR_ALWAYS_ON, "Always" },
{ PAUSE_ANY_CURSOR_ALWAYS_OFF, "Never" }
};
static const std::unordered_map<int32_t, const char*> swordToggleModes = {
{ SWORD_TOGGLE_NONE, "None" },
{ SWORD_TOGGLE_CHILD, "Child Toggle" },
{ SWORD_TOGGLE_BOTH_AGES, "Both Ages" }
};
static const std::unordered_map<int32_t, const char*> zFightingOptions = {
{ ZFIGHT_FIX_DISABLED, "Disabled" },
{ ZFIGHT_FIX_CONSISTENT_VANISH, "Consistent Vanish" },
{ ZFIGHT_FIX_NO_VANISH, "No Vanish" }
};
static const std::unordered_map<int32_t, const char*> mirroredWorldModes = {
{ MIRRORED_WORLD_OFF, "Disabled" },
{ MIRRORED_WORLD_ALWAYS, "Always" },
{ MIRRORED_WORLD_RANDOM, "Random" },
{ MIRRORED_WORLD_RANDOM_SEEDED, "Random (Seeded)" },
{ MIRRORED_WORLD_DUNGEONS_ALL, "Dungeons" },
{ MIRRORED_WORLD_DUNGEONS_VANILLA, "Dungeons (Vanilla)" },
{ MIRRORED_WORLD_DUNGEONS_MQ, "Dungeons (MQ)" },
{ MIRRORED_WORLD_DUNGEONS_RANDOM, "Dungeons Random" },
{ MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED, "Dungeons Random (Seeded)"}
};
static const std::unordered_map<int32_t, const char*> enemyRandomizerModes = {
{ ENEMY_RANDOMIZER_OFF, "Disabled" },
{ ENEMY_RANDOMIZER_RANDOM, "Random" },
{ ENEMY_RANDOMIZER_RANDOM_SEEDED, "Random (Seeded)"}
};
static const std::unordered_map<int32_t, const char*> debugSaveFileModes = {
{ 0, "Off" }, { 1, "Vanilla" }, { 2, "Maxed" },
};
static const std::unordered_map<int32_t, const char*> bootSequenceLabels = {
{ BOOTSEQUENCE_DEFAULT, "Default" },
{ BOOTSEQUENCE_AUTHENTIC, "Authentic" },
{ BOOTSEQUENCE_FILESELECT, "File Select" }
};
static const std::unordered_map<int32_t, const char*> enhancementPresetList = {
{ ENHANCEMENT_PRESET_DEFAULT, "Default" },
{ ENHANCEMENT_PRESET_VANILLA_PLUS, "Vanilla Plus" },
{ ENHANCEMENT_PRESET_ENHANCED, "Enhanced" },
{ ENHANCEMENT_PRESET_RANDOMIZER, "Randomizer" }
};
static const char* itemCountMessageCVars[3] = {
CVAR_ENHANCEMENT("InjectItemCounts.GoldSkulltula"),
CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"),
CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"),
};
static const char* itemCountMessageOptions[ARRAY_COUNT(itemCountMessageCVars)] = {
"Gold Skulltula Tokens",
"Pieces of Heart",
"Heart Containers",
};
class SohMenu : public Ship::Menu {
public:
SohMenu(const std::string& consoleVariable, const std::string& name);
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
void Draw() override;
void AddSidebarEntry(std::string sectionName, std::string sidbarName, uint32_t columnCount);
WidgetInfo& AddWidget(WidgetPath& pathInfo, std::string widgetName, WidgetType widgetType);
void AddMenuSettings();
void AddMenuEnhancements();
void AddMenuDevTools();
void AddMenuRandomizer();
void AddMenuNetwork();
private:
char mGitCommitHashTruncated[8];
bool mIsTaggedVersion;
};
} // namespace SohGui
#endif // SOHMENU_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,170 @@
#include "SohMenu.h"
namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
using namespace UIWidgets;
void SohMenu::AddMenuDevTools() {
// Add Dev Tools Menu
AddMenuEntry("Dev Tools", CVAR_SETTING("Menu.DevToolsSidebarSection"));
// General
AddSidebarEntry("Dev Tools", "General", 3);
WidgetPath path = { "Dev Tools", "General", SECTION_COLUMN_1 };
AddWidget(path, "Popout Menu", WIDGET_CVAR_CHECKBOX)
.CVar("gSettings.Menu.Popout")
.Options(CheckboxOptions().Tooltip("Changes the menu display from overlay to windowed."));
AddWidget(path, "Debug Mode", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_DEVELOPER_TOOLS("DebugEnabled"))
.Options(CheckboxOptions().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."));
AddWidget(path, "OoT Registry Editor", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_DEVELOPER_TOOLS("RegEditEnabled"))
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
.Options(CheckboxOptions().Tooltip("Enables the registry editor."));
AddWidget(path, "Debug Save File Mode", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_DEVELOPER_TOOLS("DebugSaveFileMode"))
.PreFunc([](WidgetInfo& info) { info.isHidden = !CVarGetInteger(CVAR_DEVELOPER_TOOLS("DebugEnabled"), 0); })
.Options(ComboboxOptions()
.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")
.ComboMap(debugSaveFileModes));
AddWidget(path, "OoT Skulltula Debug", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_DEVELOPER_TOOLS("SkulltulaDebugEnabled"))
.Options(CheckboxOptions().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."));
AddWidget(path, "Better Debug Warp Screen", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_DEVELOPER_TOOLS("BetterDebugWarpScreen"))
.Options(CheckboxOptions().Tooltip(
"Optimized debug warp screen, with the added ability to chose entrances and time of day"));
AddWidget(path, "Debug Warp Screen Translation", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_DEVELOPER_TOOLS("DebugWarpScreenTranslation"))
.Options(CheckboxOptions()
.Tooltip("Translate the Debug Warp Screen based on the game language.")
.DefaultValue(true));
AddWidget(path, "Resource logging", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_DEVELOPER_TOOLS("ResourceLogging"))
.Options(CheckboxOptions().Tooltip("Logs some resources as XML when they're loaded in binary format"));
AddWidget(path, "Frame Advance", WIDGET_CHECKBOX)
.Options(CheckboxOptions().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."))
.PreFunc([](WidgetInfo& info) {
info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NULL_PLAY_STATE).active ||
mSohMenu->disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active;
if (gPlayState != nullptr) {
info.valuePointer = (bool*)&gPlayState->frameAdvCtx.enabled;
} else {
info.valuePointer = (bool*)nullptr;
}
});
AddWidget(path, "Advance 1", WIDGET_BUTTON)
.Options(ButtonOptions().Tooltip("Advance 1 frame.").Size(Sizes::Inline))
.Callback([](WidgetInfo& info) { CVarSetInteger(CVAR_DEVELOPER_TOOLS("FrameAdvanceTick"), 1); })
.PreFunc([](WidgetInfo& info) {
info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_FRAME_ADVANCE_OFF).active ||
mSohMenu->disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active;
});
AddWidget(path, "Advance (Hold)", WIDGET_BUTTON)
.Options(ButtonOptions().Tooltip("Advance frames while the button is held.").Size(Sizes::Inline))
.PreFunc([](WidgetInfo& info) {
info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_FRAME_ADVANCE_OFF).active ||
mSohMenu->disabledMap.at(DISABLE_FOR_DEBUG_MODE_OFF).active;
})
.PostFunc([](WidgetInfo& info) {
if (ImGui::IsItemActive()) {
CVarSetInteger(CVAR_DEVELOPER_TOOLS("FrameAdvanceTick"), 1);
}
})
.SameLine(true);
// Stats
path.sidebarName = "Stats";
AddSidebarEntry("Dev Tools", path.sidebarName, 1);
AddWidget(path, "Popout Stats Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("Stats"))
.WindowName("Stats")
.Options(WindowButtonOptions().Tooltip("Enables the separate Stats Window."));
// Console
path.sidebarName = "Console";
AddSidebarEntry("Dev Tools", path.sidebarName, 1);
AddWidget(path, "Popout Console", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("Console"))
.WindowName("Console")
.Options(WindowButtonOptions().Tooltip("Enables the separate Console Window."));
// Save Editor
path.sidebarName = "Save Editor";
AddSidebarEntry("Dev Tools", path.sidebarName, 1);
AddWidget(path, "Popout Save Editor", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("SaveEditor"))
.WindowName("Save Editor")
.Options(WindowButtonOptions().Tooltip("Enables the separate Save Editor Window."));
// Hook Debugger
path.sidebarName = "Hook Debugger";
AddSidebarEntry("Dev Tools", path.sidebarName, 1);
AddWidget(path, "Popout Hook Debugger", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("HookDebugger"))
.WindowName("Hook Debugger")
.Options(WindowButtonOptions().Tooltip("Enables the separate Hook Debugger Window."));
// Collision Viewer
path.sidebarName = "Collision Viewer";
AddSidebarEntry("Dev Tools", path.sidebarName, 2);
AddWidget(path, "Popout Collision Viewer", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("CollisionViewer"))
.WindowName("Collision Viewer")
.Options(WindowButtonOptions().Tooltip("Enables the separate Collision Viewer Window."));
// Actor Viewer
path.sidebarName = "Actor Viewer";
AddSidebarEntry("Dev Tools", path.sidebarName, 2);
AddWidget(path, "Popout Actor Viewer", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ActorViewer"))
.WindowName("Actor Viewer")
.Options(WindowButtonOptions().Tooltip("Enables the separate Actor Viewer Window."));
// Display List Viewer
path.sidebarName = "DList Viewer";
AddSidebarEntry("Dev Tools", path.sidebarName, 2);
AddWidget(path, "Popout Display List Viewer", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("DisplayListViewer"))
.WindowName("Display List Viewer")
.Options(WindowButtonOptions().Tooltip("Enables the separate Display List Viewer Window."));
// Value Viewer
path.sidebarName = "Value Viewer";
AddSidebarEntry("Dev Tools", path.sidebarName, 2);
AddWidget(path, "Popout Value Viewer", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ValueViewer"))
.WindowName("Value Viewer")
.Options(WindowButtonOptions().Tooltip("Enables the separate Value Viewer Window."));
// Message Viewer
path.sidebarName = "Message Viewer";
AddSidebarEntry("Dev Tools", path.sidebarName, 2);
AddWidget(path, "Popout Message Viewer", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("MessageViewer"))
.WindowName("Message Viewer")
.Options(WindowButtonOptions().Tooltip("Enables the separate Message Viewer Window."));
// Gfx Debugger
path.sidebarName = "Gfx Debugger";
AddSidebarEntry("Dev Tools", path.sidebarName, 1);
AddWidget(path, "Popout Gfx Debugger", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("GfxDebugger"))
.WindowName("GfxDebuggerWindow")
.Options(WindowButtonOptions().Tooltip("Enables the separate Gfx Debugger Window."));
}
} // namespace SohGui

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,148 @@
#ifdef ENABLE_REMOTE_CONTROL
#include "SohMenu.h"
#include <soh/Notification/Notification.h>
#include <soh/Network/Network.h>
#include "SohGui.hpp"
#include <soh/Network/Sail/Sail.h>
#include <soh/Network/CrowdControl/CrowdControl.h>
namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
using namespace UIWidgets;
void SohMenu::AddMenuNetwork() {
// Add Network Menu
AddMenuEntry("Network", CVAR_SETTING("Menu.NetworkSidebarSection"));
// Sail
WidgetPath path = { "Network", "Sail", SECTION_COLUMN_1 };
AddSidebarEntry("Network", path.sidebarName, 3);
AddWidget(path, "Sail is a networking protocol designed to facilitate remote "
"control of the Ship of Harkinian client. It is intended to "
"be utilized alongside a Sail server, for which we provide a "
"few straightforward implementations on our GitHub. The current "
"implementations available allow integration with Twitch chat "
"and SAMMI Bot, feel free to contribute your own!\n"
"\n"
"Click this button to copy the link to the Sail Github "
"page to your clipboard.", WIDGET_TEXT);
AddWidget(path, ICON_FA_CLIPBOARD "##Sail", WIDGET_BUTTON)
.Callback([](WidgetInfo& info) {
ImGui::SetClipboardText("https://github.com/HarbourMasters/sail");
Notification::Emit({
.message = "Copied to clipboard",
});
})
.Options(ButtonOptions()
.Tooltip("https://github.com/HarbourMasters/sail")
);
AddWidget(path, "Host & Port", WIDGET_CUSTOM)
.CustomFunction([](WidgetInfo& info) {
ImGui::BeginDisabled(Sail::Instance->isEnabled);
ImGui::Text("%s", info.name.c_str());
CVarInputString("##HostSail", CVAR_REMOTE_SAIL("Host"), InputOptions().Color(THEME_COLOR).PlaceholderText("127.0.0.1").DefaultValue("127.0.0.1").Size(ImVec2(ImGui::GetFontSize() * 15, 0)).LabelPosition(LabelPosition::None));
ImGui::SameLine();
ImGui::Text(":");
ImGui::SameLine();
CVarInputInt("##PortSail", CVAR_REMOTE_SAIL("Port"), InputOptions().Color(THEME_COLOR).PlaceholderText("43384").DefaultValue("43384").Size(ImVec2(ImGui::GetFontSize() * 5, 0)).LabelPosition(LabelPosition::None));
ImGui::EndDisabled();
});
AddWidget(path, "Enable##Sail", WIDGET_BUTTON)
.PreFunc([](WidgetInfo& info) {
std::string host = CVarGetString(CVAR_REMOTE_SAIL("Host"), "127.0.0.1");
uint16_t port = CVarGetInteger(CVAR_REMOTE_SAIL("Port"), 43384);
info.options->disabled = !(!SohUtils::IsStringEmpty(host) && port > 1024 && port < 65535);
if (Sail::Instance->isEnabled) {
info.name = "Disable##Sail";
} else {
info.name = "Enable##Sail";
}
})
.Callback([](WidgetInfo& info) {
if (Sail::Instance->isEnabled) {
CVarClear(CVAR_REMOTE_SAIL("Enabled"));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
Sail::Instance->Disable();
} else {
CVarSetInteger(CVAR_REMOTE_SAIL("Enabled"), 1);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
Sail::Instance->Enable();
}
});
AddWidget(path, "Connecting...##Sail", WIDGET_TEXT)
.PreFunc([](WidgetInfo& info) {
info.isHidden = !Sail::Instance->isEnabled;
if (Sail::Instance->isConnected) {
info.name = "Connected##Sail";
} else {
info.name = "Connecting...##Sail";
}
});
path.sidebarName = "Crowd Control";
AddSidebarEntry("Network", path.sidebarName, 3);
path.column = SECTION_COLUMN_1;
AddWidget(path, "Crowd Control is a platform that allows viewers to interact "
"with a streamer's game in real time.\n"
"\n"
"Click the question mark to copy the link to the Crowd Control "
"website to your clipboard.", WIDGET_TEXT);
AddWidget(path, ICON_FA_CLIPBOARD "##CrowdControl", WIDGET_BUTTON)
.Callback([](WidgetInfo& info) {
ImGui::SetClipboardText("https://crowdcontrol.live");
Notification::Emit({
.message = "Copied to clipboard",
});
})
.Options(ButtonOptions()
.Tooltip("https://crowdcontrol.live")
);
AddWidget(path, "Host & Port", WIDGET_CUSTOM)
.CustomFunction([](WidgetInfo& info) {
ImGui::BeginDisabled(CrowdControl::Instance->isEnabled);
ImGui::Text("%s", info.name.c_str());
CVarInputString("##HostCrowdControl", CVAR_REMOTE_CROWD_CONTROL("Host"), InputOptions().Color(THEME_COLOR).PlaceholderText("127.0.0.1").DefaultValue("127.0.0.1").Size(ImVec2(ImGui::GetFontSize() * 15, 0)).LabelPosition(LabelPosition::None));
ImGui::SameLine();
ImGui::Text(":");
ImGui::SameLine();
CVarInputInt("##PortCrowdControl", CVAR_REMOTE_CROWD_CONTROL("Port"), InputOptions().Color(THEME_COLOR).PlaceholderText("43384").DefaultValue("43384").Size(ImVec2(ImGui::GetFontSize() * 5, 0)).LabelPosition(LabelPosition::None));
ImGui::EndDisabled();
});
AddWidget(path, "Enable##CrowdControl", WIDGET_BUTTON)
.PreFunc([](WidgetInfo& info) {
std::string host = CVarGetString(CVAR_REMOTE_CROWD_CONTROL("Host"), "127.0.0.1");
uint16_t port = CVarGetInteger(CVAR_REMOTE_CROWD_CONTROL("Port"), 43384);
info.options->disabled = !(!SohUtils::IsStringEmpty(host) && port > 1024 && port < 65535);
if (CrowdControl::Instance->isEnabled) {
info.name = "Disable##CrowdControl";
} else {
info.name = "Enable##CrowdControl";
}
})
.Callback([](WidgetInfo& info) {
if (CrowdControl::Instance->isEnabled) {
CVarClear(CVAR_REMOTE_CROWD_CONTROL("Enabled"));
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
CrowdControl::Instance->Disable();
} else {
CVarSetInteger(CVAR_REMOTE_CROWD_CONTROL("Enabled"), 1);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
CrowdControl::Instance->Enable();
}
});
AddWidget(path, "Connecting...##CrowdControl", WIDGET_TEXT)
.PreFunc([](WidgetInfo& info) {
info.isHidden = !CrowdControl::Instance->isEnabled;
if (CrowdControl::Instance->isConnected) {
info.name = "Connected##CrowdControl";
} else {
info.name = "Connecting...##CrowdControl";
}
});
}
} // namespace SohGui
#endif

View file

@ -0,0 +1,133 @@
#include "SohMenu.h"
#include <macros.h>
namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
using namespace UIWidgets;
void SohMenu::AddMenuRandomizer() {
// Add Randomizer Menu
AddMenuEntry("Randomizer", CVAR_SETTING("Menu.RandomizerSidebarSection"));
// Seed Settings
WidgetPath path = { "Randomizer", "Seed Settings", SECTION_COLUMN_1 };
AddSidebarEntry("Randomizer", path.sidebarName, 1);
AddWidget(path, "Popout Randomizer Settings Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("RandomizerSettings"))
.WindowName("Randomizer Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Randomizer Settings Window."));
path.sidebarName = "Enhancements";
AddSidebarEntry("Randomizer", path.sidebarName, 1);
AddWidget(path, "Rando-Relevant Navi Hints", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("RandoRelevantNavi"))
.Options(CheckboxOptions().Tooltip(
"Replace Navi's overworld quest hints with rando-related gameplay hints."
).DefaultValue(true));
AddWidget(path, "Random Rupee Names", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("RandomizeRupeeNames"))
.Options(CheckboxOptions().Tooltip(
"When obtaining Rupees, randomize what the Rupee is called in the textbox."
).DefaultValue(true));
AddWidget(path, "Use Custom Key Models", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("CustomKeyModels"))
.Options(CheckboxOptions().Tooltip(
"Use Custom graphics for Dungeon Keys, Big and Small, so that they can be easily told apart."
).DefaultValue(true));
AddWidget(path, "Compass Colors Match Dungeon", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("MatchCompassColors"))
.PreFunc([](WidgetInfo& info) {
info.options->disabled = !(
OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).IsNot(RO_DUNGEON_ITEM_LOC_STARTWITH) &&
OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).IsNot(RO_DUNGEON_ITEM_LOC_VANILLA) &&
OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_MAPANDCOMPASS).IsNot(RO_DUNGEON_ITEM_LOC_OWN_DUNGEON)
);
info.options->disabledTooltip = "This setting is disabled because a savefile is loaded without "
"the compass shuffle settings set to Any Dungeon, Overworld, or Anywhere.";
})
.Options(CheckboxOptions().Tooltip(
"Matches the color of compasses to the dungeon they belong to. "
"This helps identify compasses from afar and adds a little bit of flair.\n\nThis only "
"applies to seeds with compasses shuffled to \"Any Dungeon\", \"Overworld\", or \"Anywhere\"."
).DefaultValue(true));
AddWidget(path, "Quest Item Fanfares", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("QuestItemFanfares"))
.Options(CheckboxOptions().Tooltip(
"Play unique fanfares when obtaining quest items (medallions/stones/songs). Note that these "
"fanfares can be longer than usual."
));
AddWidget(path, "Mysterious Shuffled Items", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"))
.Options(CheckboxOptions().Tooltip(
"Displays a \"Mystery Item\" model in place of any freestanding/GS/shop items that were shuffled, "
"and replaces item names for them and scrubs and merchants, regardless of hint settings, "
"so you never know what you're getting."
));
AddWidget(path, "Simpler Boss Soul Models", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("SimplerBossSoulModels"))
.Options(CheckboxOptions().Tooltip(
"When shuffling boss souls, they'll appear as a simpler model instead of showing the boss' models."
"This might make boss souls more distinguishable from a distance, and can help with performance."
));
AddWidget(path, "Skip Get Item Animations", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_RANDOMIZER_ENHANCEMENT("TimeSavers.SkipGetItemAnimation"))
.Options(ComboboxOptions().ComboMap(skipGetItemAnimationOptions).DefaultIndex(SGIA_JUNK));
// Plandomizer
path.sidebarName = "Plandomizer";
AddSidebarEntry("Randomizer", path.sidebarName, 1);
AddWidget(path, "Popout Plandomizer Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("PlandomizerEditor"))
.WindowName("Plandomizer Editor")
.Options(WindowButtonOptions().Tooltip("Enables the separate Randomizer Settings Window."));
// Item Tracker
path.sidebarName = "Item Tracker";
AddSidebarEntry("Randomizer", path.sidebarName, 1);
AddWidget(path, "Item Tracker", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Item Tracker", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ItemTracker"))
.WindowName("Item Tracker")
.Options(WindowButtonOptions().Tooltip("Toggles the Item Tracker.").EmbedWindow(false));
AddWidget(path, "Item Tracker Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Item Tracker Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ItemTrackerSettings"))
.WindowName("Item Tracker Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Item Tracker Settings Window."));
// Entrance Tracker
path.sidebarName = "Entrance Tracker";
AddSidebarEntry("Randomizer", path.sidebarName, 1);
AddWidget(path, "Entrance Tracker", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Entrance Tracker", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("EntranceTracker"))
.WindowName("Entrance Tracker")
.Options(WindowButtonOptions().Tooltip("Toggles the Entrance Tracker.").EmbedWindow(false));
AddWidget(path, "Entrance Tracker Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Entrance Tracker Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("EntranceTrackerSettings"))
.WindowName("Entrance Tracker Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Entrance Tracker Settings Window."));
// Check Tracker
path.sidebarName = "Check Tracker";
AddSidebarEntry("Randomizer", path.sidebarName, 1);
AddWidget(path, "Check Tracker", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Check Tracker", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("CheckTracker"))
.WindowName("Check Tracker")
.Options(WindowButtonOptions().Tooltip("Toggles the Check Tracker.").EmbedWindow(false));
AddWidget(path, "Check Tracker Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Check Tracker Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("CheckTrackerSettings"))
.WindowName("Check Tracker Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Check Tracker Settings Window."));
}
} // namespace SohGui

View file

@ -0,0 +1,373 @@
#include "SohMenu.h"
#include "soh/Notification/Notification.h"
#include <soh/GameVersions.h>
#include "soh/ResourceManagerHelpers.h"
#include "UIWidgets.hpp"
#include <spdlog/fmt/fmt.h>
extern "C" {
#include "include/z64audio.h"
#include "variables.h"
}
namespace SohGui {
extern std::shared_ptr<SohMenu> mSohMenu;
using namespace UIWidgets;
static std::unordered_map<int32_t, const char*> languages = {{ LANGUAGE_ENG, "English" }, { LANGUAGE_GER, "German" }, { LANGUAGE_FRA, "French" }};
const char* GetGameVersionString(uint32_t index) {
uint32_t gameVersion = ResourceMgr_GetGameVersion(index);
switch (gameVersion) {
case OOT_NTSC_US_10:
return "NTSC-U 1.0";
case OOT_NTSC_US_11:
return "NTSC-U 1.1";
case OOT_NTSC_US_12:
return "NTSC-U 1.2";
case OOT_PAL_10:
return "PAL 1.0";
case OOT_PAL_11:
return "PAL 1.1";
case OOT_PAL_GC:
return "PAL GC";
case OOT_PAL_MQ:
return "PAL MQ";
case OOT_PAL_GC_DBG1:
case OOT_PAL_GC_DBG2:
return "PAL GC-D";
case OOT_PAL_GC_MQ_DBG:
return "PAL MQ-D";
case OOT_IQUE_CN:
return "IQUE CN";
case OOT_IQUE_TW:
return "IQUE TW";
default:
return "UNKNOWN";
}
}
void SohMenu::AddMenuSettings() {
// Add Settings Menu
AddMenuEntry("Settings", CVAR_SETTING("Menu.SettingsSidebarSection"));
AddSidebarEntry("Settings", "General", 3);
WidgetPath path = { "Settings", "General", SECTION_COLUMN_1 };
// General - Settings
AddWidget(path, "Menu Theme", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("Menu.Theme"))
.Options(ComboboxOptions()
.Tooltip("Changes the Theme of the Menu Widgets.")
.ComboMap(menuThemeOptions)
.DefaultIndex(Colors::LightBlue));
#if not defined(__SWITCH__) and not defined(__WIIU__)
AddWidget(path, "Menu Controller Navigation", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_IMGUI_CONTROLLER_NAV)
.Options(CheckboxOptions().Tooltip(
"Allows controller navigation of the 2Ship menu (Settings, Enhancements,...)\nCAUTION: "
"This will disable game inputs while the menu is visible.\n\nD-pad to move between "
"items, A to select, B to move up in scope."));
AddWidget(path, "Cursor Always Visible", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("CursorVisibility"))
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->SetForceCursorVisibility(
CVarGetInteger(CVAR_SETTING("CursorVisibility"), 0));
})
.Options(CheckboxOptions().Tooltip("Makes the cursor always visible, even in full screen."));
#endif
AddWidget(path, "Search In Sidebar", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Menu.SidebarSearch"))
.Callback([](WidgetInfo& info) {
if (CVarGetInteger(CVAR_SETTING("Menu.SidebarSearch"), 0)) {
mSohMenu->InsertSidebarSearch();
} else {
mSohMenu->RemoveSidebarSearch();
}
})
.Options(CheckboxOptions().Tooltip(
"Displays the Search menu as a sidebar entry in Settings instead of in the header."));
AddWidget(path, "Search Input Autofocus", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Menu.SearchAutofocus"))
.Options(CheckboxOptions().Tooltip(
"Search input box gets autofocus when visible. Does not affect using other widgets."));
AddWidget(path, "Alt Assets Tab hotkey", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Mods.AlternateAssetsHotkey"))
.Options(
CheckboxOptions().Tooltip("Allows pressing the Tab key to toggle alternate assets").DefaultValue(true));
AddWidget(path, "Open App Files Folder", WIDGET_BUTTON)
.Callback([](WidgetInfo& info) {
std::string filesPath = Ship::Context::GetInstance()->GetAppDirectoryPath();
SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str());
})
.Options(ButtonOptions().Tooltip("Opens the folder that contains the save and mods folders, etc."));
AddWidget(path, "Languages", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Translate Title Screen", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("TitleScreenTranslation"));
AddWidget(path, "Menu Language", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("Languages"))
.Options(ComboboxOptions().LabelPosition(LabelPosition::Far).ComponentAlignment(ComponentAlignment::Right).ComboMap(languages).DefaultIndex(LANGUAGE_ENG));
AddWidget(path, "Accessibility", WIDGET_SEPARATOR_TEXT);
#if defined(_WIN32) || defined(__APPLE__)
AddWidget(path, "Text to Speech", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("A11yTTS"))
.Options(CheckboxOptions().Tooltip("Enables text to speech for in game dialog"));
#endif
AddWidget(path, "Disable Idle Camera Re-Centering", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("A11yDisableIdleCam"))
.Options(CheckboxOptions().Tooltip("Disables the automatic re-centering of the camera when idle."));
// General - About
path.column = SECTION_COLUMN_2;
AddWidget(path, "About", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Ship Of Harkinian", WIDGET_TEXT);
if (gGitCommitTag[0] != 0) {
AddWidget(path, gBuildVersion, WIDGET_TEXT);
} else {
AddWidget(path, ("Branch: " + std::string(gGitBranch)), WIDGET_TEXT);
AddWidget(path, ("Commit: " + std::string(gGitCommitHash)), WIDGET_TEXT);
}
for (uint32_t i = 0; i < ResourceMgr_GetNumGameVersions(); i++) {
AddWidget(path, GetGameVersionString(i), WIDGET_TEXT);
}
// Audio Settings
path.sidebarName = "Audio";
path.column = SECTION_COLUMN_1;
AddSidebarEntry("Settings", "Audio", 3);
AddWidget(path, "Master Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.Master"))
.Options(IntSliderOptions()
.Min(0)
.Max(100)
.DefaultValue(40)
.ShowButtons(true)
.Format(""));
AddWidget(path, "Main Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.MainMusic"))
.Options(IntSliderOptions()
.Min(0)
.Max(100)
.DefaultValue(100)
.ShowButtons(true)
.Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_BGM_MAIN, ((float)CVarGetInteger(CVAR_SETTING("Volume.MainMusic"), 100) / 100.0f));
});
AddWidget(path, "Sub Music Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.SubMusic"))
.Options(IntSliderOptions()
.Min(0)
.Max(100)
.DefaultValue(100)
.ShowButtons(true)
.Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_BGM_SUB, ((float)CVarGetInteger(CVAR_SETTING("Volume.SubMusic"), 100) / 100.0f));
});
AddWidget(path, "Fanfare Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.Fanfare"))
.Options(IntSliderOptions()
.Min(0)
.Max(100)
.DefaultValue(100)
.ShowButtons(true)
.Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_FANFARE, ((float)CVarGetInteger(CVAR_SETTING("Volume.Fanfare"), 100) / 100.0f));
});
AddWidget(path, "Sound Effects Volume: %d %%", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("Volume.SFX"))
.Options(IntSliderOptions()
.Min(0)
.Max(100)
.DefaultValue(100)
.ShowButtons(true)
.Format(""))
.Callback([](WidgetInfo& info) {
Audio_SetGameVolume(SEQ_PLAYER_SFX, ((float)CVarGetInteger(CVAR_SETTING("Volume.SFX"), 100) / 100.0f));
});
AddWidget(path, "Audio API (Needs reload)", WIDGET_AUDIO_BACKEND);
// Graphics Settings
static int32_t maxFps;
const char* tooltip = "";
if (Ship::Context::GetInstance()->GetWindow()->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) {
maxFps = 360;
tooltip = "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is "
"purely visual and does not impact game logic, execution of glitches etc.\n\nA higher target "
"FPS than your monitor's refresh rate will waste resources, and might give a worse result.";
} else {
maxFps = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
tooltip = "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is "
"purely visual and does not impact game logic, execution of glitches etc.";
}
path.sidebarName = "Graphics";
AddSidebarEntry("Settings", "Graphics", 3);
AddWidget(path, "Toggle Fullscreen", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SETTING("Fullscreen"))
.Callback([](WidgetInfo& info) { Ship::Context::GetInstance()->GetWindow()->ToggleFullscreen(); })
.Options(CheckboxOptions().Tooltip("Toggles Fullscreen On/Off."));
AddWidget(path, "Internal Resolution", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_INTERNAL_RESOLUTION)
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(
CVarGetFloat(CVAR_INTERNAL_RESOLUTION, 1));
})
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->disabledMap.at(DISABLE_FOR_ADVANCED_RESOLUTION_ON).active &&
mSohMenu->disabledMap.at(DISABLE_FOR_VERTICAL_RES_TOGGLE_ON).active) {
info.activeDisables.push_back(DISABLE_FOR_ADVANCED_RESOLUTION_ON);
info.activeDisables.push_back(DISABLE_FOR_VERTICAL_RES_TOGGLE_ON);
} else if (mSohMenu->disabledMap.at(DISABLE_FOR_LOW_RES_MODE_ON).active) {
info.activeDisables.push_back(DISABLE_FOR_LOW_RES_MODE_ON);
}
})
.Options(
FloatSliderOptions()
.Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective "
"form of anti-aliasing.")
.ShowButtons(false)
.IsPercentage()
.Min(0.5f)
.Max(2.0f));
#ifndef __WIIU__
AddWidget(path, "Anti-aliasing (MSAA)", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_MSAA_VALUE)
.Callback([](WidgetInfo& info) {
Ship::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger(CVAR_MSAA_VALUE, 1));
})
.Options(
IntSliderOptions()
.Tooltip("Activates MSAA (multi-sample anti-aliasing) from 2x up to 8x, to smooth the edges of "
"rendered geometry.\n"
"Higher sample count will result in smoother edges on models, but may reduce performance.")
.Min(1)
.Max(8)
.DefaultValue(1));
#endif
auto fps = CVarGetInteger(CVAR_SETTING("InterpolationFPS"), 20);
const char* fpsFormat = fps == 20 ? "Original (%d)" : "%d";
AddWidget(path, "Current FPS", WIDGET_CVAR_SLIDER_INT)
.CVar(CVAR_SETTING("InterpolationFPS"))
.Callback([](WidgetInfo& info) {
auto options = std::static_pointer_cast<IntSliderOptions>(info.options);
int32_t defaultValue = options->defaultValue;
if (CVarGetInteger(info.cVar, defaultValue) == defaultValue) {
options->format = "Original (%d)";
}
else {
options->format = "%d";
}
})
.PreFunc([](WidgetInfo& info) {
if (mSohMenu->disabledMap.at(DISABLE_FOR_MATCH_REFRESH_RATE_ON).active)
info.activeDisables.push_back(DISABLE_FOR_MATCH_REFRESH_RATE_ON);
})
.Options(IntSliderOptions().Tooltip(tooltip).Min(20).Max(maxFps).DefaultValue(20).Format(fpsFormat));
AddWidget(path, "Match Refresh Rate", WIDGET_BUTTON)
.Callback([](WidgetInfo& info) {
int hz = Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
if (hz >= 20 && hz <= 360) {
CVarSetInteger(CVAR_SETTING("InterpolationFPS"), hz);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
})
.PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NOT_DIRECTX).active; })
.Options(ButtonOptions().Tooltip("Matches interpolation value to the current game's window refresh rate."));
AddWidget(path, "Match Refresh Rate", WIDGET_CVAR_CHECKBOX)
.CVar("gMatchRefreshRate")
.PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_DIRECTX).active; })
.Options(CheckboxOptions().Tooltip("Matches interpolation value to the current game's window refresh rate."));
AddWidget(path, "Renderer API (Needs reload)", WIDGET_VIDEO_BACKEND);
AddWidget(path, "Enable Vsync", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_VSYNC_ENABLED)
.PreFunc([](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NO_VSYNC).active; })
.Options(CheckboxOptions().Tooltip("Enables Vsync."));
AddWidget(path, "Windowed Fullscreen", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_SDL_WINDOWED_FULLSCREEN)
.PreFunc([](WidgetInfo& info) {
info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NO_WINDOWED_FULLSCREEN).active;
})
.Options(CheckboxOptions().Tooltip("Enables Windowed Fullscreen Mode."));
AddWidget(path, "Allow multi-windows", WIDGET_CVAR_CHECKBOX)
.CVar(CVAR_ENABLE_MULTI_VIEWPORTS)
.PreFunc(
[](WidgetInfo& info) { info.isHidden = mSohMenu->disabledMap.at(DISABLE_FOR_NO_MULTI_VIEWPORT).active; })
.Options(CheckboxOptions().Tooltip(
"Allows multiple windows to be opened at once. Requires a reload to take effect."));
AddWidget(path, "Texture Filter (Needs reload)", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_TEXTURE_FILTER)
.Options(ComboboxOptions().Tooltip("Sets the applied Texture Filtering.").ComboMap(textureFilteringMap));
// Controls
path.sidebarName = "Controls";
AddSidebarEntry("Settings", "Controls", 2);
AddWidget(path, "Controller Bindings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Bindings Window", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("ControllerConfiguration"))
.WindowName("Configure Controller")
.Options(WindowButtonOptions().Tooltip("Enables the separate Bindings Window."));
path.column = SECTION_COLUMN_2;
AddWidget(path, "Input Viewer", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Toggle Input Viewer", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("InputViewer"))
.WindowName("Input Viewer")
.Options(WindowButtonOptions().Tooltip("Toggles the Input Viewer.").EmbedWindow(false));
AddWidget(path, "Input Viewer Settings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Input Viewer Settings", WIDGET_WINDOW_BUTTON)
.CVar(CVAR_WINDOW("InputViewerSettings"))
.WindowName("Input Viewer Settings")
.Options(WindowButtonOptions().Tooltip("Enables the separate Input Viewer Settings Window."));
// Notifications
path.sidebarName = "Notifications";
path.column = SECTION_COLUMN_1;
AddSidebarEntry("Settings", "Notifications", 3);
AddWidget(path, "Position", WIDGET_CVAR_COMBOBOX)
.CVar(CVAR_SETTING("Notifications.Position"))
.Options(ComboboxOptions()
.Tooltip("Which corner of the screen notifications appear in.")
.ComboMap(notificationPosition)
.DefaultIndex(3));
AddWidget(path, "Duration: %.0f seconds", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_SETTING("Notifications.Duration"))
.Options(FloatSliderOptions()
.Tooltip("How long notifications are displayed for.")
.Format("%.1f")
.Step(0.1f)
.Min(3.0f)
.Max(30.0f)
.DefaultValue(10.0f));
AddWidget(path, "Background Opacity: %.0f%%", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_SETTING("Notifications.BgOpacity"))
.Options(FloatSliderOptions()
.Tooltip("How opaque the background of notifications is.")
.DefaultValue(0.5f)
.IsPercentage());
AddWidget(path, "Size %.1f", WIDGET_CVAR_SLIDER_FLOAT)
.CVar(CVAR_SETTING("Notifications.Size"))
.Options(FloatSliderOptions()
.Tooltip("How large notifications are.")
.Format("%.1f")
.Step(0.1f)
.Min(1.0f)
.Max(5.0f)
.DefaultValue(1.8f));
AddWidget(path, "Test Notification", WIDGET_BUTTON)
.Callback([](WidgetInfo& info) {
Notification::Emit({
.itemIcon = "__OTR__textures/icon_item_24_static/gQuestIconGoldSkulltulaTex",
.prefix = "This",
.message = "is a",
.suffix = "test.",
});
})
.Options(ButtonOptions().Tooltip("Displays a test notification."));
}
} // namespace SohGui

View file

@ -5,6 +5,7 @@
#include <libultraship/bridge.h>
#include <libultraship/libultraship.h>
#include "UIWidgets.hpp"
#include "SohGui.hpp"
#include "soh/OTRGlobals.h"
#include "z64.h"
@ -29,6 +30,7 @@ void SohModalWindow::Draw() {
}
void SohModalWindow::DrawElement() {
ImGui::PushFont(OTRGlobals::Instance->fontMonoLarger);
if (modals.size() > 0) {
SohModal curModal = modals.at(0);
if (!ImGui::IsPopupOpen(curModal.title_.c_str())) {
@ -36,6 +38,7 @@ void SohModalWindow::DrawElement() {
}
if (ImGui::BeginPopupModal(curModal.title_.c_str(), NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) {
ImGui::Text("%s", curModal.message_.c_str());
UIWidgets::PushStyleButton(THEME_COLOR);
if (ImGui::Button(curModal.button1_.c_str())) {
if (curModal.button1callback_ != nullptr) {
curModal.button1callback_();
@ -43,8 +46,10 @@ void SohModalWindow::DrawElement() {
ImGui::CloseCurrentPopup();
modals.erase(modals.begin());
}
ImGui::SameLine();
UIWidgets::PopStyleButton();
if (curModal.button2_ != "") {
ImGui::SameLine();
UIWidgets::PushStyleButton(THEME_COLOR);
if (ImGui::Button(curModal.button2_.c_str())) {
if (curModal.button2callback_ != nullptr) {
curModal.button2callback_();
@ -52,10 +57,12 @@ void SohModalWindow::DrawElement() {
ImGui::CloseCurrentPopup();
modals.erase(modals.begin());
}
UIWidgets::PopStyleButton();
}
}
ImGui::EndPopup();
}
ImGui::PopFont();
}
void SohModalWindow::RegisterPopup(std::string title, std::string message, std::string button1, std::string button2, std::function<void()> button1callback, std::function<void()> button2callback) {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ namespace SOH {
std::vector<Migration> version3Migrations = {
{ MigrationAction::Rename, "gSwitchAge", "gGeneral.SwitchAge" },
{ MigrationAction::Rename, "gFrameAdvance", "gGeneral.FrameAdvance" },
{ MigrationAction::Rename, "gFrameAdvance", "gDeveloperTools.FrameAdvanceTick" },
{ MigrationAction::Rename, "gRandoGenerating", "gGeneral.RandoGenerating" },
{ MigrationAction::Rename, "gNewSeedGenerated", "gGeneral.NewSeedGenerated" },
{ MigrationAction::Rename, "gOnFileSelectNameEntry", "gGeneral.OnFileSelectNameEntry" },
@ -42,14 +42,12 @@ namespace SOH {
{ MigrationAction::Rename, "gCheckTrackerSettingsEnabled", "gOpenWindows.CheckTrackerSettings" },
{ MigrationAction::Rename, "gCollisionViewerEnabled", "gOpenWindows.CollisionViewer" },
{ MigrationAction::Rename, "gCosmeticsEditorEnabled", "gOpenWindows.CosmeticsEditor" },
{ MigrationAction::Rename, "gDLViewerEnabled", "gOpenWindows.DLViewer" },
{ MigrationAction::Rename, "gDLViewerEnabled", "gOpenWindows.DisplayListViewer" },
{ MigrationAction::Rename, "gEntranceTrackerEnabled", "gOpenWindows.EntranceTracker" },
{ MigrationAction::Rename, "gGameplayStatsEnabled", "gOpenWindows.GameplayStats" },
{ MigrationAction::Rename, "gItemTrackerEnabled", "gOpenWindows.ItemTracker" },
{ MigrationAction::Rename, "gItemTrackerSettingsEnabled", "gOpenWindows.ItemTrackerSettings" },
{ MigrationAction::Rename, "gMessageViewerEnabled", "gOpenWindows.MessageViewer" },
{ MigrationAction::Rename, "gOpenWindows.InputViewer", "gOpenWindows.InputViewer" },
{ MigrationAction::Rename, "gOpenWindows.InputViewerSettings", "gOpenWindows.InputViewerSettings" },
{ MigrationAction::Rename, "gRandomizerSettingsEnabled", "gOpenWindows.RandomizerSettings" },
{ MigrationAction::Rename, "gSaveEditorEnabled", "gOpenWindows.SaveEditor" },
{ MigrationAction::Rename, "gValueViewer.WindowOpen", "gOpenWindows.ValueViewer" },

View file

@ -7,11 +7,11 @@
#define CVAR_SETTING(var) CVAR_PREFIX_SETTING "." var
#define CVAR_WINDOW(var) CVAR_PREFIX_WINDOW "." var
#define CVAR_TRACKER(var) CVAR_PREFIX_TRACKER "." var
#define CVAR_TRACKER_ITEM(var) CVAR_TRACKER(".ItemTracker." var)
#define CVAR_TRACKER_CHECK(var) CVAR_TRACKER(".CheckTracker." var)
#define CVAR_TRACKER_ENTRANCE(var) CVAR_TRACKER(".EntranceTracker." var)
#define CVAR_TRACKER_ITEM(var) CVAR_TRACKER("ItemTracker." var)
#define CVAR_TRACKER_CHECK(var) CVAR_TRACKER("CheckTracker." var)
#define CVAR_TRACKER_ENTRANCE(var) CVAR_TRACKER("EntranceTracker." var)
#define CVAR_DEVELOPER_TOOLS(var) CVAR_PREFIX_DEVELOPER_TOOLS "." var
#define CVAR_GENERAL(var) CVAR_PREFIX_GENERAL "." var
#define CVAR_REMOTE(var) CVAR_PREFIX_REMOTE "." var
#define CVAR_REMOTE_CROWD_CONTROL(var) CVAR_REMOTE(".CrowdControl." var)
#define CVAR_REMOTE_SAIL(var) CVAR_REMOTE(".Sail." var)
#define CVAR_REMOTE_CROWD_CONTROL(var) CVAR_REMOTE("CrowdControl." var)
#define CVAR_REMOTE_SAIL(var) CVAR_REMOTE("Sail." var)

View file

@ -95,7 +95,7 @@ void Audio_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* attrs) {
vel = 0.0f > vel ? 0.0f : vel;
vel = 1.0f < vel ? 1.0f : vel;
float master_vol = (float)CVarGetInteger(CVAR_SETTING("Volume.Master"), 100) / 100.0f;
float master_vol = (float)CVarGetInteger(CVAR_SETTING("Volume.Master"), 40) / 100.0f;
sub->targetVolLeft = (s32)((vel * volLeft) * (0x1000 - 0.001f)) * master_vol;
sub->targetVolRight = (s32)((vel * volRight) * (0x1000 - 0.001f)) * master_vol;

View file

@ -18,10 +18,11 @@ s32 FrameAdvance_Update(FrameAdvanceContext* frameAdvCtx, Input* input) {
frameAdvCtx->enabled = !frameAdvCtx->enabled;
}
if (!frameAdvCtx->enabled || CVarGetInteger(CVAR_GENERAL("FrameAdvance"), 0) || (CHECK_BTN_ALL(input->cur.button, BTN_Z) &&
if (!frameAdvCtx->enabled || CVarGetInteger(CVAR_DEVELOPER_TOOLS("FrameAdvanceTick"), 0) ||
(CHECK_BTN_ALL(input->cur.button, BTN_Z) &&
(CHECK_BTN_ALL(input->press.button, BTN_R) ||
(CHECK_BTN_ALL(input->cur.button, BTN_R) && (++frameAdvCtx->timer >= 9))))) {
CVarClear(CVAR_GENERAL("FrameAdvance"));
CVarClear(CVAR_DEVELOPER_TOOLS("FrameAdvanceTick"));
frameAdvCtx->timer = 0;
return true;
}