fix #374: open dropdown popups get first claim on pointer routing
Campaign OP gate 2 root cause: UiElement.HitTest walks siblings front-to-back by z-order, so an OPEN UiMenu's extended button+popup hit-test union was never consulted when a LATER sibling's rect overlapped the popup area — on the Config tab every dropdown has rows below it, so Resolution-item clicks toggled the Full Screen / VSync rows underneath (the gate session's persisted fullscreen/vsync flips were exactly those stolen clicks). Latent since UiMenu existed; vendor/chat menus only worked by z-order luck. Fix: UiMenu's open/close now registers with UiRoot (SetActivePopup / ClearActivePopup); a registered popup gets FIRST claim on mouse-down, scroll, and hover routing; a press outside a live popup dismisses it and is SWALLOWED (the dismissing click must not act on what sat underneath); hidden/detached owners self-heal the registration on the next pointer event. UiMenu gains the IsOpen seam and a single SetOpen writer. Also in this commit, from the same investigation: - SilkRuntimeDisplayWindowTarget.Apply documents the fullscreen half honestly: IViewProperties.VideoMode is READ-ONLY, so a resolution pick while fullscreen cannot switch the display mode through Silk's abstract API — split out as #376 (native glfwSetWindowMonitor port) rather than half-shipping untested native interop at a gate tail. - Gate script §OP6 step 8 re-scoped: test resolution in WINDOWED mode. Regressed by tests/AcDream.App.Tests/UI/UiMenuPopupRoutingTests.cs — 4 tests driving the real UiRoot input path on a mounted overlapping tree, with an in-test overlap CONTROL click so the popup assertions cannot pass vacuously (the #372 lesson: only mount+drive-input tests catch this class; every fixture-conformance test stayed green through this bug). Full Release suite: 13,081 passed / 4 skipped / 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
07c0c2c7b9
commit
355c86a6f6
6 changed files with 388 additions and 10 deletions
|
|
@ -56,8 +56,9 @@ internal sealed class SilkRuntimeDisplayWindowTarget : IRuntimeDisplayWindowTarg
|
|||
public void Apply(DisplaySettings display)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(display);
|
||||
if (TryParseResolution(display.Resolution, out int width, out int height)
|
||||
&& (_window.Size.X != width || _window.Size.Y != height))
|
||||
bool haveResolution =
|
||||
TryParseResolution(display.Resolution, out int width, out int height);
|
||||
if (haveResolution && (_window.Size.X != width || _window.Size.Y != height))
|
||||
{
|
||||
_window.Size = new Vector2D<int>(width, height);
|
||||
}
|
||||
|
|
@ -65,6 +66,16 @@ internal sealed class SilkRuntimeDisplayWindowTarget : IRuntimeDisplayWindowTarg
|
|||
WindowState desired = display.Fullscreen
|
||||
? WindowState.Fullscreen
|
||||
: WindowState.Normal;
|
||||
|
||||
// #374 investigation note: while FULLSCREEN, the visible resolution
|
||||
// is the display's video mode, and Silk's abstract windowing API
|
||||
// cannot change it (IViewProperties.VideoMode is read-only; Silk
|
||||
// fullscreen is desktop-mode borderless). The Size write above is
|
||||
// therefore only visible in windowed mode — a resolution pick while
|
||||
// fullscreen changes what a later return to windowed restores, not
|
||||
// the fullscreen mode itself. Retail's own fullscreen resolution
|
||||
// switch (Device::ForceDisplayResolution) needs a native
|
||||
// glfwSetWindowMonitor port — issue #376.
|
||||
if (_window.WindowState != desired)
|
||||
_window.WindowState = desired;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue