From c911901b5ec9f43718a1d382f4d01e1cbc8ec862 Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov Date: Wed, 3 Aug 2022 23:46:31 +0300 Subject: [PATCH 01/14] Fix ImGuiIO docs and default values (#5540) --- imgui.cpp | 2 ++ imgui.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 4cf04fa25..fd83d4741 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1164,6 +1164,8 @@ ImGuiIO::ImGuiIO() #endif ConfigInputTrickleEventQueue = true; ConfigInputTextCursorBlink = true; + ConfigInputTextEnterKeepActive = false; + ConfigDragClickToInputText = false; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; ConfigMemoryCompactTimer = 60.0f; diff --git a/imgui.h b/imgui.h index 4bd3f88d2..d09f09fb1 100644 --- a/imgui.h +++ b/imgui.h @@ -1903,7 +1903,7 @@ struct ImGuiIO float MouseDoubleClickTime; // = 0.30f // Time for a double-click, in seconds. float MouseDoubleClickMaxDist; // = 6.0f // Distance threshold to stay in to validate a double-click, in pixels. float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. - float KeyRepeatDelay; // = 0.250f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). + float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. void* UserData; // = NULL // Store your own data for retrieval by callbacks. From 133bbafa3cc7b7a1ca68808dacd1f6cee2552d4f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 5 Aug 2022 20:26:51 +0200 Subject: [PATCH 02/14] Platform IME: Windows: Fixed a call to ImmAssociateContextEx() leading to freeze on some setups. (#2589, #5535, #5264, #4972) + misc comments --- docs/CHANGELOG.txt | 2 ++ docs/CONTRIBUTING.md | 5 ++++- docs/EXAMPLES.md | 2 +- imgui.cpp | 6 ++++-- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f37ef42da..4d4c89481 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,8 @@ Other Changes: can apply to mouse data as well. (#4921) - Nav: Fixed moving/resizing window with gamepad or keyboard when running at very high framerate. - Nav: Pressing Space/GamepadFaceDown on a repeating button uses the same repeating rate as a mouse hold. +- Platform IME: [Windows] Fixed a call to ImmAssociateContextEx() leading to freeze on some setups. + (#2589, #5535, #5264, #4972) - Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138) - Tools: Item Picker: Mouse button can be changed by holding Ctrl+Shift, making it easier to use the Item Picker in e.g. menus. (#2673) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 7a28eadf7..16257e6be 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -10,6 +10,7 @@ ## Getting Started & General Advices +- Article: [How To Ask Good Questions](https://bit.ly/3nwRnx1). - Please browse the [Wiki](https://github.com/ocornut/imgui/wiki) to find code snippets, links and other resources (e.g. [Useful extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions)). - Please read [docs/FAQ.md](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md). - Please read [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) if your question relates to fonts or text. @@ -19,6 +20,7 @@ - Please use the search function of GitHub to look for similar issues. You may [browse issues by Labels](https://github.com/ocornut/imgui/labels). - Please use a web search engine to look for similar issues. - If you get a crash or assert, use a debugger to locate the line triggering it and read the comments around. +- Please don't be a [Help Vampire](https://slash7.com/2006/12/22/vampires/). ## Issues vs Discussions @@ -35,12 +37,13 @@ If Dear ImGui is successfully showing in your app and you have used Dear ImGui b You may use the Issue Tracker to submit bug reports, feature requests or suggestions. You may ask for help or advice as well. But **PLEASE CAREFULLY READ THIS WALL OF TEXT. ISSUES IGNORING THOSE GUIDELINES MAY BE CLOSED. USERS IGNORING THOSE GUIDELINES MIGHT BE BLOCKED.** -Please do your best to clarify your request. The amount of incomplete or ambiguous requests due to people not following those guidelines is often overwhelming. Issues created without the requested information may be closed prematurely. Exceptionally entitled, impolite or lazy requests may lead to bans. +Please do your best to clarify your request. The amount of incomplete or ambiguous requests due to people not following those guidelines is often overwhelming. Issues created without the requested information may be closed prematurely. Exceptionally entitled, impolite or lazy requests may lead to bans. **PLEASE UNDERSTAND THAT OPEN-SOURCE SOFTWARE LIVES OR DIES BY THE AMOUNT OF ENERGY MAINTAINERS CAN SPARE. WE HAVE LOTS OF STUFF TO DO. THIS IS AN ATTENTION ECONOMY AND MANY LAZY OR MINOR ISSUES ARE HOGGING OUR ATTENTION AND DRAINING ENERGY, TAKING US AWAY FROM MORE IMPORTANT WORK.** Steps: +- Article: [How To Ask Good Questions](https://bit.ly/3nwRnx1). - **PLEASE DO FILL THE REQUESTED NEW ISSUE TEMPLATE.** Including dear imgui version number, branch name, platform/renderer back-ends (imgui_impl_XXX files), operating system. - **Try to be explicit with your Goals, your Expectations and what you have Tried**. Be mindful of [The XY Problem](http://xyproblem.info/). What you have in mind or in your code is not obvious to other people. People frequently discuss problems and suggest incorrect solutions without first clarifying their goal. When requesting a new feature, please describe the usage context (how you intend to use it, why you need it, etc..). If you tried something and it failed, show us what you tried. - **Attach screenshots (or gif/video) to clarify the context**. They often convey useful information that are omitted by the description. You can drag pictures/files in the message edit box. Avoid using 3rd party image hosting services, prefer the long term longevity of GitHub attachments (you can drag pictures into your post). On Windows you can use [ScreenToGif](https://www.screentogif.com/) to easily capture .gif files. diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index b50595c85..c202f9cd9 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -178,7 +178,7 @@ This may actually also work with OpenGL 2.x contexts!
[example_sdl_sdlrenderer/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl_sdlrenderer/)
SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer (most graphics backends are supported underneath)
= main.cpp + imgui_impl_sdl.cpp + imgui_impl_sdlrenderer.cpp
-This requires SDL 2.0.17+ (expected to release November 2021)
+This requires SDL 2.0.18+ (released November 2021)
We do not really recommend using SDL_Renderer as it is a rather primitive API. [example_sdl_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl_vulkan/)
diff --git a/imgui.cpp b/imgui.cpp index fd83d4741..09bfb3edd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8535,6 +8535,9 @@ ImVec2 ImGui::GetCursorScreenPos() return window->DC.CursorPos; } +// 2022/08/05: Setting cursor position also extend boundaries (via modifying CursorMaxPos) used to compute window size, group size etc. +// I believe this was is a judicious choice but it's probably being relied upon (it has been the case since 1.31 and 1.50) +// It would be sane if we requested user to use SetCursorPos() + Dummy(ImVec2(0,0)) to extend CursorMaxPos... void ImGui::SetCursorScreenPos(const ImVec2& pos) { ImGuiWindow* window = GetCurrentWindow(); @@ -12219,10 +12222,9 @@ static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatf if (hwnd == 0) return; - ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); - if (HIMC himc = ::ImmGetContext(hwnd)) { + ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); COMPOSITIONFORM composition_form = {}; composition_form.ptCurrentPos.x = (LONG)data->InputPos.x; composition_form.ptCurrentPos.y = (LONG)data->InputPos.y; From 839c31006bb0f5320772c665c18aeb7f8a9fe6f3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Aug 2022 11:58:57 +0200 Subject: [PATCH 03/14] Debug Log: Added IO events logging. --- docs/CHANGELOG.txt | 15 ++++++++------- imgui.cpp | 38 ++++++++++++++++++++++++-------------- imgui_internal.h | 1 + 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4d4c89481..3b1087001 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,7 +77,8 @@ Other Changes: - Platform IME: [Windows] Fixed a call to ImmAssociateContextEx() leading to freeze on some setups. (#2589, #5535, #5264, #4972) - Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138) -- Tools: Item Picker: Mouse button can be changed by holding Ctrl+Shift, making it easier +- Debug Tools: Debug Log: Added IO events logging. +- Debug Tools: Item Picker: Mouse button can be changed by holding Ctrl+Shift, making it easier to use the Item Picker in e.g. menus. (#2673) - Backends: Metal: Use __bridge for ARC based systems. (#5403) [@stack] - Backends: Metal: Add dispatch synchronization. (#5447) [@luigifcruz] @@ -176,10 +177,10 @@ Other Changes: - DrawList: Fixed texture-based anti-aliasing path with RGBA textures (#5132, #3245) [@cfillion] - DrawList: Fixed divide-by-zero or glitches with Radius/Rounding values close to zero. (#5249, #5293, #3491) - DrawList: Circle with a radius smaller than 0.5f won't appear, to be consistent with other primitives. [@thedmd] -- Debug: Added ShowDebugLogWindow() showing an opt-in synthetic log of principal events (focus, popup, - active id changes) helping to diagnose issues. -- Debug: Added DebugTextEncoding() function to facilitate diagnosing issues when not sure about whether - you have a UTF-8 text encoding issue or a font loading issue. [@LaMarche05, @ocornut] +- Debug Tools: Debug Log: Added ShowDebugLogWindow() showing an opt-in synthetic log of principal events + (focus, popup, active id changes) helping to diagnose issues. +- Debug Tools: Added DebugTextEncoding() function to facilitate diagnosing issues when not sure about + whether you have a UTF-8 text encoding issue or a font loading issue. [@LaMarche05, @ocornut] - Demo: Add better demo of how to use SetNextFrameWantCaptureMouse()/SetNextFrameWantCaptureKeyboard(). - Metrics: Added a "UTF-8 Encoding Viewer" section using the aforementioned DebugTextEncoding() function. - Metrics: Added "InputText" section to visualize internal state (#4947, #4949). @@ -1740,8 +1741,8 @@ Other Changes: returning true. This also effectively make ColorEdit4() not incorrect trigger IsItemDeactivatedAfterEdit() when clicking the color button to open the picker popup. (#1875) - Misc: Added IMGUI_DISABLE_METRICS_WINDOW imconfig.h setting to explicitly compile out ShowMetricsWindow(). -- Debug, Metrics: Added "Tools->Item Picker" tool which allow clicking on a widget to break in the debugger - within the item code. The tool calls IM_DEBUG_BREAK() which can be redefined in imconfig.h if needed. +- Debug Tools: Added "Metrics->Tools->Item Picker" tool which allow clicking on a widget to break in the + debugger within the item code. The tool calls IM_DEBUG_BREAK() which can be redefined in imconfig.h. - ImDrawList: Fixed CloneOutput() helper crashing. (#1860) [@gviot] - ImDrawList::ChannelsSplit(), ImDrawListSplitter: Fixed an issue with merging draw commands between channel 0 and 1. (#2624) diff --git a/imgui.cpp b/imgui.cpp index 09bfb3edd..5cd814210 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7973,17 +7973,17 @@ static const char* GetInputSourceName(ImGuiInputSource source) IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT); return input_source_names[source]; } -#endif - -/*static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) +static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) { - if (e->Type == ImGuiInputEventType_MousePos) { IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; } + ImGuiContext& g = *GImGui; + if (e->Type == ImGuiInputEventType_MousePos) { IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f, %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; } if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("%s: MouseButton %d %s\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up"); return; } - if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.1f %.1f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; } + if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.1f, %.1f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; } if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("%s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("%s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("%s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; } -}*/ +} +#endif // Process input queue // We always call this with the value of 'bool g.IO.ConfigInputTrickleEventQueue'. @@ -8006,13 +8006,14 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) int event_n = 0; for (; event_n < g.InputEventsQueue.Size; event_n++) { - const ImGuiInputEvent* e = &g.InputEventsQueue[event_n]; + ImGuiInputEvent* e = &g.InputEventsQueue[event_n]; if (e->Type == ImGuiInputEventType_MousePos) { ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY); if (IsMousePosValid(&event_pos)) event_pos = ImVec2(ImFloorSigned(event_pos.x), ImFloorSigned(event_pos.y)); // Apply same flooring as UpdateMouseInputs() - if (io.MousePos.x != event_pos.x || io.MousePos.y != event_pos.y) + e->IgnoredAsSame = (io.MousePos.x == event_pos.x && io.MousePos.y == event_pos.y); + if (!e->IgnoredAsSame) { // Trickling Rule: Stop processing queued events if we already handled a mouse button change if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted)) @@ -8025,7 +8026,8 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) { const ImGuiMouseButton button = e->MouseButton.Button; IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); - if (io.MouseDown[button] != e->MouseButton.Down) + e->IgnoredAsSame = (io.MouseDown[button] == e->MouseButton.Down); + if (!e->IgnoredAsSame) { // Trickling Rule: Stop processing queued events if we got multiple action on the same button if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled)) @@ -8036,7 +8038,8 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) } else if (e->Type == ImGuiInputEventType_MouseWheel) { - if (e->MouseWheel.WheelX != 0.0f || e->MouseWheel.WheelY != 0.0f) + e->IgnoredAsSame = (e->MouseWheel.WheelX == 0.0f && e->MouseWheel.WheelY == 0.0f); + if (!e->IgnoredAsSame) { // Trickling Rule: Stop processing queued events if we got multiple action on the event if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0)) @@ -8052,7 +8055,8 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) IM_ASSERT(key != ImGuiKey_None); const int keydata_index = (key - ImGuiKey_KeysData_OFFSET); ImGuiKeyData* keydata = &io.KeysData[keydata_index]; - if (keydata->Down != e->Key.Down || keydata->AnalogValue != e->Key.AnalogValue) + e->IgnoredAsSame = (keydata->Down == e->Key.Down && keydata->AnalogValue == e->Key.AnalogValue); + if (!e->IgnoredAsSame) { // Trickling Rule: Stop processing queued events if we got multiple action on the same button if (trickle_fast_inputs && keydata->Down != e->Key.Down && (key_changed_mask.TestBit(keydata_index) || text_inputted || mouse_button_changed != 0)) @@ -8093,7 +8097,10 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) { // We intentionally overwrite this and process lower, in order to give a chance // to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame. - io.AppFocusLost = !e->AppFocused.Focused; + const bool focus_lost = !e->AppFocused.Focused; + e->IgnoredAsSame = (io.AppFocusLost == focus_lost); + if (!e->IgnoredAsSame) + io.AppFocusLost = focus_lost; } else { @@ -8107,9 +8114,11 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) g.InputEventsTrail.push_back(g.InputEventsQueue[n]); // [DEBUG] - /*if (event_n != 0) +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO)) for (int n = 0; n < g.InputEventsQueue.Size; n++) - DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]);*/ + DebugPrintInputEvent(n < event_n ? (g.InputEventsQueue[n].IgnoredAsSame ? "Processed (Same)" : "Processed") : "Remaining", &g.InputEventsQueue[n]); +#endif // Remaining events will be processed on the next frame if (event_n == g.InputEventsQueue.Size) @@ -13265,6 +13274,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) SameLine(); CheckboxFlags("Focus", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus); SameLine(); CheckboxFlags("Popup", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup); SameLine(); CheckboxFlags("Nav", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav); + SameLine(); CheckboxFlags("IO", &g.DebugLogFlags, ImGuiDebugLogFlags_EventIO); if (SmallButton("Clear")) g.DebugLogBuf.clear(); diff --git a/imgui_internal.h b/imgui_internal.h index 193545e20..ab76fb002 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1238,6 +1238,7 @@ struct ImGuiInputEvent ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus }; + bool IgnoredAsSame; bool AddedByTestEngine; ImGuiInputEvent() { memset(this, 0, sizeof(*this)); } From a396233cb66971db7fe767db66ce6100fc4ebfd2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Aug 2022 12:42:57 +0200 Subject: [PATCH 04/14] Platform IME: Windows: Revert 133bbafa and 29a8ee08 as regression until new results comes. (#2589, #5535, #5264, #4972) --- docs/CHANGELOG.txt | 2 +- imgui.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3b1087001..452e7edbe 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,7 +74,7 @@ Other Changes: can apply to mouse data as well. (#4921) - Nav: Fixed moving/resizing window with gamepad or keyboard when running at very high framerate. - Nav: Pressing Space/GamepadFaceDown on a repeating button uses the same repeating rate as a mouse hold. -- Platform IME: [Windows] Fixed a call to ImmAssociateContextEx() leading to freeze on some setups. +- Platform IME: [Windows] Removed call to ImmAssociateContextEx() leading to freeze on some setups. (#2589, #5535, #5264, #4972) - Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138) - Debug Tools: Debug Log: Added IO events logging. diff --git a/imgui.cpp b/imgui.cpp index 5cd814210..bbbbe8bee 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12231,9 +12231,9 @@ static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatf if (hwnd == 0) return; + //::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); if (HIMC himc = ::ImmGetContext(hwnd)) { - ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0); COMPOSITIONFORM composition_form = {}; composition_form.ptCurrentPos.x = (LONG)data->InputPos.x; composition_form.ptCurrentPos.y = (LONG)data->InputPos.y; From 268565079c56600c197602683391a1bc8afba014 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Aug 2022 17:06:11 +0200 Subject: [PATCH 05/14] InputText: numerical fields automatically accept full-width characters (U+FF01..U+FF5E) by converting them to half-width (U+0021..U+007E). --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 452e7edbe..cb7d48d47 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -65,6 +65,8 @@ Other Changes: - InputText: added experimental io.ConfigInputTextEnterKeepActive feature to make pressing Enter keep the input active and select all text. +- InputText: numerical fields automatically accept full-width characters (U+FF01..U+FF5E) + by converting them to half-width (U+0021..U+007E). - Tables,Columns: fixed a layout issue where SameLine() prior to a row change would set the next row in such state where subsequent SameLine() would move back to previous row. - Tabs: Fixed a crash when closing multiple windows (possible with docking only) with an diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9473c6147..1f9fb8838 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3923,6 +3923,13 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f ImGuiContext& g = *GImGui; const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; + // Full-width -> half-width conversion for numeric fields (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) + // While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may + // scratch their head as to why it works in numerical fields vs in generic text fields it would require support in the font. + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal)) + if (c >= 0xFF01 && c <= 0xFF5E) + c = c - 0xFF01 + 0x21; + // Allow 0-9 . - + * / if (flags & ImGuiInputTextFlags_CharsDecimal) if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/')) @@ -3941,11 +3948,13 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // Turn a-z into A-Z if (flags & ImGuiInputTextFlags_CharsUppercase) if (c >= 'a' && c <= 'z') - *p_char = (c += (unsigned int)('A' - 'a')); + c += (unsigned int)('A' - 'a'); if (flags & ImGuiInputTextFlags_CharsNoBlank) if (ImCharIsBlankW(c)) return false; + + *p_char = c; } // Custom callback filter From ef6ba0d84617c342c41e44082da5b667067d2266 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 20 Aug 2022 19:54:57 +0200 Subject: [PATCH 06/14] Misc: allowing override of IM_TABSIZE (#5593) --- imgui_demo.cpp | 2 +- imgui_internal.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1e77e31ef..376d2636a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3813,7 +3813,7 @@ static void ShowDemoWindowTables() } // [Method 3] We call TableNextColumn() _before_ each cell. We never call TableNextRow(), - // as TableNextColumn() will automatically wrap around and create new roes as needed. + // as TableNextColumn() will automatically wrap around and create new rows as needed. // This is generally more convenient when your cells all contains the same type of data. HelpMarker( "Only using TableNextColumn(), which tends to be convenient for tables where every cells contains the same type of contents.\n" diff --git a/imgui_internal.h b/imgui_internal.h index ab76fb002..e384baf99 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -237,7 +237,9 @@ namespace ImStb #else #define IM_NEWLINE "\n" #endif +#ifndef IM_TABSIZE // Until we move this to runtime and/or add proper tab support, at least allow users to compile-time override #define IM_TABSIZE (4) +#endif #define IM_MEMALIGN(_OFF,_ALIGN) (((_OFF) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align e.g. IM_ALIGN(0,4)=0, IM_ALIGN(1,4)=4, IM_ALIGN(4,4)=4, IM_ALIGN(5,4)=8 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 From 5b0510c5b766ae3dba1e70bd838bf3b1df61de94 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 20 Aug 2022 22:55:51 +0200 Subject: [PATCH 07/14] TestEngine: facilitate aiming at InputScalar() using wildcards + removed unnecessary IDStack.size hack (require TestEngine latest) --- imgui.cpp | 2 -- imgui.h | 2 +- imgui_widgets.cpp | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index bbbbe8bee..d22451d65 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6455,10 +6455,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (g.TestEngineHookItems) { IM_ASSERT(window->IDStack.Size == 1); - window->IDStack.Size = 0; IMGUI_TEST_ENGINE_ITEM_ADD(window->Rect(), window->ID); IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); - window->IDStack.Size = 1; } #endif diff --git a/imgui.h b/imgui.h index d09f09fb1..eb3d8b640 100644 --- a/imgui.h +++ b/imgui.h @@ -65,7 +65,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.89 WIP" -#define IMGUI_VERSION_NUM 18808 +#define IMGUI_VERSION_NUM 18809 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1f9fb8838..09d5ad08c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3474,6 +3474,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); + IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags); // Step buttons const ImVec2 backup_frame_padding = style.FramePadding; From cdebd70e15f57eb455485a50acb25ebc8787ab78 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 20 Aug 2022 23:01:58 +0200 Subject: [PATCH 08/14] Fix PVS-Studio static analyzer warning for "buffer underflow" Amend 4e8e177c --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 09d5ad08c..b8cc27da8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5195,7 +5195,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag bool accepted_drag_drop = false; if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) { - memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 + memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 //-V1086 value_changed = accepted_drag_drop = true; } if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) From 7f4b477d2ecc965fa87e371facd89ba316ec11b8 Mon Sep 17 00:00:00 2001 From: Adam Essemaali <63453157+AdamEssemaali@users.noreply.github.com> Date: Mon, 22 Aug 2022 08:54:08 +0200 Subject: [PATCH 09/14] CI: Update ubuntu version (#5598) --- .github/workflows/static-analysis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index f3e6b2d18..2df0f4436 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -10,7 +10,7 @@ on: jobs: PVS-Studio: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v1 with: @@ -46,7 +46,7 @@ jobs: plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log Discord-CI: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 needs: [PVS-Studio] if: always() steps: From d357e8504bc2d00a4b1068d8a8e2d25b0c77eb84 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Aug 2022 14:36:32 +0200 Subject: [PATCH 10/14] TestEngine: revert part of 5b0510c as IMGUI_TEST_ENGINE_ITEM_ADD() woul see an erreneous hierarchy. + Fix typo (#5600) --- imgui.cpp | 2 ++ imgui_internal.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index d22451d65..4905e8638 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6455,8 +6455,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (g.TestEngineHookItems) { IM_ASSERT(window->IDStack.Size == 1); + window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself. IMGUI_TEST_ENGINE_ITEM_ADD(window->Rect(), window->ID); IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); + window->IDStack.Size = 1; } #endif diff --git a/imgui_internal.h b/imgui_internal.h index e384baf99..c125698b7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2165,7 +2165,7 @@ public: ImGuiID GetID(int n); ImGuiID GetIDFromRectangle(const ImRect& r_abs); - // We don't use g.FontSize because the window may be != g.CurrentWidow. + // We don't use g.FontSize because the window may be != g.CurrentWindow. ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; } From 21b5fac57a015f0e104c4a1bc9e292bf397fbe02 Mon Sep 17 00:00:00 2001 From: David Chavez Date: Mon, 22 Aug 2022 22:56:10 +0200 Subject: [PATCH 11/14] Backends: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount' (#5603) --- backends/imgui_impl_metal.mm | 3 ++- docs/CHANGELOG.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 23805b21f..3f8c77607 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -12,6 +12,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. // 2022-07-05: Metal: Add dispatch synchronization. // 2022-06-30: Metal: Use __bridge for ARC based systems. // 2022-06-01: Metal: Fixed null dereference on exit inside command buffer completion handler. @@ -552,7 +553,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() pipelineDescriptor.vertexFunction = vertexFunction; pipelineDescriptor.fragmentFunction = fragmentFunction; pipelineDescriptor.vertexDescriptor = vertexDescriptor; - pipelineDescriptor.sampleCount = self.framebufferDescriptor.sampleCount; + pipelineDescriptor.rasterSampleCount = self.framebufferDescriptor.sampleCount; pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat; pipelineDescriptor.colorAttachments[0].blendingEnabled = YES; pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cb7d48d47..5882196f4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -84,6 +84,7 @@ Other Changes: to use the Item Picker in e.g. menus. (#2673) - Backends: Metal: Use __bridge for ARC based systems. (#5403) [@stack] - Backends: Metal: Add dispatch synchronization. (#5447) [@luigifcruz] +- Backends: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. (#5603) [@dcvz] - Backends: OSX: Fixes to support full app creation in C++. (#5403) [@stack] From 4eb9066997a95c556336b7ab5f246f0cdbf151c2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Aug 2022 14:33:29 +0200 Subject: [PATCH 12/14] Clipper: extract code into a ImGuiListClipper_StepInternal() to facilitate debugging. Moved clipper End() call to outer layer, stopped heretic use of comma operator. Removed obsolete comments in clipper Begin() --- imgui.cpp | 78 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4905e8638..99a4bd8de 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2592,9 +2592,6 @@ ImGuiListClipper::~ImGuiListClipper() End(); } -// Use case A: Begin() called from constructor with items_height<0, then called again from Step() in StepNo 1 -// Use case B: Begin() called from constructor with items_height>0 -// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style. void ImGuiListClipper::Begin(int items_count, float items_height) { ImGuiContext& g = *GImGui; @@ -2650,11 +2647,11 @@ void ImGuiListClipper::ForceDisplayRangeByIndices(int item_min, int item_max) data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_min, item_max)); } -bool ImGuiListClipper::Step() +static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImGuiListClipperData* data = (ImGuiListClipperData*)TempData; + ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData; IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?"); ImGuiTable* table = g.CurrentTable; @@ -2662,17 +2659,17 @@ bool ImGuiListClipper::Step() ImGui::TableEndRow(table); // No items - if (ItemsCount == 0 || GetSkipItemForListClipping()) - return (void)End(), false; + if (clipper->ItemsCount == 0 || GetSkipItemForListClipping()) + return false; // While we are in frozen row state, keep displaying items one by one, unclipped // FIXME: Could be stored as a table-agnostic state. if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows) { - DisplayStart = data->ItemsFrozen; - DisplayEnd = data->ItemsFrozen + 1; - if (DisplayStart >= ItemsCount) - return (void)End(), false; + clipper->DisplayStart = data->ItemsFrozen; + clipper->DisplayEnd = data->ItemsFrozen + 1; + if (clipper->DisplayStart >= clipper->ItemsCount) + return false; data->ItemsFrozen++; return true; } @@ -2681,15 +2678,15 @@ bool ImGuiListClipper::Step() bool calc_clipping = false; if (data->StepNo == 0) { - StartPosY = window->DC.CursorPos.y; - if (ItemsHeight <= 0.0f) + clipper->StartPosY = window->DC.CursorPos.y; + if (clipper->ItemsHeight <= 0.0f) { // Submit the first item (or range) so we can measure its height (generally the first range is 0..1) data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1)); - DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen); - DisplayEnd = ImMin(data->Ranges[0].Max, ItemsCount); - if (DisplayStart == DisplayEnd) - return (void)End(), false; + clipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen); + clipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount); + if (clipper->DisplayStart == clipper->DisplayEnd) + return false; data->StepNo = 1; return true; } @@ -2697,29 +2694,29 @@ bool ImGuiListClipper::Step() } // Step 1: Let the clipper infer height from first range - if (ItemsHeight <= 0.0f) + if (clipper->ItemsHeight <= 0.0f) { IM_ASSERT(data->StepNo == 1); if (table) - IM_ASSERT(table->RowPosY1 == StartPosY && table->RowPosY2 == window->DC.CursorPos.y); + IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y); - ItemsHeight = (window->DC.CursorPos.y - StartPosY) / (float)(DisplayEnd - DisplayStart); - bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); + clipper->ItemsHeight = (window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart); + bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); if (affected_by_floating_point_precision) - ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. + clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. - IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); + IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards. } // Step 0 or 1: Calculate the actual ranges of visible elements. - const int already_submitted = DisplayEnd; + const int already_submitted = clipper->DisplayEnd; if (calc_clipping) { if (g.LogEnabled) { // If logging is active, do not perform any clipping - data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, ItemsCount)); + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(0, clipper->ItemsCount)); } else { @@ -2728,7 +2725,7 @@ bool ImGuiListClipper::Step() if (is_nav_request) data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0)); if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && g.NavTabbingDir == -1) - data->Ranges.push_back(ImGuiListClipperRange::FromIndices(ItemsCount - 1, ItemsCount)); + data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount)); // Add focused/active item ImRect nav_rect_abs = ImGui::WindowRectRelToAbs(window, window->NavRectRel[0]); @@ -2748,10 +2745,10 @@ bool ImGuiListClipper::Step() for (int i = 0; i < data->Ranges.Size; i++) if (data->Ranges[i].PosToIndexConvert) { - int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / ItemsHeight); - int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / ItemsHeight) + 0.999999f); - data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, ItemsCount - 1); - data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, ItemsCount); + int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight); + int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f); + data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1); + data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, clipper->ItemsCount); data->Ranges[i].PosToIndexConvert = false; } ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo); @@ -2760,23 +2757,30 @@ bool ImGuiListClipper::Step() // Step 0+ (if item height is given in advance) or 1+: Display the next range in line. if (data->StepNo < data->Ranges.Size) { - DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted); - DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, ItemsCount); - if (DisplayStart > already_submitted) //-V1051 - ImGuiListClipper_SeekCursorForItem(this, DisplayStart); + clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted); + clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount); + if (clipper->DisplayStart > already_submitted) //-V1051 + ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart); data->StepNo++; return true; } // After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), // Advance the cursor to the end of the list and then returns 'false' to end the loop. - if (ItemsCount < INT_MAX) - ImGuiListClipper_SeekCursorForItem(this, ItemsCount); + if (clipper->ItemsCount < INT_MAX) + ImGuiListClipper_SeekCursorForItem(clipper, clipper->ItemsCount); - End(); return false; } +bool ImGuiListClipper::Step() +{ + bool ret = ImGuiListClipper_StepInternal(this); + if (ret == false) + End(); + return ret; +} + //----------------------------------------------------------------------------- // [SECTION] STYLING //----------------------------------------------------------------------------- From 07b9999de9b7c1a1c07cfbd8d972e193fdbdbfdc Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Aug 2022 15:18:07 +0200 Subject: [PATCH 13/14] Debug Log: added 'Clipper' events logging. --- docs/CHANGELOG.txt | 2 +- imgui.cpp | 16 +++++++++++++++- imgui_internal.h | 6 ++++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5882196f4..47e03a6da 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -79,7 +79,7 @@ Other Changes: - Platform IME: [Windows] Removed call to ImmAssociateContextEx() leading to freeze on some setups. (#2589, #5535, #5264, #4972) - Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138) -- Debug Tools: Debug Log: Added IO events logging. +- Debug Tools: Debug Log: Added 'IO' and 'Clipper' events logging. - Debug Tools: Item Picker: Mouse button can be changed by holding Ctrl+Shift, making it easier to use the Item Picker in e.g. menus. (#2673) - Backends: Metal: Use __bridge for ARC based systems. (#5403) [@stack] diff --git a/imgui.cpp b/imgui.cpp index 99a4bd8de..bbc35ba1f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2596,6 +2596,7 @@ void ImGuiListClipper::Begin(int items_count, float items_height) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name); if (ImGuiTable* table = g.CurrentTable) if (table->IsInsideRow) @@ -2622,6 +2623,7 @@ void ImGuiListClipper::End() if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData) { // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user. + IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name); if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0) ImGuiListClipper_SeekCursorForItem(this, ItemsCount); @@ -2775,8 +2777,19 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) bool ImGuiListClipper::Step() { + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + bool need_items_height = (ItemsHeight <= 0.0f); bool ret = ImGuiListClipper_StepInternal(this); - if (ret == false) + if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false) + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n"); + if (need_items_height && ItemsHeight > 0.0f) + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight); + if (ret) + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd); + else + IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n"); + if (!ret) End(); return ret; } @@ -13278,6 +13291,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) SameLine(); CheckboxFlags("Focus", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus); SameLine(); CheckboxFlags("Popup", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup); SameLine(); CheckboxFlags("Nav", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav); + SameLine(); CheckboxFlags("Clipper", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper); SameLine(); CheckboxFlags("IO", &g.DebugLogFlags, ImGuiDebugLogFlags_EventIO); if (SmallButton("Clear")) diff --git a/imgui_internal.h b/imgui_internal.h index c125698b7..873d97c27 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -210,6 +210,7 @@ namespace ImStb #define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_NAV(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Static Asserts @@ -1514,8 +1515,9 @@ enum ImGuiDebugLogFlags_ ImGuiDebugLogFlags_EventFocus = 1 << 1, ImGuiDebugLogFlags_EventPopup = 1 << 2, ImGuiDebugLogFlags_EventNav = 1 << 3, - ImGuiDebugLogFlags_EventIO = 1 << 4, - ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventIO, + ImGuiDebugLogFlags_EventClipper = 1 << 4, + ImGuiDebugLogFlags_EventIO = 1 << 5, + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventIO, ImGuiDebugLogFlags_OutputToTTY = 1 << 10, // Also send output to TTY }; From 72096bf6986d0bcc4543537dcfc581451d36ec29 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Aug 2022 15:38:47 +0200 Subject: [PATCH 14/14] Clipper: simplify code and remove cases where true is returned with empty display range as an extra step. --- imgui.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index bbc35ba1f..46f0c0c77 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2669,10 +2669,9 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) if (data->StepNo == 0 && table != NULL && !table->IsUnfrozenRows) { clipper->DisplayStart = data->ItemsFrozen; - clipper->DisplayEnd = data->ItemsFrozen + 1; - if (clipper->DisplayStart >= clipper->ItemsCount) - return false; - data->ItemsFrozen++; + clipper->DisplayEnd = ImMin(data->ItemsFrozen + 1, clipper->ItemsCount); + if (clipper->DisplayStart < clipper->DisplayEnd) + data->ItemsFrozen++; return true; } @@ -2687,8 +2686,6 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) data->Ranges.push_front(ImGuiListClipperRange::FromIndices(data->ItemsFrozen, data->ItemsFrozen + 1)); clipper->DisplayStart = ImMax(data->Ranges[0].Min, data->ItemsFrozen); clipper->DisplayEnd = ImMin(data->Ranges[0].Max, clipper->ItemsCount); - if (clipper->DisplayStart == clipper->DisplayEnd) - return false; data->StepNo = 1; return true; } @@ -2778,9 +2775,10 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) bool ImGuiListClipper::Step() { ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; bool need_items_height = (ItemsHeight <= 0.0f); bool ret = ImGuiListClipper_StepInternal(this); + if (ret && (DisplayStart == DisplayEnd)) + ret = false; if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false) IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n"); if (need_items_height && ItemsHeight > 0.0f)