mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-04-23 08:14:31 +00:00
Language System Basis (#6172)
Introduces the basis for a language system to allow the UI to be translated to any language and/or have the text changed by mods. A lot of things would require more work but, for a proof of concept, this PR makes all randomizer trick names & descriptions translatable (currently not re-loadable at runtime as that would require deeper changes and this is already merge conflict hell every time a trick is touched). The system works by passing it a "translation path" which is resolved in the .json including object indentation. If the resulting json object is a list of strings, instead of a string, they get concatenated (purely for organization/QoL).
This commit is contained in:
parent
3228843886
commit
e0a1b23525
1011
soh/assets/custom/lang/en_US.json
Normal file
1011
soh/assets/custom/lang/en_US.json
Normal file
File diff suppressed because it is too large
Load diff
143
soh/soh/Enhancements/Lang/Lang.cpp
Normal file
143
soh/soh/Enhancements/Lang/Lang.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#include "Lang.h"
|
||||
|
||||
#include "soh/SohGui/MenuTypes.h"
|
||||
#include "soh/SohGui/SohGui.hpp"
|
||||
#include "soh/SohGui/SohMenu.h"
|
||||
#include "soh/util.h"
|
||||
|
||||
#include "ship/Context.h"
|
||||
#include "ship/resource/File.h"
|
||||
#include "ship/resource/ResourceManager.h"
|
||||
#include "ship/resource/type/Json.h"
|
||||
#include "ship/utils/StringHelper.h"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace SohGui {
|
||||
extern std::shared_ptr<SohMenu> mSohMenu;
|
||||
}
|
||||
|
||||
static bool initialized = false;
|
||||
static std::map<std::string, nlohmann::json> langs;
|
||||
|
||||
#define LANGUAGE_CVAR CVAR_SETTING("Language")
|
||||
#define DEFAULT_LANGUAGE "en_US"
|
||||
|
||||
std::string Lang::Translate(const char* path) {
|
||||
if (!initialized) {
|
||||
SPDLOG_ERROR("Tried to obtain a translation before the translation data is initialized");
|
||||
assert(false);
|
||||
return "ERROR: Language data not initialized yet";
|
||||
}
|
||||
|
||||
std::string currentLang = CVarGetString(LANGUAGE_CVAR, DEFAULT_LANGUAGE);
|
||||
|
||||
if (!langs.contains(currentLang)) {
|
||||
SPDLOG_WARN("Current language ({}) doesn't exist, trying to fall back to default language ({})",
|
||||
currentLang.c_str(), DEFAULT_LANGUAGE);
|
||||
|
||||
currentLang = DEFAULT_LANGUAGE;
|
||||
|
||||
if (!langs.contains(currentLang)) {
|
||||
SPDLOG_ERROR("Default language ({}) doesn't exist", DEFAULT_LANGUAGE);
|
||||
assert(false);
|
||||
return "ERROR: Language data not found";
|
||||
}
|
||||
|
||||
CVarSetString(LANGUAGE_CVAR, DEFAULT_LANGUAGE);
|
||||
SPDLOG_WARN("Fallback to default language ({}) was succesful", DEFAULT_LANGUAGE);
|
||||
}
|
||||
|
||||
nlohmann::json currentLangData = langs[currentLang];
|
||||
|
||||
std::vector<std::string> segments = SohUtils::StringSplit(std::string(path), ".");
|
||||
|
||||
std::string lastSegment = segments[segments.size() - 1];
|
||||
|
||||
segments.pop_back();
|
||||
|
||||
for (const auto& segment : segments) {
|
||||
if (!currentLangData.contains(segment)) {
|
||||
SPDLOG_WARN("Current language ({}) doesn't have data for the requested path ({})", currentLang.c_str(),
|
||||
path);
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
currentLangData = currentLangData[segment];
|
||||
}
|
||||
|
||||
if (!currentLangData.contains(lastSegment)) {
|
||||
SPDLOG_WARN("Current language ({}) doesn't have data for the requested path ({})", currentLang.c_str(), path);
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
if (currentLangData[lastSegment].is_string()) {
|
||||
return currentLangData[lastSegment].get<std::string>();
|
||||
}
|
||||
|
||||
if (currentLangData[lastSegment].is_array()) {
|
||||
std::string translatedString = "";
|
||||
|
||||
for (const auto& item : currentLangData[lastSegment]) {
|
||||
if (!item.is_string()) {
|
||||
SPDLOG_WARN("Current language ({}) has an array with a non-string at the requested path ({})",
|
||||
currentLang.c_str(), path);
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
translatedString += item.get<std::string>();
|
||||
}
|
||||
|
||||
return translatedString;
|
||||
}
|
||||
|
||||
SPDLOG_WARN("Current language ({}) doesn't have either a string or an array at the requested path ({})",
|
||||
currentLang.c_str(), path);
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
void Lang::LoadLangs() {
|
||||
auto initData = std::make_shared<Ship::ResourceInitData>();
|
||||
initData->Format = RESOURCE_FORMAT_BINARY;
|
||||
initData->Type = static_cast<uint32_t>(Ship::ResourceType::Json);
|
||||
initData->ResourceVersion = 0;
|
||||
const static std::string folder = "lang/*";
|
||||
auto langFiles = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->ListFiles(folder);
|
||||
size_t start = std::string(folder).size() - 1;
|
||||
for (size_t i = 0; i < langFiles->size(); i++) {
|
||||
std::string filePath = langFiles->at(i);
|
||||
auto json = std::static_pointer_cast<Ship::Json>(
|
||||
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(filePath, true, initData));
|
||||
|
||||
std::string fileName = filePath.substr(start, filePath.size() - start - 5); // 5 for length of ".json"
|
||||
langs.insert_or_assign(fileName, json->Data);
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void LanguageCustomWidget(WidgetInfo& info) {
|
||||
ImGui::Text("Select Language:");
|
||||
for (const auto& [id, data] : langs) {
|
||||
if (ImGui::Button(StringHelper::Sprintf("%s [%s]", data["language_name"].get_ref<const std::string&>().c_str(),
|
||||
id.c_str())
|
||||
.c_str())) {
|
||||
CVarSetString(LANGUAGE_CVAR, id.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLangWidgets() {
|
||||
return;
|
||||
|
||||
// TODO: Improve & enable this when everything is set up
|
||||
|
||||
SohGui::mSohMenu->AddSidebarEntry("Settings", "Language", 1);
|
||||
WidgetPath path = { "Settings", "Language", SECTION_COLUMN_1 };
|
||||
SohGui::mSohMenu->AddWidget(path, "LanguageWidget", WIDGET_CUSTOM)
|
||||
.CustomFunction(LanguageCustomWidget)
|
||||
.HideInSearch(true);
|
||||
}
|
||||
|
||||
static RegisterMenuInitFunc menuInitFunc(RegisterLangWidgets);
|
||||
8
soh/soh/Enhancements/Lang/Lang.h
Normal file
8
soh/soh/Enhancements/Lang/Lang.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Lang {
|
||||
std::string Translate(const char* path);
|
||||
void LoadLangs();
|
||||
} // namespace Lang
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
#include "soh/SohGui/SohGui.hpp"
|
||||
#include "soh/SohGui/SohMenu.h"
|
||||
#include "soh/SohGui/UIWidgets.hpp"
|
||||
#include "soh/Enhancements/Lang/Lang.h"
|
||||
#include <soh/cvar_prefixes.h>
|
||||
|
||||
namespace SohGui {
|
||||
|
|
@ -357,18 +358,42 @@ RandomizerCheck LocationOption::GetKey() const {
|
|||
return static_cast<RandomizerCheck>(key);
|
||||
}
|
||||
|
||||
#define RANDO_ENUM_ITEM(enum) { enum, #enum },
|
||||
|
||||
std::unordered_map<RandomizerTrick, std::string> trickNames = {
|
||||
#include "randomizerEnums/RandomizerTrick.h"
|
||||
};
|
||||
|
||||
#undef RANDO_ENUM_ITEM
|
||||
|
||||
const static std::string trickPrefix = "randomizer.tricks.";
|
||||
|
||||
static std::string MakeTrickName(RandomizerTrick key) {
|
||||
const static std::string namePostfix = ".name";
|
||||
|
||||
std::string trickNamePart = trickNames[key].substr(3);
|
||||
std::transform(trickNamePart.begin(), trickNamePart.end(), trickNamePart.begin(), ::tolower);
|
||||
return Lang::Translate((trickPrefix + trickNamePart + namePostfix).c_str());
|
||||
}
|
||||
|
||||
static std::string MakeTrickDescription(RandomizerTrick key) {
|
||||
const static std::string descriptionPostfix = ".description";
|
||||
|
||||
std::string trickNamePart = trickNames[key].substr(3);
|
||||
std::transform(trickNamePart.begin(), trickNamePart.end(), trickNamePart.begin(), ::tolower);
|
||||
return Lang::Translate((trickPrefix + trickNamePart + descriptionPostfix).c_str());
|
||||
}
|
||||
|
||||
TrickSetting::TrickSetting(RandomizerTrick key_, const RandomizerCheckQuest quest_, const RandomizerArea area_,
|
||||
std::set<Tricks::Tag> tags_, const std::string& name_, const std::string nameTag_,
|
||||
std::string description_)
|
||||
: Option(key_, name_, { "Disabled", "Enabled" }, OptionCategory::Setting, "", std::move(description_),
|
||||
WIDGET_CVAR_CHECKBOX, 0, false, nullptr, IMFLAG_NONE),
|
||||
std::set<Tricks::Tag> tags_, const std::string nameTag_)
|
||||
: Option(key_, std::move(MakeTrickName(key_)), { "Disabled", "Enabled" }, OptionCategory::Setting, "",
|
||||
std::move(MakeTrickDescription(key_)), WIDGET_CVAR_CHECKBOX, 0, false, nullptr, IMFLAG_NONE),
|
||||
mQuest(quest_), mArea(area_), mNameTag(nameTag_), mTags(std::move(tags_)) {
|
||||
}
|
||||
|
||||
TrickSetting TrickSetting::LogicTrick(RandomizerTrick key_, RandomizerCheckQuest quest_, RandomizerArea area_,
|
||||
std::set<Tricks::Tag> tags_, const std::string& name_, const std::string nameTag_,
|
||||
std::string description_) {
|
||||
return { key_, quest_, area_, std::move(tags_), name_, nameTag_, std::move(description_) };
|
||||
std::set<Tricks::Tag> tags_, const std::string nameTag_) {
|
||||
return { key_, quest_, area_, std::move(tags_), nameTag_ };
|
||||
}
|
||||
|
||||
RandomizerTrick TrickSetting::GetKey() const {
|
||||
|
|
|
|||
|
|
@ -356,14 +356,11 @@ class TrickSetting : public Option {
|
|||
* @param quest_ MQ, Vanilla, or Both.
|
||||
* @param area_ The area the trick is relevant for.
|
||||
* @param tags_ The set of RandomizerTrickTags for this trick.
|
||||
* @param name_ The name of the trick. Appears in the menus and spoiler
|
||||
* @param nameTag_ The 3-8 long name tag of the trick. Appears in the settings and presets file.
|
||||
* @param description_ A brief description of the trick.
|
||||
* @param nameTag_ The 3-8 character long name tag of the trick. Appears in the settings and presets file.
|
||||
* @return Option
|
||||
*/
|
||||
static TrickSetting LogicTrick(RandomizerTrick key_, RandomizerCheckQuest quest_, RandomizerArea area_,
|
||||
std::set<Tricks::Tag> tags_, const std::string& name_, const std::string nameTag_,
|
||||
std::string description_);
|
||||
std::set<Tricks::Tag> tags_, const std::string nameTag_);
|
||||
|
||||
RandomizerTrick GetKey() const;
|
||||
|
||||
|
|
@ -400,7 +397,7 @@ class TrickSetting : public Option {
|
|||
|
||||
private:
|
||||
TrickSetting(RandomizerTrick key_, RandomizerCheckQuest quest_, RandomizerArea area_, std::set<Tricks::Tag> tags_,
|
||||
const std::string& name_, const std::string nameTag_, std::string description_);
|
||||
const std::string nameTag_);
|
||||
RandomizerCheckQuest mQuest;
|
||||
RandomizerArea mArea;
|
||||
std::string mNameTag;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -65,6 +65,8 @@
|
|||
|
||||
#include <functions.h>
|
||||
#include "Enhancements/item-tables/ItemTableManager.h"
|
||||
#include "Enhancements/Lang/Lang.h"
|
||||
#include "soh/SohGui/SohGui.hpp"
|
||||
#include "soh/SohGui/ImGuiUtils.h"
|
||||
#include "ActorDB.h"
|
||||
#include "SaveManager.h"
|
||||
|
|
@ -886,6 +888,8 @@ void OTRGlobals::Initialize() {
|
|||
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryBackgroundV0>(), RESOURCE_FORMAT_BINARY,
|
||||
"Background", static_cast<uint32_t>(SOH::ResourceType::SOH_Background), 0);
|
||||
|
||||
Lang::LoadLangs();
|
||||
|
||||
gSaveStateMgr = std::make_shared<SaveStateMgr>();
|
||||
gRandoContext->InitStaticData();
|
||||
gRandoContext = Rando::Context::CreateInstance();
|
||||
|
|
|
|||
|
|
@ -208,8 +208,7 @@ uint32_t Menu::DrawSearchResults(std::string& menuSearchText) {
|
|||
info.type == WIDGET_SEPARATOR_TEXT || info.isHidden || info.hideInSearch) {
|
||||
continue;
|
||||
}
|
||||
const char* tooltip = info.options->tooltip;
|
||||
std::string widgetStr = std::string(info.name) + std::string(tooltip != NULL ? tooltip : "");
|
||||
std::string widgetStr = std::string(info.name) + info.options->tooltip;
|
||||
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) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ void Tooltip(const char* text) {
|
|||
}
|
||||
}
|
||||
|
||||
void Tooltip(std::string text) {
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(text).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void PushStyleMenu(const ImVec4& color) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(color.x, color.y, color.z, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(color.x, color.y, color.z, 1.0f));
|
||||
|
|
@ -174,9 +180,9 @@ bool Button(const char* label, const ButtonOptions& options) {
|
|||
PopStyleButton();
|
||||
ImGui::EndDisabled();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
return dirty;
|
||||
|
|
@ -365,9 +371,9 @@ bool Checkbox(const char* _label, bool* value, const CheckboxOptions& options) {
|
|||
PopStyleCheckbox();
|
||||
ImGui::EndDisabled();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
return pressed;
|
||||
|
|
@ -595,9 +601,9 @@ bool SliderInt(const char* label, int32_t* value, const IntSliderOptions& option
|
|||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -726,9 +732,9 @@ bool SliderFloat(const char* label, float* value, const FloatSliderOptions& opti
|
|||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -799,13 +805,12 @@ bool InputString(const char* label, std::string* value, const InputOptions& opti
|
|||
PopStyleInput();
|
||||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.hasError && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.errorText)) {
|
||||
if (options.hasError && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.errorText.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.errorText).c_str());
|
||||
} else if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -854,9 +859,9 @@ bool InputInt(const char* label, int32_t* value, const InputOptions& options) {
|
|||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -1040,7 +1045,7 @@ bool CVarRadioButton(const char* text, const char* cvarName, int32_t id, const R
|
|||
ImGui::SameLine();
|
||||
ImGui::Text("%s", text);
|
||||
PopStyleCheckbox();
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ std::string WrappedText(const char* text, unsigned int charactersPerLine = 80);
|
|||
std::string WrappedText(const std::string& text, unsigned int charactersPerLine = 80);
|
||||
void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f,
|
||||
float extraVerticalBottomPadding = 0.0f);
|
||||
void Tooltip(const char* text);
|
||||
void Tooltip(std::string text);
|
||||
|
||||
typedef enum ColorPickerModifiers {
|
||||
ColorPickerResetButton = 1,
|
||||
|
|
@ -106,11 +106,11 @@ enum ComponentAlignments {
|
|||
};
|
||||
|
||||
struct WidgetOptions {
|
||||
const char* tooltip = "";
|
||||
std::string tooltip = "";
|
||||
bool disabled = false;
|
||||
const char* disabledTooltip = "";
|
||||
std::string disabledTooltip = "";
|
||||
|
||||
WidgetOptions& Tooltip(const char* tooltip_) {
|
||||
WidgetOptions& Tooltip(std::string tooltip_) {
|
||||
tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -120,7 +120,7 @@ struct WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
WidgetOptions& DisabledTooltip(const char* disabledTooltip_) {
|
||||
WidgetOptions& DisabledTooltip(std::string disabledTooltip_) {
|
||||
disabledTooltip = disabledTooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ struct ButtonOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
ButtonOptions& Tooltip(const char* tooltip_) {
|
||||
ButtonOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -182,7 +182,7 @@ struct ColorPickerOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
ColorPickerOptions& Tooltip(const char* tooltip_) {
|
||||
ColorPickerOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -240,7 +240,7 @@ struct WindowButtonOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
WindowButtonOptions& Tooltip(const char* tooltip_) {
|
||||
WindowButtonOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -283,7 +283,7 @@ struct CheckboxOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
CheckboxOptions& Tooltip(const char* tooltip_) {
|
||||
CheckboxOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -293,7 +293,7 @@ struct CheckboxOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
CheckboxOptions& DisabledTooltip(const char* disabledTooltip_) {
|
||||
CheckboxOptions& DisabledTooltip(std::string disabledTooltip_) {
|
||||
WidgetOptions::disabledTooltip = disabledTooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -332,7 +332,7 @@ struct ComboboxOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
ComboboxOptions& Tooltip(const char* tooltip_) {
|
||||
ComboboxOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -397,7 +397,7 @@ struct IntSliderOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
IntSliderOptions& Tooltip(const char* tooltip_) {
|
||||
IntSliderOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -481,7 +481,7 @@ struct FloatSliderOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
FloatSliderOptions& Tooltip(const char* tooltip_) {
|
||||
FloatSliderOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -544,7 +544,7 @@ struct RadioButtonsOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
RadioButtonsOptions& Tooltip(const char* tooltip_) {
|
||||
RadioButtonsOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -571,9 +571,9 @@ struct InputOptions : WidgetOptions {
|
|||
bool secret = false;
|
||||
ImGuiInputFlags addedFlags = 0;
|
||||
bool hasError = false;
|
||||
const char* errorText = "";
|
||||
std::string errorText = "";
|
||||
|
||||
InputOptions& Tooltip(const char* tooltip_) {
|
||||
InputOptions& Tooltip(std::string tooltip_) {
|
||||
WidgetOptions::tooltip = tooltip_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -628,7 +628,7 @@ struct InputOptions : WidgetOptions {
|
|||
return *this;
|
||||
}
|
||||
|
||||
InputOptions& ErrorText(const char* errorText_) {
|
||||
InputOptions& ErrorText(std::string errorText_) {
|
||||
errorText = errorText_;
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -754,9 +754,9 @@ bool Combobox(std::string label, T* value, const std::map<T, const char*>& combo
|
|||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -839,9 +839,9 @@ bool Combobox(std::string label, T* value, const std::vector<const char*>& combo
|
|||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -925,9 +925,9 @@ bool Combobox(std::string label, T* value, const std::vector<std::string>& combo
|
|||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
@ -1011,9 +1011,9 @@ bool Combobox(std::string label, T* value, const char* (&comboArray)[N], const C
|
|||
ImGui::EndDisabled();
|
||||
ImGui::EndGroup();
|
||||
if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) &&
|
||||
!Ship_IsCStringEmpty(options.disabledTooltip)) {
|
||||
!options.disabledTooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip).c_str());
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !Ship_IsCStringEmpty(options.tooltip)) {
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && !options.tooltip.empty()) {
|
||||
ImGui::SetTooltip("%s", WrappedText(options.tooltip).c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
|
|
|||
|
|
@ -796,3 +796,20 @@ uint32_t SohUtils::Hash(std::string str) {
|
|||
}
|
||||
return hval;
|
||||
}
|
||||
|
||||
std::vector<std::string> SohUtils::StringSplit(const std::string& str, const std::string& delimiter) {
|
||||
std::vector<std::string> tokens;
|
||||
size_t pos = str.find(delimiter, 0);
|
||||
size_t prevpos = 0;
|
||||
|
||||
while (pos != std::string::npos) {
|
||||
std::string token = str.substr(prevpos, pos - prevpos);
|
||||
tokens.push_back(token);
|
||||
prevpos = pos + 1;
|
||||
pos = str.find(delimiter, prevpos);
|
||||
}
|
||||
|
||||
tokens.push_back(str.substr(prevpos));
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum FileType { FILE_TYPE_SAVE_VANILLA, FILE_TYPE_SAVE_RANDO, FILE_TYPE_PRESET, FILE_TYPE_SPOILER } FileType;
|
||||
|
|
@ -25,4 +26,6 @@ size_t CopyStringToCharBuffer(char* buffer, const std::string& source, size_t ma
|
|||
|
||||
bool IsStringEmpty(std::string str);
|
||||
uint32_t Hash(std::string str);
|
||||
|
||||
std::vector<std::string> StringSplit(const std::string& str, const std::string& delimiter);
|
||||
} // namespace SohUtils
|
||||
|
|
|
|||
Loading…
Reference in a new issue