mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-27 04:09:37 +08:00
176 lines
6.9 KiB
C#
176 lines
6.9 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Controls.Primitives;
|
|
using Avalonia.Headless;
|
|
using Avalonia.Layout;
|
|
using Avalonia.Styling;
|
|
using Avalonia.Threading;
|
|
using Avalonia.VisualTree;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AvaloniaWindow = Avalonia.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.FeedbackStack;
|
|
|
|
public class FeedbackManagerPaddingTests
|
|
{
|
|
static FeedbackManagerPaddingTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(WindowMessageManager), 8)]
|
|
[InlineData(typeof(WindowNotificationManager), 24)]
|
|
public void Root_Padding_Controls_Stack_Geometry_And_Tracks_Position(Type managerType, double defaultInset)
|
|
{
|
|
var manager = CreateManager(managerType);
|
|
using var lifetime = (IDisposable)manager;
|
|
var customPadding = new Thickness(31, 43, 57, 69);
|
|
var rootStyle = new Style(selector => selector.OfType(managerType));
|
|
rootStyle.Setters.Add(new Setter(TemplatedControl.PaddingProperty, customPadding));
|
|
|
|
ShowInWindow(manager, window =>
|
|
{
|
|
ShowCards(manager);
|
|
UpdateLayout(window);
|
|
var presenter = manager.GetVisualDescendants().OfType<FeedbackStackPresenter>().Single();
|
|
AssertInsets(manager, presenter, new Thickness(defaultInset),
|
|
HorizontalAlignment.Right, VerticalAlignment.Top);
|
|
|
|
// Root styles and later local values must both reach the actual list geometry.
|
|
manager.Styles.Add(rootStyle);
|
|
foreach (var padding in new[] { customPadding, new Thickness(13, 17, 29, 37) })
|
|
{
|
|
if (padding != customPadding)
|
|
{
|
|
manager.Padding = padding;
|
|
}
|
|
|
|
foreach (var (position, horizontal, vertical) in new[]
|
|
{
|
|
(NotificationPosition.TopLeft, HorizontalAlignment.Left, VerticalAlignment.Top),
|
|
(NotificationPosition.TopCenter, HorizontalAlignment.Center, VerticalAlignment.Top),
|
|
(NotificationPosition.TopRight, HorizontalAlignment.Right, VerticalAlignment.Top),
|
|
(NotificationPosition.BottomLeft, HorizontalAlignment.Left, VerticalAlignment.Bottom),
|
|
(NotificationPosition.BottomCenter, HorizontalAlignment.Center, VerticalAlignment.Bottom),
|
|
(NotificationPosition.BottomRight, HorizontalAlignment.Right, VerticalAlignment.Bottom)
|
|
})
|
|
{
|
|
manager.SetValue(manager is WindowMessageManager
|
|
? WindowMessageManager.PositionProperty
|
|
: WindowNotificationManager.PositionProperty, position);
|
|
UpdateLayout(window);
|
|
AssertInsets(manager, presenter, padding, horizontal, vertical);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(typeof(WindowMessageManager))]
|
|
[InlineData(typeof(WindowNotificationManager))]
|
|
public void Custom_Padding_Preserves_Card_Hover_And_Excludes_Empty_Inset(Type managerType)
|
|
{
|
|
var manager = CreateManager(managerType);
|
|
using var lifetime = (IDisposable)manager;
|
|
manager.Padding = new Thickness(60);
|
|
|
|
ShowInWindow(manager, window =>
|
|
{
|
|
ShowCards(manager);
|
|
UpdateLayout(window);
|
|
var presenter = manager.GetVisualDescendants().OfType<FeedbackStackPresenter>().Single();
|
|
var latest = manager is WindowMessageManager message
|
|
? (Control)message.Cards[^1]
|
|
: ((WindowNotificationManager)manager).Cards[^1];
|
|
|
|
foreach (var fraction in new[] { 0.1, 0.5, 0.9 })
|
|
{
|
|
presenter.IsCollapsed.ShouldBeTrue();
|
|
var cardPoint = latest.TranslatePoint(
|
|
new Point(latest.Bounds.Width * fraction, latest.Bounds.Height / 2), window).ShouldNotBeNull();
|
|
window.MouseMove(cardPoint);
|
|
UpdateLayout(window);
|
|
presenter.IsCollapsed.ShouldBeFalse();
|
|
|
|
// This point is inside the manager but outside the visible card stack.
|
|
window.MouseMove(manager.TranslatePoint(
|
|
new Point(manager.Bounds.Width - 5, 5), window).ShouldNotBeNull());
|
|
UpdateLayout(window);
|
|
presenter.IsCollapsed.ShouldBeTrue();
|
|
}
|
|
});
|
|
}
|
|
|
|
private static TemplatedControl CreateManager(Type managerType)
|
|
{
|
|
return managerType == typeof(WindowMessageManager)
|
|
? new WindowMessageManager
|
|
{
|
|
IsMotionEnabled = false, IsStackEnabled = true, Position = NotificationPosition.TopRight
|
|
}
|
|
: new WindowNotificationManager
|
|
{
|
|
IsMotionEnabled = false, IsStackEnabled = true, Position = NotificationPosition.TopRight
|
|
};
|
|
}
|
|
|
|
private static void ShowCards(TemplatedControl manager)
|
|
{
|
|
for (var index = 0; index < 4; index++)
|
|
{
|
|
if (manager is WindowMessageManager message)
|
|
{
|
|
message.Show(new Message($"Message {index}", expiration: TimeSpan.Zero));
|
|
}
|
|
else
|
|
{
|
|
((WindowNotificationManager)manager).Show(
|
|
new Notification($"Notification {index}", "Body", expiration: TimeSpan.Zero));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void AssertInsets(TemplatedControl manager, Control stack, Thickness padding,
|
|
HorizontalAlignment horizontal, VerticalAlignment vertical)
|
|
{
|
|
var origin = stack.TranslatePoint(new Point(0, 0), manager).ShouldNotBeNull();
|
|
var expectedX = horizontal switch
|
|
{
|
|
HorizontalAlignment.Left => padding.Left,
|
|
HorizontalAlignment.Right => manager.Bounds.Width - padding.Right - stack.Bounds.Width,
|
|
_ => padding.Left + (manager.Bounds.Width - padding.Left - padding.Right - stack.Bounds.Width) / 2
|
|
};
|
|
var expectedY = vertical == VerticalAlignment.Top
|
|
? padding.Top
|
|
: manager.Bounds.Height - padding.Bottom - stack.Bounds.Height;
|
|
origin.X.ShouldBe(expectedX, 0.5);
|
|
origin.Y.ShouldBe(expectedY, 0.5);
|
|
stack.Bounds.Width.ShouldBeGreaterThan(0);
|
|
stack.Bounds.Height.ShouldBeGreaterThan(0);
|
|
}
|
|
|
|
private static void UpdateLayout(AvaloniaWindow window)
|
|
{
|
|
Dispatcher.UIThread.RunJobs();
|
|
window.UpdateLayout();
|
|
}
|
|
|
|
private static void ShowInWindow(Control content, Action<AvaloniaWindow> assertion)
|
|
{
|
|
var window = new AvaloniaWindow { Width = 800, Height = 600, Content = content };
|
|
try
|
|
{
|
|
window.Show();
|
|
UpdateLayout(window);
|
|
assertion(window);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
}
|