Merge branch 'docking2' into viewport_docking

# Conflicts:
#	examples/example_glfw_opengl2/main.cpp
#	examples/example_glfw_opengl3/main.cpp
#	examples/example_glfw_vulkan/main.cpp
#	examples/example_sdl_opengl3/main.cpp
#	examples/example_sdl_vulkan/main.cpp
#	examples/example_win32_directx10/main.cpp
#	examples/example_win32_directx11/main.cpp
#	examples/example_win32_directx12/main.cpp
#	imgui.cpp
#	imgui.h
#	imgui_demo.cpp
#	imgui_internal.h
This commit is contained in:
omar
2018-09-06 22:25:42 +02:00
21 changed files with 4388 additions and 159 deletions

View File

@ -36,6 +36,8 @@ 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()
*/
@ -98,6 +100,8 @@ 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);
static void ShowExampleAppLog(bool* p_open);
@ -157,6 +161,8 @@ 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;
static bool show_app_log = false;
@ -169,6 +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_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);
@ -207,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;
@ -216,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.
@ -257,6 +267,8 @@ 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();
}
if (ImGui::BeginMenu("Help"))
@ -308,12 +320,19 @@ 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::CheckboxFlags("io.ConfigFlags: ViewportsEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (it will offset your windows).");
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoTaskBarIcons", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoTaskBarIcons);
ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away).");
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoMerge", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoMerge);
ImGui::SameLine(); ShowHelpMarker("All floating windows will always create their own viewport and platform window.");
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);
@ -369,7 +388,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"))
@ -1468,6 +1488,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)
@ -1478,6 +1499,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",
@ -1673,6 +1695,72 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::TreePop();
}
if (ImGui::TreeNode("Tabs"))
{
if (ImGui::TreeNode("Basic"))
{
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
ImGui::BeginTabBar("MyTabBar", tab_bar_flags);
if (ImGui::BeginTabItem("Avocado"))
{
ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Broccoli"))
{
ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Cucumber"))
{
ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
ImGui::EndTabItem();
}
ImGui::EndTabBar();
ImGui::Separator();
ImGui::TreePop();
}
if (ImGui::TreeNode("Advanced & Close Button"))
{
// Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable);
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
// Tab Bar
const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
static bool opened[4] = { true, true, true, true }; // Persistent user state
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
{
if (n > 0) { ImGui::SameLine(); }
ImGui::Checkbox(names[n], &opened[n]);
}
// Passing a bool* to BeginTabItem() is similar to passing one to Begin(): the underlying bool will be set to false when the tab is closed.
ImGui::BeginTabBar("MyTabBar", tab_bar_flags);
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n]))
{
ImGui::Text("This is the %s tab!", names[n]);
if (n & 1)
ImGui::Text("I am an odd tab.");
ImGui::EndTabItem();
}
ImGui::EndTabBar();
ImGui::Separator();
ImGui::TreePop();
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Groups"))
{
ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)");
@ -2507,6 +2595,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::Text("Rounding");
ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f");
ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f");
@ -3397,6 +3486,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)); }
@ -3430,7 +3521,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
ImGui::SetNextWindowViewport(viewport->ID);
}
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();
@ -3594,6 +3685,387 @@ 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)
{
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("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()
//-----------------------------------------------------------------------------
// Simplified structure to mimic a Document model
struct MyDocument
{
const char* Name; // Document title
bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo)
bool OpenPrev; // Copy of Open from last update.
bool Dirty; // Set when the document has been modified
bool WantClose; // Set when the document
ImVec4 Color; // An arbitrary variable associated to the document
MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f))
{
Name = name;
Open = OpenPrev = open;
Dirty = false;
WantClose = false;
Color = color;
}
void DoOpen() { Open = true; }
void DoQueueClose() { WantClose = true; }
void DoForceClose() { Open = false; Dirty = false; }
void DoSave() { Dirty = false; }
// Display dummy contents for the Document
static void DisplayContents(MyDocument* doc)
{
ImGui::PushID(doc);
ImGui::Text("Document \"%s\"", doc->Name);
ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
ImGui::PopStyleColor();
if (ImGui::Button("Modify", ImVec2(100, 0)))
doc->Dirty = true;
ImGui::SameLine();
if (ImGui::Button("Save", ImVec2(100, 0)))
doc->DoSave();
ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
ImGui::PopID();
}
// Display context menu for the Document
static void DisplayContextMenu(MyDocument* doc)
{
if (!ImGui::BeginPopupContextItem())
return;
char buf[256];
sprintf(buf, "Save %s", doc->Name);
if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open))
doc->DoSave();
if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open))
doc->DoQueueClose();
ImGui::EndPopup();
}
};
struct ExampleAppDocuments
{
ImVector<MyDocument> Documents;
ExampleAppDocuments()
{
Documents.push_back(MyDocument("Radish", true, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)));
Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
Documents.push_back(MyDocument("A Rather Long Title", false));
Documents.push_back(MyDocument("Some Document", false));
}
};
// [Optional] Notify the system of Tabs/Windows of closure that happened outside the regular tab interface
// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed
// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence.
// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar
// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame.
// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
{
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
{
MyDocument* doc = &app.Documents[doc_n];
if (!doc->Open && doc->OpenPrev)
ImGui::SetTabItemClosed(doc->Name);
doc->OpenPrev = doc->Open;
}
}
void ShowExampleAppDocuments(bool* p_open)
{
static ExampleAppDocuments app;
ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar);
// Options
enum Target
{
Target_None,
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;
static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
// Menu
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("File"))
{
int open_count = 0;
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
open_count += app.Documents[doc_n].Open ? 1 : 0;
if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
{
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
{
MyDocument* doc = &app.Documents[doc_n];
if (!doc->Open)
if (ImGui::MenuItem(doc->Name))
doc->DoOpen();
}
ImGui::EndMenu();
}
if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
app.Documents[doc_n].DoQueueClose();
if (ImGui::MenuItem("Exit", "Alt+F4")) {}
ImGui::EndMenu();
}
ImGui::EndMenuBar();
}
// [Debug] List documents with one checkbox for each
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
{
MyDocument* doc = &app.Documents[doc_n];
if (doc_n > 0)
ImGui::SameLine();
ImGui::PushID(doc);
if (ImGui::Checkbox(doc->Name, &doc->Open))
if (!doc->Open)
doc->DoForceClose();
ImGui::PopID();
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
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();
// Tabs
if (opt_target == Target_Tab)
{
ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
ImGui::BeginTabBar("##tabs", tab_bar_flags);
if (opt_reorderable)
NotifyOfDocumentsClosedElsewhere(app);
// [DEBUG] Stress tests
//if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
//if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
// Submit Tabs
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
{
MyDocument* doc = &app.Documents[doc_n];
if (!doc->Open)
continue;
ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_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::EndTabItem();
}
}
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;
if (close_queue.empty())
{
// Close queue is locked once we started a popup
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
{
MyDocument* doc = &app.Documents[doc_n];
if (doc->WantClose)
{
doc->WantClose = false;
close_queue.push_back(doc);
}
}
}
// Display closing confirmation UI
if (!close_queue.empty())
{
int close_queue_unsaved_documents = 0;
for (int n = 0; n < close_queue.Size; n++)
if (close_queue[n]->Dirty)
close_queue_unsaved_documents++;
if (close_queue_unsaved_documents == 0)
{
// Close documents when all are unsaved
for (int n = 0; n < close_queue.Size; n++)
close_queue[n]->DoForceClose();
close_queue.clear();
}
else
{
if (!ImGui::IsPopupOpen("Save?"))
ImGui::OpenPopup("Save?");
if (ImGui::BeginPopupModal("Save?"))
{
ImGui::Text("Save change to the following items?");
ImGui::PushItemWidth(-1.0f);
ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6);
for (int n = 0; n < close_queue.Size; n++)
if (close_queue[n]->Dirty)
ImGui::Text("%s", close_queue[n]->Name);
ImGui::ListBoxFooter();
if (ImGui::Button("Yes", ImVec2(80, 0)))
{
for (int n = 0; n < close_queue.Size; n++)
{
if (close_queue[n]->Dirty)
close_queue[n]->DoSave();
close_queue[n]->DoForceClose();
}
close_queue.clear();
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("No", ImVec2(80, 0)))
{
for (int n = 0; n < close_queue.Size; n++)
close_queue[n]->DoForceClose();
close_queue.clear();
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(80, 0)))
{
close_queue.clear();
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
}
ImGui::End();
}
// End of Demo code
#else