This commit is contained in:
Pepe20129 2024-04-12 10:26:19 +02:00 committed by GitHub
commit 59df06d8d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 121 additions and 31 deletions

View File

@ -140,6 +140,9 @@ bool Option::RenderImGui() const {
case WidgetType::Checkbox:
changed = RenderCheckbox();
break;
case WidgetType::TristateCheckbox:
changed = RenderTristateCheckbox();
break;
case WidgetType::Combobox:
changed = RenderCombobox();
break;
@ -209,6 +212,26 @@ bool Option::RenderCheckbox() const {
return changed;
}
bool Option::RenderTristateCheckbox() const {
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;
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
}
if (!description.empty()) {
UIWidgets::InsertHelpHoverText(description.c_str());
}
if (disabled) {
UIWidgets::ReEnableComponent(disabledText.c_str());
}
return changed;
}
bool Option::RenderCombobox() const {
bool changed = false;
if (disabled) {

View File

@ -34,6 +34,7 @@ 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. */
};
@ -317,6 +318,7 @@ protected:
private:
bool RenderCheckbox() const;
bool RenderTristateCheckbox() const;
bool RenderCombobox() const;
bool RenderSlider() const;
std::variant<bool, uint8_t> var;

View File

@ -3827,6 +3827,12 @@ typedef enum {
RO_KEYRINGS_SELECTION,
} RandoOptionKeyrings;
typedef enum {
RO_KEYRING_FOR_DUNGEON_OFF,
RO_KEYRING_FOR_DUNGEON_RANDOM,
RO_KEYRING_FOR_DUNGEON_ON,
} RandoOptionKeyringForDungeon;
//Ganon's Boss Key Settings (vanilla, own dungeon, start with,
//overworld, anywhere, 100 GS reward)
typedef enum {

View File

@ -136,15 +136,15 @@ void Settings::CreateOptions() {
mOptions[RSK_LACS_OPTIONS] = Option::U8("LACS Reward Options", {"Standard Reward", "Greg as Reward", "Greg as Wildcard"}, OptionCategory::Setting, "gRandomizeLacsRewardOptions", "", WidgetType::Combobox, RO_LACS_STANDARD_REWARD);
mOptions[RSK_KEYRINGS] = Option::U8("Key Rings", {"Off", "Random", "Count", "Selection"}, OptionCategory::Setting, "gRandomizeShuffleKeyRings", mOptionDescriptions[RSK_KEYRINGS], WidgetType::Combobox, RO_KEYRINGS_OFF);
mOptions[RSK_KEYRINGS_RANDOM_COUNT] = Option::U8("Keyring Dungeon Count", {NumOpts(0, 9)}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsRandomCount", "", WidgetType::Slider, 8);
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS] = Option::Bool("Gerudo Fortress", "gRandomizeShuffleKeyRingsGerudoFortress", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_FOREST_TEMPLE] = Option::Bool("Forest Temple", "gRandomizeShuffleKeyRingsForestTemple", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_FIRE_TEMPLE] = Option::Bool("Fire Temple", "gRandomizeShuffleKeyRingsFireTemple", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_WATER_TEMPLE] = Option::Bool("Water Temple", "gRandomizeShuffleKeyRingsWaterTemple", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE] = Option::Bool("Spirit Temple", "gRandomizeShuffleKeyRingsSpiritTemple", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_SHADOW_TEMPLE] = Option::Bool("Shadow Temple", "gRandomizeShuffleKeyRingsShadowTemple", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL] = Option::Bool("Bottom of the Well", "gRandomizeShuffleKeyRingsBottomOfTheWell", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_GTG] = Option::Bool("Gerudo Training Grounds", "gRandomizeShuffleKeyRingsGTG", "", IMFLAG_NONE);
mOptions[RSK_KEYRINGS_GANONS_CASTLE] = Option::Bool("Ganon's Castle", "gRandomizeShuffleKeyRingsGanonsCastle");
mOptions[RSK_KEYRINGS_GERUDO_FORTRESS] = Option::U8("Gerudo Fortress", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsGerudoFortress", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_FOREST_TEMPLE] = Option::U8("Forest Temple", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsForestTemple", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_FIRE_TEMPLE] = Option::U8("Fire Temple", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsFireTemple", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_WATER_TEMPLE] = Option::U8("Water Temple", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsWaterTemple", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE] = Option::U8("Spirit Temple", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsSpiritTemple", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_SHADOW_TEMPLE] = Option::U8("Shadow Temple", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsShadowTemple", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL] = Option::U8("Bottom of the Well", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsBottomOfTheWell", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_GTG] = Option::U8("Gerudo Training Grounds", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsGTG", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_KEYRINGS_GANONS_CASTLE] = Option::U8("Ganon's Castle", {"No", "Random", "Yes"}, OptionCategory::Setting, "gRandomizeShuffleKeyRingsGanonsCastle", "", WidgetType::TristateCheckbox, 0);
mOptions[RSK_SKIP_CHILD_STEALTH] = Option::Bool("Skip Child Stealth", {"Don't Skip", "Skip"}, OptionCategory::Setting, "gRandomizeSkipChildStealth", mOptionDescriptions[RSK_SKIP_CHILD_STEALTH], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
mOptions[RSK_SKIP_CHILD_ZELDA] = Option::Bool("Skip Child Zelda", {"Don't Skip", "Skip"}, OptionCategory::Setting, "gRandomizeSkipChildZelda", mOptionDescriptions[RSK_SKIP_CHILD_ZELDA], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
mOptions[RSK_SKIP_TOWER_ESCAPE] = Option::Bool("Skip Tower Escape", {"Don't Skip", "Skip"}, OptionCategory::Setting, "gRandomizeSkipTowerEscape", mOptionDescriptions[RSK_SKIP_TOWER_ESCAPE], WidgetType::Checkbox, RO_GENERIC_DONT_SKIP);
@ -1943,31 +1943,31 @@ void Settings::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocatio
const uint32_t keyRingCount = mOptions[RSK_KEYRINGS].Is(RO_KEYRINGS_COUNT) ? mOptions[RSK_KEYRINGS_RANDOM_COUNT].Value<uint8_t>() : Random(0, static_cast<int>(keyrings.size()));
Shuffle(keyrings);
for (size_t i = 0; i < keyRingCount; i++) {
keyrings[i]->SetSelectedIndex(RO_GENERIC_ON);
keyrings[i]->SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_ON);
}
}
if (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL]) {
if (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_BOTTOM_OF_THE_WELL].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(BOTTOM_OF_THE_WELL)->SetKeyRing();
}
if (mOptions[RSK_KEYRINGS_FOREST_TEMPLE]) {
if (mOptions[RSK_KEYRINGS_FOREST_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_FOREST_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(FOREST_TEMPLE)->SetKeyRing();
}
if (mOptions[RSK_KEYRINGS_FIRE_TEMPLE]) {
if (mOptions[RSK_KEYRINGS_FIRE_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_FIRE_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(FIRE_TEMPLE)->SetKeyRing();
}
if (mOptions[RSK_KEYRINGS_WATER_TEMPLE]) {
if (mOptions[RSK_KEYRINGS_WATER_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_WATER_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(WATER_TEMPLE)->SetKeyRing();
}
if (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE]) {
if (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_SPIRIT_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(SPIRIT_TEMPLE)->SetKeyRing();
}
if (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE]) {
if (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_SHADOW_TEMPLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(SHADOW_TEMPLE)->SetKeyRing();
}
if (mOptions[RSK_KEYRINGS_GTG]) {
if (mOptions[RSK_KEYRINGS_GTG].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_GTG].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(GERUDO_TRAINING_GROUNDS)->SetKeyRing();
}
if (mOptions[RSK_KEYRINGS_GANONS_CASTLE]) {
if (mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_ON) || (mOptions[RSK_KEYRINGS_GANONS_CASTLE].Is(RO_KEYRING_FOR_DUNGEON_RANDOM) && Random(0, 2) == 1)) {
ctx->GetDungeon(GANONS_CASTLE)->SetKeyRing();
}
}
@ -2298,15 +2298,6 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
case RSK_HBA_HINT:
case RSK_WARP_SONG_HINTS:
case RSK_SCRUB_TEXT_HINT:
case RSK_KEYRINGS_GERUDO_FORTRESS:
case RSK_KEYRINGS_FOREST_TEMPLE:
case RSK_KEYRINGS_FIRE_TEMPLE:
case RSK_KEYRINGS_WATER_TEMPLE:
case RSK_KEYRINGS_SHADOW_TEMPLE:
case RSK_KEYRINGS_SPIRIT_TEMPLE:
case RSK_KEYRINGS_BOTTOM_OF_THE_WELL:
case RSK_KEYRINGS_GTG:
case RSK_KEYRINGS_GANONS_CASTLE:
case RSK_SHUFFLE_ENTRANCES:
case RSK_SHUFFLE_OVERWORLD_ENTRANCES:
case RSK_SHUFFLE_GROTTO_ENTRANCES:
@ -2341,6 +2332,23 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
mOptions[index].SetSelectedIndex(RO_KEYRINGS_SELECTION);
}
break;
case RSK_KEYRINGS_GERUDO_FORTRESS:
case RSK_KEYRINGS_FOREST_TEMPLE:
case RSK_KEYRINGS_FIRE_TEMPLE:
case RSK_KEYRINGS_WATER_TEMPLE:
case RSK_KEYRINGS_SHADOW_TEMPLE:
case RSK_KEYRINGS_SPIRIT_TEMPLE:
case RSK_KEYRINGS_BOTTOM_OF_THE_WELL:
case RSK_KEYRINGS_GTG:
case RSK_KEYRINGS_GANONS_CASTLE:
if (it.value() == "No") {
mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_OFF);
} else if (it.value() == "Random") {
mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_RANDOM);
} else if (it.value() == "Yes") {
mOptions[index].SetSelectedIndex(RO_KEYRING_FOR_DUNGEON_ON);
}
break;
case RSK_SHUFFLE_MERCHANTS:
if (it.value() == "Off") {
mOptions[index].SetSelectedIndex(RO_SHUFFLE_MERCHANTS_OFF);

View File

@ -127,7 +127,7 @@ namespace UIWidgets {
draw_list->PathStroke(col, 0, thickness);
}
bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic) {
bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic, bool renderCrossWhenOff) {
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems) {
return false;
@ -168,9 +168,9 @@ namespace UIWidgets {
} else if ((!disabled && *v) || (disabled && disabledGraphic == CheckboxGraphics::Checkmark)) {
const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
ImGui::RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
} else if (disabled && disabledGraphic == CheckboxGraphics::Cross) {
} else if ((!disabled && !*v && renderCrossWhenOff) || (disabled && disabledGraphic == CheckboxGraphics::Cross)) {
const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), cross_col, square_sz - pad * 2.0f);
RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), disabled ? cross_col : check_col, square_sz - pad * 2.0f);
}
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
@ -185,6 +185,36 @@ namespace UIWidgets {
return pressed;
}
bool CustomCheckboxTristate(const char* label, int* v, bool disabled, CheckboxGraphics disabledGraphic) {
bool ret;
if (*v == 0) {
bool b = false;
ret = CustomCheckbox(label, &b, disabled, disabledGraphic, true);
if (ret) {
*v = 1;
}
} else if (*v == 1) {
ImGui::PushItemFlag(ImGuiItemFlags_MixedValue, true);
bool b = true;
ret = CustomCheckbox(label, &b, disabled, disabledGraphic, true);
if (ret) {
*v = 2;
}
ImGui::PopItemFlag();
} else if (*v == 2) {
bool b = true;
ret = CustomCheckbox(label, &b, disabled, disabledGraphic, true);
if (ret) {
*v = 0;
}
} else {
SPDLOG_INFO("Invalid CheckBoxTristate value: {}", *v);
*v = 0;
return false;
}
return ret;
}
void ReEnableComponent(const char* disabledTooltipText) {
// End of disable region of previous component
ImGui::PopStyleVar(1);
@ -218,6 +248,25 @@ namespace UIWidgets {
return changed;
}
bool EnhancementCheckboxTristate(const char* text, const char* cvarName, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) {
bool changed = false;
if (disabled) {
DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
}
int val = CVarGetInteger(cvarName, defaultValue);
if (CustomCheckboxTristate(text, &val, disabled, disabledGraphic)) {
CVarSetInteger(cvarName, val);
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
changed = true;
}
if (disabled) {
ReEnableComponent(disabledTooltipText);
}
return changed;
}
bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) {
ImGui::BeginGroup();
if (padTop) Spacer(0);

View File

@ -68,12 +68,14 @@ namespace UIWidgets {
void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f);
void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz);
bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic);
bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic, bool renderCrossWhenOff = false);
bool CustomCheckboxTristate(const char* label, int* v, bool disabled, CheckboxGraphics disabledGraphic);
void ReEnableComponent(const char* disabledTooltipText);
void DisableComponent(const float alpha);
bool EnhancementCheckbox(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
bool EnhancementCheckboxTristate(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
bool EnhancementCombobox(const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled = false, const char* disabledTooltipText = "", uint8_t disabledValue = -1);