Browse Source

Make headless easier to use with HeadlessWindowExtensions

pull/10473/head
Max Katz 3 years ago
parent
commit
6b81b5a935
  1. 50
      src/Headless/Avalonia.Headless/HeadlessWindowExtensions.cs
  2. 28
      src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs
  3. 8
      src/Headless/Avalonia.Headless/IHeadlessWindow.cs
  4. 9
      tests/Avalonia.Headless.UnitTests/InputTests.cs
  5. 10
      tests/Avalonia.Headless.UnitTests/RenderingTests.cs
  6. 6
      tests/Avalonia.Headless.UnitTests/TestApplication.cs
  7. 2
      tests/Avalonia.Headless.UnitTests/ThreadingTests.cs

50
src/Headless/Avalonia.Headless/HeadlessWindowExtensions.cs

@ -0,0 +1,50 @@
using System;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
namespace Avalonia.Headless;
public static class HeadlessWindowExtensions
{
public static Bitmap? CaptureRenderedFrame(this TopLevel topLevel)
{
var impl = GetImpl(topLevel);
AvaloniaHeadlessPlatform.ForceRenderTimerTick();
return impl.GetLastRenderedFrame();
}
public static Bitmap? GetLastRenderedFrame(this TopLevel topLevel) =>
GetImpl(topLevel).GetLastRenderedFrame();
public static void KeyPress(this TopLevel topLevel, Key key, RawInputModifiers modifiers) =>
GetImpl(topLevel).KeyPress(key, modifiers);
public static void KeyRelease(this TopLevel topLevel, Key key, RawInputModifiers modifiers) =>
GetImpl(topLevel).KeyRelease(key, modifiers);
public static void MouseDown(this TopLevel topLevel, Point point, MouseButton button,
RawInputModifiers modifiers = RawInputModifiers.None) => GetImpl(topLevel).MouseDown(point, button, modifiers);
public static void MouseMove(this TopLevel topLevel, Point point,
RawInputModifiers modifiers = RawInputModifiers.None) => GetImpl(topLevel).MouseMove(point, modifiers);
public static void MouseUp(this TopLevel topLevel, Point point, MouseButton button,
RawInputModifiers modifiers = RawInputModifiers.None) => GetImpl(topLevel).MouseUp(point, button, modifiers);
public static void MouseWheel(this TopLevel topLevel, Point point, Vector delta,
RawInputModifiers modifiers = RawInputModifiers.None) => GetImpl(topLevel).MouseWheel(point, delta, modifiers);
public static void DragDrop(this TopLevel topLevel, Point point, RawDragEventType type, IDataObject data,
DragDropEffects effects, RawInputModifiers modifiers = RawInputModifiers.None) =>
GetImpl(topLevel).DragDrop(point, type, data, effects, modifiers);
private static IHeadlessWindow GetImpl(this TopLevel topLevel)
{
Dispatcher.UIThread.RunJobs();
return topLevel.PlatformImpl as IHeadlessWindow ??
throw new InvalidOperationException("TopLevel must be a headless window.");
}
}

28
src/Headless/Avalonia.Headless/HeadlessWindowImpl.cs

@ -271,12 +271,18 @@ namespace Avalonia.Headless
Input?.Invoke(new RawKeyEventArgs(_keyboard, Timestamp, InputRoot!, RawKeyEventType.KeyUp, key, modifiers));
}
void IHeadlessWindow.MouseDown(Point point, int button, RawInputModifiers modifiers)
void IHeadlessWindow.MouseDown(Point point, MouseButton button, RawInputModifiers modifiers)
{
Input?.Invoke(new RawPointerEventArgs(MouseDevice, Timestamp, InputRoot!,
button == 0 ? RawPointerEventType.LeftButtonDown :
button == 1 ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.RightButtonDown,
point, modifiers));
button switch
{
MouseButton.Left => RawPointerEventType.LeftButtonDown,
MouseButton.Right => RawPointerEventType.RightButtonDown,
MouseButton.Middle => RawPointerEventType.MiddleButtonDown,
MouseButton.XButton1 => RawPointerEventType.XButton1Down,
MouseButton.XButton2 => RawPointerEventType.XButton2Down,
_ => RawPointerEventType.Move,
}, point, modifiers));
}
void IHeadlessWindow.MouseMove(Point point, RawInputModifiers modifiers)
@ -285,12 +291,18 @@ namespace Avalonia.Headless
RawPointerEventType.Move, point, modifiers));
}
void IHeadlessWindow.MouseUp(Point point, int button, RawInputModifiers modifiers)
void IHeadlessWindow.MouseUp(Point point, MouseButton button, RawInputModifiers modifiers)
{
Input?.Invoke(new RawPointerEventArgs(MouseDevice, Timestamp, InputRoot!,
button == 0 ? RawPointerEventType.LeftButtonUp :
button == 1 ? RawPointerEventType.MiddleButtonUp : RawPointerEventType.RightButtonUp,
point, modifiers));
button switch
{
MouseButton.Left => RawPointerEventType.LeftButtonUp,
MouseButton.Right => RawPointerEventType.RightButtonUp,
MouseButton.Middle => RawPointerEventType.MiddleButtonUp,
MouseButton.XButton1 => RawPointerEventType.XButton1Up,
MouseButton.XButton2 => RawPointerEventType.XButton2Up,
_ => RawPointerEventType.Move,
}, point, modifiers));
}
void IHeadlessWindow.MouseWheel(Point point, Vector delta, RawInputModifiers modifiers)

