439 lines
15 KiB
C++
439 lines
15 KiB
C++
#include "option.h"
|
|
#include "libultraship/bridge.h"
|
|
#include <Context.h>
|
|
#include <ImGui/imgui.h>
|
|
#include "soh/UIWidgets.hpp"
|
|
|
|
namespace Rando {
|
|
Option Option::Bool(std::string name_, std::vector<std::string> options_, const OptionCategory category_,
|
|
std::string cvarName_, std::string description_, WidgetType widgetType_, const uint8_t defaultOption_,
|
|
const bool defaultHidden_, int imFlags_) {
|
|
return {false, std::move(name_), std::move(options_), category_, std::move(cvarName_), std::move(description_),
|
|
widgetType_, defaultOption_, defaultHidden_, imFlags_};
|
|
}
|
|
|
|
Option Option::Bool(std::string name_, std::string cvarName_, std::string description_, const int imFlags_,
|
|
const WidgetType widgetType_, const bool defaultOption_) {
|
|
return Option(false, std::move(name_), {"Off", "On"}, OptionCategory::Setting, std::move(cvarName_),
|
|
std::move(description_), widgetType_, defaultOption_, false, imFlags_);
|
|
}
|
|
|
|
Option Option::U8(std::string name_, std::vector<std::string> options_, const OptionCategory category_,
|
|
std::string cvarName_, std::string description_, WidgetType widgetType_, const uint8_t defaultOption_,
|
|
const bool defaultHidden_, int imFlags_) {
|
|
return {static_cast<uint8_t>(0), std::move(name_), std::move(options_), category_, std::move(cvarName_),
|
|
std::move(description_), widgetType_, defaultOption_, defaultHidden_, imFlags_};
|
|
}
|
|
|
|
Option Option::LogicTrick(std::string name_) {
|
|
return Option(false, std::move(name_), { "Disabled", "Enabled" }, OptionCategory::Setting, "",
|
|
"", WidgetType::Checkbox, 0, false, IMFLAG_NONE);
|
|
}
|
|
|
|
Option::operator bool() const {
|
|
if (std::holds_alternative<bool>(var)) {
|
|
return Value<bool>();
|
|
}
|
|
return Value<uint8_t>() != 0;
|
|
}
|
|
|
|
size_t Option::GetOptionCount() const {
|
|
return options.size();
|
|
}
|
|
|
|
const std::string& Option::GetName() const {
|
|
return name;
|
|
}
|
|
|
|
uint8_t Option::GetSelectedOptionIndex() const {
|
|
return selectedOption;
|
|
}
|
|
|
|
const std::string& Option::GetSelectedOptionText() const {
|
|
return options[selectedOption];
|
|
}
|
|
|
|
const std::string& Option::GetCVarName() const {
|
|
return cvarName;
|
|
}
|
|
|
|
void Option::SetVariable() {
|
|
if (std::holds_alternative<bool>(var)) {
|
|
var.emplace<bool>(selectedOption != 0);
|
|
} else {
|
|
var.emplace<uint8_t>(selectedOption);
|
|
}
|
|
}
|
|
|
|
void Option::SetCVar() const {
|
|
if (!cvarName.empty()) {
|
|
CVarSetInteger(cvarName.c_str(), GetSelectedOptionIndex());
|
|
}
|
|
}
|
|
|
|
void Option::SetFromCVar() {
|
|
if (!cvarName.empty()) {
|
|
SetSelectedIndex(CVarGetInteger(cvarName.c_str(), defaultOption));
|
|
}
|
|
}
|
|
|
|
void Option::SetDelayedOption() {
|
|
delayedOption = selectedOption;
|
|
}
|
|
|
|
void Option::RestoreDelayedOption() {
|
|
selectedOption = delayedOption;
|
|
SetVariable();
|
|
}
|
|
|
|
void Option::SetSelectedIndex(const size_t idx) {
|
|
selectedOption = idx;
|
|
if (selectedOption >= options.size()) {
|
|
selectedOption = 0;
|
|
}
|
|
SetVariable();
|
|
}
|
|
|
|
void Option::Hide() {
|
|
hidden = true;
|
|
}
|
|
|
|
void Option::Unhide() {
|
|
hidden = false;
|
|
}
|
|
|
|
bool Option::IsHidden() const {
|
|
return hidden;
|
|
}
|
|
|
|
void Option::ChangeOptions(std::vector<std::string> opts) {
|
|
if (selectedOption >= opts.size()) {
|
|
selectedOption = opts.size() - 1;
|
|
}
|
|
options = std::move(opts);
|
|
}
|
|
|
|
void Option::Enable() {
|
|
disabled = false;
|
|
}
|
|
|
|
void Option::Disable(std::string text, const UIWidgets::CheckboxGraphics graphic) {
|
|
if (!disabled || disabledText != text || disabledGraphic != graphic) {
|
|
disabled = true;
|
|
disabledText = std::move(text);
|
|
disabledGraphic = graphic;
|
|
}
|
|
}
|
|
|
|
bool Option::IsCategory(const OptionCategory category) const {
|
|
return category == this->category;
|
|
}
|
|
|
|
bool Option::RenderImGui() const {
|
|
bool changed = false;
|
|
ImGui::BeginGroup();
|
|
switch (widgetType) {
|
|
case WidgetType::Checkbox:
|
|
changed = RenderCheckbox();
|
|
break;
|
|
case WidgetType::Combobox:
|
|
changed = RenderCombobox();
|
|
break;
|
|
case WidgetType::Slider:
|
|
changed = RenderSlider();
|
|
break;
|
|
}
|
|
UIWidgets::Spacer(0);
|
|
ImGui::EndGroup();
|
|
return changed;
|
|
}
|
|
|
|
bool Option::HasFlag(const int imFlag_) const {
|
|
return imFlag_ & imFlags;
|
|
}
|
|
|
|
void Option::AddFlag(const int imFlag_) {
|
|
imFlags |= imFlag_;
|
|
}
|
|
|
|
void Option::SetFlag(const int imFlag_) {
|
|
imFlags = imFlag_;
|
|
}
|
|
|
|
void Option::RemoveFlag(const int imFlag_) {
|
|
imFlags &= ~imFlag_;
|
|
}
|
|
|
|
Option::Option(uint8_t var_, std::string name_, std::vector<std::string> options_, OptionCategory category_,
|
|
std::string cvarName_, std::string description_, WidgetType widgetType_, uint8_t defaultOption_,
|
|
bool defaultHidden_, int imFlags_)
|
|
: var(var_), name(std::move(name_)), options(std::move(options_)), category(category_),
|
|
cvarName(std::move(cvarName_)), description(std::move(description_)), widgetType(widgetType_),
|
|
defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) {
|
|
selectedOption = defaultOption;
|
|
hidden = defaultHidden;
|
|
SetVariable();
|
|
}
|
|
Option::Option(bool var_, std::string name_, std::vector<std::string> options_, const OptionCategory category_,
|
|
std::string cvarName_, std::string description_, WidgetType widgetType_, const uint8_t defaultOption_,
|
|
const bool defaultHidden_, int imFlags_)
|
|
: var(var_), name(std::move(name_)), options(std::move(options_)), category(category_),
|
|
cvarName(std::move(cvarName_)), description(std::move(description_)), widgetType(widgetType_),
|
|
defaultOption(defaultOption_), defaultHidden(defaultHidden_), imFlags(imFlags_) {
|
|
selectedOption = defaultOption;
|
|
hidden = defaultHidden;
|
|
SetVariable();
|
|
}
|
|
|
|
bool Option::RenderCheckbox() const {
|
|
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)) {
|
|
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) {
|
|
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--;
|
|
CVarSetInteger(cvarName.c_str(), selected);
|
|
changed = true;
|
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
|
}
|
|
if (!description.empty()) {
|
|
UIWidgets::InsertHelpHoverText(description.c_str());
|
|
}
|
|
ImGui::BeginGroup();
|
|
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));
|
|
changed = true;
|
|
selected = i;
|
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
|
}
|
|
}
|
|
}
|
|
ImGui::EndCombo();
|
|
}
|
|
ImGui::EndGroup();
|
|
if (disabled) {
|
|
UIWidgets::ReEnableComponent(disabledText.c_str());
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
bool Option::RenderSlider() const {
|
|
bool changed = false;
|
|
int val = CVarGetInteger(cvarName.c_str(), defaultOption);
|
|
if (val >= options.size()) {
|
|
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--;
|
|
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;
|
|
}
|
|
if (val > options.size() - 1) {
|
|
val = static_cast<int>(options.size() - 1);
|
|
changed = true;
|
|
}
|
|
if (changed) {
|
|
CVarSetInteger(cvarName.c_str(), val);
|
|
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
OptionGroup::OptionGroup(std::string name, std::vector<Option*> options, const OptionGroupType groupType,
|
|
const bool printInSpoiler, const WidgetContainerType containerType, std::string description)
|
|
: mName(std::move(name)), mOptions(std::move(options)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler),
|
|
mContainerType(containerType), mDescription(std::move(description)) {
|
|
}
|
|
|
|
OptionGroup::OptionGroup(std::string name, std::vector<OptionGroup*> subGroups, const OptionGroupType groupType,
|
|
const bool printInSpoiler, const WidgetContainerType containerType, std::string description)
|
|
: mName(std::move(name)), mSubGroups(std::move(subGroups)), mGroupType(groupType), mPrintInSpoiler(printInSpoiler),
|
|
mContainsType(OptionGroupType::SUBGROUP), mContainerType(containerType), mDescription(std::move(description)) {
|
|
}
|
|
|
|
OptionGroup OptionGroup::SubGroup(std::string name, std::vector<Option*> options, const bool printInSpoiler,
|
|
const WidgetContainerType containerType, std::string description) {
|
|
return {std::move(name), std::move(options), OptionGroupType::SUBGROUP, printInSpoiler, containerType,
|
|
std::move(description)};
|
|
}
|
|
|
|
OptionGroup OptionGroup::SubGroup(std::string name, std::vector<OptionGroup*> subGroups, const bool printInSpoiler,
|
|
const WidgetContainerType containerType, std::string description) {
|
|
return {std::move(name), std::move(subGroups), OptionGroupType::SUBGROUP, printInSpoiler, containerType,
|
|
std::move(description)};
|
|
}
|
|
|
|
const std::string& OptionGroup::GetName() const {
|
|
return mName;
|
|
}
|
|
|
|
const std::vector<Option*>& OptionGroup::GetOptions() const {
|
|
return mOptions;
|
|
}
|
|
|
|
const std::vector<OptionGroup*>& OptionGroup::GetSubGroups() const {
|
|
return mSubGroups;
|
|
}
|
|
|
|
bool OptionGroup::PrintInSpoiler() const {
|
|
return mPrintInSpoiler;
|
|
}
|
|
|
|
OptionGroupType OptionGroup::GetGroupType() const {
|
|
return mGroupType;
|
|
}
|
|
|
|
OptionGroupType OptionGroup::GetContainsType() const {
|
|
return mContainsType;
|
|
}
|
|
|
|
WidgetContainerType OptionGroup::GetContainerType() const {
|
|
return mContainerType;
|
|
}
|
|
|
|
const std::string& OptionGroup::GetDescription() const {
|
|
return mDescription;
|
|
}
|
|
|
|
void OptionGroup::Enable() {
|
|
mDisabled = false;
|
|
}
|
|
|
|
void OptionGroup::Disable() {
|
|
mDisabled = true;
|
|
}
|
|
|
|
bool OptionGroup::RenderImGui() const { // NOLINT(*-no-recursion)
|
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
|
bool changed = false;
|
|
ImGui::BeginDisabled(mDisabled);
|
|
if (mContainerType == WidgetContainerType::TABLE) {
|
|
if (ImGui::BeginTable(mName.c_str(), static_cast<int>(mSubGroups.size()), ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV)) {
|
|
for (const auto column : mSubGroups) {
|
|
if (column->GetContainerType() == WidgetContainerType::COLUMN) {
|
|
ImGui::TableSetupColumn(column->GetName().c_str(), ImGuiTableColumnFlags_WidthStretch, 200.0f);
|
|
}
|
|
}
|
|
ImGui::PushItemFlag(ImGuiItemFlags_NoNav, true);
|
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
|
for (int i = 0; i < mSubGroups.size(); i++) {
|
|
ImGui::TableSetColumnIndex(i);
|
|
ImGui::TableHeader(mSubGroups[i]->GetName().c_str());
|
|
if (!mSubGroups[i]->GetDescription().empty()) {
|
|
UIWidgets::SetLastItemHoverText(mSubGroups[i]->GetDescription().c_str());
|
|
}
|
|
}
|
|
ImGui::PopItemFlag();
|
|
ImGui::TableNextRow();
|
|
}
|
|
}
|
|
if (mContainerType == WidgetContainerType::SECTION && !mName.empty()) {
|
|
UIWidgets::PaddedSeparator();
|
|
ImGui::Text("%s", mName.c_str());
|
|
if (!mDescription.empty()) {
|
|
UIWidgets::InsertHelpHoverText(mDescription.c_str());
|
|
}
|
|
UIWidgets::PaddedSeparator();
|
|
}
|
|
if (mContainerType == WidgetContainerType::COLUMN) {
|
|
ImGui::TableNextColumn();
|
|
window->DC.CurrLineTextBaseOffset = 0.0f;
|
|
ImGui::BeginChild(mName.c_str(), ImVec2(0, -8));
|
|
ImGui::PushItemWidth(-FLT_MIN);
|
|
}
|
|
if (mContainsType == OptionGroupType::SUBGROUP) {
|
|
for (const auto optionGroup : mSubGroups) {
|
|
if (optionGroup->RenderImGui()) {
|
|
changed = true;
|
|
}
|
|
}
|
|
} else {
|
|
for (const auto option : mOptions) {
|
|
if (option->IsHidden()) {
|
|
continue;
|
|
}
|
|
if (option->HasFlag(IMFLAG_INDENT)) {
|
|
ImGui::Indent();
|
|
}
|
|
// If any options changed, changed will end up being true
|
|
if (option->RenderImGui()) {
|
|
changed = true;
|
|
}
|
|
if (option->HasFlag(IMFLAG_UNINDENT)) {
|
|
ImGui::Unindent();
|
|
}
|
|
if (option->HasFlag(IMFLAG_SEPARATOR_BOTTOM)) {
|
|
UIWidgets::PaddedSeparator();
|
|
}
|
|
}
|
|
}
|
|
if (mContainerType == WidgetContainerType::COLUMN) {
|
|
ImGui::EndChild();
|
|
}
|
|
if (mContainerType == WidgetContainerType::TABLE) {
|
|
ImGui::EndTable();
|
|
}
|
|
ImGui::EndDisabled();
|
|
return changed;
|
|
}
|
|
} // namespace Rando
|