Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Seeking help on implementing and saving docking layouts #4033

Closed
pixtur opened this issue Apr 10, 2021 · 9 comments
Closed

Seeking help on implementing and saving docking layouts #4033

pixtur opened this issue Apr 10, 2021 · 9 comments
Labels
docking settings .ini persistance

Comments

@pixtur
Copy link

pixtur commented Apr 10, 2021

Version/Branch of Dear ImGui:

Version: 1.78
Branch: docking

Back-end/Renderer/Compiler/OS
Back-ends: imgui.et
Compiler: c# / .net
Operating System: win10

My Issue/Question:
In our application users can customize, save, and switch between different window layouts with the function keys. Since docking is now available in imgui.net I wanted to replace this early implementation with a proper window docking. The integration of the basic docking functionality worked great. I then tried to read the API description in #2109, the glossary and the wiki. I also tried to wrap my head around the API description in imgui.h but it seems to be missing some detail.

I'm looking for advice, documentation or example code on the following topics:

  1. I wasn't able to find a detailed description of how the docking layout is working, especially how a layout can be stored and restored. (We disabled imgui's .ini configuration and save the application state in our own configuration file). I have seen that I can use ImGui.SetNextWindowDockID() to attach a window to another DockingSpace, but I calling ImGui.GetWindowDockID() didn't yield into an ID that I can use with that method. How would i be able to also set things like splitting directions and child order?
  2. I wasn't able to setup a root DockSpace that fills the complete application window like illustrated in this example. Is there an example code to see which flags achieve this behaviour?

Screenshots/Video
This is how our layout systems looks currently:

T3.ImGui.Test.2021-04-10.17-45-40.mp4
@ocornut ocornut added docking settings .ini persistance labels Apr 11, 2021
@ocornut
Copy link
Owner

ocornut commented Apr 11, 2021

