From 77ba51a18e25510ec59d50a8a78eaf91a1cdef43 Mon Sep 17 00:00:00 2001 From: Xottab-DUTY Date: Thu, 16 Jan 2025 00:56:33 +0300 Subject: [PATCH] Support saving UI Debugger settings in imgui.ini --- src/xrEngine/editor_helper.h | 11 +++ src/xrUICore/Windows/UIWindow.cpp | 30 +++--- src/xrUICore/ui_debug.cpp | 147 +++++++++++++++++++++++++++++- src/xrUICore/ui_debug.h | 37 +++++++- 4 files changed, 205 insertions(+), 20 deletions(-) diff --git a/src/xrEngine/editor_helper.h b/src/xrEngine/editor_helper.h index 4e6da48df04..0165d0a5555 100644 --- a/src/xrEngine/editor_helper.h +++ b/src/xrEngine/editor_helper.h @@ -43,6 +43,17 @@ inline bool InputText(pcstr label, shared_str& texture_name) return false; } +inline bool ColorEdit4(pcstr label, u32& clr, ImGuiColorEditFlags flags = 0) +{ + Fcolor color = clr; + if (ImGui::ColorEdit4(label, reinterpret_cast(&color), flags)) + { + clr = color.get(); + return true; + } + return false; +} + inline ImGuiKey xr_key_to_imgui_key(int key) { switch (key) diff --git a/src/xrUICore/Windows/UIWindow.cpp b/src/xrUICore/Windows/UIWindow.cpp index 723bb038730..12fcb74cb09 100644 --- a/src/xrUICore/Windows/UIWindow.cpp +++ b/src/xrUICore/Windows/UIWindow.cpp @@ -532,36 +532,42 @@ bool CUIWindow::FillDebugTree(const CUIDebugState& debugState) if (ImGui::IsItemClicked()) debugState.select(this); - const bool hovered = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled); - if (debugState.drawWndRects && (IsShown() || hovered)) + const bool examined = ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled); + if (debugState.settings.drawWndRects && (IsShown() || examined)) { const auto& focus = UI().Focus(); + auto& colors = debugState.settings.colors; Frect rect; GetAbsoluteRect(rect); UI().ClientToScreenScaled(rect.lt, rect.lt.x, rect.lt.y); UI().ClientToScreenScaled(rect.rb, rect.rb.x, rect.rb.y); - // XXX: make colours user configurable - const u32 alpha = CursorOverWindow() ? 255 : 200; - Fcolor color = color_rgba(0, 0, 255, alpha); - if (hovered) - color = color_rgba(0, 255, 255, 255); + Fcolor color; + const bool hovered = CursorOverWindow(); + + if (examined) + color = colors.examined; else if (focus.GetFocused() == this) - color = color_rgba(255, 215, 0, 255); - else if (debugState.coloredRects) + color = colors.focused; + else if (debugState.settings.coloredRects) { + const u32 alpha = hovered ? 255 : 200; // This is pseudo RNG, so when we are seeding it with 'this' pointer // we can expect predictable and stable values (no *blinking* at all) CRandom rnd; rnd.seed((s32)(intptr_t)this); color = color_rgba(rnd.randI(255), rnd.randI(255), rnd.randI(255), alpha); } - else if (focus.IsRegistered(this)) - color = color_rgba(0, 255, 0, alpha); + else if (focus.IsValuable(this)) + color = hovered ? colors.focusableValuableHovered : colors.focusableValuable; + else if (focus.IsNonValuable(this)) + color = hovered ? colors.focusableNonValuableHovered : colors.focusableNonValuable; + else + color = hovered ? colors.normalHovered : colors.normal; const auto mainVP = ImGui::GetMainViewport(); - const auto draw_list = hovered ? ImGui::GetForegroundDrawList(mainVP) : ImGui::GetBackgroundDrawList(mainVP); + const auto draw_list = examined ? ImGui::GetForegroundDrawList(mainVP) : ImGui::GetBackgroundDrawList(mainVP); draw_list->AddRect((const ImVec2&)rect.lt, (const ImVec2&)rect.rb, color.get_windows()); } diff --git a/src/xrUICore/ui_debug.cpp b/src/xrUICore/ui_debug.cpp index 42f44f8d550..c68221b80d8 100644 --- a/src/xrUICore/ui_debug.cpp +++ b/src/xrUICore/ui_debug.cpp @@ -2,6 +2,7 @@ #include "ui_debug.h" #include "ui_base.h" +#include "xrEngine/editor_helper.h" CUIDebuggable::~CUIDebuggable() { @@ -57,6 +58,7 @@ CUIDebugger::CUIDebugger() } ); ImGui::SetCurrentContext(Device.GetImGuiContext()); + reset_settings(); } void CUIDebugger::on_tool_frame() @@ -65,16 +67,45 @@ void CUIDebugger::on_tool_frame() if (!get_open_state()) return; + using namespace xray; + if (ImGui::Begin(tool_name(), &get_open_state(), get_default_window_flags())) { if (ImGui::BeginMenuBar()) { - ImGui::Checkbox("Draw rects", &m_state.drawWndRects); - - ImGui::BeginDisabled(!m_state.drawWndRects); - ImGui::Checkbox("Coloured rects", &m_state.coloredRects); - ImGui::EndDisabled(); + ImGui::Checkbox("Draw rects", &m_state.settings.drawWndRects); + if (ImGui::BeginMenu("Options")) + { + ImGui::Checkbox("Randomly coloured rects", &m_state.settings.coloredRects); + + ImGui::Text(""); + ImGui::Text("Rect colouring:"); + + auto& colors = m_state.settings.colors; + + imgui::ColorEdit4("Normal", colors.normal); + imgui::ItemHelp("Just a normal window"); + imgui::ColorEdit4("Normal hovered", colors.normalHovered); + imgui::ItemHelp("Just a normal window hovered by in-game cursor"); + imgui::ColorEdit4("Examined", colors.examined); + imgui::ItemHelp("A window that is hovered here, in the tree of the UI Debugger"); + imgui::ColorEdit4("Focused", colors.focused); + imgui::ItemHelp("Window currectly selected in the focus system"); + + ImGui::BeginDisabled(m_state.settings.coloredRects); + imgui::ColorEdit4("Valuable focusable", colors.focusableValuable); + imgui::ItemHelp("Window that is currently valuable in the focus system"); + imgui::ColorEdit4("Valuable focusable hovered", colors.focusableValuableHovered); + imgui::ItemHelp("Valuable window hovered by in-game cursor"); + imgui::ColorEdit4("Non valuable focusable", colors.focusableNonValuable); + imgui::ItemHelp("Window that is currently non-valuable in the focus system"); + imgui::ColorEdit4("Non valuable focusable hovered", colors.focusableNonValuableHovered); + imgui::ItemHelp("Non-valuable window hovered by in-game cursor"); + ImGui::EndDisabled(); + + ImGui::EndMenu(); + } ImGui::EndMenuBar(); } @@ -105,3 +136,109 @@ void CUIDebugger::on_tool_frame() ImGui::End(); #endif } + +void CUIDebugger::reset_settings() +{ + CUIDebuggerSettings settings + { + { + /*.normal =*/ color_rgba(0, 0, 255, 200), + /*.normalHovered =*/ color_rgba(0, 0, 255, 255), + /*.examined =*/ color_rgba(0, 255, 255, 255), + /*.focused =*/ color_rgba(255, 215, 0, 255), + /*.focusableValuable =*/ color_rgba(0, 255, 0, 200), + /*.focusableValuableHovered =*/ color_rgba(0, 255, 0, 255), + /*.focusableNonValuable =*/ color_rgba(255, 0, 0, 200), + /*.focusableNonValuableHovered =*/ color_rgba(255, 0, 0, 255), + }, + /*.drawWndRects =*/ true, + /*.coloredRects =*/ false, + }; + m_state.settings = settings; +} + +void CUIDebugger::apply_setting(pcstr line) +{ + auto& settings = m_state.settings; + + int i{}; + u32 color{}; + + if (sscanf(line, "ColoredRects=%d", &i) == 1) + settings.coloredRects = i != 0; + else if (sscanf(line, "NormalColor=0x%X", &color) == 1) + settings.colors.normal = color; + else if (sscanf(line, "NormalHoveredColor=0x%X", &color) == 1) + settings.colors.normalHovered = color; + else if (sscanf(line, "ExaminedColor=0x%X", &color) == 1) + settings.colors.examined = color; + else if (sscanf(line, "FocusedColor=0x%X", &color) == 1) + settings.colors.focused = color; + else if (sscanf(line, "FocusableValuableColor=0x%X", &color) == 1) + settings.colors.focusableValuable = color; + else if (sscanf(line, "FocusableValuableHoveredColor=0x%X", &color) == 1) + settings.colors.focusableValuableHovered = color; + else if (sscanf(line, "FocusableNonValuableColor=0x%X", &color) == 1) + settings.colors.focusableNonValuable = color; + else if (sscanf(line, "FocusableNonValuableHoveredColor=0x%X", &color) == 1) + settings.colors.focusableNonValuableHovered = color; +} + +void CUIDebugger::save_settings(ImGuiTextBuffer* buffer) const +{ + R_ASSERT1_CURE(buffer, return); + + const auto& settings = m_state.settings; + const auto& colors = settings.colors; + + buffer->appendf("ColoredRects=%d\n", settings.coloredRects); + buffer->appendf("NormalColor=0x%X\n", colors.normal); + buffer->appendf("NormalHoveredColor=0x%X\n", colors.normalHovered); + buffer->appendf("ExaminedColor=0x%X\n", colors.examined); + buffer->appendf("FocusedColor=0x%X\n", colors.focused); + buffer->appendf("FocusableValuableColor=0x%X\n", colors.focusableValuable); + buffer->appendf("FocusableValuableHoveredColor=0x%X\n", colors.focusableValuableHovered); + buffer->appendf("FocusableNonValuableColor=0x%X\n", colors.focusableNonValuable); + buffer->appendf("FocusableNonValuableHoveredColor=0x%X\n", colors.focusableNonValuableHovered); +} + +size_t CUIDebugger::estimate_settings_size() const +{ + // Additional space for '\n' will be also reserved + // because std::size also counts '\0' + + constexpr size_t NUMBER_SIZE = 1; // number serving as bool + constexpr size_t HEXNUMBER_SIZE = 8; // 8 for the 32-bit value in hexadecimal format + + // Count bytes for each line + size_t size = 0; + + // "ColoredRects=%d\n" + size += std::size("ColoredRects=") + NUMBER_SIZE; + + // "NormalColor=0x%X\n" + size += std::size("NormalColor=0x") + HEXNUMBER_SIZE; + + // "NormalHoveredColor=0x%X\n" + size += std::size("NormalHoveredColor=0x") + HEXNUMBER_SIZE; + + // "ExaminedColor=0x%X\n" + size += std::size("ExaminedColor=0x") + HEXNUMBER_SIZE; + + // "FocusedColor=0x%X\n" + size += std::size("FocusedColor=0x") + HEXNUMBER_SIZE; + + // "FocusableValuableColor=0x%X\n" + size += std::size("FocusableValuableColor=0x") + HEXNUMBER_SIZE; + + // "FocusableValuableHoveredColor=0x%X\n" + size += std::size("FocusableValuableHoveredColor=0x") + HEXNUMBER_SIZE; + + // "FocusableNonValuableColor=0x%X\n" + size += std::size("FocusableNonValuableColor=0x") + HEXNUMBER_SIZE; + + // "FocusableNonValuableHoveredColor=0x%X\n" + size += std::size("FocusableNonValuableHoveredColor=0x") + HEXNUMBER_SIZE; + + return size; +} diff --git a/src/xrUICore/ui_debug.h b/src/xrUICore/ui_debug.h index 5e0ed84050e..fd92007be6f 100644 --- a/src/xrUICore/ui_debug.h +++ b/src/xrUICore/ui_debug.h @@ -18,12 +18,38 @@ class XR_NOVTABLE XRUICORE_API CUIDebuggable inline pcstr CUIDebuggable::GetDebugType() { return "CUIDebuggable"; } +struct CUIDebuggerSettings +{ + struct + { + // Just a window + u32 normal; + // Just a window hovered by in-game cursor + u32 normalHovered; + // Any window that is hovered in the ImGui UI Debugger window + u32 examined; + // Window selected in the focus system + u32 focused; + // Window that is currently valuable in the focus system + u32 focusableValuable; + // Valuable window hovered by in-game cursor + u32 focusableValuableHovered; + // Window that is currently non-valuable in the focus system + u32 focusableNonValuable; + // Non-valuable window hovered by in-game cursor + u32 focusableNonValuableHovered; + } colors; + + bool drawWndRects; + bool coloredRects; +}; + struct CUIDebugState { CUIDebuggable* selected{}; mutable CUIDebuggable* newSelected{}; - bool drawWndRects{ true }; - bool coloredRects{ true }; + + CUIDebuggerSettings settings; void select(CUIDebuggable* debuggable) const { @@ -52,8 +78,13 @@ class XRUICORE_API CUIDebugger final : public xray::editor::ide_tool void SetSelected(CUIDebuggable* debuggable); [[nodiscard]] - bool ShouldDrawRects() const { return m_state.drawWndRects; } + bool ShouldDrawRects() const { return m_state.settings.drawWndRects; } private: pcstr tool_name() const override { return "UI Debugger"; } + + void reset_settings() override; + void apply_setting(pcstr line) override; + void save_settings(ImGuiTextBuffer* buffer) const override; + size_t estimate_settings_size() const override; };