From 1362fc0c56d8742167379661a353d8342f7c4a86 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Aug 2023 10:39:56 +0200 Subject: [PATCH 01/14] Debug, Internals: Added DebugDrawCursorPos(), DebugDrawLineExtents() helpers. --- imgui.cpp | 32 ++++++++++++++++++++++++++++++++ imgui_internal.h | 4 +++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index e53ecf890..af1493968 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14689,6 +14689,38 @@ void ImGui::ShowDebugLogWindow(bool* p_open) // [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) //----------------------------------------------------------------------------- +// Draw a small cross at current CursorPos in current window's DrawList +void ImGui::DebugDrawCursorPos(ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 pos = window->DC.CursorPos; + window->DrawList->AddLine(ImVec2(pos.x, pos.y - 3.0f), ImVec2(pos.x, pos.y + 4.0f), col, 1.0f); + window->DrawList->AddLine(ImVec2(pos.x - 3.0f, pos.y), ImVec2(pos.x + 4.0f, pos.y), col, 1.0f); +} + +// Draw a 10px wide rectangle around CurposPos.x using Line Y1/Y2 in current window's DrawList +void ImGui::DebugDrawLineExtents(ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float curr_x = window->DC.CursorPos.x; + float line_y1 = (window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y); + float line_y2 = line_y1 + (window->DC.IsSameLine ? window->DC.PrevLineSize.y : window->DC.CurrLineSize.y); + window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y1), ImVec2(curr_x + 5.0f, line_y1), col, 1.0f); + window->DrawList->AddLine(ImVec2(curr_x - 0.5f, line_y1), ImVec2(curr_x - 0.5f, line_y2), col, 1.0f); + window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y2), ImVec2(curr_x + 5.0f, line_y2), col, 1.0f); +} + +// Draw last item rect in ForegroundDrawList (so it is always visible) +void ImGui::DebugDrawItemRect(ImU32 col) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); +} + +// [DEBUG] Locate item position/rectangle given an ID. static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green void ImGui::DebugLocateItem(ImGuiID target_id) diff --git a/imgui_internal.h b/imgui_internal.h index f10843a5f..6ac8ffc76 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3247,10 +3247,12 @@ namespace ImGui IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); + IMGUI_API void DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255)); + IMGUI_API void DebugDrawLineExtents(ImU32 col = IM_COL32(255, 0, 0, 255)); + IMGUI_API void DebugDrawItemRect(ImU32 col = IM_COL32(255, 0, 0, 255)); IMGUI_API void DebugLocateItem(ImGuiID target_id); // Call sparingly: only 1 at the same time! IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id); // Only call on reaction to a mouse Hover: because only 1 at the same time! IMGUI_API void DebugLocateItemResolveWithLastItem(); - inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); } inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end); From 8f5ce731405e8902db90f34be77246e34e7faa66 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Aug 2023 13:02:44 +0200 Subject: [PATCH 02/14] Tables: Made it possible to use SameLine(0,0) after TableNextColumn() or TableSetColumnIndex() in order to reuse line height from previous cell. --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_demo.cpp | 24 +++++++++++++++++++++++- imgui_tables.cpp | 3 ++- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fcf936dcb..ba956a1de 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,8 @@ Breaking changes: Other changes: +- Tables: Made it possible to use SameLine(0,0) after TableNextColumn() or + TableSetColumnIndex() in order to reuse line height from previous cell. (#3740) - Nav, TreeNode: Pressing Left with ImGuiTreeNodeFlags_NavLeftJumpsBackHere now goes through proper navigation logic: honor scrolling and selection. (#1079, #1131) - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when diff --git a/imgui.h b/imgui.h index 26c55736e..05a18a3a9 100644 --- a/imgui.h +++ b/imgui.h @@ -26,7 +26,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.89.9 WIP" -#define IMGUI_VERSION_NUM 18982 +#define IMGUI_VERSION_NUM 18983 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1cc5331b1..7af4c5d57 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4766,7 +4766,7 @@ static void ShowDemoWindowTables() if (ImGui::TreeNode("Row height")) { HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row."); - if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV)) + if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders)) { for (int row = 0; row < 10; row++) { @@ -4777,6 +4777,28 @@ static void ShowDemoWindowTables() } ImGui::EndTable(); } + + HelpMarker("Showcase using SameLine(0,0) to share Current Line Height between cells.\n\nPlease note that Tables Row Height is not the same thing as Current Line Height, as a table cell may contains multiple lines."); + if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders)) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40)); + ImGui::TableNextColumn(); + ImGui::Text("Line 1"); + ImGui::Text("Line 2"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40)); + ImGui::TableNextColumn(); + ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column + ImGui::Text("Line 1, with SameLine(0,0)"); + ImGui::Text("Line 2"); + + ImGui::EndTable(); + } + ImGui::TreePop(); } diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 33927b8ad..1edfc6992 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1779,7 +1779,7 @@ void ImGui::TableBeginRow(ImGuiTable* table) table->RowTextBaseline = 0.0f; table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent window->DC.PrevLineTextBaseOffset = 0.0f; - window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); + window->DC.PrevLineSize = window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); // This allows users to call SameLine() to share LineSize between columns, and to call it from first column too. window->DC.IsSameLine = window->DC.IsSetPos = false; window->DC.CursorMaxPos.y = next_y1; @@ -2016,6 +2016,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) window->DC.CursorPos.y = table->RowPosY1 + table->CellPaddingY; window->DC.CursorMaxPos.x = window->DC.CursorPos.x; window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT + window->DC.CursorPosPrevLine = window->DC.CursorPos; // This allows users to call SameLine() to share LineSize between columns. window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent; From ac64b656340a1c8bbca4d2b80ad4344ed5ee5109 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Aug 2023 16:16:39 +0200 Subject: [PATCH 03/14] Render: draw dimmed background earlier to match docking code. (#6716) Amend f422e78 --- 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 ba956a1de..786b6c9b5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,8 @@ Other changes: through proper navigation logic: honor scrolling and selection. (#1079, #1131) - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when v_max=INT_MAX (#6675, #6679) [@jbarthelmes] +- ImDrawData: Fixed an issue where TotalVtxCount/TotalIdxCount does not match the sum + of individual ImDrawList's buffer sizes when a dimming/modal background is rendered. (#6716) - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively large radius to AddCircle(). (#6657, #5317) [@EggsyCRO, @jdpatdiscord] - Debug Tools: Metrics: Fixed "Drawlists" section and per-viewport equivalent diff --git a/imgui.cpp b/imgui.cpp index af1493968..2739c847d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5083,6 +5083,10 @@ void ImGui::Render() CallContextHooks(&g, ImGuiContextHookType_RenderPre); + // Draw modal/window whitening backgrounds + if (first_render_of_frame) + RenderDimmedBackgrounds(); + // Add background ImDrawList (for each active viewport) for (int n = 0; n != g.Viewports.Size; n++) { @@ -5092,10 +5096,6 @@ void ImGui::Render() AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); } - // Draw modal/window whitening backgrounds - if (first_render_of_frame) - RenderDimmedBackgrounds(); - // Add ImDrawList to render ImGuiWindow* windows_to_render_top_most[2]; windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; From d2c7cbcbf9bf6af935ee2b089fa772e3c6ea7d41 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Aug 2023 16:23:04 +0200 Subject: [PATCH 04/14] Misc: Made multiple calls to Render() during the same frame early out faster. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 786b6c9b5..5b71899ad 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,7 @@ Other changes: of individual ImDrawList's buffer sizes when a dimming/modal background is rendered. (#6716) - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively large radius to AddCircle(). (#6657, #5317) [@EggsyCRO, @jdpatdiscord] +- Misc: Made multiple calls to Render() during the same frame early out faster. - Debug Tools: Metrics: Fixed "Drawlists" section and per-viewport equivalent appearing empty (regression in 1.89.8). - Demo: Demonstrate out-of-order rendering using ImDrawListSplitter. diff --git a/imgui.cpp b/imgui.cpp index 2739c847d..5b5e7ad8c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5077,15 +5077,15 @@ void ImGui::Render() if (g.FrameCountEnded != g.FrameCount) EndFrame(); - const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount); + if (g.FrameCountRendered == g.FrameCount) + return; g.FrameCountRendered = g.FrameCount; - g.IO.MetricsRenderWindows = 0; + g.IO.MetricsRenderWindows = 0; CallContextHooks(&g, ImGuiContextHookType_RenderPre); // Draw modal/window whitening backgrounds - if (first_render_of_frame) - RenderDimmedBackgrounds(); + RenderDimmedBackgrounds(); // Add background ImDrawList (for each active viewport) for (int n = 0; n != g.Viewports.Size; n++) @@ -5112,7 +5112,7 @@ void ImGui::Render() AddRootWindowToDrawData(windows_to_render_top_most[n]); // Draw software mouse cursor if requested by io.MouseDrawCursor flag - if (g.IO.MouseDrawCursor && first_render_of_frame && g.MouseCursor != ImGuiMouseCursor_None) + if (g.IO.MouseDrawCursor && g.MouseCursor != ImGuiMouseCursor_None) RenderMouseCursor(g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); // Setup ImDrawData structures for end-user From 983b95bc874edf8fa9528a6bbfa6bdb57893c8d3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Aug 2023 16:55:03 +0200 Subject: [PATCH 05/14] Demo: tweak explanation about static keyword. (#6718) --- imgui_demo.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7af4c5d57..a50d54d50 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10,9 +10,9 @@ // Read imgui.cpp for more details, documentation and comments. // Get the latest version at https://github.com/ocornut/imgui -// ------------------------------------------------- +//--------------------------------------------------- // PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT! -// ------------------------------------------------- +//--------------------------------------------------- // Message to the person tempted to delete this file when integrating Dear ImGui into their codebase: // Think again! It is the most useful reference code that you and other coders will want to refer to and call. // Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app! @@ -26,14 +26,23 @@ // Thank you, // -Your beloved friend, imgui_demo.cpp (which you won't delete) -// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: -// In this demo code, we frequently use 'static' variables inside functions. A static variable persists across calls, -// so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to -// gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller -// in size. It also happens to be a convenient way of storing simple UI related information as long as your function -// doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, -// but most of the real data you would be editing is likely going to be stored outside your functions. +//-------------------------------------------- +// ABOUT THE MEANING OF THE 'static' KEYWORD: +//-------------------------------------------- +// In this demo code, we frequently use 'static' variables inside functions. +// A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function. +// Think of "static int n = 0;" as "global int n = 0;" ! +// We do this IN THE DEMO because we want: +// - to gather code and data in the same place. +// - to make the demo source code faster to read, faster to change, smaller in size. +// - it is also a convenient way of storing simple UI related information as long as your function +// doesn't need to be reentrant or used in multiple threads. +// This might be a pattern you will want to use in your code, but most of the data you would be working +// with in a complex codebase is likely going to be stored outside your functions. +//----------------------------------------- +// ABOUT THE CODING STYLE OF OUR DEMO CODE +//----------------------------------------- // The Demo code in this file is designed to be easy to copy-and-paste into your application! // Because of this: // - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. From 1e17d59965eec58b481f60cfbdca77661ab0af72 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Aug 2023 12:48:46 +0200 Subject: [PATCH 06/14] Backends: SDL2,SDL3: added ImGui_ImplSDL2_InitForOther() / ImGui_ImplSDL3_InitForOther(). e.g. WebGPU users use a similarly named functions from GLFW backend. --- backends/imgui_impl_sdl2.cpp | 5 +++++ backends/imgui_impl_sdl2.h | 1 + backends/imgui_impl_sdl3.cpp | 5 +++++ backends/imgui_impl_sdl3.h | 1 + docs/CHANGELOG.txt | 3 +++ 5 files changed, 15 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 389a12010..1c0bb9634 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -478,6 +478,11 @@ bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere return ImGui_ImplSDL2_Init(window, renderer); } +bool ImGui_ImplSDL2_InitForOther(SDL_Window* window) +{ + return ImGui_ImplSDL2_Init(window, nullptr); +} + void ImGui_ImplSDL2_Shutdown() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index 4645efa92..e7aa5c22b 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -28,6 +28,7 @@ IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); +IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window); IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 3c0122e18..af4231926 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -413,6 +413,11 @@ bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere return ImGui_ImplSDL3_Init(window, renderer); } +bool ImGui_ImplSDL2_InitForOther(SDL_Window* window) +{ + return ImGui_ImplSDL2_Init(window, nullptr); +} + void ImGui_ImplSDL3_Shutdown() { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index fc1d6bcde..bb5caf0cb 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -30,6 +30,7 @@ IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); +IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window); IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5b71899ad..015db4b83 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,9 @@ Other changes: - Debug Tools: Metrics: Fixed "Drawlists" section and per-viewport equivalent appearing empty (regression in 1.89.8). - Demo: Demonstrate out-of-order rendering using ImDrawListSplitter. +- Backends: SDL2,SDL3: added ImGui_ImplSDL2_InitForOther()/ImGui_ImplSDL3_InitForOther() + for consistency (matching GLFW backend) and as most initialization paths don't actually + need to care about rendering backend. ----------------------------------------------------------------------- From c06c79624294530ef7e5f441f3f0768d31fb623a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Aug 2023 16:09:49 +0200 Subject: [PATCH 07/14] TreeNode: added note about ImGuiTreeNodeFlags_Bullet. --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 05a18a3a9..923b8f5fb 100644 --- a/imgui.h +++ b/imgui.h @@ -1050,7 +1050,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). - ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow + ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag! ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default. ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area). From a6857ede031b155521db2291f5c3cdbae263863c Mon Sep 17 00:00:00 2001 From: Rick Huang Date: Wed, 16 Aug 2023 15:18:02 +0000 Subject: [PATCH 08/14] IO: fix writing to incorrect union section for MouseSource in AddMousePosEvent and AddMouseButtonEvent. (#6727, #2702) Technically may have had no side-effects unless non-standard alignment used. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 015db4b83..8deebc49e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,9 @@ Other changes: of individual ImDrawList's buffer sizes when a dimming/modal background is rendered. (#6716) - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively large radius to AddCircle(). (#6657, #5317) [@EggsyCRO, @jdpatdiscord] +- IO: Fixed io.AddMousePosEvent() and io.AddMouseButtonEvent() writing MouseSource to + wrong union section. Was semantically incorrect and accidentally had no side-effects + with default compiler alignment settings. (#6727) [@RickHuang2001] - Misc: Made multiple calls to Render() during the same frame early out faster. - Debug Tools: Metrics: Fixed "Drawlists" section and per-viewport equivalent appearing empty (regression in 1.89.8). diff --git a/imgui.cpp b/imgui.cpp index 5b5e7ad8c..a2848650e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1531,7 +1531,7 @@ void ImGuiIO::AddMousePosEvent(float x, float y) e.EventId = g.InputEventsNextEventId++; e.MousePos.PosX = pos.x; e.MousePos.PosY = pos.y; - e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + e.MousePos.MouseSource = g.InputEventsNextMouseSource; g.InputEventsQueue.push_back(e); } @@ -1555,7 +1555,7 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) e.EventId = g.InputEventsNextEventId++; e.MouseButton.Button = mouse_button; e.MouseButton.Down = down; - e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; + e.MouseButton.MouseSource = g.InputEventsNextMouseSource; g.InputEventsQueue.push_back(e); } @@ -8852,8 +8852,8 @@ static const char* GetMouseSourceName(ImGuiMouseSource source) static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) { ImGuiContext& g = *GImGui; - if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } - if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseWheel.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MousePos.MouseSource)); return; } + if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseButton.MouseSource)); return; } if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[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("[io] %s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } From a1a7a1bc037b23477dd469c82f1d7590f4fb10cf Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Aug 2023 13:02:56 +0200 Subject: [PATCH 09/14] InputFloat, SliderFloat, DragFloat: always turn both '.' and ',' into the current decimal point character. (#6719, #2278) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8deebc49e..3f45d7749 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,8 @@ Other changes: through proper navigation logic: honor scrolling and selection. (#1079, #1131) - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when v_max=INT_MAX (#6675, #6679) [@jbarthelmes] +- InputFloat, SliderFloat, DragFloat: always turn both '.' and ',' into the current decimal + point character when using Decimal/Scientific character filter. (#6719, #2278) [@adamsepp] - ImDrawData: Fixed an issue where TotalVtxCount/TotalIdxCount does not match the sum of individual ImDrawList's buffer sizes when a dimming/modal background is rendered. (#6716) - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e5b9c0610..ddf652152 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3948,6 +3948,9 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. ImGuiContext& g = *GImGui; const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; + if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific)) + if (c == '.' || c == ',') + c = c_decimal_point; // 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 From ba1fa904a96ebbc8923d5d2b00a1adcba918e21b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Aug 2023 13:11:30 +0200 Subject: [PATCH 10/14] IO: Exposed io.PlatformLocaleDecimalPoint to configure decimal point ('.' or ','). (#6719, #2278) Amend 13f718337 --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 1 + imgui.h | 3 +++ imgui_internal.h | 2 -- imgui_widgets.cpp | 18 +++++++++--------- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3f45d7749..2fe771fd3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,9 @@ Other changes: of individual ImDrawList's buffer sizes when a dimming/modal background is rendered. (#6716) - ImDrawList: Fixed OOB access in _CalcCircleAutoSegmentCount when passing excessively large radius to AddCircle(). (#6657, #5317) [@EggsyCRO, @jdpatdiscord] +- IO: Exposed io.PlatformLocaleDecimalPoint to configure decimal point ('.' or ',') for + languages needing it. Should ideally be set to the value of '*localeconv()->decimal_point' + but our backends don't do it yet. (#6719, #2278) - IO: Fixed io.AddMousePosEvent() and io.AddMouseButtonEvent() writing MouseSource to wrong union section. Was semantically incorrect and accidentally had no side-effects with default compiler alignment settings. (#6727) [@RickHuang2001] diff --git a/imgui.cpp b/imgui.cpp index a2848650e..acb58a428 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1286,6 +1286,7 @@ ImGuiIO::ImGuiIO() // Note: Initialize() will setup default clipboard/ime handlers. BackendPlatformName = BackendRendererName = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + PlatformLocaleDecimalPoint = '.'; // Input (NB: we already have memset zero the entire structure!) MousePos = ImVec2(-FLT_MAX, -FLT_MAX); diff --git a/imgui.h b/imgui.h index 923b8f5fb..c3e6a2458 100644 --- a/imgui.h +++ b/imgui.h @@ -2044,6 +2044,9 @@ struct ImGuiIO void* _UnusedPadding; // Unused field to keep data structure the same size. #endif + // Optional: Platform locale + ImWchar PlatformLocaleDecimalPoint; // '.' // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point + //------------------------------------------------------------------ // Input - Call before calling NewFrame() //------------------------------------------------------------------ diff --git a/imgui_internal.h b/imgui_internal.h index 6ac8ffc76..eba9bf948 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2021,7 +2021,6 @@ struct ImGuiContext // Platform support ImGuiPlatformImeData PlatformImeData; // Data updated by current frame ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data (when changing we will call io.SetPlatformImeDataFn - char PlatformLocaleDecimalPoint; // '.' or *localeconv()->decimal_point // Settings bool SettingsLoaded; @@ -2212,7 +2211,6 @@ struct ImGuiContext PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission - PlatformLocaleDecimalPoint = '.'; SettingsLoaded = false; SettingsDirtyTimer = 0.0f; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ddf652152..c59b727c5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -120,7 +120,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); //------------------------------------------------------------------------- // For InputTextEx() -static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); +static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); @@ -3905,7 +3905,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons } // Return false to discard a character. -static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source) +static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source) { IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard); unsigned int c = *p_char; @@ -3944,10 +3944,10 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f // The standard mandate that programs starts in the "C" locale where the decimal point is '.'. // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. // Change the default decimal_point with: - // ImGui::GetCurrentContext()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; + // ImGui::GetIO()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. - ImGuiContext& g = *GImGui; - const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; + ImGuiContext& g = *ctx; + const unsigned c_decimal_point = (unsigned int)g.IO.PlatformLocaleDecimalPoint; if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific)) if (c == '.' || c == ',') c = c_decimal_point; @@ -4386,7 +4386,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly) { unsigned int c = '\t'; // Insert TAB - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } @@ -4402,7 +4402,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ unsigned int c = (unsigned int)io.InputQueueCharacters[n]; if (c == '\t') // Skip Tab, see above. continue; - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } @@ -4485,7 +4485,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else if (!is_readonly) { unsigned int c = '\n'; // Insert new line - if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) + if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) state->OnKeyPressed((int)c); } } @@ -4552,7 +4552,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { unsigned int c; s += ImTextCharFromUtf8(&c, s, NULL); - if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) + if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) continue; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; } From 162f8e01aa99d48032fdc85fc583dc0bb7aea40c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Aug 2023 13:12:50 +0200 Subject: [PATCH 11/14] Backends: SDL3: fixed typo in 1e17d59 (#6735) --- backends/imgui_impl_sdl3.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index af4231926..c831ca541 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -413,9 +413,9 @@ bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere return ImGui_ImplSDL3_Init(window, renderer); } -bool ImGui_ImplSDL2_InitForOther(SDL_Window* window) +bool ImGui_ImplSDL3_InitForOther(SDL_Window* window) { - return ImGui_ImplSDL2_Init(window, nullptr); + return ImGui_ImplSDL3_Init(window, nullptr); } void ImGui_ImplSDL3_Shutdown() From 040e818d7215b648e216c25fa51c6093e273f651 Mon Sep 17 00:00:00 2001 From: Diego Mateos Date: Wed, 23 Aug 2023 10:11:42 +0200 Subject: [PATCH 12/14] Fix typo in SameLine comment (#6745) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index acb58a428..5993656f5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9547,7 +9547,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // Gets back to previous line and continue with horizontal layout // offset_from_start_x == 0 : follow right after previous item // offset_from_start_x != 0 : align to specified x position (relative to window/group left) -// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing_w < 0 : use default spacing if offset_from_start_x == 0, no spacing if offset_from_start_x != 0 // spacing_w >= 0 : enforce spacing amount void ImGui::SameLine(float offset_from_start_x, float spacing_w) { From b41811a68cb8f82beddcc8fb9b7f6234482149c2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Aug 2023 13:54:18 +0200 Subject: [PATCH 13/14] CollapseButton: handle clipping better + align circle like in docking branch. Amend 6c3697f6 --- imgui_widgets.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c59b727c5..397b2ba85 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -809,7 +809,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) bb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f)); // Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window. - // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). + // (this isn't the common behavior of buttons, but it doesn't affect the user because navigation tends to keep items visible in scrolling layer). bool is_clipped = !ItemAdd(bb_interact, id); bool hovered, held; @@ -839,15 +839,17 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) ImGuiWindow* window = g.CurrentWindow; ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); - ItemAdd(bb, id); + bool is_clipped = !ItemAdd(bb, id); bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); + if (is_clipped) + return pressed; // Render ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 text_col = GetColorU32(ImGuiCol_Text); if (hovered || held) - window->DrawList->AddCircleFilled(bb.GetCenter()/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col); + window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, bg_col); RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); // Switch to moving the window after mouse is moved beyond the initial drag threshold From 4a8142449252c03e52116689f74a315f7b0100a3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Aug 2023 14:02:31 +0200 Subject: [PATCH 14/14] CloseButton, CollapseButton: don't include FramePadding into size. Use ItemInnerSpacing.x between title bar buttons. (#6749) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 12 ++++++------ imgui_widgets.cpp | 14 ++++++-------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2fe771fd3..f47e49873 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,9 @@ Other changes: through proper navigation logic: honor scrolling and selection. (#1079, #1131) - Sliders: Fixed an integer overflow and div-by-zero in SliderInt() when v_max=INT_MAX (#6675, #6679) [@jbarthelmes] +- Windows: Layout of Close/Collapse buttons uses style.ItemInnerSpacing.x between items, + stopped incorrectly using FramePadding in a way where hit-boxes could overlap when + setting large values. (#6749) - InputFloat, SliderFloat, DragFloat: always turn both '.' and ',' into the current decimal point character when using Decimal/Scientific character filter. (#6719, #2278) [@adamsepp] - ImDrawData: Fixed an issue where TotalVtxCount/TotalIdxCount does not match the sum diff --git a/imgui.cpp b/imgui.cpp index 5993656f5..e18b571ba 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6095,18 +6095,18 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl ImVec2 collapse_button_pos; if (has_close_button) { - pad_r += button_sz; - close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y); + pad_r += button_sz + style.ItemInnerSpacing.x; } if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right) { - pad_r += button_sz; - collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); + collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y); + pad_r += button_sz + style.ItemInnerSpacing.x; } if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left) { - collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y); - pad_l += button_sz; + collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y + style.FramePadding.y); + pad_l += button_sz + style.ItemInnerSpacing.x; } // Collapse button (submitting first so it gets priority when choosing a navigation init fallback) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 397b2ba85..200bb6d70 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -802,7 +802,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) // Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825) // This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible? - const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize)); ImRect bb_interact = bb; const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea(); if (area_to_visible_ratio < 1.5f) @@ -838,7 +838,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); + ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize)); bool is_clipped = !ItemAdd(bb, id); bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); @@ -850,7 +850,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) ImU32 text_col = GetColorU32(ImGuiCol_Text); if (hovered || held) window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, bg_col); - RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); + RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); // Switch to moving the window after mouse is moved beyond the initial drag threshold if (IsItemActive() && IsMouseDragging(0)) @@ -6421,8 +6421,8 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl ImGuiContext& g = *GImGui; ImGuiLastItemData last_item_backup = g.LastItemData; float button_size = g.FontSize; - float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); - float button_y = g.LastItemData.Rect.Min.y; + float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x - button_size); + float button_y = g.LastItemData.Rect.Min.y + g.Style.FramePadding.y; ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); if (CloseButton(close_button_id, ImVec2(button_x, button_y))) *p_visible = false; @@ -8596,7 +8596,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, } const float button_sz = g.FontSize; - const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x * 2.0f - button_sz), bb.Min.y); + const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x - button_sz), bb.Min.y + frame_padding.y); // Close Button & Unsaved Marker // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() @@ -8614,10 +8614,8 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, if (close_button_visible) { ImGuiLastItemData last_item_backup = g.LastItemData; - PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding); if (CloseButton(close_button_id, button_pos)) close_button_pressed = true; - PopStyleVar(); g.LastItemData = last_item_backup; // Close with middle mouse button