committed by
GitHub
448 changed files with 8932 additions and 4535 deletions
@ -0,0 +1,5 @@ |
|||
<ProjectConfiguration> |
|||
<Settings> |
|||
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely> |
|||
</Settings> |
|||
</ProjectConfiguration> |
|||
@ -0,0 +1,16 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<PropertyGroup> |
|||
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings> |
|||
<EnableTrimAnalyzer>true</EnableTrimAnalyzer> |
|||
<TrimmerSingleWarn>false</TrimmerSingleWarn> |
|||
<IsTrimmable>true</IsTrimmable> |
|||
</PropertyGroup> |
|||
<!-- Remove check for the AOT when we get rid of dependencies with reflection --> |
|||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0' and '$(PublishAot)' != 'true'"> |
|||
<ILLinkTreatWarningsAsErrors>true</ILLinkTreatWarningsAsErrors> |
|||
<!-- Trim warnings --> |
|||
<WarningsAsErrors>$(WarningsAsErrors);IL2000;IL2001;IL2002;IL2003;IL2004;IL2005;IL2006;IL2007;IL2008;IL2009;IL2010;IL2011;IL2012;IL2013;IL2014;IL2015;IL2016;IL2017;IL2018;IL2019;IL2020;IL2021;IL2022;IL2023;IL2024;IL2025;IL2026;IL2027;IL2028;IL2029;IL2030;IL2031;IL2032;IL2033;IL2034;IL2035;IL2036;IL2037;IL2038;IL2039;IL2040;IL2041;IL2042;IL2043;IL2044;IL2045;IL2046;IL2047;IL2048;IL2049;IL2050;IL2051;IL2052;IL2053;IL2054;IL2055;IL2056;IL2057;IL2058;IL2059;IL2060;IL2061;IL2062;IL2063;IL2064;IL2065;IL2066;IL2067;IL2068;IL2069;IL2070;IL2071;IL2072;IL2073;IL2074;IL2075;IL2076;IL2077;IL2078;IL2079;IL2080;IL2081;IL2082;IL2083;IL2084;IL2085;IL2086;IL2087;IL2088;IL2089;IL2090;IL2091;IL2092;IL2093;IL2094;IL2095;IL2096;IL2097;IL2098;IL2099;IL2100;IL2101;IL2102;IL2103;IL2104;IL2105;IL2106;IL2107;IL2108;IL2109;IL2110;IL2111;IL2112;IL2113;IL2114;IL2115;IL2116;IL2117;IL2118;IL2119;IL2120;IL2121;IL2122;IL2123;IL2124;IL2125;IL2126;IL2127;IL2128;IL2129;IL2130;IL2131;IL2132;IL2133;IL2134;IL2135;IL2136;IL2137;IL2138;IL2139;IL2140;IL2141;IL2142;IL2143;IL2144;IL2145;IL2146;IL2147;IL2148;IL2149;IL2150;IL2151;IL2152;IL2153;IL2154;IL2155;IL2156;IL2157</WarningsAsErrors> |
|||
<!-- NativeAOT warnings --> |
|||
<WarningsAsErrors>$(WarningsAsErrors);IL3050;IL3051;IL3052;IL3053;IL3054;IL3055;IL3056</WarningsAsErrors> |
|||
</PropertyGroup> |
|||
</Project> |
|||
@ -0,0 +1,27 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
xmlns:viewModels="using:ControlCatalog.ViewModels" |
|||
mc:Ignorable="d" |
|||
d:DesignWidth="800" |
|||
d:DesignHeight="450" |
|||
x:DataType="viewModels:RefreshContainerViewModel" |
|||
x:Class="ControlCatalog.Pages.RefreshContainerPage"> |
|||
<DockPanel HorizontalAlignment="Stretch" |
|||
Height="600" |
|||
VerticalAlignment="Top"> |
|||
<Label DockPanel.Dock="Top">A control that supports pull to refresh</Label> |
|||
<RefreshContainer Name="Refresh" |
|||
DockPanel.Dock="Bottom" |
|||
HorizontalAlignment="Stretch" |
|||
VerticalAlignment="Stretch" |
|||
PullDirection="TopToBottom" |
|||
RefreshRequested="RefreshContainerPage_RefreshRequested" |
|||
Margin="5"> |
|||
<ListBox HorizontalAlignment="Stretch" |
|||
VerticalAlignment="Top" |
|||
Items="{Binding Items}"/> |
|||
</RefreshContainer> |
|||
</DockPanel> |
|||
</UserControl> |
|||
@ -0,0 +1,36 @@ |
|||
using System.Threading.Tasks; |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class RefreshContainerPage : UserControl |
|||
{ |
|||
private RefreshContainerViewModel _viewModel; |
|||
|
|||
public RefreshContainerPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
|
|||
_viewModel = new RefreshContainerViewModel(); |
|||
|
|||
DataContext = _viewModel; |
|||
} |
|||
|
|||
private async void RefreshContainerPage_RefreshRequested(object? sender, RefreshRequestedEventArgs e) |
|||
{ |
|||
var deferral = e.GetDeferral(); |
|||
|
|||
await _viewModel.AddToTop(); |
|||
|
|||
deferral.Complete(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using System.Collections.ObjectModel; |
|||
using System.Linq; |
|||
using System.Reactive; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls.Notifications; |
|||
using ControlCatalog.Pages; |
|||
using MiniMvvm; |
|||
|
|||
namespace ControlCatalog.ViewModels |
|||
{ |
|||
public class RefreshContainerViewModel : ViewModelBase |
|||
{ |
|||
public ObservableCollection<string> Items { get; } |
|||
|
|||
public RefreshContainerViewModel() |
|||
{ |
|||
Items = new ObservableCollection<string>(Enumerable.Range(1, 200).Select(i => $"Item {i}")); |
|||
} |
|||
|
|||
public async Task AddToTop() |
|||
{ |
|||
await Task.Delay(3000); |
|||
Items.Insert(0, $"Item {200 - Items.Count}"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
<Application |
|||
xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="ReactiveUIDemo.App"> |
|||
<Application.Styles> |
|||
<FluentTheme /> |
|||
</Application.Styles> |
|||
</Application> |
|||
@ -0,0 +1,37 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls.ApplicationLifetimes; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.ReactiveUI; |
|||
using ReactiveUI; |
|||
using ReactiveUIDemo.ViewModels; |
|||
using ReactiveUIDemo.Views; |
|||
using Splat; |
|||
|
|||
namespace ReactiveUIDemo |
|||
{ |
|||
public class App : Application |
|||
{ |
|||
public override void Initialize() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
Locator.CurrentMutable.Register(() => new FooView(), typeof(IViewFor<FooViewModel>)); |
|||
Locator.CurrentMutable.Register(() => new BarView(), typeof(IViewFor<BarViewModel>)); |
|||
} |
|||
|
|||
public override void OnFrameworkInitializationCompleted() |
|||
{ |
|||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) |
|||
desktop.MainWindow = new MainWindow(); |
|||
base.OnFrameworkInitializationCompleted(); |
|||
} |
|||
|
|||
public static int Main(string[] args) |
|||
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); |
|||
|
|||
public static AppBuilder BuildAvaloniaApp() |
|||
=> AppBuilder.Configure<App>() |
|||
.UsePlatformDetect() |
|||
.UseReactiveUI() |
|||
.LogToTrace(); |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<Window xmlns="https://github.com/avaloniaui" |
|||
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' |
|||
x:Class="ReactiveUIDemo.MainWindow" |
|||
xmlns:vm="using:ReactiveUIDemo.ViewModels" |
|||
xmlns:rxui="using:Avalonia.ReactiveUI" |
|||
Title="AvaloniaUI ReactiveUI Demo" |
|||
x:DataType="vm:MainWindowViewModel"> |
|||
<TabControl TabStripPlacement="Left"> |
|||
<TabItem Header="RoutedViewHost"> |
|||
<DockPanel DataContext="{Binding RoutedViewHost}"> |
|||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Spacing="8"> |
|||
<Button Command="{Binding ShowFoo}">Foo</Button> |
|||
<Button Command="{Binding ShowBar}">Bar</Button> |
|||
</StackPanel> |
|||
<rxui:RoutedViewHost Router="{Binding Router}"/> |
|||
</DockPanel> |
|||
</TabItem> |
|||
</TabControl> |
|||
</Window> |
|||
@ -0,0 +1,22 @@ |
|||
using ReactiveUIDemo.ViewModels; |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ReactiveUIDemo |
|||
{ |
|||
public class MainWindow : Window |
|||
{ |
|||
public MainWindow() |
|||
{ |
|||
this.InitializeComponent(); |
|||
this.DataContext = new MainWindowViewModel(); |
|||
this.AttachDevTools(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
<PropertyGroup> |
|||
<OutputType>Exe</OutputType> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> |
|||
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" /> |
|||
<ProjectReference Include="..\..\src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<Compile Update="Views\BarView.axaml.cs"> |
|||
<DependentUpon>BarView.axaml</DependentUpon> |
|||
</Compile> |
|||
<Compile Update="Views\FooView.axaml.cs"> |
|||
<DependentUpon>FooView.axaml</DependentUpon> |
|||
</Compile> |
|||
</ItemGroup> |
|||
|
|||
<Import Project="..\..\build\SampleApp.props" /> |
|||
<Import Project="..\..\build\ReferenceCoreLibraries.props" /> |
|||
<Import Project="..\..\build\BuildTargets.targets" /> |
|||
<Import Project="..\..\build\Rx.props" /> |
|||
<Import Project="..\..\build\ReactiveUI.props" /> |
|||
</Project> |
|||
@ -0,0 +1,11 @@ |
|||
using ReactiveUI; |
|||
|
|||
namespace ReactiveUIDemo.ViewModels |
|||
{ |
|||
internal class BarViewModel : ReactiveObject, IRoutableViewModel |
|||
{ |
|||
public BarViewModel(IScreen screen) => HostScreen = screen; |
|||
public string UrlPathSegment => "Bar"; |
|||
public IScreen HostScreen { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using ReactiveUI; |
|||
|
|||
namespace ReactiveUIDemo.ViewModels |
|||
{ |
|||
internal class FooViewModel : ReactiveObject, IRoutableViewModel |
|||
{ |
|||
public FooViewModel(IScreen screen) => HostScreen = screen; |
|||
public string UrlPathSegment => "Foo"; |
|||
public IScreen HostScreen { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using ReactiveUI; |
|||
|
|||
namespace ReactiveUIDemo.ViewModels |
|||
{ |
|||
internal class MainWindowViewModel : ReactiveObject |
|||
{ |
|||
public RoutedViewHostPageViewModel RoutedViewHost { get; } = new(); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using ReactiveUI; |
|||
|
|||
namespace ReactiveUIDemo.ViewModels |
|||
{ |
|||
internal class RoutedViewHostPageViewModel : ReactiveObject, IScreen |
|||
{ |
|||
public RoutedViewHostPageViewModel() |
|||
{ |
|||
Foo = new(this); |
|||
Bar = new(this); |
|||
Router.Navigate.Execute(Foo); |
|||
} |
|||
|
|||
public RoutingState Router { get; } = new(); |
|||
public FooViewModel Foo { get; } |
|||
public BarViewModel Bar { get; } |
|||
|
|||
public void ShowFoo() => Router.Navigate.Execute(Foo); |
|||
public void ShowBar() => Router.Navigate.Execute(Bar); |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
|||
x:Class="ReactiveUIDemo.Views.BarView" |
|||
HorizontalAlignment="Stretch" |
|||
VerticalAlignment="Stretch"> |
|||
<Border Background="Blue"> |
|||
<TextBlock HorizontalAlignment="Center" |
|||
VerticalAlignment="Center" |
|||
FontSize="48"> |
|||
Bar! |
|||
</TextBlock> |
|||
</Border> |
|||
</UserControl> |
|||
@ -0,0 +1,28 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ReactiveUI; |
|||
using ReactiveUIDemo.ViewModels; |
|||
|
|||
namespace ReactiveUIDemo.Views |
|||
{ |
|||
internal partial class BarView : UserControl, IViewFor<BarViewModel> |
|||
{ |
|||
public BarView() |
|||
{ |
|||
InitializeComponent(); |
|||
} |
|||
|
|||
public BarViewModel? ViewModel { get; set; } |
|||
|
|||
object? IViewFor.ViewModel |
|||
{ |
|||
get => ViewModel; |
|||
set => ViewModel = (BarViewModel?)value; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
|||
x:Class="ReactiveUIDemo.Views.FooView" |
|||
HorizontalAlignment="Stretch" |
|||
VerticalAlignment="Stretch"> |
|||
<Border Background="Red"> |
|||
<TextBlock HorizontalAlignment="Center" |
|||
VerticalAlignment="Center" |
|||
FontSize="48"> |
|||
Foo! |
|||
</TextBlock> |
|||
</Border> |
|||
</UserControl> |
|||
@ -0,0 +1,28 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ReactiveUI; |
|||
using ReactiveUIDemo.ViewModels; |
|||
|
|||
namespace ReactiveUIDemo.Views |
|||
{ |
|||
internal partial class FooView : UserControl, IViewFor<FooViewModel> |
|||
{ |
|||
public FooView() |
|||
{ |
|||
InitializeComponent(); |
|||
} |
|||
|
|||
public FooViewModel? ViewModel { get; set; } |
|||
|
|||
object? IViewFor.ViewModel |
|||
{ |
|||
get => ViewModel; |
|||
set => ViewModel = (FooViewModel?)value; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -1,32 +0,0 @@ |
|||
using Avalonia.OpenGL; |
|||
using Avalonia.OpenGL.Egl; |
|||
using Avalonia.OpenGL.Surfaces; |
|||
|
|||
namespace Avalonia.Android.OpenGL |
|||
{ |
|||
internal sealed class GlPlatformSurface : EglGlPlatformSurfaceBase |
|||
{ |
|||
private readonly EglPlatformOpenGlInterface _egl; |
|||
private readonly IEglWindowGlPlatformSurfaceInfo _info; |
|||
|
|||
private GlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) |
|||
{ |
|||
_egl = egl; |
|||
_info = info; |
|||
} |
|||
|
|||
public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget() => |
|||
new GlRenderTarget(_egl, _info, _egl.CreateWindowSurface(_info.Handle), _info.Handle); |
|||
|
|||
public static GlPlatformSurface TryCreate(IEglWindowGlPlatformSurfaceInfo info) |
|||
{ |
|||
var feature = AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>(); |
|||
if (feature is EglPlatformOpenGlInterface egl) |
|||
{ |
|||
return new GlPlatformSurface(egl, info); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,30 +0,0 @@ |
|||
using System; |
|||
|
|||
using Avalonia.OpenGL.Egl; |
|||
using Avalonia.OpenGL.Surfaces; |
|||
|
|||
namespace Avalonia.Android.OpenGL |
|||
{ |
|||
internal sealed class GlRenderTarget : EglPlatformSurfaceRenderTargetBase, IGlPlatformSurfaceRenderTargetWithCorruptionInfo |
|||
{ |
|||
private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info; |
|||
private readonly EglSurface _surface; |
|||
private readonly IntPtr _handle; |
|||
|
|||
public GlRenderTarget( |
|||
EglPlatformOpenGlInterface egl, |
|||
EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info, |
|||
EglSurface surface, |
|||
IntPtr handle) |
|||
: base(egl) |
|||
{ |
|||
_info = info; |
|||
_surface = surface; |
|||
_handle = handle; |
|||
} |
|||
|
|||
public bool IsCorrupted => _handle != _info.Handle; |
|||
|
|||
public override IGlPlatformSurfaceRenderingSession BeginDraw() => BeginDraw(_surface, _info); |
|||
} |
|||
} |
|||
@ -0,0 +1,121 @@ |
|||
#pragma warning disable MA0048 // File name must match type name
|
|||
// https://github.com/dotnet/runtime/tree/main/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis
|
|||
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
|||
// See the LICENSE file in the project root for more information.
|
|||
|
|||
namespace System.Diagnostics.CodeAnalysis |
|||
{ |
|||
#nullable enable |
|||
#if !NET6_0_OR_GREATER
|
|||
[AttributeUsage( |
|||
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter | |
|||
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method | |
|||
AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, |
|||
Inherited = false)] |
|||
internal sealed class DynamicallyAccessedMembersAttribute : Attribute |
|||
{ |
|||
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) |
|||
{ |
|||
MemberTypes = memberTypes; |
|||
} |
|||
|
|||
public DynamicallyAccessedMemberTypes MemberTypes { get; } |
|||
} |
|||
|
|||
[Flags] |
|||
internal enum DynamicallyAccessedMemberTypes |
|||
{ |
|||
None = 0, |
|||
PublicParameterlessConstructor = 0x0001, |
|||
PublicConstructors = 0x0002 | PublicParameterlessConstructor, |
|||
NonPublicConstructors = 0x0004, |
|||
PublicMethods = 0x0008, |
|||
NonPublicMethods = 0x0010, |
|||
PublicFields = 0x0020, |
|||
NonPublicFields = 0x0040, |
|||
PublicNestedTypes = 0x0080, |
|||
NonPublicNestedTypes = 0x0100, |
|||
PublicProperties = 0x0200, |
|||
NonPublicProperties = 0x0400, |
|||
PublicEvents = 0x0800, |
|||
NonPublicEvents = 0x1000, |
|||
Interfaces = 0x2000, |
|||
All = ~None |
|||
} |
|||
|
|||
[AttributeUsage( |
|||
AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method, |
|||
AllowMultiple = true, Inherited = false)] |
|||
internal sealed class DynamicDependencyAttribute : Attribute |
|||
{ |
|||
public DynamicDependencyAttribute(string memberSignature) |
|||
{ |
|||
MemberSignature = memberSignature; |
|||
} |
|||
|
|||
public DynamicDependencyAttribute(string memberSignature, Type type) |
|||
{ |
|||
MemberSignature = memberSignature; |
|||
Type = type; |
|||
} |
|||
|
|||
public DynamicDependencyAttribute(string memberSignature, string typeName, string assemblyName) |
|||
{ |
|||
MemberSignature = memberSignature; |
|||
TypeName = typeName; |
|||
AssemblyName = assemblyName; |
|||
} |
|||
|
|||
public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, Type type) |
|||
{ |
|||
MemberTypes = memberTypes; |
|||
Type = type; |
|||
} |
|||
|
|||
public DynamicDependencyAttribute(DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) |
|||
{ |
|||
MemberTypes = memberTypes; |
|||
TypeName = typeName; |
|||
AssemblyName = assemblyName; |
|||
} |
|||
|
|||
public string? MemberSignature { get; } |
|||
public DynamicallyAccessedMemberTypes MemberTypes { get; } |
|||
public Type? Type { get; } |
|||
public string? TypeName { get; } |
|||
public string? AssemblyName { get; } |
|||
public string? Condition { get; set; } |
|||
} |
|||
|
|||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)] |
|||
internal sealed class RequiresUnreferencedCodeAttribute : Attribute |
|||
{ |
|||
public RequiresUnreferencedCodeAttribute(string message) |
|||
{ |
|||
Message = message; |
|||
} |
|||
|
|||
public string Message { get; } |
|||
public string? Url { get; set; } |
|||
} |
|||
|
|||
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] |
|||
internal sealed class UnconditionalSuppressMessageAttribute : Attribute |
|||
{ |
|||
public UnconditionalSuppressMessageAttribute(string category, string checkId) |
|||
{ |
|||
Category = category; |
|||
CheckId = checkId; |
|||
} |
|||
public string Category { get; } |
|||
public string CheckId { get; } |
|||
public string? Scope { get; set; } |
|||
public string? Target { get; set; } |
|||
public string? MessageId { get; set; } |
|||
public string? Justification { get; set; } |
|||
} |
|||
#endif
|
|||
} |
|||
|
|||
@ -0,0 +1,30 @@ |
|||
namespace Avalonia; |
|||
|
|||
internal static class TrimmingMessages |
|||
{ |
|||
public const string ImplicitTypeConvertionSupressWarningMessage = "Implicit convertion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible."; |
|||
public const string ImplicitTypeConvertionRequiresUnreferencedCodeMessage = "Implicit convertion methods are required for type conversion."; |
|||
|
|||
public const string TypeConvertionSupressWarningMessage = "Convertion methods might be removed by the linker. We don't have a reliable way to prevent it, except converting everything in compile time when possible."; |
|||
public const string TypeConvertionRequiresUnreferencedCodeMessage = "Convertion methods are required for type conversion, including op_Implicit, op_Explicit, Parse and TypeConverter."; |
|||
|
|||
public const string ReflectionBindingRequiresUnreferencedCodeMessage = "BindingExpression and ReflectionBinding heavily use reflection. Consider using CompiledBindings instead."; |
|||
public const string ReflectionBindingSupressWarningMessage = "BindingExpression and ReflectionBinding internal heavily use reflection."; |
|||
|
|||
public const string CompiledBindingSafeSupressWarningMessage = "CompiledBinding preserves members used in the expression tree."; |
|||
|
|||
public const string ExpressionNodeRequiresUnreferencedCodeMessage = "ExpressionNode might require unreferenced code."; |
|||
public const string ExpressionSafeSupressWarningMessage = "Typed Expressions preserves members used in the expression tree."; |
|||
|
|||
public const string SelectorsParseRequiresUnreferencedCodeMessage = "Selectors runtime parser might require unreferenced code. Consider using stronly typed selectors factory with 'new Style(s => s.OfType<Button>())' syntax."; |
|||
|
|||
public const string PropertyAccessorsRequiresUnreferencedCodeMessage = "PropertyAccessors might require unreferenced code."; |
|||
public const string DataValidationPluginRequiresUnreferencedCodeMessage = "DataValidationPlugin might require unreferenced code."; |
|||
public const string StreamPluginRequiresUnreferencedCodeMessage = "StreamPlugin might require unreferenced code."; |
|||
|
|||
public const string StyleResourceIncludeRequiresUnreferenceCodeMessage = "StyleInclude and ResourceInclude use AvaloniaXamlLoader.Load which dynamically loads referenced assembly with Avalonia resources. Note, StyleInclude and ResourceInclude defined in XAML are resolved compile time and are safe with trimming and AOT."; |
|||
public const string AvaloniaXamlLoaderRequiresUnreferenceCodeMessage = "AvaloniaXamlLoader.Load(uri, baseUri) dynamically loads referenced assembly with Avalonia resources."; |
|||
public const string XamlTypeResolvedRequiresUnreferenceCodeMessage = "XamlTypeResolver might require unreferenced code."; |
|||
|
|||
public const string IgnoreNativeAotSupressWarningMessage = "This method is not supported by NativeAOT."; |
|||
} |
|||
@ -0,0 +1,152 @@ |
|||
using Avalonia.Input.GestureRecognizers; |
|||
|
|||
namespace Avalonia.Input |
|||
{ |
|||
public class PullGestureRecognizer : StyledElement, IGestureRecognizer |
|||
{ |
|||
private IInputElement? _target; |
|||
private IGestureRecognizerActionsDispatcher? _actions; |
|||
private Point _initialPosition; |
|||
private int _gestureId; |
|||
private IPointer? _tracking; |
|||
private PullDirection _pullDirection; |
|||
|
|||
/// <summary>
|
|||
/// Defines the <see cref="PullDirection"/> property.
|
|||
/// </summary>
|
|||
public static readonly DirectProperty<PullGestureRecognizer, PullDirection> PullDirectionProperty = |
|||
AvaloniaProperty.RegisterDirect<PullGestureRecognizer, PullDirection>( |
|||
nameof(PullDirection), |
|||
o => o.PullDirection, |
|||
(o, v) => o.PullDirection = v); |
|||
|
|||
public PullDirection PullDirection |
|||
{ |
|||
get => _pullDirection; |
|||
set => SetAndRaise(PullDirectionProperty, ref _pullDirection, value); |
|||
} |
|||
|
|||
public PullGestureRecognizer(PullDirection pullDirection) |
|||
{ |
|||
PullDirection = pullDirection; |
|||
} |
|||
|
|||
public void Initialize(IInputElement target, IGestureRecognizerActionsDispatcher actions) |
|||
{ |
|||
_target = target; |
|||
_actions = actions; |
|||
|
|||
_target?.AddHandler(InputElement.PointerPressedEvent, OnPointerPressed, Interactivity.RoutingStrategies.Tunnel | Interactivity.RoutingStrategies.Bubble); |
|||
_target?.AddHandler(InputElement.PointerReleasedEvent, OnPointerReleased, Interactivity.RoutingStrategies.Tunnel | Interactivity.RoutingStrategies.Bubble); |
|||
} |
|||
|
|||
private void OnPointerPressed(object? sender, PointerPressedEventArgs e) |
|||
{ |
|||
PointerPressed(e); |
|||
} |
|||
|
|||
private void OnPointerReleased(object? sender, PointerReleasedEventArgs e) |
|||
{ |
|||
PointerReleased(e); |
|||
} |
|||
|
|||
public void PointerCaptureLost(IPointer pointer) |
|||
{ |
|||
if (_tracking == pointer) |
|||
{ |
|||
EndPull(); |
|||
} |
|||
} |
|||
|
|||
public void PointerMoved(PointerEventArgs e) |
|||
{ |
|||
if (_tracking == e.Pointer && _target is Visual visual) |
|||
{ |
|||
var currentPosition = e.GetPosition(visual); |
|||
_actions!.Capture(e.Pointer, this); |
|||
|
|||
Vector delta = default; |
|||
switch (PullDirection) |
|||
{ |
|||
case PullDirection.TopToBottom: |
|||
if (currentPosition.Y > _initialPosition.Y) |
|||
{ |
|||
delta = new Vector(0, currentPosition.Y - _initialPosition.Y); |
|||
} |
|||
break; |
|||
case PullDirection.BottomToTop: |
|||
if (currentPosition.Y < _initialPosition.Y) |
|||
{ |
|||
delta = new Vector(0, _initialPosition.Y - currentPosition.Y); |
|||
} |
|||
break; |
|||
case PullDirection.LeftToRight: |
|||
if (currentPosition.X > _initialPosition.X) |
|||
{ |
|||
delta = new Vector(currentPosition.X - _initialPosition.X, 0); |
|||
} |
|||
break; |
|||
case PullDirection.RightToLeft: |
|||
if (currentPosition.X < _initialPosition.X) |
|||
{ |
|||
delta = new Vector(_initialPosition.X - currentPosition.X, 0); |
|||
} |
|||
break; |
|||
} |
|||
|
|||
_target?.RaiseEvent(new PullGestureEventArgs(_gestureId, delta, PullDirection)); |
|||
} |
|||
} |
|||
|
|||
public void PointerPressed(PointerPressedEventArgs e) |
|||
{ |
|||
if (_target != null && _target is Visual visual && (e.Pointer.Type == PointerType.Touch || e.Pointer.Type == PointerType.Pen)) |
|||
{ |
|||
var position = e.GetPosition(visual); |
|||
|
|||
var canPull = false; |
|||
|
|||
var bounds = visual.Bounds; |
|||
|
|||
switch (PullDirection) |
|||
{ |
|||
case PullDirection.TopToBottom: |
|||
canPull = position.Y < bounds.Height * 0.1; |
|||
break; |
|||
case PullDirection.BottomToTop: |
|||
canPull = position.Y > bounds.Height - (bounds.Height * 0.1); |
|||
break; |
|||
case PullDirection.LeftToRight: |
|||
canPull = position.X < bounds.Width * 0.1; |
|||
break; |
|||
case PullDirection.RightToLeft: |
|||
canPull = position.X > bounds.Width - (bounds.Width * 0.1); |
|||
break; |
|||
} |
|||
|
|||
if (canPull) |
|||
{ |
|||
_gestureId = PullGestureEventArgs.GetNextFreeId(); |
|||
_tracking = e.Pointer; |
|||
_initialPosition = position; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void PointerReleased(PointerReleasedEventArgs e) |
|||
{ |
|||
if (_tracking == e.Pointer) |
|||
{ |
|||
EndPull(); |
|||
} |
|||
} |
|||
|
|||
private void EndPull() |
|||
{ |
|||
_tracking = null; |
|||
_initialPosition = default; |
|||
|
|||
_target?.RaiseEvent(new PullGestureEndedEventArgs(_gestureId, PullDirection)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
using System; |
|||
using Avalonia.Interactivity; |
|||
|
|||
namespace Avalonia.Input |
|||
{ |
|||
public class PullGestureEventArgs : RoutedEventArgs |
|||
{ |
|||
public int Id { get; } |
|||
public Vector Delta { get; } |
|||
public PullDirection PullDirection { get; } |
|||
|
|||
private static int _nextId = 1; |
|||
|
|||
internal static int GetNextFreeId() => _nextId++; |
|||
|
|||
public PullGestureEventArgs(int id, Vector delta, PullDirection pullDirection) : base(Gestures.PullGestureEvent) |
|||
{ |
|||
Id = id; |
|||
Delta = delta; |
|||
PullDirection = pullDirection; |
|||
} |
|||
} |
|||
|
|||
public class PullGestureEndedEventArgs : RoutedEventArgs |
|||
{ |
|||
public int Id { get; } |
|||
public PullDirection PullDirection { get; } |
|||
|
|||
public PullGestureEndedEventArgs(int id, PullDirection pullDirection) : base(Gestures.PullGestureEndedEvent) |
|||
{ |
|||
Id = id; |
|||
PullDirection = pullDirection; |
|||
} |
|||
} |
|||
|
|||
public enum PullDirection |
|||
{ |
|||
TopToBottom, |
|||
BottomToTop, |
|||
LeftToRight, |
|||
RightToLeft |
|||
} |
|||
} |
|||
@ -1,25 +1,31 @@ |
|||
namespace Avalonia.Media |
|||
{ |
|||
public readonly struct GlyphRunMetrics |
|||
public readonly record struct GlyphRunMetrics |
|||
{ |
|||
public GlyphRunMetrics(double width, double widthIncludingTrailingWhitespace, int trailingWhitespaceLength, |
|||
int newlineLength, double height) |
|||
public GlyphRunMetrics(double width, double widthIncludingTrailingWhitespace, double height, |
|||
int trailingWhitespaceLength, int newLineLength, int firstCluster, int lastCluster) |
|||
{ |
|||
Width = width; |
|||
WidthIncludingTrailingWhitespace = widthIncludingTrailingWhitespace; |
|||
TrailingWhitespaceLength = trailingWhitespaceLength; |
|||
NewlineLength = newlineLength; |
|||
Height = height; |
|||
TrailingWhitespaceLength = trailingWhitespaceLength; |
|||
NewLineLength= newLineLength; |
|||
FirstCluster = firstCluster; |
|||
LastCluster = lastCluster; |
|||
} |
|||
|
|||
public double Width { get; } |
|||
|
|||
public double WidthIncludingTrailingWhitespace { get; } |
|||
|
|||
public double Height { get; } |
|||
|
|||
public int TrailingWhitespaceLength { get; } |
|||
|
|||
public int NewlineLength { get; } |
|||
public int NewLineLength { get; } |
|||
|
|||
public double Height { get; } |
|||
public int FirstCluster { get; } |
|||
|
|||
public int LastCluster { get; } |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,293 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Runtime.CompilerServices; |
|||
using Avalonia.Utilities; |
|||
|
|||
namespace Avalonia.Media.TextFormatting |
|||
{ |
|||
public readonly struct CharacterBufferRange : IReadOnlyList<char> |
|||
{ |
|||
/// <summary>
|
|||
/// Getting an empty character string
|
|||
/// </summary>
|
|||
public static CharacterBufferRange Empty => new CharacterBufferRange(); |
|||
|
|||
/// <summary>
|
|||
/// Construct <see cref="CharacterBufferRange"/> from character array
|
|||
/// </summary>
|
|||
/// <param name="characterArray">character array</param>
|
|||
/// <param name="offsetToFirstChar">character buffer offset to the first character</param>
|
|||
/// <param name="characterLength">character length</param>
|
|||
public CharacterBufferRange( |
|||
char[] characterArray, |
|||
int offsetToFirstChar, |
|||
int characterLength |
|||
) |
|||
: this( |
|||
new CharacterBufferReference(characterArray, offsetToFirstChar), |
|||
characterLength |
|||
) |
|||
{ } |
|||
|
|||
/// <summary>
|
|||
/// Construct <see cref="CharacterBufferRange"/> from string
|
|||
/// </summary>
|
|||
/// <param name="characterString">character string</param>
|
|||
/// <param name="offsetToFirstChar">character buffer offset to the first character</param>
|
|||
/// <param name="characterLength">character length</param>
|
|||
public CharacterBufferRange( |
|||
string characterString, |
|||
int offsetToFirstChar, |
|||
int characterLength |
|||
) |
|||
: this( |
|||
new CharacterBufferReference(characterString, offsetToFirstChar), |
|||
characterLength |
|||
) |
|||
{ } |
|||
|
|||
/// <summary>
|
|||
/// Construct a <see cref="CharacterBufferRange"/> from <see cref="CharacterBufferReference"/>
|
|||
/// </summary>
|
|||
/// <param name="characterBufferReference">character buffer reference</param>
|
|||
/// <param name="characterLength">number of characters</param>
|
|||
public CharacterBufferRange( |
|||
CharacterBufferReference characterBufferReference, |
|||
int characterLength |
|||
) |
|||
{ |
|||
if (characterLength < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("characterLength", "ParameterCannotBeNegative"); |
|||
} |
|||
|
|||
int maxLength = characterBufferReference.CharacterBuffer.Length > 0 ? |
|||
characterBufferReference.CharacterBuffer.Length - characterBufferReference.OffsetToFirstChar : |
|||
0; |
|||
|
|||
if (characterLength > maxLength) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("characterLength", $"ParameterCannotBeGreaterThan {maxLength}"); |
|||
} |
|||
|
|||
CharacterBufferReference = characterBufferReference; |
|||
Length = characterLength; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Construct a <see cref="CharacterBufferRange"/> from part of another <see cref="CharacterBufferRange"/>
|
|||
/// </summary>
|
|||
internal CharacterBufferRange( |
|||
CharacterBufferRange characterBufferRange, |
|||
int offsetToFirstChar, |
|||
int characterLength |
|||
) : |
|||
this( |
|||
characterBufferRange.CharacterBuffer, |
|||
characterBufferRange.OffsetToFirstChar + offsetToFirstChar, |
|||
characterLength |
|||
) |
|||
{ } |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Construct a <see cref="CharacterBufferRange"/> from string
|
|||
/// </summary>
|
|||
internal CharacterBufferRange( |
|||
string charString |
|||
) : |
|||
this( |
|||
charString, |
|||
0, |
|||
charString.Length |
|||
) |
|||
{ } |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Construct <see cref="CharacterBufferRange"/> from memory buffer
|
|||
/// </summary>
|
|||
internal CharacterBufferRange( |
|||
ReadOnlyMemory<char> charBuffer, |
|||
int offsetToFirstChar, |
|||
int characterLength |
|||
) : |
|||
this( |
|||
new CharacterBufferReference(charBuffer, offsetToFirstChar), |
|||
characterLength |
|||
) |
|||
{ } |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Construct a <see cref="CharacterBufferRange"/> by extracting text info from a text run
|
|||
/// </summary>
|
|||
internal CharacterBufferRange(TextRun textRun) |
|||
{ |
|||
CharacterBufferReference = textRun.CharacterBufferReference; |
|||
Length = textRun.Length; |
|||
} |
|||
|
|||
public char this[int index] |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get |
|||
{ |
|||
#if DEBUG
|
|||
if (index.CompareTo(0) < 0 || index.CompareTo(Length) > 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(index)); |
|||
} |
|||
#endif
|
|||
return Span[index]; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a reference to the character buffer
|
|||
/// </summary>
|
|||
public CharacterBufferReference CharacterBufferReference { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the number of characters in text source character store
|
|||
/// </summary>
|
|||
public int Length { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a span from the character buffer range
|
|||
/// </summary>
|
|||
public ReadOnlySpan<char> Span => |
|||
CharacterBufferReference.CharacterBuffer.Span.Slice(CharacterBufferReference.OffsetToFirstChar, Length); |
|||
|
|||
/// <summary>
|
|||
/// Gets the character memory buffer
|
|||
/// </summary>
|
|||
internal ReadOnlyMemory<char> CharacterBuffer |
|||
{ |
|||
get { return CharacterBufferReference.CharacterBuffer; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the character offset relative to the beginning of buffer to
|
|||
/// the first character of the run
|
|||
/// </summary>
|
|||
internal int OffsetToFirstChar |
|||
{ |
|||
get { return CharacterBufferReference.OffsetToFirstChar; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Indicate whether the character buffer range is empty
|
|||
/// </summary>
|
|||
internal bool IsEmpty |
|||
{ |
|||
get { return CharacterBufferReference.CharacterBuffer.Length == 0 || Length <= 0; } |
|||
} |
|||
|
|||
internal CharacterBufferRange Take(int length) |
|||
{ |
|||
if (IsEmpty) |
|||
{ |
|||
return this; |
|||
} |
|||
|
|||
if (length > Length) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(length)); |
|||
} |
|||
|
|||
return new CharacterBufferRange(CharacterBufferReference, length); |
|||
} |
|||
|
|||
internal CharacterBufferRange Skip(int length) |
|||
{ |
|||
if (IsEmpty) |
|||
{ |
|||
return this; |
|||
} |
|||
|
|||
if (length > Length) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(length)); |
|||
} |
|||
|
|||
if (length == Length) |
|||
{ |
|||
return new CharacterBufferRange(new CharacterBufferReference(), 0); |
|||
} |
|||
|
|||
var characterBufferReference = new CharacterBufferReference( |
|||
CharacterBufferReference.CharacterBuffer, |
|||
CharacterBufferReference.OffsetToFirstChar + length); |
|||
|
|||
return new CharacterBufferRange(characterBufferReference, Length - length); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compute hash code
|
|||
/// </summary>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return CharacterBufferReference.GetHashCode() ^ Length; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Test equality with the input object
|
|||
/// </summary>
|
|||
/// <param name="obj"> The object to test </param>
|
|||
public override bool Equals(object? obj) |
|||
{ |
|||
if (obj is CharacterBufferRange range) |
|||
{ |
|||
return Equals(range); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Test equality with the input CharacterBufferRange
|
|||
/// </summary>
|
|||
/// <param name="value"> The CharacterBufferRange value to test </param>
|
|||
public bool Equals(CharacterBufferRange value) |
|||
{ |
|||
return CharacterBufferReference.Equals(value.CharacterBufferReference) |
|||
&& Length == value.Length; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compare two CharacterBufferRange for equality
|
|||
/// </summary>
|
|||
/// <param name="left">left operand</param>
|
|||
/// <param name="right">right operand</param>
|
|||
/// <returns>whether or not two operands are equal</returns>
|
|||
public static bool operator ==(CharacterBufferRange left, CharacterBufferRange right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compare two CharacterBufferRange for inequality
|
|||
/// </summary>
|
|||
/// <param name="left">left operand</param>
|
|||
/// <param name="right">right operand</param>
|
|||
/// <returns>whether or not two operands are equal</returns>
|
|||
public static bool operator !=(CharacterBufferRange left, CharacterBufferRange right) |
|||
{ |
|||
return !(left == right); |
|||
} |
|||
|
|||
int IReadOnlyCollection<char>.Count => Length; |
|||
|
|||
public IEnumerator<char> GetEnumerator() |
|||
{ |
|||
return new ImmutableReadOnlyListStructEnumerator<char>(this); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return GetEnumerator(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,115 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Media.TextFormatting |
|||
{ |
|||
/// <summary>
|
|||
/// Text character buffer reference
|
|||
/// </summary>
|
|||
public readonly struct CharacterBufferReference : IEquatable<CharacterBufferReference> |
|||
{ |
|||
/// <summary>
|
|||
/// Construct character buffer reference from character array
|
|||
/// </summary>
|
|||
/// <param name="characterArray">character array</param>
|
|||
/// <param name="offsetToFirstChar">character buffer offset to the first character</param>
|
|||
public CharacterBufferReference(char[] characterArray, int offsetToFirstChar = 0) |
|||
: this(characterArray.AsMemory(), offsetToFirstChar) |
|||
{ } |
|||
|
|||
/// <summary>
|
|||
/// Construct character buffer reference from string
|
|||
/// </summary>
|
|||
/// <param name="characterString">character string</param>
|
|||
/// <param name="offsetToFirstChar">character buffer offset to the first character</param>
|
|||
public CharacterBufferReference(string characterString, int offsetToFirstChar = 0) |
|||
: this(characterString.AsMemory(), offsetToFirstChar) |
|||
{ } |
|||
|
|||
/// <summary>
|
|||
/// Construct character buffer reference from memory buffer
|
|||
/// </summary>
|
|||
internal CharacterBufferReference(ReadOnlyMemory<char> characterBuffer, int offsetToFirstChar = 0) |
|||
{ |
|||
if (offsetToFirstChar < 0) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("offsetToFirstChar", "ParameterCannotBeNegative"); |
|||
} |
|||
|
|||
// maximum offset is one less than CharacterBuffer.Count, except that zero is always a valid offset
|
|||
// even in the case of an empty or null character buffer
|
|||
var maxOffset = characterBuffer.Length == 0 ? 0 : Math.Max(0, characterBuffer.Length - 1); |
|||
if (offsetToFirstChar > maxOffset) |
|||
{ |
|||
throw new ArgumentOutOfRangeException("offsetToFirstChar", $"ParameterCannotBeGreaterThan, {maxOffset}"); |
|||
} |
|||
|
|||
CharacterBuffer = characterBuffer; |
|||
OffsetToFirstChar = offsetToFirstChar; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the character memory buffer
|
|||
/// </summary>
|
|||
public ReadOnlyMemory<char> CharacterBuffer { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the character offset relative to the beginning of buffer to
|
|||
/// the first character of the run
|
|||
/// </summary>
|
|||
public int OffsetToFirstChar { get; } |
|||
|
|||
/// <summary>
|
|||
/// Compute hash code
|
|||
/// </summary>
|
|||
public override int GetHashCode() |
|||
{ |
|||
return CharacterBuffer.IsEmpty ? 0 : CharacterBuffer.GetHashCode(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Test equality with the input object
|
|||
/// </summary>
|
|||
/// <param name="obj"> The object to test. </param>
|
|||
public override bool Equals(object? obj) |
|||
{ |
|||
if (obj is CharacterBufferReference reference) |
|||
{ |
|||
return Equals(reference); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Test equality with the input CharacterBufferReference
|
|||
/// </summary>
|
|||
/// <param name="value"> The characterBufferReference value to test </param>
|
|||
public bool Equals(CharacterBufferReference value) |
|||
{ |
|||
return CharacterBuffer.Equals(value.CharacterBuffer); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compare two CharacterBufferReference for equality
|
|||
/// </summary>
|
|||
/// <param name="left">left operand</param>
|
|||
/// <param name="right">right operand</param>
|
|||
/// <returns>whether or not two operands are equal</returns>
|
|||
public static bool operator ==(CharacterBufferReference left, CharacterBufferReference right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compare two CharacterBufferReference for inequality
|
|||
/// </summary>
|
|||
/// <param name="left">left operand</param>
|
|||
/// <param name="right">right operand</param>
|
|||
/// <returns>whether or not two operands are equal</returns>
|
|||
public static bool operator !=(CharacterBufferReference left, CharacterBufferReference right) |
|||
{ |
|||
return !(left == right); |
|||
} |
|||
} |
|||
} |
|||
|
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue