Docking: Added Docking system. Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. (Part 1) (#351)

docking
omar 6 years ago
parent 5adcb9ce6d
commit bd5b38e232

@ -33,9 +33,19 @@ HOW TO UPDATE?
DOCKING BRANCH (In Progress)
-----------------------------------------------------------------------
- Added ImGuiConfigFlags_DockingEnable flag to enable Docking. [BETA]
Set with `io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;`.
- Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. (#261, #351)
- Added DockSpace() API. (#351)
- Added SetNextWindowDock() API. (#351)
- Added IsWindowDocked() API. (#351)
- Added ImGuiWindowFlags_NoDocking window flag to disable the possibility for a window to be docked.
Popup, Menu and Child windows always have the ImGuiWindowFlags_NoDocking flag set. (#351)
- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID,
as a convenience to avoid using the ### operator.
- Added io.ConfigDockingWithKeyMod option to configure docking mode.
- Style: Added ImGuiCol_DockingPreview, ImGuiCol_DockingBg colors. (#351)
- Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. (#261, #351)
- Demo: Added Layout->Tabs demo code. (#261, #351)
- Demo: Added "Documents" example app showcasing possible use for tabs. (#261, #351)

@ -26,6 +26,7 @@
#define IMGUI_VERSION "1.66 WIP"
#define IMGUI_VERSION_NUM 16600
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert))
#define IMGUI_HAS_DOCK 1 // Docking WIP branch
#define IMGUI_HAS_TABS 1 // Docking WIP branch
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
@ -209,7 +210,9 @@ namespace ImGui
IMGUI_API bool IsWindowCollapsed();
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options.
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ!
IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the window, to append your own drawing primitives
IMGUI_API bool IsWindowDocked();
IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives
IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API)
IMGUI_API ImVec2 GetWindowSize(); // get current window size
IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x)
@ -228,6 +231,7 @@ namespace ImGui
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin()
IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin()
IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg.
IMGUI_API void SetNextWindowDock(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK)
IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.
IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
@ -499,12 +503,18 @@ namespace ImGui
// Tabs
// [BETA API] API may evolve.
// Note: Tabs are automatically created by the docking system. Use this to create tab bars/tabs yourself without docking being involved.
IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar
IMGUI_API void EndTabBar();
IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags = 0);// create a Tab. Returns true if the Tab is selected.
IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true!
IMGUI_API 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.
// Docking
// [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable.
// Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. Use DockSpace() if you need to create an explicit docking space _within_ an existing window. See Docking demo for details)
IMGUI_API void DockSpace(const char* str_id, const ImVec2& size = ImVec2(0, 0));
// Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging.
IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty
IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file
@ -635,7 +645,8 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window
ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without altering the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker.
ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker.
ImGuiWindowFlags_NoDocking = 1 << 21, // Disable docking of this window
// [Internal]
ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
@ -643,7 +654,8 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal()
ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu()
ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu()
ImGuiWindowFlags_DockNodeHost = 1 << 29 // Don't use! For internal use by Begin()/NewFrame()
// [Obsolete]
//ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f / style.WindowBorderSize=1.0f to enable borders around windows and items
@ -897,6 +909,9 @@ enum ImGuiConfigFlags_
ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end.
ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
// [BETA] Docking
ImGuiConfigFlags_DockingEnable = 1 << 6, // Docking enable flags. Use SHIFT to dock window into another (or without SHIFT if io.ConfigDockingWithKeyMod = false).
// User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core ImGui)
ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware.
ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse.
@ -951,6 +966,8 @@ enum ImGuiCol_
ImGuiCol_TabActive,
ImGuiCol_TabUnfocused,
ImGuiCol_TabUnfocusedActive,
ImGuiCol_DockingPreview,
ImGuiCol_DockingBg, // Empty node
ImGuiCol_PlotLines,
ImGuiCol_PlotLinesHovered,
ImGuiCol_PlotHistogram,
@ -1150,6 +1167,7 @@ struct ImGuiIO
// Miscellaneous configuration options
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations.
bool ConfigDockingWithKeyMod; // = true // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space)
bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63)
bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63)
bool ConfigResizeWindowsFromEdges; // = false // [BETA] Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the ImGuiWindowFlags_ResizeFromAnySide flag)

@ -36,6 +36,7 @@ Index of this file:
// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
*/
@ -99,6 +100,7 @@ Index of this file:
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
// Forward Declarations
static void ShowExampleAppDockSpace(bool* p_open);
static void ShowExampleAppDocuments(bool* p_open);
static void ShowExampleAppMainMenuBar();
static void ShowExampleAppConsole(bool* p_open);
@ -159,6 +161,7 @@ void ImGui::ShowUserGuide()
void ImGui::ShowDemoWindow(bool* p_open)
{
// Examples Apps (accessible from the "Examples" menu)
static bool show_app_dockspace = false;
static bool show_app_documents = false;
static bool show_app_main_menu_bar = false;
static bool show_app_console = false;
@ -172,7 +175,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
static bool show_app_window_titles = false;
static bool show_app_custom_rendering = false;
if (show_app_documents) ShowExampleAppDocuments(&show_app_documents);
if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() needs to be submitted early (read comments near the DockSpace function)
if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
if (show_app_console) ShowExampleAppConsole(&show_app_console);
if (show_app_log) ShowExampleAppLog(&show_app_log);
@ -211,6 +215,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
static bool no_collapse = false;
static bool no_close = false;
static bool no_nav = false;
static bool no_docking = false;
ImGuiWindowFlags window_flags = 0;
if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
@ -220,6 +225,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
if (no_close) p_open = NULL; // Don't pass our bool* to Begin
// We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming.
@ -260,6 +266,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
ImGui::MenuItem("Docking", NULL, &show_app_dockspace);
ImGui::MenuItem("Documents", NULL, &show_app_documents);
ImGui::EndMenu();
}
@ -312,6 +319,12 @@ void ImGui::ShowDemoWindow(bool* p_open)
}
ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility.");
ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
ImGui::SameLine(); ShowHelpMarker("Use SHIFT to dock window into another (or without SHIFT if io.ConfigDockingWithKeyMod == false)");
ImGui::Checkbox("io.ConfigDockingWithKeyMod", &io.ConfigDockingWithKeyMod);
ImGui::SameLine(); ShowHelpMarker("Enable docking when holding Shift only (allows to drop in wider space, reduce visual noise)");
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting");
ImGui::Checkbox("io.ConfigResizeWindowsFromEdges [beta]", &io.ConfigResizeWindowsFromEdges);
@ -364,7 +377,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300);
ImGui::Checkbox("No collapse", &no_collapse);
ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150);
ImGui::Checkbox("No nav", &no_nav);
ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300);
ImGui::Checkbox("No docking", &no_docking);
}
if (ImGui::CollapsingHeader("Widgets"))
@ -1463,6 +1477,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
// Calling IsItemHovered() after begin returns the hovered status of the title bar.
// This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window.
// This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
static bool test_window = false;
ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
if (test_window)
@ -1473,6 +1488,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (ImGui::MenuItem("Close")) { test_window = false; }
ImGui::EndPopup();
}
//if (IsItemHovered() || IsItemActive()) { printf("[%05d] Hovered %d Active %d\n", GetFrameCount(), IsItemHovered(), IsItemActive()); } // [DEBUG]
ImGui::Text(
"IsItemHovered() after begin = %d (== is title bar hovered)\n"
"IsItemActive() after begin = %d (== is window being clicked/moved)\n",
@ -3459,6 +3475,8 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
"Custom: Always Square",
"Custom: Fixed Steps (100)",
};
if (ImGui::IsWindowDocked())
ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
@ -3487,7 +3505,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
if (corner != -1)
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
if (ImGui::Begin("Example: Simple Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
if (ImGui::Begin("Example: Simple Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
{
ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
ImGui::Separator();
@ -3651,6 +3669,72 @@ static void ShowExampleAppCustomRendering(bool* p_open)
ImGui::End();
}
//-----------------------------------------------------------------------------
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
//-----------------------------------------------------------------------------
// Demonstrate using DockSpace() to create an explicit docking spacing within an existing window.
// Note that you already dock windows into each others _without_ a DockSpace() by just holding SHIFT when moving a window.
// DockSpace() is only useful to construct to a central location for your application.
void ShowExampleAppDockSpace(bool* p_open)
{
static bool opt_fullscreen_persistant = true;
bool opt_fullscreen = opt_fullscreen_persistant;
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into.
// Because 1) it would be confusing to have two docking targets within each others.
// and 2) we want our main DockSpace to always be visible (never hidden within a tab bar): if the DockSpace disappear its child windows will be orphaned.
ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar;
flags |= ImGuiWindowFlags_NoDocking;
if (opt_fullscreen)
{
ImVec2 viewport_pos = ImVec2(0.0f, 0.0f);
ImVec2 viewport_size = ImGui::GetIO().DisplaySize;
ImGui::SetNextWindowPos(viewport_pos);
ImGui::SetNextWindowSize(viewport_size);
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("Docking Documents Demo", p_open, flags);
ImGui::PopStyleVar();
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Docking"))
{
if (ImGui::MenuItem("Remove DockSpace", NULL, false, p_open != NULL))
*p_open = false;
ImGui::EndMenu();
}
// Disabling fullscreen would allow the window to be moved to the front of other windows,
// which we can't undo at the moment without finer window depth/z control.
/*if (ImGui::BeginMenu("Options"))
{
ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen_persistant);
ImGui::EndMenu();
}*/
ShowHelpMarker(
"You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!" "\n"
"This demo app has nothing to do with it!" "\n\n"
"This demo app only demonstrate the use of ImGui::DockSpace() which allows you to specify a docking spot _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n"
"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 your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n"
"(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace(), because that window is submitted as part of the NewFrame() call. An easy workaround is 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::EndMenuBar();
}
//ImGui::PushStyleColor(ImGuiCol_DockingBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
ImGui::DockSpace("##MyCentralDockSpace");
//ImGui::PopStyleColor();
ImGui::End();
if (opt_fullscreen)
ImGui::PopStyleVar();
}
//-----------------------------------------------------------------------------
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
//-----------------------------------------------------------------------------
@ -3754,7 +3838,8 @@ void ShowExampleAppDocuments(bool* p_open)
enum Target
{
Target_None,
Target_Tab // Create document as a local tab into a local tab bar
Target_Tab, // Create document as a local tab into a local tab bar
Target_Window // Create document as a regular window
};
static Target opt_target = Target_Tab;
static bool opt_reorderable = true;
@ -3802,9 +3887,11 @@ void ShowExampleAppDocuments(bool* p_open)
ImGui::PopID();
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0");
ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
ImGui::PopItemWidth();
bool redock_all = false;
if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
if (opt_target == Target_Window) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
ImGui::Separator();
@ -3848,6 +3935,42 @@ void ShowExampleAppDocuments(bool* p_open)
ImGui::EndTabBar();
}
else if (opt_target == Target_Window)
{
NotifyOfDocumentsClosedElsewhere(app);
// Create a DockSpace where any window can be docked
ImGui::DockSpace("##DockSpace");
ImGuiID dockspace_id = ImGui::GetID("##DockSpace");
// Create Windows
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
{
MyDocument* doc = &app.Documents[doc_n];
if (!doc->Open)
continue;
// FIXME-DOCK: SetNextWindowDock()
//ImGuiID default_dock_id = GetDockspaceRootDocumentDockID();
//ImGuiID default_dock_id = GetDockspacePreferedDocumentDockID();
ImGui::SetNextWindowDock(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
// Cancel attempt to close when unsaved add to save queue so we can display a popup.
if (!doc->Open && doc->Dirty)
{
doc->Open = true;
doc->DoQueueClose();
}
MyDocument::DisplayContextMenu(doc);
if (visible)
MyDocument::DisplayContents(doc);
ImGui::End();
}
}
// Update closing queue
static ImVector<MyDocument*> close_queue;

@ -210,6 +210,8 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
@ -265,6 +267,8 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
@ -321,6 +325,8 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
@ -2831,8 +2837,10 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
// (progressively moved from imgui.cpp to here when they are redesigned to stop accessing ImGui global state)
//-----------------------------------------------------------------------------
// - RenderMouseCursor()
// - RenderArrowDockMenu()
// - RenderArrowPointingAt()
// - RenderRectFilledRangeH()
// - RenderRectFilledWithHole()
// - RenderPixelEllipsis()
//-----------------------------------------------------------------------------
@ -2874,6 +2882,14 @@ void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half
}
}
// This is less wide than RenderArrow() and we use in dock nodes instead of the regular RenderArrow() to denote a change of functionality,
// and because the saved space means that the left-most tab label can stay at exactly the same position as the label of a loose window.
void ImGui::RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col)
{
draw_list->AddRectFilled(p_min + ImVec2(sz * 0.10f, sz * 0.15f), p_min + ImVec2(sz * 0.70f, sz * 0.30f), col);
RenderArrowPointingAt(draw_list, p_min + ImVec2(sz * 0.40f, sz * 0.85f), ImVec2(sz * 0.30f, sz * 0.40f), ImGuiDir_Down, col);
}
static inline float ImAcos01(float x)
{
if (x <= 0.0f) return IM_PI * 0.5f;
@ -2942,6 +2958,24 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
draw_list->PathFillConvex(col);
}
// For CTRL+TAB within a docking node we need to render the dimming background in 8 steps
// (Because the root node renders the background in one shot, in order to avoid flickering when a child dock node is not submitted)
void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding)
{
const bool fill_L = (inner.Min.x > outer.Min.x);
const bool fill_R = (inner.Max.x < outer.Max.x);
const bool fill_U = (inner.Min.y > outer.Min.y);
const bool fill_D = (inner.Max.y < outer.Max.y);
if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopLeft) | (fill_D ? 0 : ImDrawCornerFlags_BotLeft));
if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopRight) | (fill_D ? 0 : ImDrawCornerFlags_BotRight));
if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_TopLeft) | (fill_R ? 0 : ImDrawCornerFlags_TopRight));
if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_BotLeft) | (fill_R ? 0 : ImDrawCornerFlags_BotRight));
if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopLeft);
if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopRight);
if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotLeft);
if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight);
}
// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem... can't rely on font glyph having it, and regular dot are typically too wide.
// If we render a dot/shape ourselves it comes with the risk that it wouldn't match the boldness or positioning of what the font uses...
void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col)

@ -40,6 +40,9 @@ struct ImGuiColorMod; // Stacked color modifier, backup of modifie
struct ImGuiColumnData; // Storage data for a single column
struct ImGuiColumnsSet; // Storage data for a columns set
struct ImGuiContext; // Main imgui context
struct ImGuiDockContext; // Docking system context
struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes)
struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session)
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data
@ -90,6 +93,9 @@ namespace ImGuiStb
extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointer
#endif
// Internal Drag and Drop payload types. String starting with '_' are reserved for Dear ImGui.
#define IMGUI_PAYLOAD_TYPE_WINDOW "_IMWINDOW" // Payload == ImGuiWindow*
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
@ -406,6 +412,14 @@ struct ImVec1
ImVec1(float _x) { x = _x; }
};
// 2D vector (half-size integer)
struct ImVec2ih
{
short x, y;
ImVec2ih() { x = y = 0; }
ImVec2ih(short _x, short _y) { x = _x; y = _y; }
};
// 2D axis aligned bounding-box
// NB: we can't rely on ImVec2 math operators being available here
struct IMGUI_API ImRect
@ -524,15 +538,17 @@ struct ImGuiWindowSettings
ImGuiID ID;
ImVec2 Pos;
ImVec2 Size;
ImGuiID DockId; // ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none.
short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
bool Collapsed;
ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ImVec2(0,0); Collapsed = false; }
ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ImVec2(0, 0); DockId = 0; DockOrder = -1; Collapsed = false; }
};
struct ImGuiSettingsHandler
{
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
ImGuiID TypeHash; // == ImHash(TypeName, 0, 0)
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
ImGuiID TypeHash; // == ImHash(TypeName, 0, 0)
void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf'
@ -642,33 +658,37 @@ struct ImGuiNextWindowData
ImGuiCond SizeConstraintCond;
ImGuiCond FocusCond;
ImGuiCond BgAlphaCond;
ImGuiCond DockCond;
ImVec2 PosVal;
ImVec2 PosPivotVal;
ImVec2 SizeVal;
ImVec2 ContentSizeVal;
bool PosUndock;
bool CollapsedVal;
ImRect SizeConstraintRect;
ImGuiSizeCallback SizeCallback;
void* SizeCallbackUserData;
float BgAlphaVal;
ImGuiID DockId;
ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it.
ImGuiNextWindowData()
{
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0;
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = DockCond = 0;
PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f);
ContentSizeVal = ImVec2(0.0f, 0.0f);
CollapsedVal = false;
PosUndock = CollapsedVal = false;
SizeConstraintRect = ImRect();
SizeCallback = NULL;
SizeCallbackUserData = NULL;
BgAlphaVal = FLT_MAX;
DockId = 0;
MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
}
void Clear()
{
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0;
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = DockCond = 0;
}
};
@ -682,6 +702,43 @@ struct ImGuiTabBarSortItem
float Width;
};
// sizeof() 88~124
struct ImGuiDockNode
{
ImGuiID ID;
ImGuiDockNode* ParentNode;
ImGuiDockNode* ChildNodes[2];
ImVector<ImGuiWindow*> Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order.
ImGuiTabBar* TabBar;
ImVec2 Pos, Size; // Current position, size
ImVec2 LastExplicitSize; // Last explicit size (overridden when using a splitter affecting the node)
int SplitAxis;
float SplitRatio;
ImGuiWindow* HostWindow;
ImGuiWindow* VisibleWindow;
ImGuiDockNode* OnlyNodeWithWindows; // Root node only, set when there is a single visible node within the hierarchy
ImGuiID SelectedTabID;
int LastFrameActive;
ImGuiID LastFocusedNodeID;
ImGuiID WantCloseOne;
bool InitFromFirstWindow :1;
bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window)
bool IsExplicitRoot :1; // Mark root node as explicit when created from a DockSpace()
bool IsDocumentRoot :1;
bool HasCloseButton :1;
bool HasCollapseButton :1;
bool WantCloseAll :1;
bool WantLockSizeOnce :1;
ImGuiDockNode(ImGuiID id);
~ImGuiDockNode();
bool IsRootNode() const { return ParentNode == NULL; }
bool IsParent() const { return ChildNodes[0] != NULL; }
bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; }
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
};
//-----------------------------------------------------------------------------
// Main imgui context
//-----------------------------------------------------------------------------
@ -710,6 +767,7 @@ struct ImGuiContext
ImGuiWindow* CurrentWindow; // Being drawn into
ImGuiWindow* HoveredWindow; // Will catch mouse inputs
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
ImGuiWindow* HoveredWindowUnderMovingWindow;
ImGuiID HoveredId; // Hovered widget
bool HoveredIdAllowOverlap;
ImGuiID HoveredIdPreviousFrame;
@ -823,6 +881,10 @@ struct ImGuiContext
ImVector<char> PrivateClipboard; // If no custom clipboard handler is defined
ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor
// Extensions
// FIXME: We could provide an API to register one slot in an array held in ImGuiContext?
ImGuiDockContext* DockContext;
// Settings
bool SettingsLoaded;
float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero
@ -862,6 +924,7 @@ struct ImGuiContext
CurrentWindow = NULL;
HoveredWindow = NULL;
HoveredRootWindow = NULL;
HoveredWindowUnderMovingWindow = NULL;
HoveredId = 0;
HoveredIdAllowOverlap = false;
HoveredIdPreviousFrame = 0;
@ -934,6 +997,7 @@ struct ImGuiContext
ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f);
TooltipOverrideCount = 0;
PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX);
DockContext = NULL;
SettingsLoaded = false;
SettingsDirtyTimer = 0.0f;
@ -1078,6 +1142,7 @@ struct IMGUI_API ImGuiWindow
ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use.
ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use.
ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use.
ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use.
ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)
ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right.
@ -1099,6 +1164,7 @@ struct IMGUI_API ImGuiWindow
ImDrawList DrawListInst;
ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL.
ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window.
ImGuiWindow* RootWindowDockStop; // Point to ourself or first ancestor that is not a child window. Doesn't cross through dock nodes. We use this so IsWindowFocused() can behave consistently regardless of docking state.
ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
@ -1115,6 +1181,17 @@ struct IMGUI_API ImGuiWindow
int FocusIdxAllRequestNext; // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame)
int FocusIdxTabRequestNext; // "
// Docking
ImGuiDockNode* DockNode; // Which node are we docked into
ImGuiDockNode* DockNodeAsHost; // Which node are we owning (for parent windows)
ImGuiID DockId; // Backup of last valid DockNode->Id, so single value remember their dock node id
ImGuiItemStatusFlags DockTabItemStatusFlags;
ImRect DockTabItemRect;
short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
bool DockIsActive; // =~ (DockNode != NULL) && (DockNode->Windows.Size > 1)
bool DockTabIsVisible; // Is the window visible this frame? =~ is the corresponding tab selected?
bool DockTabWantClose;
public:
ImGuiWindow(ImGuiContext* context, const char* name);
~ImGuiWindow();
@ -1221,6 +1298,7 @@ namespace ImGui
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
IMGUI_API ImGuiWindow* FindWindowByName(const char* name);
IMGUI_API void FocusWindow(ImGuiWindow* window); // FIXME: Rename to SetWindowFocus()
IMGUI_API void FocusFrontMostActiveWindowIgnoringOne(ImGuiWindow* ignore_window);
@ -1309,6 +1387,20 @@ namespace ImGui
inline bool IsNavInputDown(ImGuiNavInput n) { return GImGui->IO.NavInputs[n] > 0.0f; }
inline bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) { return GetNavInputAmount(n, mode) > 0.0f; }
inline bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) { return (GetNavInputAmount(n1, mode) + GetNavInputAmount(n2, mode)) > 0.0f; }
// Docking
IMGUI_API void DockContextInitialize(ImGuiContext* imgui_context);
IMGUI_API void DockContextShutdown(ImGuiContext* imgui_context);
IMGUI_API void DockContextOnLoadSettings();
IMGUI_API void DockContextRebuild(ImGuiDockContext* ctx);
IMGUI_API void DockContextUpdateUndocking(ImGuiDockContext* ctx);
IMGUI_API void DockContextUpdateDocking(ImGuiDockContext* ctx);
IMGUI_API void DockContextQueueUndock(ImGuiDockContext* ctx, ImGuiWindow* window);
IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open);
IMGUI_API void BeginAsDockableDragDropSource(ImGuiWindow* window);
IMGUI_API void BeginAsDockableDragDropTarget(ImGuiWindow* window);
IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond);
IMGUI_API void ShowDockingDebug();
// Drag and Drop
IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
@ -1321,8 +1413,7 @@ namespace ImGui
IMGUI_API void PushColumnClipRect(int column_index = -1);
// Tab Bars
IMGUI_API void ShowDockingDebug();
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node);
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiWindow* window);
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
@ -1353,7 +1444,9 @@ namespace ImGui
// Render helpers (those functions don't access any ImGui state!)
IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow);
IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
IMGUI_API void RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col);
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding);
IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col);
// Widgets

