OverviewFilesCommitsIssuesDocsReleasesPeers

ifsrenderer-linux / AvaloniaShell.Tests / DiamondLayoutTests.cs

82 lines · csharp ref:
using System.Linq;

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Headless.XUnit;
using Avalonia.Threading;
using Avalonia.VisualTree;

using IFSRenderer.AvaloniaShell.Controls;

using Xunit;
using Xunit.Abstractions;

namespace IFSRenderer.AvaloniaShell.Tests;

/// <summary>
/// "left hand panel has some keyframes that are slightly occluded."
/// </summary>
/// <remarks>
/// The keyframe diamond is how an animation channel is created — the canonical empty dopesheet
/// says so outright: "Insert a keyframe by clicking ◇ next to the value!". If it is clipped or
/// sitting under the scrollbar it is not just cosmetic, it is the entry point to animation
/// being partly unreachable.
/// </remarks>
public class DiamondLayoutTests
{
    private readonly ITestOutputHelper _out;

    public DiamondLayoutTests(ITestOutputHelper output) => _out = output;

    [AvaloniaFact]
    public void No_keyframe_diamond_is_clipped_or_under_the_scrollbar()
    {
        (MainWindow window, _) = MainWindowHarness.Start();
        window.Measure(new Size(1500, 900));
        window.Arrange(new Rect(0, 0, 1500, 900));
        Dispatcher.UIThread.RunJobs();

        var pane = window.FindControl<Border>("LeftPanel");
        Assert.NotNull(pane);

        ScrollViewer viewer = pane.GetVisualDescendants().OfType<ScrollViewer>().First();
        ScrollBar bar = viewer.GetVisualDescendants().OfType<ScrollBar>()
            .First(b => b.Orientation == Avalonia.Layout.Orientation.Vertical);
        double barLeftInViewer = bar.TranslatePoint(new Point(0, 0), viewer)?.X ?? double.MaxValue;

        var sliders = pane.GetVisualDescendants().OfType<ValueSlider>().ToList();
        Assert.NotEmpty(sliders);

        int clipped = 0, occluded = 0;
        foreach (ValueSlider slider in sliders)
        {
            foreach (Button diamond in slider.GetVisualDescendants().OfType<Button>()
                         .Where(b => b.Name is "Diamond1" or "Diamond2" && b.IsVisible))
            {
                Rect bounds = diamond.Bounds;
                double rightInViewer =
                    (diamond.TranslatePoint(new Point(bounds.Width, 0), viewer)?.X) ?? 0;

                // A zero-width button means the glyph had nowhere to go.
                bool isClipped = bounds.Width <= 0 || bounds.Height <= 0;
                bool isOccluded = rightInViewer > barLeftInViewer;

                if (isClipped || isOccluded)
                {
                    _out.WriteLine($"{slider.Name ?? slider.Label}/{diamond.Name}: " +
                                   $"bounds={bounds} rightInViewer={rightInViewer} " +
                                   $"barLeft={barLeftInViewer} " +
                                   $"{(isClipped ? "CLIPPED " : "")}{(isOccluded ? "OCCLUDED" : "")}");
                }
                if (isClipped) clipped++;
                if (isOccluded) occluded++;
            }
        }

        _out.WriteLine($"diamonds checked: {sliders.Count}, clipped: {clipped}, occluded: {occluded}");
        Assert.True(clipped == 0, $"{clipped} keyframe diamonds have no room to draw");
        Assert.True(occluded == 0, $"{occluded} keyframe diamonds sit under the scrollbar");
    }
}