AvaloniaUI / Avalonia

Develop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The most popular .NET UI client technology
https://avaloniaui.net
MIT License
25.68k stars 2.22k forks source link

Margin / Padding / BorderThickness treatment with RenderScaling #7798

Open AndrejBunjac opened 2 years ago

AndrejBunjac commented 2 years ago

Describe the bug The controls with margins / paddings and thicknesses do not behave correctly when RenderScaling that's not equal to 1 is applied. Some of the thicknesses have visible anti-aliasing, padding offsets child controls, margin offsets from parent controls, in some scales thicknesses even overlap.

To Reproduce The problem is not windows specific (but I will describe the steps for Windows) Create a new app and add the following control to the main view

<Border BorderBrush="Red" BorderThickness="1" Width="41" Height="41">
  <Border BorderBrush="Green" BorderThickness="1" Padding="5">
    <Border BorderBrush="Purple" BorderThickness="1">
      <Border BorderBrush="Blue" BorderThickness="1" Margin="5"/>
    </Border>
  </Border>
</Border>

Go to windows display settings and choose a scale other than 100%. Observe.

To view what happens in some of the more exotic scales (not available in Windows), you'd need to force the value to WindowImpl, especially if you want to see what happens when downscaling.

Expected behavior The control is supposed to appear like this: image Instead it appears like this: image A few more examples: image

Additional context This happens because margins / padding / thickness is not given the same rounding treatment as width / height in the Layoutable.MeasureCore image The reason why this behavior matters to me is because in my custom implementation of WindowImpl I want to use the RenderScaling property to scale the entire UI up and down with the window in different resolution settings or window sizes (I don't want the UI to preserve size as the window size changes - but I want to still have pixel perfect snapping). Nonetheless, the behavior is visible in when running such an app in the latest implementation version of Avalonia.

After a few "hacky" tweaks to the source here is how it looks for me: image

The reason I call them "hacky" is because Layoutable doens't know about Padding / Thickness so I added them to Border's own MeasureOverride which is obviously not the correct place to put it.

What I would do is create a new LayoutHelper.MeasureChild overload that can update the parent's thickness / margin in the same way and apply this whenever a control with UseLayoutRounding is being laid out.

I am completely willing to do a pull request of my own with this change.

Karmoq commented 2 years ago

I encountered this behaviour too, when implementing some custom buttons. It's especially noticable when using screen with different UI scalings next to each other. I have 2 monitors with normal 100% scaling, and one higher resolution with 125% scaling. The example code provided by Andrej highlights it especially with the red & green border: image

I'd be very glad if this gets fixed.

maxkatz6 commented 1 year ago

Should be retested with 11.0 latest previews.