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

Docking branch available for testing #2109

Open
ocornut opened this issue Oct 1, 2018 · 158 comments
Open

Docking branch available for testing #2109

ocornut opened this issue Oct 1, 2018 · 158 comments

Comments

@ocornut
Copy link
Owner

@ocornut ocornut commented Oct 1, 2018

I have pushed an experimental 'docking' branch:
https://github.com/ocornut/imgui/tree/docking
Effectively providing a long awaited official solution to the features discussed in #351 and #261.

TL;DR; You can benefit from good portion of docking features with no extra work or API call. Windows can be merged with each others, with or without partitioning the space.

Prefer creating separate New Issues for specific questions/issues, so they can more easily be closed when solved and not clutter this thread (which is already too big)

Please do not report issues without reading the 'Feedback' section of the next post and without reading the 'Contributing' document listed in there. The number of ambiguous, ill-formed questions and incomplete bug reports posted on this entire github is difficult to deal with. Thank you.

image

GIF (this is actually a gif from an older version which has some glitches, but you get the gist!)
20180809_docking

Quick demo

You may checkout docking and build one the example e.g. example_win32_dx11/ , example_glfw_opengl3, example_sdl_vulkan to test this. Head to Demo>Configuration to see the global configuration flags. Note that multi-viewports are enabled by default in those demo but only well tested under Windows. If you have issues with them you can disable them via the Demo>Configuration pane or by commenting out the line that sets ImGuiConfigFlags_ViewportsEnable in the main.cpp of your example. Docking is functional without multi-viewports enabled.

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 1, 2018