(We disabled imgui's .ini configuration and save the application state in our own configuration file

I don't know why you would need to do that. ini saving (to disk or text/memory) is where we store data including docking layout so that answers your question.

Since 1.77 you should be able to save/load ini data while the session is running. (#2573). It hasn't been exercised very widely, and #3215 seemingly had a problem (which contradicted my own research, suggesting there's another problem lurking ;) but it is something you can investigate.

The value returned by GetWindowDockID() does match value passed to SetNextWindowDockID() assuming the docking setup wasn't changed (matching identifiers).

How would i be able to also set things like splitting directions and child order?

Again this is all handled by the existing saving/loading functions so I would first question why you are not using them.

I wasn't able to setup a root DockSpace that fills the complete application window like illustrated in this example. Is there an example code to see which flags achieve this behaviour?

I'm not sure I understand your question. Your video seems to show a dockspace covering the entire viewport. Demo>Examples>Dockspace does that too. It is generally achieved by creating a window with pos/size matching the viewport and with WindowPadding set to 0,0, then emitting a DockSpace() inside.

@pixtur
Copy link
Author

pixtur commented Apr 13, 2021

The reason I'm not using the already existing save functionality is that I need to save (and restore) multiple docking layouts (potentially one for each function key). As far as I understood the .ini file feature, it only saves a single layout, and once the layout is locally modified, I can't restore it to a previously saved configuration.

Is there an API for saving and restoring multiple layouts? That would be perfect.

Demo>Examples>Dockspace does that too

Doh! I was looking for that in the examples folder. Found it!

The last time I tried, it wasn't possible to force a window to stay in the background. When focused or resized, it became the new foreground window covering other windows behind. Does this behaviour change with Docking?

PathogenDavid added a commit to PathogenDavid/imgui that referenced this issue Apr 14, 2021
@PathogenDavid
Copy link
Contributor

PathogenDavid commented Apr 14, 2021

The reason I'm not using the already existing save functionality is that I need to save (and restore) multiple docking layouts (potentially one for each function key). As far as I understood the .ini file feature, it only saves a single layout, and once the layout is locally modified, I can't restore it to a previously saved configuration.

Is there an API for saving and restoring multiple layouts? That would be perfect.

As noted in the issue Omar linked, you can use the settings API for this by managing them manually. I made a quick and dirty test demonstrating it here: PathogenDavid@8de138d

Launch example_win32_directx11 and press the function keys to swap between layouts. (The example doesn't persist the layouts, but you could add that pretty easily.)


Edit: Diff for posterity:

diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp
index d6378d80..a6459db1 100644
--- a/examples/example_win32_directx11/main.cpp
+++ b/examples/example_win32_directx11/main.cpp
@@ -6,6 +6,7 @@
 #include "imgui_impl_win32.h"
 #include "imgui_impl_dx11.h"
 #include <d3d11.h>
+#include <stdio.h>
 #include <tchar.h>
 
 // Data
@@ -14,6 +15,11 @@ static ID3D11DeviceContext*     g_pd3dDeviceContext = NULL;
 static IDXGISwapChain*          g_pSwapChain = NULL;
 static ID3D11RenderTargetView*  g_mainRenderTargetView = NULL;
 
+#define SAVED_LATYOUT_COUNT 12
+static char* saved_layouts[SAVED_LATYOUT_COUNT];
+static size_t saved_layout_sizes[SAVED_LATYOUT_COUNT];
+static int current_layout = 0;
+
 // Forward declarations of helper functions
 bool CreateDeviceD3D(HWND hWnd);
 void CleanupDeviceD3D();
@@ -114,6 +120,41 @@ int main(int, char**)
         if (done)
             break;
 
+        // Check if the user requested a layout change
+        unsigned int desired_layout = current_layout;
+        for (unsigned int i = 0; i < IM_ARRAYSIZE(saved_layouts); i++)
+        {
+            unsigned int key_code = VK_F1 + i;
+
+            if (io.KeysDown[key_code])
+            {
+                desired_layout = i;
+            }
+        }
+
+        if (desired_layout != current_layout)
+        {
+            printf("Changing layout F%d -> F%d\n", current_layout + 1, desired_layout + 1);
+
+            // Save the current layout
+            ImGui::MemFree((void*)saved_layouts[current_layout]);
+
+            size_t settings_size = 0;
+            const char* settings = ImGui::SaveIniSettingsToMemory(&settings_size);
+
+            saved_layouts[current_layout] = (char*)ImGui::MemAlloc(settings_size);
+            memcpy(saved_layouts[current_layout], settings, settings_size);
+            saved_layout_sizes[current_layout] = settings_size;
+
+            // Load the requested layout
+            // (Or if there is no layout in that slot, use the current layout for that slot.)
+            current_layout = desired_layout;
+            if (saved_layouts[current_layout] != nullptr)
+            {
+                ImGui::LoadIniSettingsFromMemory(saved_layouts[current_layout]);
+            }
+        }
+
         // Start the Dear ImGui frame
         ImGui_ImplDX11_NewFrame();
         ImGui_ImplWin32_NewFrame();
@@ -175,6 +216,13 @@ int main(int, char**)
     }
 
     // Cleanup
+    for (unsigned int i = 0; i < IM_ARRAYSIZE(saved_layouts); i++)
+    {
+        ImGui::MemFree(saved_layouts[i]);
+        saved_layouts[i] = nullptr;
+        saved_layout_sizes[i] = 0;
+    }
+
     ImGui_ImplDX11_Shutdown();
     ImGui_ImplWin32_Shutdown();
     ImGui::DestroyContext();

@ocornut
Copy link
Owner

ocornut commented Apr 14, 2021

Thanks David, given the valuable example I think you may paste it inline in your message so it is more likely to stay visible for future readers :)

Demo>Examples>Dockspace does that too
Doh! I was looking for that in the examples folder. Found it!

When searching for help I would suggest to always grep within the file system entirely:
Searching for DockSpace( those are the references I found in imgui_demo.cpp:

imgui_demo.cpp(293):    if (show_app_dockspace)           ShowExampleAppDockSpace(&show_app_dockspace);     // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments function)
imgui_demo.cpp(294):    if (show_app_documents)           ShowExampleAppDocuments(&show_app_documents);     // Process the Document app next, as it may also use a DockSpace()
imgui_demo.cpp(7461):// Demonstrate using DockSpace() to create an explicit docking node within an existing window.
imgui_demo.cpp(7464):// DockSpace() and DockSpaceOverViewport() are only useful to construct a central docking
imgui_demo.cpp(7503):    // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
imgui_demo.cpp(7509):    // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
imgui_demo.cpp(7527):        ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
imgui_demo.cpp(7561):            "This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main (e.g. with a menu bar)." "\n\n"
imgui_demo.cpp(7562):            "ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of ou'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n"
imgui_demo.cpp(7563):            "(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)"
imgui_demo.cpp(7794):            ImGui::DockSpace(dockspace_id);

Please note that examples/ are standalone applications aimed to showcase integration of Dear ImGui with different technology. All meaningful examples of actually using the API are in imgui_demo.cpp. I will tweak the docs to amplify this information.

There's also a function DockSpaceOverViewport() which in 90%+ use cases it sufficient and does everything with a single call.

The last time I tried, it wasn't possible to force a window to stay in the background.

The aforementioned example use ImGuiWindowFlags_NoBringToFrontOnFocus to achieve something like that.

@pixtur
Copy link
Author

pixtur commented Apr 14, 2021

@PathogenDavid thank your for the example. I think, I can manage from here.

When searching for help I would suggest to always grep within the file system entirely.

I am really sorry. I appreciate that your taking this time. Maybe rephrasing... "There are 2 new demos: Demo Window → Examples → Documents" into something like "The application menu of demo.cpp now includes two new examples" would help inattentive people like me.

@pixtur pixtur closed this as completed Apr 14, 2021
@ocornut
Copy link
Owner

ocornut commented Apr 14, 2021

Thanks Thomas. It's ok and it's good that we have some redundancy and extra cross-links and references on the GitHub, your questions are useful.

I think, I can manage from here.

As mentioned in #3215 it is possible you'll run into issues (which I couldn't repro). If you do and you think they are related you can comment in #3215.

Some tangential notes:

  • Since 1.83 WIP I'm adding docking/viewports related items to the Changelog in docking branch. Previously they were only mentioned in https://github.com/ocornut/imgui/releases. I am going to "backport" those changelog entries into the changelog.txt file to increase visibility of docking/viewport related changes.
  • The "There are 2 new demos: Demo Window → Examples → Documents" from the Docking thread is from 2018 and I admit I hadn't thought about updating this, but tweaked wording now.

@ocornut
Copy link
Owner

ocornut commented Apr 14, 2021

I am going to "backport" those changelog entries

Done 76902c4

@pixtur
Copy link
Author

pixtur commented Apr 14, 2021

One more note on documentation: I would personally prefer links/lists to useful references/issues/examples over incomplete wiki-pages like this one. Even though it spent many hours (trying to) reading the available documentation and examples, I'm always surprised how much is already possible with ImGui. Often things are not really evident to me (e.g. that there is an layout API for ini-files). And I struggle with questions of "is it possible" more frequently than "how is possible".

Crosslinking the documentation would really help me a lot.

@PathogenDavid
Copy link
Contributor

Thanks David, given the valuable example I think you may paste it inline in your message so it is more likely to stay visible for future readers :)

@ocornut I never delete branches, but not a bad idea. I added a diff for posterity.

thank your for the example. I think, I can manage from here.

@pixtur No problem, glad I could help!

Often things are not really evident to me (e.g. that there is an layout API for ini-files).

To be fair this isn't really the original intended purpose of these functions, but yeah it'd probably be helpful if the settings section of imgui.h mentioned that its primary purpose of the settings file is for persisting layout information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docking settings .ini persistance
Projects
None yet
Development

No branches or pull requests

3 participants