Files
Shiip-of-Hakinian-Espanol/soh/soh/SohGui/SohMenu.cpp
nickpons666 5656d48efe feat: add translation system with runtime reload and 636 new Spanish translations
- Add LanguageManager::ReloadTranslations() and RequestMenuRebuild()
- Add SohMenu::RequestRebuild() and RebuildMenu() for in-place translation updates
- Add originalName field to WidgetInfo for tracking English source strings
- Add 636 new Spanish translations (1084 -> 1720 keys)
  - Menu tooltips and labels (Enhancements, Network, DevTools)
  - Randomizer item tracker (boss souls, jabber nuts, keys, ocarina buttons)
  - Randomizer check tracker (color pickers, labels, tooltips)
  - Randomizer entrance tracker (entrance names, group names, tooltips)
  - Plandomizer (area names, buttons, labels)
- UI Translation dropdown now triggers menu rebuild on language change
2026-04-04 23:34:10 -06:00

209 lines
8.0 KiB
C++

#include "SohMenu.h"
#include "LanguageManager.h"
#include <ship/window/gui/GuiMenuBar.h>
#include <ship/window/gui/GuiElement.h>
#include <ship/utils/StringHelper.h>
#include <spdlog/fmt/fmt.h>
extern "C" {
extern PlayState* gPlayState;
}
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());
std::string translatedSidebar = LanguageManager::Instance().GetString(sidebarName);
menuEntries.at(sectionName).sidebars.emplace(sidebarName, SidebarEntry{ .columnCount = columnCount, .translatedName = translatedSidebar });
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);
std::string translatedName = LanguageManager::Instance().GetString(widgetName);
entry.columnWidgets.at(column).push_back({ .name = translatedName, .originalName = 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_CVAR_BTN_SELECTOR:
widget.options = std::make_shared<BtnSelectorOptions>();
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_CVAR_COLOR_PICKER:
case WIDGET_COLOR_PICKER:
widget.options = std::make_shared<ColorPickerOptions>();
break;
case WIDGET_SEPARATOR_TEXT:
case WIDGET_TEXT:
widget.options = std::make_shared<TextOptions>();
break;
case WIDGET_SEARCH:
case WIDGET_SEPARATOR:
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::AddMenuElements() {
AddMenuSettings();
AddMenuEnhancements();
AddMenuRandomizer();
AddMenuNetwork();
AddMenuDevTools();
if (CVarGetInteger(CVAR_SETTING("Menu.SidebarSearch"), 0)) {
InsertSidebarSearch();
}
for (auto& initFunc : MenuInit::GetInitFuncs()) {
initFunc();
}
mMenuElementsInitialized = true;
}
void SohMenu::InitElement() {
Ship::Menu::InitElement();
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("MatchRefreshRate"), 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(CVAR_DEVELOPER_TOOLS("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() {
if (mNeedsRebuild) {
RebuildMenu();
}
if (mMenuElementsInitialized) {
Ship::Menu::DrawElement();
}
}
void SohMenu::RequestRebuild() {
mNeedsRebuild = true;
}
void SohMenu::RebuildMenu() {
for (auto& [sectionName, section] : menuEntries) {
for (auto& [sidebarName, sidebar] : section.sidebars) {
for (auto& column : sidebar.columnWidgets) {
for (auto& widget : column) {
if (!widget.originalName.empty()) {
widget.name = LanguageManager::Instance().GetString(widget.originalName);
}
}
}
}
}
mNeedsRebuild = false;
}
} // namespace SohGui