Skip to content

Commit

Permalink
Reworked modal/ctrl+tab dimming system to be entirely processed at en…
Browse files Browse the repository at this point in the history
…d of the frame (backported 1dc3af3 from docking)
  • Loading branch information
ocornut committed Dec 3, 2021
1 parent da3a36e commit 23ef6c1
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 39 deletions.
105 changes: 67 additions & 38 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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++)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit 23ef6c1

Please sign in to comment.