Begin: WIP consistent Begin/End behavior.
diff --git a/docs/FAQ.md b/docs/FAQ.md index f47015d..8c247f3 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md
@@ -429,8 +429,10 @@ ### Q: How can I display custom shapes? (using low-level ImDrawList API) - You can use the low-level `ImDrawList` api to render shapes within a window. + ```cpp -ImGui::Begin("My shapes"); +if (!ImGui::Begin("My shapes")) + return; ImDrawList* draw_list = ImGui::GetWindowDrawList();
diff --git a/docs/README.md b/docs/README.md index a555588..c3bccc3 100644 --- a/docs/README.md +++ b/docs/README.md
@@ -52,7 +52,8 @@ Code: ```cpp // Create a window called "My First Tool", with a menu bar. -ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar); +if (!ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar)) + return; if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("File"))
diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index e6a098d..6bae5fc 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp
@@ -122,17 +122,21 @@ ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); +#if 1 + // Enable Debugging + io.ConfigDebugBeginReturnValue = io.KeyShift; +#endif + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). if (show_demo_window) ImGui::ShowDemoWindow(&show_demo_window); // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window. + if (ImGui::Begin("Hello, world!")) // Create a window called "Hello, world!" and append into it. { static float f = 0.0f; static int counter = 0; - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state ImGui::Checkbox("Another Window", &show_another_window); @@ -150,9 +154,9 @@ } // 3. Show another simple window. - if (show_another_window) + // Passing a pointer to our bool variable in the Begin() call: the window will have a closing button that will clear the bool when clicked. + if (show_another_window && ImGui::Begin("Another Window", &show_another_window)) { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) ImGui::Text("Hello from another window!"); if (ImGui::Button("Close Me")) show_another_window = false;
diff --git a/imgui.cpp b/imgui.cpp index 8531fbb..a818748 100644 --- a/imgui.cpp +++ b/imgui.cpp
@@ -1083,6 +1083,9 @@ ConfigWindowsMoveFromTitleBarOnly = false; ConfigMemoryCompactTimer = 60.0f; + // Debug options + ConfigDebugBeginReturnValue = false; + // Platform Functions BackendPlatformName = BackendRendererName = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; @@ -4107,13 +4110,27 @@ UpdateDebugToolItemPicker(); // Create implicit/fallback window - which we will only render it if the user has added something to it. - // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. - // This fallback is particularly important as it avoid ImGui:: calls from crashing. + // - We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. + // - This fallback is particularly important as it avoid ImGui:: calls from crashing. + // - The fallback window exceptionally doesn't call End() automatically if Begin() returns false (this is intended). g.WithinFrameScopeWithImplicitWindow = true; SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); Begin("Debug##Default"); IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); + // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin() return false at different level of the window stack to validate Begin()/End() behavior in user code. + if (g.IO.ConfigDebugBeginReturnValue) + { + g.DebugBeginReturnValueCullDepth = (g.DebugBeginReturnValueCullDepth == -1) ? 0 : ((g.DebugBeginReturnValueCullDepth + ((g.FrameCount % 4) == 0 ? 1 : 0)) % 10); + char buf[64]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "Cull depth %d", g.DebugBeginReturnValueCullDepth); + GetForegroundDrawList()->AddText(ImVec2(0, 0), IM_COL32(255, 255, 0, 255), buf); + } + else + { + g.DebugBeginReturnValueCullDepth = -1; + } + CallContextHooks(&g, ImGuiContextHookType_NewFramePost); } @@ -5120,7 +5137,7 @@ bool ret = Begin(title, NULL, flags); g.Style.ChildBorderSize = backup_border_size; - ImGuiWindow* child_window = g.CurrentWindow; + ImGuiWindow* child_window = g.LastBeginWindow; // FIXME-NEWBEGIN child_window->ChildId = id; child_window->AutoFitChildAxises = (ImS8)auto_fit_axises; @@ -5198,6 +5215,7 @@ // Helper to create a child window / scrolling region that looks like a normal widget frame. bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags) { + // FIXME-NEWBEGIN ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); @@ -5981,6 +5999,7 @@ // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() g.CurrentWindowStack.push_back(window); g.CurrentWindow = window; + g.LastBeginWindow = window; window->DC.StackSizesOnBegin.SetToCurrentState(); g.CurrentWindow = NULL; @@ -6740,7 +6759,24 @@ window->SkipItems = skip_items; } - return !window->SkipItems; + // FIXME-OPT + if (window->SkipItems || g.DebugBeginReturnValueCullDepth == g.CurrentWindowStack.Size) + { + // The implicit fallback is NOT automatically ended as an exception to the rule, + // allowing it to always be able to receive commands without crashing. + if (!window->IsFallbackWindow) + { + if (window->Flags & ImGuiWindowFlags_Popup) + EndPopup(); + else if (window->Flags & ImGuiWindowFlags_ChildWindow) + EndChild(); + else + End(); + } + return false; + } + + return true; } void ImGui::End() @@ -6751,6 +6787,34 @@ // Error checking: verify that user hasn't called End() too many times! if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow) { + // - IMPORTANT: SINCE 1.XX (XXXX 2020): Only call a matching End() if Begin() returned true!. + // - IMPORTANT: BEFORE 1.XX (XXXX 2020): The return value of Begin() was inconsistent with most other BeginXXX() + // functions, and would require the user to always call End() even if Begin() returned false. + + // - When transitioning a codebase from < 1.XX to >= 1.XX, code needs to be refactored the following way: + // Before ------------------------------------> After + // ImGui::Begin("Hello"); if (ImGui::Begin("Hello")) + // ImGui::Button("OK"); { + // ImGui::End(); ImGui::Button("OK"); + // ImGui::End(); + // } + // + // Before ------------------------------------> After + // if (ImGui::Begin("Hello")) if (ImGui::Begin("Hello")) + // { { + // ImGui::Button("OK"); ImGui::Button("OK"); + // } ImGui::End(); + // ImGui::End(); } + // + // Before ------------------------------------> After + // if (!ImGui::Begin("Hello")) if (!ImGui::Begin("Hello")) + // { return; + // ImGui::End(); ImGui::Button("OK"); + // return; ImGui::End(); + // } + // ImGui::Button("OK"); + // ImGui::End(); + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!"); return; } @@ -8509,7 +8573,9 @@ ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); } ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking; - Begin(window_name, NULL, flags | extra_flags); + bool ret = Begin(window_name, NULL, flags | extra_flags); + // FIXME-NEWBEGIN + IM_ASSERT(ret); } void ImGui::EndTooltip() @@ -8765,11 +8831,9 @@ else ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame + // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoDocking; bool is_open = Begin(name, NULL, flags); - if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) - EndPopup(); - return is_open; } @@ -8811,9 +8875,11 @@ const bool is_open = Begin(name, p_open, flags); if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) { - EndPopup(); if (is_open) + { + EndPopup(); ClosePopupToLevel(g.BeginPopupStack.Size, true); + } return false; } return is_open; @@ -10188,7 +10254,10 @@ SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); SetNextWindowPos(viewport->Pos + viewport->Size * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); - Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + bool ret = Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + PopStyleVar(); + if (!ret) + return; for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) { ImGuiWindow* window = g.WindowsFocusOrder[n]; @@ -10200,7 +10269,6 @@ Selectable(label, g.NavWindowingTarget == window); } End(); - PopStyleVar(); } @@ -15680,10 +15748,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) { if (!Begin("Dear ImGui Metrics/Debugger", p_open)) - { - End(); return; - } ImGuiContext& g = *GImGui; ImGuiIO& io = g.IO;
diff --git a/imgui.h b/imgui.h index 52110b8..af4e787 100644 --- a/imgui.h +++ b/imgui.h
@@ -68,6 +68,9 @@ #define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch #define IMGUI_HAS_DOCK 1 // Docking WIP branch +// Features +#define IMGUI_HAS_NEWBEGIN 1 + // Define attributes of all API symbols declarations (e.g. for DLL under Windows) // IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) // Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API) @@ -297,10 +300,10 @@ // - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times. // Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin(). // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting - // anything to the window. Always call a matching End() for each Begin() call, regardless of its return value! - // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, - // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function - // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + // anything to the window. + // - IMPORTANT: SINCE 1.XX (XXXX 2020): Only call a matching End() if Begin() returned true!. + // - IMPORTANT: BEFORE 1.XX (XXXX 2020): The return value of Begin() was inconsistent with most other BeginXXX() + // functions, and would require the user to always call End() even if Begin() returned false. // - Note that the bottom of window stack always contains a window called "Debug". IMGUI_API bool Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); IMGUI_API void End(); @@ -309,10 +312,9 @@ // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400). // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window. - // Always call a matching EndChild() for each BeginChild() call, regardless of its return value. - // [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu, - // BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function - // returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.] + // - IMPORTANT: SINCE 1.XX (XXXX 2020): Only call a matching EndChild() if BeginChild() returned true!. + // - IMPORTANT: BEFORE 1.XX (XXXX 2020): The return value of BeginChild() was inconsistent with most other BeginXXX() + // functions, and would require the user to always call EndChild() even if BeginChild() returned false. This has been changed. IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); IMGUI_API void EndChild(); @@ -1821,6 +1823,9 @@ bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected. float ConfigMemoryCompactTimer; // = 60.0f // [BETA] Free transient windows/tables memory buffers when unused for given amount of time. Set to -1.0f to disable. + // Debug options + bool ConfigDebugBeginReturnValue; // = false // When set, some calls to Begin() will return false to facilitate testing and transitioning to 1.78 Begin()/End() pairing behavior. Will cycle through each unique window depth then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering. Your code will assert in End() if calling End() incorrectly. + //------------------------------------------------------------------ // Platform Functions // (the imgui_impl_xxxx backend files are setting those up for you)
diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4df021c..76b8c95 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp
@@ -300,9 +300,11 @@ if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } if (show_app_style_editor) { - ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); - ImGui::ShowStyleEditor(); - ImGui::End(); + if (ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor)) + { + ImGui::ShowStyleEditor(); + ImGui::End(); + } } // Demonstrate the various window flags. Typically you would just use the default! @@ -339,11 +341,7 @@ // Main body of the Demo window starts here. if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags)) - { - // Early out if the window is collapsed, as an optimization. - ImGui::End(); return; - } // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. @@ -2109,48 +2107,54 @@ static bool embed_all_inside_a_child_window = false; ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window); + bool visible = true; if (embed_all_inside_a_child_window) - ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); + visible = ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true); - // Testing IsWindowFocused() function with its various flags. - // Note that the ImGuiFocusedFlags_XXX flags can be combined. - ImGui::BulletText( - "IsWindowFocused() = %d\n" - "IsWindowFocused(_ChildWindows) = %d\n" - "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" - "IsWindowFocused(_RootWindow) = %d\n" - "IsWindowFocused(_AnyWindow) = %d\n", - ImGui::IsWindowFocused(), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); + if (visible) + { + // Testing IsWindowFocused() function with its various flags. + // Note that the ImGuiFocusedFlags_XXX flags can be combined. + ImGui::BulletText( + "IsWindowFocused() = %d\n" + "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_AnyWindow) = %d\n", + ImGui::IsWindowFocused(), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); - // Testing IsWindowHovered() function with its various flags. - // Note that the ImGuiHoveredFlags_XXX flags can be combined. - ImGui::BulletText( - "IsWindowHovered() = %d\n" - "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" - "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" - "IsWindowHovered(_ChildWindows) = %d\n" - "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" - "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" - "IsWindowHovered(_RootWindow) = %d\n" - "IsWindowHovered(_AnyWindow) = %d\n", - ImGui::IsWindowHovered(), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); + // Testing IsWindowHovered() function with its various flags. + // Note that the ImGuiHoveredFlags_XXX flags can be combined. + ImGui::BulletText( + "IsWindowHovered() = %d\n" + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsWindowHovered(_ChildWindows) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_RootWindow) = %d\n" + "IsWindowHovered(_AnyWindow) = %d\n", + ImGui::IsWindowHovered(), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)); - ImGui::BeginChild("child", ImVec2(0, 50), true); - ImGui::Text("This is another child window for testing the _ChildWindows flag."); - ImGui::EndChild(); - if (embed_all_inside_a_child_window) - ImGui::EndChild(); + if (ImGui::BeginChild("child", ImVec2(0, 50), true)) + { + ImGui::Text("This is another child window for testing the _ChildWindows flag."); + ImGui::EndChild(); + } + if (embed_all_inside_a_child_window) + ImGui::EndChild(); + } static char unused_str[] = "This widget is only here to be able to tab-out of the widgets above."; ImGui::InputText("unused", unused_str, IM_ARRAYSIZE(unused_str), ImGuiInputTextFlags_ReadOnly); @@ -2159,12 +2163,11 @@ // This is useful in particular if you want to create a context menu 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; + // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. + // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); - if (test_window) + if (test_window && ImGui::Begin("Title bar Hovered/Active tests", &test_window)) { - // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. - // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? - ImGui::Begin("Title bar Hovered/Active tests", &test_window); if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() { if (ImGui::MenuItem("Close")) { test_window = false; } @@ -2199,10 +2202,12 @@ ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar; if (disable_mouse_wheel) window_flags |= ImGuiWindowFlags_NoScrollWithMouse; - ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags); - for (int i = 0; i < 100; i++) - ImGui::Text("%04d: scrollable region", i); - ImGui::EndChild(); + if (ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags)) + { + for (int i = 0; i < 100; i++) + ImGui::Text("%04d: scrollable region", i); + ImGui::EndChild(); + } } ImGui::SameLine(); @@ -2215,29 +2220,32 @@ if (!disable_menu) window_flags |= ImGuiWindowFlags_MenuBar; ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); - ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); - if (!disable_menu && ImGui::BeginMenuBar()) - { - if (ImGui::BeginMenu("Menu")) - { - ShowExampleMenuFile(); - ImGui::EndMenu(); - } - ImGui::EndMenuBar(); - } - if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings)) - { - for (int i = 0; i < 100; i++) - { - char buf[32]; - sprintf(buf, "%03d", i); - ImGui::TableNextColumn(); - ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); - } - ImGui::EndTable(); - } - ImGui::EndChild(); + bool visible = ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags); ImGui::PopStyleVar(); + if (visible) + { + if (!disable_menu && ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Menu")) + { + ShowExampleMenuFile(); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + if (ImGui::BeginTable("split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings)) + { + for (int i = 0; i < 100; i++) + { + char buf[32]; + sprintf(buf, "%03d", i); + ImGui::TableNextColumn(); + ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f)); + } + ImGui::EndTable(); + } + ImGui::EndChild(); + } } ImGui::Separator(); @@ -2256,14 +2264,17 @@ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x); ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100)); - ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); - for (int n = 0; n < 50; n++) - ImGui::Text("Some test %d", n); - ImGui::EndChild(); + bool visible = ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None); + ImGui::PopStyleColor(); + if (visible) + { + for (int n = 0; n < 50; n++) + ImGui::Text("Some test %d", n); + ImGui::EndChild(); + } bool child_is_hovered = ImGui::IsItemHovered(); ImVec2 child_rect_min = ImGui::GetItemRectMin(); ImVec2 child_rect_max = ImGui::GetItemRectMax(); - ImGui::PopStyleColor(); ImGui::Text("Hovered: %d", child_is_hovered); ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y); } @@ -2780,18 +2791,17 @@ const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags); - if (ImGui::BeginMenuBar()) + if (ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags)) { - ImGui::TextUnformatted("abc"); - ImGui::EndMenuBar(); - } - if (scroll_to_off) - ImGui::SetScrollY(scroll_to_off_px); - if (scroll_to_pos) - ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); - if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items - { + if (ImGui::BeginMenuBar()) + { + ImGui::TextUnformatted("abc"); + ImGui::EndMenuBar(); + } + if (scroll_to_off) + ImGui::SetScrollY(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f); for (int item = 0; item < 100; item++) { if (enable_track && item == track_item) @@ -2804,11 +2814,15 @@ ImGui::Text("Item %d", item); } } + float scroll_y = ImGui::GetScrollY(); + float scroll_max_y = ImGui::GetScrollMaxY(); + ImGui::EndChild(); + ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); } - float scroll_y = ImGui::GetScrollY(); - float scroll_max_y = ImGui::GetScrollMaxY(); - ImGui::EndChild(); - ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y); + else + { + ImGui::Text("N/A"); + } ImGui::EndGroup(); } ImGui::PopID(); @@ -2826,13 +2840,14 @@ float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags); - if (scroll_to_off) - ImGui::SetScrollX(scroll_to_off_px); - if (scroll_to_pos) - ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); - if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items + float scroll_x = 0.0f; + float scroll_max_x = 0.0f; + if (ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags)) { + if (scroll_to_off) + ImGui::SetScrollX(scroll_to_off_px); + if (scroll_to_pos) + ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f); for (int item = 0; item < 100; item++) { if (enable_track && item == track_item) @@ -2846,10 +2861,10 @@ } ImGui::SameLine(); } + scroll_x = ImGui::GetScrollX(); + scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); } - float scroll_x = ImGui::GetScrollX(); - float scroll_max_x = ImGui::GetScrollMaxX(); - ImGui::EndChild(); ImGui::SameLine(); const char* names[] = { "Left", "25%", "Center", "75%", "Right" }; ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x); @@ -2866,33 +2881,37 @@ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); - ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar); - for (int line = 0; line < lines; line++) + float scroll_x = 0.0f; + float scroll_max_x = 0.0f; + if (ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar)) { - // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() - // If you want to create your own time line for a real application you may be better off manipulating - // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets - // yourself. You may also want to use the lower-level ImDrawList API. - int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); - for (int n = 0; n < num_buttons; n++) + for (int line = 0; line < lines; line++) { - if (n > 0) ImGui::SameLine(); - ImGui::PushID(n + line * 1000); - char num_buf[16]; - sprintf(num_buf, "%d", n); - const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; - float hue = n * 0.05f; - ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); - ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); - ImGui::PopStyleColor(3); - ImGui::PopID(); + // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() + // If you want to create your own time line for a real application you may be better off manipulating + // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets + // yourself. You may also want to use the lower-level ImDrawList API. + int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); + for (int n = 0; n < num_buttons; n++) + { + if (n > 0) ImGui::SameLine(); + ImGui::PushID(n + line * 1000); + char num_buf[16]; + sprintf(num_buf, "%d", n); + const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf; + float hue = n * 0.05f; + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); + ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } } + scroll_x = ImGui::GetScrollX(); + scroll_max_x = ImGui::GetScrollMaxX(); + ImGui::EndChild(); } - float scroll_x = ImGui::GetScrollX(); - float scroll_max_x = ImGui::GetScrollMaxX(); - ImGui::EndChild(); ImGui::PopStyleVar(2); float scroll_x_delta = 0.0f; ImGui::SmallButton("<<"); @@ -2909,9 +2928,12 @@ { // Demonstrate a trick: you can use Begin to set yourself in the context of another window // (here we are already out of your child window) - ImGui::BeginChild("scrolling"); - ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); - ImGui::EndChild(); + // FIXME-NEWBEGIN: Becomes more awkward + if (ImGui::BeginChild("scrolling")) + { + ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta); + ImGui::EndChild(); + } } ImGui::Spacing(); @@ -2931,88 +2953,90 @@ static float contents_size_x = 300.0f; if (explicit_content_size) ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f)); - ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0); - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); - HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); - ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); - ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) - ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width - ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size - ImGui::Checkbox("Columns", &show_columns); // Will use contents size - ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size - ImGui::Checkbox("Child", &show_child); // Will grow and use contents size - ImGui::Checkbox("Explicit content size", &explicit_content_size); - ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); - if (explicit_content_size) + if (ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0)) { - ImGui::SameLine(); - ImGui::SetNextItemWidth(100); - ImGui::DragFloat("##csx", &contents_size_x); - ImVec2 p = ImGui::GetCursorScreenPos(); - ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); - ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); - ImGui::Dummy(ImVec2(0, 10)); - } - ImGui::PopStyleVar(2); - ImGui::Separator(); - if (show_button) - { - ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); - } - if (show_tree_nodes) - { - bool open = true; - if (ImGui::TreeNode("this is a tree node")) + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0)); + HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles."); + ImGui::Checkbox("H-scrollbar", &show_h_scrollbar); + ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten) + ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width + ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size + ImGui::Checkbox("Columns", &show_columns); // Will use contents size + ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size + ImGui::Checkbox("Child", &show_child); // Will grow and use contents size + ImGui::Checkbox("Explicit content size", &explicit_content_size); + ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY()); + if (explicit_content_size) { - if (ImGui::TreeNode("another one of those tree node...")) + ImGui::SameLine(); + ImGui::SetNextItemWidth(100); + ImGui::DragFloat("##csx", &contents_size_x); + ImVec2 p = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE); + ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE); + ImGui::Dummy(ImVec2(0, 10)); + } + ImGui::PopStyleVar(2); + ImGui::Separator(); + if (show_button) + { + ImGui::Button("this is a 300-wide button", ImVec2(300, 0)); + } + if (show_tree_nodes) + { + bool open = true; + if (ImGui::TreeNode("this is a tree node")) { - ImGui::Text("Some tree contents"); + if (ImGui::TreeNode("another one of those tree node...")) + { + ImGui::Text("Some tree contents"); + ImGui::TreePop(); + } ImGui::TreePop(); } - ImGui::TreePop(); + ImGui::CollapsingHeader("CollapsingHeader", &open); } - ImGui::CollapsingHeader("CollapsingHeader", &open); - } - if (show_text_wrapped) - { - ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); - } - if (show_columns) - { - ImGui::Text("Tables:"); - if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders)) + if (show_text_wrapped) { + ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle."); + } + if (show_columns) + { + ImGui::Text("Tables:"); + if (ImGui::BeginTable("table", 4, ImGuiTableFlags_Borders)) + { + for (int n = 0; n < 4; n++) + { + ImGui::TableNextColumn(); + ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x); + } + ImGui::EndTable(); + } + ImGui::Text("Columns:"); + ImGui::Columns(4); for (int n = 0; n < 4; n++) { - ImGui::TableNextColumn(); - ImGui::Text("Width %.2f", ImGui::GetContentRegionAvail().x); + ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); + ImGui::NextColumn(); } - ImGui::EndTable(); + ImGui::Columns(1); } - ImGui::Text("Columns:"); - ImGui::Columns(4); - for (int n = 0; n < 4; n++) + if (show_tab_bar && ImGui::BeginTabBar("Hello")) { - ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); - ImGui::NextColumn(); + if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } + if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } + ImGui::EndTabBar(); } - ImGui::Columns(1); + if (show_child) + { + if (ImGui::BeginChild("child", ImVec2(0, 0), true)) + ImGui::EndChild(); + } + ImGui::End(); } - if (show_tab_bar && ImGui::BeginTabBar("Hello")) - { - if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); } - ImGui::EndTabBar(); - } - if (show_child) - { - ImGui::BeginChild("child", ImVec2(0, 0), true); - ImGui::EndChild(); - } - ImGui::End(); } ImGui::TreePop(); @@ -5147,24 +5171,25 @@ { ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f)); ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); - ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); - ImGui::Columns(10); - - // Also demonstrate using clipper for large vertical lists - int ITEMS_COUNT = 2000; - ImGuiListClipper clipper; - clipper.Begin(ITEMS_COUNT); - while (clipper.Step()) + if (ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar)) { - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) - for (int j = 0; j < 10; j++) - { - ImGui::Text("Line %d Column %d...", i, j); - ImGui::NextColumn(); - } + // Also demonstrate using clipper for large vertical lists + ImGui::Columns(10); + int ITEMS_COUNT = 2000; + ImGuiListClipper clipper; + clipper.Begin(ITEMS_COUNT); + while (clipper.Step()) + { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + for (int j = 0; j < 10; j++) + { + ImGui::Text("Line %d Column %d...", i, j); + ImGui::NextColumn(); + } + } + ImGui::Columns(1); + ImGui::EndChild(); } - ImGui::Columns(1); - ImGui::EndChild(); ImGui::TreePop(); } @@ -5388,10 +5413,8 @@ void ImGui::ShowAboutWindow(bool* p_open) { if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::End(); return; - } + ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); ImGui::Separator(); ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); @@ -5407,6 +5430,7 @@ bool copy_to_clipboard = ImGui::Button("Copy to clipboard"); ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18); ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove); + if (copy_to_clipboard) { ImGui::LogToClipboard(); @@ -5534,7 +5558,6 @@ ImGui::LogText("\n```\n"); ImGui::LogFinish(); } - ImGui::EndChildFrame(); } ImGui::End(); } @@ -5804,29 +5827,31 @@ "Left-click on color square to open color picker,\n" "Right-click to open edit options menu."); - ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened); - ImGui::PushItemWidth(-160); - for (int i = 0; i < ImGuiCol_COUNT; i++) + if (ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened)) { - const char* name = ImGui::GetStyleColorName(i); - if (!filter.PassFilter(name)) - continue; - ImGui::PushID(i); - ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); - if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) + ImGui::PushItemWidth(-160); + for (int i = 0; i < ImGuiCol_COUNT; i++) { - // Tips: in a real user application, you may want to merge and use an icon font into the main font, - // so instead of "Save"/"Revert" you'd use icons! - // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } + const char* name = ImGui::GetStyleColorName(i); + if (!filter.PassFilter(name)) + continue; + ImGui::PushID(i); + ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); + if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) + { + // Tips: in a real user application, you may want to merge and use an icon font into the main font, + // so instead of "Save"/"Revert" you'd use icons! + // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } + } + ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); + ImGui::TextUnformatted(name); + ImGui::PopID(); } - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); - ImGui::TextUnformatted(name); - ImGui::PopID(); + ImGui::PopItemWidth(); + ImGui::EndChild(); } - ImGui::PopItemWidth(); - ImGui::EndChild(); ImGui::EndTabItem(); } @@ -5986,10 +6011,12 @@ { static bool enabled = true; ImGui::MenuItem("Enabled", "", &enabled); - ImGui::BeginChild("child", ImVec2(0, 60), true); - for (int i = 0; i < 10; i++) - ImGui::Text("Scrolling Text %d", i); - ImGui::EndChild(); + if (ImGui::BeginChild("child", ImVec2(0, 60), true)) + { + for (int i = 0; i < 10; i++) + ImGui::Text("Scrolling Text %d", i); + ImGui::EndChild(); + } static float f = 0.5f; static int n = 0; ImGui::SliderFloat("Value", &f, 0.0f, 1.0f); @@ -6099,10 +6126,7 @@ { ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin(title, p_open)) - { - ImGui::End(); return; - } // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. // So e.g. IsItemHovered() will return true when hovering the title bar. @@ -6148,67 +6172,69 @@ // Reserve enough left-over height for 1 separator + 1 input text const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); - ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); - if (ImGui::BeginPopupContextWindow()) + if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar)) { - if (ImGui::Selectable("Clear")) ClearLog(); - ImGui::EndPopup(); + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::Selectable("Clear")) ClearLog(); + ImGui::EndPopup(); + } + + // Display every line as a separate entry so we can change their color or add custom widgets. + // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); + // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping + // to only process visible items. The clipper will automatically measure the height of your first item and then + // "seek" to display only items in the visible area. + // To use the clipper we can replace your standard loop: + // for (int i = 0; i < Items.Size; i++) + // With: + // ImGuiListClipper clipper; + // clipper.Begin(Items.Size); + // while (clipper.Step()) + // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) + // - That your items are evenly spaced (same height) + // - That you have cheap random access to your elements (you can access them given their index, + // without processing all the ones before) + // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. + // We would need random-access on the post-filtered list. + // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices + // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, + // and appending newly elements as they are inserted. This is left as a task to the user until we can manage + // to improve this example code! + // If your items are of variable height: + // - Split them into same height items would be simpler and facilitate random-seeking into your list. + // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing + if (copy_to_clipboard) + ImGui::LogToClipboard(); + for (int i = 0; i < Items.Size; i++) + { + const char* item = Items[i]; + if (!Filter.PassFilter(item)) + continue; + + // Normally you would store more information in your item than just a string. + // (e.g. make Items[] an array of structure, store color/type etc.) + ImVec4 color; + bool has_color = false; + if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } + else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } + if (has_color) + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::TextUnformatted(item); + if (has_color) + ImGui::PopStyleColor(); + } + if (copy_to_clipboard) + ImGui::LogFinish(); + + if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) + ImGui::SetScrollHereY(1.0f); + ScrollToBottom = false; + + ImGui::PopStyleVar(); + ImGui::EndChild(); } - - // Display every line as a separate entry so we can change their color or add custom widgets. - // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end()); - // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping - // to only process visible items. The clipper will automatically measure the height of your first item and then - // "seek" to display only items in the visible area. - // To use the clipper we can replace your standard loop: - // for (int i = 0; i < Items.Size; i++) - // With: - // ImGuiListClipper clipper; - // clipper.Begin(Items.Size); - // while (clipper.Step()) - // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) - // - That your items are evenly spaced (same height) - // - That you have cheap random access to your elements (you can access them given their index, - // without processing all the ones before) - // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property. - // We would need random-access on the post-filtered list. - // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices - // or offsets of items that passed the filtering test, recomputing this array when user changes the filter, - // and appending newly elements as they are inserted. This is left as a task to the user until we can manage - // to improve this example code! - // If your items are of variable height: - // - Split them into same height items would be simpler and facilitate random-seeking into your list. - // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items. - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing - if (copy_to_clipboard) - ImGui::LogToClipboard(); - for (int i = 0; i < Items.Size; i++) - { - const char* item = Items[i]; - if (!Filter.PassFilter(item)) - continue; - - // Normally you would store more information in your item than just a string. - // (e.g. make Items[] an array of structure, store color/type etc.) - ImVec4 color; - bool has_color = false; - if (strstr(item, "[error]")) { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; } - else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; } - if (has_color) - ImGui::PushStyleColor(ImGuiCol_Text, color); - ImGui::TextUnformatted(item); - if (has_color) - ImGui::PopStyleColor(); - } - if (copy_to_clipboard) - ImGui::LogFinish(); - - if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())) - ImGui::SetScrollHereY(1.0f); - ScrollToBottom = false; - - ImGui::PopStyleVar(); - ImGui::EndChild(); ImGui::Separator(); // Command-line @@ -6432,10 +6458,7 @@ void Draw(const char* title, bool* p_open = NULL) { if (!ImGui::Begin(title, p_open)) - { - ImGui::End(); return; - } // Options menu if (ImGui::BeginPopup("Options")) @@ -6455,64 +6478,65 @@ Filter.Draw("Filter", -100.0f); ImGui::Separator(); - ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); - - if (clear) - Clear(); - if (copy) - ImGui::LogToClipboard(); - - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - const char* buf = Buf.begin(); - const char* buf_end = Buf.end(); - if (Filter.IsActive()) + if (ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { - // In this example we don't use the clipper when Filter is enabled. - // This is because we don't have a random access on the result on our filter. - // A real application processing logs with ten of thousands of entries may want to store the result of - // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). - for (int line_no = 0; line_no < LineOffsets.Size; line_no++) + if (clear) + Clear(); + if (copy) + ImGui::LogToClipboard(); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + const char* buf = Buf.begin(); + const char* buf_end = Buf.end(); + if (Filter.IsActive()) { - const char* line_start = buf + LineOffsets[line_no]; - const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; - if (Filter.PassFilter(line_start, line_end)) - ImGui::TextUnformatted(line_start, line_end); - } - } - else - { - // The simplest and easy way to display the entire buffer: - // ImGui::TextUnformatted(buf_begin, buf_end); - // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward - // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are - // within the visible area. - // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them - // on your side is recommended. Using ImGuiListClipper requires - // - A) random access into your data - // - B) items all being the same height, - // both of which we can handle since we an array pointing to the beginning of each line of text. - // When using the filter (in the block of code above) we don't have random access into the data to display - // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make - // it possible (and would be recommended if you want to search through tens of thousands of entries). - ImGuiListClipper clipper; - clipper.Begin(LineOffsets.Size); - while (clipper.Step()) - { - for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + // In this example we don't use the clipper when Filter is enabled. + // This is because we don't have a random access on the result on our filter. + // A real application processing logs with ten of thousands of entries may want to store the result of + // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp). + for (int line_no = 0; line_no < LineOffsets.Size; line_no++) { const char* line_start = buf + LineOffsets[line_no]; const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; - ImGui::TextUnformatted(line_start, line_end); + if (Filter.PassFilter(line_start, line_end)) + ImGui::TextUnformatted(line_start, line_end); } } - clipper.End(); + else + { + // The simplest and easy way to display the entire buffer: + // ImGui::TextUnformatted(buf_begin, buf_end); + // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward + // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are + // within the visible area. + // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them + // on your side is recommended. Using ImGuiListClipper requires + // - A) random access into your data + // - B) items all being the same height, + // both of which we can handle since we an array pointing to the beginning of each line of text. + // When using the filter (in the block of code above) we don't have random access into the data to display + // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make + // it possible (and would be recommended if you want to search through tens of thousands of entries). + ImGuiListClipper clipper; + clipper.Begin(LineOffsets.Size); + while (clipper.Step()) + { + for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) + { + const char* line_start = buf + LineOffsets[line_no]; + const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; + ImGui::TextUnformatted(line_start, line_end); + } + } + clipper.End(); + } + ImGui::PopStyleVar(); + + if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) + ImGui::SetScrollHereY(1.0f); + + ImGui::EndChild(); } - ImGui::PopStyleVar(); - - if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) - ImGui::SetScrollHereY(1.0f); - - ImGui::EndChild(); ImGui::End(); } }; @@ -6526,22 +6550,24 @@ // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window. // Most of the contents of the window will be added by the log.Draw() call. ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); - ImGui::Begin("Example: Log", p_open); - if (ImGui::SmallButton("[Debug] Add 5 entries")) + if (ImGui::Begin("Example: Log", p_open)) { - static int counter = 0; - const char* categories[3] = { "info", "warn", "error" }; - const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; - for (int n = 0; n < 5; n++) + if (ImGui::SmallButton("[Debug] Add 5 entries")) { - const char* category = categories[counter % IM_ARRAYSIZE(categories)]; - const char* word = words[counter % IM_ARRAYSIZE(words)]; - log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", - ImGui::GetFrameCount(), category, ImGui::GetTime(), word); - counter++; + static int counter = 0; + const char* categories[3] = { "info", "warn", "error" }; + const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" }; + for (int n = 0; n < 5; n++) + { + const char* category = categories[counter % IM_ARRAYSIZE(categories)]; + const char* word = words[counter % IM_ARRAYSIZE(words)]; + log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n", + ImGui::GetFrameCount(), category, ImGui::GetTime(), word); + counter++; + } } + ImGui::End(); } - ImGui::End(); // Actually call in the regular Log helper (which will Begin() into the same window as we just did) log.Draw("Example: Log", p_open); @@ -6555,22 +6581,23 @@ static void ShowExampleAppLayout(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver); - if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) + if (!ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar)) + return; + if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenuBar()) + if (ImGui::BeginMenu("File")) { - if (ImGui::BeginMenu("File")) - { - if (ImGui::MenuItem("Close")) *p_open = false; - ImGui::EndMenu(); - } - ImGui::EndMenuBar(); + if (ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndMenu(); } + ImGui::EndMenuBar(); + } - // Left - static int selected = 0; + // Left + static int selected = 0; + { + if (ImGui::BeginChild("left pane", ImVec2(150, 0), true)) { - ImGui::BeginChild("left pane", ImVec2(150, 0), true); for (int i = 0; i < 100; i++) { char label[128]; @@ -6580,12 +6607,14 @@ } ImGui::EndChild(); } - ImGui::SameLine(); + } + ImGui::SameLine(); - // Right + // Right + { + ImGui::BeginGroup(); + if (ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()))) // Leave room for 1 line below us { - ImGui::BeginGroup(); - ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us ImGui::Text("MyObject: %d", selected); ImGui::Separator(); if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None)) @@ -6603,11 +6632,11 @@ ImGui::EndTabBar(); } ImGui::EndChild(); - if (ImGui::Button("Revert")) {} - ImGui::SameLine(); - if (ImGui::Button("Save")) {} - ImGui::EndGroup(); } + if (ImGui::Button("Revert")) {} + ImGui::SameLine(); + if (ImGui::Button("Save")) {} + ImGui::EndGroup(); } ImGui::End(); } @@ -6668,10 +6697,7 @@ { ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Property editor", p_open)) - { - ImGui::End(); return; - } HelpMarker( "This example shows how you may implement a property editor using two columns.\n" @@ -6703,10 +6729,7 @@ { ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Long text display", p_open)) - { - ImGui::End(); return; - } static int test_type = 0; static ImGuiTextBuffer log; @@ -6725,14 +6748,16 @@ log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i); lines += 1000; } - ImGui::BeginChild("Log"); - switch (test_type) + + if (ImGui::BeginChild("Log")) { - case 0: - // Single call to TextUnformatted() with a big buffer - ImGui::TextUnformatted(log.begin(), log.end()); - break; - case 1: + switch (test_type) + { + case 0: + // Single call to TextUnformatted() with a big buffer + ImGui::TextUnformatted(log.begin(), log.end()); + break; + case 1: { // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper. ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); @@ -6744,15 +6769,16 @@ ImGui::PopStyleVar(); break; } - case 2: - // Multiple calls to Text(), not clipped (slow) - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); - for (int i = 0; i < lines; i++) - ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); - ImGui::PopStyleVar(); - break; + case 2: + // Multiple calls to Text(), not clipped (slow) + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + for (int i = 0; i < lines; i++) + ImGui::Text("%i The quick brown fox jumps over the lazy dog", i); + ImGui::PopStyleVar(); + break; + } + ImGui::EndChild(); } - ImGui::EndChild(); ImGui::End(); } @@ -6764,10 +6790,7 @@ static void ShowExampleAppAutoResize(bool* p_open) { if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::End(); return; - } static int lines = 10; ImGui::TextUnformatted( @@ -6817,21 +6840,22 @@ if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; - if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) - { - 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)); } - ImGui::SetNextItemWidth(200); - ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); - ImGui::SetNextItemWidth(200); - ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); - ImGui::Checkbox("Auto-resize", &auto_resize); - for (int i = 0; i < display_lines; i++) - ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); - } + if (!ImGui::Begin("Example: Constrained Resize", p_open, flags)) + return; + + 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)); } + ImGui::SetNextItemWidth(200); + ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); + ImGui::SetNextItemWidth(200); + ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); + ImGui::Checkbox("Auto-resize", &auto_resize); + for (int i = 0; i < display_lines; i++) + ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); ImGui::End(); } @@ -6860,24 +6884,24 @@ ImGui::SetNextWindowViewport(viewport->ID); } ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background - if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) + if (!ImGui::Begin("Example: Simple overlay", p_open, window_flags)) + return; + + ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); + ImGui::Separator(); + if (ImGui::IsMousePosValid()) + ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); + else + ImGui::Text("Mouse Position: <invalid>"); + if (ImGui::BeginPopupContextWindow()) { - ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); - ImGui::Separator(); - if (ImGui::IsMousePosValid()) - ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); - else - ImGui::Text("Mouse Position: <invalid>"); - if (ImGui::BeginPopupContextWindow()) - { - if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; - if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; - if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; - if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; - if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; - if (p_open && ImGui::MenuItem("Close")) *p_open = false; - ImGui::EndPopup(); - } + if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; + if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; + if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; + if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; + if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; + if (p_open && ImGui::MenuItem("Close")) *p_open = false; + ImGui::EndPopup(); } ImGui::End(); } @@ -6896,22 +6920,28 @@ // Using "##" to display same title but have unique identifier. ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver); - ImGui::Begin("Same title as another window##1"); - ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); - ImGui::End(); + if (ImGui::Begin("Same title as another window##1")) + { + ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique."); + ImGui::End(); + } ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver); - ImGui::Begin("Same title as another window##2"); - ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); - ImGui::End(); + if (ImGui::Begin("Same title as another window##2")) + { + ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); + ImGui::End(); + } // Using "###" to display a changing title but keep a static identifier "AnimatedTitle" char buf[128]; sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount()); ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver); - ImGui::Begin(buf); - ImGui::Text("This window has a changing title."); - ImGui::End(); + if (ImGui::Begin(buf)) + { + ImGui::Text("This window has a changing title."); + ImGui::End(); + } } //----------------------------------------------------------------------------- @@ -6922,10 +6952,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) { if (!ImGui::Begin("Example: Custom rendering", p_open)) - { - ImGui::End(); return; - } // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your @@ -7376,11 +7403,8 @@ // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking. bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); - if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow) - { - ImGui::End(); + if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow) // FIXME-NEWBEGIN return; - } // Menu if (ImGui::BeginMenuBar())
diff --git a/imgui_internal.h b/imgui_internal.h index bb8ea5c..3ff9cde 100644 --- a/imgui_internal.h +++ b/imgui_internal.h
@@ -1438,6 +1438,7 @@ ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. ImGuiDockNode* HoveredDockNode; // Hovered dock node. ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. + ImGuiWindow* LastBeginWindow; // Track the last window we called Begin() on, this is used to easily access it even if Begin() returned false. ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. ImVec2 WheelingWindowRefMousePos; float WheelingWindowTimer; @@ -1640,6 +1641,7 @@ // Debug Tools bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this id + int DebugBeginReturnValueCullDepth; // Cycle between 0..9 then wrap around. ImGuiMetricsConfig DebugMetricsConfig; // Misc @@ -1675,6 +1677,7 @@ HoveredWindowUnderMovingWindow = NULL; HoveredDockNode = NULL; MovingWindow = NULL; + LastBeginWindow = NULL; WheelingWindow = NULL; WheelingWindowTimer = 0.0f; @@ -1793,6 +1796,7 @@ DebugItemPickerActive = false; DebugItemPickerBreakId = 0; + DebugBeginReturnValueCullDepth = -1; memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); FramerateSecPerFrameIdx = 0;
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4d232fb..2e99e6e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp
@@ -1627,7 +1627,6 @@ PopStyleVar(); if (!ret) { - EndPopup(); IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above return false; } @@ -3838,7 +3837,6 @@ PopStyleColor(); if (!child_visible) { - EndChild(); EndGroup(); return false; } @@ -6133,8 +6131,8 @@ if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - BeginChildFrame(id, frame_bb.GetSize()); - return true; + // FIXME-NEWBEGIN + return BeginChildFrame(id, frame_bb.GetSize()); } // FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. @@ -6568,10 +6566,7 @@ g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); if (!is_open) - { - End(); return false; - } return true; //-V1020 }
diff --git a/misc/freetype/README.md b/misc/freetype/README.md index e565097..0a83602 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md
@@ -104,7 +104,8 @@ // Call to draw interface void ShowFreetypeOptionsWindow() { - ImGui::Begin("FreeType Options"); + if (!ImGui::Begin("FreeType Options")) + return; ImGui::ShowFontSelector("Fonts"); WantRebuild |= ImGui::RadioButton("FreeType", (int*)&BuildMode, FontBuildMode_FreeType); ImGui::SameLine();