Skip to content

Commit

Permalink
Added AddDockableWindow() / RemoveDockableWindow()
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Sep 18, 2024
1 parent 2dedc94 commit 4f58c7b
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 26 deletions.
8 changes: 8 additions & 0 deletions src/hello_imgui/doc_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,14 @@ void SwitchLayout(const std::string& layoutName);

// `CurrentLayoutName()`: returns the name of the current layout
std::string CurrentLayoutName();

// `AddDockableWindow()`: will add a dockable window to the current layout.
// Will dock the window to the dockspace it belongs to.
void AddDockableWindow(const DockableWindow& dockableWindow);

// `RemoveDockableWindow()`: will remove a dockable window from the current layout.
void RemoveDockableWindow(const std::string& dockableWindowName);

```
----
Expand Down
2 changes: 1 addition & 1 deletion src/hello_imgui/doc_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,7 @@ struct DockableWindow
{
// --------------- Main params -------------------
// `label`: _string_. Title of the window.
// `label`: _string_. Title of the window. It should be unique! Use "##" to add a unique suffix if needed.
std::string label;
// `dockSpaceName`: _DockSpaceName (aka string)_.
Expand Down
2 changes: 1 addition & 1 deletion src/hello_imgui/docking_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ struct DockableWindow
{
// --------------- Main params -------------------

// `label`: _string_. Title of the window.
// `label`: _string_. Title of the window. It should be unique! Use "##" to add a unique suffix if needed.
std::string label;

// `dockSpaceName`: _DockSpaceName (aka string)_.
Expand Down
8 changes: 8 additions & 0 deletions src/hello_imgui/hello_imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ void SwitchLayout(const std::string& layoutName);

// `CurrentLayoutName()`: returns the name of the current layout
std::string CurrentLayoutName();

// `AddDockableWindow()`: will add a dockable window to the current layout.
// Will dock the window to the dockspace it belongs to.
void AddDockableWindow(const DockableWindow& dockableWindow);

// `RemoveDockableWindow()`: will remove a dockable window from the current layout.
void RemoveDockableWindow(const std::string& dockableWindowName);

// @@md


Expand Down
15 changes: 15 additions & 0 deletions src/hello_imgui/internal/backend_impls/abstract_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ bool ShouldRemoteDisplay();
// Encapsulated inside docking_details.cpp
void ShowThemeTweakGuiWindow_Static();

// Encapsulated inside docking_details.cpp
namespace AddDockableWindowHelper
{
void Callback_1_GuiRender();
void Callback_2_PreNewFrame();
}



struct AbstractRunnerStatics
{
Expand Down Expand Up @@ -1323,6 +1331,10 @@ void AbstractRunner::CreateFramesAndRender(bool insideReentrantCall)
fnLoadAdditionalFontDuringExecution_UserCallback(); // User callback
}

// Handle AddDockableWindow(): this call should be done before ImGui::NewFrame
if (!insideReentrantCall)
AddDockableWindowHelper::Callback_2_PreNewFrame();

if ((params.callbacks.PreNewFrame) && !insideReentrantCall)
params.callbacks.PreNewFrame();

Expand All @@ -1341,6 +1353,9 @@ void AbstractRunner::CreateFramesAndRender(bool insideReentrantCall)
fnDrawCustomBackgroundOrClearColor_UserCallback(); // User callback
}

// Handle AddDockableWindow(): this call should be done when ImGui is accepting widgets
AddDockableWindowHelper::Callback_1_GuiRender();

// iii/ At the end of the second frame, we measure the size of the widgets and use it as the application window size,
// if the user required auto size
// ==> Note: RenderGui() may measure the size of the window and resize it if mIdxFrame==1
Expand Down
99 changes: 99 additions & 0 deletions src/hello_imgui/internal/docking_details.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "hello_imgui/internal/functional_utils.h"
#include "imgui_internal.h"
#include <map>
#include <vector>
#include <cassert>
#include <optional>

Expand Down Expand Up @@ -608,4 +609,102 @@ std::optional<ImGuiID> DockingParams::dockSpaceIdFromName(const std::string& doc
}


// `AddDockableWindow()` implementation and helper
namespace AddDockableWindowHelper
{
// Adding dockable windows is a three-step process:
// - First, the user calls `AddDockableWindow()`: the dockable window is added to gDockableWindowsToAdd
// with the state `DockableWindowAdditionState::Waiting`
// - Then, in the first callback, the dockable window is added to ImGui as a dummy window:
// we call `ImGui::Begin()` and `ImGui::End()` to create the window, but we don't draw anything in it,
// then we call `ImGui::DockBuilderDockWindow()` to dock the window to the correct dockspace
// - Finally, in the second callback, the dockable window is added to HelloImGui::RunnerParams.dockingParams.dockableWindows

enum class DockableWindowAdditionState
{
Waiting,
AddedAsDummyToImGui,
AddedToHelloImGui
};

struct DockableWindowWaitingForAddition
{
DockableWindow dockableWindow;
DockableWindowAdditionState state = DockableWindowAdditionState::Waiting;
};

std::vector<DockableWindowWaitingForAddition> gDockableWindowsToAdd;

void AddDockableWindow(const DockableWindow& dockableWindow)
{
gDockableWindowsToAdd.push_back({dockableWindow, DockableWindowAdditionState::Waiting});
}

void Callback_1_GuiRender()
{
for (auto & dockableWindow: gDockableWindowsToAdd)
{
if (dockableWindow.state == DockableWindowAdditionState::Waiting)
{
ImGui::Begin(dockableWindow.dockableWindow.label.c_str());
ImGui::Dummy(ImVec2(10, 10));
ImGui::End();

auto dockId = HelloImGui::GetRunnerParams()->dockingParams.dockSpaceIdFromName(dockableWindow.dockableWindow.dockSpaceName);
if (dockId.has_value())
ImGui::DockBuilderDockWindow(dockableWindow.dockableWindow.label.c_str(), dockId.value());

dockableWindow.state = DockableWindowAdditionState::AddedAsDummyToImGui;
}
}
}

void Callback_2_PreNewFrame()
{
for (auto & dockableWindow: gDockableWindowsToAdd)
{
if (dockableWindow.state == DockableWindowAdditionState::AddedAsDummyToImGui)
{
HelloImGui::GetRunnerParams()->dockingParams.dockableWindows.push_back(dockableWindow.dockableWindow);
dockableWindow.state = DockableWindowAdditionState::AddedToHelloImGui;
}
}

// Remove the dockable windows that have been added to HelloImGui
gDockableWindowsToAdd.erase( // typical C++ shenanigans
std::remove_if(
gDockableWindowsToAdd.begin(),
gDockableWindowsToAdd.end(),
[](const DockableWindowWaitingForAddition& dockableWindow) {
return dockableWindow.state == DockableWindowAdditionState::AddedToHelloImGui;
}
),
gDockableWindowsToAdd.end()
);
}

} // namespace AddDockableWindowHelper


void AddDockableWindow(const DockableWindow& dockableWindow)
{
AddDockableWindowHelper::AddDockableWindow(dockableWindow);
}

void RemoveDockableWindow(const std::string& dockableWindowName)
{
auto& dockableWindows = HelloImGui::GetRunnerParams()->dockingParams.dockableWindows;
dockableWindows.erase(
std::remove_if(
dockableWindows.begin(),
dockableWindows.end(),
[&dockableWindowName](const DockableWindow& dockableWindow) {
return dockableWindow.label == dockableWindowName;
}
),
dockableWindows.end()
);
}


} // namespace HelloImGui
Original file line number Diff line number Diff line change
Expand Up @@ -178,26 +178,27 @@ void DemoHideWindow(AppState& appState)
}
}

// Display a button that will show an additional window
// Display a button that will add another dockable window during execution
void DemoShowAdditionalWindow(AppState& appState)
{
// Notes:
// - it is *not* possible to modify the content of the vector runnerParams.dockingParams.dockableWindows
// from the code inside a window's `GuiFunction` (since this GuiFunction will be called while iterating on this vector!)
// - there are two ways to dynamically add windows:
// * either make them initially invisible, and exclude them from the view menu (such as shown here)
// * or modify runnerParams.dockingParams.dockableWindows inside the callback RunnerCallbacks.PreNewFrame
// In order to add a dockable window during execution, you should use
// HelloImGui::AddDockableWindow()

// Note: you should not modify manually the content of the vector runnerParams.dockingParams.dockableWindows
// (since HelloImGui is constantly looping on it)
const char* windowName = "Additional Window";
ImGui::PushFont(appState.TitleFont->font); ImGui::Text("Dynamically add window"); ImGui::PopFont();
if (ImGui::Button("Show additional window"))
{
auto additionalWindowPtr = HelloImGui::GetRunnerParams()->dockingParams.dockableWindowOfName(windowName);
if (additionalWindowPtr)
{
// additionalWindowPtr->includeInViewMenu = true;
additionalWindowPtr->isVisible = true;
}
HelloImGui::DockableWindow additionalWindow;
additionalWindow.label = "Additional Window";
additionalWindow.includeInViewMenu = false; // this window is not shown in the view menu,
additionalWindow.rememberIsVisible = false; // its visibility is not saved in the settings file,
additionalWindow.dockSpaceName = "MiscSpace"; // when shown, it will appear in MiscSpace.
additionalWindow.GuiFunction = [] { ImGui::Text("This is the additional window"); };
HelloImGui::AddDockableWindow(additionalWindow);
}

if (ImGui::IsItemHovered())
ImGui::SetTooltip("By clicking this button, you can show an additional window");
}
Expand Down Expand Up @@ -729,16 +730,6 @@ std::vector<HelloImGui::DockableWindow> CreateDockableWindows(AppState& appState
dearImGuiDemoWindow.imGuiWindowFlags = ImGuiWindowFlags_MenuBar;
dearImGuiDemoWindow.GuiFunction = [] { ImGui::ShowDemoWindow(); };

// additionalWindow is initially not visible (and not mentioned in the view menu).
// it will be opened only if the user chooses to display it
HelloImGui::DockableWindow additionalWindow;
additionalWindow.label = "Additional Window";
additionalWindow.isVisible = false; // this window is initially hidden,
additionalWindow.includeInViewMenu = false; // it is not shown in the view menu,
additionalWindow.rememberIsVisible = false; // its visibility is not saved in the settings file,
additionalWindow.dockSpaceName = "MiscSpace"; // when shown, it will appear in BottomSpace.
additionalWindow.GuiFunction = [] { ImGui::Text("This is the additional window"); };

// alternativeThemeWindow
HelloImGui::DockableWindow alternativeThemeWindow;
// Since this window applies a theme, We need to call "ImGui::Begin" ourselves so
Expand All @@ -753,7 +744,6 @@ std::vector<HelloImGui::DockableWindow> CreateDockableWindows(AppState& appState
layoutCustomizationWindow,
logsWindow,
dearImGuiDemoWindow,
additionalWindow,
alternativeThemeWindow
};
return dockableWindows;
Expand Down

0 comments on commit 4f58c7b

Please sign in to comment.