@ -679,10 +679,16 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
ImVec2 off = is_dock_menu ? ImVec2((float)(int)(-g.Style.ItemInnerSpacing.x * 0.5f) + 0.5f, 0.0f) : ImVec2(0.0f, 0.0f);
ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
if (hovered || held)
window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, col, 9);
RenderArrow(bb.Min + g.Style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
window->DrawList->AddCircleFilled(bb.GetCenter() + off + ImVec2(0,-0.5f), g.FontSize * 0.5f + 1.0f, col, 9);
if (is_dock_menu)
RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, GetColorU32(ImGuiCol_Text));
else
RenderArrow(bb.Min + g.Style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
// Switch to moving the window after mouse is moved beyond the initial drag threshold
if (IsItemActive() && IsMouseDragging())
@ -5429,7 +5435,7 @@ bool ImGui::BeginMainMenuBar()
SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y));
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0));
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
PopStyleVar(2);
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
@ -5796,10 +5802,10 @@ bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id);
ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->InnerClipRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2);
tab_bar->ID = id;
return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused);
return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused, NULL);
}
bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags)
bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@ -5839,10 +5845,18 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
// Draw separator
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab);
const float y = tab_bar->BarRect.Max.y - 1.0f;
const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
if (dock_node != NULL)
{
const float separator_min_x = dock_node->Pos.x;
const float separator_max_x = dock_node->Pos.x + dock_node->Size.x;
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
}
else
{
const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
}
return true;
}
@ -6019,6 +6033,10 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
tab_bar->VisibleTabId = tab_bar->SelectedTabId;
tab_bar->VisibleTabWasSubmitted = false;
// CTRL+TAB can override visible tab temporarily
if (g.NavWindowingTarget != NULL && g.NavWindowingTarget->DockNode && g.NavWindowingTarget->DockNode->TabBar == tab_bar)
tab_bar->VisibleTabId = scroll_track_selected_tab_id = g.NavWindowingTarget->ID;
// Update scrolling
if (scroll_track_selected_tab_id)
if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id))
@ -6371,6 +6389,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Click to Select a tab
ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap);
if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW))
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
hovered |= (g.HoveredId == id);
@ -6427,6 +6447,16 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
undocking_tab = true;
}
}
// Undock
if (undocking_tab && g.ActiveId == id && IsMouseDragging())
{
ImGuiDockContext* ctx = g.DockContext;
DockContextQueueUndock(ctx, docked_window);
g.MovingWindow = docked_window;
g.ActiveId = g.MovingWindow->MoveId;
g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min;
}
}
}
@ -6488,6 +6518,16 @@ void ImGui::SetTabItemClosed(const char* label)
ImGuiID tab_id = TabBarCalcTabID(tab_bar, label);
TabBarRemoveTab(tab_bar, tab_id);
}
else if (ImGuiWindow* window = FindWindowByName(label))
{
if (window->DockIsActive)
if (ImGuiDockNode* node = window->DockNode)
{
ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label);
TabBarRemoveTab(node->TabBar, tab_id);
window->DockTabWantClose = true;
}
}
}
ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button)

Loading…
Cancel
Save