Feature Proposal: Add a Flag to Toggle Rendering Behavior (RenderInCurrentWindow = false by default)
Summary
Introduce a configurable flag, RenderInCurrentWindow, to control whether the test engine renders within the existing UI instead of creating a separate floating window. By default, this flag will be set to false, maintaining the current behavior.
Context
This proposal aims to introduce a configurable flag to allow developers to toggle whether the test engine renders inside the existing UI rather than opening a new window. This provides greater flexibility while maintaining backward compatibility by keeping the current behavior as the default.
Tag
Test Engine UI Configurable Flag Render In Current Window Not spawn new window for test engine
Motivation
In certain projects, developers may already have custom inspector tools integrated into their UI. For these cases, automatically spawning a new floating window for testing can be redundant or disruptive. Allowing the option to render within an existing window would provide better flexibility and a more seamless user experience.
Steps to reproduce
- Include the required libraries
#include "imgui_test_engine/imgui_te_ui.h"
#include "imgui_test_engine/imgui_te_engine.h"
#include "imgui_test_engine/imgui_te_context.h"
#include "imgui_test_engine/imgui_te_internal.h"
#include "imgui_test_engine/imgui_te_perftool.h"
- Create the current context
ImGuiTestEngine *e = HelloImGui::GetImGuiTestEngine();
bool *p_open = nullptr;
- Call the only known public function that display the test engine
ImGuiTestEngine_ShowTestEngineWindows(e, p_open);
- During the GUI rendering, you may add some tests to check the behaviour
if (ImGui::Button("Add new runtime test")) {
static int counter = 0;
++counter;
ImGuiTestEngine *engine = HelloImGui::GetImGuiTestEngine();
const std::string testname = ("test" + std::to_string(counter));
testSimple = IM_REGISTER_TEST(engine, "Runtime Tests", testname.c_str());
testSimple->GuiFunc = [](ImGuiTestContext *ctx) // Optionally provide a GUI function in addition to your application GUI
{
ImGui::Begin("Test Window", NULL, ImGuiWindowFlags_NoSavedSettings);
ImGui::Text("Hello, automation world");
ImGui::Button("Click Me");
if (ImGui::TreeNode("Node")) {
static bool b = false;
ImGui::Checkbox("Checkbox", &b);
ImGui::TreePop();
}
ImGui::End();
};
testSimple->TestFunc = [](ImGuiTestContext *ctx) // Generally provide a Test function which will drive the test.
{
ctx->SetRef("Test Window");
ctx->ItemClick("Click Me");
ctx->ItemOpen("Node"); // Optional as ItemCheck("Node/Checkbox") can do it automatically
ctx->ItemCheck("Node/Checkbox");
ctx->ItemUncheck("Node/Checkbox");
};
}
- You may also use RegisterTests from
hello_imgui, like this
auto TestCase() -> void
{
static ImGuiTest *testFirstScreenShot;
ImGuiTestEngine *engine = HelloImGui::GetImGuiTestEngine();
testFirstScreenShot = IM_REGISTER_TEST(engine, "Backend Tests", "First_Screenshot");
auto testFirstScreenShotFunc = [](ImGuiTestContext *ctx) {
ctx->CaptureScreenshot();
};
testFirstScreenShot->TestFunc = testFirstScreenShotFunc;
}
runner.callbacks.RegisterTests = TestCase();
Tradeoff
I think it has many applicable pros
- Improves workflow efficiency to people who prefer one-window workspace and let user combine with their own private inspector tools.
- Provides developers with greater control over UI integration and makes the test engine more adaptable to various UI structures.
- Reduces UI clutter for those who prefer an embedded approach and reduces window management overhead.
- Maintains backward compatibility by keeping
falseas the default behavior.
compare to its cons
- Add one more flag value (either 8 bit or 1 bit) auxiliary memory consumption
- May introduce new edge cases or require additional testing to ensure smooth integration.
- Ensuring that all related UI elements behave correctly in both modes (new window vs. current window) may require extra adjustments.
- While default value preserve common behaviours, certain projects relying on assumptions about window creation might need minor refactoring.
Proposal Solution
In imgui_te_internal.h
struct ImGuiTestEngine
{
// Others
...
// Inputs
...
// UI support
...
// Performance Monitor
...
// Screen/Video Capturing
...
// Tools
...
bool BackupConfigNoThrottle = false;
bool RenderInCurrentWindow = false; // add this line <------------------------
// Functions
...
}
Then in imgui_te_ui.cpp
ImGui::SetNextWindowSize(ImVec2(ImGui::GetFontSize() * 50, ImGui::GetFontSize() * 40), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Dear ImGui Test Engine", p_open, ImGuiWindowFlags_MenuBar))
{
ImGui::End();
return;
}
...
ImGui::End();
we change to become
if (!engine->RenderInCurrentWindow) {
ImGui::SetNextWindowSize(ImVec2(ImGui::GetFontSize() * 50, ImGui::GetFontSize() * 40), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Dear ImGui Test Engine", p_open, ImGuiWindowFlags_MenuBar))
{
ImGui::End();
return;
}
}
...
if (!engine->RenderInCurrentWindow) {
ImGui::End();
}
Alternative solutions
We can also use ImGui::BeginChild() instead of ignoring it completely
if (RenderInCurrentWindow)
{
ImGui::BeginChild("TestToolEmbedded");
}
else
{
if (!ImGui::Begin("Dear ImGui Test Engine", p_open, ImGuiWindowFlags_MenuBar))
{
ImGui::End();
return;
}
}
Instead of using a boolean, you may
- treat it as a string for Window name, with empty means no window, by default it is
- treat it as an enum of options
bool RenderInCurrentWindow = false;
ImGuiTestEngineName WindowName = "Dear ImGui Test Engine";
ImGuiTestEngineRenderOptions RenderOptions = ImGuiTestEngineRenderOptions::NewWindow;
the other options can be
enum class ImGuiTestEngineRenderOptions {
CurrentWindow, // everything rendered in current window, separated by separator
CurrentWindowTabbed, // same things, but tabbed for each of its tool
NewWindow, // everything rendered in a new window, separated by docks
NewWindowWithTabbed, // everything rendered in a new window, but separated by tabs
Custom, // define a custom VoidFunction to change the order of how it should be rendered
};
Futher Improvements
If it is appropriate, we can make it configurable at runtime via UI settings
- Adding an option in the settings menu so users can toggle
RenderInCurrentWindowwithout modifying code.
if (ImGui::Checkbox("Render in Current Window", &engine->RenderInCurrentWindow))
{
// Apply changes dynamically
}
- As mentioned ealier, use callback for custom rendering so the user can define the order of
imgui_tecombined with their own inspector tools.
using RenderFunction = std::function<void()>;
RenderFunction DefaultRenderFunction = []() { ... };
RenderFunction CustomRenderCallback = DefaultRenderFunction; // User-defined callback
Benchmarked Testing
With my System and Environment like this
- OS: Windows 11 Home Single Language 64bit (10.0, Build 22631)
- MSVC: C/C++ Optimizing Compiler Version 19.42.34436 for x86
- vscode: 1.96.4 (cd4ee3b1c348a13bafd8f9ad8060705f6d4b9cba x64)
- Git: git version 2.47.0.windows.2
- Github CLI: gh version 2.27.0 (2023-04-07)
I successfully tested imgui_te with bool RenderInCurrentWindow = false;
- Performance impact: None (too small to bring any undesirable effects)
- Memory impact: None (only consume one more byte of memory for the flags)
- Compatibility impact: None (things work just fine as before the changes, dependencies remained the same)
Before posting the issues, I have...
- Searched for similar feature requests regarding configurable rendering options.
- Explored alternative libraries such as hello_imgui and imm_app to determine if they support rendering within an existing window.
- Tested possible workarounds but found that they either required modifying core behavior or lacked flexibility.
- Exploit some APIs to see if I can enforce the behaviour to be inside current window.
- Asking chatgpt o1 pro, deepseek r1, perplexity, claude, github copilot, gemini, meta bot, grek, ... given certain knowledge about
imgui_teand its implementations - Literally devour (or to says, intergrate, mix, alternate, modify, ...) certain parts of original functions just to mimic the needed behaviours.
- Tested the solution and benchmark for performance to verified the impact of the change on UI performance and usability.
- Checked for related issues like https://github.com/ocornut/imgui_test_engine/issues?q=current%20window