This is my second version of Docking (I developed a V1 during the year which didn't get released, and which I have completely scrapped, then a rebuilt a V2 from stratch. V2 has issues but is already very useful.). The development of this feature has been sponsored by Blizzard Entertainment and supporters on Patreon.

The current branch scheme is docking > viewport > master.
This is because docking is best used with multi-viewport enabled (also a Beta feature) and it is less maintenance for me to follow this arrangement. It is however possible that Docking features may eventually be merged into master before viewport features. Right now I am hoping that both Docking and Viewport would become stable and useful enough to constitute a 1.70 release, but that will depend on your feedback.

The basic design is based on what Visual Studio do. When creating an explicit DockSpace() node, there is a Central Node which is a node that doesn't fold even when empty (when nothing is docked into it). It also uses the remaining/available space.

I'm also working on various features to manipulate dock nodes programmatically allowing to replicate what Unreal Engine is doing (each top-level editor have its own layout, and layout are copied/forked on demand). Some of those features are currently only exposed in imgui_internal.h but will slowly make it into the public API (they currently need a bit of rework).

Preamble

UPDATING

  • This is unrelated to the docking branch, but please note that the contents of imgui.cpp files have been massively shuffled in imgui 1.64+1.65. If you have ANY modifications to imgui.cpp and you are updating from a version OLDER than 1.64, please read the release note for 1.64. Otherwise it should be safe and easy to update.
  • If you use this branch I would appreciate if you tried to update regularly or semi-regularly so you can provide feedback and help detect regression.
  • Some of the API are subject to change, but luckily the majority of stuff here uses no API. If you are not at ease with fixing for minor API changes from time to time, wait until this branch is more stable and come back e.g. a few months.
  • If you end up going back and forth between multiple branches, there are a few #define such as IMGUI_HAS_VIEWPORT and IMGUI_HAS_DOCK which you might use to keep user code compiling in multiple branches.

FEEDBACK

  • If it works for you, let me know! You can also post screenshot/video in #2265 showcasing your use of the docking system.
  • Feedback/issues/bug reports are super welcome. Please be aware that the docking system is (unfortunately) more complex than it looks like and it is easy to convey wrong or misleading information with written words. If you make a report, please be extra careful and thorough with your wording and try to provide detailed information, git hash, pseudo-code, repro, screenshots, copy of .ini file. It's very easy to be unable to understand or reproduce a bug. The order of actions matters. your persistent settings (.ini file) matters, the order of submission of windows and function calls matters, etc. One advice is that if you stumble on an assert/crash, save your callstack and make a copy of your ini file, this will make it easier for you to reproduce and describe your issue.
  • Please try to make a Minimal, Complete and Verifiable Example (MCVE) to demonstrate your problem. An ideal submission is code I can paste in one of the example app to reproduce the issue. It can be tedious but it is also very often the more efficient way to understand and communicate issues. If for some reason you can't provide precise information but you have an issue, feel free to post anyway with what you know. Please read Contributing and try to make an effort to describe things properly and be considerate of my workload.

CONFIGURATION

  • Set the master enable flag io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; to enable docking.
  • Option: io.ConfigDockingWithShift = true; [current default*] → Dock when holding SHIFT, click anywhere in a window and drop anywhere on another window. Less visually noisy because the docking overlay only appears when holding Shift. Tends to be suitable for applications with loose windows and lots of moving.
  • or: io.ConfigDockingWithShift = false; → Dock without holding SHIFT, drag from title bar, to title bar or drop nodes. Tends to be suitable for applications where the majority of windows will be always docked because moving floating window is rare and therefore the overlay is not visually noisy.

* the current default is a little unexpected and may be changed in the future. I would recommend that you try it before toggling the option.

DESIRABLE (NOT STRICTLY DOCKING) FEATURES TO ENABLE ALONG WITH DOCKING

Note: All of this is enabled if you try one of the standard examples e.g. example_win32_directx11/, example_glfw_opengl3/, example_glfw_vulkan/, etc. Those paragraphs are useful if you want to integrate docking in your own application with your own back-end.

  1. Mouse cursors
    Your back-end needs to honor the resizing mouse cursors (ImGui::GetMouseCursor() returning ImGuiMouseCursor_ResizeNS / ImGuiMouseCursor_ResizeEW). Most default back-ends are honoring this already, but if you have implemented your custom back-end, it would be preferable you add support for this. Without those cursors changes you will have less feedback when hovering the small splitter between docking nodes. See the back-ends in examples/ for reference code. Your back-end needs to set io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; to notify imgui that this is supported.

  2. Resizing windows from their edge.
    You'll probably also want to enable io.ConfigResizeWindowsFromEdges = true; to allow resizing windows from their edge, providing a more consistent experience between docked and floating windows. This is not currently enabled by default because of (1). When you hover the edge of a window, the most noticeable feedback is the change of mouse cursor. This will eventually be enabled by default when ImGuiBackendFlags_HasMouseCursors is set by the back-end.

  3. Multi-Viewports
    The Docking feature obviously works more nicely when multi-viewports are enabled (#1542), allowing you to take take anything outside the boundaries of your main OS window. Though it is not required, and Docking works without multi-viewports. You can play with viewports by compiling most of the examples/ app under Windows (with either viewport or docking branch). Depending on the back-end and/or VM, viewports appears to be broken under Linux, your help would be welcome if you are a Linux user.
    For your own application to support multi-viewport, please refer to #1542 + read the comments in imgui.h for ImGuiPlatformIO + read the main.cpp of the examples/ application and the platform and renderer example bindings (e.g. imgui_impl_win32.cpp + imgui_imgui_dx11.cpp).
    Please note that IF you enable viewports io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; the coordinate system changes to follow your OS natural coordinate system, so e.g. (0,0) will always be the top-left of your primary monitor under Windows, etc. If you are using any absolute coordinates when calling e.g. SetNextWindowPos(), you should use GetMainViewport()->Pos as a base position instead.
    If you are interested in enabling multi-viewports, be aware that unlike Docking which requires no changes in the bindings, the integration of Multi-Viewport into your back-end is a little complicated and involved.
    For reference: this is the showing the part that is handled by the multi-viewports feature: taking imgui windows out of your main os window (it is creating new os windows and graphical context on the fly. This is done using a single imgui context, you can drag and drop stuff between windows etc.):
    viewport_201810

(if you have any issue related to viewports please post in #1542)


Docking

The core Docking feature requires no new API. Whenever you are moving a window you can merge them into each others and split nodes. When io.ConfigDockingWithShift = true the docking happens when holding SHIFT (see the "Configuration" blurb above).

Merging windows:
docking_201810_base-01

You can play around with that anywhere in the demo, the merging of windows itself is super useful (even without any of the "splitting" feature usually associated to Docking).

Settings and docking trees are persisting and references are tracked under the hood so when you restore a window it should be where you expect it to be:

docking_201810_base-02

There are various useful subtleties and complications associated to the persistence model which are not conveyed in the GIF. I'm not going to detail everything right now, but basically if you have any feedback or issue, please report them (there WILL be issues).

If you have keyboard navigation enabled, you can use CTRL+Tab to cycle through windows with the keyboard:

ctrl_tab

You can re-order tabs by dragging them horizontal. You can click the button on the upper-left corner to open a menu listing all the tabs by name. You can click and drag this button to undock an entire node when it is docking (so you can redock it elsewhere):

docking_201810_base-03

What should persist:

  • Docking hierarchy / configuration (note that if a dock node doesn't have active windows it is automatically folded)
  • Tab order for each visible dock node
  • Merged windows

What doesn't persist on restart:

  • Selected tab for each visible dock node: TODO
  • Window visibility (this is up to your application to store e.g. the associated bool and execute the code or not).
  • Last focused window (this is currently also missing in the master branch, will be added. It's not a big issue)

API

As pointed out above many operation can be done without any API.

(This is not a complete documentation, merely enough to get you started with basic uses. More advanced programmatic manipulation of docking are currently exposed only in imgui_internal.h as ImGui::DockBuilderXXX and will be reworked into a public-facing API)

There is ImGui::DockSpace() call which allows you to create an explicit docking node within an existing window. If you have a full-on editor this is useful to build your main application around a menu-bar etc. Simpler applications will be using docking functions without ever calling DockSpace(). This function comes with one fundamental constraint: anything you dock into an explicit DockSpace() node needs to be submitted after it, so you’ll have to structure your app around that one limitation. It is also generally expected that your dockspaces, if you have any, persist at all time.

DockSpace() create by default a "Central Node" which is a node that doesn't fold/disappear even if no windows are docked into it. There are a few properties associated to this which I'll detail later.

Using some combination of flag ImGuiDockNodeFlags_PassthruCentralNode (WAS ImGuiDockNodeFlags_PassthruDockspace) you can make the central node invisible and inputs pass-thru. See the Demo>Dockspace options for details and this comment.

image

As with regular window, if you call IsItemHovered() or other "Item" function right after your call to Begin(), the title-bar or tab is used as a reference item. You can use this to create context-menu over title bars or tabs:

image

There is a ImGuiWindowFlags_NoDocking to disable the ability for a window to be involved in docking. Menus, popups etc. are not dockable by default.

The SetNextWindowDockFamily() API, which doesn't have a demo yet, allows you to make some windows dockable into to another set of windows. In particular, if you have multiple dockspace with tools related to a given editor or document, you may want each dockspace to use a unique family so windows from one cannot be docked into the other.

There are 2 new demos
Demo Window → "Examples" Menu → Documents
Demo Window → "Examples" Menu → Dockspace
However as pointed above many of the features do not need those demos.
In fact, the “Dockspace” demo is pretty much only a call to DockSpace() + a bunch of comments.

Picture: This is a dockspace, the upper-right node is the empty document root node

image

// Docking 
// [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable.
// Note: you DO NOT need to call DockSpace() to use most Docking facilities! 
// To dock windows: hold SHIFT anywhere while moving windows (if io.ConfigDockingWithShift == true) or drag windows from their title bar (if io.ConfigDockingWithShift = false)
// Use DockSpace() to create an explicit dock node _within_ an existing window. See Docking demo for details.
void    DockSpace(ImGuiID id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiDockFamily* dock_family = NULL);
void    SetNextWindowDockId(ImGuiID dock_id, ImGuiCond cond = 0);           // set next window dock id (FIXME-DOCK)
void    SetNextWindowDockFamily(const ImGuiDockFamily* dock_family);        // set next window user type (docking filters by same user_type)
ImGuiID GetWindowDockId();
bool    IsWindowDocked();                                                   // is current window docked into another window? 
// Flags for ImGui::DockSpace()
enum ImGuiDockNodeFlags_
{
ImGuiDockNodeFlags_None                         = 0,
ImGuiDockNodeFlags_KeepAliveOnly                = 1 << 0,   // Don't display the dockspace node but keep it alive. Windows docked into this dockspace node won't be undocked.
//ImGuiDockNodeFlags_NoCentralNode              = 1 << 1,   // Disable Central Node (the node which can stay empty)
ImGuiDockNodeFlags_NoDockingInCentralNode       = 1 << 2,   // Disable docking inside the Central Node, which will be always kept empty. Note: when turned off, existing docked nodes will be preserved.
ImGuiDockNodeFlags_NoSplit                      = 1 << 3,   // Disable splitting the node into smaller nodes. Useful e.g. when embedding dockspaces into a main root one (the root one may have splitting disabled to reduce confusion). Note: when turned off, existing splits will be preserved.
ImGuiDockNodeFlags_NoResize                     = 1 << 4,   // Disable resizing child nodes using the splitter/separators. Useful with programatically setup dockspaces. 
ImGuiDockNodeFlags_PassthruCentralNode          = 1 << 5,   // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. See demo for details.
ImGuiDockNodeFlags_AutoHideTabBar               = 1 << 6    // Tab bar will automatically hide when there is a single window in the dock node.
};

If you have multiple dockspace each behind their own tabs (aka nested tabs), the ImGuiDockNodeFlags_KeepAliveOnly flag is useful to specify that a DockSpace is still alive even though it it is hidden and not being fully submitted. Otherwise, submitted windows that are docked into the hidden dockspace would normally undock themselves (as they lost their parent).

Tab Bars and Tabs

The docking system is in charge of creating tabs, but you can use the tab-bar/tabs system as regular low-level widgets, unrelated to Docking.

if (ImGui::BeginTabBar("blah"))
{
    if (ImGui::BeginTabItem("Video"))
    {
        ImGui::Text("Blah blah");
        ImGui::EndTabItem();
    }
    if (ImGui::BeginTabItem("Audio"))
    {
        ImGui::EndTabItem();
    }
    if (ImGui::BeginTabItem("Controls"))
    {
        ImGui::EndTabItem();
    }
    ImGui::EndTabBar();
}

image

API

bool  BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0);        // create and append into a TabBar
void  EndTabBar();
bool  BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags = 0);// create a Tab. Returns true if the Tab is selected.
void  EndTabItem();                                                       // only call EndTabItem() if BeginTabItem() returns true!
void  SetTabItemClosed(const char* tab_or_docked_window_label);           // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name.
// Flags for ImGui::BeginTabBar()
enum ImGuiTabBarFlags_
{
    ImGuiTabBarFlags_None                           = 0,
    ImGuiTabBarFlags_Reorderable                    = 1 << 0,   // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list
    ImGuiTabBarFlags_AutoSelectNewTabs              = 1 << 1,   // Automatically select new tabs when they appear
    ImGuiTabBarFlags_NoCloseWithMiddleMouseButton   = 1 << 2,   // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
    ImGuiTabBarFlags_NoTabListPopupButton           = 1 << 3,
    ImGuiTabBarFlags_NoTabListScrollingButtons      = 1 << 4,
    ImGuiTabBarFlags_FittingPolicyResizeDown        = 1 << 5,   // Resize tabs when they don't fit
    ImGuiTabBarFlags_FittingPolicyScroll            = 1 << 6,   // Add scroll buttons when tabs don't fit
    ImGuiTabBarFlags_FittingPolicyMask_             = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
    ImGuiTabBarFlags_FittingPolicyDefault_          = ImGuiTabBarFlags_FittingPolicyResizeDown
};  

// Flags for ImGui::BeginTabItem()
enum ImGuiTabItemFlags_
{
    ImGuiTabItemFlags_None                          = 0,
    ImGuiTabItemFlags_UnsavedDocument               = 1 << 0,   // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker.
    ImGuiTabItemFlags_SetSelected                   = 1 << 1,   // Trigger flag to programatically make the tab selected when calling BeginTabItem()
    ImGuiTabItemFlags_NoCloseWithMiddleMouseButton  = 1 << 2,   // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
    ImGuiTabItemFlags_NoPushId                      = 1 << 3    // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem()
};

See the demo under Demo->Layout->Tabs

image

And Demo->Examples Menu->Documents

image

image

Standalone tab-bars (not part of the docking system) are not currently saving their order/selected persistently.

TODO

not an exhaustive list, posted for informative pupose

  • A~ Unreal style document system (requires low-level controls of dockspace serialization fork/copy/delete): this is mostly working but the DockBuilderXXX api are not exposed/finished --> proof of concept demo posted.
  • dock: A: it should be possible with dock builder to build a floating node.
  • dock: B: when docking outer, perform size locking on neighbors nodes the same way we do it with splitters, so other nodes are not resized
  • dock: B~ central node resizing behavior incorrect.
  • dock: B~ central node ID retrieval API?
  • dock: B: changing title font/style per-window is not supported as dock nodes are created in NewFrame.
  • dock: B- debug full rebuild loses viewport of floating dock nodes
  • dock: B- dock node inside its own viewports creates 1 temporary viewport per window on startup before ditching them (doesn't affect the user nor request platform windows to be created, but unnecessary)
  • dock: B- resize sibling locking behavior may be less desirable if we merged same-axis sibling in a same node level?
  • dock: B- single visible node part of a hidden split hierarchy (OnlyNodeWithWindows != NULL) should show a normal title bar (not a tab bar)
  • dock: B~ tidy up tab list popup buttons features (available with manual tab-bar, see ImGuiTabBarFlags_NoTabListPopupButton code, not used by docking nodes)
  • dock: B- inconsistent clipping/border 1-pixel issue (trickier to solve that it looks).
  • dock: B- fix/disable auto-resize grip z-order on split host nodes.
  • dock: B- SetNextWindowFocus() doesn't seem to apply if the window is hidden this frame, need repro.
  • dock: B- resizing a dock tree small currently has glitches (overlapping collapse and close button, etc.)
  • dock: B- dpi: look at interaction with the hi-dpi and multi-dpi stuff.
  • dock: B- tab bar: appearing on first frame with a dumb layout would do less harm that not appearing? (when behind dynamic branch) or store titles + render in EndTabBar()
  • dock: B- tab bar: make selected tab always shows its full title?
  • dock: B- tab bar: the order/focus restoring code could be part of TabBar and not DockNode? (#8)
  • dock: B- dockspace: flag to lock the dock tree and/or sizes
  • dock: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node!
  • dock: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button)
  • dock: B- option to remember undocked window size? (instead of keeping their docked size) (relate to #2104)
  • dock: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs)
  • dock B- nav: being able to dock/undock with gamepad controls?
  • dock: C- after a dock/undock, the Scrollbar Status update in Begin() should use an updated e.g. size_y_for_scrollbars to avoid a 1 frame scrollbar flicker.
  • dock: A- implicit, invisible per-viewport dockspace to dock to.
  • dock: B- DockSpace() border issues

@ocornut ocornut changed the title Docking branch available (Alpha) Docking branch available for testing Oct 1, 2018
@ocornut ocornut mentioned this issue Oct 1, 2018
@Ylannl
Copy link

@Ylannl Ylannl commented Oct 1, 2018

The viewport part does not seem to be working properly on macOS with the glfw_opengl3 example. If I disable ImGuiConfigFlags_ViewportsEnable, the docking works fine. (commit 2cff3f6)

output

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 1, 2018

@Ylannl Thanks! Anything related to viewport please report in the viewport thread #1542 (**edit: for Mac/Linux please report to #2117). By the look of it, it looks like the clipping rectangles are not projected from the global coordinates space to each window’s space. Will have to inspect but last time I tried the glfw+gl demo on Mac OSX it worked for me. Will try again when I have the chance.

@rokups
Copy link
Contributor

@rokups rokups commented Oct 2, 2018

Hey this is great news! Is there a way to set initial position of the docked window? I am looking to have some kind of default placement of newly opened windows.

@bsviglo
Copy link

@bsviglo bsviglo commented Oct 2, 2018

Hey this is great news! Is there a way to set initial position of the docked window? I am looking to have some kind of default placement of newly opened windows.

Same question. Having ability to setup default layout either by default setting or programmatically will be really helpful.
Other than that look awesome. Many Thanks.

ocornut added a commit that referenced this issue Oct 2, 2018
@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 2, 2018

Hey this is great news! Is there a way to set initial position of the docked window? I am looking to have some kind of default placement of newly opened windows.

All the programmatic stuff are currently hidden in imgui_internal.h so please bear in mind that those API will evolve.

Given dockspace_id (same value passed to DockSpace())
Given dockspace_size (which currently cannot be zero, unlike the one passed to DockSpace()

EDITED Oct 6: Removed ImGuIContext* ctx parameter
EDITED Feb 20: Updated to current internal api

You can create an initial layout, e.g.

ImGui::DockBuilderRemoveNode(dockspace_id); // Clear out existing layout
ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_Dockspace); // Add empty node
ImGui::DockBuilderSetNodeSize(dockspace_id, dockspace_size);

ImGuiID dock_main_id = dockspace_id; // This variable will track the document node, however we are not using it here as we aren't docking anything into it.
ImGuiID dock_id_prop = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Left, 0.20f, NULL, &dock_main_id);
ImGuiID dock_id_bottom = ImGui::DockBuilderSplitNode(dock_main_id, ImGuiDir_Down, 0.20f, NULL, &dock_main_id);

ImGui::DockBuilderDockWindow("Log", dock_id_bottom);
ImGui::DockBuilderDockWindow("Properties", dock_id_prop);
ImGui::DockBuilderDockWindow("Mesh", dock_id_prop);
ImGui::DockBuilderDockWindow("Extra", dock_id_prop);
ImGui::DockBuilderFinish(dockspace_id);

In order to only call it once you may use e.g.

if (ImGui::DockBuilderGetNode(dockspace_id) == NULL)
   MyEditor_LayoutPreset();

(Note that I just pushed a fix for DockBuilderSplitNode for a bug I introduced yesterday)

image

@Ylannl
Copy link

@Ylannl Ylannl commented Oct 2, 2018

I've just tested the GLFW + OpenGL3 example (branch docking, commit 2cff3f6) on macOS 10.12 and I have not the problem presented by @Ylannl as shown in the following GIF

@Alzathar Interesting! Do you have a retina screen? I do, perhaps that is related? I'm on macOS 10.14 btw, but also noticed this on the viewport branch on macOS 10.13.

@ocornut Thanks for the great work on ImGui. I'm very exited about these new features! Sorry for posting in the wrong thread.

@rokups
Copy link
Contributor

@rokups rokups commented Oct 2, 2018

@ocornut creating initial dock layout is clear, but what about setting initial dock placement of new window in already existing layout? Do we have to rebuild entire layout to dock new window into existing layout?

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 2, 2018

creating initial dock layout is clear, but what about setting initial dock placement of new window in already existing layout? Do we have to rebuild entire layout to dock new window into existing layout?

@rokups You can use DockBuilderDockWindow() or SetNextWindowDockId(). The problem you will have is that you can not easily identify a docking node from an already split state. So the "where" parameter is tricky to define.

If you are building the whole hierarchy you have the ID, otherwise you can use e.g. GetWindowDockId() to get an ID from a window.

Another possibility (which I was using in Docking V1) would be to tag node on creation, and being later able to find a dock node id given the tag, The problem is that node that can merged/split by the user. To be able to track through merge we need node to be able to carry multiple tags.

Take some time to think about the problem and let me know if you have more ideas.

@Alzathar @Ylannl Please move viewport related discussion to the viewport thread.

@rokups
Copy link
Contributor

@rokups rokups commented Oct 2, 2018

Thanks, i got it working easily. Not sure how i missed that. And i hopefully last question: is there a way to set next window dock position to an empty undocked space? I suspect i might need to iterate through ImGuiDockNode* tree but i am not sure how to identify undocked space.
2018-10-02_19-28

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 2, 2018

@rokups Do you actually want "an empty undocked space" (there can be only one) or do you want the DocRoot node (which happens to be the only node that can be empty, but it might have other windows docking). What would do do if there's already a window in there?

@rokups
Copy link
Contributor

@rokups rokups commented Oct 2, 2018

I think i want "empty undocked space". I tried SetNextWindowDockId(dockRoot, ..) but it just does not dock window anywhere so that must be wrong. What i want to do is dock window into empty space if there is any, if not - dock window as a tab to the largest docked tab. That second part is already working great.

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 2, 2018

I tried SetNextWindowDockId(dockRoot, ..) but it just does not dock window anywhere

That's exactly what this function does, dock windows. If you believe you are running into an issue try to build a repro.

I think i want "empty undocked space". [...] What i want to do is dock window into empty space if there is any, if not - dock window as a tab to the largest docked tab.

The DocRoot node (the grey node) is essentially meant to represent that space (If there is an empty node it WILL be the DocRoot node) and it is up to the user to decide where it goes and how big it this. This matches VS behavior, rather than just looking for the "largest docked tab". It also behave differently sizing wise (if you resize your host OS windows you'll find that out).

You should probably either use the DocRoot node (which ID is not possible to query yet, haha) or track the current DockID of the LATEST focused document/tool (up to you how to define document/tool) and use this DockID to dock new windows, I think either would make more sense to the user.

EDIT You should never have to iterate the dock node hierarchy yourself, but we could provide helper functions to find DockID under different criteria: DocRoot node, largest node, last focused node, dock where a given window is hosted, with or without DockFamily filter, etc.

EDIT2: The DocRoot node is now called CentralNode

@codz01
Copy link

@codz01 codz01 commented Oct 2, 2018

great news :D , it works perfectly on windows
Note : for mingw users , you have to add :
#define WINVER 0x0601
#define _WIN32_WINNT 0x0601
on top of include <windows.h>
this is only to visible the function SetProcessDPIAware

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 2, 2018

Note : for mingw users , you have to add :
#define WINVER 0x0601
#define _WIN32_WINNT 0x0601
on top of include <windows.h>

I think you need to add those defines are program-wide defines if you use Mingw.

@Dingobloo
Copy link

@Dingobloo Dingobloo commented Oct 3, 2018

Took a bit of work going through the examples to update my application because I hadn't updated imgui in a while but docking and viewport seems to work just fine on OSX High Sierra (10.13.6) SDL2 + OpenGL2. The only slightly unintuitive bit is that I cannot interact with the translate gizmo if the window is undocked (it just drags the whole window) but that's likely my doing.

dockingsmall

@rokups
Copy link
Contributor

@rokups rokups commented Oct 3, 2018

@ocornut i created a small testcase of what i attempted. Please take a look.

		static int initialized = 0;
		static int new_window = 0;
		ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar;
		flags |= ImGuiWindowFlags_NoDocking;
		ImGuiViewport* viewport = ImGui::GetMainViewport();
		ImGui::SetNextWindowPos(viewport->Pos);
		ImGui::SetNextWindowSize(viewport->Size);
		ImGui::SetNextWindowViewport(viewport->ID);
		ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
		flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
		flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
		ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
		ImGui::Begin("DockSpace Demo", 0, flags);
		ImGui::PopStyleVar();

		if (ImGui::BeginMenuBar())
		{
			if (initialized == 0)
			{
				if (ImGui::Button("1. Initialize"))
					initialized = 1;
			}
			if (initialized > 0 && new_window == 0)
			{
				if (ImGui::Button("2. New Window"))
					new_window = 1;
			}
			ImGui::EndMenuBar();
		}

		ImGuiIO& io = ImGui::GetIO();
		ImGuiID dockspace_id = ImGui::GetID("MyDockspace");

		if (initialized == 1)
		{
			initialized = 2;
			ImGuiContext* ctx = ImGui::GetCurrentContext();
			ImGui::DockBuilderRemoveNode(ctx, dockspace_id); // Clear out existing layout
			ImGui::DockBuilderAddNode(ctx, dockspace_id, ImGui::GetMainViewport()->Size); // Add empty node

			ImGuiID dock_main_id = dockspace_id; // This variable will track the document node, however we are not using it here as we aren't docking anything into it.
			ImGuiID dock_id_prop = ImGui::DockBuilderSplitNode(ctx, dock_main_id, ImGuiDir_Left, 0.20f, NULL, &dock_main_id);
			ImGuiID dock_id_bottom = ImGui::DockBuilderSplitNode(ctx, dock_main_id, ImGuiDir_Down, 0.20f, NULL, &dock_main_id);

			ImGui::DockBuilderDockWindow(ctx, "Log", dock_id_bottom);
			ImGui::DockBuilderDockWindow(ctx, "Properties", dock_id_prop);
			ImGui::DockBuilderFinish(ctx, dockspace_id);
		}

		ImGui::DockSpace(dockspace_id);
		if (initialized == 2)
		{
			ImGui::Begin("Properties");
			ImGui::End();

			ImGui::Begin("Log");
			ImGui::End();
		}

		if (new_window == 1)
		{
			// Should dock window to empty space, instead window is not docked anywhere.
			ImGui::SetNextWindowDockId(dockspace_id, ImGuiCond_Once);
			ImGui::Begin("New Window");
			ImGui::End();
		}

		ImGui::End();
		ImGui::PopStyleVar();

Click buttons in the menu bar to 1. initialize default layout and 2. create new window and dock it into empty space. Window is created but not docked anywhere. Do i do it wrong or is this a bug?

And another question: is there a way to detect presence of this free undocked space?

@nem0
Copy link
Contributor

@nem0 nem0 commented Oct 3, 2018

I want to make a dockspace transparent, while windows docked in it should keep their style. I tried many ways, e.g.

	ImGui::SetNextWindowBgAlpha(0);
	ImGui::Begin("DockSpace Demo", 0, flags);

	ImGuiID dockspace_id = ImGui::GetID("MyDockspace");
	ImGui::DockSpace(dockspace_id);

	ImGui::End();

however, all I managed to do is that everything became transparent. Is there a way to this?

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Oct 3, 2018

I want to make a dockspace transparent, while windows docked in it should keep their style.

I am working on this right now, it should be available during the day.
It also involve passing inputs through.

@codz01
Copy link

@codz01 codz01 commented Oct 3, 2018

the dockspace's scrollbar is visible , is it normal ?
gif

ocornut added a commit that referenced this issue Oct 3, 2018
… the node backgrounds. Rename ImGuiCol_DockingBg to ImGuiCol_DockingEmptyBg. Added ImGuiDockNode::IsLeaftNode(). (#2109)
@ocornut ocornut removed this from the v1.80 milestone Aug 2, 2020
@ocornut ocornut added this to the v1.90 milestone Aug 2, 2020
ocornut added a commit that referenced this issue Aug 11, 2020
@nauq302
Copy link

@nauq302 nauq302 commented Aug 13, 2020

How can I use this with Vcpkg and Cmake?

@PathogenDavid
Copy link
Contributor

@PathogenDavid PathogenDavid commented Aug 13, 2020

Dear ImGui does not impose (or provide support for) any particular build system. From the readme:

No specific build process is required. You can add the .cpp files to your existing project.

@1aam2am1
Copy link

@1aam2am1 1aam2am1 commented Sep 28, 2020

How could I dock visible window and undock it sometime later?

@FilipePpereira
Copy link

@FilipePpereira FilipePpereira commented Sep 28, 2020

Como faço para começar a usar os painéis de encaixe?
Bom trabalho, equipe ImGui. Eu tenho que começar a doar novamente.

Leia isso

e isto

usa isto
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::SetNextWindowBgAlpha(0.0f);

ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;

ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("DockSpace Demo", p_open, window_flags);
ImGui::PopStyleVar(3);

ImGuiID dockspace_id = ImGui::GetID("MyDockspace");
ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_PassthruCentralNode;
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);

@1aam2am1
Copy link

@1aam2am1 1aam2am1 commented Sep 30, 2020

Flag:
ImGui::GetStyle().WindowMenuButtonPosition = ImGuiDir_None;
Creates visible artifacts as it displays Hide Bar menu but don't move cursor for drawing tabs.

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Sep 30, 2020

@1aam2am1 Please open a separate issue with screenshots/gifs and details, thank you.

@BBI-YggyKing
Copy link

@BBI-YggyKing BBI-YggyKing commented Nov 2, 2020

The docking implementation looks great! Will this eventually be merged to master, or is it planned to remain as a parallel implementation, with users choosing which version to work with? (I see the docking branch is up to date with master, but many commits ahead ...)
image

@PathogenDavid
Copy link
Contributor

@PathogenDavid PathogenDavid commented Nov 9, 2020

@cailuming

Note the request at the top of this issue:

Prefer creating separate New Issues for specific questions/issues, so they can more easily be closed when solved and not clutter this thread (which is already too big)

I'm not sure exactly what you're asking for and it'd probably help if you elaborated on the problem you're trying to solve. My gut says you could maybe use a combination of IsWindowDocked, GetWindowDockID, and IsWindowFocused to get what you need.

@PathogenDavid
Copy link
Contributor

@PathogenDavid PathogenDavid commented Nov 9, 2020

Will this eventually be merged to master

@bbi-yggy I can't speak for Omar, but there's an item on the todo list to merge it into master.

@ocornut
Copy link
Owner Author

@ocornut ocornut commented Nov 9, 2020

@irieger
Copy link

@irieger irieger commented Jan 10, 2021

In order to only call it once you may use e.g.

if (ImGui::DockBuilderGetNode(dockspace_id) == NULL)
   MyEditor_LayoutPreset();

Hey,

I just setup a DockSpace in my app to have a nice window layout and it works fine. While now trying to set a default layout, your sample code works with one caveat: This example returns NULL / a valid node independent of whether I have a previously changed layout (in the imgui.ini) so each time I start my app the layout gets reset.

I'd like to only use my setup routine if the imgui.ini doesn't contain the [Docking][Data] section. Is there a native way to check this or would I need to check this manually by looking at the ini data myself?

Kind regards and thank you for making ImGui,
Ingmar

@PathogenDavid
Copy link
Contributor

@PathogenDavid PathogenDavid commented Jan 10, 2021

@irieger Please take note of the notice at the top of this issue:

Prefer creating separate New Issues for specific questions/issues, so they can more easily be closed when solved and not clutter this thread (which is already too big)

Please do not report issues without reading the 'Feedback' section of the next post and without reading the 'Contributing' document listed in there. The number of ambiguous, ill-formed questions and incomplete bug reports posted on this entire github is difficult to deal with. Thank you.

@UnidayStudio
Copy link

@UnidayStudio UnidayStudio commented May 26, 2021

Hi, sorry for leaving a question here, but is it possible to a main window with sub dockable windows inside just like Unreal Engine does?

@PathogenDavid
Copy link
Contributor

@PathogenDavid PathogenDavid commented May 27, 2021

@UnidayStudio

Hi, sorry for leaving a question here

As noted in the main issue above, you should not be asking questions in this thread. I understand there's a lot to read there, but I suspect even just skimming over the screenshots would've answered your question.


It sounds like what you're looking for is ImGui::DockSpaceOverViewport. There's a demonstration of it in the demo under Examples > Dockspace.

If that's not what you're looking for you should create a separate issue with a clearer example of what you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet