Browse Source

Measure PopupRoot to MaxAutoSizeHint.

On win32 popup's don't receive `WM_GETMINMAXINFO` so instead query the monitor info for the max work area,
Steven Kirk 5 years ago
parent
commit
fc711e7c86

+ 14 - 1
src/Avalonia.Controls/Primitives/PopupRoot.cs

@@ -119,7 +119,20 @@ namespace Avalonia.Controls.Primitives
 
         protected override Size MeasureOverride(Size availableSize)
         {
-            var measured = base.MeasureOverride(availableSize);
+            var maxAutoSize = PlatformImpl?.MaxAutoSizeHint ?? Size.Infinity;
+            var constraint = availableSize;
+
+            if (double.IsInfinity(constraint.Width))
+            {
+                constraint = constraint.WithWidth(maxAutoSize.Width);
+            }
+
+            if (double.IsInfinity(constraint.Height))
+            {
+                constraint = constraint.WithHeight(maxAutoSize.Height);
+            }
+
+            var measured = base.MeasureOverride(constraint);
             var width = measured.Width;
             var height = measured.Height;
             var widthCache = Width;

+ 26 - 0
src/Windows/Avalonia.Win32/PopupImpl.cs

@@ -8,12 +8,35 @@ namespace Avalonia.Win32
     class PopupImpl : WindowImpl, IPopupImpl
     {
         private bool _dropShadowHint = true;
+        private Size? _maxAutoSize;
 
         public override void Show()
         {
             UnmanagedMethods.ShowWindow(Handle.Handle, UnmanagedMethods.ShowWindowCommand.ShowNoActivate);
         }
 
+        public override Size MaxAutoSizeHint
+        {
+            get
+            {
+                if (_maxAutoSize is null)
+                {
+                    var monitor = UnmanagedMethods.MonitorFromWindow(
+                        Hwnd,
+                        UnmanagedMethods.MONITOR.MONITOR_DEFAULTTONEAREST);
+                    
+                    if (monitor != IntPtr.Zero)
+                    {
+                        var info = UnmanagedMethods.MONITORINFO.Create();
+                        UnmanagedMethods.GetMonitorInfo(monitor, ref info);
+                        _maxAutoSize = info.rcWork.ToPixelRect().ToRect(Scaling).Size;
+                    }
+                }
+
+                return _maxAutoSize ?? Size.Infinity;
+            }
+        }
+
         protected override IntPtr CreateWindowOverride(ushort atom)
         {
             UnmanagedMethods.WindowStyles style =
@@ -47,6 +70,9 @@ namespace Avalonia.Win32
         {
             switch ((UnmanagedMethods.WindowsMessage)msg)
             {
+                case UnmanagedMethods.WindowsMessage.WM_DISPLAYCHANGE:
+                    _maxAutoSize = null;
+                    goto default;
                 case UnmanagedMethods.WindowsMessage.WM_MOUSEACTIVATE:
                     return (IntPtr)UnmanagedMethods.MouseActivate.MA_NOACTIVATE;
                 default:

+ 3 - 1
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -169,7 +169,7 @@ namespace Avalonia.Win32
 
         public IPlatformHandle Handle { get; private set; }
 
-        public Size MaxAutoSizeHint => new Size(_maxTrackSize.X / Scaling, _maxTrackSize.Y / Scaling);
+        public virtual Size MaxAutoSizeHint => new Size(_maxTrackSize.X / Scaling, _maxTrackSize.Y / Scaling);
 
         public IMouseDevice MouseDevice => _mouseDevice;
 
@@ -203,6 +203,8 @@ namespace Avalonia.Win32
 
         public WindowTransparencyLevel TransparencyLevel { get; private set; }
 
+        protected IntPtr Hwnd => _hwnd;
+
         public void SetTransparencyLevelHint (WindowTransparencyLevel transparencyLevel)
         {
             TransparencyLevel = EnableBlur(transparencyLevel);

+ 13 - 7
tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using Avalonia.Controls.Presenters;
 using Avalonia.Controls.Primitives;
@@ -181,18 +182,21 @@ namespace Avalonia.Controls.UnitTests.Primitives
         }
 
         [Fact]
-        public void Child_Should_Be_Measured_With_Infinity()
+        public void Child_Should_Be_Measured_With_MaxAutoSizeHint()
         {
             using (UnitTestApplication.Start(TestServices.StyledWindow))
             {
                 var child = new ChildControl();
                 var window = new Window();
-                var target = CreateTarget(window);
+                var popupImpl = MockWindowingPlatform.CreatePopupMock(window.PlatformImpl);
+                popupImpl.Setup(x => x.MaxAutoSizeHint).Returns(new Size(1200, 1000));
+                var target = CreateTarget(window, popupImpl.Object);
                 
                 target.Content = child;
                 target.Show();
 
-                Assert.Equal(Size.Infinity, child.MeasureSize);
+                Assert.Equal(1, child.MeasureSizes.Count);
+                Assert.Equal(new Size(1200, 1000), child.MeasureSizes[0]);
             }
         }
 
@@ -210,7 +214,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 target.Content = child;
                 target.Show();
 
-                Assert.Equal(new Size(500, 600), child.MeasureSize);
+                Assert.Equal(1, child.MeasureSizes.Count);
+                Assert.Equal(new Size(500, 600), child.MeasureSizes[0]);
             }
         }
 
@@ -228,7 +233,8 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 target.Content = child;
                 target.Show();
 
-                Assert.Equal(new Size(500, 600), child.MeasureSize);
+                Assert.Equal(1, child.MeasureSizes.Count);
+                Assert.Equal(new Size(500, 600), child.MeasureSizes[0]);
             }
         }
 
@@ -365,11 +371,11 @@ namespace Avalonia.Controls.UnitTests.Primitives
 
         private class ChildControl : Control
         {
-            public Size MeasureSize { get; private set; }
+            public List<Size> MeasureSizes { get; } = new List<Size>();
 
             protected override Size MeasureOverride(Size availableSize)
             {
-                MeasureSize = availableSize;
+                MeasureSizes.Add(availableSize);
                 return base.MeasureOverride(availableSize);
             }
         }

+ 1 - 0
tests/Avalonia.UnitTests/MockWindowingPlatform.cs

@@ -80,6 +80,7 @@ namespace Avalonia.UnitTests
 
             popupImpl.SetupAllProperties();
             popupImpl.Setup(x => x.ClientSize).Returns(() => clientSize);
+            popupImpl.Setup(x => x.MaxAutoSizeHint).Returns(s_screenSize);
             popupImpl.Setup(x => x.Scaling).Returns(1);
             popupImpl.Setup(x => x.PopupPositioner).Returns(positioner);