ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
59.71k stars 10.16k forks source link

Combo popup flickering near screen edge #6207

Open Vin789 opened 1 year ago

Vin789 commented 1 year ago

Version/Branch of Dear ImGui:

Version: 1.89.4 WIP (18931) Branch: https://github.com/ocornut/imgui/tree/docking

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_opengl3.cpp + imgui.impl_sdl2.cpp Operating System: Windows 10 SDL Version: SDL2-2.24.0

My Issue/Question:

I have an issue with combo popup that are near other window edge. It seems that the position of the combo list (a popup) is screen dependent. You can see a simple exemple with the code of the demo (using the combo inside the modal popup menu). The bug is at ~8s. Maybe coming from BeginComboPopup that doesn't seems to apply viewport restriction on the popup ?

Screenshots/Video

https://user-images.githubusercontent.com/13332569/221927949-2379571f-aa8c-4cf8-98a2-3d9f966f49ac.mp4

Standalone, minimal, complete and verifiable example: (see https://github.com/ocornut/imgui/issues/2261)

This was reproduced with the base code. No changes.
Vin789 commented 1 year ago

Side note: on my personal application the combo popup open on the other screen (no flickering but still not correct). image

Vin789 commented 1 year ago

Hi !

I took some little time to debug this today (I guess nobody is going to do it for me ahah).

Quick version: I start from BeginComboPopup discovering that r_outer from GetPopupAllowedExtentRect was not correct. GetPopupAllowedExtentRect was not correct because ViewportAllowPlatformMonitorExtend was not correct. ViewportAllowPlatformMonitorExtend was not correct because PlatformMonitor was not correct (setted inside WindowSelectViewport).

PlatformMonitor is set at the wrong monitor during one frame inside UpdateViewportPlatformMonitor because viewport->GetMainRect() seems incorrect. Viewport positions are coming from windows positions that are changed to the correct position side in the next frame but at this point we already set PlatformMonitor with a wrong value during one frame.

At this point I didn't go further to check why because it's seems as wanted by ImGui (it probably required more investigation however).

Because during this fatal frame the window doesn't seems 100% ready (it's still Hidden) I did a modification here:

if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
        {
            // We need to take account of the possibility that mouse may become invalid.
            // Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds.
            ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.BeginPopupStack.back().OpenMousePos;
            bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow);
            bool mouse_valid = IsMousePosValid(&mouse_ref);
            if ((window->Appearing || window->Hidden || (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_ChildMenu))) && (!use_mouse_ref || mouse_valid))
                window->ViewportAllowPlatformMonitorExtend = FindPlatformMonitorForPos((use_mouse_ref && mouse_valid) ? mouse_ref : NavCalcPreferredRefPos());
            else
                window->ViewportAllowPlatformMonitorExtend = window->Viewport->PlatformMonitor;
        }

I add || window->Hidden after window->Appearing and it fix the issue. It doesn't seems to have side effect but it may not be the best way of fixing it. @ocornut you will probably better know what happens under the hood.

In the meantime I will go with this fix inside my Editor.

chad171 commented 1 year ago

We have a hamburger menu on the top right of our windows that triggers a popup menu, so we are running into this issue frequently. This fix works for us, but it would be nice to know if there are any side effects.

ocornut commented 6 months ago

Somebody has reported this to me privately, and I've been struggling to repro the issue until today. I seem to be able to get the bug when primary monitor is the right side, meaning left-side monitor while use negative coordinates.

ocornut commented 6 months ago

The reporting user have monitors in the other order. Regardless I have a repro currently, and the issue is due to ViewportAllowPlatformMonitorExtend taking a copy of viewport->PlatformMonitor early in Begin() before that value is settled. Because BeginCombo() indirectly relies on that value to set position it creates a back and forth:

But other manifestation of that bug includes situations where the popups appears for a single frame on one side and then stays on the other.

I add || window->Hidden after window->Appearing and it fix the issue. It doesn't seems to have side effect but it may not be the best way of fixing it. @ocornut you will probably better know what happens under the hood.

It doesn't seem to be the right logical fix, but it seems to bypass the issue because it stabilize the current monitor for two successive frames and once it's stabilized it tends to stay so.