From 4dc3f9e03382b0ced99abb1eb79006dc58e41dcd Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 19 Sep 2025 18:21:57 +0200 Subject: [PATCH] build: Update ImGui Test Engine --- .../include/imgui_te_context.h | 7 +- .../include/imgui_te_internal.h | 1 + .../source/imgui_te_context.cpp | 71 ++++++++++++++++++- .../source/imgui_te_engine.cpp | 5 +- .../imgui_test_engine/source/imgui_te_ui.cpp | 30 ++++++-- .../source/imgui_te_utils.cpp | 2 - main/gui/source/window/window.cpp | 2 +- 7 files changed, 103 insertions(+), 15 deletions(-) diff --git a/lib/third_party/imgui/imgui_test_engine/include/imgui_te_context.h b/lib/third_party/imgui/imgui_test_engine/include/imgui_te_context.h index 2aaab4466..81901cc09 100644 --- a/lib/third_party/imgui/imgui_test_engine/include/imgui_te_context.h +++ b/lib/third_party/imgui/imgui_test_engine/include/imgui_te_context.h @@ -157,6 +157,7 @@ struct IMGUI_API ImGuiTestGenericItemStatus { int RetValue; // return value int Hovered; // result of IsItemHovered() + int HoveredAllowDisabled; // result of IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) int Active; // result of IsItemActive() int Focused; // result of IsItemFocused() int Clicked; // result of IsItemClicked() @@ -169,7 +170,7 @@ struct IMGUI_API ImGuiTestGenericItemStatus ImGuiTestGenericItemStatus() { Clear(); } void Clear() { memset(this, 0, sizeof(*this)); } void QuerySet(bool ret_val = false) { Clear(); QueryInc(ret_val); } - void QueryInc(bool ret_val = false) { RetValue += ret_val; Hovered += ImGui::IsItemHovered(); Active += ImGui::IsItemActive(); Focused += ImGui::IsItemFocused(); Clicked += ImGui::IsItemClicked(); Visible += ImGui::IsItemVisible(); Edited += ImGui::IsItemEdited(); Activated += ImGui::IsItemActivated(); Deactivated += ImGui::IsItemDeactivated(); DeactivatedAfterEdit += ImGui::IsItemDeactivatedAfterEdit(); } + void QueryInc(bool ret_val = false) { RetValue += ret_val; Hovered += ImGui::IsItemHovered(); HoveredAllowDisabled += ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled); Active += ImGui::IsItemActive(); Focused += ImGui::IsItemFocused(); Clicked += ImGui::IsItemClicked(); Visible += ImGui::IsItemVisible(); Edited += ImGui::IsItemEdited(); Activated += ImGui::IsItemActivated(); Deactivated += ImGui::IsItemDeactivated(); DeactivatedAfterEdit += ImGui::IsItemDeactivatedAfterEdit(); } void Draw() { ImGui::Text("Ret: %d, Hovered: %d, Active: %d, Focused: %d\nClicked: %d, Visible: %d, Edited: %d\nActivated: %d, Deactivated: %d, DeactivatedAfterEdit: %d", RetValue, Hovered, Active, Focused, Clicked, Visible, Edited, Activated, Deactivated, DeactivatedAfterEdit); } }; @@ -187,6 +188,7 @@ struct IMGUI_API ImGuiTestGenericVars ImGuiWindowFlags WindowFlags; ImGuiTableFlags TableFlags; ImGuiPopupFlags PopupFlags; + ImGuiInputTextFlags InputTextFlags; ImGuiTestGenericItemStatus Status; bool ShowWindow1, ShowWindow2; bool UseClipper; @@ -400,6 +402,9 @@ struct IMGUI_API ImGuiTestContext void ScrollToY(ImGuiTestRef ref, float scroll_y) { ScrollTo(ref, ImGuiAxis_Y, scroll_y); } void ScrollToTop(ImGuiTestRef ref); void ScrollToBottom(ImGuiTestRef ref); + void ScrollToPos(ImGuiTestRef window_ref, float pos_v, ImGuiAxis axis, ImGuiTestOpFlags flags = ImGuiTestOpFlags_None); + void ScrollToPosX(ImGuiTestRef window_ref, float pos_x); + void ScrollToPosY(ImGuiTestRef window_ref, float pos_y); void ScrollToItem(ImGuiTestRef ref, ImGuiAxis axis, ImGuiTestOpFlags flags = ImGuiTestOpFlags_None); void ScrollToItemX(ImGuiTestRef ref); void ScrollToItemY(ImGuiTestRef ref); diff --git a/lib/third_party/imgui/imgui_test_engine/include/imgui_te_internal.h b/lib/third_party/imgui/imgui_test_engine/include/imgui_te_internal.h index b8543425c..a3ee790de 100644 --- a/lib/third_party/imgui/imgui_test_engine/include/imgui_te_internal.h +++ b/lib/third_party/imgui/imgui_test_engine/include/imgui_te_internal.h @@ -156,6 +156,7 @@ struct ImGuiTestEngine ImGuiContext* UiContextActive = nullptr; // imgui context for testing == UiContextTarget or nullptr bool Started = false; + bool UiContextHasHooks = false; ImU64 BatchStartTime = 0; ImU64 BatchEndTime = 0; int FrameCount = 0; diff --git a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_context.cpp b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_context.cpp index 6d305c7ae..9234ef9c1 100644 --- a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_context.cpp +++ b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_context.cpp @@ -936,6 +936,9 @@ static void ItemInfoErrorLog(ImGuiTestContext* ctx, ImGuiTestRef ref, ImGuiID fu if (flags & ImGuiTestOpFlags_NoError) return; + if (ctx->Engine->UiContextHasHooks == false) + IM_ERRORF_NOHDR("%s", "IMGUI DOES NOT SEEM COMPILED WITH '#define IMGUI_ENABLE_TEST_ENGINE'!\nMAKE SURE THAT BOTH 'imgui' AND 'imgui_test_engine' ARE USING THE SAME 'imconfig' FILE."); + // Prefixing the string with / ignore the reference/current ID Str256 msg; if (ref.Path && ref.Path[0] == '/' && ctx->RefStr[0] != 0) @@ -1412,6 +1415,39 @@ void ImGuiTestContext::ScrollTo(ImGuiTestRef ref, ImGuiAxis axis, float scrol Yield(); } +// Supported values for ImGuiTestOpFlags: +// - ImGuiTestOpFlags_NoFocusWindow +void ImGuiTestContext::ScrollToPos(ImGuiTestRef window_ref, float pos_v, ImGuiAxis axis, ImGuiTestOpFlags flags) +{ + if (IsError()) + return; + + IMGUI_TEST_CONTEXT_REGISTER_DEPTH(this); + LogDebug("ScrollToPos %c %.2f", 'X' + axis, pos_v); + + // Ensure window size and ScrollMax are up-to-date + Yield(); + + ImGuiWindow* window = GetWindowByRef(window_ref); + IM_CHECK_SILENT(window != NULL); + float item_curr = pos_v; + float item_target = ImFloor(window->InnerClipRect.GetCenter()[axis]); + float scroll_delta = item_target - item_curr; + float scroll_target = ImClamp(window->Scroll[axis] - scroll_delta, 0.0f, window->ScrollMax[axis]); + + ScrollTo(window->ID, axis, scroll_target, (flags & ImGuiTestOpFlags_NoFocusWindow)); +} + +void ImGuiTestContext::ScrollToPosX(ImGuiTestRef window_ref, float pos_x) +{ + ScrollToPos(window_ref, pos_x, ImGuiAxis_X); +} + +void ImGuiTestContext::ScrollToPosY(ImGuiTestRef window_ref, float pos_y) +{ + ScrollToPos(window_ref, pos_y, ImGuiAxis_Y); +} + // Supported values for ImGuiTestOpFlags: // - ImGuiTestOpFlags_NoFocusWindow void ImGuiTestContext::ScrollToItem(ImGuiTestRef ref, ImGuiAxis axis, ImGuiTestOpFlags flags) @@ -3599,6 +3635,10 @@ void ImGuiTestContext::ComboClick(ImGuiTestRef ref) Str128f combo_item_buf = Str128f("//%s/**/%s", popup->Name, p + 1); ItemClick(combo_item_buf.c_str()); + + // For if Combo Selectables uses ImGuiSelectableFlags_NoAutoClosePopups + if (GetWindowByRef("//$FOCUSED") == popup) + KeyPress(ImGuiKey_Enter); } void ImGuiTestContext::ComboClickAll(ImGuiTestRef ref_parent) @@ -3617,6 +3657,10 @@ void ImGuiTestContext::ComboClickAll(ImGuiTestRef ref_parent) ItemClick(ref_parent); ItemClick(item.ID); } + + // For if Combo Selectables uses ImGuiSelectableFlags_NoAutoClosePopups + if (GetWindowByRef("//$FOCUSED") == popup) + KeyPress(ImGuiKey_Enter); } static ImGuiTableColumn* HelperTableFindColumnByName(ImGuiTable* table, const char* name) @@ -3641,7 +3685,18 @@ void ImGuiTestContext::TableOpenContextMenu(ImGuiTestRef ref, int column_n) if (column_n == -1) column_n = table->RightMostEnabledColumn; - ItemClick(TableGetHeaderID(table, column_n), ImGuiMouseButton_Right); + + IM_CHECK(column_n >= 0 && column_n <= table->ColumnsCount); + ImGuiTableColumn* column = &table->Columns[column_n]; + IM_CHECK_SILENT(column->IsEnabled); + + ImGuiID header_id = TableGetHeaderID(table, column_n); + + // Make visible + if (!ItemExists(header_id)) + ScrollToPosX(table->InnerWindow->ID, (column->MinX + column->MaxX) * 0.5f); + + ItemClick(header_id, ImGuiMouseButton_Right); Yield(); } @@ -3658,7 +3713,13 @@ ImGuiSortDirection ImGuiTestContext::TableClickHeader(ImGuiTestRef ref, const ch if (key_mods != ImGuiMod_None) KeyDown(key_mods); - ItemClick(TableGetHeaderID(table, label), ImGuiMouseButton_Left); + ImGuiID header_id = TableGetHeaderID(table, label); + + // Make visible + if (!ItemExists(header_id)) + ScrollToPosX(table->InnerWindow->ID, (column->MinX + column->MaxX) * 0.5f); + + ItemClick(header_id, ImGuiMouseButton_Left); if (key_mods != ImGuiMod_None) KeyUp(key_mods); @@ -3674,7 +3735,11 @@ void ImGuiTestContext::TableSetColumnEnabled(ImGuiTestRef ref, const char* label ImGuiTestRefDesc desc(ref); LogDebug("TableSetColumnEnabled %s label '%s' enabled = %d", desc.c_str(), label, enabled); - TableOpenContextMenu(ref); + ImGuiTable* table = ImGui::TableFindByID(GetID(ref)); + IM_CHECK_SILENT(table != NULL); + ImGuiTableColumn* column = HelperTableFindColumnByName(table, label); + int column_n = column->IsEnabled ? table->Columns.index_from_ptr(column) : -1; + TableOpenContextMenu(ref, column_n); ImGuiTestRef backup_ref = GetRef(); SetRef("//$FOCUSED"); diff --git a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_engine.cpp b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_engine.cpp index a7f75a54e..acc148e2f 100644 --- a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_engine.cpp +++ b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_engine.cpp @@ -197,6 +197,7 @@ void ImGuiTestEngine_BindImGuiContext(ImGuiTestEngine* engine, ImGuiContext* ui_ GImGuiTestEngine = engine; IM_ASSERT(ui_ctx->TestEngine == nullptr); ui_ctx->TestEngine = engine; + engine->UiContextHasHooks = false; } void ImGuiTestEngine_UnbindImGuiContext(ImGuiTestEngine* engine, ImGuiContext* ui_ctx) @@ -230,6 +231,7 @@ void ImGuiTestEngine_UnbindImGuiContext(ImGuiTestEngine* engine, ImGuiContext // Create test context (not bound to any dear imgui context yet) ImGuiTestEngine* ImGuiTestEngine_CreateContext() { + IMGUI_CHECKVERSION(); // <--- If you get a crash here: mismatching config, check that both imgui and imgui_test_engine are using same defines (e.g. using the same imconfig file) ImGuiTestEngine* engine = IM_NEW(ImGuiTestEngine)(); return engine; } @@ -1901,7 +1903,7 @@ void ImGuiTestEngine_RunTest(ImGuiTestEngine* engine, ImGuiTestContext* parent_c // Additional yields to avoid consecutive tests who may share identifiers from missing their window/item activation. ctx->RunFlags |= ImGuiTestRunFlags_GuiFuncDisable; - ctx->Yield(2); + ctx->Yield(3); // Restore active func ctx->ActiveFunc = backup_active_func; @@ -2177,6 +2179,7 @@ static void ImGuiTestEngineHook_ItemAdd_GatherTask(ImGuiContext* ui_ctx, ImGuiTe void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ui_ctx, ImGuiID id, const ImRect& bb, const ImGuiLastItemData* item_data) { ImGuiTestEngine* engine = (ImGuiTestEngine*)ui_ctx->TestEngine; + engine->UiContextHasHooks = true; IM_ASSERT(id != 0); ImGuiContext& g = *ui_ctx; diff --git a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_ui.cpp b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_ui.cpp index fdde871fc..5d493746c 100644 --- a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_ui.cpp +++ b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_ui.cpp @@ -271,7 +271,7 @@ static void TestStatusButton(const char* id, const ImVec4& color, bool running, } } -static void ShowTestGroup(ImGuiTestEngine* e, ImGuiTestGroup group, Str* filter) +static void ShowTestGroup(ImGuiTestEngine* e, ImGuiTestGroup group, Str* filter, bool run) { ImGuiStyle& style = ImGui::GetStyle(); ImGuiIO& io = ImGui::GetIO(); @@ -285,14 +285,14 @@ static void ShowTestGroup(ImGuiTestEngine* e, ImGuiTestGroup group, Str* filter) //ImGui::Text("TESTS (%d)", engine->TestsAll.Size); #if IMGUI_VERSION_NUM >= 19066 ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip | ImGuiInputFlags_RouteFromRootWindow); - bool run = ImGui::Button("Run"); + run |= ImGui::Button("Run"); #elif IMGUI_VERSION_NUM >= 18837 - bool run = ImGui::Button("Run") || ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_R); + run |= ImGui::Button("Run") || ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_R); #if IMGUI_VERSION_NUM > 18963 ImGui::SetItemTooltip("Ctrl+R"); #endif #else - bool run = ImGui::Button("Run"); + run |= ImGui::Button("Run"); #endif if (run) { @@ -652,7 +652,13 @@ static void ImGuiTestEngine_ShowLogAndTools(ImGuiTestEngine* engine) { ImGuiIO& io = ImGui::GetIO(); ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); - ImGui::Text("TestEngine: HookItems: %d, HookPushId: %d, InfoTasks: %d", g.TestEngineHookItems, g.DebugHookIdInfo != 0, engine->InfoTasks.Size); + ImGui::Text("TestEngine: HookItems: %d, HookPushId: %d, InfoTasks: %d", g.TestEngineHookItems, +#if IMGUI_VERSION_NUM < 19229 + g.DebugHookIdInfo != 0, +#else + g.DebugHookIdInfoId != 0, +#endif + engine->InfoTasks.Size); ImGui::Separator(); if (ImGui::Button("Reboot UI context")) @@ -739,8 +745,18 @@ static void ImGuiTestEngine_ShowTestTool(ImGuiTestEngine* engine, bool* p_open) return; } + bool run = false; if (ImGui::BeginMenuBar()) { + if (ImGui::BeginMenu("Tests")) + { + // FIXME: This idiom showcases an issue with menus vs shortcuts. Would be nice if e.g. we could activate a shortcut? + run = ImGui::MenuItem("Run Visible", "Ctrl+R"); + ImGui::MenuItem("Filter", "Ctrl+F"); + if (p_open != NULL && ImGui::MenuItem("Close")) + *p_open = false; + ImGui::EndMenu(); + } if (ImGui::BeginMenu("Tools")) { ImGuiContext& g = *GImGui; @@ -824,12 +840,12 @@ static void ImGuiTestEngine_ShowTestTool(ImGuiTestEngine* engine, bool* p_open) { if (ImGui::BeginTabItem("TESTS", nullptr, ImGuiTabItemFlags_NoPushId)) { - ShowTestGroup(engine, ImGuiTestGroup_Tests, engine->UiFilterTests); + ShowTestGroup(engine, ImGuiTestGroup_Tests, engine->UiFilterTests, run); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("PERFS", nullptr, ImGuiTabItemFlags_NoPushId)) { - ShowTestGroup(engine, ImGuiTestGroup_Perfs, engine->UiFilterPerfs); + ShowTestGroup(engine, ImGuiTestGroup_Perfs, engine->UiFilterPerfs, run); ImGui::EndTabItem(); } ImGui::EndTabBar(); diff --git a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_utils.cpp b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_utils.cpp index e5ae38ccf..1b4910f79 100644 --- a/lib/third_party/imgui/imgui_test_engine/source/imgui_te_utils.cpp +++ b/lib/third_party/imgui/imgui_test_engine/source/imgui_te_utils.cpp @@ -16,9 +16,7 @@ #if defined(_WIN32) #if !defined(_WINDOWS_) -#if !defined(WIN32_LEAN_AND_MEAN) #define WIN32_LEAN_AND_MEAN -#endif #include #endif #include // ShellExecuteA() diff --git a/main/gui/source/window/window.cpp b/main/gui/source/window/window.cpp index ddf6f7194..4fbfeeffc 100644 --- a/main/gui/source/window/window.cpp +++ b/main/gui/source/window/window.cpp @@ -1266,7 +1266,7 @@ namespace hex { #if defined(IMGUI_TEST_ENGINE) m_testEngine = ImGuiTestEngine_CreateContext(); - auto testEngineIo = ImGuiTestEngine_GetIO(m_testEngine); + auto &testEngineIo = ImGuiTestEngine_GetIO(m_testEngine); testEngineIo.ConfigVerboseLevel = ImGuiTestVerboseLevel_Info; testEngineIo.ConfigVerboseLevelOnError = ImGuiTestVerboseLevel_Debug;