From f8a806ad9f82d18b3b49334cbfc8e3cdb1f82276 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 10 Nov 2021 17:53:58 +0100 Subject: [PATCH 01/17] Tooltips, Internal: (Breaking) swapped parameter order to accomodate for future tooltip api rework. --- imgui.cpp | 8 ++++---- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 854706b2..aafec54c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8219,10 +8219,10 @@ void ImGui::SetScrollHereY(float center_y_ratio) void ImGui::BeginTooltip() { - BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None); + BeginTooltipEx(ImGuiTooltipFlags_None, ImGuiWindowFlags_None); } -void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags) +void ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags) { ImGuiContext& g = *GImGui; @@ -8251,7 +8251,7 @@ void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags toolt ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); } ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; - Begin(window_name, NULL, flags | extra_flags); + Begin(window_name, NULL, flags | extra_window_flags); } void ImGui::EndTooltip() @@ -8262,7 +8262,7 @@ void ImGui::EndTooltip() void ImGui::SetTooltipV(const char* fmt, va_list args) { - BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip); + BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None); TextV(fmt, args); EndTooltip(); } diff --git a/imgui_internal.h b/imgui_internal.h index 448c2b13..9e4fc159 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2527,7 +2527,7 @@ namespace ImGui IMGUI_API void ClosePopupsExceptModals(); IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags); IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags); - IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags); + IMGUI_API void BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window); IMGUI_API ImGuiWindow* GetTopMostPopupModal(); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 96c0e2cb..00f481b5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5580,7 +5580,7 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags { ImGuiContext& g = *GImGui; - BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip); + BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None); const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text; if (text_end > text) { From 2c29e391dd2e640f4c5ddca18e2e7df7ccf57b23 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 10 Nov 2021 19:17:01 +0100 Subject: [PATCH 02/17] Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceAllowNullID doesn't lose tooltip when scrolling. (#143) Reduced amount of self critical commentary since it'll appear like a hack for users but it isn't more a hack than many other things. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 254c9329..944a0975 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,8 @@ Other Changes: by the clipper to display. (#3841) - Clipper: fixed content height declaration slightly mismatching the value of when not using a clipper. (an additional ItemSpacing.y was declared, affecting scrollbar range). +- Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceAllowNullID doesn't lose + tooltip when scrolling. (#143) - Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. (#4644) diff --git a/imgui.cpp b/imgui.cpp index aafec54c..ef1d2554 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3121,7 +3121,7 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n) ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) { ImGuiID seed = IDStack.back(); - const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) }; + ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs); ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed); ImGui::KeepAliveID(id); return id; @@ -10276,16 +10276,16 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) return false; // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to: - // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride. + // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag. if (!(flags & ImGuiDragDropFlags_SourceAllowNullID)) { IM_ASSERT(0); return false; } - // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image() + // Magic fallback to handle items with no assigned ID, e.g. Text(), Image() // We build a throwaway ID based on current ID stack + relative AABB of items in window. - // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled. // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); From d80a9123b741dc7d99cee76cbbb047cfb7d91292 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 10 Nov 2021 20:17:11 +0100 Subject: [PATCH 03/17] Internals: move chunks of IsItemHovered() so upcoming commit can be less noisy. This commit should be a no-op (check by comparing without white-space changes) --- imgui.cpp | 72 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ef1d2554..d92f3f4d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3278,42 +3278,46 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) { if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; - return IsItemFocused(); + if (!IsItemFocused()) + return false; + } + else + { + // Test for bounding box overlap, as updated as ItemAdd() + ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags; + if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) + return false; + IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) == 0); // Flags not supported by this function + + // Test if we are hovering the right window (our window could be behind another window) + // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851) + // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable + // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was + // the test that has been running for a long while. + if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) + if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) + return false; + + // Test if another item is active (e.g. being dragged) + if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) + if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) + return false; + + // Test if interactions on this window are blocked by an active popup or modal. + // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. + if (!IsWindowContentHoverable(window, flags)) + return false; + + // Test if the item is disabled + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + return false; + + // Special handling for calling after Begin() which represent the title bar or tab. + // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. + if (g.LastItemData.ID == window->MoveId && window->WriteAccessed) + return false; } - // Test for bounding box overlap, as updated as ItemAdd() - ImGuiItemStatusFlags status_flags = g.LastItemData.StatusFlags; - if (!(status_flags & ImGuiItemStatusFlags_HoveredRect)) - return false; - IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy)) == 0); // Flags not supported by this function - - // Test if we are hovering the right window (our window could be behind another window) - // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851) - // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable - // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was - // the test that has been running for a long while. - if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0) - if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0) - return false; - - // Test if another item is active (e.g. being dragged) - if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0) - if (g.ActiveId != 0 && g.ActiveId != g.LastItemData.ID && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId) - return false; - - // Test if interactions on this window are blocked by an active popup or modal. - // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. - if (!IsWindowContentHoverable(window, flags)) - return false; - - // Test if the item is disabled - if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) - return false; - - // Special handling for calling after Begin() which represent the title bar or tab. - // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case. - if (g.LastItemData.ID == window->MoveId && window->WriteAccessed) - return false; return true; } From 3fde445b91a357db4d3e78a1526170a479b130f4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 15 Nov 2021 16:05:54 +0100 Subject: [PATCH 04/17] Misc: Added missing ImGuiMouseCursor_NotAllowed cursor for software rendering (when io.MouseDrawCursor is enabled). (#4713) --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 58 ++++++++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 944a0975..089d8e84 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,8 @@ Other Changes: - Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. (#4644) +- Misc: Added missing ImGuiMouseCursor_NotAllowed cursor for software rendering (when the + io.MouseDrawCursor flag is enabled). (#4713) [@nobody-special666] - Misc: Fix MinGW DLL build issue (when IMGUI_API is defined). [@rokups] - CI: Add MinGW DLL build to test suite. [@rokups] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 86bc0f2b..809c8490 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1919,37 +1919,38 @@ ImFontConfig::ImFontConfig() // A work of art lies ahead! (. = white layer, X = black layer, others are blank) // The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. -const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; // Actual texture will be 2 times that + 1 spacing. +// (This is used when io.MouseDrawCursor = true) +const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing. const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = { - "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX " - "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X " - "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X " - "X - X.X - X.....X - X.....X -X...X - X...X- X..X " - "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X " - "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX " - "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX " - "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX " - "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X " - "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X" - "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X" - "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X" - "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X" - "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X" - "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X" - "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X" - "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X " - "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X " - "X.X X..X - -X.......X- X.......X - XX XX - - X..........X " - "XX X..X - - X.....X - X.....X - X.X X.X - - X........X " - " X..X - X...X - X...X - X..X X..X - - X........X " - " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX " - "------------ - X - X -X.....................X- ------------------" - " ----------------------------------- X...XXXXXXXXXXXXX...X - " - " - X..X X..X - " - " - X.X X.X - " - " - XX XX - " + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX " + "..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X" + "--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X" + "X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X " + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X " + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X " + "X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X " + "X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X " + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X " + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X" + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X" + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX " + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------" + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - " + "X.X X..X - -X.......X- X.......X - XX XX - - X..........X - " + "XX X..X - - X.....X - X.....X - X.X X.X - - X........X - " + " X..X - - X...X - X...X - X..X X..X - - X........X - " + " XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - " + "------------- - X - X -X.....................X- ------------------- " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " }; static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] = @@ -1963,6 +1964,7 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand + { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed }; ImFontAtlas::ImFontAtlas() From a3667f462a01b5dfc05e8032a2006762c426d4fd Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 16 Nov 2021 16:13:04 +0100 Subject: [PATCH 05/17] Fixed tooltip in own viewport over modal from being incorrectly dimmed. (#4729) Normally we would aim to ensure that g.Windows[] gets maintained to reflect display layer but it is presently non trivial. --- imgui.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d92f3f4d..a7bd7280 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4365,11 +4365,15 @@ static void AddWindowToDrawData(ImGuiWindow* window, int layer) } } -// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) -static void AddRootWindowToDrawData(ImGuiWindow* window) +static inline int GetWindowDisplayLayer(ImGuiWindow* window) { - int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; - AddWindowToDrawData(window, layer); + return (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0; +} + +// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu) +static inline void AddRootWindowToDrawData(ImGuiWindow* window) +{ + AddWindowToDrawData(window, GetWindowDisplayLayer(window)); } void ImDrawDataBuilder::FlattenIntoSingleLayer() @@ -6763,6 +6767,12 @@ bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below) { ImGuiContext& g = *GImGui; + + // It would be saner to ensure that display layer is always reflected in the g.Windows[] order, which would likely requires altering all manipulations of that array + const int display_layer_delta = GetWindowDisplayLayer(potential_above) - GetWindowDisplayLayer(potential_below); + if (display_layer_delta != 0) + return display_layer_delta > 0; + for (int i = g.Windows.Size - 1; i >= 0; i--) { ImGuiWindow* candidate_window = g.Windows[i]; From 764f9e606d106591072a8e5a79d4e801c4c699fb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 17 Nov 2021 12:45:33 +0100 Subject: [PATCH 06/17] Fixed crash on right-click without modal, introduced by previous commit a3667f46, (#4729) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a7bd7280..8b6613e0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3712,7 +3712,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() // Find the top-most window between HoveredWindow and the top-most Modal Window. // This is where we can trim the popup stack. ImGuiWindow* modal = GetTopMostPopupModal(); - bool hovered_window_above_modal = g.HoveredWindow && IsWindowAbove(g.HoveredWindow, modal); + bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || IsWindowAbove(g.HoveredWindow, modal)); ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true); } } From 4d9a3b19d5e348fafa5f680ffe1e49167b149aa0 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Thu, 18 Nov 2021 16:54:16 +0200 Subject: [PATCH 07/17] Internals: Implement a continuable IM_DEBUG_BREAK on GCC for common archs. (#2673) --- imgui_internal.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 9e4fc159..7b430dc4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -253,12 +253,19 @@ namespace ImStb #endif // Debug Tools -// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item. +// Use 'Metrics/Debugger->Tools->Item Picker' to break into the call-stack of a specific item. +// This will call IM_DEBUG_BREAK() which you may redefine yourself. See https://github.com/scottt/debugbreak for more reference. #ifndef IM_DEBUG_BREAK -#if defined(__clang__) -#define IM_DEBUG_BREAK() __builtin_debugtrap() -#elif defined (_MSC_VER) +#if defined (_MSC_VER) #define IM_DEBUG_BREAK() __debugbreak() +#elif defined(__clang__) +#define IM_DEBUG_BREAK() __builtin_debugtrap() +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +#define IM_DEBUG_BREAK() __asm__ volatile("int $0x03") +#elif defined(__GNUC__) && defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01") +#elif defined(__GNUC__) defined(__arm__) && !defined(__thumb__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0"); #else #define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! #endif From 5ac25e7c7a8f244f84b935ea5a5f69b67b72b6f4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Nov 2021 15:10:47 +0100 Subject: [PATCH 08/17] InputText: fixed ReadOnly flag preventing callbacks from receiving the text buffer. (#4762) --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 089d8e84..bde6e9e3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,7 @@ Other Changes: - InputText, Nav: fixed repeated calls to SetKeyboardFocusHere() preventing to use InputText(). (#4682) - InputText: made double-click select word, triple-line select line. Word delimitation logic differs slightly from the one used by CTRL+arrows. (#2244) +- InputText: fixed ReadOnly flag preventing callbacks from receiving the text buffer. (#4762) [@actondev] - Clipper: currently focused item is automatically included in clipper range. Fixes issue where e.g. drag and dropping an item and scrolling ensure the item source location is still submitted. (#3841, #1725) [@GamingMinds-DanielC, @ocornut] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 00f481b5..bb90b118 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4484,8 +4484,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback_data.Flags = flags; callback_data.UserData = callback_user_data; + char* callback_buf = is_readonly ? buf : state->TextA.Data; callback_data.EventKey = event_key; - callback_data.Buf = state->TextA.Data; + callback_data.Buf = callback_buf; callback_data.BufTextLen = state->CurLenA; callback_data.BufSize = state->BufCapacityA; callback_data.BufDirty = false; @@ -4500,7 +4501,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback(&callback_data); // Read back what user may have modified - IM_ASSERT(callback_data.Buf == state->TextA.Data); // Invalid to modify those fields + IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields IM_ASSERT(callback_data.BufSize == state->BufCapacityA); IM_ASSERT(callback_data.Flags == flags); const bool buf_dirty = callback_data.BufDirty; From 65f4be1a10932545a29faa54b8619eef7c0fe678 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Nov 2021 21:41:34 +0100 Subject: [PATCH 09/17] InputText: Internals: moved "apply_new_text" application code to reduce noise in a future commit (will be for #4714) + removed unused fields. The move would ideally be no-op. technically we now clear state->Flags before calling ResizeCallback but those are unrelated. The 2 unused fields were incorrectly added by 24ff25981. --- imgui.h | 4 +-- imgui_internal.h | 2 -- imgui_widgets.cpp | 66 ++++++++++++++++++++++------------------------- 3 files changed, 33 insertions(+), 39 deletions(-) diff --git a/imgui.h b/imgui.h index d90d9041..49218b0f 100644 --- a/imgui.h +++ b/imgui.h @@ -64,7 +64,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.86 WIP" -#define IMGUI_VERSION_NUM 18510 +#define IMGUI_VERSION_NUM 18511 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE @@ -974,7 +974,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, // [Internal] - ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!) + ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] On child window: allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() diff --git a/imgui_internal.h b/imgui_internal.h index 7b430dc4..4ff33794 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1027,8 +1027,6 @@ struct IMGUI_API ImGuiInputTextState bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection bool Edited; // edited this frame ImGuiInputTextFlags Flags; // copy of InputText() flags - ImGuiInputTextCallback UserCallback; // " - void* UserCallbackData; // " ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bb90b118..a6f31958 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4165,8 +4165,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->Edited = false; state->BufCapacityA = buf_size; state->Flags = flags; - state->UserCallback = callback; - state->UserCallbackData = callback_user_data; // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. // Down the line we should have a cleaner library-wide concept of Selected vs Active. @@ -4404,11 +4402,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Process callbacks and apply result back to user's buffer. + const char* apply_new_text = NULL; + int apply_new_text_length = 0; if (g.ActiveId == id) { IM_ASSERT(state != NULL); - const char* apply_new_text = NULL; - int apply_new_text_length = 0; if (cancel_edit) { // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. @@ -4528,39 +4526,37 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } } - // Copy result to user buffer - if (apply_new_text) - { - // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size - // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used - // without any storage on user's side. - IM_ASSERT(apply_new_text_length >= 0); - if (is_resizable) - { - ImGuiInputTextCallbackData callback_data; - callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; - callback_data.Flags = flags; - callback_data.Buf = buf; - callback_data.BufTextLen = apply_new_text_length; - callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); - callback_data.UserData = callback_user_data; - callback(&callback_data); - buf = callback_data.Buf; - buf_size = callback_data.BufSize; - apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); - IM_ASSERT(apply_new_text_length <= buf_size); - } - //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); - - // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. - ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); - value_changed = true; - } - // Clear temporary user storage state->Flags = ImGuiInputTextFlags_None; - state->UserCallback = NULL; - state->UserCallbackData = NULL; + } + + // Copy result to user buffer. This can currently only happen when (g.ActiveId == id) + if (apply_new_text != NULL) + { + // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size + // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used + // without any storage on user's side. + IM_ASSERT(apply_new_text_length >= 0); + if (is_resizable) + { + ImGuiInputTextCallbackData callback_data; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.Flags = flags; + callback_data.Buf = buf; + callback_data.BufTextLen = apply_new_text_length; + callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); + callback_data.UserData = callback_user_data; + callback(&callback_data); + buf = callback_data.Buf; + buf_size = callback_data.BufSize; + apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1); + IM_ASSERT(apply_new_text_length <= buf_size); + } + //IMGUI_DEBUG_LOG("InputText(\"%s\"): apply_new_text length %d\n", label, apply_new_text_length); + + // If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size. + ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size)); + value_changed = true; } // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value) From cb5c73f64a225bb3fdaea1a4db3e20096b8928be Mon Sep 17 00:00:00 2001 From: averne <45773016+averne@users.noreply.github.com> Date: Mon, 29 Nov 2021 00:05:57 +0100 Subject: [PATCH 10/17] Fix: IM_DEBUG_BREAK macro on ARM GCC (#4767) --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 4ff33794..581ddd12 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -264,7 +264,7 @@ namespace ImStb #define IM_DEBUG_BREAK() __asm__ volatile("int $0x03") #elif defined(__GNUC__) && defined(__thumb__) #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01") -#elif defined(__GNUC__) defined(__arm__) && !defined(__thumb__) +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0"); #else #define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! From 5ccb66794b7533cd473a7179d4114de992ebc271 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Nov 2021 12:18:25 +0100 Subject: [PATCH 11/17] Backends: WebGPU: Passing explicit buffer sizes as validation layers appears to not do what the in-flux specs says. (#4766 --- backends/imgui_impl_sdlrenderer.cpp | 9 ++++++--- backends/imgui_impl_sdlrenderer.h | 9 ++++++--- backends/imgui_impl_wgpu.cpp | 5 +++-- docs/BACKENDS.md | 5 ++++- docs/CHANGELOG.txt | 9 ++++++--- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/backends/imgui_impl_sdlrenderer.cpp b/backends/imgui_impl_sdlrenderer.cpp index bfc2b676..6c1786e7 100644 --- a/backends/imgui_impl_sdlrenderer.cpp +++ b/backends/imgui_impl_sdlrenderer.cpp @@ -1,14 +1,17 @@ // dear imgui: Renderer Backend for SDL_Renderer // (Requires: SDL 2.0.17+) -// Important to understand: SDL_Renderer is an _optional_ component of SDL. We do not recommend you use SDL_Renderer -// because it provide a rather limited API to the end-user. We provide this backend for the sake of completeness. +// Important to understand: SDL_Renderer is an _optional_ component of SDL. // For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. +// If your application will want to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might +// be difficult to step out of those boundaries. +// However, we understand it is a convenient choice to get an app started easily. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! // Missing features: -// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. +// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices (SDL_RenderGeometryRaw() is missing a vertex offset). // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. diff --git a/backends/imgui_impl_sdlrenderer.h b/backends/imgui_impl_sdlrenderer.h index 8c67fa3a..e8f4d10b 100644 --- a/backends/imgui_impl_sdlrenderer.h +++ b/backends/imgui_impl_sdlrenderer.h @@ -1,14 +1,17 @@ // dear imgui: Renderer Backend for SDL_Renderer // (Requires: SDL 2.0.17+) -// Important to understand: SDL_Renderer is an _optional_ component of SDL. We do not recommend you use SDL_Renderer -// because it provide a rather limited API to the end-user. We provide this backend for the sake of completeness. +// Important to understand: SDL_Renderer is an _optional_ component of SDL. // For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. +// If your application will want to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might +// be difficult to step out of those boundaries. +// However, we understand it is a convenient choice to get an app started easily. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! // Missing features: -// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. +// [ ] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices (SDL_RenderGeometryRaw() is missing a vertex offset). #pragma once #include "imgui.h" // IMGUI_IMPL_API diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 2f621ed8..66430515 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -13,6 +13,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2021-11-29: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer()/wgpuRenderPassEncoderSetIndexBuffer(). // 2021-08-24: Fix for latest specs. // 2021-05-24: Add support for draw_data->FramebufferScale. // 2021-05-19: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) @@ -313,8 +314,8 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1); // Bind shader and vertex buffers - wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, 0); - wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, 0); + wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize); + wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize); wgpuRenderPassEncoderSetPipeline(ctx, g_pipelineState); wgpuRenderPassEncoderSetBindGroup(ctx, 0, g_resources.CommonBindGroup, 0, NULL); diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index c878132b..f061d70c 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -128,7 +128,10 @@ Once it works, if you really need it you can replace parts of backends with your and you have high-level systems everywhere.
Suggestion: try using a non-portable backend first (e.g. win32 + underlying graphics API) to get your desktop builds working first. This will get you running faster and get your acquainted with -how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API. +how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API... + +Generally: +It is unlikely you will add value to your project by creating your own backend. Also: The [multi-viewports feature](https://github.com/ocornut/imgui/issues/1542) of the 'docking' branch allows diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bde6e9e3..8bc8d57f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -70,13 +70,16 @@ Other Changes: (an additional ItemSpacing.y was declared, affecting scrollbar range). - Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceAllowNullID doesn't lose tooltip when scrolling. (#143) -- Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce - likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling - vkCmdSetScissor() explicitly every frame. (#4644) - Misc: Added missing ImGuiMouseCursor_NotAllowed cursor for software rendering (when the io.MouseDrawCursor flag is enabled). (#4713) [@nobody-special666] - Misc: Fix MinGW DLL build issue (when IMGUI_API is defined). [@rokups] - CI: Add MinGW DLL build to test suite. [@rokups] +- Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce + likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling + vkCmdSetScissor() explicitly every frame. (#4644) +- Backends: WebGPU: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer() and + wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the + in-flux specs says. (#4766) [@meshula] ----------------------------------------------------------------------- From 66f0fb986ce9f187d5d17e0488e7836fe14ceafc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Nov 2021 16:25:45 +0100 Subject: [PATCH 12/17] Inputtext, Nav: fixed using SetKeyboardFocusHere() on InputTextMultiline(). (#4761) --- docs/CHANGELOG.txt | 1 + imgui.h | 2 +- imgui_widgets.cpp | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8bc8d57f..5f18a91a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,7 @@ Other Changes: Home/End leads to scrolling. Fixed not setting mouse position when a failed move request (e.g. when already at edge) reactivates the navigation highlight. - InputText, Nav: fixed repeated calls to SetKeyboardFocusHere() preventing to use InputText(). (#4682) +- Inputtext, Nav: fixed using SetKeyboardFocusHere() on InputTextMultiline(). (#4761) - InputText: made double-click select word, triple-line select line. Word delimitation logic differs slightly from the one used by CTRL+arrows. (#2244) - InputText: fixed ReadOnly flag preventing callbacks from receiving the text buffer. (#4762) [@actondev] diff --git a/imgui.h b/imgui.h index 49218b0f..6cbe6944 100644 --- a/imgui.h +++ b/imgui.h @@ -64,7 +64,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.86 WIP" -#define IMGUI_VERSION_NUM 18511 +#define IMGUI_VERSION_NUM 18512 #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 a6f31958..431a9183 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3966,7 +3966,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! - if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope, + if (is_multiline) // Open group before calling GetID() because groups tracks id created within their scope (including the scrollbar) BeginGroup(); const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); @@ -4770,9 +4770,22 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) { + // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); + ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; + g.CurrentItemFlags |= ImGuiItemFlags_Inputable; EndChild(); + g.CurrentItemFlags = backup_item_flags; + + // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... + ImGuiLastItemData item_data = g.LastItemData; EndGroup(); + if (g.LastItemData.ID == 0) + { + g.LastItemData.ID = id; + g.LastItemData.InFlags = item_data.InFlags; + g.LastItemData.StatusFlags = item_data.StatusFlags; + } } // Log as text From 9d704d99d3d76da51be36e824df1fc2059403fc2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Nov 2021 12:42:23 +0100 Subject: [PATCH 13/17] Internals: wrapped ImQsort() in an inline function + added a define guard. --- imgui.cpp | 6 ++---- imgui_internal.h | 8 +++++--- imgui_widgets.cpp | 3 +-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8b6613e0..ed3cebc2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1954,8 +1954,7 @@ void ImGuiStorage::BuildSortByKey() return 0; } }; - if (Data.Size > 1) - ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID); + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID); } int ImGuiStorage::GetInt(ImGuiID key, int default_val) const @@ -4304,8 +4303,7 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im if (window->Active) { int count = window->DC.ChildWindows.Size; - if (count > 1) - ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); + ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer); for (int i = 0; i < count; i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; diff --git a/imgui_internal.h b/imgui_internal.h index 581ddd12..52b20654 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -302,7 +302,9 @@ static inline ImGuiID ImHash(const void* data, int size, ImU32 seed = 0) { ret #endif // Helpers: Sorting -#define ImQsort qsort +#ifndef ImQsort +static inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); } +#endif // Helpers: Color Blending IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); @@ -409,8 +411,8 @@ static inline double ImLog(double x) { return log(x); } static inline int ImAbs(int x) { return x < 0 ? -x : x; } static inline float ImAbs(float x) { return fabsf(x); } static inline double ImAbs(double x) { return fabs(x); } -static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : ((x > 0.0f) ? 1.0f : 0.0f); } // Sign operator - returns -1, 0 or 1 based on sign of argument -static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); } +static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument +static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; } #ifdef IMGUI_ENABLE_SSE static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); } #else diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 431a9183..04ab40d8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7247,8 +7247,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) - if (tab_bar->Tabs.Size > 1) - ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); tab_bar->TabsAddedNew = false; // Flags From c5db276521d56f3408cef7c17f20f05f9722abba Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Nov 2021 15:17:18 +0100 Subject: [PATCH 14/17] InputText, Nav: fixed tabbing through InputTextMultiline(). (#4761, #3092) Messy... Broken by 66f0fb9. Added ImGuiItemFlags_NoTabStop to EndGroup() ahead of time (not strictly needed here). --- imgui.cpp | 2 +- imgui_demo.cpp | 21 +++++++++++---------- imgui_widgets.cpp | 11 +++++++---- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ed3cebc2..2172d0fe 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7942,7 +7942,7 @@ void ImGui::EndGroup() window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. ItemSize(group_bb.GetSize()); - ItemAdd(group_bb, 0); + ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop); // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group. // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 91bfb2d8..d8a25b55 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2285,7 +2285,7 @@ static void ShowDemoWindowWidgets() // Select an item type const char* item_names[] = { - "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat", + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" }; static int item_type = 4; @@ -2308,15 +2308,16 @@ static void ShowDemoWindowWidgets() if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) - if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input - if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 9) { ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item - if (item_type == 10){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) - if (item_type == 11){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node - if (item_type == 12){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. - if (item_type == 13){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } - if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window) + if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input + if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item + if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node + if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } + if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } // Display the values of IsItemHovered() and other common item state functions. // Note that the ImGuiHoveredFlags_XXX flags can be combined. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 04ab40d8..c3d09e5a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3979,6 +3979,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImGuiWindow* draw_window = window; ImVec2 inner_size = frame_size; ImGuiItemStatusFlags item_status_flags = 0; + ImGuiLastItemData item_data_backup; if (is_multiline) { ImVec2 backup_pos = window->DC.CursorPos; @@ -3989,6 +3990,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ return false; } item_status_flags = g.LastItemData.StatusFlags; + item_data_backup = g.LastItemData; window->DC.CursorPos = backup_pos; // We reproduce the contents of BeginChildFrame() in order to provide 'label' so our window internal data are easier to read/debug. @@ -4773,18 +4775,19 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); ImGuiItemFlags backup_item_flags = g.CurrentItemFlags; - g.CurrentItemFlags |= ImGuiItemFlags_Inputable; + g.CurrentItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; EndChild(); + item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); g.CurrentItemFlags = backup_item_flags; // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... - ImGuiLastItemData item_data = g.LastItemData; + // FIXME: This quite messy/tricky, should attempt to get rid of the child window. EndGroup(); if (g.LastItemData.ID == 0) { g.LastItemData.ID = id; - g.LastItemData.InFlags = item_data.InFlags; - g.LastItemData.StatusFlags = item_data.StatusFlags; + g.LastItemData.InFlags = item_data_backup.InFlags; + g.LastItemData.StatusFlags = item_data_backup.StatusFlags; } } From f087a5b856b1f5e2d4572baa54ddff05073644b4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Nov 2021 16:02:47 +0100 Subject: [PATCH 15/17] Metrics: Added a node showing windows in submission order and showing the Begin() stack. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 50 +++++++++++++++++++++++++++++++++++++++++----- imgui_internal.h | 2 ++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5f18a91a..d7401c93 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,7 @@ Other Changes: (an additional ItemSpacing.y was declared, affecting scrollbar range). - Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceAllowNullID doesn't lose tooltip when scrolling. (#143) +- Metrics: Added a node showing windows in submission order and showing the Begin() stack. - Misc: Added missing ImGuiMouseCursor_NotAllowed cursor for software rendering (when the io.MouseDrawCursor flag is enabled). (#4713) [@nobody-special666] - Misc: Fix MinGW DLL build issue (when IMGUI_API is defined). [@rokups] diff --git a/imgui.cpp b/imgui.cpp index 2172d0fe..a7568e4f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1946,7 +1946,7 @@ void ImGuiStorage::BuildSortByKey() { struct StaticFunc { - static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs) + static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs) { // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that. if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1; @@ -1954,7 +1954,7 @@ void ImGuiStorage::BuildSortByKey() return 0; } }; - ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID); + ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID); } int ImGuiStorage::GetInt(ImGuiID key, int default_val) const @@ -5872,7 +5872,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Update ->RootWindow and others pointers (before any possible call to FocusWindow) if (first_begin_of_the_frame) + { UpdateWindowParentAndRootLinks(window, flags, parent_window); + window->ParentWindowInBeginStack = parent_window_in_stack; + } // Process SetNextWindow***() calls // (FIXME: Consider splitting the HasXXX flags into X/Y components @@ -11314,6 +11317,7 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} // - DebugNodeWindow() [Internal] // - DebugNodeWindowSettings() [Internal] // - DebugNodeWindowsList() [Internal] +// - DebugNodeWindowsListByBeginStackParent() [Internal] //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_METRICS_WINDOW @@ -11536,8 +11540,27 @@ void ImGui::ShowMetricsWindow(bool* p_open) } // Windows - DebugNodeWindowsList(&g.Windows, "Windows"); - //DebugNodeWindowsList(&g.WindowsFocusOrder, "WindowsFocusOrder"); + if (TreeNode("Windows", "Windows (%d)", g.Windows.Size)) + { + //SetNextItemOpen(true, ImGuiCond_Once); + DebugNodeWindowsList(&g.Windows, "By display order"); + DebugNodeWindowsList(&g.WindowsFocusOrder, "By focus order (root windows)"); + if (TreeNode("By submission order (begin stack)")) + { + // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship! + ImVector& temp_buffer = g.WindowsTempSortBuffer; + temp_buffer.resize(0); + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount) + temp_buffer.push_back(g.Windows[i]); + struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } }; + ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder); + DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL); + TreePop(); + } + + TreePop(); + } // DrawLists int drawlist_count = 0; @@ -12161,7 +12184,6 @@ void ImGui::DebugNodeWindowsList(ImVector* windows, const char* la { if (!TreeNode(label, "%s (%d)", label, windows->Size)) return; - Text("(In front-to-back order:)"); for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back { PushID((*windows)[i]); @@ -12171,6 +12193,24 @@ void ImGui::DebugNodeWindowsList(ImVector* windows, const char* la TreePop(); } +// FIXME-OPT: This is technically suboptimal, but it is simpler this way. +void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack) +{ + for (int i = 0; i < windows_size; i++) + { + ImGuiWindow* window = windows[i]; + if (window->ParentWindowInBeginStack != parent_in_begin_stack) + continue; + char buf[20]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext); + //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name); + DebugNodeWindow(window, buf); + Indent(); + DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window); + Unindent(); + } +} + //----------------------------------------------------------------------------- // [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index 52b20654..f624e707 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2026,6 +2026,7 @@ struct IMGUI_API ImGuiWindow ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) ImDrawList DrawListInst; ImGuiWindow* ParentWindow; // If we are a child _or_ popup _or_ docked window, this is pointing to our parent. Otherwise NULL. + ImGuiWindow* ParentWindowInBeginStack; ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes. ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child. ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. @@ -2784,6 +2785,7 @@ namespace ImGui IMGUI_API void DebugNodeWindow(ImGuiWindow* window, const char* label); IMGUI_API void DebugNodeWindowSettings(ImGuiWindowSettings* settings); IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); + IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); From 440824d4314b59049a196e9e6964d8e72aed25bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Nov 2021 21:48:29 +0100 Subject: [PATCH 16/17] Backends: Fixed early out on empty clip rect. In particular, DX12 backend would warn about it (others not so much). (#4775, #4464) Amend/fix 2b0bd40b --- backends/imgui_impl_allegro5.cpp | 2 +- backends/imgui_impl_dx10.cpp | 2 +- backends/imgui_impl_dx11.cpp | 2 +- backends/imgui_impl_dx12.cpp | 2 +- backends/imgui_impl_dx9.cpp | 2 +- backends/imgui_impl_metal.mm | 2 +- backends/imgui_impl_opengl2.cpp | 2 +- backends/imgui_impl_opengl3.cpp | 2 +- backends/imgui_impl_sdlrenderer.cpp | 2 +- backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_wgpu.cpp | 2 +- docs/CHANGELOG.txt | 1 + 12 files changed, 12 insertions(+), 11 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index ccb1396d..43b04f6b 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -174,7 +174,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle, Draw diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 5be46f67..79bf731d 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -256,7 +256,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index bfe5dca2..3f628cbc 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -266,7 +266,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 5058885c..e9d2e961 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -262,7 +262,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply Scissor/clipping rectangle, Bind texture, Draw diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 9234cb01..4cbd7959 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -251,7 +251,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply Scissor/clipping rectangle, Bind texture, Draw diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 18dcc914..26ddc922 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -513,7 +513,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects() if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index ee52632d..65e778f5 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -203,7 +203,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle (Y is inverted in OpenGL) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 58664ea1..5a802887 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -445,7 +445,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle (Y is inverted in OpenGL) diff --git a/backends/imgui_impl_sdlrenderer.cpp b/backends/imgui_impl_sdlrenderer.cpp index 6c1786e7..e86f473f 100644 --- a/backends/imgui_impl_sdlrenderer.cpp +++ b/backends/imgui_impl_sdlrenderer.cpp @@ -164,7 +164,7 @@ void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data) if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) }; diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index e4f12f2b..aa6a3ddb 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -520,7 +520,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 66430515..072f2549 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -447,7 +447,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); - if (clip_max.x < clip_min.x || clip_max.y < clip_min.y) + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; // Apply scissor/clipping rectangle, Draw diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d7401c93..c54ebcaa 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -79,6 +79,7 @@ Other Changes: - Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. (#4644) +- Backends: DX12: Fixed DRAW_EMPTY_SCISSOR_RECTANGLE warnings. (#4775) - Backends: WebGPU: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer() and wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the in-flux specs says. (#4766) [@meshula] From 5b1a70aa2dafcd589843deb3bd7e97473b47d3ec Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Dec 2021 15:24:55 +0100 Subject: [PATCH 17/17] Fixed RenderRectFilledWithHole() (used by docking) + added dummy EndFrameDrawDimmedBackgrounds() stub in master. The round corner flag change in 033dfd9d forgot to default to _None. --- imgui.cpp | 9 +++++++++ imgui_draw.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a7568e4f..2c43500f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -946,6 +946,7 @@ static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVe static void RenderWindowOuterBorders(ImGuiWindow* window); static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); +static void EndFrameDrawDimmedBackgrounds(); // Viewports static void UpdateViewportsNewFrame(); @@ -4430,6 +4431,11 @@ void ImGui::PopClipRect() window->ClipRect = window->DrawList->_ClipRectStack.back(); } +static void ImGui::EndFrameDrawDimmedBackgrounds() +{ + // (This is currently empty, left here to facilitate sync/merge with docking branch) +} + // This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal. void ImGui::EndFrame() { @@ -4485,6 +4491,9 @@ void ImGui::EndFrame() // Initiate moving window + handle left-click and right-click focus UpdateMouseMovingWindowEndFrame(); + // Draw modal/window whitening backgrounds + EndFrameDrawDimmedBackgrounds(); + // Sort the window list so that all child windows are after their parent // We cannot do that on FocusWindow() because children may not exist yet g.WindowsTempSortBuffer.resize(0); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 809c8490..f76dc2dc 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3901,10 +3901,10 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect const bool fill_R = (inner.Max.x < outer.Max.x); const bool fill_U = (inner.Min.y > outer.Min.y); const bool fill_D = (inner.Max.y < outer.Max.y); - if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft)); - if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight)); - if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight)); - if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft)); + if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight)); + if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight)); + if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight)); if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft); if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight); if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);