A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

212 lines
8.0 KiB

using System;
using System.Collections.Generic;
using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Metadata;
using Avalonia.VisualTree;
namespace Avalonia.Input
{
public class PointerEventArgs : RoutedEventArgs
{
private readonly Visual? _rootVisual;
private readonly Point _rootVisualPosition;
private readonly PointerPointProperties _properties;
private readonly Lazy<IReadOnlyList<RawPointerPoint>?>? _previousPoints;
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
public PointerEventArgs(RoutedEvent routedEvent,
object? source,
IPointer pointer,
Visual? rootVisual, Point rootVisualPosition,
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers)
: base(routedEvent)
{
Source = source;
_rootVisual = rootVisual;
_rootVisualPosition = rootVisualPosition;
_properties = properties;
Pointer = pointer;
Timestamp = timestamp;
KeyModifiers = modifiers;
}
internal PointerEventArgs(RoutedEvent routedEvent,
object? source,
IPointer pointer,
Visual? rootVisual, Point rootVisualPosition,
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers,
Lazy<IReadOnlyList<RawPointerPoint>?>? previousPoints)
#pragma warning disable CS0618
: this(routedEvent, source, pointer, rootVisual, rootVisualPosition, timestamp, properties, modifiers)
#pragma warning restore CS0618
{
_previousPoints = previousPoints;
}
/// <summary>
/// Gets specific pointer generated by input device.
/// </summary>
public IPointer Pointer { get; }
/// <summary>
/// Gets the time when the input occurred.
/// </summary>
public ulong Timestamp { get; }
internal bool IsGestureRecognitionSkipped
{
get
{
return (Pointer as Pointer)?.IsGestureRecognitionSkipped ?? false;
}
private set
{
if (Pointer is Pointer pointer)
pointer.IsGestureRecognitionSkipped = true;
}
}
/// <summary>
/// Gets a value that indicates which key modifiers were active at the time that the pointer event was initiated.
/// </summary>
public KeyModifiers KeyModifiers { get; }
private Point GetPosition(Point pt, Visual? relativeTo)
{
if (_rootVisual == null)
return default;
if (relativeTo == null)
return pt;
// If the visual the user passed in, is not connected to the same visual root
// (i.e. they called it for a control inside a popup.
if (!ReferenceEquals(_rootVisual, relativeTo.VisualRoot) && relativeTo.VisualRoot is { })
{
// Convert to absolute screen coordinates.
var screenPt = _rootVisual.PointToScreen(pt);
// Convert to client co-ordinates of the visual inside the other visual root.
return relativeTo.PointToClient(screenPt);
}
return pt * _rootVisual.TransformToVisual(relativeTo) ?? default;
}
/// <summary>
/// Gets the pointer position relative to a control.
/// </summary>
/// <param name="relativeTo">The visual whose coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns>The pointer position in the control's coordinates.</returns>
public Point GetPosition(Visual? relativeTo) => GetPosition(_rootVisualPosition, relativeTo);
/// <summary>
/// Returns the PointerPoint associated with the current event
/// </summary>
/// <param name="relativeTo">The visual whose coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns></returns>
public PointerPoint GetCurrentPoint(Visual? relativeTo)
=> new PointerPoint(Pointer, GetPosition(relativeTo), _properties);
/// <summary>
/// Returns the PointerPoint associated with the current event
/// </summary>
/// <param name="relativeTo">The visual which coordinate system to use. Pass null for toplevel coordinate system</param>
/// <returns></returns>
public IReadOnlyList<PointerPoint> GetIntermediatePoints(Visual? relativeTo)
{
var previousPoints = _previousPoints?.Value;
if (previousPoints == null || previousPoints.Count == 0)
return new[] { GetCurrentPoint(relativeTo) };
var points = new PointerPoint[previousPoints.Count + 1];
for (var c = 0; c < previousPoints.Count; c++)
{
var pt = previousPoints[c];
var pointProperties = new PointerPointProperties(_properties, pt);
points[c] = new PointerPoint(Pointer, GetPosition(pt.Position, relativeTo), pointProperties);
}
points[points.Length - 1] = GetCurrentPoint(relativeTo);
return points;
}
/// <summary>
/// Prevents this event from being handled by other gesture recognizers in the route
/// </summary>
public void PreventGestureRecognition()
{
IsGestureRecognitionSkipped = true;
}
/// <summary>
/// Gets the state the pointer device had when this event occurred.
/// </summary>
public PointerPointProperties Properties => _properties;
}
public enum MouseButton
{
None,
Left,
Right,
Middle,
XButton1,
XButton2
}
public class PointerPressedEventArgs : PointerEventArgs
{
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
public PointerPressedEventArgs(
object source,
IPointer pointer,
Visual rootVisual, Point rootVisualPosition,
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers,
int clickCount = 1)
: base(InputElement.PointerPressedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers)
{
ClickCount = clickCount;
}
public int ClickCount { get; }
}
public class PointerReleasedEventArgs : PointerEventArgs
{
[Unstable("This constructor might be removed in 12.0. For unit testing, consider using IHeadlessWindow mouse methods.")]
public PointerReleasedEventArgs(
object source, IPointer pointer,
Visual rootVisual, Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, KeyModifiers modifiers,
MouseButton initialPressMouseButton)
: base(InputElement.PointerReleasedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers)
{
InitialPressMouseButton = initialPressMouseButton;
}
/// <summary>
/// Gets the mouse button that triggered the corresponding PointerPressed event
/// </summary>
public MouseButton InitialPressMouseButton { get; }
}
public class PointerCaptureLostEventArgs : RoutedEventArgs
{
public IPointer Pointer { get; }
[Unstable("This constructor might be removed in 12.0. If you need to remove capture, use stable methods on the IPointer instance.,")]
public PointerCaptureLostEventArgs(object source, IPointer pointer) : base(InputElement.PointerCaptureLostEvent)
{
Pointer = pointer;
Source = source;
}
}
}