diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index 4c84d32637..4546a1aadb 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -117,20 +117,14 @@ namespace Avalonia.Controls.Primitives
});
}
- ///
- /// Carries out the arrange pass of the window.
- ///
- /// The final window size.
- /// The parameter unchanged.
- protected override Size ArrangeOverride(Size finalSize)
+ protected override sealed Size ArrangeSetBounds(Size size)
{
using (BeginAutoSizing())
{
- _positionerParameters.Size = finalSize;
+ _positionerParameters.Size = size;
UpdatePosition();
+ return ClientSize;
}
-
- return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size));
}
}
}
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 387bf0adb8..dcf4e98528 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -313,22 +313,7 @@ namespace Avalonia.Controls
/// Should be called from left mouse button press event handler
///
public void BeginResizeDrag(WindowEdge edge, PointerPressedEventArgs e) => PlatformImpl?.BeginResizeDrag(edge, e);
-
- ///
- /// Carries out the arrange pass of the window.
- ///
- /// The final window size.
- /// The parameter unchanged.
- protected override Size ArrangeOverride(Size finalSize)
- {
- using (BeginAutoSizing())
- {
- PlatformImpl?.Resize(finalSize);
- }
- return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size));
- }
-
///
Size ILayoutRoot.MaxClientSize => _maxPlatformClientSize;
@@ -450,6 +435,19 @@ namespace Avalonia.Controls
EnsureInitialized();
IsVisible = true;
+
+ var initialSize = new Size(
+ double.IsNaN(Width) ? ClientSize.Width : Width,
+ double.IsNaN(Height) ? ClientSize.Height : Height);
+
+ if (initialSize != ClientSize)
+ {
+ using (BeginAutoSizing())
+ {
+ PlatformImpl?.Resize(initialSize);
+ }
+ }
+
LayoutManager.ExecuteInitialLayoutPass(this);
using (BeginAutoSizing())
@@ -569,31 +567,30 @@ namespace Avalonia.Controls
}
}
- ///
protected override Size MeasureOverride(Size availableSize)
{
var sizeToContent = SizeToContent;
var clientSize = ClientSize;
- var constraint = availableSize;
+ var constraint = clientSize;
- if ((sizeToContent & SizeToContent.Width) != 0)
+ if (sizeToContent.HasFlagCustom(SizeToContent.Width))
{
constraint = constraint.WithWidth(double.PositiveInfinity);
}
- if ((sizeToContent & SizeToContent.Height) != 0)
+ if (sizeToContent.HasFlagCustom(SizeToContent.Height))
{
constraint = constraint.WithHeight(double.PositiveInfinity);
}
var result = base.MeasureOverride(constraint);
- if ((sizeToContent & SizeToContent.Width) == 0)
+ if (!sizeToContent.HasFlagCustom(SizeToContent.Width))
{
result = result.WithWidth(clientSize.Width);
}
- if ((sizeToContent & SizeToContent.Height) == 0)
+ if (!sizeToContent.HasFlagCustom(SizeToContent.Height))
{
result = result.WithHeight(clientSize.Height);
}
@@ -601,6 +598,15 @@ namespace Avalonia.Controls
return result;
}
+ protected sealed override Size ArrangeSetBounds(Size size)
+ {
+ using (BeginAutoSizing())
+ {
+ PlatformImpl?.Resize(size);
+ return ClientSize;
+ }
+ }
+
protected sealed override void HandleClosed()
{
RaiseEvent(new RoutedEventArgs(WindowClosedEvent));
diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs
index 63eabb32f4..025dfde610 100644
--- a/src/Avalonia.Controls/WindowBase.cs
+++ b/src/Avalonia.Controls/WindowBase.cs
@@ -224,16 +224,66 @@ namespace Avalonia.Controls
/// The new client size.
protected override void HandleResized(Size clientSize)
{
- if (!AutoSizing)
- {
- Width = clientSize.Width;
- Height = clientSize.Height;
- }
+ Width = clientSize.Width;
+ Height = clientSize.Height;
ClientSize = clientSize;
LayoutManager.ExecuteLayoutPass();
Renderer?.Resized(clientSize);
}
+ ///
+ /// Overrides the core measure logic for windows.
+ ///
+ /// The available size.
+ /// The measured size.
+ ///
+ /// The layout logic for top-level windows is different than for other controls because
+ /// they don't have a parent, meaning that many layout properties handled by the default
+ /// MeasureCore (such as margins and alignment) make no sense.
+ ///
+ protected override Size MeasureCore(Size availableSize)
+ {
+ ApplyStyling();
+ ApplyTemplate();
+
+ var constraint = availableSize;
+
+ if (!double.IsNaN(Width))
+ {
+ constraint = constraint.WithWidth(Width);
+ }
+
+ if (!double.IsNaN(Height))
+ {
+ constraint = constraint.WithHeight(Height);
+ }
+
+ return MeasureOverride(constraint);
+ }
+
+ ///
+ /// Overrides the core arrange logic for windows.
+ ///
+ /// The final arrange rect.
+ ///
+ /// The layout logic for top-level windows is different than for other controls because
+ /// they don't have a parent, meaning that many layout properties handled by the default
+ /// ArrangeCore (such as margins and alignment) make no sense.
+ ///
+ protected override void ArrangeCore(Rect finalRect)
+ {
+ var constraint = ArrangeSetBounds(finalRect.Size);
+ var arrangeSize = ArrangeOverride(constraint);
+ Bounds = new Rect(arrangeSize);
+ }
+
+ ///
+ /// Called durung the arrange pass to set the size of the window.
+ ///
+ /// The requested size of the window.
+ /// The actual size of the window.
+ protected virtual Size ArrangeSetBounds(Size size) => size;
+
///
/// Handles a window position change notification from
/// .
diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
index 5a47a86e51..28e87dd671 100644
--- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
@@ -209,16 +209,17 @@ namespace Avalonia.Controls.UnitTests
screenImpl.Setup(x => x.ScreenCount).Returns(1);
screenImpl.Setup(X => X.AllScreens).Returns( new[] { new Screen(1, screen, screen, true) });
- popupImpl = MockWindowingPlatform.CreatePopupMock();
+ var windowImpl = MockWindowingPlatform.CreateWindowMock();
+ popupImpl = MockWindowingPlatform.CreatePopupMock(windowImpl.Object);
popupImpl.SetupGet(x => x.Scaling).Returns(1);
+ windowImpl.Setup(x => x.CreatePopup()).Returns(popupImpl.Object);
- var windowImpl = MockWindowingPlatform.CreateWindowMock(() => popupImpl.Object);
windowImpl.Setup(x => x.Screen).Returns(screenImpl.Object);
var services = TestServices.StyledWindow.With(
inputManager: new InputManager(),
windowImpl: windowImpl.Object,
- windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object, () => popupImpl.Object));
+ windowingPlatform: new MockWindowingPlatform(() => windowImpl.Object, x => popupImpl.Object));
return UnitTestApplication.Start(services);
}
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs
index 501c0455d0..b03f8b8892 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupRootTests.cs
@@ -4,6 +4,7 @@ using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.LogicalTree;
+using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
@@ -172,9 +173,75 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
}
- private PopupRoot CreateTarget(TopLevel popupParent)
+ [Fact]
+ public void Child_Should_Be_Measured_With_Infinity()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var child = new ChildControl();
+ var window = new Window();
+ var target = CreateTarget(window);
+
+ target.Content = child;
+ target.Show();
+
+ Assert.Equal(Size.Infinity, child.MeasureSize);
+ }
+ }
+
+ [Fact]
+ public void Child_Should_Be_Measured_With_Width_Height_When_Set()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var child = new ChildControl();
+ var window = new Window();
+ var target = CreateTarget(window);
+
+ target.Width = 500;
+ target.Height = 600;
+ target.Content = child;
+ target.Show();
+
+ Assert.Equal(new Size(500, 600), child.MeasureSize);
+ }
+ }
+
+ [Fact]
+ public void Should_Not_Have_Offset_On_Bounds_When_Content_Larger_Than_Max_Window_Size()
+ {
+ // Issue #3784.
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var window = new Window();
+ var popupImpl = MockWindowingPlatform.CreatePopupMock(window.PlatformImpl);
+
+ popupImpl.Setup(x => x.ClientSize).Returns(new Size(400, 480));
+
+ var child = new Canvas
+ {
+ Width = 400,
+ Height = 800,
+ };
+
+ var target = CreateTarget(window, popupImpl.Object);
+ target.Content = child;
+
+ target.Show();
+
+ Assert.Equal(new Size(400, 480), target.Bounds.Size);
+
+ // Issue #3784 causes this to be (0, 160) which makes no sense as Window has no
+ // parent control to be offset against.
+ Assert.Equal(new Point(0, 0), target.Bounds.Position);
+ }
+ }
+
+ private PopupRoot CreateTarget(TopLevel popupParent, IPopupImpl impl = null)
{
- var result = new PopupRoot(popupParent, popupParent.PlatformImpl.CreatePopup())
+ impl ??= popupParent.PlatformImpl.CreatePopup();
+
+ var result = new PopupRoot(popupParent, impl)
{
Template = new FuncControlTemplate((parent, scope) =>
new ContentPresenter
@@ -217,5 +284,16 @@ namespace Avalonia.Controls.UnitTests.Primitives
Popup = (Popup)this.GetVisualChildren().Single();
}
}
+
+ private class ChildControl : Control
+ {
+ public Size MeasureSize { get; private set; }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ MeasureSize = availableSize;
+ return base.MeasureOverride(availableSize);
+ }
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
index a4c0fa054b..1a2c93ac22 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
@@ -355,11 +355,11 @@ namespace Avalonia.Controls.UnitTests.Primitives
{
return UnitTestApplication.Start(TestServices.StyledWindow.With(windowingPlatform:
new MockWindowingPlatform(null,
- () =>
+ x =>
{
if(UsePopupHost)
return null;
- return MockWindowingPlatform.CreatePopupMock().Object;
+ return MockWindowingPlatform.CreatePopupMock(x).Object;
})));
}
diff --git a/tests/Avalonia.Controls.UnitTests/WindowTests.cs b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
index fed63fc683..5382e6ea3e 100644
--- a/tests/Avalonia.Controls.UnitTests/WindowTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WindowTests.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.UnitTests;
@@ -355,6 +356,27 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void Child_Should_Be_Measured_With_ClientSize_If_SizeToContent_Is_Manual_And_No_Width_Height_Specified()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var windowImpl = MockWindowingPlatform.CreateWindowMock();
+ windowImpl.Setup(x => x.ClientSize).Returns(new Size(550, 450));
+
+ var child = new ChildControl();
+ var target = new Window(windowImpl.Object)
+ {
+ SizeToContent = SizeToContent.Manual,
+ Content = child
+ };
+
+ target.Show();
+
+ Assert.Equal(new Size(550, 450), child.MeasureSize);
+ }
+ }
+
[Fact]
public void Child_Should_Be_Measured_With_Infinity_If_SizeToContent_Is_WidthAndHeight()
{
@@ -375,6 +397,123 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void Should_Not_Have_Offset_On_Bounds_When_Content_Larger_Than_Max_Window_Size()
+ {
+ // Issue #3784.
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var windowImpl = MockWindowingPlatform.CreateWindowMock();
+ var clientSize = new Size(200, 200);
+ var maxClientSize = new Size(480, 480);
+
+ windowImpl.Setup(x => x.Resize(It.IsAny())).Callback(size =>
+ {
+ clientSize = size.Constrain(maxClientSize);
+ windowImpl.Object.Resized?.Invoke(clientSize);
+ });
+
+ windowImpl.Setup(x => x.ClientSize).Returns(() => clientSize);
+
+ var child = new Canvas
+ {
+ Width = 400,
+ Height = 800,
+ };
+ var target = new Window(windowImpl.Object)
+ {
+ SizeToContent = SizeToContent.WidthAndHeight,
+ Content = child
+ };
+
+ target.Show();
+
+ Assert.Equal(new Size(400, 480), target.Bounds.Size);
+
+ // Issue #3784 causes this to be (0, 160) which makes no sense as Window has no
+ // parent control to be offset against.
+ Assert.Equal(new Point(0, 0), target.Bounds.Position);
+ }
+ }
+
+ [Fact]
+ public void Width_Height_Should_Not_Be_NaN_After_Show_With_SizeToContent_WidthAndHeight()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var child = new Canvas
+ {
+ Width = 400,
+ Height = 800,
+ };
+
+ var target = new Window()
+ {
+ SizeToContent = SizeToContent.WidthAndHeight,
+ Content = child
+ };
+
+ target.Show();
+
+ Assert.Equal(400, target.Width);
+ Assert.Equal(800, target.Height);
+ }
+ }
+
+ [Fact]
+ public void SizeToContent_Should_Not_Be_Lost_On_Show()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var child = new Canvas
+ {
+ Width = 400,
+ Height = 800,
+ };
+
+ var target = new Window()
+ {
+ SizeToContent = SizeToContent.WidthAndHeight,
+ Content = child
+ };
+
+ target.Show();
+
+ Assert.Equal(SizeToContent.WidthAndHeight, target.SizeToContent);
+ }
+ }
+
+ [Fact]
+ public void Width_Height_Should_Be_Updated_When_SizeToContent_Is_WidthAndHeight()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var child = new Canvas
+ {
+ Width = 400,
+ Height = 800,
+ };
+
+ var target = new Window()
+ {
+ SizeToContent = SizeToContent.WidthAndHeight,
+ Content = child
+ };
+
+ target.Show();
+
+ Assert.Equal(400, target.Width);
+ Assert.Equal(800, target.Height);
+
+ child.Width = 410;
+ target.LayoutManager.ExecuteLayoutPass();
+
+ Assert.Equal(410, target.Width);
+ Assert.Equal(800, target.Height);
+ Assert.Equal(SizeToContent.WidthAndHeight, target.SizeToContent);
+ }
+ }
+
private IWindowImpl CreateImpl(Mock renderer)
{
return Mock.Of(x =>
diff --git a/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs b/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
index 69eff0b65d..dcc29a9716 100644
--- a/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
+++ b/tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
@@ -1,25 +1,12 @@
-using System.Diagnostics;
-using System.IO;
using System.Linq;
-using Moq;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
-using Avalonia.Diagnostics;
-using Avalonia.Input;
-using Avalonia.Platform;
-using Avalonia.Rendering;
-using Avalonia.Shared.PlatformSupport;
using Avalonia.Styling;
-using Avalonia.Themes.Default;
+using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
-using Avalonia.Media;
-using System;
-using System.Collections.Generic;
-using Avalonia.Controls.UnitTests;
-using Avalonia.UnitTests;
namespace Avalonia.Layout.UnitTests
{
@@ -28,10 +15,8 @@ namespace Avalonia.Layout.UnitTests
[Fact]
public void Grandchild_Size_Changed()
{
- using (var context = AvaloniaLocator.EnterScope())
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
{
- RegisterServices();
-
Border border;
TextBlock textBlock;
@@ -55,7 +40,6 @@ namespace Avalonia.Layout.UnitTests
};
window.Show();
- window.LayoutManager.ExecuteInitialLayoutPass(window);
Assert.Equal(new Size(400, 400), border.Bounds.Size);
textBlock.Width = 200;
@@ -68,10 +52,8 @@ namespace Avalonia.Layout.UnitTests
[Fact]
public void Test_ScrollViewer_With_TextBlock()
{
- using (var context = AvaloniaLocator.EnterScope())
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
{
- RegisterServices();
-
ScrollViewer scrollViewer;
TextBlock textBlock;
@@ -79,7 +61,6 @@ namespace Avalonia.Layout.UnitTests
{
Width = 800,
Height = 600,
- SizeToContent = SizeToContent.WidthAndHeight,
Content = scrollViewer = new ScrollViewer
{
Width = 200,
@@ -99,7 +80,6 @@ namespace Avalonia.Layout.UnitTests
window.Resources["ScrollBarThickness"] = 10.0;
window.Show();
- window.LayoutManager.ExecuteInitialLayoutPass(window);
Assert.Equal(new Size(800, 600), window.Bounds.Size);
Assert.Equal(new Size(200, 200), scrollViewer.Bounds.Size);
@@ -131,87 +111,5 @@ namespace Avalonia.Layout.UnitTests
{
return v.Bounds.Position;
}
-
- class FormattedTextMock : IFormattedTextImpl
- {
- public FormattedTextMock(string text)
- {
- Text = text;
- }
-
- public Size Constraint { get; set; }
-
- public string Text { get; }
-
- public Rect Bounds => Rect.Empty;
-
- public void Dispose()
- {
- }
-
- public IEnumerable GetLines() => new FormattedTextLine[0];
-
- public TextHitTestResult HitTestPoint(Point point) => new TextHitTestResult();
-
- public Rect HitTestTextPosition(int index) => new Rect();
-
- public IEnumerable HitTestTextRange(int index, int length) => new Rect[0];
-
- public Size Measure() => Constraint;
- }
-
- private void RegisterServices()
- {
- var globalStyles = new Mock();
- var globalStylesResources = globalStyles.As();
- var outObj = (object)10;
- globalStylesResources.Setup(x => x.TryGetResource("FontSizeNormal", out outObj)).Returns(true);
-
- var renderInterface = new Mock();
- renderInterface.Setup(x =>
- x.CreateFormattedText(
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny>()))
- .Returns(new FormattedTextMock("TEST"));
-
- var streamGeometry = new Mock();
- streamGeometry.Setup(x =>
- x.Open())
- .Returns(new Mock().Object);
-
- renderInterface.Setup(x =>
- x.CreateStreamGeometry())
- .Returns(streamGeometry.Object);
-
- var windowImpl = new Mock();
-
- Size clientSize = default(Size);
-
- windowImpl.SetupGet(x => x.ClientSize).Returns(() => clientSize);
- windowImpl.Setup(x => x.Resize(It.IsAny())).Callback(s => clientSize = s);
- windowImpl.Setup(x => x.MaxClientSize).Returns(new Size(1024, 1024));
- windowImpl.SetupGet(x => x.Scaling).Returns(1);
-
- AvaloniaLocator.CurrentMutable
- .Bind().ToConstant(new CursorFactoryMock())
- .Bind().ToConstant(new AssetLoader())
- .Bind().ToConstant(new Mock().Object)
- .Bind().ToConstant(globalStyles.Object)
- .Bind().ToConstant(new AppBuilder().RuntimePlatform)
- .Bind().ToConstant(renderInterface.Object)
- .Bind().ToConstant(new Styler())
- .Bind().ToConstant(new MockFontManagerImpl())
- .Bind().ToConstant(new MockTextShaperImpl())
- .Bind().ToConstant(new Avalonia.Controls.UnitTests.WindowingPlatformMock(() => windowImpl.Object));
-
- var theme = new DefaultTheme();
- globalStyles.Setup(x => x.IsStylesInitialized).Returns(true);
- globalStyles.Setup(x => x.Styles).Returns(theme);
- }
}
}
diff --git a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs
index 782e4a0974..b8b7512c9e 100644
--- a/tests/Avalonia.UnitTests/MockWindowingPlatform.cs
+++ b/tests/Avalonia.UnitTests/MockWindowingPlatform.cs
@@ -8,65 +8,118 @@ namespace Avalonia.UnitTests
{
public class MockWindowingPlatform : IWindowingPlatform
{
+ private static readonly Size s_screenSize = new Size(1280, 1024);
private readonly Func _windowImpl;
- private readonly Func _popupImpl;
+ private readonly Func _popupImpl;
- public MockWindowingPlatform(Func windowImpl = null, Func popupImpl = null )
+ public MockWindowingPlatform(
+ Func windowImpl = null,
+ Func popupImpl = null )
{
_windowImpl = windowImpl;
_popupImpl = popupImpl;
}
- public static Mock CreateWindowMock(Func popupImpl = null)
+ public static Mock CreateWindowMock()
{
- var win = Mock.Of(x => x.Scaling == 1);
- var mock = Mock.Get(win);
- mock.Setup(x => x.Show()).Callback(() =>
+ var windowImpl = new Mock();
+ var position = new PixelPoint();
+ var clientSize = new Size(800, 600);
+
+ windowImpl.SetupAllProperties();
+ windowImpl.Setup(x => x.ClientSize).Returns(() => clientSize);
+ windowImpl.Setup(x => x.Scaling).Returns(1);
+ windowImpl.Setup(x => x.Screen).Returns(CreateScreenMock().Object);
+ windowImpl.Setup(x => x.Position).Returns(() => position);
+ SetupToplevel(windowImpl);
+
+ windowImpl.Setup(x => x.CreatePopup()).Returns(() =>
{
- mock.Object.Activated?.Invoke();
+ return CreatePopupMock(windowImpl.Object).Object;
});
- mock.Setup(x => x.CreatePopup()).Returns(() =>
+
+ windowImpl.Setup(x => x.Dispose()).Callback(() =>
{
- if (popupImpl != null)
- return popupImpl();
- return CreatePopupMock().Object;
+ windowImpl.Object.Closed?.Invoke();
+ });
+
+ windowImpl.Setup(x => x.Move(It.IsAny())).Callback(x =>
+ {
+ position = x;
+ windowImpl.Object.PositionChanged?.Invoke(x);
+ });
+ windowImpl.Setup(x => x.Resize(It.IsAny())).Callback(x =>
+ {
+ clientSize = x.Constrain(s_screenSize);
+ windowImpl.Object.Resized?.Invoke(clientSize);
});
- mock.Setup(x => x.Dispose()).Callback(() =>
+
+ windowImpl.Setup(x => x.Show()).Callback(() =>
{
- mock.Object.Closed?.Invoke();
+ windowImpl.Object.Activated?.Invoke();
});
- PixelPoint pos = default;
- mock.SetupGet(x => x.Position).Returns(() => pos);
- mock.Setup(x => x.Move(It.IsAny())).Callback(new Action(np => pos = np));
- SetupToplevel(mock);
- return mock;
+
+ return windowImpl;
}
- static void SetupToplevel(Mock mock) where T : class, ITopLevelImpl
+ public static Mock CreatePopupMock(IWindowBaseImpl parent)
{
- mock.SetupGet(x => x.MouseDevice).Returns(new MouseDevice());
+ var popupImpl = new Mock();
+
+ var positionerHelper = new ManagedPopupPositionerPopupImplHelper(parent, (pos, size, scale) =>
+ {
+ popupImpl.Object.PositionChanged?.Invoke(pos);
+ popupImpl.Object.Resized?.Invoke(size);
+ });
+
+ var positioner = new ManagedPopupPositioner(positionerHelper);
+
+ popupImpl.Setup(x => x.Scaling).Returns(1);
+ popupImpl.Setup(x => x.PopupPositioner).Returns(positioner);
+
+ SetupToplevel(popupImpl);
+
+ return popupImpl;
}
- public static Mock CreatePopupMock()
+ public static Mock CreateScreenMock()
{
- var positioner = Mock.Of();
- var popup = Mock.Of(x => x.Scaling == 1);
- var mock = Mock.Get(popup);
- mock.SetupGet(x => x.PopupPositioner).Returns(positioner);
- SetupToplevel(mock);
-
- return mock;
+ var screenImpl = new Mock();
+ var bounds = new PixelRect(0, 0, (int)s_screenSize.Width, (int)s_screenSize.Height);
+ var screen = new Screen(96, bounds, bounds, true);
+ screenImpl.Setup(x => x.AllScreens).Returns(new[] { screen });
+ screenImpl.Setup(x => x.ScreenCount).Returns(1);
+ return screenImpl;
}
public IWindowImpl CreateWindow()
{
- return _windowImpl?.Invoke() ?? CreateWindowMock(_popupImpl).Object;
+ if (_windowImpl is object)
+ {
+ return _windowImpl();
+ }
+ else
+ {
+ var mock = CreateWindowMock();
+
+ if (_popupImpl is object)
+ {
+ mock.Setup(x => x.CreatePopup()).Returns(() => _popupImpl(mock.Object));
+ }
+
+ return mock.Object;
+ }
}
public IEmbeddableWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}
+
+ private static void SetupToplevel(Mock mock) where T : class, ITopLevelImpl
+ {
+ mock.SetupGet(x => x.MouseDevice).Returns(new MouseDevice());
+ }
}
}