mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-29 07:16:33 +08:00
256 lines
8.3 KiB
C#
256 lines
8.3 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Headless;
|
|
using Avalonia.Input;
|
|
using Avalonia.Threading;
|
|
using Avalonia.VisualTree;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AvaloniaWindow = Avalonia.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.Steps;
|
|
|
|
public class StepsInteractionTests
|
|
{
|
|
static StepsInteractionTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void Clicking_NonCurrent_Item_Requests_Change_Without_Mutating_Current()
|
|
{
|
|
var steps = CreateSteps(current: 10, initial: 10);
|
|
int? requested = null;
|
|
steps.CurrentChangeRequested += (_, args) => requested = args.Current;
|
|
|
|
ShowInWindow(steps, window => Click(GetPresenter(GetItem(steps, 1), "HeaderPresenter"), window));
|
|
|
|
requested.ShouldBe(11);
|
|
steps.Current.ShouldBe(10);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("HeaderPresenter")]
|
|
[InlineData("SubHeaderPresenter")]
|
|
[InlineData("ContentPresenter")]
|
|
public void Entire_Item_Content_Area_Uses_The_Same_Pointer_Activation_Path(string presenterName)
|
|
{
|
|
var steps = CreateSteps();
|
|
int? requested = null;
|
|
steps.CurrentChangeRequested += (_, args) => requested = args.Current;
|
|
|
|
ShowInWindow(steps, window => Click(GetPresenter(GetItem(steps, 1), presenterName), window));
|
|
|
|
requested.ShouldBe(1);
|
|
steps.Current.ShouldBe(0);
|
|
}
|
|
|
|
[Fact]
|
|
public void Clicking_Current_Item_Plays_Wave_Without_Request()
|
|
{
|
|
var steps = CreateSteps();
|
|
var requests = 0;
|
|
steps.CurrentChangeRequested += (_, _) => requests++;
|
|
|
|
ShowInWindow(steps, window =>
|
|
{
|
|
var item = GetItem(steps, 0);
|
|
Click(GetPresenter(item, "HeaderPresenter"), window);
|
|
|
|
requests.ShouldBe(0);
|
|
GetIndicator(item).IsWavePlaying.ShouldBeTrue();
|
|
});
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false, true)]
|
|
[InlineData(true, false)]
|
|
public void NonClickable_Or_Disabled_Item_Does_Not_Activate(bool isItemClickable, bool isItemEnabled)
|
|
{
|
|
var steps = CreateSteps();
|
|
steps.IsItemClickable = isItemClickable;
|
|
GetItem(steps, 1).IsEnabled = isItemEnabled;
|
|
var requests = 0;
|
|
steps.CurrentChangeRequested += (_, _) => requests++;
|
|
|
|
ShowInWindow(steps, window =>
|
|
{
|
|
var item = GetItem(steps, 1);
|
|
Click(GetPresenter(item, "HeaderPresenter"), window);
|
|
|
|
requests.ShouldBe(0);
|
|
GetIndicator(item).IsWavePlaying.ShouldBeFalse();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Releasing_Outside_The_Pressed_Item_Cancels_Activation()
|
|
{
|
|
var steps = CreateSteps();
|
|
var requests = 0;
|
|
steps.CurrentChangeRequested += (_, _) => requests++;
|
|
|
|
ShowInWindow(steps, window =>
|
|
{
|
|
var item = GetItem(steps, 1);
|
|
var target = GetPresenter(item, "HeaderPresenter");
|
|
var point = GetCenter(target, window);
|
|
window.MouseMove(point);
|
|
window.MouseDown(point, MouseButton.Left);
|
|
window.MouseMove(new Point(window.Bounds.Width - 2, window.Bounds.Height - 2));
|
|
window.MouseUp(new Point(window.Bounds.Width - 2, window.Bounds.Height - 2), MouseButton.Left);
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
requests.ShouldBe(0);
|
|
GetIndicator(item).IsWavePlaying.ShouldBeFalse();
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void Empty_Area_Within_Item_Uses_The_Item_Activation_Path()
|
|
{
|
|
var steps = CreateSteps();
|
|
int? requested = null;
|
|
steps.CurrentChangeRequested += (_, args) => requested = args.Current;
|
|
|
|
ShowInWindow(steps, window =>
|
|
{
|
|
var item = GetItem(steps, 1);
|
|
var point = item.TranslatePoint(
|
|
new Point(item.Bounds.Width - 4, item.Bounds.Height - 4),
|
|
window).ShouldNotBeNull();
|
|
|
|
window.MouseMove(point);
|
|
window.MouseDown(point, MouseButton.Left);
|
|
window.MouseUp(point, MouseButton.Left);
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
requested.ShouldBe(1);
|
|
});
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(Key.Enter, PhysicalKey.Enter)]
|
|
[InlineData(Key.Space, PhysicalKey.Space)]
|
|
public void Keyboard_Activation_Requests_Change_And_Plays_Wave(Key key, PhysicalKey physicalKey)
|
|
{
|
|
var steps = CreateSteps();
|
|
int? requested = null;
|
|
steps.CurrentChangeRequested += (_, args) => requested = args.Current;
|
|
|
|
ShowInWindow(steps, window =>
|
|
{
|
|
var item = GetItem(steps, 1);
|
|
item.Focus().ShouldBeTrue();
|
|
window.KeyPress(key, RawInputModifiers.None, physicalKey, null);
|
|
window.KeyRelease(key, RawInputModifiers.None, physicalKey, null);
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
requested.ShouldBe(1);
|
|
steps.Current.ShouldBe(0);
|
|
GetIndicator(item).IsWavePlaying.ShouldBeTrue();
|
|
});
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0, true, true, true)]
|
|
[InlineData(1, false, true, false)]
|
|
[InlineData(1, true, false, false)]
|
|
public void Keyboard_Does_Not_Request_Current_Disabled_Or_NonClickable_Item_And_Waves_Only_When_Invokable(
|
|
int index,
|
|
bool isItemClickable,
|
|
bool isItemEnabled,
|
|
bool expectedWave)
|
|
{
|
|
var steps = CreateSteps();
|
|
steps.IsItemClickable = isItemClickable;
|
|
GetItem(steps, index).IsEnabled = isItemEnabled;
|
|
var requests = 0;
|
|
steps.CurrentChangeRequested += (_, _) => requests++;
|
|
|
|
ShowInWindow(steps, window =>
|
|
{
|
|
var item = GetItem(steps, index);
|
|
item.Focus();
|
|
window.KeyPress(Key.Enter, RawInputModifiers.None, PhysicalKey.Enter, null);
|
|
window.KeyRelease(Key.Enter, RawInputModifiers.None, PhysicalKey.Enter, null);
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
requests.ShouldBe(0);
|
|
GetIndicator(item).IsWavePlaying.ShouldBe(expectedWave);
|
|
});
|
|
}
|
|
|
|
private static Desktop.Controls.Steps CreateSteps(int current = 0, int initial = 0)
|
|
{
|
|
var steps = new Desktop.Controls.Steps
|
|
{
|
|
Width = 760,
|
|
Current = current,
|
|
Initial = initial,
|
|
IsItemClickable = true,
|
|
IsMotionEnabled = true
|
|
};
|
|
steps.Items.Add(new Desktop.Controls.StepsItem { Header = "Step 1", SubHeader = "Sub 1", Content = "Content 1" });
|
|
steps.Items.Add(new Desktop.Controls.StepsItem { Header = "Step 2", SubHeader = "Sub 2", Content = "Content 2" });
|
|
steps.Items.Add(new Desktop.Controls.StepsItem { Header = "Step 3", SubHeader = "Sub 3", Content = "Content 3" });
|
|
return steps;
|
|
}
|
|
|
|
private static Desktop.Controls.StepsItem GetItem(Desktop.Controls.Steps steps, int index)
|
|
{
|
|
return steps.Items[index].ShouldBeOfType<Desktop.Controls.StepsItem>();
|
|
}
|
|
|
|
private static Control GetPresenter(Desktop.Controls.StepsItem item, string name)
|
|
{
|
|
return item.GetVisualDescendants().OfType<Control>().Single(control => control.Name == name);
|
|
}
|
|
|
|
private static Desktop.Controls.StepsItemIndicator GetIndicator(Desktop.Controls.StepsItem item)
|
|
{
|
|
return item.GetVisualDescendants().OfType<Desktop.Controls.StepsItemIndicator>().Single();
|
|
}
|
|
|
|
private static void Click(Control target, AvaloniaWindow window)
|
|
{
|
|
var point = GetCenter(target, window);
|
|
window.MouseMove(point);
|
|
window.MouseDown(point, MouseButton.Left);
|
|
window.MouseUp(point, MouseButton.Left);
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
|
|
private static Point GetCenter(Control target, AvaloniaWindow window)
|
|
{
|
|
var point = target.TranslatePoint(
|
|
new Point(target.Bounds.Width / 2, target.Bounds.Height / 2),
|
|
window);
|
|
return point.ShouldNotBeNull();
|
|
}
|
|
|
|
private static void ShowInWindow(Control content, Action<AvaloniaWindow> assertion)
|
|
{
|
|
var window = new AvaloniaWindow
|
|
{
|
|
Width = 900,
|
|
Height = 240,
|
|
Content = content
|
|
};
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
AvaloniaHeadlessPlatform.ForceRenderTimerTick(1);
|
|
Dispatcher.UIThread.RunJobs();
|
|
assertion(window);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
}
|