mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-28 14:20:47 +08:00
215 lines
6.6 KiB
C#
215 lines
6.6 KiB
C#
using AtomUI.Controls.Primitives;
|
|
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Media;
|
|
using Avalonia.Threading;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AvaloniaWindow = Avalonia.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.Primitives;
|
|
|
|
public class DashedBorderClipContentTests
|
|
{
|
|
static DashedBorderClipContentTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void Clip_Content_To_Corner_Radius_Clips_The_Child_To_The_Inner_Border_Edge()
|
|
{
|
|
var border = new GeometryHitTestCapableBorder
|
|
{
|
|
Width = 200,
|
|
Height = 100,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(8),
|
|
ClipContentToCornerRadius = true,
|
|
Child = new Border { Background = Brushes.Red }
|
|
};
|
|
|
|
ShowInWindow(border, () =>
|
|
{
|
|
var clip = border.Child!.Clip;
|
|
clip.ShouldNotBeNull();
|
|
|
|
// The child is inset by the border thickness, so the ring's inner edge in
|
|
// child space is the child's own bounds — the clip must not shrink them.
|
|
AssertRectClose(clip!.Bounds, new Rect(0, 0, 198, 98));
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Clip_Is_Not_Applied_When_The_Platform_Cannot_Hit_Test_The_Rounded_Figure()
|
|
{
|
|
var border = new DashedBorder
|
|
{
|
|
Width = 200,
|
|
Height = 100,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(8),
|
|
ClipContentToCornerRadius = true,
|
|
Child = new Border { Background = Brushes.Red }
|
|
};
|
|
|
|
ShowInWindow(border, () =>
|
|
{
|
|
// Platforms whose geometry containment cannot represent rounded figures
|
|
// (the headless test platform) degrade to not applying the clip so that
|
|
// pointer input over the content keeps working.
|
|
border.Child!.Clip.ShouldBeNull();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Disabling_Clip_Content_To_Corner_Radius_Clears_The_Managed_Clip()
|
|
{
|
|
var border = new GeometryHitTestCapableBorder
|
|
{
|
|
Width = 200,
|
|
Height = 100,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(8),
|
|
ClipContentToCornerRadius = true,
|
|
Child = new Border { Background = Brushes.Red }
|
|
};
|
|
|
|
ShowInWindow(border, () =>
|
|
{
|
|
border.Child!.Clip.ShouldNotBeNull();
|
|
|
|
border.ClipContentToCornerRadius = false;
|
|
|
|
border.Child.Clip.ShouldBeNull();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Disabled_Clip_Content_To_Corner_Radius_Leaves_The_Child_Clip_Untouched()
|
|
{
|
|
var border = new DashedBorder
|
|
{
|
|
Width = 200,
|
|
Height = 100,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(8),
|
|
Child = new Border { Background = Brushes.Red }
|
|
};
|
|
var originalClip = new RectangleGeometry(new Rect(4, 4, 64, 64));
|
|
border.Child.Clip = originalClip;
|
|
|
|
ShowInWindow(border, () =>
|
|
{
|
|
border.Child.Clip.ShouldBeSameAs(originalClip);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Removing_Child_Releases_The_Managed_Clip()
|
|
{
|
|
var child = new Border { Background = Brushes.Red };
|
|
var border = new GeometryHitTestCapableBorder
|
|
{
|
|
Width = 200,
|
|
Height = 100,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(8),
|
|
ClipContentToCornerRadius = true,
|
|
Child = child
|
|
};
|
|
|
|
ShowInWindow(border, () =>
|
|
{
|
|
child.Clip.ShouldNotBeNull();
|
|
border.Child = null;
|
|
child.Clip.ShouldBeNull();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Replacing_Child_Releases_The_Previous_Managed_Clip()
|
|
{
|
|
var oldChild = new Border { Background = Brushes.Red };
|
|
var newChild = new Border { Background = Brushes.Blue };
|
|
var border = new GeometryHitTestCapableBorder
|
|
{
|
|
Width = 200,
|
|
Height = 100,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(8),
|
|
ClipContentToCornerRadius = true,
|
|
Child = oldChild
|
|
};
|
|
|
|
ShowInWindow(border, () =>
|
|
{
|
|
oldChild.Clip.ShouldNotBeNull();
|
|
border.Child = newChild;
|
|
Dispatcher.UIThread.RunJobs();
|
|
newChild.Clip.ShouldNotBeNull();
|
|
oldChild.Clip.ShouldBeNull();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Disabling_Clip_Does_Not_Clear_A_Clip_Replaced_After_Management()
|
|
{
|
|
var child = new Border { Background = Brushes.Red };
|
|
var border = new GeometryHitTestCapableBorder
|
|
{
|
|
Width = 200,
|
|
Height = 100,
|
|
BorderThickness = new Thickness(1),
|
|
CornerRadius = new CornerRadius(8),
|
|
ClipContentToCornerRadius = true,
|
|
Child = child
|
|
};
|
|
var externalClip = new RectangleGeometry(new Rect(2, 3, 40, 50));
|
|
|
|
ShowInWindow(border, () =>
|
|
{
|
|
child.Clip.ShouldNotBeNull();
|
|
child.Clip = externalClip;
|
|
border.ClipContentToCornerRadius = false;
|
|
child.Clip.ShouldBeSameAs(externalClip);
|
|
});
|
|
}
|
|
|
|
private sealed class GeometryHitTestCapableBorder : DashedBorder
|
|
{
|
|
protected override bool SupportsGeometryClipHitTesting(Geometry figure) => true;
|
|
}
|
|
|
|
private static void AssertRectClose(Rect actual, Rect expected)
|
|
{
|
|
const double tolerance = 0.01;
|
|
Math.Abs(actual.X - expected.X).ShouldBeLessThan(tolerance);
|
|
Math.Abs(actual.Y - expected.Y).ShouldBeLessThan(tolerance);
|
|
Math.Abs(actual.Width - expected.Width).ShouldBeLessThan(tolerance);
|
|
Math.Abs(actual.Height - expected.Height).ShouldBeLessThan(tolerance);
|
|
}
|
|
|
|
private static void ShowInWindow(Control content, Action assertion)
|
|
{
|
|
var window = new AvaloniaWindow
|
|
{
|
|
Width = 300,
|
|
Height = 200,
|
|
Content = content
|
|
};
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
assertion();
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|
|
}
|