From 5c388c39f44283304e85afe9838597bffcfd6019 Mon Sep 17 00:00:00 2001 From: Rokas Kupstys Date: Fri, 3 Dec 2021 12:03:05 +0200 Subject: [PATCH 1/4] Backends: SDL_Renderer: Added support for large meshes (64k+ vertices) with 16-bit indices, enable 'ImGuiBackendFlags_RendererHasVtxOffset' in this backend. (#3926) --- backends/imgui_impl_sdlrenderer.cpp | 14 ++++++++------ backends/imgui_impl_sdlrenderer.h | 3 +-- docs/CHANGELOG.txt | 2 ++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/backends/imgui_impl_sdlrenderer.cpp b/backends/imgui_impl_sdlrenderer.cpp index e86f473f4..1aab5b48a 100644 --- a/backends/imgui_impl_sdlrenderer.cpp +++ b/backends/imgui_impl_sdlrenderer.cpp @@ -10,14 +10,15 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // Missing features: -// [ ] 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. // Read online: https://github.com/ocornut/imgui/tree/master/docs // CHANGELOG +// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2021-10-06: Backup and restore modified ClipRect/Viewport. // 2021-09-21: Initial version. @@ -61,6 +62,7 @@ bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer) ImGui_ImplSDLRenderer_Data* bd = IM_NEW(ImGui_ImplSDLRenderer_Data)(); io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_sdlrenderer"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. bd->SDLRenderer = renderer; @@ -127,7 +129,7 @@ void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data) SDL_Rect ClipRect; }; BackupSDLRendererState old = {}; - old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer); + old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE; SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport); SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect); @@ -170,9 +172,9 @@ void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data) 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) }; SDL_RenderSetClipRect(bd->SDLRenderer, &r); - const float* xy = (const float*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, pos)); - const float* uv = (const float*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)); - const int* color = (const int*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)); + const float* xy = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, pos)); + const float* uv = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, uv)); + const int* color = (const int*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // Bind texture, Draw SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); @@ -180,7 +182,7 @@ void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data) xy, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert), uv, (int)sizeof(ImDrawVert), - cmd_list->VtxBuffer.Size, + cmd_list->VtxBuffer.Size - pcmd->VtxOffset, idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx)); } } diff --git a/backends/imgui_impl_sdlrenderer.h b/backends/imgui_impl_sdlrenderer.h index e8f4d10ba..51a1c45f9 100644 --- a/backends/imgui_impl_sdlrenderer.h +++ b/backends/imgui_impl_sdlrenderer.h @@ -10,8 +10,7 @@ // 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 (SDL_RenderGeometryRaw() is missing a vertex offset). +// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. #pragma once #include "imgui.h" // IMGUI_IMPL_API diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c54ebcaa0..81f3a67f5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -80,6 +80,8 @@ Other Changes: 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: SDL_Renderer: Added support for large meshes (64k+ vertices) with 16-bit indices, + enabling 'ImGuiBackendFlags_RendererHasVtxOffset' in the backend. (#3926) [@rokups] - 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 78c6435dbb65e84897f22cf8d4a6c5169c3775bc Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 3 Dec 2021 12:38:58 +0100 Subject: [PATCH 2/4] Inputs: (breaking wip) removed IsMouseTripleClicked() added recently (during 1.86 WIP), replaced with GetMouseClickedCount(). (#3229) --- docs/CHANGELOG.txt | 6 ++++-- imgui.cpp | 4 ++-- imgui.h | 8 ++++---- imgui_demo.cpp | 11 +++-------- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 81f3a67f5..c90d3ce65 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,7 +41,9 @@ Breaking Changes: Other Changes: -- Added IsMouseTripleClicked() function. Tracking multi-click count in IO structure. (#3229) [@kudaba] +- Added GetMouseClickedCount() function, returning the number of successive clicks. (#3229) [@kudaba] + (so IsMouseDoubleClicked(ImGuiMouseButton_Left) is same as GetMouseClickedCount(ImGuiMouseButton_Left) == 2, + but it allows testing for triple clicks and more). - Modals: fixed issue hovering popups inside a child inside a modal. (#4676, #4527) - Fixed IsWindowFocused()/IsWindowHovered() issues with childs inside popups. (#4676) - Nav: Ctrl+tabbing to cycle through windows is now enabled regardless of using the _NavEnableKeyboard @@ -63,7 +65,7 @@ Other Changes: - 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] -- Cliooer: added ForceDisplayRangeByIndices() to force a given item (or several) to be stepped out +- Clipper: added ForceDisplayRangeByIndices() to force a given item (or several) to be stepped out during a clipping operation. (#3841) [@@GamingMinds-DanielC] - Clipper: rework so gamepad/keyboard navigation doesn't create spikes in number of items requested by the clipper to display. (#3841) diff --git a/imgui.cpp b/imgui.cpp index 2c43500f9..f53bdafe1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4796,11 +4796,11 @@ bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) return g.IO.MouseClickedCount[button] == 2; } -bool ImGui::IsMouseTripleClicked(ImGuiMouseButton button) +int ImGui::GetMouseClickedCount(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - return g.IO.MouseClickedCount[button] == 3; + return g.IO.MouseClickedCount[button]; } // Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame. diff --git a/imgui.h b/imgui.h index 6cbe69442..1fcadcbb2 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 18512 +#define IMGUI_VERSION_NUM 18513 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE @@ -896,10 +896,10 @@ namespace ImGui // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') IMGUI_API bool IsMouseDown(ImGuiMouseButton button); // is mouse button held? - IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down) + IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) - IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? (note that a double-click will also report IsMouseClicked() == true) - IMGUI_API bool IsMouseTripleClicked(ImGuiMouseButton button); // did mouse button triple-clicked? (note that a triple-click will also report IsMouseClicked() == true) + IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true) + IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available IMGUI_API bool IsAnyMouseDown(); // is any mouse button held? diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d8a25b55f..97963ae1b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -5668,14 +5668,9 @@ static void ShowDemoWindowMisc() ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y); int count = IM_ARRAYSIZE(io.MouseDown); - ImGui::Text("Mouse down:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } - ImGui::Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } - ImGui::Text(" - clicked double:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } - ImGui::Text(" - clicked triple:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseTripleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } - ImGui::Text(" - clicked count:"); for (int i = 0; i < count; i++) if (io.MouseClickedCount[i]) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, io.MouseClickedCount[i]); } - //ImGui::Text(" - last count:"); for (int i = 0; i < count; i++) if (io.MouseClickedLastCount[i]) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, io.MouseClickedLastCount[i]); } - - ImGui::Text("Mouse released:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } + ImGui::Text("Mouse down:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } + ImGui::Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, ImGui::GetMouseClickedCount(i)); } + ImGui::Text("Mouse released:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); } ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused ImGui::TreePop(); From da3a36eefda4152488981f9953a91c2b69aa6e4a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 3 Dec 2021 19:11:58 +0100 Subject: [PATCH 3/4] Backport from docking branch: minor stuff. Fixed software mouse cursor being rendered multiple times if Render() is called more than once. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 29 +++++++++++++++++++---------- imgui.h | 2 +- imgui_internal.h | 3 ++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c90d3ce65..64ff179eb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,7 @@ Other Changes: - 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: Fixed software mouse cursor being rendered multiple times if Render() is called more than once. - 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 diff --git a/imgui.cpp b/imgui.cpp index f53bdafe1..83800dd5b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3386,6 +3386,17 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) return false; } +// This is also inlined in ItemAdd() +// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect! +void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) +{ + ImGuiContext& g = *GImGui; + g.LastItemData.ID = item_id; + g.LastItemData.InFlags = in_flags; + g.LastItemData.StatusFlags = item_flags; + g.LastItemData.Rect = item_rect; +} + float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) { if (wrap_pos_x < 0.0f) @@ -4533,6 +4544,7 @@ void ImGui::Render() if (g.FrameCountEnded != g.FrameCount) EndFrame(); + const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount); g.FrameCountRendered = g.FrameCount; g.IO.MetricsRenderWindows = 0; @@ -4570,7 +4582,7 @@ void ImGui::Render() viewport->DrawDataBuilder.FlattenIntoSingleLayer(); // Draw software mouse cursor if requested by io.MouseDrawCursor flag - if (g.IO.MouseDrawCursor) + if (g.IO.MouseDrawCursor && first_render_of_frame) RenderMouseCursor(GetForegroundDrawList(viewport), g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48)); // Add foreground ImDrawList (for each active viewport) @@ -5351,11 +5363,11 @@ ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window) return size_final; } -static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags) +static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window) { - if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) + if (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) return ImGuiCol_PopupBg; - if (flags & ImGuiWindowFlags_ChildWindow) + if (window->Flags & ImGuiWindowFlags_ChildWindow) return ImGuiCol_ChildBg; return ImGuiCol_WindowBg; } @@ -5633,7 +5645,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar // Window background if (!(flags & ImGuiWindowFlags_NoBackground)) { - ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); + ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window)); bool override_alpha = false; float alpha = 1.0f; if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) @@ -6386,10 +6398,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // This is useful to allow creating context menus on title bar only, etc. - g.LastItemData.ID = window->MoveId; - g.LastItemData.InFlags = g.CurrentItemFlags; - g.LastItemData.StatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; - g.LastItemData.Rect = title_bar_rect; + SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect); #ifdef IMGUI_ENABLE_TEST_ENGINE if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) @@ -6837,8 +6846,8 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) return false; if (flags & ImGuiFocusedFlags_AnyWindow) return true; - IM_ASSERT(cur_window); // Not inside a Begin()/End() + IM_ASSERT(cur_window); // Not inside a Begin()/End() const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; if (flags & ImGuiHoveredFlags_RootWindow) cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); diff --git a/imgui.h b/imgui.h index 1fcadcbb2..848d6b57f 100644 --- a/imgui.h +++ b/imgui.h @@ -954,7 +954,7 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoMove = 1 << 2, // Disable user moving the window ImGuiWindowFlags_NoScrollbar = 1 << 3, // Disable scrollbars (window can still scroll with mouse or programmatically) ImGuiWindowFlags_NoScrollWithMouse = 1 << 4, // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set. - ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it + ImGuiWindowFlags_NoCollapse = 1 << 5, // Disable user collapsing window by double-clicking on it. Also referred to as Window Menu Button (e.g. within a docking node). ImGuiWindowFlags_AlwaysAutoResize = 1 << 6, // Resize every window to its content every frame ImGuiWindowFlags_NoBackground = 1 << 7, // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f). ImGuiWindowFlags_NoSavedSettings = 1 << 8, // Never load/save settings in .ini file diff --git a/imgui_internal.h b/imgui_internal.h index f624e707e..c1111c873 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2100,7 +2100,7 @@ struct ImGuiTabItem }; // Storage for a tab bar (sizeof() 152 bytes) -struct ImGuiTabBar +struct IMGUI_API ImGuiTabBar { ImVector Tabs; ImGuiTabBarFlags Flags; @@ -2499,6 +2499,7 @@ namespace ImGui IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); + IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API void PushMultiItemsWidths(int components, float width_full); From 23ef6c149ea14d8a5981cfec02994dcd7d21d09e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 3 Dec 2021 19:21:39 +0100 Subject: [PATCH 4/4] Reworked modal/ctrl+tab dimming system to be entirely processed at end of the frame (backported 1dc3af3 from docking) --- imgui.cpp | 105 ++++++++++++++++++++++++++++++----------------- imgui.h | 2 +- imgui_internal.h | 1 + 3 files changed, 69 insertions(+), 39 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 83800dd5b..ddae0b8ff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -946,7 +946,8 @@ 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(); +static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); +static void RenderDimmedBackgrounds(); // Viewports static void UpdateViewportsNewFrame(); @@ -4442,9 +4443,58 @@ void ImGui::PopClipRect() window->ClipRect = window->DrawList->_ClipRectStack.back(); } -static void ImGui::EndFrameDrawDimmedBackgrounds() +static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col) { - // (This is currently empty, left here to facilitate sync/merge with docking branch) + if ((col & IM_COL32_A_MASK) == 0) + return; + + ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport(); + ImRect viewport_rect = viewport->GetMainRect(); + + // Draw behind window by moving the draw command at the FRONT of the draw list + { + ImDrawList* draw_list = window->RootWindow->DrawList; + draw_list->AddDrawCmd(); + draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged + draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); + ImDrawCmd cmd = draw_list->CmdBuffer.back(); + IM_ASSERT(cmd.ElemCount == 6); + draw_list->CmdBuffer.pop_back(); + draw_list->CmdBuffer.push_front(cmd); + } +} + +static void ImGui::RenderDimmedBackgrounds() +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal(); + const bool dim_bg_for_modal = (modal_window != NULL); + const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.NavWindowingTargetAnim->Active); + if (!dim_bg_for_modal && !dim_bg_for_window_list) + return; + + if (dim_bg_for_modal) + { + // Draw dimming behind modal + RenderDimmedBackgroundBehindWindow(modal_window, GetColorU32(ImGuiCol_ModalWindowDimBg, g.DimBgRatio)); + } + else if (dim_bg_for_window_list) + { + // Draw dimming behind CTRL+Tab target window + RenderDimmedBackgroundBehindWindow(g.NavWindowingTargetAnim, GetColorU32(ImGuiCol_NavWindowingDimBg, g.DimBgRatio)); + + // Draw border around CTRL+Tab target window + ImGuiWindow* window = g.NavWindowingTargetAnim; + ImGuiViewport* viewport = GetMainViewport(); + float distance = g.FontSize; + ImRect bb = window->Rect(); + bb.Expand(distance); + if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y) + bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward + window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f); + window->DrawList->PopClipRect(); + } } // 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. @@ -4502,9 +4552,6 @@ 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); @@ -4574,6 +4621,10 @@ void ImGui::Render() if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window AddRootWindowToDrawData(windows_to_render_top_most[n]); + // Draw modal/window whitening backgrounds + if (first_render_of_frame) + RenderDimmedBackgrounds(); + // Setup ImDrawData structures for end-user g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0; for (int n = 0; n < g.Viewports.Size; n++) @@ -6248,24 +6299,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); PushClipRect(host_rect.Min, host_rect.Max, false); - // Draw modal window background (darkens what is behind them, all viewports) - const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0; - const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow); - if (dim_bg_for_modal || dim_bg_for_window_list) - { - const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio); - window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); - } - - // Draw navigation selection/windowing rectangle background - if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim) - { - ImRect bb = window->Rect(); - bb.Expand(g.FontSize); - if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway - window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); - } - // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71) // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order. // FIXME: User code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected (github #4493) @@ -6293,20 +6326,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DrawList = &window->DrawListInst; } - // Draw navigation selection/windowing rectangle border - if (g.NavWindowingTargetAnim == window) - { - float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding); - ImRect bb = window->Rect(); - bb.Expand(g.FontSize); - if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward - { - bb.Expand(-g.FontSize - 1.0f); - rounding = window->WindowRounding; - } - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, 0, 3.0f); - } - // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING) // Work rectangle. @@ -8363,6 +8382,16 @@ ImGuiWindow* ImGui::GetTopMostPopupModal() return NULL; } +ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() +{ + ImGuiContext& g = *GImGui; + for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--) + if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window) + if ((popup->Flags & ImGuiWindowFlags_Modal) && IsWindowActiveAndVisible(popup)) + return popup; + return NULL; +} + void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 848d6b57f..ab8157998 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 18513 +#define IMGUI_VERSION_NUM 18514 #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_internal.h b/imgui_internal.h index c1111c873..f0711d672 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2539,6 +2539,7 @@ namespace ImGui IMGUI_API void BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags extra_window_flags); IMGUI_API ImRect GetPopupAllowedExtentRect(ImGuiWindow* window); IMGUI_API ImGuiWindow* GetTopMostPopupModal(); + IMGUI_API ImGuiWindow* GetTopMostAndVisiblePopupModal(); IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window); IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);