8
src/Headless/Avalonia.Headless/IHeadlessWindow.cs

@ -6,15 +6,15 @@ using Avalonia.Utilities;
namespace Avalonia.Headless
{
public interface IHeadlessWindow
internal interface IHeadlessWindow
{
Bitmap? GetLastRenderedFrame();
void KeyPress(Key key, RawInputModifiers modifiers);
void KeyRelease(Key key, RawInputModifiers modifiers);
void MouseDown(Point point, int button, RawInputModifiers modifiers = RawInputModifiers.None);
void MouseDown(Point point, MouseButton button, RawInputModifiers modifiers = RawInputModifiers.None);
void MouseMove(Point point, RawInputModifiers modifiers = RawInputModifiers.None);
void MouseUp(Point point, int button, RawInputModifiers modifiers = RawInputModifiers.None);
void MouseUp(Point point, MouseButton button, RawInputModifiers modifiers = RawInputModifiers.None);
void MouseWheel(Point point, Vector delta, RawInputModifiers modifiers = RawInputModifiers.None);
void DragDrop(Point point, RawDragEventType type, IDataObject data, DragDropEffects effects, RawInputModifiers modifiers);
void DragDrop(Point point, RawDragEventType type, IDataObject data, DragDropEffects effects, RawInputModifiers modifiers = RawInputModifiers.None);
}
}

9
tests/Avalonia.Headless.UnitTests/InputTests.cs

@ -1,9 +1,10 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Threading;
using Xunit;
namespace Avalonia.Headless.XUnit.Tests;
namespace Avalonia.Headless.UnitTests;
public class InputTests
{
@ -27,10 +28,8 @@ public class InputTests
};
window.Show();
Dispatcher.UIThread.RunJobs();
((IHeadlessWindow)window.PlatformImpl!).MouseDown(new Point(50, 50), 0);
((IHeadlessWindow)window.PlatformImpl!).MouseUp(new Point(50, 50), 0);
window.MouseDown(new Point(50, 50), MouseButton.Left);
window.MouseUp(new Point(50, 50), MouseButton.Left);
Assert.True(buttonClicked);
}

10
tests/Avalonia.Headless.UnitTests/RenderingTests.cs

@ -1,13 +1,10 @@
using System.IO;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Threading;
using Xunit;
namespace Avalonia.Headless.XUnit.Tests;
namespace Avalonia.Headless.UnitTests;
public class RenderingTests
{
@ -32,8 +29,7 @@ public class RenderingTests
Dispatcher.UIThread.RunJobs();
AvaloniaHeadlessPlatform.ForceRenderTimerTick();
var frame = ((IHeadlessWindow)window.PlatformImpl!).GetLastRenderedFrame();
var frame = window.CaptureRenderedFrame();
Assert.NotNull(frame);
}
}

6
tests/Avalonia.Headless.UnitTests/TestApplication.cs

@ -1,12 +1,12 @@
using Avalonia.Headless.XUnit;
using Avalonia.Headless.XUnit.Tests;
using Avalonia.Headless.UnitTests;
using Avalonia.Headless.XUnit;
using Avalonia.Themes.Simple;
using Xunit;
[assembly: AvaloniaTestFramework(typeof(TestApplication))]
[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace Avalonia.Headless.XUnit.Tests;
namespace Avalonia.Headless.UnitTests;
public class TestApplication : Application
{

2
tests/Avalonia.Headless.UnitTests/ThreadingTests.cs

@ -4,7 +4,7 @@ using System.Threading.Tasks;
using Avalonia.Threading;
using Xunit;
namespace Avalonia.Headless.XUnit.Tests;
namespace Avalonia.Headless.UnitTests;
public class ThreadingTests
{

Loading…
Cancel
Save