From 1c7be88a1ab9c975a956f971367b91c51745c19d Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 30 Nov 2018 14:13:51 +0100 Subject: [PATCH 1/2] Viewport: Fixed a bug where tooltips on their first frame didn't find a monitor leading to the "recovery" code to revert it to the main viewport for a frame. (#1542) --- docs/TODO.txt | 2 +- imgui.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index ffc0dbe0..edc053a9 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -287,7 +287,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - viewport: with platform decoration enabled, platform may force constraint (e.g. minimum size) - viewport: use getfocus/setfocus api to synchronize imgui<>platform focus better (e.g imgui-side ctrl-tab can focus os window, OS initial setup and alt-tab can focus imgui window etc.) - viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for. - - viewport: implicit Debug window can hog a zombie viewport (harmless, noisy?) + - viewport: implicit Debug window can hog a zombie viewport (harmless, noisy?) > could at least clear out the reference on a per session basis? - viewport: need to clarify how to use GetMousePos() from a user point of view. - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport. - platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set diff --git a/imgui.cpp b/imgui.cpp index 28e34cec..0395eb8a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7699,9 +7699,13 @@ static int ImGui::FindPlatformMonitorForPos(const ImVec2& pos) static int ImGui::FindPlatformMonitorForRect(const ImRect& rect) { ImGuiContext& g = *GImGui; - float surface_threshold = rect.GetWidth() * rect.GetHeight() * 0.5f; + + // Use a minimum threshold of 1.0f so a zero-sized rect will still find its monitor given its position. + // This is necessary for tooltips which always resize down to zero at first. + const float surface_threshold = ImMax(rect.GetWidth() * rect.GetHeight() * 0.5f, 1.0f); int best_monitor_n = -1; float best_monitor_surface = 0.001f; + for (int monitor_n = 0; monitor_n < g.PlatformIO.Monitors.Size && best_monitor_surface < surface_threshold; monitor_n++) { const ImGuiPlatformMonitor& monitor = g.PlatformIO.Monitors[monitor_n]; From f663277591388f766b3c783fe1c17c690d14f16e Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 30 Nov 2018 14:33:43 +0100 Subject: [PATCH 2/2] Merge misc/shallow changes from Docking branch to minimize drift: moved some blocks, added comments. --- imgui.cpp | 81 ++++++++++++++++++++++++++++++------------------ imgui_internal.h | 51 +++++++++++++++++------------- 2 files changed, 80 insertions(+), 52 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0395eb8a..76a3135f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3801,7 +3801,8 @@ void ImGui::EndFrame() AddWindowToSortBuffer(&g.WindowsSortBuffer, window); } - IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong + // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong. + IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); g.Windows.swap(g.WindowsSortBuffer); g.IO.MetricsActiveWindows = g.WindowsActiveCount; @@ -4824,17 +4825,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) const int current_frame = g.FrameCount; const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame); - if (first_begin_of_the_frame) - { - window->FlagsPreviousFrame = window->Flags; - window->Flags = (ImGuiWindowFlags)flags; - window->BeginOrderWithinParent = 0; - window->BeginOrderWithinContext = g.WindowsActiveCount++; - } - else - { - flags = window->Flags; - } // Update the Appearing flag bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on @@ -4849,6 +4839,20 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (window->Appearing) SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true); + // Update Flags, LastFrameActive, BeginOrderXXX fields + if (first_begin_of_the_frame) + { + window->FlagsPreviousFrame = window->Flags; + window->Flags = (ImGuiWindowFlags)flags; + window->LastFrameActive = current_frame; + window->BeginOrderWithinParent = 0; + window->BeginOrderWithinContext = g.WindowsActiveCount++; + } + else + { + flags = window->Flags; + } + // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back(); ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; @@ -4923,7 +4927,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->Active = true; window->HasCloseButton = (p_open != NULL); window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX); - window->LastFrameActive = current_frame; window->IDStack.resize(1); // Update stored window name when it changes (which can only happen with the "###" operator). @@ -5223,21 +5226,27 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (!(flags & ImGuiWindowFlags_NoBackground)) { ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags)); - if (g.NextWindowData.BgAlphaCond != 0) - bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(g.NextWindowData.BgAlphaVal) << IM_COL32_A_SHIFT); if (window->ViewportOwned) { - //window->Viewport->Alpha = ((bg_col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) / 255.0f; + // No alpha bg_col = (bg_col | IM_COL32_A_MASK); } + else + { + // Adjust alpha + if (g.NextWindowData.BgAlphaCond != 0) + bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(g.NextWindowData.BgAlphaVal) << IM_COL32_A_SHIFT); + } window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot); } g.NextWindowData.BgAlphaCond = 0; // Title bar - ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); if (!(flags & ImGuiWindowFlags_NoTitleBar)) + { + ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg); window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top); + } // Menu bar if (flags & ImGuiWindowFlags_MenuBar) @@ -5391,7 +5400,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.NavLayerCurrentMask >>= 1; window->DC.ItemFlags = item_flags_backup; - // Title text (FIXME: refactor text alignment facilities along with RenderText helpers, this is too much code for what it does.) + // Title bar text (with: horizontal alignment, avoiding collapse/close button) + // FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code.. ImVec2 text_size = CalcTextSize(name, NULL, true); ImRect text_r = title_bar_rect; float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x); @@ -5461,7 +5471,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Child window can be out of sight and have "negative" clip windows. // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar). IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0); - if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y) window->HiddenFramesRegular = 1; @@ -5476,7 +5485,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->HiddenFramesRegular = 1; // Update the Hidden flag - window->Hidden = (window->HiddenFramesRegular > 0) || (window->HiddenFramesForResize); + window->Hidden = (window->HiddenFramesRegular > 0) || (window->HiddenFramesForResize > 0); // Return false if we don't intend to display anything to allow user to perform an early out optimization window->SkipItems = (window->Collapsed || !window->Active || window->Hidden) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesForResize <= 0; @@ -5580,7 +5589,7 @@ void ImGui::FocusWindow(ImGuiWindow* window) g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId g.NavIdIsAlive = false; g.NavLayer = 0; - //printf("[%05d] FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL); + //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL); } // Passing NULL allow to disable keyboard focus @@ -6912,7 +6921,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values return false; } - return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); + flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings; + return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); } bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) @@ -6931,7 +6941,8 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla if (g.NextWindowData.PosCond == 0) SetNextWindowPos(window->Viewport->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - bool is_open = Begin(name, p_open, flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings); + flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings; + const bool is_open = Begin(name, p_open, flags); if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) { EndPopup(); @@ -7111,7 +7122,7 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) } //----------------------------------------------------------------------------- -// [SECTION] VIEWPORTS / PLATFORM WINDOWS +// [SECTION] VIEWPORTS, PLATFORM WINDOWS //----------------------------------------------------------------------------- ImGuiViewport* ImGui::GetMainViewport() @@ -7178,7 +7189,7 @@ static bool ImGui::GetWindowAlwaysWantOwnViewport(ImGuiWindow* window) // Tooltips and menus are not automatically forced into their own viewport when the NoMerge flag is set, however the multiplication of viewports makes them more likely to protude and create their own. ImGuiContext& g = *GImGui; if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoMerge) && (g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) - //if (window->DockStatus == ImGuiDockStatus_Floating) + //if (!window->DockIsActive) if ((window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip)) == 0) return true; return false; @@ -7258,6 +7269,7 @@ static void ImGui::UpdateViewports() // Update main viewport with current platform position and size ImGuiViewportP* main_viewport = g.Viewports[0]; IM_ASSERT(main_viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID); + IM_ASSERT(main_viewport->Window == NULL); ImVec2 main_viewport_platform_pos = ImVec2(0.0f, 0.0f); if ((g.ConfigFlagsForFrame & ImGuiConfigFlags_ViewportsEnable)) main_viewport_platform_pos = g.PlatformIO.Platform_GetWindowPos(main_viewport); @@ -7285,6 +7297,7 @@ static void ImGui::UpdateViewports() g.Viewports.erase(g.Viewports.Data + n); // Destroy + //IMGUI_DEBUG_LOG("Delete Viewport %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a"); DestroyPlatformWindow(viewport); // In most circumstances the platform window will already be destroyed here. IM_ASSERT(g.PlatformIO.Viewports.contains(viewport) == false); IM_DELETE(viewport); @@ -7298,7 +7311,7 @@ static void ImGui::UpdateViewports() if (g.PlatformIO.Platform_GetWindowMinimized && platform_funcs_available) viewport->PlatformWindowMinimized = g.PlatformIO.Platform_GetWindowMinimized(viewport); - // Apply Position and Size (from Platform Window to ImGui) if requested. + // Update Position and Size (from Platform Window to ImGui) if requested. // We do it early in the frame instead of waiting for UpdatePlatformWindows() to avoid a frame of lag when moving/resizing using OS facilities. if (!viewport->PlatformWindowMinimized && platform_funcs_available) { @@ -7312,6 +7325,9 @@ static void ImGui::UpdateViewports() viewport->PlatformMonitor = FindPlatformMonitorForRect(viewport->GetRect()); } + // Reset alpha every frame. Users of transparency will need to request a lower alpha back. + viewport->Alpha = 1.0f; + // Translate imgui windows when a Host Viewport has been moved // (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!) ImVec2 viewport_delta = viewport->Pos - viewport->LastPos; @@ -7427,6 +7443,7 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const viewport->Size = size; viewport->PlatformMonitor = FindPlatformMonitorForRect(viewport->GetRect()); g.Viewports.push_back(viewport); + //IMGUI_DEBUG_LOG("Add Viewport %08X (%s)\n", id, window->Name); // We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport. // We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame @@ -7605,6 +7622,7 @@ void ImGui::UpdatePlatformWindows() bool is_new_window = (viewport->PlatformWindowCreated == false); if (is_new_window) { + //IMGUI_DEBUG_LOG("Create Platform Window %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a"); g.PlatformIO.Platform_CreateWindow(viewport); if (g.PlatformIO.Renderer_CreateWindow != NULL) g.PlatformIO.Renderer_CreateWindow(viewport); @@ -10185,12 +10203,13 @@ void ImGui::ShowMetricsWindow(bool* p_open) ImGuiWindow* window = g.Windows[n]; if ((window->Flags & ImGuiWindowFlags_ChildWindow) || !window->WasActive) continue; - char buf[32]; - ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext); - float font_size = ImGui::GetFontSize() * 2; + + char buf[64] = ""; + char* p = buf; + p += ImFormatString(p, buf + IM_ARRAYSIZE(buf) - p, "Order: %d\n", window->BeginOrderWithinContext); ImDrawList* overlay_draw_list = GetOverlayDrawList(window->Viewport); - overlay_draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255)); - overlay_draw_list->AddText(NULL, font_size, window->Pos, IM_COL32(255, 255, 255, 255), buf); + overlay_draw_list->AddRectFilled(window->Pos - ImVec2(1, 1), window->Pos + CalcTextSize(buf) + ImVec2(1, 1), IM_COL32(200, 100, 100, 255)); + overlay_draw_list->AddText(NULL, 0.0f, window->Pos, IM_COL32(255, 255, 255, 255), buf); } } ImGui::End(); diff --git a/imgui_internal.h b/imgui_internal.h index aff91eb1..1dc43c94 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -99,6 +99,8 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe #else #define IM_NEWLINE "\n" #endif + +//#define IMGUI_DEBUG_LOG(FMT,...) printf("[%05d] " FMT, GImGui->FrameCount, __VA_ARGS__) #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1] #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255 @@ -241,14 +243,6 @@ struct IMGUI_API ImPool // Types //----------------------------------------------------------------------------- -// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D and maintenance of some patches) -struct ImVec1 -{ - float x; - ImVec1() { x = 0.0f; } - ImVec1(float _x) { x = _x; } -}; - enum ImGuiButtonFlags_ { ImGuiButtonFlags_None = 0, @@ -307,6 +301,19 @@ enum ImGuiSeparatorFlags_ ImGuiSeparatorFlags_Vertical = 1 << 1 }; +// Transient per-window ItemFlags, reset at the beginning of the frame. For child windows: inherited from parent on first Begin(). +// This is going to be exposed in imgui.h when stabilized enough. +enum ImGuiItemFlags_ +{ + ImGuiItemFlags_NoTabStop = 1 << 0, // false + ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. + ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211 + ImGuiItemFlags_NoNav = 1 << 3, // false + ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false + ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window + ImGuiItemFlags_Default_ = 0 +}; + // Storage for LastItem data enum ImGuiItemStatusFlags_ { @@ -398,6 +405,14 @@ enum ImGuiPopupPositionPolicy ImGuiPopupPositionPolicy_ComboBox }; +// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D and maintenance of some patches) +struct ImVec1 +{ + float x; + ImVec1() { x = 0.0f; } + ImVec1(float _x) { x = _x; } +}; + // 2D axis aligned bounding-box // NB: we can't rely on ImVec2 math operators being available here struct IMGUI_API ImRect @@ -632,7 +647,7 @@ struct ImGuiViewportP : public ImGuiViewport int PlatformMonitor; bool PlatformWindowCreated; bool PlatformWindowMinimized; - ImGuiWindow* Window; + ImGuiWindow* Window; // Set when the viewport is owned by a window ImDrawList* OverlayDrawList; // For convenience, a draw list we can render to that's always rendered last (we use it to draw software mouse cursor when io.MouseDrawCursor is set) ImDrawData DrawDataP; ImDrawDataBuilder DrawDataBuilder; @@ -702,7 +717,10 @@ struct ImGuiNextWindowData } }; +//----------------------------------------------------------------------------- // Main imgui context +//----------------------------------------------------------------------------- + struct ImGuiContext { bool Initialized; @@ -984,18 +1002,9 @@ struct ImGuiContext } }; -// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). -// This is going to be exposed in imgui.h when stabilized enough. -enum ImGuiItemFlags_ -{ - ImGuiItemFlags_NoTabStop = 1 << 0, // false - ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings. - ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211 - ImGuiItemFlags_NoNav = 1 << 3, // false - ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false - ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window - ImGuiItemFlags_Default_ = 0 -}; +//----------------------------------------------------------------------------- +// ImGuiWindow +//----------------------------------------------------------------------------- // Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered.