Skip to content

Ignore child margin when positioning a popup #18827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

TomEdwardsEnscape
Copy link
Contributor

This PR brings an overlooked aspect of WPF's popup positioning to Avalonia. The margins of a popup's child are now ignored when positioning the popup, but still count toward the popup's size. This enables the child's margin to be used as a drawing surface for out-of-bounds effects like drop shadows, without affecting the child's final position.

This means that a popup with a child margin now sits closer to the target, and can also fit into smaller gaps without being repositioned.

What is the current behavior?

WPF:

Image

Avalonia:

Image

See #18810 for the XAML which generates the screenshots above.

What is the updated/expected behavior with this PR?

image

Note that on desktop platforms the margin area is part of the popup window, and so cannot be clicked through to reach the target window. WPF behaves in the same way, and if Microsoft couldn't make click-through work then I don't think I will fare any better! There may be a solution on other desktop platforms but I've not done any investigation into this.

If overlay popups are used then the popup margin (and any effects drawn within it) can be clicked through, the same as with any other Avalonia visual.

How was the solution implemented (if it's not obvious)?

A new property has been added: PopupPositionerParameters.Deflate. We deflate the popup size by this amount when calculating a position, then inflate the returned bounds by the same amount before generating popup geometry. Render scaling is accounted for.

Changes to the margin of the popup child now trigger repositioning of the popup, even if the overall size didn't change.

Checklist

Breaking changes

If the popup child's margin actually was intended to affect the popup's position, the UI author will have to wrap the child in a new panel/grid/decorator without a margin to restore their intended popup position.

Obsoletions / Deprecations

None.

Fixed issues

Fixes #18810

@TomEdwardsEnscape TomEdwardsEnscape force-pushed the feature/popup-child-margin branch from 9ebc173 to c3aea3e Compare May 9, 2025 21:28
@avaloniaui-bot
Copy link

You can test this PR using the following package version. 12.0.999-cibuild0056444-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Avoids drop shadows and other out-of-bounds visual effects from affecting popup positioning
@TomEdwardsEnscape TomEdwardsEnscape force-pushed the feature/popup-child-margin branch from c3aea3e to fc669e4 Compare May 13, 2025 19:10
@kekekeks
Copy link
Member

Sorry, we can't change PopupPositionerParameters and ManagedPopupPositioner logic, it was designed specifically to mirros xdg_positioner protocol, so we can have Wayland support in the future.

@kekekeks
Copy link
Member

i. e. those are the only values we can pass to the OS window system when using wayland:
https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/stable/xdg-shell/xdg-shell.xml#L152-367

IPopupPositioner is meant to have a managed implementation (which positions the popup according to specified parameters) and Wayland-specific implementation that simply passed those through.

So, check if logic required for your change could be implemented by adjusting positioner parameters before passing them to positioner.

@maxkatz6
Copy link
Member

So our only option is to adjust Horizontal/VerticalOffset properties before passing these to the positioner. Right?

@maxkatz6
Copy link
Member

This can be part of Popup.cs logic and not IPopupHost, since all the popup-like controls have been already rewriten to use Popup internally. That includes Tooltip. IPopupHost itself is going to be a private api eventually.

@TomEdwardsEnscape
Copy link
Contributor Author

What you are asking for is difficult, if it's possible at all. The positioner both calculates the position and applies it in one operation. Because we want the position to be calculated with popup size A, but then to apply a different size and position, we have no choice but to execute during the positioner's operation.

We can't give the positioner the deflated size and add an offset because the positioner could have flipped, slid, or squashed the popup in an unpredictable way, and this would cause the offset to have the wrong effect in many cases.

I think the only way this will work is if we give the deflated bounds to the positioner, and then intercept the window bounds update which comes out of it. If we want to do this in an XDG-compatible way, this means intercepting a platform message in each platform implementation. Then hoping that we don't get a flicker or any other glitch when we immediately alter the window position that was just set.

I'm probably not the first person to point out that restricting the feature set of every platform to the feature set of one platform which isn't even supported yet doesn't seem wise...

@kekekeks
Copy link
Member

Before making a decision on this, we'll need to check what can be done about Wayland. Maybe it's possible to have content outside of the rect that's being positioned, e. g. xdg_surface has set_window_geometry specifically to mark the region that doesn't contain shadows and while xdg_positioner has set_size method, the actual surface size is determined by the content attached via wl_surface::attach.

However, to make changes into the positioner interface we'll need to

  1. verify that it's indeed possible
  2. have Wayland support merged into the main repo at least as a preview feature

Once that happens, we can change the API and maybe even backport the implementation into 11.x.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Match WPF behaviour when positioning popups with margin on the root element
5 participants