veldrid / veldrid

A low-level, portable graphics library for .NET.
https://veldrid.dev/
MIT License
2.47k stars 268 forks source link

ImGui docking layout is not preserved #410

Open fenati opened 2 years ago

fenati commented 2 years ago

When I'm turning on docking support via ImGui.NET, the docking layout is not correctly preserved after I restarted my app. The problem is that the location, size, etc. of the ImGui windows are preserved but their docking state is not.

Basicly I'm doing something like this to turn on docking:

            imGuiRenderer = new ImGuiRenderer(
                graphicsDevice,
                framebuffer.OutputDescription,
                (int)framebuffer.Width,
                (int)framebuffer.Height);

            ...
            ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable;
            ...

I investigated the ImGuiRenderer's ctor and I think I see what's the problem.

The state of ImGui window is stored in the "imgui.ini" file - which is located at $(OutputDir) - and it seems that it stores the necessary docking data as expected.The problem is that this file is loaded automatically by the ImGuiRenderer constructor at the ImGui.NewFrame() line but the flag for docking support is not turned on at this point yet as that line of code is located after the call of ImGuiRenderer ctor. My first thought was to set the necessary flag for docking before calling the ImGuiRenderer ctor... However, that does not work as I get NullReferenceException for "ImGui.GetIO().ConfigFlags" since the ImGui.GetIO() method returns null if I call it before the ImGuiRenderer's ctor. I suppose that's because this method can be called only after calling the ImGui.SetCurrentContext(context) method. Since both ImGui.SetCurrentContext() and ImGui.NewFrame() methods are called inside the ctor, I cannot turn on the necessary flag for docking support in a way that preserves the docking states of windows.

Fortunately, I've found a workaround:

If I put these lines immediately after calling the ImGuiRenderer constructor, I can force reload the imgui.ini file after turning on he "DockingEnable" flag. With this small change the docking state is preserved properly.

            ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable;
            ImGui.LoadIniSettingsFromDisk(ImGui.GetIO().IniFilename);

However, this does not seem to be the cleanest solution as this way the ini file is processed twice (once by ImGui.NewFrame() and once by ImGui.LoadIniSettingsFromDisk())

I think maybe we'd need an overload for the ImGuiRenderer constructor where we could pass ImGuiConfigFlags parameter and the ctor could set the flags automatically based on this new parameter. Or maybe the ImGui.NewFrame() method should not be called automatically by the ctor to give more control over ImGui config for the end-user's code.

And by the way, thank you very much for these great libraries! Keep up the good work!

XorZy commented 2 years ago

I have encountered the same issue. I agree with fenati, the constructor probably should not call ImGui.NewFrame(), in order to let the user set all the desired flags before the first frame.