From efc0569397c085ff43d1bcce94a61ae3d834cd54 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 7 Oct 2023 08:33:37 -0500 Subject: [PATCH] Implement Button, Checkbox, Slider, and Combobox --- soh/soh/SohMenuBar.cpp | 47 ++++++ soh/soh/UIWidgets.cpp | 345 +++++++++++++++++++++++++++++++++++++++++ soh/soh/UIWidgets.hpp | 98 +++++++++++- 3 files changed, 489 insertions(+), 1 deletion(-) diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index ec663c6b44f..e8cd5610cf5 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -490,6 +490,53 @@ void DrawEnhancementsMenu() { { if (ImGui::BeginMenu("Time Savers")) { + // new + UIWidgets::CVarSliderInt("Text Speed", "gTextSpeed", 1, 5, 1, { + .format = "%dx", + }); + UIWidgets::CVarCheckbox("Skip Text", "gSkipText", { + .tooltip = "Holding down B skips text", + }); + UIWidgets::CVarSliderInt("King Zora Speed", "gMweepSpeed", 1, 5, 1, { + .format = "%dx", + }); + UIWidgets::CVarSliderInt("Biggoron Forge Time", "gForgeTime", 0, 3, 3, { + .tooltip = "Allows you to change the number of days it takes for Biggoron to forge the Biggoron Sword", + .format = "%d days" + }); + UIWidgets::CVarSliderInt("Vine/Ladder Climb speed", "gClimbSpeed", 0, 12, 0, { + .format = "%dx", + }); + UIWidgets::CVarSliderInt("Block pushing speed", "gFasterBlockPush", 0, 5, 0, { + .format = "%dx", + }); + UIWidgets::CVarCheckbox("Faster Heavy Block Lift", "gFasterHeavyBlockLift", { + .tooltip = "Speeds up lifting silver rocks and obelisks", + }); + UIWidgets::CVarCheckbox("Link as default file name", "gLinkDefaultName", { + .tooltip = "Allows you to have \"Link\" as a premade file name", + }); + UIWidgets::CVarCheckbox("No Forced Navi", "gNoForcedNavi", { + .tooltip = "Prevent forced Navi conversations", + }); + UIWidgets::CVarCheckbox("No Skulltula Freeze", "gSkulltulaFreeze", { + .tooltip = "Stops the game from freezing the player when picking up Gold Skulltulas", + }); + UIWidgets::CVarCheckbox("Fast Chests", "gFastChests", { + .tooltip = "Kick open every chest", + }); + UIWidgets::CVarCombobox("Chest size & texture matches contents", "gChestSizeAndTextureMatchesContents", chestStyleMatchesContentsOptions, { + .defaultIndex = CSMC_DISABLED, + .tooltip = + "Chest sizes and textures are changed to help identify the item inside.\n" + " - Major items: Large gold chests\n" + " - Lesser items: Large brown chests\n" + " - Junk items: Small brown chests\n" + " - Small keys: Small silver chest\n" + " - Boss keys: Vanilla size and texture\n" + " - Skulltula Tokens: Small skulltula chest\n", + }); + // old UIWidgets::PaddedEnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, "", 1, true, false, true); UIWidgets::PaddedEnhancementCheckbox("Skip Text", "gSkipText", false, true); UIWidgets::Tooltip("Holding down B skips text"); diff --git a/soh/soh/UIWidgets.cpp b/soh/soh/UIWidgets.cpp index 15bb088a357..f7f25a3603c 100644 --- a/soh/soh/UIWidgets.cpp +++ b/soh/soh/UIWidgets.cpp @@ -734,4 +734,349 @@ namespace UIWidgets { float sz = ImGui::GetFrameHeight(); return StateButtonEx(str_id, label, ImVec2(sz, sz), ImGuiButtonFlags_None); } + + void PushStyleButton(const ImVec4& color) { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(color.x, color.y, color.z, 0.8f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(color.x, color.y, color.z, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.3f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 5.0f); + } + + void PopStyleButton() { + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(4); + } + + bool Button(const char* label, const ButtonOptions& options) { + ImGui::BeginDisabled(options.disabled); + PushStyleButton(options.color); + bool dirty = ImGui::Button(label, options.size); + PopStyleButton(); + ImGui::EndDisabled(); + if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); + } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.tooltip)); + } + return dirty; + } + + bool WindowButton(const char* label, const char* cvarName, std::shared_ptr windowPtr, const ButtonOptions& options) { + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); + std::string buttonText = label; + bool dirty = false; + if (CVarGetInteger(cvarName, 0)) { + buttonText = ICON_FA_WINDOW_CLOSE " " + buttonText; + } else { + buttonText = ICON_FA_EXTERNAL_LINK_SQUARE " " + buttonText; + } + if (Button(buttonText.c_str(), options)) { + windowPtr->ToggleVisibility(); + dirty = true; + } + ImGui::PopStyleVar(); + return dirty; + } + + void PushStyleCheckbox(const ImVec4& color) { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(color.x, color.y, color.z, 0.8f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(color.x, color.y, color.z, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.3f)); + ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.0f, 1.0f, 1.0f, 0.7f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 5.0f); + } + + void PopStyleCheckbox() { + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(5); + } + + bool Checkbox(const char* label, bool* value, const CheckboxOptions& options) { + ImGui::PushID(label); + bool dirty = false; + float startX = ImGui::GetCursorPosX(); + const char* invisibleLabel = ("##" + std::string(label)).c_str(); + ImGui::BeginDisabled(options.disabled); + PushStyleCheckbox(options.color); + if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x); + } else if (options.labelPosition == LabelPosition::Above) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + ImGui::NewLine(); + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x); + } + } else if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::Text(label); + } + } + dirty = CustomCheckbox(invisibleLabel, value, options.disabled); + if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x * 2); + ImGui::Text(label); + } else if (options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(); + ImGui::SetCursorPosX(startX); + ImGui::Text(label); + } + } else if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(); + ImGui::Text(label); + } else if (options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + } + } + PopStyleCheckbox(); + ImGui::EndDisabled(); + if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); + } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.tooltip)); + } + ImGui::PopID(); + return dirty; + } + + bool CVarCheckbox(const char* label, const char* cvarName, const CheckboxOptions& options) { + bool dirty = false; + bool value = (bool)CVarGetInteger(cvarName, options.defaultValue); + if (Checkbox(label, &value, options)) { + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + return dirty; + } + + void PushStyleCombobox(const ImVec4& color) { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 0.8f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(color.x, color.y, color.z, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(color.x, color.y, color.z, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(color.x, color.y, color.z, 0.8f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(color.x, color.y, color.z, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(color.x, color.y, color.z, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(color.x, color.y, color.z, 0.6f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 6.0f)); + } + + void PopStyleCombobox() { + ImGui::PopStyleVar(4); + ImGui::PopStyleColor(9); + } + + bool Combobox(const char* label, uint8_t* value, std::span comboArray, const ComboboxOptions& options) { + bool dirty = false; + float startX = ImGui::GetCursorPosX(); + const char* invisibleLabel = ("##" + std::string(label)).c_str(); + ImGui::PushID(label); + ImGui::BeginGroup(); + ImGui::BeginDisabled(options.disabled); + PushStyleCombobox(options.color); + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().ItemSpacing.x * 2); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + ImGui::SetNextItemWidth(ImGui::CalcTextSize(comboArray[*value]).x + ImGui::GetStyle().FramePadding.x * 4 + ImGui::GetStyle().ItemSpacing.x); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::NewLine(); + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x * 2); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) { + float width = ImGui::CalcTextSize(comboArray[*value]).x + ImGui::GetStyle().FramePadding.x * 4; + ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } + } + if (ImGui::BeginCombo(invisibleLabel, comboArray[*value], options.flags)) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f)); + for (uint8_t i = 0; i < comboArray.size(); i++) { + if (strlen(comboArray[i]) > 1) { + if (ImGui::Selectable(comboArray[i], i == *value)) { + *value = i; + dirty = true; + } + } + } + ImGui::PopStyleVar(); + ImGui::EndCombo(); + } + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Near) { + ImGui::SameLine(); + ImGui::Text(label); + } else if (options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) { + ImGui::SameLine(startX); + ImGui::Text(label); + } + } + PopStyleCombobox(); + ImGui::EndDisabled(); + ImGui::EndGroup(); + if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); + } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.tooltip)); + } + ImGui::PopID(); + return dirty; + } + + bool CVarCombobox(const char* label, const char* cvarName, std::span comboArray, const ComboboxOptions& options) { + bool dirty = false; + uint8_t value = (uint8_t)CVarGetInteger(cvarName, options.defaultIndex); + if (Combobox(label, &value, comboArray, options)) { + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + return dirty; + } + + 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, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(color.x, color.y, color.z, 0.6f)); + ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f)); + } + + void PopStyleMenu() { + ImGui::PopStyleVar(4); + ImGui::PopStyleColor(3); + } + + bool BeginMenu(const char* label, bool enabled) { + bool dirty = false; + + PushStyleMenu(); + + if (ImGui::BeginMenu(label, enabled)) { + PopStyleMenu(); + dirty = true; + } else { + PopStyleMenu(); + } + + return dirty; + } + + // Old component usage + // UIWidgets::PaddedEnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", + // "gRandomizeGanonTrialCount", 1, 6, "", 6, true, true, false); + // UIWidgets::InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); + // New and improved component usage + // UIWidgets::CVarSliderInt("Ganon's Trial Count: %d", "gRandomizeGanonTrialCount", 1, 6, 6, { + // .tooltip = "Set the number of trials required to enter Ganon's Tower." + // .disabled = false, + // .disabledTooltip = "", + // .showButtons = true, + // .color = UIWidgets::Color::Indigo, + // }); + void PushStyleSlider(const ImVec4& color) { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(color.x, color.y, color.z, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(1.0, 1.0, 1.0, 0.4f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(1.0, 1.0, 1.0, 0.5f)); + ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); + } + + void PopStyleSlider() { + ImGui::PopStyleVar(4); + ImGui::PopStyleColor(6); + } + + bool CVarSliderInt(const char* label, const char* cvarName, int32_t min, int32_t max, const int32_t defaultValue, const SliderOptions& options){ + bool dirty = false; + const char* invisibleLabel = ("##" + std::string(label)).c_str(); + int32_t value = CVarGetInteger(cvarName, defaultValue); + ImGui::PushID(label); + ImGui::BeginGroup(); + ImGui::BeginDisabled(options.disabled); + PushStyleSlider(options.color); + if (options.alignment == ComponentAlignment::Left) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::Text(label, value); + } + } else if (options.alignment == ComponentAlignment::Right) { + if (options.labelPosition == LabelPosition::Above) { + ImGui::NewLine(); + ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x); + ImGui::Text(label, value); + } + } + if (options.showButtons) { + if (Button("-", { .size = Sizes::Inline, .color = options.color }) && value > min) { + value--; + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + ImGui::SameLine(0, 3.0f); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize("+").x + 20.0f + 3.0f)); + } else { + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + } + if (ImGui::SliderScalar(invisibleLabel, ImGuiDataType_S32, &value, &min, &max, options.format, options.flags)) { + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + if (options.showButtons) { + ImGui::SameLine(0, 3.0f); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (Button("+", { .size = Sizes::Inline, .color = options.color }) && value < max) { + value++; + CVarSetInteger(cvarName, value); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + dirty = true; + } + } + PopStyleSlider(); + ImGui::EndDisabled(); + ImGui::EndGroup(); + if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip)); + } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) { + ImGui::SetTooltip("%s", WrappedText(options.tooltip)); + } + ImGui::PopID(); + return dirty; + } } diff --git a/soh/soh/UIWidgets.hpp b/soh/soh/UIWidgets.hpp index b18487977b7..0369fe6f38e 100644 --- a/soh/soh/UIWidgets.hpp +++ b/soh/soh/UIWidgets.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace UIWidgets { @@ -64,7 +65,7 @@ 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 = false, CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross); void ReEnableComponent(const char* disabledTooltipText); void DisableComponent(const float alpha); @@ -96,6 +97,101 @@ namespace UIWidgets { void DrawFlagArray16(const std::string& name, uint16_t& flags); void DrawFlagArray8(const std::string& name, uint8_t& flags); bool StateButton(const char* str_id, const char* label); + + namespace Colors { + const ImVec4 White = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + const ImVec4 Gray = ImVec4(0.4f, 0.4f, 0.4f, 1.0f); + const ImVec4 Indigo = ImVec4(0.24f, 0.31f, 0.71f, 1.0f); + const ImVec4 Red = ImVec4(0.5f, 0.0f, 0.0f, 1.0f); + const ImVec4 DarkRed = ImVec4(0.3f, 0.0f, 0.0f, 1.0f); + const ImVec4 LightGreen = ImVec4(0.0f, 0.7f, 0.0f, 1.0f); + const ImVec4 Green = ImVec4(0.0f, 0.5f, 0.0f, 1.0f); + const ImVec4 DarkGreen = ImVec4(0.0f, 0.3f, 0.0f, 1.0f); + const ImVec4 Yellow = ImVec4(1.0f, 0.627f, 0.0f, 1.0f); + }; + + namespace Sizes { + const ImVec2 Inline = ImVec2(0.0f, 0.0f); + const ImVec2 Fill = ImVec2(-1.0f, 0.0f); + } + + enum LabelPosition { + Near, + Far, + Above, + None, + Within, + }; + enum ComponentAlignment { + Left, + Right, + }; + + struct ButtonOptions { + const ImVec4 color = Colors::Gray; + const ImVec2 size = Sizes::Fill; + const char* tooltip = ""; + bool disabled = false; + const char* disabledTooltip = ""; + }; + + struct CheckboxOptions { + const ImVec4 color = Colors::Green; + const char* tooltip = ""; + bool disabled = false; + const char* disabledTooltip = ""; + bool defaultValue = false; // Only applicable to CVarCheckbox + ComponentAlignment alignment = ComponentAlignment::Left; + LabelPosition labelPosition = LabelPosition::Near; + // TODO: Add a "disabledGraphic" option + }; + + struct ComboboxOptions { + const ImVec4 color = Colors::Green; + const char* tooltip = ""; + bool disabled = false; + const char* disabledTooltip = ""; + u8 defaultIndex = 0; // Only applicable to CVarCombobox + ComponentAlignment alignment = ComponentAlignment::Left; + LabelPosition labelPosition = LabelPosition::Above; + ImGuiComboFlags flags = 0; + }; + + struct SliderOptions { + const ImVec4 color = Colors::Green; + const char* tooltip = ""; + bool disabled = false; + const char* disabledTooltip = ""; + bool showButtons = true; + ImGuiSliderFlags flags = 0; + const char* format = "%d"; + ComponentAlignment alignment = ComponentAlignment::Left; + LabelPosition labelPosition = LabelPosition::Above; + }; + + void PushStyleButton(const ImVec4& color = Colors::Gray); + void PopStyleButton(); + bool Button(const char* label, const ButtonOptions& options = {}); + bool WindowButton(const char* label, const char* cvarName, std::shared_ptr windowPtr, const ButtonOptions& options = {}); + + void PushStyleCheckbox(const ImVec4& color = Colors::Indigo); + void PopStyleCheckbox(); + bool Checkbox(const char* label, bool* v, const CheckboxOptions& options = {}); + bool CVarCheckbox(const char* label, const char* cvarName, const CheckboxOptions& options = {}); + + void PushStyleCombobox(const ImVec4& color = Colors::Indigo); + void PopStyleCombobox(); + bool Combobox(const char* label, std::span comboArray, const ComboboxOptions& options = {}); + bool CVarCombobox(const char* label, const char* cvarName, std::span comboArray, const ComboboxOptions& options = {}); + + void PushStyleMenu(const ImVec4& color = Colors::Gray); + void PopStyleMenu(); + bool BeginMenu(const char* label, bool enabled = true); + + void PushStyleSlider(const ImVec4& color = Colors::Indigo); + void PopStyleSlider(); + bool CVarSliderInt(const char* label, const char* cvarName, int32_t min, int32_t max, const int32_t defaultValue, const SliderOptions& options = {}); + bool CVarSliderFloat(const char* label, const char* cvarName, float min, float max, const float defaultValue, const SliderOptions& options = {}); } #endif /* UIWidgets_hpp */