180 changed files with 3070 additions and 2486 deletions
@ -1,7 +1,7 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="HarfBuzzSharp" Version="2.8.2" /> |
<PackageReference Include="HarfBuzzSharp" Version="2.8.2.1-preview.108" /> |
||||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2" /> |
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2.1-preview.108" /> |
||||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2" /> |
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.WebAssembly" Version="2.8.2.1-preview.108" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,5 +1,5 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="ReactiveUI" Version="13.2.10" /> |
<PackageReference Include="ReactiveUI" Version="18.3.1" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,7 +1,7 @@ |
|||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ItemGroup> |
<ItemGroup> |
||||
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1" /> |
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.108" /> |
||||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1-preview.1" /> |
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.88.1-preview.108" /> |
||||
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.1-preview.1" /> |
<PackageReference Condition="'$(IncludeWasmSkia)' == 'true'" Include="SkiaSharp.NativeAssets.WebAssembly" Version="2.88.1-preview.108" /> |
||||
</ItemGroup> |
</ItemGroup> |
||||
</Project> |
</Project> |
||||
|
|||||
@ -1,134 +1,141 @@ |
|||||
<UserControl |
<UserControl |
||||
xmlns="https://github.com/avaloniaui" |
xmlns="https://github.com/avaloniaui" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
x:Class="RenderDemo.Pages.DrawingPage"> |
x:Class="RenderDemo.Pages.DrawingPage"> |
||||
<UserControl.Styles> |
<UserControl.Styles> |
||||
<Style> |
<Style> |
||||
<Style.Resources> |
<Style.Resources> |
||||
<DrawingGroup x:Key="Bulb"> |
<DrawingGroup x:Key="Bulb"> |
||||
<DrawingGroup.Transform> |
<DrawingGroup.Transform> |
||||
<MatrixTransform Matrix="1,0,0,1,0,-1028.4" /> |
<MatrixTransform Matrix="1,0,0,1,0,-1028.4" /> |
||||
</DrawingGroup.Transform> |
</DrawingGroup.Transform> |
||||
<DrawingGroup> |
<DrawingGroup> |
||||
<DrawingGroup.Transform> |
<DrawingGroup.Transform> |
||||
<MatrixTransform Matrix="1,0,0,1.25,-10,1031.4" /> |
<MatrixTransform Matrix="1,0,0,1.25,-10,1031.4" /> |
||||
</DrawingGroup.Transform> |
</DrawingGroup.Transform> |
||||
<GeometryDrawing Brush="#FF7F8C8D" |
<GeometryDrawing Brush="#FF7F8C8D" |
||||
Geometry="F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z" /> |
Geometry="F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z" /> |
||||
</DrawingGroup> |
</DrawingGroup> |
||||
<GeometryDrawing Brush="#FFF39C12" |
<GeometryDrawing Brush="#FFF39C12" |
||||
Geometry="F1 M12,1030.4 C8.134,1030.4 5,1033.6 5,1037.6 5,1040.7 8.125,1043.5 9,1045.4 9.875,1047.2 9,1050.4 9,1050.4 L12,1049.9 15,1050.4 C15,1050.4 14.125,1047.2 15,1045.4 15.875,1043.5 19,1040.7 19,1037.6 19,1033.6 15.866,1030.4 12,1030.4 z" /> |
Geometry="F1 M12,1030.4 C8.134,1030.4 5,1033.6 5,1037.6 5,1040.7 8.125,1043.5 9,1045.4 9.875,1047.2 9,1050.4 9,1050.4 L12,1049.9 15,1050.4 C15,1050.4 14.125,1047.2 15,1045.4 15.875,1043.5 19,1040.7 19,1037.6 19,1033.6 15.866,1030.4 12,1030.4 z" /> |
||||
<GeometryDrawing Brush="#FFF1C40F" |
<GeometryDrawing Brush="#FFF1C40F" |
||||
Geometry="F1 M12,1030.4 C15.866,1030.4 19,1033.6 19,1037.6 19,1040.7 15.875,1043.5 15,1045.4 14.125,1047.2 15,1050.4 15,1050.4 L12,1049.9 12,1030.4 z" /> |
Geometry="F1 M12,1030.4 C15.866,1030.4 19,1033.6 19,1037.6 19,1040.7 15.875,1043.5 15,1045.4 14.125,1047.2 15,1050.4 15,1050.4 L12,1049.9 12,1030.4 z" /> |
||||
<GeometryDrawing Brush="#FFE67E22" |
<GeometryDrawing Brush="#FFE67E22" |
||||
Geometry="F1 M9,1036.4 L8,1037.4 12,1049.4 16,1037.4 15,1036.4 14,1037.4 13,1036.4 12,1037.4 11,1036.4 10,1037.4 9,1036.4 z M9,1037.4 L10,1038.4 10.5,1037.9 11,1037.4 11.5,1037.9 12,1038.4 12.5,1037.9 13,1037.4 13.5,1037.9 14,1038.4 15,1037.4 15.438,1037.8 12,1048.1 8.5625,1037.8 9,1037.4 z" /> |
Geometry="F1 M9,1036.4 L8,1037.4 12,1049.4 16,1037.4 15,1036.4 14,1037.4 13,1036.4 12,1037.4 11,1036.4 10,1037.4 9,1036.4 z M9,1037.4 L10,1038.4 10.5,1037.9 11,1037.4 11.5,1037.9 12,1038.4 12.5,1037.9 13,1037.4 13.5,1037.9 14,1038.4 15,1037.4 15.438,1037.8 12,1048.1 8.5625,1037.8 9,1037.4 z" /> |
||||
<DrawingGroup> |
<DrawingGroup> |
||||
<DrawingGroup.Transform> |
<DrawingGroup.Transform> |
||||
<MatrixTransform Matrix="1,0,0,1,9,1045.4" /> |
<MatrixTransform Matrix="1,0,0,1,9,1045.4" /> |
||||
</DrawingGroup.Transform> |
</DrawingGroup.Transform> |
||||
<GeometryDrawing Brush="#FFBDC3C7"> |
<GeometryDrawing Brush="#FFBDC3C7"> |
||||
<GeometryDrawing.Geometry> |
<GeometryDrawing.Geometry> |
||||
<RectangleGeometry Rect="0,0,6,5" /> |
<RectangleGeometry Rect="0,0,6,5" /> |
||||
</GeometryDrawing.Geometry> |
</GeometryDrawing.Geometry> |
||||
</GeometryDrawing> |
</GeometryDrawing> |
||||
</DrawingGroup> |
</DrawingGroup> |
||||
<GeometryDrawing Brush="#FF95A5A6" |
<GeometryDrawing Brush="#FF95A5A6" |
||||
Geometry="F1 M9,1045.4 L9,1050.4 12,1050.4 12,1049.4 15,1049.4 15,1048.4 12,1048.4 12,1047.4 15,1047.4 15,1046.4 12,1046.4 12,1045.4 9,1045.4 z" /> |
Geometry="F1 M9,1045.4 L9,1050.4 12,1050.4 12,1049.4 15,1049.4 15,1048.4 12,1048.4 12,1047.4 15,1047.4 15,1046.4 12,1046.4 12,1045.4 9,1045.4 z" /> |
||||
<GeometryDrawing Brush="#FF7F8C8D" |
<GeometryDrawing Brush="#FF7F8C8D" |
||||
Geometry="F1 M9,1046.4 L9,1047.4 12,1047.4 12,1046.4 9,1046.4 z M9,1048.4 L9,1049.4 12,1049.4 12,1048.4 9,1048.4 z" /> |
Geometry="F1 M9,1046.4 L9,1047.4 12,1047.4 12,1046.4 9,1046.4 z M9,1048.4 L9,1049.4 12,1049.4 12,1048.4 9,1048.4 z" /> |
||||
</DrawingGroup> |
</DrawingGroup> |
||||
</Style.Resources> |
</Style.Resources> |
||||
</Style> |
</Style> |
||||
</UserControl.Styles> |
</UserControl.Styles> |
||||
<Grid RowDefinitions="Auto,Auto,Auto" |
<Grid RowDefinitions="Auto,Auto,Auto" |
||||
ColumnDefinitions="Auto,Auto,Auto,Auto"> |
ColumnDefinitions="Auto,Auto,Auto,Auto"> |
||||
<TextBlock Text="None" |
<TextBlock Text="None" |
||||
Margin="3" /> |
Margin="3" /> |
||||
<Border Grid.Column="0" |
<Border Grid.Column="0" |
||||
Grid.Row="1" |
Grid.Row="1" |
||||
VerticalAlignment="Top" |
VerticalAlignment="Top" |
||||
HorizontalAlignment="Left" |
HorizontalAlignment="Left" |
||||
BorderThickness="1" |
BorderThickness="1" |
||||
BorderBrush="Gray" |
BorderBrush="Gray" |
||||
Margin="5"> |
Margin="5"> |
||||
<DrawingPresenter Drawing="{DynamicResource Bulb}" /> |
<Image> |
||||
</Border> |
<Image.Source> |
||||
<TextBlock Text="Fill" |
<DrawingImage Drawing="{DynamicResource Bulb}" /> |
||||
Margin="3" |
</Image.Source> |
||||
Grid.Column="1" /> |
</Image> |
||||
<Border Grid.Column="1" |
</Border> |
||||
Grid.Row="1" |
<TextBlock Text="Fill" |
||||
VerticalAlignment="Top" |
Margin="3" |
||||
HorizontalAlignment="Left" |
Grid.Column="1" /> |
||||
BorderThickness="1" |
<Border Grid.Column="1" |
||||
BorderBrush="Gray" |
Grid.Row="1" |
||||
Margin="5"> |
VerticalAlignment="Top" |
||||
<DrawingPresenter Drawing="{DynamicResource Bulb}" |
HorizontalAlignment="Left" |
||||
Width="100" |
BorderThickness="1" |
||||
Height="50" |
BorderBrush="Gray" |
||||
Stretch="Fill" /> |
Margin="5"> |
||||
</Border> |
<Image Width="100" Height="50" Stretch="Fill"> |
||||
<TextBlock Text="Uniform" |
<Image.Source> |
||||
Margin="3" |
<DrawingImage Drawing="{DynamicResource Bulb}" /> |
||||
Grid.Column="2" /> |
</Image.Source> |
||||
<Border Grid.Column="2" |
</Image> |
||||
Grid.Row="1" |
</Border> |
||||
VerticalAlignment="Top" |
<TextBlock Text="Uniform" |
||||
HorizontalAlignment="Left" |
Margin="3" |
||||
BorderThickness="1" |
Grid.Column="2" /> |
||||
BorderBrush="Gray" |
<Border Grid.Column="2" |
||||
Margin="5"> |
Grid.Row="1" |
||||
<DrawingPresenter Drawing="{DynamicResource Bulb}" |
VerticalAlignment="Top" |
||||
Width="100" |
HorizontalAlignment="Left" |
||||
Height="50" |
BorderThickness="1" |
||||
Stretch="Uniform" /> |
BorderBrush="Gray" |
||||
</Border> |
Margin="5"> |
||||
<TextBlock Text="UniformToFill" |
<Image Width="100" Height="50" Stretch="Uniform"> |
||||
Margin="3" |
<Image.Source> |
||||
Grid.Column="3" /> |
<DrawingImage Drawing="{DynamicResource Bulb}" /> |
||||
<Border Grid.Column="3" |
</Image.Source> |
||||
Grid.Row="1" |
</Image> |
||||
VerticalAlignment="Top" |
</Border> |
||||
HorizontalAlignment="Left" |
<TextBlock Text="UniformToFill" |
||||
BorderThickness="1" |
Margin="3" |
||||
BorderBrush="Gray" |
Grid.Column="3" /> |
||||
Margin="5"> |
<Border Grid.Column="3" |
||||
<DrawingPresenter Drawing="{DynamicResource Bulb}" |
Grid.Row="1" |
||||
Width="100" |
VerticalAlignment="Top" |
||||
Height="50" |
HorizontalAlignment="Left" |
||||
Stretch="UniformToFill" /> |
BorderThickness="1" |
||||
</Border> |
BorderBrush="Gray" |
||||
|
Margin="5"> |
||||
|
<Image Width="100" Height="50" Stretch="UniformToFill"> |
||||
|
<Image.Source> |
||||
|
<DrawingImage Drawing="{DynamicResource Bulb}" /> |
||||
|
</Image.Source> |
||||
|
</Image> |
||||
|
</Border> |
||||
|
|
||||
<!-- For comparison --> |
<!-- For comparison --> |
||||
|
|
||||
<Ellipse Grid.Row="2" |
<Ellipse Grid.Row="2" |
||||
Grid.Column="0" |
Grid.Column="0" |
||||
Width="100" |
Width="100" |
||||
Height="50" |
Height="50" |
||||
Stretch="None" |
Stretch="None" |
||||
Fill="Blue" |
Fill="Blue" |
||||
Margin="5"/> |
Margin="5"/> |
||||
<Ellipse Grid.Row="2" |
<Ellipse Grid.Row="2" |
||||
Grid.Column="1" |
Grid.Column="1" |
||||
Width="100" |
Width="100" |
||||
Height="50" |
Height="50" |
||||
Stretch="Fill" |
Stretch="Fill" |
||||
Fill="Blue" |
Fill="Blue" |
||||
Margin="5" /> |
Margin="5" /> |
||||
<Ellipse Grid.Row="2" |
<Ellipse Grid.Row="2" |
||||
Grid.Column="2" |
Grid.Column="2" |
||||
Width="100" |
Width="100" |
||||
Height="50" |
Height="50" |
||||
Stretch="Uniform" |
Stretch="Uniform" |
||||
Fill="Blue" |
Fill="Blue" |
||||
Margin="5" /> |
Margin="5" /> |
||||
<Ellipse Grid.Row="2" |
<Ellipse Grid.Row="2" |
||||
Grid.Column="3" |
Grid.Column="3" |
||||
Width="100" |
Width="100" |
||||
Height="50" |
Height="50" |
||||
Stretch="UniformToFill" |
Stretch="UniformToFill" |
||||
Fill="Blue" |
Fill="Blue" |
||||
Margin="5" /> |
Margin="5" /> |
||||
|
|
||||
</Grid> |
</Grid> |
||||
</UserControl> |
</UserControl> |
||||
|
|||||
@ -0,0 +1,251 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
using Android.Views; |
||||
|
|
||||
|
using Avalonia.Android.Platform.SkiaPlatform; |
||||
|
using Avalonia.Collections.Pooled; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Input.Raw; |
||||
|
|
||||
|
#nullable enable |
||||
|
|
||||
|
namespace Avalonia.Android.Platform.Specific.Helpers |
||||
|
{ |
||||
|
internal class AndroidMotionEventsHelper : IDisposable |
||||
|
{ |
||||
|
private static readonly PooledList<RawPointerPoint> s_intermediatePointsPooledList = new(ClearMode.Never); |
||||
|
private static readonly float s_radiansToDegree = (float)(180f * Math.PI); |
||||
|
private readonly TouchDevice _touchDevice; |
||||
|
private readonly MouseDevice _mouseDevice; |
||||
|
private readonly PenDevice _penDevice; |
||||
|
private readonly TopLevelImpl _view; |
||||
|
private bool _disposed; |
||||
|
|
||||
|
public AndroidMotionEventsHelper(TopLevelImpl view) |
||||
|
{ |
||||
|
_touchDevice = new TouchDevice(); |
||||
|
_penDevice = new PenDevice(); |
||||
|
_mouseDevice = new MouseDevice(); |
||||
|
_view = view; |
||||
|
} |
||||
|
|
||||
|
public bool? DispatchMotionEvent(MotionEvent e, out bool callBase) |
||||
|
{ |
||||
|
callBase = true; |
||||
|
if (_disposed) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var eventTime = (ulong)DateTime.Now.Millisecond; |
||||
|
var inputRoot = _view.InputRoot; |
||||
|
var actionMasked = e.ActionMasked; |
||||
|
var modifiers = GetModifiers(e.MetaState, e.ButtonState); |
||||
|
|
||||
|
if (actionMasked == MotionEventActions.Move) |
||||
|
{ |
||||
|
for (int index = 0; index < e.PointerCount; index++) |
||||
|
{ |
||||
|
var toolType = e.GetToolType(index); |
||||
|
var device = GetDevice(toolType); |
||||
|
var eventType = toolType == MotionEventToolType.Finger ? RawPointerEventType.TouchUpdate : RawPointerEventType.Move; |
||||
|
var point = CreatePoint(e, index); |
||||
|
modifiers |= GetToolModifiers(toolType); |
||||
|
|
||||
|
// ButtonState reports only mouse buttons, but not touch or stylus pointer.
|
||||
|
if (toolType != MotionEventToolType.Mouse) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.LeftMouseButton; |
||||
|
} |
||||
|
|
||||
|
var args = new RawTouchEventArgs(device, eventTime, inputRoot, eventType, point, modifiers, e.GetPointerId(index)) |
||||
|
{ |
||||
|
IntermediatePoints = new Lazy<IReadOnlyList<RawPointerPoint>?>(() => |
||||
|
{ |
||||
|
var site = e.HistorySize; |
||||
|
s_intermediatePointsPooledList.Clear(); |
||||
|
s_intermediatePointsPooledList.Capacity = site; |
||||
|
|
||||
|
for (int pos = 0; pos < site; pos++) |
||||
|
{ |
||||
|
s_intermediatePointsPooledList.Add(CreateHistoricalPoint(e, index, pos)); |
||||
|
} |
||||
|
|
||||
|
return s_intermediatePointsPooledList; |
||||
|
}) |
||||
|
}; |
||||
|
_view.Input(args); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var index = e.ActionIndex; |
||||
|
var toolType = e.GetToolType(index); |
||||
|
var device = GetDevice(toolType); |
||||
|
modifiers |= GetToolModifiers(toolType); |
||||
|
var point = CreatePoint(e, index); |
||||
|
|
||||
|
if (actionMasked == MotionEventActions.Scroll && toolType == MotionEventToolType.Mouse) |
||||
|
{ |
||||
|
var delta = new Vector(e.GetAxisValue(Axis.Hscroll), e.GetAxisValue(Axis.Vscroll)); |
||||
|
var args = new RawMouseWheelEventArgs(device, eventTime, inputRoot, point.Position, delta, RawInputModifiers.None); |
||||
|
_view.Input(args); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var eventType = GetActionType(e, actionMasked, toolType); |
||||
|
if (eventType >= 0) |
||||
|
{ |
||||
|
var args = new RawTouchEventArgs(device, eventTime, inputRoot, eventType, point, modifiers, e.GetPointerId(index)); |
||||
|
_view.Input(args); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private static RawInputModifiers GetModifiers(MetaKeyStates metaState, MotionEventButtonState buttonState) |
||||
|
{ |
||||
|
var modifiers = RawInputModifiers.None; |
||||
|
if (metaState.HasAnyFlag(MetaKeyStates.ShiftOn)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.Shift; |
||||
|
} |
||||
|
if (metaState.HasAnyFlag(MetaKeyStates.CtrlOn)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.Control; |
||||
|
} |
||||
|
if (metaState.HasAnyFlag(MetaKeyStates.AltOn)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.Alt; |
||||
|
} |
||||
|
if (metaState.HasAnyFlag(MetaKeyStates.MetaOn)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.Meta; |
||||
|
} |
||||
|
if (buttonState.HasAnyFlag(MotionEventButtonState.Primary)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.LeftMouseButton; |
||||
|
} |
||||
|
if (buttonState.HasAnyFlag(MotionEventButtonState.Secondary)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.RightMouseButton; |
||||
|
} |
||||
|
if (buttonState.HasAnyFlag(MotionEventButtonState.Tertiary)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.MiddleMouseButton; |
||||
|
} |
||||
|
if (buttonState.HasAnyFlag(MotionEventButtonState.Back)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.XButton1MouseButton; |
||||
|
} |
||||
|
if (buttonState.HasAnyFlag(MotionEventButtonState.Forward)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.XButton2MouseButton; |
||||
|
} |
||||
|
if (buttonState.HasAnyFlag(MotionEventButtonState.StylusPrimary)) |
||||
|
{ |
||||
|
modifiers |= RawInputModifiers.PenBarrelButton; |
||||
|
} |
||||
|
return modifiers; |
||||
|
} |
||||
|
|
||||
|
#pragma warning disable CA1416 // Validate platform compatibility
|
||||
|
private static RawPointerEventType GetActionType(MotionEvent e, MotionEventActions actionMasked, MotionEventToolType toolType) |
||||
|
{ |
||||
|
var isTouch = toolType == MotionEventToolType.Finger; |
||||
|
var isMouse = toolType == MotionEventToolType.Mouse; |
||||
|
switch (actionMasked) |
||||
|
{ |
||||
|
// DOWN
|
||||
|
case MotionEventActions.Down when !isMouse: |
||||
|
case MotionEventActions.PointerDown when !isMouse: |
||||
|
return isTouch ? RawPointerEventType.TouchBegin : RawPointerEventType.LeftButtonDown; |
||||
|
case MotionEventActions.ButtonPress: |
||||
|
return e.ActionButton switch |
||||
|
{ |
||||
|
MotionEventButtonState.Back => RawPointerEventType.XButton1Down, |
||||
|
MotionEventButtonState.Forward => RawPointerEventType.XButton2Down, |
||||
|
MotionEventButtonState.Primary => RawPointerEventType.LeftButtonDown, |
||||
|
MotionEventButtonState.Secondary => RawPointerEventType.RightButtonDown, |
||||
|
MotionEventButtonState.StylusPrimary => RawPointerEventType.LeftButtonDown, |
||||
|
MotionEventButtonState.StylusSecondary => RawPointerEventType.RightButtonDown, |
||||
|
MotionEventButtonState.Tertiary => RawPointerEventType.MiddleButtonDown, |
||||
|
_ => RawPointerEventType.LeftButtonDown |
||||
|
}; |
||||
|
// UP
|
||||
|
case MotionEventActions.Up when !isMouse: |
||||
|
case MotionEventActions.PointerUp when !isMouse: |
||||
|
return isTouch ? RawPointerEventType.TouchEnd : RawPointerEventType.LeftButtonUp; |
||||
|
case MotionEventActions.ButtonRelease: |
||||
|
return e.ActionButton switch |
||||
|
{ |
||||
|
MotionEventButtonState.Back => RawPointerEventType.XButton1Up, |
||||
|
MotionEventButtonState.Forward => RawPointerEventType.XButton2Up, |
||||
|
MotionEventButtonState.Primary => RawPointerEventType.LeftButtonUp, |
||||
|
MotionEventButtonState.Secondary => RawPointerEventType.RightButtonUp, |
||||
|
MotionEventButtonState.StylusPrimary => RawPointerEventType.LeftButtonUp, |
||||
|
MotionEventButtonState.StylusSecondary => RawPointerEventType.RightButtonUp, |
||||
|
MotionEventButtonState.Tertiary => RawPointerEventType.MiddleButtonUp, |
||||
|
_ => RawPointerEventType.LeftButtonUp |
||||
|
}; |
||||
|
// MOVE
|
||||
|
case MotionEventActions.Outside: |
||||
|
case MotionEventActions.HoverMove: |
||||
|
case MotionEventActions.Move: |
||||
|
return isTouch ? RawPointerEventType.TouchUpdate : RawPointerEventType.Move; |
||||
|
// CANCEL
|
||||
|
case MotionEventActions.Cancel: |
||||
|
return isTouch ? RawPointerEventType.TouchCancel : RawPointerEventType.LeaveWindow; |
||||
|
default: |
||||
|
return (RawPointerEventType)(-1); |
||||
|
} |
||||
|
} |
||||
|
#pragma warning restore CA1416 // Validate platform compatibility
|
||||
|
|
||||
|
private IPointerDevice GetDevice(MotionEventToolType type) |
||||
|
{ |
||||
|
return type switch |
||||
|
{ |
||||
|
MotionEventToolType.Mouse => _mouseDevice, |
||||
|
MotionEventToolType.Stylus => _penDevice, |
||||
|
MotionEventToolType.Eraser => _penDevice, |
||||
|
MotionEventToolType.Finger => _touchDevice, |
||||
|
_ => _touchDevice |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private RawPointerPoint CreatePoint(MotionEvent e, int index) |
||||
|
{ |
||||
|
return new RawPointerPoint |
||||
|
{ |
||||
|
Position = new Point(e.GetX(index), e.GetY(index)) / _view.RenderScaling, |
||||
|
Pressure = Math.Min(e.GetPressure(index), 1), // android pressure can depend on the device, can be mixed up with "GetSize", may be larger than 1.0f on some devices
|
||||
|
Twist = e.GetOrientation(index) * s_radiansToDegree |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private RawPointerPoint CreateHistoricalPoint(MotionEvent e, int index, int pos) |
||||
|
{ |
||||
|
return new RawPointerPoint |
||||
|
{ |
||||
|
Position = new Point(e.GetHistoricalX(index, pos), e.GetHistoricalY(index, pos)) / _view.RenderScaling, |
||||
|
Pressure = Math.Min(e.GetHistoricalPressure(index, pos), 1), |
||||
|
Twist = e.GetHistoricalOrientation(index, pos) * s_radiansToDegree |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
private static RawInputModifiers GetToolModifiers(MotionEventToolType toolType) |
||||
|
{ |
||||
|
// Android "Eraser" indicates Inverted pen OR actual Eraser. So we have to go both here.
|
||||
|
return toolType == MotionEventToolType.Eraser ? RawInputModifiers.PenInverted | RawInputModifiers.PenEraser : RawInputModifiers.None; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
_disposed = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,85 +0,0 @@ |
|||||
using System; |
|
||||
using Android.Views; |
|
||||
using Avalonia.Input; |
|
||||
using Avalonia.Input.Raw; |
|
||||
using Avalonia.Platform; |
|
||||
|
|
||||
namespace Avalonia.Android.Platform.Specific.Helpers |
|
||||
{ |
|
||||
public class AndroidTouchEventsHelper<TView> : IDisposable where TView : ITopLevelImpl, IAndroidView |
|
||||
{ |
|
||||
private TView _view; |
|
||||
public bool HandleEvents { get; set; } |
|
||||
|
|
||||
public AndroidTouchEventsHelper(TView view, Func<IInputRoot> getInputRoot, Func<MotionEvent, int, Point> getPointfunc) |
|
||||
{ |
|
||||
this._view = view; |
|
||||
HandleEvents = true; |
|
||||
_getPointFunc = getPointfunc; |
|
||||
_getInputRoot = getInputRoot; |
|
||||
} |
|
||||
|
|
||||
private TouchDevice _touchDevice = new TouchDevice(); |
|
||||
private Func<MotionEvent, int, Point> _getPointFunc; |
|
||||
private Func<IInputRoot> _getInputRoot; |
|
||||
|
|
||||
public bool? DispatchTouchEvent(MotionEvent e, out bool callBase) |
|
||||
{ |
|
||||
if (!HandleEvents) |
|
||||
{ |
|
||||
callBase = true; |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
var eventTime = DateTime.Now; |
|
||||
|
|
||||
//Basic touch support
|
|
||||
var pointerEventType = e.Action switch |
|
||||
{ |
|
||||
MotionEventActions.Down => RawPointerEventType.TouchBegin, |
|
||||
MotionEventActions.Up => RawPointerEventType.TouchEnd, |
|
||||
MotionEventActions.Cancel => RawPointerEventType.TouchCancel, |
|
||||
_ => RawPointerEventType.TouchUpdate |
|
||||
}; |
|
||||
|
|
||||
if (e.Action.HasFlag(MotionEventActions.PointerDown)) |
|
||||
{ |
|
||||
pointerEventType = RawPointerEventType.TouchBegin; |
|
||||
} |
|
||||
|
|
||||
if (e.Action.HasFlag(MotionEventActions.PointerUp)) |
|
||||
{ |
|
||||
pointerEventType = RawPointerEventType.TouchEnd; |
|
||||
} |
|
||||
|
|
||||
for (int i = 0; i < e.PointerCount; i++) |
|
||||
{ |
|
||||
//if point is in view otherwise it's possible avalonia not to find the proper window to dispatch the event
|
|
||||
var point = _getPointFunc(e, i); |
|
||||
|
|
||||
double x = _view.View.GetX(); |
|
||||
double y = _view.View.GetY(); |
|
||||
double r = x + _view.View.Width; |
|
||||
double b = y + _view.View.Height; |
|
||||
|
|
||||
if (x <= point.X && r >= point.X && y <= point.Y && b >= point.Y) |
|
||||
{ |
|
||||
var inputRoot = _getInputRoot(); |
|
||||
|
|
||||
var mouseEvent = new RawTouchEventArgs(_touchDevice, (uint)eventTime.Ticks, inputRoot, |
|
||||
i == e.ActionIndex ? pointerEventType : RawPointerEventType.TouchUpdate, point, RawInputModifiers.None, e.GetPointerId(i)); |
|
||||
_view.Input(mouseEvent); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
callBase = true; |
|
||||
//if return false events for move and up are not received!!!
|
|
||||
return e.Action != MotionEventActions.Up; |
|
||||
} |
|
||||
|
|
||||
public void Dispose() |
|
||||
{ |
|
||||
HandleEvents = false; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace Avalonia.Controls.Templates |
||||
|
{ |
||||
|
public interface ITemplateResult |
||||
|
{ |
||||
|
public object? Result { get; } |
||||
|
public INameScope NameScope { get; } |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,10 @@ |
|||||
namespace Avalonia.Controls.Templates |
namespace Avalonia.Controls.Templates |
||||
{ |
{ |
||||
public class TemplateResult<T> |
public class TemplateResult<T> : ITemplateResult |
||||
{ |
{ |
||||
public T Result { get; } |
public T Result { get; } |
||||
public INameScope NameScope { get; } |
public INameScope NameScope { get; } |
||||
|
object? ITemplateResult.Result => Result; |
||||
|
|
||||
public TemplateResult(T result, INameScope nameScope) |
public TemplateResult(T result, INameScope nameScope) |
||||
{ |
{ |
||||
@ -1,193 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Reflection; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
|
|
||||
namespace Avalonia.Utilities |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Manages subscriptions to events using weak listeners.
|
|
||||
/// </summary>
|
|
||||
public static class WeakSubscriptionManager |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Subscribes to an event on an object using a weak subscription.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TTarget">The type of the target.</typeparam>
|
|
||||
/// <typeparam name="TEventArgs">The type of the event arguments.</typeparam>
|
|
||||
/// <param name="target">The event source.</param>
|
|
||||
/// <param name="eventName">The name of the event.</param>
|
|
||||
/// <param name="subscriber">The subscriber.</param>
|
|
||||
[Obsolete("Use WeakEvent")] |
|
||||
public static void Subscribe<TTarget, TEventArgs>(TTarget target, string eventName, IWeakSubscriber<TEventArgs> subscriber) |
|
||||
where TEventArgs : EventArgs |
|
||||
{ |
|
||||
_ = target ?? throw new ArgumentNullException(nameof(target)); |
|
||||
|
|
||||
var dic = SubscriptionTypeStorage<TEventArgs>.Subscribers.GetOrCreateValue(target); |
|
||||
|
|
||||
if (!dic.TryGetValue(eventName, out var sub)) |
|
||||
{ |
|
||||
dic[eventName] = sub = new Subscription<TEventArgs>(dic, typeof(TTarget), target, eventName); |
|
||||
} |
|
||||
|
|
||||
sub.Add(new WeakReference<IWeakSubscriber<TEventArgs>>(subscriber)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Unsubscribes from an event.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="T">The type of the event arguments.</typeparam>
|
|
||||
/// <param name="target">The event source.</param>
|
|
||||
/// <param name="eventName">The name of the event.</param>
|
|
||||
/// <param name="subscriber">The subscriber.</param>
|
|
||||
public static void Unsubscribe<T>(object target, string eventName, IWeakSubscriber<T> subscriber) |
|
||||
where T : EventArgs |
|
||||
{ |
|
||||
if (SubscriptionTypeStorage<T>.Subscribers.TryGetValue(target, out var dic)) |
|
||||
{ |
|
||||
if (dic.TryGetValue(eventName, out var sub)) |
|
||||
{ |
|
||||
sub.Remove(subscriber); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static class SubscriptionTypeStorage<T> |
|
||||
where T : EventArgs |
|
||||
{ |
|
||||
public static readonly ConditionalWeakTable<object, SubscriptionDic<T>> Subscribers |
|
||||
= new ConditionalWeakTable<object, SubscriptionDic<T>>(); |
|
||||
} |
|
||||
|
|
||||
private class SubscriptionDic<T> : Dictionary<string, Subscription<T>> |
|
||||
where T : EventArgs |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
private static readonly Dictionary<Type, Dictionary<string, EventInfo>> Accessors |
|
||||
= new Dictionary<Type, Dictionary<string, EventInfo>>(); |
|
||||
|
|
||||
private class Subscription<T> where T : EventArgs |
|
||||
{ |
|
||||
private readonly EventInfo _info; |
|
||||
private readonly SubscriptionDic<T> _sdic; |
|
||||
private readonly object _target; |
|
||||
private readonly string _eventName; |
|
||||
private readonly Delegate _delegate; |
|
||||
|
|
||||
private WeakReference<IWeakSubscriber<T>>?[] _data = new WeakReference<IWeakSubscriber<T>>?[16]; |
|
||||
private int _count = 0; |
|
||||
|
|
||||
public Subscription(SubscriptionDic<T> sdic, Type targetType, object target, string eventName) |
|
||||
{ |
|
||||
_sdic = sdic; |
|
||||
_target = target; |
|
||||
_eventName = eventName; |
|
||||
if (!Accessors.TryGetValue(targetType, out var evDic)) |
|
||||
Accessors[targetType] = evDic = new Dictionary<string, EventInfo>(); |
|
||||
|
|
||||
if (evDic.TryGetValue(eventName, out var info)) |
|
||||
{ |
|
||||
_info = info; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
var ev = targetType.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName); |
|
||||
|
|
||||
if (ev == null) |
|
||||
{ |
|
||||
throw new ArgumentException( |
|
||||
$"The event {eventName} was not found on {target.GetType()}."); |
|
||||
} |
|
||||
|
|
||||
evDic[eventName] = _info = ev; |
|
||||
} |
|
||||
|
|
||||
var del = new Action<object, T>(OnEvent); |
|
||||
_delegate = del.GetMethodInfo().CreateDelegate(_info.EventHandlerType!, del.Target); |
|
||||
_info.AddMethod!.Invoke(target, new[] { _delegate }); |
|
||||
} |
|
||||
|
|
||||
void Destroy() |
|
||||
{ |
|
||||
_info.RemoveMethod!.Invoke(_target, new[] { _delegate }); |
|
||||
_sdic.Remove(_eventName); |
|
||||
} |
|
||||
|
|
||||
public void Add(WeakReference<IWeakSubscriber<T>> s) |
|
||||
{ |
|
||||
if (_count == _data.Length) |
|
||||
{ |
|
||||
//Extend capacity
|
|
||||
var ndata = new WeakReference<IWeakSubscriber<T>>?[_data.Length*2]; |
|
||||
Array.Copy(_data, ndata, _data.Length); |
|
||||
_data = ndata; |
|
||||
} |
|
||||
_data[_count] = s!; |
|
||||
_count++; |
|
||||
} |
|
||||
|
|
||||
public void Remove(IWeakSubscriber<T> s) |
|
||||
{ |
|
||||
var removed = false; |
|
||||
|
|
||||
for (int c = 0; c < _count; ++c) |
|
||||
{ |
|
||||
var reference = _data[c]; |
|
||||
IWeakSubscriber<T>? instance; |
|
||||
|
|
||||
if (reference != null && reference.TryGetTarget(out instance) && instance == s) |
|
||||
{ |
|
||||
_data[c] = null; |
|
||||
removed = true; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (removed) |
|
||||
{ |
|
||||
Compact(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void Compact() |
|
||||
{ |
|
||||
int empty = -1; |
|
||||
for (int c = 0; c < _count; c++) |
|
||||
{ |
|
||||
var r = _data[c]; |
|
||||
//Mark current index as first empty
|
|
||||
if (r == null && empty == -1) |
|
||||
empty = c; |
|
||||
//If current element isn't null and we have an empty one
|
|
||||
if (r != null && empty != -1) |
|
||||
{ |
|
||||
_data[c] = null; |
|
||||
_data[empty] = r; |
|
||||
empty++; |
|
||||
} |
|
||||
} |
|
||||
if (empty != -1) |
|
||||
_count = empty; |
|
||||
if (_count == 0) |
|
||||
Destroy(); |
|
||||
} |
|
||||
|
|
||||
void OnEvent(object sender, T eventArgs) |
|
||||
{ |
|
||||
var needCompact = false; |
|
||||
for(var c=0; c<_count; c++) |
|
||||
{ |
|
||||
var r = _data[c]; |
|
||||
if (r?.TryGetTarget(out var sub) == true) |
|
||||
sub!.OnEvent(sender, eventArgs); |
|
||||
else |
|
||||
needCompact = true; |
|
||||
} |
|
||||
if (needCompact) |
|
||||
Compact(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
using System; |
|
||||
|
|
||||
namespace Avalonia.VisualTree |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Interface for controls that host their own separate visual tree, such as popups.
|
|
||||
/// </summary>
|
|
||||
[Obsolete] |
|
||||
public interface IVisualTreeHost |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the root of the hosted visual tree.
|
|
||||
/// </summary>
|
|
||||
/// <value>
|
|
||||
/// The root of the hosted visual tree.
|
|
||||
/// </value>
|
|
||||
IVisual? Root { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,61 +0,0 @@ |
|||||
using System; |
|
||||
using Avalonia.Controls.Shapes; |
|
||||
using Avalonia.Media; |
|
||||
using Avalonia.Metadata; |
|
||||
|
|
||||
namespace Avalonia.Controls |
|
||||
{ |
|
||||
[Obsolete("Use Image control with DrawingImage source")] |
|
||||
public class DrawingPresenter : Control |
|
||||
{ |
|
||||
static DrawingPresenter() |
|
||||
{ |
|
||||
AffectsMeasure<DrawingPresenter>(DrawingProperty); |
|
||||
AffectsRender<DrawingPresenter>(DrawingProperty); |
|
||||
} |
|
||||
|
|
||||
public static readonly StyledProperty<Drawing> DrawingProperty = |
|
||||
AvaloniaProperty.Register<DrawingPresenter, Drawing>(nameof(Drawing)); |
|
||||
|
|
||||
public static readonly StyledProperty<Stretch> StretchProperty = |
|
||||
AvaloniaProperty.Register<DrawingPresenter, Stretch>(nameof(Stretch), Stretch.Uniform); |
|
||||
|
|
||||
[Content] |
|
||||
public Drawing Drawing |
|
||||
{ |
|
||||
get => GetValue(DrawingProperty); |
|
||||
set => SetValue(DrawingProperty, value); |
|
||||
} |
|
||||
|
|
||||
public Stretch Stretch |
|
||||
{ |
|
||||
get => GetValue(StretchProperty); |
|
||||
set => SetValue(StretchProperty, value); |
|
||||
} |
|
||||
|
|
||||
private Matrix _transform = Matrix.Identity; |
|
||||
|
|
||||
protected override Size MeasureOverride(Size availableSize) |
|
||||
{ |
|
||||
if (Drawing == null) return new Size(); |
|
||||
|
|
||||
var (size, transform) = Shape.CalculateSizeAndTransform(availableSize, Drawing.GetBounds(), Stretch); |
|
||||
|
|
||||
_transform = transform; |
|
||||
|
|
||||
return size; |
|
||||
} |
|
||||
|
|
||||
public override void Render(DrawingContext context) |
|
||||
{ |
|
||||
if (Drawing != null) |
|
||||
{ |
|
||||
using (context.PushPreTransform(_transform)) |
|
||||
using (context.PushClip(new Rect(Bounds.Size))) |
|
||||
{ |
|
||||
Drawing.Draw(context); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue