From 2785ac0ee342d5cbcab0d546d773e7492a1e3cfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BE=E8=B5=B7=E5=A8=81?= Date: Wed, 11 Nov 2020 11:35:47 +0100 Subject: [PATCH 01/15] InputText: Fixed updating cursor/selection position when a callback alters the buffer in a way where the byte count is unchanged but the decoded character count changes. (#3587) --- docs/CHANGELOG.txt | 4 +++- imgui_widgets.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7b8254ac..8dc2aa48 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,9 +64,11 @@ Other Changes: - Drag and Drop: Fix drag and drop to tie same-size drop targets by choosen the later one. Fixes dragging into a full-window-sized dockspace inside a zero-padded window. (#3519, #2717) [@Black-Cat] - Checkbox: Added CheckboxFlags() helper with int* type. +- InputText: Fixed updating cursor/selection position when a callback altered the buffer in a way + where the byte count is unchanged but the decoded character count changes. (#3587) [@gqw] - Metrics: Fixed mishandling of ImDrawCmd::VtxOffset in wireframe mesh renderer. - Misc: Replaced UTF-8 decoder by branchless one by Christopher Wellons (30~40% faster). [@rokups] - Super minor fix handling incomplete UTF-8 contents: if input does not contain enough bytes, decoder + Super minor fix handling incomplete UTF-8 contents: if input does not contain enough bytes, decoder returns IM_UNICODE_CODEPOINT_INVALID and consume remaining bytes (vs old decoded consumed only 1 byte). - Backends: OpenGL3: Use glGetString(GL_VERSION) query instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x). (#3530) [@xndcn] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2c5e1814..d8f88f9e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4273,10 +4273,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(callback_data.Buf == state->TextA.Data); // Invalid to modify those fields IM_ASSERT(callback_data.BufSize == state->BufCapacityA); IM_ASSERT(callback_data.Flags == flags); - if (callback_data.CursorPos != utf8_cursor_pos) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } - if (callback_data.SelectionStart != utf8_selection_start) { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } - if (callback_data.SelectionEnd != utf8_selection_end) { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } - if (callback_data.BufDirty) + const bool buf_dirty = callback_data.BufDirty; + if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (buf_dirty) { IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! if (callback_data.BufTextLen > backup_current_text_length && is_resizable) From 61825c7735ada0797a536bbd74d5c93d9e23cef3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Nov 2020 12:04:35 +0100 Subject: [PATCH 02/15] Tab Bar: Fixed minor/unlikely bug skipping over a button when scrolling left with arrows + InputText: minor optimization. --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8dc2aa48..ad6b11c4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,7 @@ Other Changes: - Tab Bar: Made it possible to append to an existing tab bar by calling BeginTabBar()/EndTabBar() again. - Tab Bar: Fixed using more than 128 tabs in a tab bar (scrolling policy recommended). - Tab Bar: Do not display a tooltip if the name already fits over a given tab. (#3521) +- Tab Bar: Fixed minor/unlikely bug skipping over a button when scrolling left with arrows. - Drag and Drop: Fix losing drop source ActiveID (and often source tooltip) when opening a TreeNode() or CollapsingHeader() while dragging. (#1738) - Drag and Drop: Fix drag and drop to tie same-size drop targets by choosen the later one. Fixes dragging diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d8f88f9e..8fe841e1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4275,8 +4275,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(callback_data.Flags == flags); const bool buf_dirty = callback_data.BufDirty; if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } - if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } - if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } if (buf_dirty) { IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! @@ -7388,7 +7388,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) { target_order += select_dir; selected_order += select_dir; - tab_to_scroll_to = (target_order <= 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL; + tab_to_scroll_to = (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL; } } } From 6a0e85c561cba43ceb4c401917756bd9d2c735d0 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Sat, 7 Nov 2020 07:32:48 -0800 Subject: [PATCH 03/15] Backends: Vulkan: Add override for the subpass to reference during VkPipeline creation. (#3579) This allows for binding the pipeline/sending draw commands (via `ImGui_ImplVulkan_RenderDrawData`) against any subpass, rather than being restricted to only the first subpass. Without this, attempting to bind the pipeline against a subpass other than the first one results in validation layer errors and, at worst, some drivers failing if the subpass attachments differ. --- backends/imgui_impl_vulkan.cpp | 11 ++++++++--- backends/imgui_impl_vulkan.h | 1 + docs/CHANGELOG.txt | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 7e8a1a76..46062390 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2020-11-11: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation. // 2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init). // 2020-05-04: Vulkan: Fixed crash if initial frame has no vertices. // 2020-04-26: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData didn't have vertices. @@ -81,6 +82,7 @@ static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE; static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE; static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE; static VkPipeline g_Pipeline = VK_NULL_HANDLE; +static uint32_t g_Subpass = 0; static VkShaderModule g_ShaderModuleVert; static VkShaderModule g_ShaderModuleFrag; @@ -675,7 +677,7 @@ static void ImGui_ImplVulkan_CreatePipelineLayout(VkDevice device, const VkAlloc check_vk_result(err); } -static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline) +static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline, uint32_t subpass) { ImGui_ImplVulkan_CreateShaderModules(device, allocator); @@ -775,6 +777,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC info.pDynamicState = &dynamic_state; info.layout = g_PipelineLayout; info.renderPass = renderPass; + info.subpass = subpass; VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline); check_vk_result(err); } @@ -846,7 +849,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, g_RenderPass, v->MSAASamples, &g_Pipeline); + ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, g_RenderPass, v->MSAASamples, &g_Pipeline, g_Subpass); return true; } @@ -901,6 +904,8 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend g_VulkanInitInfo = *info; g_RenderPass = render_pass; + g_Subpass = info->Subpass; + ImGui_ImplVulkan_CreateDeviceObjects(); return true; @@ -1193,7 +1198,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V // We do not create a pipeline by default as this is also used by examples' main.cpp, // but secondary viewport in multi-viewport mode may want to create one with: - //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline); + //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, g_Subpass); } // Create The Image Views diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 33dfe6ad..1e984b39 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -35,6 +35,7 @@ struct ImGui_ImplVulkan_InitInfo VkQueue Queue; VkPipelineCache PipelineCache; VkDescriptorPool DescriptorPool; + uint32_t Subpass; uint32_t MinImageCount; // >= 2 uint32_t ImageCount; // >= MinImageCount VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ad6b11c4..1a320359 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,7 @@ Other Changes: - Backends: OpenGL3: Use glGetString(GL_VERSION) query instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x). (#3530) [@xndcn] - Backends: OpenGL3: Backup and restore GL_PRIMITIVE_RESTART state. (#3544) [@Xipiryon] +- Backends: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation. (@3579) [@bdero] - Backends: OSX: Fix keypad-enter key not working on MacOS. (#3554) [@rokups, @lfnoise] - Examples: Apple+Metal: Consolidated/simplified to get closer to other examples. (#3543) [@warrenm] - Docs: Split examples/README.txt into docs/BACKENDS.md and docs/EXAMPLES.md improved them. From a3f79104dfab2224d29faa3309b7d529501e5437 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Wed, 28 Oct 2020 12:20:10 +0200 Subject: [PATCH 04/15] Examples: Apple+Metal: Forward events to OS key combinations like CMD+Q can work. (#3554) --- docs/CHANGELOG.txt | 1 + examples/example_apple_metal/main.mm | 29 +++++++++++++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1a320359..25e587a3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,7 @@ Other Changes: - Backends: Vulkan: Added support for specifying which subpass to reference during VkPipeline creation. (@3579) [@bdero] - Backends: OSX: Fix keypad-enter key not working on MacOS. (#3554) [@rokups, @lfnoise] - Examples: Apple+Metal: Consolidated/simplified to get closer to other examples. (#3543) [@warrenm] +- Examples: Apple+Metal: Forward events down so OS key combination like Cmd+Q can work. (#3554) [@rokups] - Docs: Split examples/README.txt into docs/BACKENDS.md and docs/EXAMPLES.md improved them. - Docs: Consistently renamed all occurences of "binding" and "back-end" to "backend" in comments and docs. diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 541dc5e1..015aee90 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -34,19 +34,19 @@ @implementation ViewController -- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil +- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - + _device = MTLCreateSystemDefaultDevice(); _commandQueue = [_device newCommandQueue]; - if (!self.device) + if (!self.device) { NSLog(@"Metal is not supported"); abort(); } - + // Setup Dear ImGui context // FIXME: This example doesn't have proper cleanup... IMGUI_CHECKVERSION(); @@ -76,16 +76,16 @@ //io.Fonts->AddFontFromFileTTF("../../misc/fonts/ProggyTiny.ttf", 10.0f); //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); //IM_ASSERT(font != NULL); - + return self; } -- (MTKView *)mtkView +- (MTKView *)mtkView { return (MTKView *)self.view; } -- (void)loadView +- (void)loadView { self.view = [[MTKView alloc] initWithFrame:CGRectMake(0, 0, 1200, 720)]; } @@ -96,7 +96,7 @@ self.mtkView.device = self.device; self.mtkView.delegate = self; - + #if TARGET_OS_OSX // Add a tracking area in order to receive mouse events whenever the mouse is within the bounds of our view NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect @@ -108,20 +108,17 @@ // If we want to receive key events, we either need to be in the responder chain of the key view, // or else we can install a local monitor. The consequence of this heavy-handed approach is that // we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our - // window, we'd want to be much more careful than just ingesting the complete event stream, though we - // do make an effort to be good citizens by passing along events when Dear ImGui doesn't want to capture. + // window, we'd want to be much more careful than just ingesting the complete event stream. + // To match the behavior of other backends, we pass every event down to the OS. NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged | NSEventTypeScrollWheel; [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event) { - BOOL wantsCapture = ImGui_ImplOSX_HandleEvent(event, self.view); - if (event.type == NSEventTypeKeyDown && wantsCapture) - return nil; - else - return event; + ImGui_ImplOSX_HandleEvent(event, self.view); + return event; }]; ImGui_ImplOSX_Init(); - + #endif } From dcfb986fa84524845cd6bed036a95fd26f01d95a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Nov 2020 18:07:29 +0100 Subject: [PATCH 05/15] Made EndFrame() assertion for key modifiers being unchanged during the frame more lenient. (#3575) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 25e587a3..64308fff 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,9 @@ Other Changes: - Misc: Replaced UTF-8 decoder by branchless one by Christopher Wellons (30~40% faster). [@rokups] Super minor fix handling incomplete UTF-8 contents: if input does not contain enough bytes, decoder returns IM_UNICODE_CODEPOINT_INVALID and consume remaining bytes (vs old decoded consumed only 1 byte). +- Misc: Made EndFrame() assertion for key modifiers being unchanged during the frame (added in 1.76) more + lenient, allowing full mid-frame releases. This is to accommodate the use of mid-frame modal native + windows calls, which leads backends such as GLFW to send key clearing events on focus loss. (#3575) - Backends: OpenGL3: Use glGetString(GL_VERSION) query instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x). (#3530) [@xndcn] - Backends: OpenGL3: Backup and restore GL_PRIMITIVE_RESTART state. (#3544) [@Xipiryon] diff --git a/imgui.cpp b/imgui.cpp index 427806d8..4c372551 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6905,9 +6905,13 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame() // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). - const ImGuiKeyModFlags expected_key_mod_flags = GetMergedKeyModFlags(); - IM_ASSERT(g.IO.KeyMods == expected_key_mod_flags && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); - IM_UNUSED(expected_key_mod_flags); + // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will + // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. + // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), + // while still correctly asserting on mid-frame key press events. + const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags(); + IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); + IM_UNUSED(key_mod_flags); // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). From 7a135a763c66e91cdf78d38ff343ffd06e39dec8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Nov 2020 11:56:04 +0100 Subject: [PATCH 06/15] Fix format warnings when using gnu printf extensions in a setup that supports them (gcc/mingw). (#3592) --- docs/CHANGELOG.txt | 3 ++- imgui.h | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 64308fff..2c85200e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,9 +68,10 @@ Other Changes: - InputText: Fixed updating cursor/selection position when a callback altered the buffer in a way where the byte count is unchanged but the decoded character count changes. (#3587) [@gqw] - Metrics: Fixed mishandling of ImDrawCmd::VtxOffset in wireframe mesh renderer. -- Misc: Replaced UTF-8 decoder by branchless one by Christopher Wellons (30~40% faster). [@rokups] +- Misc: Replaced UTF-8 decoder with one based on branchless one by Christopher Wellons. [@rokups] Super minor fix handling incomplete UTF-8 contents: if input does not contain enough bytes, decoder returns IM_UNICODE_CODEPOINT_INVALID and consume remaining bytes (vs old decoded consumed only 1 byte). +- Misc: Fix format warnings when using gnu printf extensions in a setup that supports them (gcc/mingw). (#3592) - Misc: Made EndFrame() assertion for key modifiers being unchanged during the frame (added in 1.76) more lenient, allowing full mid-frame releases. This is to accommodate the use of mid-frame modal native windows calls, which leads backends such as GLFW to send key clearing events on focus loss. (#3575) diff --git a/imgui.h b/imgui.h index f3dcac71..b0a35138 100644 --- a/imgui.h +++ b/imgui.h @@ -78,13 +78,6 @@ Index of this file: #include #define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h #endif -#if !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) -#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // To apply printf-style warnings to our functions. -#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) -#else -#define IM_FMTARGS(FMT) -#define IM_FMTLIST(FMT) -#endif #define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! #define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. #if (__cplusplus >= 201100) @@ -92,6 +85,16 @@ Index of this file: #else #define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro. #endif +#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__clang__) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to our formatting functions. +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#elif !defined(IMGUI_USE_STB_SPRINTF) && defined(__GNUC__) +#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) // Apply printf-style warnings to our formatting functions. +#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) +#else +#define IM_FMTARGS(FMT) +#define IM_FMTLIST(FMT) +#endif // Warnings #if defined(__clang__) From 13258f59575eae643affea976abe818417047777 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Nov 2020 12:01:49 +0100 Subject: [PATCH 07/15] Internals: zero-clearing ImGuiWindow / ImGuiWindowTempData for simplicity. (amend) All the non-zero fields previously initialized in ImGuiWindowTempData() are in fact setup in Begin: FocusCounterRegular, FocusCounterTabStop, TextWrapPos, LayoutType, ParentLayoutType --- imgui.cpp | 51 ++++-------------------------------------------- imgui_internal.h | 37 ++--------------------------------- 2 files changed, 6 insertions(+), 82 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4c372551..ca7afd36 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2774,70 +2774,27 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl //----------------------------------------------------------------------------- // ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods -ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) - : DrawListInst(&context->DrawListSharedData) +ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(NULL) { + memset(this, 0, sizeof(*this)); Name = ImStrdup(name); + NameBufLen = (int)strlen(name) + 1; ID = ImHashStr(name); IDStack.push_back(ID); - Flags = ImGuiWindowFlags_None; - Pos = ImVec2(0.0f, 0.0f); - Size = SizeFull = ImVec2(0.0f, 0.0f); - ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f); - WindowPadding = ImVec2(0.0f, 0.0f); - WindowRounding = 0.0f; - WindowBorderSize = 0.0f; - NameBufLen = (int)strlen(name) + 1; MoveId = GetID("#MOVE"); - ChildId = 0; - Scroll = ImVec2(0.0f, 0.0f); ScrollTarget = ImVec2(FLT_MAX, FLT_MAX); ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); - ScrollbarSizes = ImVec2(0.0f, 0.0f); - ScrollbarX = ScrollbarY = false; - Active = WasActive = false; - WriteAccessed = false; - Collapsed = false; - WantCollapseToggle = false; - SkipItems = false; - Appearing = false; - Hidden = false; - IsFallbackWindow = false; - HasCloseButton = false; - ResizeBorderHeld = -1; - BeginCount = 0; - BeginOrderWithinParent = -1; - BeginOrderWithinContext = -1; - PopupId = 0; AutoFitFramesX = AutoFitFramesY = -1; - AutoFitChildAxises = 0x00; - AutoFitOnlyGrows = false; AutoPosLastDirection = ImGuiDir_None; - HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0; SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); - - InnerRect = ImRect(0.0f, 0.0f, 0.0f, 0.0f); // Clear so the InnerRect.GetSize() code in Begin() doesn't lead to overflow even if the result isn't used. - LastFrameActive = -1; LastTimeActive = -1.0f; - ItemWidthDefault = 0.0f; FontWindowScale = 1.0f; SettingsOffset = -1; - DrawList = &DrawListInst; + DrawList->_Data = &context->DrawListSharedData; DrawList->_OwnerName = Name; - ParentWindow = NULL; - RootWindow = NULL; - RootWindowForTitleBarHighlight = NULL; - RootWindowForNav = NULL; - - NavLastIds[0] = NavLastIds[1] = 0; - NavRectRel[0] = NavRectRel[1] = ImRect(); - NavLastChildNavWindow = NULL; - - MemoryCompacted = false; - MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0; } ImGuiWindow::~ImGuiWindow() diff --git a/imgui_internal.h b/imgui_internal.h index 6b701a0b..8e19894e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1503,7 +1503,8 @@ struct ImGuiContext //----------------------------------------------------------------------------- // Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. -// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered. +// (That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered..) +// (This doesn't need a constructor because we zero-clear it as part of ImGuiWindow and all frame-temporary data are setup on Begin) struct IMGUI_API ImGuiWindowTempData { // Layout @@ -1557,40 +1558,6 @@ struct IMGUI_API ImGuiWindowTempData ImVector TextWrapPosStack; ImVectorGroupStack; short StackSizesBackup[6]; // Store size of various stacks for asserting - - ImGuiWindowTempData() - { - CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f); - CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f); - CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f; - Indent = ImVec1(0.0f); - ColumnsOffset = ImVec1(0.0f); - GroupOffset = ImVec1(0.0f); - - LastItemId = 0; - LastItemStatusFlags = ImGuiItemStatusFlags_None; - LastItemRect = LastItemDisplayRect = ImRect(); - - NavLayerActiveMask = NavLayerActiveMaskNext = 0x00; - NavLayerCurrent = ImGuiNavLayer_Main; - NavFocusScopeIdCurrent = 0; - NavHideHighlightOneFrame = false; - NavHasScroll = false; - - MenuBarAppending = false; - MenuBarOffset = ImVec2(0.0f, 0.0f); - TreeDepth = 0; - TreeJumpToParentOnPopMask = 0x00; - StateStorage = NULL; - CurrentColumns = NULL; - LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical; - FocusCounterRegular = FocusCounterTabStop = -1; - - ItemFlags = ImGuiItemFlags_Default_; - ItemWidth = 0.0f; - TextWrapPos = -1.0f; - memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); - } }; // Storage for one window From 78f1d2d319b31fc5e78f154baf3746ec59a6c551 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Nov 2020 17:34:30 +0100 Subject: [PATCH 08/15] ImDrawListSplitter: create first draw cmd on demand + Internals: fix incorrect ImBitArraySetBitRange() (only used by tables) Make it cheaper to allocate unused draw cmd, can't measure perf difference other our stress tests. --- imgui_draw.cpp | 13 +++++-------- imgui_internal.h | 10 +++++----- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8a102220..f922f689 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1417,6 +1417,7 @@ void ImDrawListSplitter::ClearFreeMemory() void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) { + IM_UNUSED(draw_list); IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter."); int old_channels_count = _Channels.Size; if (old_channels_count < channels_count) @@ -1441,12 +1442,6 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) _Channels[i]._CmdBuffer.resize(0); _Channels[i]._IdxBuffer.resize(0); } - if (_Channels[i]._CmdBuffer.Size == 0) - { - ImDrawCmd draw_cmd; - ImDrawCmd_HeaderCopy(&draw_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset - _Channels[i]._CmdBuffer.push_back(draw_cmd); - } } } @@ -1536,8 +1531,10 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; // If current command is used with different settings we need to add a new command - ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; - if (curr_cmd->ElemCount == 0) + ImDrawCmd* curr_cmd = (draw_list->CmdBuffer.Size == 0) ? NULL : &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd == NULL) + draw_list->AddDrawCmd(); + else if (curr_cmd->ElemCount == 0) ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) draw_list->AddDrawCmd(); diff --git a/imgui_internal.h b/imgui_internal.h index 8e19894e..a661c3a9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -453,15 +453,15 @@ struct IMGUI_API ImRect }; // Helper: ImBitArray -inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } -inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } -inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } -inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) +inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; } +inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; } +inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; } +inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) { while (n <= n2) { int a_mod = (n & 31); - int b_mod = ((n2 >= n + 31) ? 31 : (n2 & 31)) + 1; + int b_mod = (n2 > (n | 31) ? 31 : (n2 & 31)) + 1; ImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1); arr[n >> 5] |= mask; n = (n + 32) & ~31; From a138855d569fd4f9490d7936b6b5ac26af259bcd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Nov 2020 21:12:05 +0100 Subject: [PATCH 09/15] Hotfix for PushFocusScope() being utterly wrong (until we split the stacks), Added asserts on PopID to help catch bugs, Added GC trigger. --- imgui.cpp | 24 ++++++++++++++++-------- imgui_internal.h | 1 + imgui_widgets.cpp | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ca7afd36..398e3900 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3845,7 +3845,7 @@ void ImGui::NewFrame() // Mark all windows as not visible and compact unused memory. IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); - const float memory_compact_start_time = (g.IO.ConfigMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigMemoryCompactTimer : FLT_MAX; + const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; for (int i = 0; i != g.Windows.Size; i++) { ImGuiWindow* window = g.Windows[i]; @@ -3858,6 +3858,7 @@ void ImGui::NewFrame() if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) GcCompactTransientWindowBuffers(window); } + g.GcCompactAll = false; // Closing the focused window restore focus to the first active root window in descending z-order if (g.NavWindow && !g.NavWindow->WasActive) @@ -6650,12 +6651,14 @@ void ImGui::ActivateItem(ImGuiID id) g.NavNextActivateId = id; } -// Note: this is storing in same stack as IDStack, so Push/Pop mismatch will be reported there. +// FIXME: this is storing in same stack as IDStack, so Push/Pop mismatch will be reported there. Maybe play nice and a separate in-context stack. void ImGui::PushFocusScope(ImGuiID id) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + ImGuiID top_most_id = window->IDStack.back(); window->IDStack.push_back(window->DC.NavFocusScopeIdCurrent); + window->IDStack.push_back(top_most_id); window->DC.NavFocusScopeIdCurrent = id; } @@ -6665,6 +6668,8 @@ void ImGui::PopFocusScope() ImGuiWindow* window = g.CurrentWindow; window->DC.NavFocusScopeIdCurrent = window->IDStack.back(); window->IDStack.pop_back(); + IM_ASSERT(window->IDStack.Size > 1); // Too many PopID or PopFocusScope (or could be popping in a wrong/different window?) + window->IDStack.pop_back(); } void ImGui::SetKeyboardFocusHere(int offset) @@ -6763,6 +6768,7 @@ ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) void ImGui::PopID() { ImGuiWindow* window = GImGui->CurrentWindow; + IM_ASSERT(window->IDStack.Size > 1); // Too many PopID or PopFocusScope (or could be popping in a wrong/different window?) window->IDStack.pop_back(); } @@ -10323,12 +10329,14 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; // Basic info - ImGui::Text("Dear ImGui %s", ImGui::GetVersion()); - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); - ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); - ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); - ImGui::Text("%d active allocations", io.MetricsActiveAllocations); - ImGui::Separator(); + Text("Dear ImGui %s", ImGui::GetVersion()); + Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); + Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); + Text("%d active allocations", io.MetricsActiveAllocations); + //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; } + + Separator(); // Debugging enums enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type diff --git a/imgui_internal.h b/imgui_internal.h index a661c3a9..b46d665a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1148,6 +1148,7 @@ struct ImGuiContext bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed bool WithinEndChild; // Set within EndChild() + bool GcCompactAll; // Request full GC bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() ImGuiID TestEngineHookIdInfo; // Will call test engine hooks: ImGuiTestEngineHook_IdInfo() from GetID() void* TestEngine; // Test engine user data diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8fe841e1..4cb52b19 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7489,7 +7489,7 @@ void ImGui::EndTabItem() IM_ASSERT(tab_bar->LastTabItemIdx >= 0); ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) - window->IDStack.pop_back(); + PopID(); } bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) From a3e8dc3f34668457e43ab683b44221a4a6101d63 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Fri, 13 Nov 2020 12:07:32 +0200 Subject: [PATCH 10/15] CI: Fix deployment of PVS-Studio license + fix reported error. --- .github/workflows/static-analysis.yml | 5 ++--- imgui_internal.h | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 0b7ef361..7a9b573e 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -3,8 +3,6 @@ name: static-analysis on: push: {} pull_request: {} - schedule: - - cron: '0 9 * * *' jobs: PVS-Studio: @@ -16,16 +14,17 @@ jobs: - name: Install Dependencies env: + # The Secret variable setup in GitHub must be in format: "name_or_email key", on a single line PVS_STUDIO_LICENSE: ${{ secrets.PVS_STUDIO_LICENSE }} run: | if [[ "$PVS_STUDIO_LICENSE" != "" ]]; then - echo "$PVS_STUDIO_LICENSE" > pvs-studio.lic wget -q https://files.viva64.com/etc/pubkey.txt sudo apt-key add pubkey.txt sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list sudo apt-get update sudo apt-get install -y pvs-studio + pvs-studio-analyzer credentials -o pvs-studio.lic $PVS_STUDIO_LICENSE fi - name: PVS-Studio static analysis diff --git a/imgui_internal.h b/imgui_internal.h index b46d665a..c4d267e5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1368,6 +1368,7 @@ struct ImGuiContext FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + GcCompactAll = false; TestEngineHookItems = false; TestEngineHookIdInfo = 0; TestEngine = NULL; From 12ba6f46066642efd02eac1becee660e1d4a5d79 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Nov 2020 14:09:09 +0100 Subject: [PATCH 11/15] Fix PushFocusScopeID() + using shared stack. Renamed GetFocusScopeID() to GetFocusedFocusScope() - the two existing functions name are very error prone. --- imgui.cpp | 21 ++++++++------------- imgui.h | 5 ++++- imgui_internal.h | 4 +++- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 398e3900..488ccccb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5962,7 +5962,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayerCurrent = ImGuiNavLayer_Main; window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext; window->DC.NavLayerActiveMaskNext = 0x00; - window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595 window->DC.NavHideHighlightOneFrame = false; window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f); @@ -6030,12 +6029,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetCurrentWindow(window); } + window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595 + PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) - if (first_begin_of_the_frame) - window->WriteAccessed = false; - + window->WriteAccessed = false; window->BeginCount++; g.NextWindowData.ClearFlags(); @@ -6651,14 +6650,11 @@ void ImGui::ActivateItem(ImGuiID id) g.NavNextActivateId = id; } -// FIXME: this is storing in same stack as IDStack, so Push/Pop mismatch will be reported there. Maybe play nice and a separate in-context stack. void ImGui::PushFocusScope(ImGuiID id) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImGuiID top_most_id = window->IDStack.back(); - window->IDStack.push_back(window->DC.NavFocusScopeIdCurrent); - window->IDStack.push_back(top_most_id); + g.FocusScopeStack.push_back(window->DC.NavFocusScopeIdCurrent); window->DC.NavFocusScopeIdCurrent = id; } @@ -6666,10 +6662,9 @@ void ImGui::PopFocusScope() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - window->DC.NavFocusScopeIdCurrent = window->IDStack.back(); - window->IDStack.pop_back(); - IM_ASSERT(window->IDStack.Size > 1); // Too many PopID or PopFocusScope (or could be popping in a wrong/different window?) - window->IDStack.pop_back(); + IM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ? + window->DC.NavFocusScopeIdCurrent = g.FocusScopeStack.back(); + g.FocusScopeStack.pop_back(); } void ImGui::SetKeyboardFocusHere(int offset) @@ -6768,7 +6763,7 @@ ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) void ImGui::PopID() { ImGuiWindow* window = GImGui->CurrentWindow; - IM_ASSERT(window->IDStack.Size > 1); // Too many PopID or PopFocusScope (or could be popping in a wrong/different window?) + IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window? window->IDStack.pop_back(); } diff --git a/imgui.h b/imgui.h index b0a35138..75e045fa 100644 --- a/imgui.h +++ b/imgui.h @@ -291,7 +291,10 @@ namespace ImGui // - 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 [as with Begin: this is due to legacy reason and inconsistent with most BeginXXX functions apart from the regular Begin() which behaves like BeginChild().] + // 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.] 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(); diff --git a/imgui_internal.h b/imgui_internal.h index c4d267e5..26f47883 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1207,6 +1207,7 @@ struct ImGuiContext ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector FontStack; // Stack for PushFont()/PopFont() + ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() ImVectorOpenPopupStack; // Which popups are open (persistent) ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) @@ -1910,7 +1911,8 @@ namespace ImGui // patterns generally need to react (e.g. clear selection) when landing on an item of the set. IMGUI_API void PushFocusScope(ImGuiID id); IMGUI_API void PopFocusScope(); - inline ImGuiID GetFocusScopeID() { ImGuiContext& g = *GImGui; return g.NavFocusScopeId; } + inline ImGuiID GetFocusedFocusScope() { ImGuiContext& g = *GImGui; return g.NavFocusScopeId; } // Focus scope which is actually active + inline ImGuiID GetFocusScope() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.NavFocusScopeIdCurrent; } // Focus scope we are outputting into, set by PushFocusScope() // Inputs // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. From 6e94013a3db1867f3cb421ccbbcea7a0f065a35e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Nov 2020 14:36:32 +0100 Subject: [PATCH 12/15] Made ItemFlagsStack and GroupStack shared stacks. --- docs/CHANGELOG.txt | 3 ++ imgui.cpp | 77 ++++++++++++++++++++++++++++------------------ imgui.h | 8 ++--- imgui_internal.h | 11 ++++--- imgui_widgets.cpp | 6 ++-- 5 files changed, 65 insertions(+), 40 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2c85200e..89506712 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,6 +68,9 @@ Other Changes: - InputText: Fixed updating cursor/selection position when a callback altered the buffer in a way where the byte count is unchanged but the decoded character count changes. (#3587) [@gqw] - Metrics: Fixed mishandling of ImDrawCmd::VtxOffset in wireframe mesh renderer. +- Misc: Made the ItemFlags stack shared, so effectively the ButtonRepeat/AllowKeyboardFocus states + (and others exposed in internals such as PushItemFlag) are inherited by stacked Begin/End pairs, + vs previously a non-child stacked Begin() would reset those flags back to zero for the stacked window. - Misc: Replaced UTF-8 decoder with one based on branchless one by Christopher Wellons. [@rokups] Super minor fix handling incomplete UTF-8 contents: if input does not contain enough bytes, decoder returns IM_UNICODE_CODEPOINT_INVALID and consume remaining bytes (vs old decoded consumed only 1 byte). diff --git a/imgui.cpp b/imgui.cpp index 488ccccb..aa07c3f6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -872,7 +872,7 @@ static int FindWindowFocusIndex(ImGuiWindow* window); // Error Checking static void ErrorCheckNewFrameSanityChecks(); static void ErrorCheckEndFrameSanityChecks(); -static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write); +static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool begin); // Misc static void UpdateSettings(); @@ -2892,6 +2892,13 @@ static void SetCurrentWindow(ImGuiWindow* window) g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); } +void ImGui::GcCompactTransientMiscBuffers() +{ + ImGuiContext& g = *GImGui; + g.ItemFlagsStack.clear(); + g.GroupStack.clear(); +} + // Free up/compact internal window buffers, we can use this when a window becomes unused. // This is currently unused by the library, but you may call this yourself for easy GC. // Not freed: @@ -2906,10 +2913,8 @@ void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) window->IDStack.clear(); window->DrawList->_ClearFreeMemory(); window->DC.ChildWindows.clear(); - window->DC.ItemFlagsStack.clear(); window->DC.ItemWidthStack.clear(); window->DC.TextWrapPosStack.clear(); - window->DC.GroupStack.clear(); } void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window) @@ -3858,6 +3863,8 @@ void ImGui::NewFrame() if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) GcCompactTransientWindowBuffers(window); } + if (g.GcCompactAll) + GcCompactTransientMiscBuffers(); g.GcCompactAll = false; // Closing the focused window restore focus to the first active root window in descending z-order @@ -3868,6 +3875,9 @@ void ImGui::NewFrame() // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear. g.CurrentWindowStack.resize(0); g.BeginPopupStack.resize(0); + g.ItemFlagsStack.resize(0); + g.ItemFlagsStack.push_back(ImGuiItemFlags_Default_); + g.GroupStack.resize(0); ClosePopupsOverWindow(g.NavWindow, false); // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. @@ -5978,13 +5988,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.ItemWidth = window->ItemWidthDefault; window->DC.TextWrapPos = -1.0f; // disabled - window->DC.ItemFlagsStack.resize(0); window->DC.ItemWidthStack.resize(0); window->DC.TextWrapPosStack.resize(0); - window->DC.GroupStack.resize(0); - window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_; - if (parent_window) - window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); if (window->AutoFitFramesX > 0) window->AutoFitFramesX--; @@ -6029,7 +6034,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetCurrentWindow(window); } - window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595 + // Pull/inherit current state + window->DC.ItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack + window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // Inherit from parent only // -V595 PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); @@ -6257,19 +6264,25 @@ void ImGui::PopFont() void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) { - ImGuiWindow* window = GetCurrentWindow(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiItemFlags item_flags = window->DC.ItemFlags; + IM_ASSERT(item_flags == g.ItemFlagsStack.back()); if (enabled) - window->DC.ItemFlags |= option; + item_flags |= option; else - window->DC.ItemFlags &= ~option; - window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); + item_flags &= ~option; + window->DC.ItemFlags = item_flags; + g.ItemFlagsStack.push_back(item_flags); } void ImGui::PopItemFlag() { - ImGuiWindow* window = GetCurrentWindow(); - window->DC.ItemFlagsStack.pop_back(); - window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack. + g.ItemFlagsStack.pop_back(); + window->DC.ItemFlags = g.ItemFlagsStack.back(); } // FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system. @@ -6886,27 +6899,29 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); } } + + IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!"); } // Save and compare stack sizes on Begin()/End() to detect usage errors // Begin() calls this with write=true // End() calls this with write=false -static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write) +static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool begin) { ImGuiContext& g = *GImGui; short* p = &window->DC.StackSizesBackup[0]; // Window stacks - // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) - { int n = window->IDStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!"); p++; } // Too few or too many PopID()/TreePop() - { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() + // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + { IM_ASSERT(window->IDStack.Size == 1 && "PushID/PopID or TreeNode/TreePop Mismatch!"); } // Too few or too many PopID()/TreePop(); // Global stacks // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. - { int n = g.BeginPopupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() - { int n = g.ColorModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() - { int n = g.StyleModifiers.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() - { int n = g.FontStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() + { int n = g.GroupStack.Size; if (begin) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() + { int n = g.BeginPopupStack.Size; if (begin) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() + { int n = g.ColorModifiers.Size; if (begin) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() + { int n = g.StyleModifiers.Size; if (begin) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() + { int n = g.FontStack.Size; if (begin) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); } @@ -7310,8 +7325,9 @@ void ImGui::BeginGroup() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1); - ImGuiGroupData& group_data = window->DC.GroupStack.back(); + g.GroupStack.resize(g.GroupStack.Size + 1); + ImGuiGroupData& group_data = g.GroupStack.back(); + group_data.WindowID = window->ID; group_data.BackupCursorPos = window->DC.CursorPos; group_data.BackupCursorMaxPos = window->DC.CursorMaxPos; group_data.BackupIndent = window->DC.Indent; @@ -7334,9 +7350,10 @@ void ImGui::EndGroup() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(window->DC.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls + IM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls - ImGuiGroupData& group_data = window->DC.GroupStack.back(); + ImGuiGroupData& group_data = g.GroupStack.back(); + IM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window? ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); @@ -7351,7 +7368,7 @@ void ImGui::EndGroup() if (!group_data.EmitItem) { - window->DC.GroupStack.pop_back(); + g.GroupStack.pop_back(); return; } @@ -7380,7 +7397,7 @@ void ImGui::EndGroup() if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated; - window->DC.GroupStack.pop_back(); + g.GroupStack.pop_back(); //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug] } diff --git a/imgui.h b/imgui.h index 75e045fa..c472d9a2 100644 --- a/imgui.h +++ b/imgui.h @@ -358,6 +358,10 @@ namespace ImGui IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); IMGUI_API void PopStyleVar(int count = 1); + IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets + IMGUI_API void PopAllowKeyboardFocus(); + IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. + IMGUI_API void PopButtonRepeat(); IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in. IMGUI_API ImFont* GetFont(); // get current font IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied @@ -373,10 +377,6 @@ namespace ImGui IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions. IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space IMGUI_API void PopTextWrapPos(); - IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets - IMGUI_API void PopAllowKeyboardFocus(); - IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame. - IMGUI_API void PopButtonRepeat(); // Cursor / Layout // - By "cursor" we mean the current output position. diff --git a/imgui_internal.h b/imgui_internal.h index 26f47883..fb990db3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -826,6 +826,7 @@ struct ImGuiStyleMod // Stacked storage data for BeginGroup()/EndGroup() struct ImGuiGroupData { + ImGuiID WindowID; ImVec2 BackupCursorPos; ImVec2 BackupCursorMaxPos; ImVec1 BackupIndent; @@ -1208,6 +1209,8 @@ struct ImGuiContext ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() ImVector FontStack; // Stack for PushFont()/PopFont() ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() + ImVectorItemFlagsStack; // Stack for PushItemFlag()/PopItemFlag() + ImVectorGroupStack; // Stack for BeginGroup()/EndGroup() ImVectorOpenPopupStack; // Which popups are open (persistent) ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) @@ -1553,14 +1556,12 @@ struct IMGUI_API ImGuiWindowTempData // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. - ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] + ImGuiItemFlags ItemFlags; // == g.ItemFlagsStack.back() float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] - ImVectorItemFlagsStack; ImVector ItemWidthStack; ImVector TextWrapPosStack; - ImVectorGroupStack; - short StackSizesBackup[6]; // Store size of various stacks for asserting + short StackSizesBackup[5]; // Store size of various stacks for asserting }; // Storage for one window @@ -1849,6 +1850,7 @@ namespace ImGui inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } + inline ImGuiItemFlags GetItemsFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.ItemFlags; } IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); IMGUI_API void SetFocusID(ImGuiID id, ImGuiWindow* window); IMGUI_API void ClearActiveID(); @@ -2045,6 +2047,7 @@ namespace ImGui IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp); // Garbage collection + IMGUI_API void GcCompactTransientMiscBuffers(); IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4cb52b19..b8e7591f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1346,7 +1346,9 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) // Horizontal Separator float x1 = window->Pos.x; float x2 = window->Pos.x + window->Size.x; - if (!window->DC.GroupStack.empty()) + + // FIXME-WORKRECT: old hack (#205) until we decide of consistent behavior with WorkRect/Indent and Separator + if (g.GroupStack.Size > 0 && g.GroupStack.back().WindowID == window->ID) x1 += window->DC.Indent.x; ImGuiColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL; @@ -6500,7 +6502,7 @@ void ImGui::EndMenuBar() PopClipRect(); PopID(); window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. - window->DC.GroupStack.back().EmitItem = false; + g.GroupStack.back().EmitItem = false; EndGroup(); // Restore position on layer 0 window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.NavLayerCurrent = ImGuiNavLayer_Main; From 8119759329e9c9096b4a5f62c8ce3e8db49325eb Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Nov 2020 16:26:43 +0100 Subject: [PATCH 13/15] Internals: extracted stack checking code into a ImGuiStackSizes helper struct + added test for FocusScope + renamed g.ColorModifiers > g.ColorStack, g.StyleModifiers > g.StyleVarStack --- imgui.cpp | 63 +++++++++++++++++++++++++++++------------------- imgui_internal.h | 35 +++++++++++++++++++++------ 2 files changed, 66 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index aa07c3f6..3a00b310 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -872,7 +872,6 @@ static int FindWindowFocusIndex(ImGuiWindow* window); // Error Checking static void ErrorCheckNewFrameSanityChecks(); static void ErrorCheckEndFrameSanityChecks(); -static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool begin); // Misc static void UpdateSettings(); @@ -2352,7 +2351,7 @@ void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col) ImGuiColorMod backup; backup.Col = idx; backup.BackupValue = g.Style.Colors[idx]; - g.ColorModifiers.push_back(backup); + g.ColorStack.push_back(backup); g.Style.Colors[idx] = ColorConvertU32ToFloat4(col); } @@ -2362,7 +2361,7 @@ void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) ImGuiColorMod backup; backup.Col = idx; backup.BackupValue = g.Style.Colors[idx]; - g.ColorModifiers.push_back(backup); + g.ColorStack.push_back(backup); g.Style.Colors[idx] = col; } @@ -2371,9 +2370,9 @@ void ImGui::PopStyleColor(int count) ImGuiContext& g = *GImGui; while (count > 0) { - ImGuiColorMod& backup = g.ColorModifiers.back(); + ImGuiColorMod& backup = g.ColorStack.back(); g.Style.Colors[backup.Col] = backup.BackupValue; - g.ColorModifiers.pop_back(); + g.ColorStack.pop_back(); count--; } } @@ -2427,7 +2426,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { ImGuiContext& g = *GImGui; float* pvar = (float*)var_info->GetVarPtr(&g.Style); - g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; } @@ -2441,7 +2440,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); - g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar)); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; return; } @@ -2454,12 +2453,12 @@ void ImGui::PopStyleVar(int count) while (count > 0) { // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. - ImGuiStyleMod& backup = g.StyleModifiers.back(); + ImGuiStyleMod& backup = g.StyleVarStack.back(); const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx); void* data = info->GetVarPtr(&g.Style); if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } - g.StyleModifiers.pop_back(); + g.StyleVarStack.pop_back(); count--; } } @@ -3996,8 +3995,8 @@ void ImGui::Shutdown(ImGuiContext* context) g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL; g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; g.MovingWindow = NULL; - g.ColorModifiers.clear(); - g.StyleModifiers.clear(); + g.ColorStack.clear(); + g.StyleVarStack.clear(); g.FontStack.clear(); g.OpenPopupStack.clear(); g.BeginPopupStack.clear(); @@ -5515,8 +5514,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Add to stack // 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; + window->DC.StackSizesOnBegin.SetToCurrentState(); g.CurrentWindow = NULL; - ErrorCheckBeginEndCompareStacksSize(window, true); + if (flags & ImGuiWindowFlags_Popup) { ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size]; @@ -6112,7 +6113,7 @@ void ImGui::End() g.CurrentWindowStack.pop_back(); if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); - ErrorCheckBeginEndCompareStacksSize(window, false); + window->DC.StackSizesOnBegin.CompareWithCurrentState(); SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back()); } @@ -6903,26 +6904,38 @@ static void ImGui::ErrorCheckEndFrameSanityChecks() IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!"); } -// Save and compare stack sizes on Begin()/End() to detect usage errors -// Begin() calls this with write=true -// End() calls this with write=false -static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool begin) +// Save current stack sizes for later compare +void ImGuiStackSizes::SetToCurrentState() { ImGuiContext& g = *GImGui; - short* p = &window->DC.StackSizesBackup[0]; + ImGuiWindow* window = g.CurrentWindow; + SizeOfIDStack = (short)window->IDStack.Size; + SizeOfColorStack = (short)g.ColorStack.Size; + SizeOfStyleVarStack = (short)g.StyleVarStack.Size; + SizeOfFontStack = (short)g.FontStack.Size; + SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size; + SizeOfGroupStack = (short)g.GroupStack.Size; + SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; +} + +// Compare to detect usage errors +void ImGuiStackSizes::CompareWithCurrentState() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; // Window stacks // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) - { IM_ASSERT(window->IDStack.Size == 1 && "PushID/PopID or TreeNode/TreePop Mismatch!"); } // Too few or too many PopID()/TreePop(); + IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!"); // Global stacks // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. - { int n = g.GroupStack.Size; if (begin) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!"); p++; } // Too few or too many EndGroup() - { int n = g.BeginPopupStack.Size; if (begin) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup() - { int n = g.ColorModifiers.Size; if (begin) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!"); p++; } // Too few or too many PopStyleColor() - { int n = g.StyleModifiers.Size; if (begin) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!"); p++; } // Too few or too many PopStyleVar() - { int n = g.FontStack.Size; if (begin) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!"); p++; } // Too few or too many PopFont() - IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup)); + IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!"); + IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!"); + IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!"); + IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!"); + IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!"); + IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!"); } diff --git a/imgui_internal.h b/imgui_internal.h index fb990db3..7a190969 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -23,6 +23,7 @@ Index of this file: // [SECTION] Docking support // [SECTION] Viewport support // [SECTION] Settings support +// [SECTION] Metrics, Debug // [SECTION] Generic context hooks // [SECTION] ImGuiContext (main imgui context) // [SECTION] ImGuiWindowTempData, ImGuiWindow @@ -106,6 +107,7 @@ struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiNextItemData; // Storage for SetNextItem** functions struct ImGuiPopupData; // Storage for current popup stack struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file +struct ImGuiStackSizes; // Storage of stack sizes for debugging/asserting struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it struct ImGuiTabBar; // Storage for a tab bar struct ImGuiTabItem; // Storage for a tab item (within a tab bar) @@ -1089,6 +1091,10 @@ struct ImGuiSettingsHandler ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); } }; +//----------------------------------------------------------------------------- +// [SECTION] Metrics, Debug +//----------------------------------------------------------------------------- + struct ImGuiMetricsConfig { bool ShowWindowsRects; @@ -1111,6 +1117,21 @@ struct ImGuiMetricsConfig } }; +struct IMGUI_API ImGuiStackSizes +{ + short SizeOfIDStack; + short SizeOfColorStack; + short SizeOfStyleVarStack; + short SizeOfFontStack; + short SizeOfFocusScopeStack; + short SizeOfGroupStack; + short SizeOfBeginPopupStack; + + ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } + IMGUI_API void SetToCurrentState(); + IMGUI_API void CompareWithCurrentState(); +}; + //----------------------------------------------------------------------------- // [SECTION] Generic context hooks //----------------------------------------------------------------------------- @@ -1205,12 +1226,12 @@ struct ImGuiContext ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions // Shared stacks - ImVector ColorModifiers; // Stack for PushStyleColor()/PopStyleColor() - ImVector StyleModifiers; // Stack for PushStyleVar()/PopStyleVar() - ImVector FontStack; // Stack for PushFont()/PopFont() - ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() - ImVectorItemFlagsStack; // Stack for PushItemFlag()/PopItemFlag() - ImVectorGroupStack; // Stack for BeginGroup()/EndGroup() + ImVector ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin() + ImVector StyleVarStack; // Stack for PushStyleVar()/PopStyleVar() - inherited by Begin() + ImVector FontStack; // Stack for PushFont()/PopFont() - inherited by Begin() + ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() - not inherited by Begin(), unless child window + ImVectorItemFlagsStack; // Stack for PushItemFlag()/PopItemFlag() - inherited by Begin() + ImVectorGroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin() ImVectorOpenPopupStack; // Which popups are open (persistent) ImVectorBeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) @@ -1561,7 +1582,7 @@ struct IMGUI_API ImGuiWindowTempData float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] ImVector ItemWidthStack; ImVector TextWrapPosStack; - short StackSizesBackup[5]; // Store size of various stacks for asserting + ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting }; // Storage for one window From e736039538182d50d41e011e3fc246df396fa229 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Nov 2020 20:59:59 +0100 Subject: [PATCH 14/15] Nav: Fixed IsItemFocused() from returning false when Nav highlight is hidden because mouse has moved. (#787) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 7 +++---- imgui.h | 4 ++-- imgui_demo.cpp | 5 +++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 89506712..f967bebb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,9 @@ Other Changes: - Checkbox: Added CheckboxFlags() helper with int* type. - InputText: Fixed updating cursor/selection position when a callback altered the buffer in a way where the byte count is unchanged but the decoded character count changes. (#3587) [@gqw] +- Nav: Fixed IsItemFocused() from returning false when Nav highlight is hidden because mouse has moved. + It's essentially been always the case but it doesn't make much sense. Instead we will aim at exposing + feedback and control of keyboard/gamepad navigation highlight and mouse hover disable flag. (#787, #2048) - Metrics: Fixed mishandling of ImDrawCmd::VtxOffset in wireframe mesh renderer. - Misc: Made the ItemFlags stack shared, so effectively the ButtonRepeat/AllowKeyboardFocus states (and others exposed in internals such as PushItemFlag) are inherited by stacked Begin/End pairs, diff --git a/imgui.cpp b/imgui.cpp index 3a00b310..ea1b12c3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2899,10 +2899,8 @@ void ImGui::GcCompactTransientMiscBuffers() } // Free up/compact internal window buffers, we can use this when a window becomes unused. -// This is currently unused by the library, but you may call this yourself for easy GC. // Not freed: -// - ImGuiWindow, ImGuiWindowSettings, Name -// - StateStorage, ColumnsStorage (may hold useful data) +// - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data) // This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost. void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) { @@ -4642,12 +4640,13 @@ bool ImGui::IsItemDeactivatedAfterEdit() return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); } +// == GetItemID() == GetFocusID() bool ImGui::IsItemFocused() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId) + if (g.NavId != window->DC.LastItemId || g.NavId == 0) return false; return true; } diff --git a/imgui.h b/imgui.h index c472d9a2..4586fa0a 100644 --- a/imgui.h +++ b/imgui.h @@ -390,8 +390,8 @@ namespace ImGui IMGUI_API void NewLine(); // undo a SameLine() or force a new line when in an horizontal-layout context. IMGUI_API void Spacing(); // add vertical spacing. IMGUI_API void Dummy(const ImVec2& size); // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into. - IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by style.IndentSpacing or indent_w if != 0 - IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by style.IndentSpacing or indent_w if != 0 + IMGUI_API void Indent(float indent_w = 0.0f); // move content position toward the right, by indent_w, or style.IndentSpacing if indent_w <= 0 + IMGUI_API void Unindent(float indent_w = 0.0f); // move content position back to the left, by indent_w, or style.IndentSpacing if indent_w <= 0 IMGUI_API void BeginGroup(); // lock horizontal starting position IMGUI_API void EndGroup(); // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) IMGUI_API ImVec2 GetCursorPos(); // cursor position in window coordinates (relative to window position) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 07cd3a23..14aaff61 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -380,8 +380,9 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Configuration##2")) { ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); + ImGui::SameLine(); HelpMarker("Enable keyboard controls."); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); - ImGui::SameLine(); HelpMarker("Required backend to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); @@ -3568,7 +3569,7 @@ static void ShowDemoWindowMisc() char label[32]; sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]); ImGui::Bullet(); ImGui::Selectable(label, false); - if (ImGui::IsItemHovered() || ImGui::IsItemFocused()) + if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(i); } ImGui::TreePop(); From 71cc636696bd17c81514da49707e909958c14632 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Nov 2020 21:17:46 +0100 Subject: [PATCH 15/15] Metrics: Rebranded as "Dear ImGui Metrics/Debugger". Fix Show Window Rectangle. Fix Clang OSX warnings. Amend #3592 for Mingw only. --- docs/CHANGELOG.txt | 1 + imconfig.h | 2 +- imgui.cpp | 12 ++++++------ imgui.h | 4 ++-- imgui_demo.cpp | 4 ++-- imgui_draw.cpp | 3 +++ imgui_internal.h | 2 +- 7 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f967bebb..0098b612 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,7 @@ Other Changes: It's essentially been always the case but it doesn't make much sense. Instead we will aim at exposing feedback and control of keyboard/gamepad navigation highlight and mouse hover disable flag. (#787, #2048) - Metrics: Fixed mishandling of ImDrawCmd::VtxOffset in wireframe mesh renderer. +- Metrics: Rebranded as "Dear ImGui Metrics/Debugger" to clarify its purpose. - Misc: Made the ItemFlags stack shared, so effectively the ButtonRepeat/AllowKeyboardFocus states (and others exposed in internals such as PushItemFlag) are inherited by stacked Begin/End pairs, vs previously a non-child stacked Begin() would reset those flags back to zero for the stacked window. diff --git a/imconfig.h b/imconfig.h index 015540f3..736958b3 100644 --- a/imconfig.h +++ b/imconfig.h @@ -31,7 +31,7 @@ // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. -//#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty. +//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty. //---- Don't implement some functions to reduce linkage requirements. //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. diff --git a/imgui.cpp b/imgui.cpp index ea1b12c3..dad7ff7b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4058,7 +4058,7 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) { // Remove trailing command if unused. - // Technically we could return directly instead of popping, but this make things looks neat in Metrics window as well. + // Technically we could return directly instead of popping, but this make things looks neat in Metrics/Debugger window as well. draw_list->_PopUnusedDrawCmd(); if (draw_list->CmdBuffer.Size == 0) return; @@ -4073,7 +4073,7 @@ static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* d // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) // If this assert triggers because you are drawing lots of stuff manually: // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds. - // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents. + // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents. // - If you want large meshes with more than 64K vertices, you can either: // (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'. // Most example backends already support this from 1.71. Pre-1.71 backends won't. @@ -10342,7 +10342,7 @@ static void MetricsHelpMarker(const char* desc) void ImGui::ShowMetricsWindow(bool* p_open) { - if (!Begin("Dear ImGui Metrics", p_open)) + if (!Begin("Dear ImGui Metrics/Debugger", p_open)) { End(); return; @@ -10370,7 +10370,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) if (cfg->ShowWindowsRectsType < 0) cfg->ShowWindowsRectsType = WRT_WorkRect; if (cfg->ShowTablesRectsType < 0) - cfg->ShowWindowsRectsType = TRT_WorkRect; + cfg->ShowTablesRectsType = TRT_WorkRect; struct Funcs { @@ -10398,7 +10398,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder); - ImGui::Checkbox("Show windows rectangles", &cfg->ShowWindowsRects); + Checkbox("Show windows rectangles", &cfg->ShowWindowsRects); SameLine(); SetNextItemWidth(GetFontSize() * 12); cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count); @@ -10595,7 +10595,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) } #endif // #ifdef IMGUI_HAS_DOCK - ImGui::End(); + End(); } // [DEBUG] Display contents of Columns diff --git a/imgui.h b/imgui.h index 4586fa0a..6d2b54cd 100644 --- a/imgui.h +++ b/imgui.h @@ -88,7 +88,7 @@ Index of this file: #if !defined(IMGUI_USE_STB_SPRINTF) && defined(__clang__) #define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to our formatting functions. #define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) -#elif !defined(IMGUI_USE_STB_SPRINTF) && defined(__GNUC__) +#elif !defined(IMGUI_USE_STB_SPRINTF) && defined(__GNUC__) && defined(__MINGW32__) #define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) // Apply printf-style warnings to our formatting functions. #define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) #else @@ -260,7 +260,7 @@ namespace ImGui // Demo, Debug, Information IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. - IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Debug/Metrics window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc. + IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc. IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 14aaff61..045ae509 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -340,7 +340,7 @@ void ImGui::ShowDemoWindow(bool* p_open) } if (ImGui::BeginMenu("Tools")) { - ImGui::MenuItem("Metrics", NULL, &show_app_metrics); + ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics); ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); ImGui::EndMenu(); @@ -357,7 +357,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::BulletText("Sections below are demonstrating many aspects of the library."); ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" - "and Metrics (general purpose Dear ImGui debugging tool)."); + "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); ImGui::Separator(); ImGui::Text("PROGRAMMER GUIDE:"); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f922f689..306c296e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -60,6 +60,9 @@ Index of this file: #if __has_warning("-Wunknown-warning-option") #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great! #endif +#if __has_warning("-Walloca") +#pragma clang diagnostic ignored "-Walloca" // warning: use of function '__builtin_alloca' is discouraged +#endif #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok. diff --git a/imgui_internal.h b/imgui_internal.h index 7a190969..55b2e641 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1639,7 +1639,7 @@ struct IMGUI_API ImGuiWindow ImVector IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure) ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name. - // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer. + // The best way to understand what those rectangles are is to use the 'Metrics->Tools->Show Windows Rectangles' viewer. // The main 'OuterRect', omitted as a field, is window->Rect(). ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window. ImRect InnerRect; // Inner rectangle (omit title bar, menu bar, scroll bar)