From 9d335c3a96b3ca1d6c9aedcd6a5c1408375d4e78 Mon Sep 17 00:00:00 2001 From: v-yadli Date: Sun, 13 Dec 2020 02:11:28 +0800 Subject: [PATCH 001/332] fix #4996 --- native/Avalonia.Native/src/OSX/window.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 8419258fe9..9cb5fcbb58 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -1590,7 +1590,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent if(_parent != nullptr) { - _lastKeyHandled = _parent->BaseEvents->RawKeyEvent(type, timestamp, modifiers, key); + auto handled = _parent->BaseEvents->RawKeyEvent(type, timestamp, modifiers, key); + if (key != LeftCtrl && key != RightCtrl) { + _lastKeyHandled = handled; + } else { + _lastKeyHandled = false; + } } } From f41a6340f908e189204104385cd73e6e614da125 Mon Sep 17 00:00:00 2001 From: Andreas Schauerte Date: Mon, 5 Jul 2021 19:11:36 +0200 Subject: [PATCH 002/332] Cherry Pick and merge. --- src/Avalonia.Visuals/Matrix.cs | 192 +++++++++++++++++++++++++-------- 1 file changed, 145 insertions(+), 47 deletions(-) diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index b08a0eb98a..9dd5bced86 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -1,12 +1,21 @@ using System; using System.Globalization; +using System.Linq; using Avalonia.Utilities; namespace Avalonia { /// - /// A 2x3 matrix. + /// A 3x3 matrix. /// + /// Matrix layout: + /// | 1st col | 2nd col | 3r col | + /// 1st row | scaleX | skrewY | persX | + /// 2nd row | skrewX | scaleY | persY | + /// 3rd row | transX | transY | persZ | + /// + /// Note: Skia.SkMatrix uses a transposed layout (where for example skrewX/skrewY and persX/transX are swapped). + /// #if !BUILDTASK public #endif @@ -14,40 +23,77 @@ namespace Avalonia { private readonly double _m11; private readonly double _m12; + private readonly double _m13; private readonly double _m21; private readonly double _m22; + private readonly double _m23; private readonly double _m31; private readonly double _m32; + private readonly double _m33; + + + /// + /// Initializes a new instance of the struct (equivalent to a 2x3 Matrix without perspective). + /// + /// The first element of the first row. + /// The second element of the first row. + /// The first element of the second row. + /// The second element of the second row. + /// The first element of the third row. + /// The second element of the third row. + public Matrix( + double scaleX, + double skrewY, + double skrewX, + double scaleY, + double offsetX, + double offsetY) : this( scaleX, skrewY, 0, skrewX, scaleY, 0, offsetX, offsetY, 1) + { + } + + /// /// Initializes a new instance of the struct. /// - /// The first element of the first row. - /// The second element of the first row. - /// The first element of the second row. - /// The second element of the second row. + /// The first element of the first row. + /// The second element of the first row. + /// The third element of the first row. + /// The first element of the second row. + /// The second element of the second row. + /// The third element of the second row. /// The first element of the third row. /// The second element of the third row. + /// The third element of the third row. public Matrix( - double m11, - double m12, - double m21, - double m22, + double scaleX, + double skrewY, + double persX, + double skrewX, + double scaleY, + double persY, double offsetX, - double offsetY) + double offsetY, + double persZ) { - _m11 = m11; - _m12 = m12; - _m21 = m21; - _m22 = m22; + _m11 = scaleX; + _m12 = skrewY; + _m13 = persX; + _m21 = skrewX; + _m22 = scaleY; + _m23 = persY; _m31 = offsetX; _m32 = offsetY; + _m33 = persZ; } /// /// Returns the multiplicative identity matrix. /// - public static Matrix Identity { get; } = new Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + public static Matrix Identity { get; } = new Matrix( + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0); /// /// Returns whether the matrix is the identity matrix. @@ -60,35 +106,50 @@ namespace Avalonia public bool HasInverse => !MathUtilities.IsZero(GetDeterminant()); /// - /// The first element of the first row + /// The first element of the first row (scaleX). /// public double M11 => _m11; /// - /// The second element of the first row + /// The second element of the first row (skrewY). /// public double M12 => _m12; /// - /// The first element of the second row + /// The third element of the first row (persX: input x-axis perspective factor). + /// + public double M13 => _m13; + + /// + /// The first element of the second row (skrewX). /// public double M21 => _m21; /// - /// The second element of the second row + /// The second element of the second row (scaleY). /// public double M22 => _m22; /// - /// The first element of the third row + /// The third element of the second row (persY: input y-axis perspective factor). + /// + public double M23 => _m23; + + /// + /// The first element of the third row (offsetX/translateX). /// public double M31 => _m31; /// - /// The second element of the third row + /// The second element of the third row (offsetY/translateY). /// public double M32 => _m32; + /// + /// The third element of the third row (persZ: perspective scale factor). + /// + public double M33 => _m33; + /// /// Multiplies two matrices together and returns the resulting matrix. /// @@ -103,7 +164,7 @@ namespace Avalonia (value1.M21 * value2.M11) + (value1.M22 * value2.M21), (value1.M21 * value2.M12) + (value1.M22 * value2.M22), (value1._m31 * value2.M11) + (value1._m32 * value2.M21) + value2._m31, - (value1._m31 * value2.M12) + (value1._m32 * value2.M22) + value2._m32); + (value1._m31 * value2.M12) + (value1._m32 * value2.M22) + value2._m32); //TODO: include perspective } /// @@ -171,7 +232,7 @@ namespace Avalonia /// A scaling matrix. public static Matrix CreateScale(double xScale, double yScale) { - return CreateScale(new Vector(xScale, yScale)); + return new Matrix(xScale, 0, 0, yScale, 0, 0); } /// @@ -181,7 +242,7 @@ namespace Avalonia /// A scaling matrix. public static Matrix CreateScale(Vector scales) { - return new Matrix(scales.X, 0, 0, scales.Y, 0, 0); + return CreateScale(scales.X, scales.Y); } /// @@ -247,7 +308,12 @@ namespace Avalonia /// public double GetDeterminant() { - return (_m11 * _m22) - (_m12 * _m21); + //return (_m11 * _m22) - (_m12 * _m21); //TODO: ensure new implementation yields the same result as before, when pers is 0,0,1 + + // implemented using "Laplace expansion": + return _m11 * (_m22 * _m33 - _m23 * _m32) + - _m12 * (_m21 * _m33 - _m23 * _m31) + + _m13 * (_m21 * _m32 - _m22 * _m31); } /// @@ -260,10 +326,13 @@ namespace Avalonia // ReSharper disable CompareOfFloatsByEqualityOperator return _m11 == other.M11 && _m12 == other.M12 && + _m13 == other.M13 && _m21 == other.M21 && _m22 == other.M22 && + _m23 == other.M23 && _m31 == other.M31 && - _m32 == other.M32; + _m32 == other.M32 && + _m33 == other.M33; // ReSharper restore CompareOfFloatsByEqualityOperator } @@ -280,9 +349,18 @@ namespace Avalonia /// The hash code. public override int GetHashCode() { - return M11.GetHashCode() + M12.GetHashCode() + - M21.GetHashCode() + M22.GetHashCode() + - M31.GetHashCode() + M32.GetHashCode(); + return (_m11, _m12, _m13, _m21, _m22, _m23, _m31, _m32, _m33).GetHashCode(); + } + + /// + /// Determines if the current matrix contains perspective (non-affine) transforms (true) or only (affine) transforms that could be mapped into an 2x3 matrix (false). + /// + private bool ContainsPerspective() + { + + // ReSharper disable CompareOfFloatsByEqualityOperator + return _m13 != 0 || _m23 != 0 || _m33 != 1; + // ReSharper restore CompareOfFloatsByEqualityOperator } /// @@ -292,15 +370,25 @@ namespace Avalonia public override string ToString() { CultureInfo ci = CultureInfo.CurrentCulture; + + string msg; + double[] values; + + if (ContainsPerspective()) + { + msg = "{{ {{M11:{0} M12:{1} M13:{2}}} {{M21:{3} M22:{4} M23:{5}}} {{M31:{6} M32:{7} M33:{8}}} }}"; + values = new[] { M11, M12, M13, M21, M22, M23, M31, M32, M33 }; + } + else + { + msg = "{{ {{M11:{0} M12:{1}}} {{M21:{2} M22:{3}}} {{M31:{4} M32:{5}}} }}"; + values = new[] { M11, M12, M21, M22, M31, M32 }; + } + return string.Format( ci, - "{{ {{M11:{0} M12:{1}}} {{M21:{2} M22:{3}}} {{M31:{4} M32:{5}}} }}", - M11.ToString(ci), - M12.ToString(ci), - M21.ToString(ci), - M22.ToString(ci), - M31.ToString(ci), - M32.ToString(ci)); + msg, + values.Select((v) => v.ToString(ci)).ToArray()); } /// @@ -311,7 +399,7 @@ namespace Avalonia { double d = GetDeterminant(); - if (MathUtilities.IsZero(d)) + if (MathUtilities.IsZero(d)) //TODO: decide if special handling is required for perspective { inverted = default; @@ -347,20 +435,30 @@ namespace Avalonia /// /// Parses a string. /// - /// Six comma-delimited double values (m11, m12, m21, m22, offsetX, offsetY) that describe the new + /// Six or nine comma-delimited double values (m11, m12, m21, m22, offsetX, offsetY[, persX, persY, persZ]) that describe the new /// The . public static Matrix Parse(string s) { + // initialize to satisfy compiler - only used when retrieved from string. + double v8 = 0; + double v9 = 0; + using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Matrix.")) { - return new Matrix( - tokenizer.ReadDouble(), - tokenizer.ReadDouble(), - tokenizer.ReadDouble(), - tokenizer.ReadDouble(), - tokenizer.ReadDouble(), - tokenizer.ReadDouble() - ); + var v1 = tokenizer.ReadDouble(); + var v2 = tokenizer.ReadDouble(); + var v3 = tokenizer.ReadDouble(); + var v4 = tokenizer.ReadDouble(); + var v5 = tokenizer.ReadDouble(); + var v6 = tokenizer.ReadDouble(); + var pers = tokenizer.TryReadDouble(out var v7); + pers = pers && tokenizer.TryReadDouble(out v8); + pers = pers && tokenizer.TryReadDouble(out v9); + + if (pers) + return new Matrix(v1, v2, v7, v3, v4, v8, v5, v6, v9); + else + return new Matrix(v1, v2, v3, v4, v5, v6); } } @@ -376,7 +474,7 @@ namespace Avalonia var determinant = matrix.GetDeterminant(); - if (MathUtilities.IsZero(determinant)) + if (MathUtilities.IsZero(determinant) || matrix.ContainsPerspective()) { return false; } From c40410cdb371f37071fb5df91367c60f057ea317 Mon Sep 17 00:00:00 2001 From: Andreas Schauerte Date: Mon, 5 Jul 2021 18:29:12 +0200 Subject: [PATCH 003/332] Add basic 3d transformation. --- .../Resources/Resource.Designer.cs | 2 +- samples/RenderDemo/MainWindow.xaml | 3 + .../RenderDemo/Pages/Transform3DPage.axaml | 81 ++++++++ .../RenderDemo/Pages/Transform3DPage.axaml.cs | 21 ++ .../ViewModels/Transform3DPageViewModel.cs | 61 ++++++ .../Resources/Resource.Designer.cs | 2 +- .../Animation/Animators/TransformAnimator.cs | 1 + src/Avalonia.Visuals/Matrix.cs | 50 +++-- src/Avalonia.Visuals/Media/Transform3D.cs | 192 ++++++++++++++++++ src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs | 6 +- 10 files changed, 393 insertions(+), 26 deletions(-) create mode 100644 samples/RenderDemo/Pages/Transform3DPage.axaml create mode 100644 samples/RenderDemo/Pages/Transform3DPage.axaml.cs create mode 100644 samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs create mode 100644 src/Avalonia.Visuals/Media/Transform3D.cs diff --git a/samples/ControlCatalog.Android/Resources/Resource.Designer.cs b/samples/ControlCatalog.Android/Resources/Resource.Designer.cs index dccc3f7159..b1ca548e2c 100644 --- a/samples/ControlCatalog.Android/Resources/Resource.Designer.cs +++ b/samples/ControlCatalog.Android/Resources/Resource.Designer.cs @@ -14,7 +14,7 @@ namespace ControlCatalog.Android { - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] public partial class Resource { diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml index a4c6299278..2b5bba928a 100644 --- a/samples/RenderDemo/MainWindow.xaml +++ b/samples/RenderDemo/MainWindow.xaml @@ -63,5 +63,8 @@ + + + diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml new file mode 100644 index 0000000000..ebd838eb67 --- /dev/null +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + X-Rotation: + + Y-Rotation: + + Z-Rotation: + + X: + + Y: + + Z: + + + + + + diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml.cs b/samples/RenderDemo/Pages/Transform3DPage.axaml.cs new file mode 100644 index 0000000000..5083189c4c --- /dev/null +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml.cs @@ -0,0 +1,21 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using RenderDemo.ViewModels; + +namespace RenderDemo.Pages; + +public class Transform3DPage : UserControl +{ + public Transform3DPage() + { + InitializeComponent(); + this.DataContext = new Transform3DPageViewModel(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} + diff --git a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs new file mode 100644 index 0000000000..7e7849bd01 --- /dev/null +++ b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs @@ -0,0 +1,61 @@ +using System; +using MiniMvvm; +using Avalonia.Animation; + +namespace RenderDemo.ViewModels +{ + public class Transform3DPageViewModel : ViewModelBase + { + private double _roationX = 0; + private double _rotationY = 0; + private double _rotationZ = 0; + + private double _x = 0; + private double _y = 0; + private double _z = 0; + + private double _depth = 200; + + public double RoationX + { + get => _roationX; + set => RaiseAndSetIfChanged(ref _roationX, value); + } + + public double RotationY + { + get => _rotationY; + set => RaiseAndSetIfChanged(ref _rotationY, value); + } + + public double RotationZ + { + get => _rotationZ; + set => RaiseAndSetIfChanged(ref _rotationZ, value); + } + + public double Depth + { + get => _depth; + set => RaiseAndSetIfChanged(ref _depth, value); + } + + public double X + { + get => _x; + set => RaiseAndSetIfChanged(ref _x, value); + } + + public double Y + { + get => _y; + set => RaiseAndSetIfChanged(ref _y, value); + } + + public double Z + { + get => _z; + set => RaiseAndSetIfChanged(ref _z, value); + } + } +} diff --git a/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs b/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs index 87fd47df25..83db67fcee 100644 --- a/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs +++ b/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs @@ -14,7 +14,7 @@ namespace Avalonia.AndroidTestApplication { - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] public partial class Resource { diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs index 34ec8ac503..a98f2ec65e 100644 --- a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs @@ -43,6 +43,7 @@ namespace Avalonia.Animation.Animators normalTransform.Children.Add(new SkewTransform()); normalTransform.Children.Add(new RotateTransform()); normalTransform.Children.Add(new TranslateTransform()); + normalTransform.Children.Add(new Transform3D()); ctrl.RenderTransform = normalTransform; } diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 9dd5bced86..e949d728d0 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -14,7 +14,7 @@ namespace Avalonia /// 2nd row | skrewX | scaleY | persY | /// 3rd row | transX | transY | persZ | /// - /// Note: Skia.SkMatrix uses a transposed layout (where for example skrewX/skrewY and persX/transX are swapped). + /// Note: Skia.SkMatrix uses a transposed layout (where for example skrewX/skrewY and perspp0/tranX are swapped). /// #if !BUILDTASK public @@ -30,8 +30,7 @@ namespace Avalonia private readonly double _m31; private readonly double _m32; private readonly double _m33; - - + /// /// Initializes a new instance of the struct (equivalent to a 2x3 Matrix without perspective). /// @@ -159,12 +158,15 @@ namespace Avalonia public static Matrix operator *(Matrix value1, Matrix value2) { return new Matrix( - (value1.M11 * value2.M11) + (value1.M12 * value2.M21), - (value1.M11 * value2.M12) + (value1.M12 * value2.M22), - (value1.M21 * value2.M11) + (value1.M22 * value2.M21), - (value1.M21 * value2.M12) + (value1.M22 * value2.M22), - (value1._m31 * value2.M11) + (value1._m32 * value2.M21) + value2._m31, - (value1._m31 * value2.M12) + (value1._m32 * value2.M22) + value2._m32); //TODO: include perspective + (value1.M11 * value2.M11) + (value1.M12 * value2.M21) + (value1.M13 * value2.M31), + (value1.M11 * value2.M12) + (value1.M12 * value2.M22) + (value1.M13 * value2.M32), + (value1.M11 * value2.M13) + (value1.M12 * value2.M23) + (value1.M13 * value2.M33), + (value1.M21 * value2.M11) + (value1.M22 * value2.M21) + (value1.M23 * value2.M31), + (value1.M21 * value2.M12) + (value1.M22 * value2.M22) + (value1.M23 * value2.M32), + (value1.M21 * value2.M13) + (value1.M22 * value2.M23) + (value1.M23 * value2.M33), + (value1.M31 * value2.M11) + (value1.M32 * value2.M21) + (value1.M33 * value2.M31), + (value1.M31 * value2.M12) + (value1.M32 * value2.M22) + (value1.M33 * value2.M32), + (value1.M31 * value2.M13) + (value1.M32 * value2.M23) + (value1.M33 * value2.M33)); } /// @@ -288,7 +290,7 @@ namespace Avalonia } /// - /// Prpends another matrix as pre-multiplication operation. + /// Prepends another matrix as pre-multiplication operation. /// Equivalent to value * this; /// /// A matrix. @@ -359,7 +361,7 @@ namespace Avalonia { // ReSharper disable CompareOfFloatsByEqualityOperator - return _m13 != 0 || _m23 != 0 || _m33 != 1; + return _m31 != 0 || _m32 != 0 || _m33 != 1; // ReSharper restore CompareOfFloatsByEqualityOperator } @@ -399,21 +401,27 @@ namespace Avalonia { double d = GetDeterminant(); - if (MathUtilities.IsZero(d)) //TODO: decide if special handling is required for perspective + if (MathUtilities.IsZero(d)) { inverted = default; return false; } + var invdet = 1 / d; + inverted = new Matrix( - _m22 / d, - -_m12 / d, - -_m21 / d, - _m11 / d, - ((_m21 * _m32) - (_m22 * _m31)) / d, - ((_m12 * _m31) - (_m11 * _m32)) / d); - + (_m22 * _m33 - _m32 * _m23) * invdet, + (_m13 * _m31 - _m12 * _m33) * invdet, + (_m12 * _m23 - _m13 * _m22) * invdet, + (_m23 * _m31 - _m21 * _m33) * invdet, + (_m11 * _m33 - _m13 * _m31) * invdet, + (_m21 * _m13 - _m11 * _m23) * invdet, + (_m21 * _m32 - _m31 * _m22) * invdet, + (_m21 * _m12 - _m11 * _m32) * invdet, + (_m11 * _m22 - _m21 * _m12) * invdet + ); + return true; } @@ -424,7 +432,7 @@ namespace Avalonia /// The inverted matrix. public Matrix Invert() { - if (!TryInvert(out Matrix inverted)) + if (!TryInvert(out var inverted)) { throw new InvalidOperationException("Transform is not invertible."); } @@ -467,7 +475,7 @@ namespace Avalonia /// /// Matrix to decompose. /// Decomposed matrix. - /// The status of the operation. + /// The status of the operation. public static bool TryDecomposeTransform(Matrix matrix, out Decomposed decomposed) { decomposed = default; diff --git a/src/Avalonia.Visuals/Media/Transform3D.cs b/src/Avalonia.Visuals/Media/Transform3D.cs new file mode 100644 index 0000000000..e063f76556 --- /dev/null +++ b/src/Avalonia.Visuals/Media/Transform3D.cs @@ -0,0 +1,192 @@ +using System; +using System.Numerics; + +namespace Avalonia.Media; + +public class Transform3D : Transform +{ + /// + /// Defines the property. + /// + public static readonly StyledProperty s_rotationXProperty = + AvaloniaProperty.Register(nameof(RotationX)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_rotationYProperty = + AvaloniaProperty.Register(nameof(RotationY)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_rotationZProperty = + AvaloniaProperty.Register(nameof(RotationZ)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_depthProperty = + AvaloniaProperty.Register(nameof(Depth)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_centerXProperty = + AvaloniaProperty.Register(nameof(CenterX)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_centerYProperty = + AvaloniaProperty.Register(nameof(CenterY)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_xProperty = + AvaloniaProperty.Register(nameof(X)); + + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_yProperty = + AvaloniaProperty.Register(nameof(Y)); + + + /// + /// Defines the property. + /// + public static readonly StyledProperty s_zProperty = + AvaloniaProperty.Register(nameof(Z)); + + + /// + /// Initializes a new instance of the class. + /// + public Transform3D() + { + this.GetObservable(s_rotationXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_rotationYProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_rotationZProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_depthProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_centerXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_centerYProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_xProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_yProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(s_zProperty).Subscribe(_ => RaiseChanged()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The skew angle of X-axis, in degrees. + /// The skew angle of Y-axis, in degrees. + /// + public Transform3D( + double rotationX, + double rotationY, + double rotationZ, + double depth, + double centerX, + double centerY) : this() + { + RotationX = rotationX; + RotationY = rotationY; + RotationZ = rotationZ; + Depth = depth; + CenterX = centerX; + CenterY = centerY; + } + + /// + /// Gets or sets the X property. + /// + public double RotationX + { + get => GetValue(s_rotationXProperty); + set => SetValue(s_rotationXProperty, value); + } + + /// + /// Gets or sets the Y property. + /// + public double RotationY + { + get => GetValue(s_rotationYProperty); + set => SetValue(s_rotationYProperty, value); + } + + public double RotationZ + { + get => GetValue(s_rotationZProperty); + set => SetValue(s_rotationZProperty, value); + } + + public double Depth + { + get => GetValue(s_depthProperty); + set => SetValue(s_depthProperty, value); + } + + public double CenterX + { + get => GetValue(s_centerXProperty); + set => SetValue(s_centerXProperty, value); + } + + public double CenterY + { + get => GetValue(s_centerYProperty); + set => SetValue(s_centerYProperty, value); + } + + public double X + { + get => GetValue(s_xProperty); + set => SetValue(s_xProperty, value); + } + + public double Y + { + get => GetValue(s_yProperty); + set => SetValue(s_yProperty, value); + } + + public double Z + { + get => GetValue(s_zProperty); + set => SetValue(s_zProperty, value); + } + + /// + /// Gets the transform's . + /// + public override Matrix Value + { + get + { + var matrix44 = Matrix4x4.Identity; + + matrix44 *= Matrix4x4.CreateTranslation((float)X, (float)Y, (float)Z); + + matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(RotationX)); + matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(RotationY)); + matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(RotationZ)); + + var matrix = new Matrix( + matrix44.M11, + matrix44.M12, + matrix44.M14, + matrix44.M21, + matrix44.M22, + matrix44.M24, + matrix44.M41, + matrix44.M42, + matrix44.M44); + + return matrix; + } + } +} diff --git a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs index 75b4231640..c0afc8bd9c 100644 --- a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs @@ -103,9 +103,9 @@ namespace Avalonia.Skia SkewY = (float)m.M12, ScaleY = (float)m.M22, TransY = (float)m.M32, - Persp0 = 0, - Persp1 = 0, - Persp2 = 1 + Persp0 = (float)m.M13, + Persp1 = (float)m.M23, + Persp2 = (float)m.M33 }; return sm; From 0a831b978483699b1dfa75ca177307aebef98e6e Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Wed, 19 Jan 2022 11:16:33 +0100 Subject: [PATCH 004/332] Refactor names. --- .../RenderDemo/Pages/Transform3DPage.axaml | 7 +- .../ViewModels/Transform3DPageViewModel.cs | 8 +- src/Avalonia.Visuals/Media/Transform3D.cs | 135 ++++++++---------- 3 files changed, 64 insertions(+), 86 deletions(-) diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index ebd838eb67..e66c498bbc 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -54,12 +54,11 @@ + CenterX="{Binding X}" + CenterY="{Binding Y}" + CenterZ="{Binding Z}" /> X-Rotation: diff --git a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs index 7e7849bd01..d28705fc0d 100644 --- a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs +++ b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs @@ -6,7 +6,7 @@ namespace RenderDemo.ViewModels { public class Transform3DPageViewModel : ViewModelBase { - private double _roationX = 0; + private double _rotationX = 0; private double _rotationY = 0; private double _rotationZ = 0; @@ -16,10 +16,10 @@ namespace RenderDemo.ViewModels private double _depth = 200; - public double RoationX + public double RotationX { - get => _roationX; - set => RaiseAndSetIfChanged(ref _roationX, value); + get => _rotationX; + set => RaiseAndSetIfChanged(ref _rotationX, value); } public double RotationY diff --git a/src/Avalonia.Visuals/Media/Transform3D.cs b/src/Avalonia.Visuals/Media/Transform3D.cs index e063f76556..cfbde3204a 100644 --- a/src/Avalonia.Visuals/Media/Transform3D.cs +++ b/src/Avalonia.Visuals/Media/Transform3D.cs @@ -8,58 +8,41 @@ public class Transform3D : Transform /// /// Defines the property. /// - public static readonly StyledProperty s_rotationXProperty = + public static readonly StyledProperty RotationXProperty = AvaloniaProperty.Register(nameof(RotationX)); /// /// Defines the property. /// - public static readonly StyledProperty s_rotationYProperty = + public static readonly StyledProperty RotationYProperty = AvaloniaProperty.Register(nameof(RotationY)); /// /// Defines the property. /// - public static readonly StyledProperty s_rotationZProperty = + public static readonly StyledProperty RotationZProperty = AvaloniaProperty.Register(nameof(RotationZ)); - /// - /// Defines the property. - /// - public static readonly StyledProperty s_depthProperty = - AvaloniaProperty.Register(nameof(Depth)); /// /// Defines the property. /// - public static readonly StyledProperty s_centerXProperty = + public static readonly StyledProperty CenterXProperty = AvaloniaProperty.Register(nameof(CenterX)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty s_centerYProperty = - AvaloniaProperty.Register(nameof(CenterY)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty s_xProperty = - AvaloniaProperty.Register(nameof(X)); /// /// Defines the property. /// - public static readonly StyledProperty s_yProperty = - AvaloniaProperty.Register(nameof(Y)); + public static readonly StyledProperty CenterYProperty = + AvaloniaProperty.Register(nameof(CenterY)); /// - /// Defines the property. + /// Defines the property. /// - public static readonly StyledProperty s_zProperty = - AvaloniaProperty.Register(nameof(Z)); + public static readonly StyledProperty CenterZProperty = + AvaloniaProperty.Register(nameof(CenterZ)); /// @@ -67,97 +50,93 @@ public class Transform3D : Transform /// public Transform3D() { - this.GetObservable(s_rotationXProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_rotationYProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_rotationZProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_depthProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_centerXProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_centerYProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_xProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_yProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(s_zProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(RotationXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(RotationYProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(RotationZProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterZProperty).Subscribe(_ => RaiseChanged()); } /// /// Initializes a new instance of the class. /// - /// The skew angle of X-axis, in degrees. - /// The skew angle of Y-axis, in degrees. - /// + /// The rotation around the X-Axis + /// The rotation around the Y-Axis + /// The rotation around the Z-Axis + /// The origin of the X-Axis + /// The origin of the Y-Axis + /// The origin of the Z-Axis public Transform3D( double rotationX, double rotationY, double rotationZ, - double depth, - double centerX, - double centerY) : this() + double originCenterX, + double originCenterY, + double originCenterZ) : this() { RotationX = rotationX; RotationY = rotationY; RotationZ = rotationZ; - Depth = depth; - CenterX = centerX; - CenterY = centerY; + CenterX = originCenterX; + CenterY = originCenterY; + CenterZ = originCenterZ; } /// - /// Gets or sets the X property. + /// Sets the rotation around the X-Axis /// public double RotationX { - get => GetValue(s_rotationXProperty); - set => SetValue(s_rotationXProperty, value); + get => GetValue(RotationXProperty); + set => SetValue(RotationXProperty, value); } /// - /// Gets or sets the Y property. + /// Sets the rotation around the Y-Axis /// public double RotationY { - get => GetValue(s_rotationYProperty); - set => SetValue(s_rotationYProperty, value); + get => GetValue(RotationYProperty); + set => SetValue(RotationYProperty, value); } + /// + /// Sets the rotation around the Z-Axis + /// public double RotationZ { - get => GetValue(s_rotationZProperty); - set => SetValue(s_rotationZProperty, value); - } - - public double Depth - { - get => GetValue(s_depthProperty); - set => SetValue(s_depthProperty, value); + get => GetValue(RotationZProperty); + set => SetValue(RotationZProperty, value); } + /// + /// Moves the origin of the X-Axis + /// public double CenterX { - get => GetValue(s_centerXProperty); - set => SetValue(s_centerXProperty, value); + get => GetValue(CenterXProperty); + set => SetValue(CenterXProperty, value); } + /// + /// Moves the origin of the Y-Axis + /// public double CenterY { - get => GetValue(s_centerYProperty); - set => SetValue(s_centerYProperty, value); + get => GetValue(CenterYProperty); + set => SetValue(CenterYProperty, value); } - public double X - { - get => GetValue(s_xProperty); - set => SetValue(s_xProperty, value); - } - - public double Y - { - get => GetValue(s_yProperty); - set => SetValue(s_yProperty, value); - } - - public double Z + /// + /// Moves the origin of the Z-Axis + /// + public double CenterZ { - get => GetValue(s_zProperty); - set => SetValue(s_zProperty, value); + get => GetValue(CenterZProperty); + set => SetValue(CenterZProperty, value); } /// @@ -169,7 +148,7 @@ public class Transform3D : Transform { var matrix44 = Matrix4x4.Identity; - matrix44 *= Matrix4x4.CreateTranslation((float)X, (float)Y, (float)Z); + matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ); matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(RotationX)); matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(RotationY)); From 9a01f13114f77a889d68af2e06fbfebd0aa87882 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Wed, 19 Jan 2022 13:39:57 +0100 Subject: [PATCH 005/332] Fix order of transforms. --- samples/RenderDemo/Pages/Transform3DPage.axaml | 2 +- src/Avalonia.Visuals/Media/Transform3D.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index e66c498bbc..0bf2279dd3 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -2,7 +2,7 @@ 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" + mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650" x:Class="RenderDemo.Pages.Transform3DPage"> diff --git a/src/Avalonia.Visuals/Media/Transform3D.cs b/src/Avalonia.Visuals/Media/Transform3D.cs index cfbde3204a..cbc1fc958d 100644 --- a/src/Avalonia.Visuals/Media/Transform3D.cs +++ b/src/Avalonia.Visuals/Media/Transform3D.cs @@ -154,6 +154,13 @@ public class Transform3D : Transform matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(RotationY)); matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(RotationZ)); + matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ); + + var perspectiveMatrix = Matrix4x4.Identity; + perspectiveMatrix.M34 = -1 / (float)50; + + matrix44 *= perspectiveMatrix; + var matrix = new Matrix( matrix44.M11, matrix44.M12, From 07f45cf1d724535d483f2c9b8acdfe6d393630cf Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Wed, 19 Jan 2022 15:15:56 +0100 Subject: [PATCH 006/332] Add animation. Add controls instead of Vector to prof usability. --- .../RenderDemo/Pages/Transform3DPage.axaml | 252 +++++++++++++----- 1 file changed, 179 insertions(+), 73 deletions(-) diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index 0bf2279dd3..438611976a 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -2,79 +2,185 @@ 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="650" + mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="200" x:Class="RenderDemo.Pages.Transform3DPage"> - - - - - - - - - - - - - - - - - - - - X-Rotation: - - Y-Rotation: - - Z-Rotation: - - X: - - Y: - - Z: - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - From 9fdb48d0c4328ea6332851ed0758bd24ca692ee8 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Wed, 19 Jan 2022 17:29:31 +0100 Subject: [PATCH 007/332] Rename transform. Re-add depth. Add slider to preview for showing effect of depth. --- .../RenderDemo/Pages/Transform3DPage.axaml | 89 ++++---- .../ViewModels/Transform3DPageViewModel.cs | 44 ---- .../Animation/Animators/TransformAnimator.cs | 2 +- .../Media/Rotate3DTransform.cs | 195 ++++++++++++++++++ src/Avalonia.Visuals/Media/Transform3D.cs | 178 ---------------- 5 files changed, 235 insertions(+), 273 deletions(-) create mode 100644 src/Avalonia.Visuals/Media/Rotate3DTransform.cs delete mode 100644 src/Avalonia.Visuals/Media/Transform3D.cs diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index 438611976a..1093399c0c 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -2,7 +2,7 @@ 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="200" d:DesignHeight="200" + mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="400" x:Class="RenderDemo.Pages.Transform3DPage"> @@ -16,10 +16,10 @@ - + @@ -142,45 +142,34 @@ - + - + - + - + + + Depth: + + + diff --git a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs index d28705fc0d..0c1caac8ea 100644 --- a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs +++ b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs @@ -6,56 +6,12 @@ namespace RenderDemo.ViewModels { public class Transform3DPageViewModel : ViewModelBase { - private double _rotationX = 0; - private double _rotationY = 0; - private double _rotationZ = 0; - - private double _x = 0; - private double _y = 0; - private double _z = 0; - private double _depth = 200; - public double RotationX - { - get => _rotationX; - set => RaiseAndSetIfChanged(ref _rotationX, value); - } - - public double RotationY - { - get => _rotationY; - set => RaiseAndSetIfChanged(ref _rotationY, value); - } - - public double RotationZ - { - get => _rotationZ; - set => RaiseAndSetIfChanged(ref _rotationZ, value); - } - public double Depth { get => _depth; set => RaiseAndSetIfChanged(ref _depth, value); } - - public double X - { - get => _x; - set => RaiseAndSetIfChanged(ref _x, value); - } - - public double Y - { - get => _y; - set => RaiseAndSetIfChanged(ref _y, value); - } - - public double Z - { - get => _z; - set => RaiseAndSetIfChanged(ref _z, value); - } } } diff --git a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs index a98f2ec65e..e12ca722f9 100644 --- a/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs +++ b/src/Avalonia.Visuals/Animation/Animators/TransformAnimator.cs @@ -43,7 +43,7 @@ namespace Avalonia.Animation.Animators normalTransform.Children.Add(new SkewTransform()); normalTransform.Children.Add(new RotateTransform()); normalTransform.Children.Add(new TranslateTransform()); - normalTransform.Children.Add(new Transform3D()); + normalTransform.Children.Add(new Rotate3DTransform()); ctrl.RenderTransform = normalTransform; } diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs new file mode 100644 index 0000000000..9a81ae306c --- /dev/null +++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs @@ -0,0 +1,195 @@ +using System; +using System.Numerics; + +namespace Avalonia.Media; + +/// +/// Non-Affine 3D transformation for rotating an visual around a definable axis +/// +public class Rotate3DTransform : Transform +{ + /// + /// Defines the property. + /// + public static readonly StyledProperty RotationXProperty = + AvaloniaProperty.Register(nameof(RotationX)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty RotationYProperty = + AvaloniaProperty.Register(nameof(RotationY)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty RotationZProperty = + AvaloniaProperty.Register(nameof(RotationZ)); + + + /// + /// Defines the property. + /// + public static readonly StyledProperty CenterXProperty = + AvaloniaProperty.Register(nameof(CenterX)); + + + /// + /// Defines the property. + /// + public static readonly StyledProperty CenterYProperty = + AvaloniaProperty.Register(nameof(CenterY)); + + + /// + /// Defines the property. + /// + public static readonly StyledProperty CenterZProperty = + AvaloniaProperty.Register(nameof(CenterZ)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty DepthProperty = + AvaloniaProperty.Register(nameof(Depth)); + + /// + /// Initializes a new instance of the class. + /// + public Rotate3DTransform() + { + this.GetObservable(RotationXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(RotationYProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(RotationZProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(CenterZProperty).Subscribe(_ => RaiseChanged()); + } + + /// + /// Initializes a new instance of the class. + /// + /// The rotation around the X-Axis + /// The rotation around the Y-Axis + /// The rotation around the Z-Axis + /// The origin of the X-Axis + /// The origin of the Y-Axis + /// The origin of the Z-Axis + public Rotate3DTransform( + double rotationX, + double rotationY, + double rotationZ, + double centerX, + double centerY, + double centerZ) : this() + { + RotationX = rotationX; + RotationY = rotationY; + RotationZ = rotationZ; + CenterX = centerX; + CenterY = centerY; + CenterZ = centerZ; + } + + /// + /// Sets the rotation around the X-Axis + /// + public double RotationX + { + get => GetValue(RotationXProperty); + set => SetValue(RotationXProperty, value); + } + + /// + /// Sets the rotation around the Y-Axis + /// + public double RotationY + { + get => GetValue(RotationYProperty); + set => SetValue(RotationYProperty, value); + } + + /// + /// Sets the rotation around the Z-Axis + /// + public double RotationZ + { + get => GetValue(RotationZProperty); + set => SetValue(RotationZProperty, value); + } + + /// + /// Moves the origin of the X-Axis + /// + public double CenterX + { + get => GetValue(CenterXProperty); + set => SetValue(CenterXProperty, value); + } + + /// + /// Moves the origin of the Y-Axis + /// + public double CenterY + { + get => GetValue(CenterYProperty); + set => SetValue(CenterYProperty, value); + } + + /// + /// Moves the origin of the Z-Axis + /// + public double CenterZ + { + get => GetValue(CenterZProperty); + set => SetValue(CenterZProperty, value); + } + + /// + /// Affects the depth of the rotation effect + /// + public double Depth + { + get => GetValue(DepthProperty); + set => SetValue(DepthProperty, value); + } + + /// + /// Gets the transform's . + /// + public override Matrix Value + { + get + { + var matrix44 = Matrix4x4.Identity; + + matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ); + + matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(RotationX)); + matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(RotationY)); + matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(RotationZ)); + + matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ); + + if (Depth != 0) + { + var perspectiveMatrix = Matrix4x4.Identity; + perspectiveMatrix.M34 = -1 / (float)Depth; + matrix44 *= perspectiveMatrix; + } + + var matrix = new Matrix( + matrix44.M11, + matrix44.M12, + matrix44.M14, + matrix44.M21, + matrix44.M22, + matrix44.M24, + matrix44.M41, + matrix44.M42, + matrix44.M44); + + return matrix; + } + } +} diff --git a/src/Avalonia.Visuals/Media/Transform3D.cs b/src/Avalonia.Visuals/Media/Transform3D.cs deleted file mode 100644 index cbc1fc958d..0000000000 --- a/src/Avalonia.Visuals/Media/Transform3D.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using System.Numerics; - -namespace Avalonia.Media; - -public class Transform3D : Transform -{ - /// - /// Defines the property. - /// - public static readonly StyledProperty RotationXProperty = - AvaloniaProperty.Register(nameof(RotationX)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty RotationYProperty = - AvaloniaProperty.Register(nameof(RotationY)); - - /// - /// Defines the property. - /// - public static readonly StyledProperty RotationZProperty = - AvaloniaProperty.Register(nameof(RotationZ)); - - - /// - /// Defines the property. - /// - public static readonly StyledProperty CenterXProperty = - AvaloniaProperty.Register(nameof(CenterX)); - - - /// - /// Defines the property. - /// - public static readonly StyledProperty CenterYProperty = - AvaloniaProperty.Register(nameof(CenterY)); - - - /// - /// Defines the property. - /// - public static readonly StyledProperty CenterZProperty = - AvaloniaProperty.Register(nameof(CenterZ)); - - - /// - /// Initializes a new instance of the class. - /// - public Transform3D() - { - this.GetObservable(RotationXProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(RotationYProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(RotationZProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged()); - this.GetObservable(CenterZProperty).Subscribe(_ => RaiseChanged()); - } - - /// - /// Initializes a new instance of the class. - /// - /// The rotation around the X-Axis - /// The rotation around the Y-Axis - /// The rotation around the Z-Axis - /// The origin of the X-Axis - /// The origin of the Y-Axis - /// The origin of the Z-Axis - public Transform3D( - double rotationX, - double rotationY, - double rotationZ, - double originCenterX, - double originCenterY, - double originCenterZ) : this() - { - RotationX = rotationX; - RotationY = rotationY; - RotationZ = rotationZ; - CenterX = originCenterX; - CenterY = originCenterY; - CenterZ = originCenterZ; - } - - /// - /// Sets the rotation around the X-Axis - /// - public double RotationX - { - get => GetValue(RotationXProperty); - set => SetValue(RotationXProperty, value); - } - - /// - /// Sets the rotation around the Y-Axis - /// - public double RotationY - { - get => GetValue(RotationYProperty); - set => SetValue(RotationYProperty, value); - } - - /// - /// Sets the rotation around the Z-Axis - /// - public double RotationZ - { - get => GetValue(RotationZProperty); - set => SetValue(RotationZProperty, value); - } - - /// - /// Moves the origin of the X-Axis - /// - public double CenterX - { - get => GetValue(CenterXProperty); - set => SetValue(CenterXProperty, value); - } - - /// - /// Moves the origin of the Y-Axis - /// - public double CenterY - { - get => GetValue(CenterYProperty); - set => SetValue(CenterYProperty, value); - } - - /// - /// Moves the origin of the Z-Axis - /// - public double CenterZ - { - get => GetValue(CenterZProperty); - set => SetValue(CenterZProperty, value); - } - - /// - /// Gets the transform's . - /// - public override Matrix Value - { - get - { - var matrix44 = Matrix4x4.Identity; - - matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ); - - matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(RotationX)); - matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(RotationY)); - matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(RotationZ)); - - matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ); - - var perspectiveMatrix = Matrix4x4.Identity; - perspectiveMatrix.M34 = -1 / (float)50; - - matrix44 *= perspectiveMatrix; - - var matrix = new Matrix( - matrix44.M11, - matrix44.M12, - matrix44.M14, - matrix44.M21, - matrix44.M22, - matrix44.M24, - matrix44.M41, - matrix44.M42, - matrix44.M44); - - return matrix; - } - } -} From 8c131ba100ac3890595216c4936feb54840a2688 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 20 Jan 2022 06:13:00 +0100 Subject: [PATCH 008/332] Improve readability in RenderDemo, slow down animation. --- .../RenderDemo/Pages/Transform3DPage.axaml | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index 1093399c0c..8646dc6870 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -8,10 +8,15 @@ @@ -24,9 +29,16 @@ + + @@ -140,25 +156,25 @@ - + - + - + - + From e6d86fb898ce92569cb590bc2466d8ec7542627c Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 20 Jan 2022 06:54:00 +0100 Subject: [PATCH 009/332] Fix ContainsPerspective method. --- src/Avalonia.Visuals/Matrix.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index e949d728d0..4326dc3670 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -361,7 +361,7 @@ namespace Avalonia { // ReSharper disable CompareOfFloatsByEqualityOperator - return _m31 != 0 || _m32 != 0 || _m33 != 1; + return _m13 != 0 || _m23 != 0 || _m33 != 1; // ReSharper restore CompareOfFloatsByEqualityOperator } From bde9c078c56eb3f7864cac17a46315af783fa123 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 20 Jan 2022 13:58:34 +0100 Subject: [PATCH 010/332] Add observable. Remove borders from sample to better visualize error. --- samples/RenderDemo/Pages/Transform3DPage.axaml | 8 ++++---- src/Avalonia.Visuals/Media/Rotate3DTransform.cs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index 8646dc6870..9f369dae98 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -162,24 +162,24 @@ Depth="{Binding Depth}"/> - + - + diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs index 9a81ae306c..a3af6b8c66 100644 --- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs +++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs @@ -64,6 +64,7 @@ public class Rotate3DTransform : Transform this.GetObservable(CenterXProperty).Subscribe(_ => RaiseChanged()); this.GetObservable(CenterYProperty).Subscribe(_ => RaiseChanged()); this.GetObservable(CenterZProperty).Subscribe(_ => RaiseChanged()); + this.GetObservable(DepthProperty).Subscribe(_ => RaiseChanged()); } /// From 9078ca7dc8b2512322e5a2b26e91c2ca8348f9e1 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Wed, 26 Jan 2022 14:46:54 +0100 Subject: [PATCH 011/332] Fix Rotate3DTransform for DeferredRenderer. --- .../Avalonia.Build.Tasks.csproj | 1 + src/Avalonia.Visuals/Matrix.cs | 2 +- src/Avalonia.Visuals/Point.cs | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj index e864ea2007..7e4272f5d2 100644 --- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj +++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj @@ -94,5 +94,6 @@ + diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 4326dc3670..38d0508ffb 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -357,7 +357,7 @@ namespace Avalonia /// /// Determines if the current matrix contains perspective (non-affine) transforms (true) or only (affine) transforms that could be mapped into an 2x3 matrix (false). /// - private bool ContainsPerspective() + public bool ContainsPerspective() { // ReSharper disable CompareOfFloatsByEqualityOperator diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs index 67e7d71fbc..473de8e501 100644 --- a/src/Avalonia.Visuals/Point.cs +++ b/src/Avalonia.Visuals/Point.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Numerics; #if !BUILDTASK using Avalonia.Animation.Animators; #endif @@ -244,6 +245,22 @@ namespace Avalonia /// The transformed point. public Point Transform(Matrix transform) { + if (transform.ContainsPerspective()) + { + var m44 = new Matrix4x4( + (float)transform.M11, (float)transform.M12, (float)transform.M13, 0, + (float)transform.M21, (float)transform.M22, (float)transform.M23, 0, + (float)transform.M31, (float)transform.M32, (float)transform.M33, 0, + 0, 0, 0, 1 + ); + + var vector = new Vector3((float)X, (float)Y, 1); + var transformedVector = Vector3.Transform(vector, m44); + var z = 1 / transformedVector.Z; + + return new Point(transformedVector.X * z, transformedVector.Y * z); + } + var x = X; var y = Y; var xadd = y * transform.M21 + transform.M31; From e8f2d3e3f3372fa226a1cb57b447974fe1da8f79 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Wed, 26 Jan 2022 16:25:18 +0100 Subject: [PATCH 012/332] Add comments, remove todos, extend example. --- .../RenderDemo/Pages/Transform3DPage.axaml | 162 ++++++++++++------ .../ViewModels/Transform3DPageViewModel.cs | 44 +++++ src/Avalonia.Visuals/Matrix.cs | 50 +++++- .../Media/Rotate3DTransform.cs | 73 ++++---- src/Avalonia.Visuals/Point.cs | 29 +--- 5 files changed, 235 insertions(+), 123 deletions(-) diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index 9f369dae98..bf63b6d1c6 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -2,12 +2,12 @@ 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="400" d:DesignHeight="400" + mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="700" x:Class="RenderDemo.Pages.Transform3DPage"> - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs index 2a6bdcb434..c8d1d40e3a 100644 --- a/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs +++ b/samples/RenderDemo/ViewModels/Transform3DPageViewModel.cs @@ -8,7 +8,6 @@ namespace RenderDemo.ViewModels { private double _depth = 200; - private double _depth2 = 200; private double _centerX = 0; private double _centerY = 0; private double _centerZ = 0; @@ -22,11 +21,6 @@ namespace RenderDemo.ViewModels set => RaiseAndSetIfChanged(ref _depth, value); } - public double Depth2 - { - get => _depth2; - set => RaiseAndSetIfChanged(ref _depth2, value); - } public double CenterX { get => _centerX; From 3e7f190ff9881fc0785e4698aca96099212e5b71 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 27 Jan 2022 13:39:27 +0100 Subject: [PATCH 017/332] Add code review changes: Fix typos. Simplify code. Generalize code. Remove duplications. Improve performance. --- .../RenderDemo/Pages/Transform3DPage.axaml | 234 +++++++++--------- .../Resources/Resource.Designer.cs | 2 +- .../Transitions/Rotate3DTransition.cs | 124 ++++------ src/Avalonia.Visuals/Matrix.cs | 12 +- .../Media/Rotate3DTransform.cs | 2 +- src/Avalonia.Visuals/Point.cs | 7 +- 6 files changed, 163 insertions(+), 218 deletions(-) diff --git a/samples/RenderDemo/Pages/Transform3DPage.axaml b/samples/RenderDemo/Pages/Transform3DPage.axaml index fa03c7ba49..30ed35bbac 100644 --- a/samples/RenderDemo/Pages/Transform3DPage.axaml +++ b/samples/RenderDemo/Pages/Transform3DPage.axaml @@ -21,149 +21,139 @@ + + + + + + + + + - - - - - - - - - - - + - - - - + - - - - + - - - - + diff --git a/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs b/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs index 83db67fcee..87fd47df25 100644 --- a/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs +++ b/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs @@ -14,7 +14,7 @@ namespace Avalonia.AndroidTestApplication { - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")] public partial class Resource { diff --git a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs index b603fe5f7b..56567f5fea 100644 --- a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs +++ b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Avalonia.Collections; using Avalonia.Media; using Avalonia.Styling; @@ -9,18 +10,26 @@ namespace Avalonia.Animation; public class Rotate3DTransition: PageSlide { - + /// - /// Creates a new instance if the + /// Creates a new instance of the /// /// How long the rotation should take place /// The orientation of the rotation - public Rotate3DTransition(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal) + public Rotate3DTransition(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal, double? depth = null) : base(duration, orientation) - {} + { + Depth = depth; + } + + /// + /// Defines the depth of the 3D Effect. If null, depth will be calculated automatically from the width or height + /// of the common parent of the visual being rotated. + /// + public double? Depth { get; set; } /// - /// Creates a new instance if the + /// Creates a new instance of the /// public Rotate3DTransition() { } @@ -41,49 +50,32 @@ public class Rotate3DTransition: PageSlide _ => throw new ArgumentOutOfRangeException() }; - var depthSetter = new Setter {Property = Rotate3DTransform.DepthProperty, Value = center}; + var depthSetter = new Setter {Property = Rotate3DTransform.DepthProperty, Value = Depth ?? center}; var centerZSetter = new Setter {Property = Rotate3DTransform.CenterZProperty, Value = -center / 2}; + KeyFrame CreateKeyFrame(double cue, double rotation, int zIndex) => + new() { + Setters = + { + new Setter { Property = rotateProperty, Value = rotation }, + new Setter { Property = Visual.ZIndexProperty, Value = zIndex }, + centerZSetter, + depthSetter + }, + Cue = new Cue(cue) + }; + if (from != null) { var animation = new Animation { + Easing = SlideOutEasing, Duration = Duration, Children = { - new KeyFrame - { - Setters = - { - new Setter { Property = rotateProperty, Value = 0d }, - new Setter { Property = Visual.ZIndexProperty, Value = 2 }, - centerZSetter, - depthSetter, - }, - Cue = new Cue(0d) - }, - new KeyFrame - { - Setters = - { - new Setter { Property = rotateProperty, Value = 45d * (forward ? -1 : 1) }, - new Setter { Property = Visual.ZIndexProperty, Value = 1 }, - centerZSetter, - depthSetter - }, - Cue = new Cue(0.5d) - }, - new KeyFrame - { - Setters = - { - new Setter { Property = rotateProperty, Value = 90d * (forward ? -1 : 1) }, - new Setter { Property = Visual.ZIndexProperty, Value = 1 }, - centerZSetter, - depthSetter - }, - Cue = new Cue(1d) - } + CreateKeyFrame(0d, 0d, 2), + CreateKeyFrame(0.5d, 45d * (forward ? -1 : 1), 1), + CreateKeyFrame(1d, 90d * (forward ? -1 : 1), 1) } }; @@ -95,42 +87,13 @@ public class Rotate3DTransition: PageSlide to.IsVisible = true; var animation = new Animation { + Easing = SlideInEasing, Duration = Duration, Children = { - new KeyFrame - { - Setters = - { - new Setter { Property = rotateProperty, Value = 90d * (forward ? 1 : -1) }, - new Setter { Property = Visual.ZIndexProperty, Value = 1 }, - centerZSetter, - depthSetter - }, - Cue = new Cue(0d) - }, - new KeyFrame - { - Setters = - { - new Setter { Property = Visual.ZIndexProperty, Value = 1 }, - new Setter { Property = rotateProperty, Value = 45d * (forward ? 1 : -1) }, - centerZSetter, - depthSetter - }, - Cue = new Cue(0.5d) - }, - new KeyFrame - { - Setters = - { - new Setter { Property = rotateProperty, Value = 0d }, - new Setter { Property = Visual.ZIndexProperty, Value = 2 }, - centerZSetter, - depthSetter, - }, - Cue = new Cue(1d) - } + CreateKeyFrame(0d, 90d * (forward ? 1 : -1), 1), + CreateKeyFrame(0.5d, 45d * (forward ? 1 : -1), 1), + CreateKeyFrame(1d, 0d, 2) } }; @@ -139,15 +102,18 @@ public class Rotate3DTransition: PageSlide await Task.WhenAll(tasks); - if (from != null && !cancellationToken.IsCancellationRequested) + if (!cancellationToken.IsCancellationRequested) { - from.IsVisible = false; - from.ZIndex = 1; - } + if (from != null) + { + from.IsVisible = false; + from.ZIndex = 1; + } - if (to != null && !cancellationToken.IsCancellationRequested) - { - to.ZIndex = 2; + if (to != null) + { + to.ZIndex = 2; + } } } } diff --git a/src/Avalonia.Visuals/Matrix.cs b/src/Avalonia.Visuals/Matrix.cs index 5c7d42676a..5bbc657385 100644 --- a/src/Avalonia.Visuals/Matrix.cs +++ b/src/Avalonia.Visuals/Matrix.cs @@ -348,15 +348,9 @@ namespace Avalonia } else { - var x = p.X; - var y = p.Y; - var xAdd = y * M21 + M31; - var yAdd = x * M12 + M32; - x *= M11; - x += xAdd; - y *= M22; - y += yAdd; - transformedResult = new Point(x, y); + return new Point( + (p.X * M11) + (p.Y * M21) + M31, + (p.X * M12) + (p.Y * M22) + M32); } return transformedResult; diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs index 0fea9d73a0..4feca7acd8 100644 --- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs +++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs @@ -5,7 +5,7 @@ using Avalonia.Animation.Animators; namespace Avalonia.Media; /// -/// Non-Affine 3D transformation for rotating an visual around a definable axis +/// Non-Affine 3D transformation for rotating a visual around a definable axis /// public class Rotate3DTransform : Transform { diff --git a/src/Avalonia.Visuals/Point.cs b/src/Avalonia.Visuals/Point.cs index 8e01ea47c5..fbdf0db800 100644 --- a/src/Avalonia.Visuals/Point.cs +++ b/src/Avalonia.Visuals/Point.cs @@ -169,12 +169,7 @@ namespace Avalonia /// The point. /// The matrix. /// The resulting point. - public static Point operator *(Point point, Matrix matrix) - { - return new Point( - (point.X * matrix.M11) + (point.Y * matrix.M21) + matrix.M31, - (point.X * matrix.M12) + (point.Y * matrix.M22) + matrix.M32); - } + public static Point operator *(Point point, Matrix matrix) => matrix.Transform(point); /// /// Parses a string. From 43de185f2fb181faa01d244d5312283ffd385ed3 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 27 Jan 2022 16:52:35 +0100 Subject: [PATCH 018/332] Add unit tests. Add param to constructor. --- .../Media/Rotate3DTransform.cs | 5 +- .../Avalonia.Visuals.UnitTests/MatrixTests.cs | 95 +++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/Avalonia.Visuals.UnitTests/MatrixTests.cs diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs index 4feca7acd8..dbcf749789 100644 --- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs +++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs @@ -70,13 +70,15 @@ public class Rotate3DTransform : Transform /// The origin of the X-Axis /// The origin of the Y-Axis /// The origin of the Z-Axis + /// The depth of the 3D effect public Rotate3DTransform( double angleX, double angleY, double angleZ, double centerX, double centerY, - double centerZ) : this() + double centerZ, + double depth) : this() { _isInitializing = true; AngleX = angleX; @@ -85,6 +87,7 @@ public class Rotate3DTransform : Transform CenterX = centerX; CenterY = centerY; CenterZ = centerZ; + Depth = depth; _isInitializing = false; } diff --git a/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs b/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs new file mode 100644 index 0000000000..cb5e2390c7 --- /dev/null +++ b/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs @@ -0,0 +1,95 @@ +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using Avalonia.Media; +using Xunit; + +namespace Avalonia.Visuals.UnitTests; + +/// +/// These tests use the "official" Matrix4x4 and Matrix3x2 from the System.Numerics namespace, to validate +/// that Avalonias own implementation of a 3x3 Matrix works correctly. +/// +public class MatrixTests +{ + private double ReducePrecision(double input) + { + return Math.Truncate(input * 10000); + } + + /// + /// Because Avalonia is working internally with doubles, but System.Numerics Vector and Matrix implementations + /// only make use of floats, we need to reduce precision, comparing them. It should be sufficient to compare + /// 5 fractional digits to ensure, that the result is correct. + /// + /// The expected vector + /// The actual transformed point + private void AssertCoordinatesEqualWithReducedPrecision(Vector2 expected, Point actual) + { + var expectedX = ReducePrecision(expected.X); + var expectedY = ReducePrecision(expected.Y); + + var actualX = ReducePrecision(actual.X); + var actualY = ReducePrecision(actual.Y); + + Assert.Equal(expectedX, actualX); + Assert.Equal(expectedY, actualY); + } + + [Fact] + public void Transform_Point_Should_Return_Correct_Value_For_Translated_Matrix() + { + var vector2 = Vector2.Transform( + new Vector2(1, 1), + Matrix3x2.CreateTranslation(2, 2)); + var expected = new Point(vector2.X, vector2.Y); + + var matrix = Matrix.CreateTranslation(2, 2); + var point = new Point(1, 1); + var transformedPoint = matrix.Transform(point); + + Assert.Equal(expected, transformedPoint); + } + + [Fact] + public void Transform_Point_Should_Return_Correct_Value_For_Rotated_Matrix() + { + var expected = Vector2.Transform( + new Vector2(0, 10), + Matrix3x2.CreateRotation((float)Matrix.ToRadians(45))); + + var matrix = Matrix.CreateRotation(Matrix.ToRadians(45)); + var point = new Point(0, 10); + var actual = matrix.Transform(point); + + AssertCoordinatesEqualWithReducedPrecision(expected, actual); + } + + [Fact] + public void Transform_Point_Should_Return_Correct_Value_For_Scaled_Matrix() + { + var vector2 = Vector2.Transform( + new Vector2(1, 1), + Matrix3x2.CreateScale(2, 2)); + var expected = new Point(vector2.X, vector2.Y); + var matrix = Matrix.CreateScale(2, 2); + var point = new Point(1, 1); + var actual = matrix.Transform(point); + + Assert.Equal(expected, actual); + } + + [Fact] + public void Transform_Point_Should_Return_Correct_Value_For_Skewed_Matrix() + { + var expected = Vector2.Transform( + new Vector2(1, 1), + Matrix3x2.CreateSkew(30, 20)); + + var matrix = Matrix.CreateSkew(30, 20); + var point = new Point(1, 1); + var actual = matrix.Transform(point); + + AssertCoordinatesEqualWithReducedPrecision(expected, actual); + } +} From 30f99c847a767d2ff7776964ed209df6a55ddd0d Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 27 Jan 2022 16:54:26 +0100 Subject: [PATCH 019/332] Refactor test. --- tests/Avalonia.Visuals.UnitTests/MatrixTests.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs b/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs index cb5e2390c7..99fe4685d7 100644 --- a/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/MatrixTests.cs @@ -12,11 +12,6 @@ namespace Avalonia.Visuals.UnitTests; /// public class MatrixTests { - private double ReducePrecision(double input) - { - return Math.Truncate(input * 10000); - } - /// /// Because Avalonia is working internally with doubles, but System.Numerics Vector and Matrix implementations /// only make use of floats, we need to reduce precision, comparing them. It should be sufficient to compare @@ -26,6 +21,8 @@ public class MatrixTests /// The actual transformed point private void AssertCoordinatesEqualWithReducedPrecision(Vector2 expected, Point actual) { + double ReducePrecision(double input) => Math.Truncate(input * 10000); + var expectedX = ReducePrecision(expected.X); var expectedY = ReducePrecision(expected.Y); From 69d65f6c95715934ff295780c05fe846d22052b7 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 27 Jan 2022 20:40:47 +0100 Subject: [PATCH 020/332] Revert unwanted change. --- samples/ControlCatalog.Android/Resources/Resource.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog.Android/Resources/Resource.Designer.cs b/samples/ControlCatalog.Android/Resources/Resource.Designer.cs index b1ca548e2c..dccc3f7159 100644 --- a/samples/ControlCatalog.Android/Resources/Resource.Designer.cs +++ b/samples/ControlCatalog.Android/Resources/Resource.Designer.cs @@ -14,7 +14,7 @@ namespace ControlCatalog.Android { - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.99.62")] public partial class Resource { From b07a1b0222e194b559445a0a8fac0c7f903b8512 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Fri, 28 Jan 2022 13:53:03 +0100 Subject: [PATCH 021/332] Add double.Epsilon check instead of 0. --- src/Avalonia.Visuals/Media/Rotate3DTransform.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs index dbcf749789..e899f6b49b 100644 --- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs +++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs @@ -164,13 +164,13 @@ public class Rotate3DTransform : Transform var matrix44 = Matrix4x4.Identity; var centerSum = CenterX + CenterY + CenterZ; - if (centerSum != 0) matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ); + if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ); if (AngleX != 0) matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(AngleX)); if (AngleY != 0) matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(AngleY)); if (AngleZ != 0) matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(AngleZ)); - if (centerSum != 0) matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ); + if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ); if (Depth != 0) { From 75788233170777fe8305bb57df8a72e11b0fd564 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Fri, 28 Jan 2022 15:36:25 +0100 Subject: [PATCH 022/332] Add copy of values as basis for matrix transform. It is not guaranteed, that values will not change during calculation. --- .../Media/Rotate3DTransform.cs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs index e899f6b49b..a24d6b26c3 100644 --- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs +++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs @@ -162,20 +162,29 @@ public class Rotate3DTransform : Transform get { var matrix44 = Matrix4x4.Identity; - var centerSum = CenterX + CenterY + CenterZ; + //Copy values first, because it's not guaranteed, that values will not change during calculation + var (copyCenterX, + copyCenterY, + copyCenterZ, + copyAngleX, + copyAngleY, + copyAngleZ, + copyDepth) = (CenterX, CenterY, CenterZ, AngleX, AngleY, AngleZ, Depth); - if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation(-(float)CenterX, -(float)CenterY, -(float)CenterZ); + var centerSum = copyCenterX + copyCenterY + copyCenterZ; + + if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation(-(float)copyCenterX, -(float)copyCenterY, -(float)copyCenterZ); - if (AngleX != 0) matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(AngleX)); - if (AngleY != 0) matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(AngleY)); - if (AngleZ != 0) matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(AngleZ)); + if (AngleX != 0) matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(copyAngleX)); + if (AngleY != 0) matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(copyAngleY)); + if (AngleZ != 0) matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(copyAngleZ)); - if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation((float)CenterX, (float)CenterY, (float)CenterZ); + if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation((float)copyCenterX, (float)copyCenterY, (float)copyCenterZ); - if (Depth != 0) + if (copyDepth != 0) { var perspectiveMatrix = Matrix4x4.Identity; - perspectiveMatrix.M34 = -1 / (float)Depth; + perspectiveMatrix.M34 = -1 / (float)copyDepth; matrix44 *= perspectiveMatrix; } From e571559b64ca6c6c832aa6bf90e5db2743f3f74f Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Fri, 28 Jan 2022 16:47:22 +0100 Subject: [PATCH 023/332] Fix missing use of local copies. --- src/Avalonia.Visuals/Media/Rotate3DTransform.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs index a24d6b26c3..306363ec39 100644 --- a/src/Avalonia.Visuals/Media/Rotate3DTransform.cs +++ b/src/Avalonia.Visuals/Media/Rotate3DTransform.cs @@ -175,9 +175,9 @@ public class Rotate3DTransform : Transform if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation(-(float)copyCenterX, -(float)copyCenterY, -(float)copyCenterZ); - if (AngleX != 0) matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(copyAngleX)); - if (AngleY != 0) matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(copyAngleY)); - if (AngleZ != 0) matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(copyAngleZ)); + if (copyAngleX != 0) matrix44 *= Matrix4x4.CreateRotationX((float)Matrix.ToRadians(copyAngleX)); + if (copyAngleY != 0) matrix44 *= Matrix4x4.CreateRotationY((float)Matrix.ToRadians(copyAngleY)); + if (copyAngleZ != 0) matrix44 *= Matrix4x4.CreateRotationZ((float)Matrix.ToRadians(copyAngleZ)); if (Math.Abs(centerSum) > double.Epsilon) matrix44 *= Matrix4x4.CreateTranslation((float)copyCenterX, (float)copyCenterY, (float)copyCenterZ); From 9318ce1612579cb5d1f7b36c33012137f955e9ac Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 7 Feb 2022 16:28:40 +0100 Subject: [PATCH 024/332] Added failing tests for #7552. --- .../LayoutableTests.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs b/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs index a8aa0bbf0e..514eae12c0 100644 --- a/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs +++ b/tests/Avalonia.Layout.UnitTests/LayoutableTests.cs @@ -320,6 +320,71 @@ namespace Avalonia.Layout.UnitTests Times.Once); } + [Fact] + public void Making_Control_Invisible_Should_Invalidate_Parent_Measure() + { + Border child; + var target = new StackPanel + { + Children = + { + (child = new Border + { + Width = 100, + }), + } + }; + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(target.DesiredSize)); + + Assert.True(target.IsMeasureValid); + Assert.True(target.IsArrangeValid); + Assert.True(child.IsMeasureValid); + Assert.True(child.IsArrangeValid); + + child.IsVisible = false; + + Assert.False(target.IsMeasureValid); + Assert.False(target.IsArrangeValid); + Assert.True(child.IsMeasureValid); + Assert.True(child.IsArrangeValid); + } + + [Fact] + public void Measuring_Invisible_Control_Should_Not_Invalidate_Parent_Measure() + { + Border child; + var target = new StackPanel + { + Children = + { + (child = new Border + { + Width = 100, + }), + } + }; + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(target.DesiredSize)); + + Assert.True(target.IsMeasureValid); + Assert.True(target.IsArrangeValid); + Assert.Equal(new Size(100, 0), child.DesiredSize); + + child.IsVisible = false; + Assert.Equal(default, child.DesiredSize); + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(target.DesiredSize)); + child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + + Assert.True(target.IsMeasureValid); + Assert.True(target.IsArrangeValid); + Assert.Equal(default, child.DesiredSize); + } + private class TestLayoutable : Layoutable { public Size ArrangeSize { get; private set; } From 1f3cb4fa00dfc6e443d92a1658517653c039066b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 7 Feb 2022 16:29:39 +0100 Subject: [PATCH 025/332] Invalidate parent measure when child visibility changes. Fixes #7552 but breaks `ListBoxTests.LayoutManager_Should_Measure_Arrange_All`. --- src/Avalonia.Layout/Layoutable.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Layout/Layoutable.cs b/src/Avalonia.Layout/Layoutable.cs index 09e0c4263a..516a70c3c9 100644 --- a/src/Avalonia.Layout/Layoutable.cs +++ b/src/Avalonia.Layout/Layoutable.cs @@ -141,7 +141,6 @@ namespace Avalonia.Layout static Layoutable() { AffectsMeasure( - IsVisibleProperty, WidthProperty, HeightProperty, MinWidthProperty, @@ -781,6 +780,17 @@ namespace Avalonia.Layout { } + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == IsVisibleProperty) + { + DesiredSize = default; + this.GetVisualParent()?.ChildDesiredSizeChanged(this); + } + } + /// protected sealed override void OnVisualParentChanged(IVisual? oldParent, IVisual? newParent) { From 662dbf78649c60fbdee853bb4076f5ac3836bf7e Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Wed, 9 Feb 2022 19:18:25 +0100 Subject: [PATCH 026/332] Switch from list to array. Fix flickering. --- .../Transitions/Rotate3DTransition.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs index 56567f5fea..ebc8f44278 100644 --- a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs +++ b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Avalonia.Collections; using Avalonia.Media; using Avalonia.Styling; @@ -41,7 +39,7 @@ public class Rotate3DTransition: PageSlide return; } - var tasks = new List(); + var tasks = new Task[2]; var parent = GetVisualParent(from, to); var (rotateProperty, center) = Orientation switch { @@ -53,12 +51,13 @@ public class Rotate3DTransition: PageSlide var depthSetter = new Setter {Property = Rotate3DTransform.DepthProperty, Value = Depth ?? center}; var centerZSetter = new Setter {Property = Rotate3DTransform.CenterZProperty, Value = -center / 2}; - KeyFrame CreateKeyFrame(double cue, double rotation, int zIndex) => + KeyFrame CreateKeyFrame(double cue, double rotation, int zIndex, bool isVisible = true) => new() { Setters = { new Setter { Property = rotateProperty, Value = rotation }, new Setter { Property = Visual.ZIndexProperty, Value = zIndex }, + new Setter { Property = Visual.IsVisibleProperty, Value = isVisible }, centerZSetter, depthSetter }, @@ -71,15 +70,16 @@ public class Rotate3DTransition: PageSlide { Easing = SlideOutEasing, Duration = Duration, + FillMode = FillMode.Forward, Children = { CreateKeyFrame(0d, 0d, 2), CreateKeyFrame(0.5d, 45d * (forward ? -1 : 1), 1), - CreateKeyFrame(1d, 90d * (forward ? -1 : 1), 1) + CreateKeyFrame(1d, 90d * (forward ? -1 : 1), 1, isVisible: false) } }; - tasks.Add(animation.RunAsync(from, null, cancellationToken)); + tasks[0] = animation.RunAsync(from, null, cancellationToken); } if (to != null) @@ -89,6 +89,7 @@ public class Rotate3DTransition: PageSlide { Easing = SlideInEasing, Duration = Duration, + FillMode = FillMode.Forward, Children = { CreateKeyFrame(0d, 90d * (forward ? 1 : -1), 1), @@ -97,23 +98,23 @@ public class Rotate3DTransition: PageSlide } }; - tasks.Add(animation.RunAsync(to, null, cancellationToken)); + tasks[1] = animation.RunAsync(to, null, cancellationToken); } await Task.WhenAll(tasks); if (!cancellationToken.IsCancellationRequested) { + if (to != null) + { + to.ZIndex = 2; + } + if (from != null) { from.IsVisible = false; from.ZIndex = 1; } - - if (to != null) - { - to.ZIndex = 2; - } } } } From 9c5b3ab4d8c7b454e5a33ae65a2d8d501fbf4ca7 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 10 Feb 2022 13:22:33 +0100 Subject: [PATCH 027/332] Fix null reference exception for Tasks.WhenAll. --- .../Animation/Transitions/Rotate3DTransition.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs index ebc8f44278..01d04dff6b 100644 --- a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs +++ b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs @@ -39,7 +39,7 @@ public class Rotate3DTransition: PageSlide return; } - var tasks = new Task[2]; + var tasks = new Task[from != null && to != null ? 2 : 1]; var parent = GetVisualParent(from, to); var (rotateProperty, center) = Orientation switch { From 20c28efd90a7f4a6a636a7bb70745fcbbab8d473 Mon Sep 17 00:00:00 2001 From: Jan-Peter Zurek Date: Thu, 10 Feb 2022 13:24:33 +0100 Subject: [PATCH 028/332] Improve previous fix. --- .../Animation/Transitions/Rotate3DTransition.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs index 01d04dff6b..60c7a97ced 100644 --- a/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs +++ b/src/Avalonia.Visuals/Animation/Transitions/Rotate3DTransition.cs @@ -98,7 +98,7 @@ public class Rotate3DTransition: PageSlide } }; - tasks[1] = animation.RunAsync(to, null, cancellationToken); + tasks[from != null ? 1 : 0] = animation.RunAsync(to, null, cancellationToken); } await Task.WhenAll(tasks); From 38e2ab818a5b68becab6be93b9259e07bc9ddaa7 Mon Sep 17 00:00:00 2001 From: Luthfi Tri Atmaja Date: Wed, 16 Feb 2022 13:09:49 +0700 Subject: [PATCH 029/332] introduce gtk_file_chooser_set_current_folder --- src/Avalonia.X11/NativeDialogs/Gtk.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.X11/NativeDialogs/Gtk.cs b/src/Avalonia.X11/NativeDialogs/Gtk.cs index a0f146afa8..73e6a2d6a4 100644 --- a/src/Avalonia.X11/NativeDialogs/Gtk.cs +++ b/src/Avalonia.X11/NativeDialogs/Gtk.cs @@ -195,7 +195,10 @@ namespace Avalonia.X11.NativeDialogs [DllImport(GtkName)] public static extern void gtk_file_chooser_set_current_name(IntPtr chooser, Utf8Buffer file); - + + [DllImport(GtkName)] + public static extern void gtk_file_chooser_set_current_folder(IntPtr chooser, Utf8Buffer file); + [DllImport(GtkName)] public static extern IntPtr gtk_file_filter_new(); From 1888ab9fe5388d8058dbac6e91aaf242e2509621 Mon Sep 17 00:00:00 2001 From: Luthfi Tri Atmaja Date: Wed, 16 Feb 2022 13:28:06 +0700 Subject: [PATCH 030/332] navigate to initial directory --- .../NativeDialogs/GtkNativeFileDialogs.cs | 66 +++++++++++++------ 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs index 1a6514eb03..9539f024b7 100644 --- a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs +++ b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs @@ -15,8 +15,9 @@ namespace Avalonia.X11.NativeDialogs class GtkSystemDialog : ISystemDialogImpl { private Task _initialized; - private unsafe Task ShowDialog(string title, IWindowImpl parent, GtkFileChooserAction action, - bool multiSelect, string initialFileName, IEnumerable filters, string defaultExtension, bool overwritePrompt) + + private unsafe Task ShowDialog(string title, IWindowImpl parent, GtkFileChooserAction action, + bool multiSelect, string initialDirectory, string initialFileName, IEnumerable filters, string defaultExtension, bool overwritePrompt) { IntPtr dlg; using (var name = new Utf8Buffer(title)) @@ -44,7 +45,7 @@ namespace Avalonia.X11.NativeDialogs filtersDic[filter] = f; using (var b = new Utf8Buffer(f.Name)) gtk_file_filter_set_name(filter, b); - + foreach (var e in f.Extensions) using (var b = new Utf8Buffer("*." + e)) gtk_file_filter_add_pattern(filter, b); @@ -100,17 +101,32 @@ namespace Avalonia.X11.NativeDialogs gtk_dialog_add_button(dlg, open, GtkResponseType.Accept); using (var open = new Utf8Buffer("Cancel")) gtk_dialog_add_button(dlg, open, GtkResponseType.Cancel); + + if (initialDirectory != null) + { + using var dir = new Utf8Buffer(initialDirectory); + gtk_file_chooser_set_current_folder(dlg, dir); + } + if (initialFileName != null) - using (var fn = new Utf8Buffer(initialFileName)) + { + // gtk_file_chooser_set_filename() expects full path + using var fn = action == GtkFileChooserAction.Open + ? new Utf8Buffer(Path.Combine(initialDirectory ?? "", initialFileName)) + : new Utf8Buffer(initialFileName); + + if (action == GtkFileChooserAction.Save) { - if (action == GtkFileChooserAction.Save) - gtk_file_chooser_set_current_name(dlg, fn); - else - gtk_file_chooser_set_filename(dlg, fn); + gtk_file_chooser_set_current_name(dlg, fn); } + else + { + gtk_file_chooser_set_filename(dlg, fn); + } + } gtk_file_chooser_set_do_overwrite_confirmation(dlg, overwritePrompt); - + gtk_window_present(dlg); return tcs.Task; } @@ -144,13 +160,15 @@ namespace Avalonia.X11.NativeDialogs var platformImpl = parent?.PlatformImpl; - return await await RunOnGlibThread( - () => ShowDialog(dialog.Title, platformImpl, - dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save, - (dialog as OpenFileDialog)?.AllowMultiple ?? false, - Path.Combine(string.IsNullOrEmpty(dialog.Directory) ? "" : dialog.Directory, - string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName), dialog.Filters, - (dialog as SaveFileDialog)?.DefaultExtension, (dialog as SaveFileDialog)?.ShowOverwritePrompt ?? false)); + return await await RunOnGlibThread(() => ShowDialog( + dialog.Title, platformImpl, + dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save, + (dialog as OpenFileDialog)?.AllowMultiple ?? false, + dialog.Directory, + dialog.InitialFileName, + dialog.Filters, + (dialog as SaveFileDialog)?.DefaultExtension, + (dialog as SaveFileDialog)?.ShowOverwritePrompt ?? false)); } public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) @@ -161,12 +179,20 @@ namespace Avalonia.X11.NativeDialogs return await await RunOnGlibThread(async () => { - var res = await ShowDialog(dialog.Title, platformImpl, - GtkFileChooserAction.SelectFolder, false, dialog.Directory, null, null, false); + var res = await ShowDialog( + dialog.Title, + platformImpl,GtkFileChooserAction.SelectFolder, + false, + dialog.Directory, + null, + null, + null, + false); + return res?.FirstOrDefault(); }); } - + async Task EnsureInitialized() { if (_initialized == null) _initialized = StartGtk(); @@ -174,7 +200,7 @@ namespace Avalonia.X11.NativeDialogs if (!(await _initialized)) throw new Exception("Unable to initialize GTK on separate thread"); } - + void UpdateParent(IntPtr chooser, IWindowImpl parentWindow) { var xid = parentWindow.Handle.Handle; From eefe009a810473abb0b0d4699ff8d01b9fc041a6 Mon Sep 17 00:00:00 2001 From: Luthfi Tri Atmaja Date: Wed, 16 Feb 2022 13:38:48 +0700 Subject: [PATCH 031/332] update dialogs sample page --- .../ControlCatalog/Pages/DialogsPage.xaml.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index e96b7aff08..a7af9c5cb7 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -42,13 +42,17 @@ namespace ControlCatalog.Pages this.FindControl /// - /// The date to display. The default - /// . + /// The date to display. The default is . /// - /// + /// /// The specified date is not in the range defined by - /// + /// /// and - /// . + /// . /// public DateTime DisplayDate { @@ -215,11 +214,11 @@ namespace Avalonia.Controls /// /// /// The specified date is not in the range defined by - /// + /// /// and - /// , + /// , /// or the specified date is in the - /// + /// /// collection. /// public DateTime? SelectedDate @@ -233,9 +232,9 @@ namespace Avalonia.Controls /// /// /// The format that is used to display the selected date. The default is - /// . + /// . /// - /// + /// /// An specified format is not valid. /// public CalendarDatePickerFormat SelectedDateFormat @@ -251,18 +250,16 @@ namespace Avalonia.Controls } /// - /// Gets or sets the text that is displayed by the - /// . + /// Gets or sets the text that is displayed by the . /// /// - /// The text displayed by the - /// . + /// The text displayed by the . /// - /// + /// /// The text entered cannot be parsed to a valid date, and the exception /// is not suppressed. /// - /// + /// /// The text entered parses to a date that is not selectable. /// public string? Text From b0246965b8a72cc33403093919acfb449bc21c38 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:00:08 -0400 Subject: [PATCH 044/332] Modernize TextBox property accessor code --- src/Avalonia.Controls/TextBox.cs | 94 ++++++++++++++------------------ 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index ce7d2f7e5f..82346599a4 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -239,23 +239,19 @@ namespace Avalonia.Controls public bool AcceptsReturn { - get { return GetValue(AcceptsReturnProperty); } - set { SetValue(AcceptsReturnProperty, value); } + get => GetValue(AcceptsReturnProperty); + set => SetValue(AcceptsReturnProperty, value); } public bool AcceptsTab { - get { return GetValue(AcceptsTabProperty); } - set { SetValue(AcceptsTabProperty, value); } + get => GetValue(AcceptsTabProperty); + set => SetValue(AcceptsTabProperty, value); } public int CaretIndex { - get - { - return _caretIndex; - } - + get => _caretIndex; set { value = CoerceCaretIndex(value); @@ -271,8 +267,8 @@ namespace Avalonia.Controls public bool IsReadOnly { - get { return GetValue(IsReadOnlyProperty); } - set { SetValue(IsReadOnlyProperty, value); } + get => GetValue(IsReadOnlyProperty); + set => SetValue(IsReadOnlyProperty, value); } public char PasswordChar @@ -301,11 +297,7 @@ namespace Avalonia.Controls public int SelectionStart { - get - { - return _selectionStart; - } - + get => _selectionStart; set { value = CoerceCaretIndex(value); @@ -325,11 +317,7 @@ namespace Avalonia.Controls public int SelectionEnd { - get - { - return _selectionEnd; - } - + get => _selectionEnd; set { value = CoerceCaretIndex(value); @@ -349,20 +337,20 @@ namespace Avalonia.Controls public int MaxLength { - get { return GetValue(MaxLengthProperty); } - set { SetValue(MaxLengthProperty, value); } + get => GetValue(MaxLengthProperty); + set => SetValue(MaxLengthProperty, value); } public int MaxLines { - get { return GetValue(MaxLinesProperty); } - set { SetValue(MaxLinesProperty, value); } + get => GetValue(MaxLinesProperty); + set => SetValue(MaxLinesProperty, value); } [Content] public string? Text { - get { return _text; } + get => _text; set { if (!_ignoreTextChanges) @@ -386,7 +374,7 @@ namespace Avalonia.Controls public string SelectedText { - get { return GetSelection(); } + get => GetSelection(); set { if (string.IsNullOrEmpty(value)) @@ -407,8 +395,8 @@ namespace Avalonia.Controls /// public HorizontalAlignment HorizontalContentAlignment { - get { return GetValue(HorizontalContentAlignmentProperty); } - set { SetValue(HorizontalContentAlignmentProperty, value); } + get => GetValue(HorizontalContentAlignmentProperty); + set => SetValue(HorizontalContentAlignmentProperty, value); } /// @@ -416,14 +404,14 @@ namespace Avalonia.Controls /// public VerticalAlignment VerticalContentAlignment { - get { return GetValue(VerticalContentAlignmentProperty); } - set { SetValue(VerticalContentAlignmentProperty, value); } + get => GetValue(VerticalContentAlignmentProperty); + set => SetValue(VerticalContentAlignmentProperty, value); } public TextAlignment TextAlignment { - get { return GetValue(TextAlignmentProperty); } - set { SetValue(TextAlignmentProperty, value); } + get => GetValue(TextAlignmentProperty); + set => SetValue(TextAlignmentProperty, value); } /// @@ -448,26 +436,26 @@ namespace Avalonia.Controls public object InnerLeftContent { - get { return GetValue(InnerLeftContentProperty); } - set { SetValue(InnerLeftContentProperty, value); } + get => GetValue(InnerLeftContentProperty); + set => SetValue(InnerLeftContentProperty, value); } public object InnerRightContent { - get { return GetValue(InnerRightContentProperty); } - set { SetValue(InnerRightContentProperty, value); } + get => GetValue(InnerRightContentProperty); + set => SetValue(InnerRightContentProperty, value); } public bool RevealPassword { - get { return GetValue(RevealPasswordProperty); } - set { SetValue(RevealPasswordProperty, value); } + get => GetValue(RevealPasswordProperty); + set => SetValue(RevealPasswordProperty, value); } public TextWrapping TextWrapping { - get { return GetValue(TextWrappingProperty); } - set { SetValue(TextWrappingProperty, value); } + get => GetValue(TextWrappingProperty); + set => SetValue(TextWrappingProperty, value); } /// @@ -475,8 +463,8 @@ namespace Avalonia.Controls /// public string NewLine { - get { return _newLine; } - set { SetAndRaise(NewLineProperty, ref _newLine, value); } + get => _newLine; + set => SetAndRaise(NewLineProperty, ref _newLine, value); } /// @@ -492,8 +480,8 @@ namespace Avalonia.Controls /// public bool CanCut { - get { return _canCut; } - private set { SetAndRaise(CanCutProperty, ref _canCut, value); } + get => _canCut; + private set => SetAndRaise(CanCutProperty, ref _canCut, value); } /// @@ -501,8 +489,8 @@ namespace Avalonia.Controls /// public bool CanCopy { - get { return _canCopy; } - private set { SetAndRaise(CanCopyProperty, ref _canCopy, value); } + get => _canCopy; + private set => SetAndRaise(CanCopyProperty, ref _canCopy, value); } /// @@ -510,8 +498,8 @@ namespace Avalonia.Controls /// public bool CanPaste { - get { return _canPaste; } - private set { SetAndRaise(CanPasteProperty, ref _canPaste, value); } + get => _canPaste; + private set => SetAndRaise(CanPasteProperty, ref _canPaste, value); } /// @@ -519,13 +507,13 @@ namespace Avalonia.Controls /// public bool IsUndoEnabled { - get { return GetValue(IsUndoEnabledProperty); } - set { SetValue(IsUndoEnabledProperty, value); } + get => GetValue(IsUndoEnabledProperty); + set => SetValue(IsUndoEnabledProperty, value); } public int UndoLimit { - get { return _undoRedoHelper.Limit; } + get => _undoRedoHelper.Limit; set { if (_undoRedoHelper.Limit != value) @@ -1544,7 +1532,7 @@ namespace Avalonia.Controls UndoRedoState UndoRedoHelper.IUndoRedoHost.UndoRedoState { - get { return new UndoRedoState(Text, CaretIndex); } + get => new UndoRedoState(Text, CaretIndex); set { Text = value.Text; From b043db169cc02d1018ed02c95ea41231acf4a010 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:15:34 -0400 Subject: [PATCH 045/332] Make sure to call base methods in Button --- src/Avalonia.Controls/Button.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index a4d15bab8d..9a7853cd4b 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -309,6 +309,8 @@ namespace Avalonia.Controls IsPressed = false; e.Handled = true; } + + base.OnKeyUp(e); } /// @@ -393,6 +395,8 @@ namespace Avalonia.Controls /// protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e) { + base.OnPointerCaptureLost(e); + IsPressed = false; } @@ -407,6 +411,8 @@ namespace Avalonia.Controls /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { + base.OnApplyTemplate(e); + UnregisterFlyoutEvents(Flyout); RegisterFlyoutEvents(Flyout); UpdatePseudoClasses(); From 0329a8daa1ceef647d89f3ccece0ca1e94e544ec Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:18:34 -0400 Subject: [PATCH 046/332] Support opening the calendar flyout when pressing outside the button --- .../Calendar/CalendarDatePicker.cs | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index fbd3f36aea..1f9b457c42 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -331,6 +331,7 @@ namespace Avalonia.Controls base.OnPropertyChanged(change); } + /// protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value) { if (property == SelectedDateProperty) @@ -339,6 +340,55 @@ namespace Avalonia.Controls } } + /// + protected override void OnPointerPressed(PointerPressedEventArgs e) + { + base.OnPointerPressed(e); + + if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + { + e.Handled = true; + + _ignoreButtonClick = _isPopupClosing; + + _isPressed = true; + UpdatePseudoClasses(); + } + } + + /// + protected override void OnPointerReleased(PointerReleasedEventArgs e) + { + base.OnPointerReleased(e); + + if (_isPressed && e.InitialPressMouseButton == MouseButton.Left) + { + e.Handled = true; + + if (!_ignoreButtonClick) + { + HandlePopUp(); + } + else + { + _ignoreButtonClick = false; + } + + _isPressed = false; + UpdatePseudoClasses(); + } + } + + /// + protected override void OnPointerCaptureLost(PointerCaptureLostEventArgs e) + { + base.OnPointerCaptureLost(e); + + _isPressed = false; + UpdatePseudoClasses(); + } + + /// protected override void OnPointerWheelChanged(PointerWheelEventArgs e) { base.OnPointerWheelChanged(e); @@ -354,6 +404,7 @@ namespace Avalonia.Controls } } + /// protected override void OnGotFocus(GotFocusEventArgs e) { base.OnGotFocus(e); @@ -369,10 +420,14 @@ namespace Avalonia.Controls } } + /// protected override void OnLostFocus(RoutedEventArgs e) { base.OnLostFocus(e); + _isPressed = false; + UpdatePseudoClasses(); + SetSelectedDate(); } @@ -671,7 +726,6 @@ namespace Avalonia.Controls private bool ProcessDatePickerKey(KeyEventArgs e) { - switch (e.Key) { case Key.Enter: From 24a3dc560aaed3f7208bce05b190f4b79a3695fd Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 16:23:39 -0400 Subject: [PATCH 047/332] Better support MinHeight --- src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index c5a219540b..00f53a563d 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -19,6 +19,7 @@ 12 + 32 - + + + + + + From dbe46697c9e75b3d77afed712321695e679588d0 Mon Sep 17 00:00:00 2001 From: robloo Date: Sun, 10 Apr 2022 20:21:53 -0400 Subject: [PATCH 049/332] Improve CalendarDatePicker Fluent style --- .../Controls/CalendarDatePicker.xaml | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index e030e14243..592581e975 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -23,7 +23,6 @@ - - - + - + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var foo = window.FindControl("foo"); + + Assert.Null(foo.Background); + + foo.Classes.Add("foo"); + + Assert.Equal(Colors.Red, ((ISolidColorBrush)foo.Background).Color); + } + } } } From 43a3841dcbdc224c528f95c9f25eb585b141c8fc Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 15 Apr 2022 18:02:43 +0200 Subject: [PATCH 054/332] Add/remove resource owner. --- src/Avalonia.Base/Styling/StyleChildren.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Styling/StyleChildren.cs b/src/Avalonia.Base/Styling/StyleChildren.cs index 21ac3c4072..64d838e4ce 100644 --- a/src/Avalonia.Base/Styling/StyleChildren.cs +++ b/src/Avalonia.Base/Styling/StyleChildren.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using Avalonia.Controls; namespace Avalonia.Styling { @@ -16,7 +17,10 @@ namespace Avalonia.Styling protected override void RemoveItem(int index) { - (Items[index] as Style)?.SetParent(null); + var item = Items[index]; + if (_owner.Owner is IResourceHost host) + (item as IResourceProvider)?.RemoveOwner(host); + (item as Style)?.SetParent(null); base.RemoveItem(index); } @@ -24,6 +28,8 @@ namespace Avalonia.Styling { base.SetItem(index, item); (item as Style)?.SetParent(_owner); + if (_owner.Owner is IResourceHost host) + (item as IResourceProvider)?.AddOwner(host); } } } From 248b3c87c34fb5679a8cb120211ed94066081bfa Mon Sep 17 00:00:00 2001 From: robloo Date: Fri, 15 Apr 2022 21:15:08 -0400 Subject: [PATCH 055/332] Use more standard x:Double resource --- src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index 592581e975..6f7b14ce25 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -18,7 +18,7 @@ - 12 + 12 32 From 53fc90a108ef8216e3b54d50f289e9dc3fe3f9c9 Mon Sep 17 00:00:00 2001 From: robloo Date: Fri, 15 Apr 2022 21:16:26 -0400 Subject: [PATCH 056/332] Remove Microsoft copyright An audit of git blame shows the style has now been fully rewritten for Avalonia --- .../Controls/CalendarDatePicker.xaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml index 6f7b14ce25..c6f70d05e1 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml @@ -1,10 +1,3 @@ - - Date: Thu, 21 Apr 2022 09:53:28 +0200 Subject: [PATCH 057/332] Use nested styles in Button template. And related fixes to make this work. --- src/Avalonia.Base/Styling/NestingSelector.cs | 2 +- src/Avalonia.Base/Styling/Style.cs | 8 +- .../Controls/Button.xaml | 80 ++++++++++--------- .../Styling/SelectorTests_Nesting.cs | 68 +++++++++++++++- 4 files changed, 116 insertions(+), 42 deletions(-) diff --git a/src/Avalonia.Base/Styling/NestingSelector.cs b/src/Avalonia.Base/Styling/NestingSelector.cs index 1be54dea3c..741eb7e9ca 100644 --- a/src/Avalonia.Base/Styling/NestingSelector.cs +++ b/src/Avalonia.Base/Styling/NestingSelector.cs @@ -17,7 +17,7 @@ namespace Avalonia.Styling { if (parent is Style s && s.Selector is Selector selector) { - return selector.Match(control, null, subscribe); + return selector.Match(control, (parent as Style)?.Parent, subscribe); } throw new InvalidOperationException( diff --git a/src/Avalonia.Base/Styling/Style.cs b/src/Avalonia.Base/Styling/Style.cs index 6020dfe25f..7a83322355 100644 --- a/src/Avalonia.Base/Styling/Style.cs +++ b/src/Avalonia.Base/Styling/Style.cs @@ -120,15 +120,19 @@ namespace Avalonia.Styling instance.Start(); } + var result = match.Result; + if (_children is not null) { foreach (var child in _children) { - child.TryAttach(target, host); + var childResult = child.TryAttach(target, host); + if (childResult > result) + result = childResult; } } - return match.Result; + return result; } public bool TryGetResource(object key, out object? result) diff --git a/src/Avalonia.Themes.Fluent/Controls/Button.xaml b/src/Avalonia.Themes.Fluent/Controls/Button.xaml index f545206a2f..282f575605 100644 --- a/src/Avalonia.Themes.Fluent/Controls/Button.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/Button.xaml @@ -7,9 +7,11 @@ + 8,5,8,6 + - - + + - + - + - + - + - + + + + + - diff --git a/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs b/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs index eeb2fad996..f7e8793ede 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs @@ -9,7 +9,7 @@ namespace Avalonia.Base.UnitTests.Styling public class SelectorTests_Nesting { [Fact] - public void Nesting_Class_Doesnt_Match_Parent_Selector() + public void Nesting_Class_Doesnt_Match_Parent_OfType_Selector() { var control = new Control2(); Style nested; @@ -26,7 +26,7 @@ namespace Avalonia.Base.UnitTests.Styling } [Fact] - public void Or_Nesting_Class_Doesnt_Match_Parent_Selector() + public void Or_Nesting_Class_Doesnt_Match_Parent_OfType_Selector() { var control = new Control2(); Style nested; @@ -45,7 +45,7 @@ namespace Avalonia.Base.UnitTests.Styling } [Fact] - public void Or_Nesting_Child_OfType_Does_Not_Match_Parent_Selector() + public void Or_Nesting_Child_OfType_Doesnt_Match_Parent_OfType_Selector() { var control = new Control1(); var panel = new DockPanel { Children = { control } }; @@ -64,6 +64,34 @@ namespace Avalonia.Base.UnitTests.Styling Assert.Equal(SelectorMatchResult.NeverThisInstance, match.Result); } + [Fact] + public void Double_Nesting_Class_Doesnt_Match_Grandparent_OfType_Selector() + { + var control = new Control2 + { + Classes = { "foo", "bar" }, + }; + + Style parent; + Style nested; + var grandparent = new Style(x => x.OfType()) + { + Children = + { + (parent = new Style(x => x.Nesting().Class("foo")) + { + Children = + { + (nested = new Style(x => x.Nesting().Class("bar"))) + } + }) + } + }; + + var match = nested.Selector.Match(control, parent); + Assert.Equal(SelectorMatchResult.NeverThisType, match.Result); + } + [Fact] public void Nesting_Class_Matches() { @@ -87,6 +115,40 @@ namespace Avalonia.Base.UnitTests.Styling Assert.False(sink.Active); } + [Fact] + public void Double_Nesting_Class_Matches() + { + var control = new Control1 + { + Classes = { "foo", "bar" }, + }; + + Style parent; + Style nested; + var grandparent = new Style(x => x.OfType()) + { + Children = + { + (parent = new Style(x => x.Nesting().Class("foo")) + { + Children = + { + (nested = new Style(x => x.Nesting().Class("bar"))) + } + }) + } + }; + + var match = nested.Selector.Match(control, parent); + Assert.Equal(SelectorMatchResult.Sometimes, match.Result); + + var sink = new ActivatorSink(match.Activator); + + Assert.True(sink.Active); + control.Classes.Remove("foo"); + Assert.False(sink.Active); + } + [Fact] public void Or_Nesting_Class_Matches() { From 7e2c1ad165b28a3918ec22278e2716254bcc1e45 Mon Sep 17 00:00:00 2001 From: amwx <40413319+amwx@users.noreply.github.com> Date: Fri, 22 Apr 2022 21:33:55 -0400 Subject: [PATCH 058/332] Implement TransformOrigin for brushes --- .../Animation/Animators/GradientBrushAnimator.cs | 6 ++++++ src/Avalonia.Base/Media/Brush.cs | 15 +++++++++++++++ src/Avalonia.Base/Media/IBrush.cs | 5 +++++ .../Immutable/ImmutableConicGradientBrush.cs | 4 +++- .../Media/Immutable/ImmutableGradientBrush.cs | 11 ++++++++++- .../Media/Immutable/ImmutableImageBrush.cs | 3 +++ .../Immutable/ImmutableLinearGradientBrush.cs | 4 +++- .../Immutable/ImmutableRadialGradientBrush.cs | 4 +++- .../Media/Immutable/ImmutableSolidColorBrush.cs | 5 +++++ .../Media/Immutable/ImmutableTileBrush.cs | 9 +++++++++ .../Media/Immutable/ImmutableVisualBrush.cs | 3 +++ 11 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs index 5e97635c9a..4727ea1bfb 100644 --- a/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs +++ b/src/Avalonia.Base/Animation/Animators/GradientBrushAnimator.cs @@ -31,6 +31,7 @@ namespace Avalonia.Animation.Animators InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, + s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldRadial.Center, newRadial.Center), s_relativePointAnimator.Interpolate(progress, oldRadial.GradientOrigin, newRadial.GradientOrigin), @@ -41,6 +42,7 @@ namespace Avalonia.Animation.Animators InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, + s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldConic.Center, newConic.Center), s_doubleAnimator.Interpolate(progress, oldConic.Angle, newConic.Angle)); @@ -50,6 +52,7 @@ namespace Avalonia.Animation.Animators InterpolateStops(progress, oldValue.GradientStops, newValue.GradientStops), s_doubleAnimator.Interpolate(progress, oldValue.Opacity, newValue.Opacity), oldValue.Transform is { } ? new ImmutableTransform(oldValue.Transform.Value) : null, + s_relativePointAnimator.Interpolate(progress, oldValue.TransformOrigin, newValue.TransformOrigin), oldValue.SpreadMethod, s_relativePointAnimator.Interpolate(progress, oldLinear.StartPoint, newLinear.StartPoint), s_relativePointAnimator.Interpolate(progress, oldLinear.EndPoint, newLinear.EndPoint)); @@ -102,18 +105,21 @@ namespace Avalonia.Animation.Animators return new ImmutableRadialGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldRadial.GradientStops), solidColorBrush.Opacity, oldRadial.Transform is { } ? new ImmutableTransform(oldRadial.Transform.Value) : null, + oldRadial.TransformOrigin, oldRadial.SpreadMethod, oldRadial.Center, oldRadial.GradientOrigin, oldRadial.Radius); case IConicGradientBrush oldConic: return new ImmutableConicGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldConic.GradientStops), solidColorBrush.Opacity, oldConic.Transform is { } ? new ImmutableTransform(oldConic.Transform.Value) : null, + oldConic.TransformOrigin, oldConic.SpreadMethod, oldConic.Center, oldConic.Angle); case ILinearGradientBrush oldLinear: return new ImmutableLinearGradientBrush( CreateStopsFromSolidColorBrush(solidColorBrush, oldLinear.GradientStops), solidColorBrush.Opacity, oldLinear.Transform is { } ? new ImmutableTransform(oldLinear.Transform.Value) : null, + oldLinear.TransformOrigin, oldLinear.SpreadMethod, oldLinear.StartPoint, oldLinear.EndPoint); default: diff --git a/src/Avalonia.Base/Media/Brush.cs b/src/Avalonia.Base/Media/Brush.cs index 9d989979a7..8d531e9394 100644 --- a/src/Avalonia.Base/Media/Brush.cs +++ b/src/Avalonia.Base/Media/Brush.cs @@ -24,6 +24,12 @@ namespace Avalonia.Media public static readonly StyledProperty TransformProperty = AvaloniaProperty.Register(nameof(Transform)); + /// + /// Defines the property + /// + public static readonly StyledProperty TransformOriginProperty = + AvaloniaProperty.Register(nameof(TransformOrigin)); + /// public event EventHandler? Invalidated; @@ -51,6 +57,15 @@ namespace Avalonia.Media set { SetValue(TransformProperty, value); } } + /// + /// Gets or sets the origin of the brush + /// + public RelativePoint TransformOrigin + { + get => GetValue(TransformOriginProperty); + set => SetValue(TransformOriginProperty, value); + } + /// /// Parses a brush string. /// diff --git a/src/Avalonia.Base/Media/IBrush.cs b/src/Avalonia.Base/Media/IBrush.cs index 830c066182..14ccf12b8f 100644 --- a/src/Avalonia.Base/Media/IBrush.cs +++ b/src/Avalonia.Base/Media/IBrush.cs @@ -17,5 +17,10 @@ namespace Avalonia.Media /// Gets the transform of the brush. /// ITransform? Transform { get; } + + /// + /// Gets the origin of the brushes + /// + RelativePoint TransformOrigin { get; } } } diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs index 4b97615c4c..70232f0a63 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableConicGradientBrush.cs @@ -13,6 +13,7 @@ namespace Avalonia.Media.Immutable /// The gradient stops. /// The opacity of the brush. /// The transform of the brush. + /// The transform origin of the brush /// The spread method. /// The center point for the gradient. /// The starting angle for the gradient. @@ -20,10 +21,11 @@ namespace Avalonia.Media.Immutable IReadOnlyList gradientStops, double opacity = 1, ImmutableTransform? transform = null, + RelativePoint? transformOrigin = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, double angle = 0) - : base(gradientStops, opacity, transform, spreadMethod) + : base(gradientStops, opacity, transform, transformOrigin, spreadMethod) { Center = center ?? RelativePoint.Center; Angle = angle; diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs index f1e51687d0..1e95acbf22 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableGradientBrush.cs @@ -13,16 +13,19 @@ namespace Avalonia.Media.Immutable /// The gradient stops. /// The opacity of the brush. /// The transform of the brush. + /// The transform origin of the brush /// The spread method. protected ImmutableGradientBrush( IReadOnlyList gradientStops, double opacity, ImmutableTransform? transform, + RelativePoint? transformOrigin, GradientSpreadMethod spreadMethod) { GradientStops = gradientStops; Opacity = opacity; Transform = transform; + TransformOrigin = transformOrigin.HasValue ? transformOrigin.Value : RelativePoint.TopLeft; SpreadMethod = spreadMethod; } @@ -31,7 +34,8 @@ namespace Avalonia.Media.Immutable /// /// The brush from which this brush's properties should be copied. protected ImmutableGradientBrush(GradientBrush source) - : this(source.GradientStops.ToImmutable(), source.Opacity, source.Transform?.ToImmutable(), source.SpreadMethod) + : this(source.GradientStops.ToImmutable(), source.Opacity, source.Transform?.ToImmutable(), + source.TransformOrigin, source.SpreadMethod) { } @@ -47,6 +51,11 @@ namespace Avalonia.Media.Immutable /// public ITransform? Transform { get; } + /// + /// Gets the transform origin of the brush + /// + public RelativePoint TransformOrigin { get; } + /// public GradientSpreadMethod SpreadMethod { get; } } diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs index c36e82eacb..f9892bf60c 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableImageBrush.cs @@ -16,6 +16,7 @@ namespace Avalonia.Media.Immutable /// The rectangle on the destination in which to paint a tile. /// The opacity of the brush. /// The transform of the brush. + /// The transform origin of the brush /// The rectangle of the source image that will be displayed. /// /// How the source rectangle will be stretched to fill the destination rect. @@ -29,6 +30,7 @@ namespace Avalonia.Media.Immutable RelativeRect? destinationRect = null, double opacity = 1, ImmutableTransform? transform = null, + RelativePoint transformOrigin = new RelativePoint(), RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, @@ -39,6 +41,7 @@ namespace Avalonia.Media.Immutable destinationRect ?? RelativeRect.Fill, opacity, transform, + transformOrigin, sourceRect ?? RelativeRect.Fill, stretch, tileMode, diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs index 64c0f9b44e..3c26b5c009 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableLinearGradientBrush.cs @@ -13,6 +13,7 @@ namespace Avalonia.Media.Immutable /// The gradient stops. /// The opacity of the brush. /// The transform of the brush. + /// The transform origin of the brush /// The spread method. /// The start point for the gradient. /// The end point for the gradient. @@ -20,10 +21,11 @@ namespace Avalonia.Media.Immutable IReadOnlyList gradientStops, double opacity = 1, ImmutableTransform? transform = null, + RelativePoint? transformOrigin = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? startPoint = null, RelativePoint? endPoint = null) - : base(gradientStops, opacity, transform, spreadMethod) + : base(gradientStops, opacity, transform, transformOrigin, spreadMethod) { StartPoint = startPoint ?? RelativePoint.TopLeft; EndPoint = endPoint ?? RelativePoint.BottomRight; diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs index 3da4bdd8e9..e08d2810f8 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableRadialGradientBrush.cs @@ -13,6 +13,7 @@ namespace Avalonia.Media.Immutable /// The gradient stops. /// The opacity of the brush. /// The transform of the brush. + /// The transform origin of the brush /// The spread method. /// The start point for the gradient. /// @@ -25,11 +26,12 @@ namespace Avalonia.Media.Immutable IReadOnlyList gradientStops, double opacity = 1, ImmutableTransform? transform = null, + RelativePoint? transformOrigin = null, GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad, RelativePoint? center = null, RelativePoint? gradientOrigin = null, double radius = 0.5) - : base(gradientStops, opacity, transform, spreadMethod) + : base(gradientStops, opacity, transform, transformOrigin, spreadMethod) { Center = center ?? RelativePoint.Center; GradientOrigin = gradientOrigin ?? RelativePoint.Center; diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs index 9b1b2500ef..6755dfd236 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableSolidColorBrush.cs @@ -53,6 +53,11 @@ namespace Avalonia.Media.Immutable /// public ITransform? Transform { get; } + /// + /// Gets the transform origin of the brush + /// + public RelativePoint TransformOrigin { get; } + public bool Equals(ImmutableSolidColorBrush? other) { if (ReferenceEquals(null, other)) return false; diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs index 2c1844a2c2..6df27872fc 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableTileBrush.cs @@ -15,6 +15,7 @@ namespace Avalonia.Media.Immutable /// The rectangle on the destination in which to paint a tile. /// The opacity of the brush. /// The transform of the brush. + /// The transform origin of the brush /// The rectangle of the source image that will be displayed. /// /// How the source rectangle will be stretched to fill the destination rect. @@ -27,6 +28,7 @@ namespace Avalonia.Media.Immutable RelativeRect destinationRect, double opacity, ImmutableTransform? transform, + RelativePoint transformOrigin, RelativeRect sourceRect, Stretch stretch, TileMode tileMode, @@ -37,6 +39,7 @@ namespace Avalonia.Media.Immutable DestinationRect = destinationRect; Opacity = opacity; Transform = transform; + TransformOrigin = transformOrigin; SourceRect = sourceRect; Stretch = stretch; TileMode = tileMode; @@ -54,6 +57,7 @@ namespace Avalonia.Media.Immutable source.DestinationRect, source.Opacity, source.Transform?.ToImmutable(), + source.TransformOrigin, source.SourceRect, source.Stretch, source.TileMode, @@ -78,6 +82,11 @@ namespace Avalonia.Media.Immutable /// public ITransform? Transform { get; } + /// + /// Gets the transform origin of the brush + /// + public RelativePoint TransformOrigin { get; } + /// public RelativeRect SourceRect { get; } diff --git a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs index 8ecef63237..b436dcdb5e 100644 --- a/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs +++ b/src/Avalonia.Base/Media/Immutable/ImmutableVisualBrush.cs @@ -17,6 +17,7 @@ namespace Avalonia.Media.Immutable /// The rectangle on the destination in which to paint a tile. /// The opacity of the brush. /// The transform of the brush. + /// The transform origin of the brush /// The rectangle of the source image that will be displayed. /// /// How the source rectangle will be stretched to fill the destination rect. @@ -30,6 +31,7 @@ namespace Avalonia.Media.Immutable RelativeRect? destinationRect = null, double opacity = 1, ImmutableTransform? transform = null, + RelativePoint transformOrigin = new RelativePoint(), RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, TileMode tileMode = TileMode.None, @@ -40,6 +42,7 @@ namespace Avalonia.Media.Immutable destinationRect ?? RelativeRect.Fill, opacity, transform, + transformOrigin, sourceRect ?? RelativeRect.Fill, stretch, tileMode, From 488108aab24c59547e4cac443e28bd41d2f7f0bc Mon Sep 17 00:00:00 2001 From: amwx <40413319+amwx@users.noreply.github.com> Date: Fri, 22 Apr 2022 21:34:27 -0400 Subject: [PATCH 059/332] Support for TransformOrigin in Skia DC --- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 39 ++++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 2548b9f5aa..7e0360d691 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -180,7 +180,8 @@ namespace Avalonia.Skia var size = geometry.Bounds.Size; using (var fill = brush != null ? CreatePaint(_fillPaint, brush, size) : default(PaintWrapper)) - using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen, size) : default(PaintWrapper)) + using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen, + size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))) : default(PaintWrapper)) { if (fill.Paint != null) { @@ -397,7 +398,7 @@ namespace Avalonia.Skia if (pen?.Brush != null) { - using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size)) + using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0)))) { if (paint.Paint is object) { @@ -432,7 +433,7 @@ namespace Avalonia.Skia if (pen?.Brush != null) { - using (var paint = CreatePaint(_strokePaint, pen, rect.Size)) + using (var paint = CreatePaint(_strokePaint, pen, rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0)))) { if (paint.Paint is object) { @@ -624,8 +625,12 @@ namespace Avalonia.Skia } else { + var transformOrigin = linearGradient.TransformOrigin.ToPixels(targetSize); + var offset = Matrix.CreateTranslation(transformOrigin); + var transform = (-offset) * linearGradient.Transform.Value * (offset); + using (var shader = - SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode, linearGradient.Transform.Value.ToSKMatrix())) + SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode, transform.ToSKMatrix())) { paintWrapper.Paint.Shader = shader; } @@ -653,8 +658,12 @@ namespace Avalonia.Skia } else { + var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetSize); + var offset = Matrix.CreateTranslation(transformOrigin); + var transform = (-offset) * radialGradient.Transform.Value * (offset); + using (var shader = - SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode, radialGradient.Transform.Value.ToSKMatrix())) + SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode, transform.ToSKMatrix())) { paintWrapper.Paint.Shader = shader; } @@ -693,9 +702,14 @@ namespace Avalonia.Skia } else { + + var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetSize); + var offset = Matrix.CreateTranslation(transformOrigin); + var transform = (-offset) * radialGradient.Transform.Value * (offset); + using (var shader = SKShader.CreateCompose( SKShader.CreateColor(reversedColors[0]), - SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode, radialGradient.Transform.Value.ToSKMatrix()) + SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode, transform.ToSKMatrix()) )) { paintWrapper.Paint.Shader = shader; @@ -716,7 +730,12 @@ namespace Avalonia.Skia if (conicGradient.Transform is { }) { - rotation = rotation.PreConcat(conicGradient.Transform.Value.ToSKMatrix()); + + var transformOrigin = conicGradient.TransformOrigin.ToPixels(targetSize); + var offset = Matrix.CreateTranslation(transformOrigin); + var transform = (-offset) * conicGradient.Transform.Value * (offset); + + rotation = rotation.PreConcat(transform.ToSKMatrix()); } using (var shader = @@ -793,7 +812,11 @@ namespace Avalonia.Skia if (tileBrush.Transform is { }) { - paintTransform = paintTransform.PreConcat(tileBrush.Transform.Value.ToSKMatrix()); + var origin = tileBrush.TransformOrigin.ToPixels(targetSize); + var offset = Matrix.CreateTranslation(origin); + var transform = (-offset) * tileBrush.Transform.Value * (offset); + + paintTransform = paintTransform.PreConcat(transform.ToSKMatrix()); } using (var shader = image.ToShader(tileX, tileY, paintTransform)) From d75732699cb4ad2ed53ae441fe83ebbe0a27a758 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 26 Apr 2022 16:59:58 +0200 Subject: [PATCH 060/332] Added attributes describing API stability. Adds two attributes which describe the stability of an API: - `UnstableAttribute` indicates that we provide no API stability guarantees for the class between minor/patch versions. This is mostly applied to `*Impl` interfaces which describe the interface between core Avalonia and platform implementations - `NotClientImplementableAttribute` indicates that an interface is stable for consumption by a client, but should not be implemented outside of Avalonia itself (either because custom implementations are not supported, or because as members may be added to its API) --- build/ApiCompatAttributeExcludeList.txt | 2 ++ src/Avalonia.Base/Animation/IAnimation.cs | 2 ++ src/Avalonia.Base/Animation/IAnimationSetter.cs | 3 +++ src/Avalonia.Base/Animation/IAnimator.cs | 2 ++ src/Avalonia.Base/Animation/IClock.cs | 4 ++-- src/Avalonia.Base/Animation/IGlobalClock.cs | 5 ++--- src/Avalonia.Base/Animation/ITransition.cs | 2 ++ src/Avalonia.Base/Controls/INameScope.cs | 4 ++-- src/Avalonia.Base/Controls/IPseudoClasses.cs | 2 ++ src/Avalonia.Base/Controls/IResourceHost.cs | 4 ++-- src/Avalonia.Base/Controls/IResourceNode.cs | 4 ++-- .../Controls/ISetInheritanceParent.cs | 3 ++- src/Avalonia.Base/Controls/ISetLogicalParent.cs | 4 ++-- src/Avalonia.Base/Data/Core/IPropertyInfo.cs | 2 ++ src/Avalonia.Base/Data/IBinding.cs | 3 +++ src/Avalonia.Base/IAvaloniaObject.cs | 2 ++ src/Avalonia.Base/IDataContextProvider.cs | 3 ++- src/Avalonia.Base/IDirectPropertyAccessor.cs | 1 + src/Avalonia.Base/IDirectPropertyMetadata.cs | 3 +++ src/Avalonia.Base/IStyledElement.cs | 4 ++-- src/Avalonia.Base/IStyledPropertyMetadata.cs | 3 +++ src/Avalonia.Base/Input/IAccessKeyHandler.cs | 3 +++ src/Avalonia.Base/Input/IFocusManager.cs | 3 +++ src/Avalonia.Base/Input/IInputDevice.cs | 2 ++ src/Avalonia.Base/Input/IInputElement.cs | 2 ++ src/Avalonia.Base/Input/IInputManager.cs | 2 ++ src/Avalonia.Base/Input/IInputRoot.cs | 3 +++ src/Avalonia.Base/Input/IKeyboardDevice.cs | 2 ++ .../Input/IKeyboardNavigationHandler.cs | 3 +++ src/Avalonia.Base/Input/IMainMenu.cs | 2 ++ src/Avalonia.Base/Input/IMouseDevice.cs | 2 ++ src/Avalonia.Base/Input/IPointer.cs | 3 +++ src/Avalonia.Base/Input/IPointerDevice.cs | 2 ++ src/Avalonia.Base/Input/Platform/IClipboard.cs | 2 ++ .../Input/Platform/IPlatformDragSource.cs | 2 ++ src/Avalonia.Base/Input/Raw/IDragDropDevice.cs | 5 ++++- .../Input/TextInput/ITextInputMethodImpl.cs | 4 ++++ src/Avalonia.Base/Interactivity/IInteractive.cs | 2 ++ src/Avalonia.Base/Layout/ILayoutManager.cs | 4 ++-- src/Avalonia.Base/Layout/ILayoutRoot.cs | 3 +++ src/Avalonia.Base/Layout/ILayoutable.cs | 4 ++-- src/Avalonia.Base/LogicalTree/ILogical.cs | 2 ++ src/Avalonia.Base/LogicalTree/ILogicalRoot.cs | 5 ++++- src/Avalonia.Base/Media/IBrush.cs | 2 ++ src/Avalonia.Base/Media/IConicGradientBrush.cs | 5 ++++- src/Avalonia.Base/Media/IDashStyle.cs | 2 ++ .../Media/IExperimentalAcrylicMaterial.cs | 5 ++++- src/Avalonia.Base/Media/IGradientBrush.cs | 2 ++ src/Avalonia.Base/Media/IGradientStop.cs | 5 ++++- src/Avalonia.Base/Media/IImageBrush.cs | 4 +++- src/Avalonia.Base/Media/ILinearGradientBrush.cs | 7 +++++-- src/Avalonia.Base/Media/IMutableBrush.cs | 2 ++ .../IMutableExperimentalAcrylicMaterial.cs | 5 ++++- src/Avalonia.Base/Media/IMutableTransform.cs | 1 + src/Avalonia.Base/Media/IPen.cs | 5 ++++- src/Avalonia.Base/Media/IRadialGradientBrush.cs | 7 +++++-- src/Avalonia.Base/Media/ISolidColorBrush.cs | 5 ++++- src/Avalonia.Base/Media/ITileBrush.cs | 4 +++- src/Avalonia.Base/Media/IVisualBrush.cs | 6 ++++-- src/Avalonia.Base/Media/Imaging/IBitmap.cs | 2 ++ .../Media/TextFormatting/ITextSource.cs | 5 ++++- .../Metadata/NotClientImplementableAttribute.cs | 17 +++++++++++++++++ src/Avalonia.Base/Metadata/UnstableAttribute.cs | 12 ++++++++++++ src/Avalonia.Base/Platform/IAssetLoader.cs | 2 ++ src/Avalonia.Base/Platform/IBitmapImpl.cs | 2 ++ src/Avalonia.Base/Platform/ICursorImpl.cs | 2 ++ .../Platform/IDrawingContextImpl.cs | 2 ++ src/Avalonia.Base/Platform/IFontManagerImpl.cs | 2 ++ src/Avalonia.Base/Platform/IGeometryImpl.cs | 2 ++ src/Avalonia.Base/Platform/IGlyphRunImpl.cs | 2 ++ .../Platform/IGlyphTypefaceImpl.cs | 2 ++ .../Platform/IMacOSTopLevelPlatformHandle.cs | 2 ++ .../Platform/IPlatformRenderInterface.cs | 2 ++ src/Avalonia.Base/Platform/IPlatformSettings.cs | 2 ++ .../Platform/IPlatformThreadingInterface.cs | 2 ++ .../Platform/IRenderTargetBitmapImpl.cs | 2 ++ src/Avalonia.Base/Platform/IRuntimePlatform.cs | 5 +++++ .../Platform/IStreamGeometryContextImpl.cs | 3 +++ .../Platform/IStreamGeometryImpl.cs | 3 +++ src/Avalonia.Base/Platform/ITextShaperImpl.cs | 2 ++ .../Platform/ITransformedGeometryImpl.cs | 5 ++++- .../Platform/IWriteableBitmapImpl.cs | 5 ++++- .../Platform/Interop/IDynamicLibraryLoader.cs | 2 ++ .../Rendering/IDeferredRendererLock.cs | 2 ++ src/Avalonia.Base/Rendering/IRenderLoop.cs | 5 ++++- src/Avalonia.Base/Rendering/IRenderRoot.cs | 2 ++ src/Avalonia.Base/Rendering/IRenderTimer.cs | 2 ++ .../Rendering/IVisualBrushInitialize.cs | 2 ++ .../Rendering/IVisualBrushRenderer.cs | 2 ++ .../Styling/Activators/IStyleActivator.cs | 6 +++--- .../Styling/Activators/IStyleActivatorSink.cs | 3 ++- src/Avalonia.Base/Styling/IGlobalStyles.cs | 4 ++-- src/Avalonia.Base/Styling/ISetter.cs | 4 ++-- src/Avalonia.Base/Styling/ISetterInstance.cs | 6 +++--- src/Avalonia.Base/Styling/IStyle.cs | 5 ++--- src/Avalonia.Base/Styling/IStyleHost.cs | 2 ++ src/Avalonia.Base/Styling/IStyleInstance.cs | 4 ++-- src/Avalonia.Base/Styling/IStyleable.cs | 2 ++ src/Avalonia.Base/Styling/ITemplatedControl.cs | 2 ++ src/Avalonia.Base/VisualTree/IVisual.cs | 4 ++-- .../IApplicationLifetime.cs | 3 +++ .../IClassicDesktopStyleApplicationLifetime.cs | 2 ++ .../IControlledApplicationLifetime.cs | 2 ++ .../ISingleViewApplicationLifetime.cs | 3 +++ .../Diagnostics/IPopupHostProvider.cs | 2 ++ .../Offscreen/OffscreenTopLevelImpl.cs | 2 ++ src/Avalonia.Controls/IContentControl.cs | 2 ++ src/Avalonia.Controls/IControl.cs | 2 ++ src/Avalonia.Controls/IGlobalDataTemplates.cs | 2 ++ src/Avalonia.Controls/IMenu.cs | 2 ++ src/Avalonia.Controls/IMenuElement.cs | 2 ++ src/Avalonia.Controls/IMenuItem.cs | 5 ++++- .../INativeMenuExporterEventsImplBridge.cs | 3 +++ .../INativeMenuItemExporterEventsImplBridge.cs | 3 +++ src/Avalonia.Controls/IPanel.cs | 5 ++++- src/Avalonia.Controls/IScrollable.cs | 1 - .../IManagedNotificationManager.cs | 5 ++++- .../Notifications/INotification.cs | 2 ++ .../Notifications/INotificationManager.cs | 5 ++++- .../Platform/DefaultMenuInteractionHandler.cs | 2 ++ .../Platform/IApplicationPlatformEvents.cs | 3 +++ .../Platform/IMenuInteractionHandler.cs | 5 ++++- .../Platform/IMountedVolumeInfoProvider.cs | 4 ++-- .../Platform/INativeControlHostImpl.cs | 6 +++++- .../Platform/IPlatformIconLoader.cs | 2 ++ .../Platform/IPlatformLifetimeEventsImpl.cs | 3 ++- .../Platform/IPlatformNativeSurfaceHandle.cs | 2 ++ src/Avalonia.Controls/Platform/IPopupImpl.cs | 2 ++ src/Avalonia.Controls/Platform/IScreenImpl.cs | 4 ++-- .../Platform/ISystemDialogImpl.cs | 2 ++ src/Avalonia.Controls/Platform/ITopLevelImpl.cs | 2 ++ .../ITopLevelImplWithTextInputMethod.cs | 2 ++ .../Platform/ITopLevelNativeMenuExporter.cs | 7 ++++++- src/Avalonia.Controls/Platform/ITrayIconImpl.cs | 2 ++ .../Platform/IWindowBaseImpl.cs | 2 ++ .../Platform/IWindowIconImpl.cs | 2 ++ src/Avalonia.Controls/Platform/IWindowImpl.cs | 2 ++ .../Platform/IWindowingPlatform.cs | 3 +++ .../InternalPlatformThreadingInterface.cs | 5 ++--- .../Platform/MountedDriveInfo.cs | 2 ++ .../Platform/PlatformManager.cs | 2 ++ .../Surfaces/IFramebufferPlatformSurface.cs | 4 +++- .../Presenters/IContentPresenter.cs | 2 ++ .../Presenters/IContentPresenterHost.cs | 2 ++ .../Presenters/IItemsPresenter.cs | 2 ++ .../Presenters/IItemsPresenterHost.cs | 2 ++ src/Avalonia.Controls/Presenters/IPresenter.cs | 2 ++ src/Avalonia.Controls/Primitives/IPopupHost.cs | 2 ++ .../PopupPositioning/IPopupPositioner.cs | 4 ++++ src/Avalonia.Controls/Remote/RemoteServer.cs | 3 ++- .../Remote/Server/RemoteServerTopLevelImpl.cs | 2 ++ .../Templates/IDataTemplateHost.cs | 4 +++- .../Imaging/IOpenGlBitmapImpl.cs | 4 +++- src/Skia/Avalonia.Skia/GlyphRunImpl.cs | 2 ++ src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs | 2 ++ .../Avalonia.Skia/ISkiaDrawingContextImpl.cs | 2 ++ .../Avalonia.Direct2D1/Media/BrushImpl.cs | 2 ++ .../Media/DrawingContextImpl.cs | 2 ++ .../Avalonia.Direct2D1/Media/GeometryImpl.cs | 2 ++ .../Media/GlyphTypefaceImpl.cs | 2 ++ .../Avalonia.Direct2D1/Media/ImageBrushImpl.cs | 2 ++ .../Media/Imaging/BitmapImpl.cs | 2 ++ .../Media/Imaging/D2DBitmapImpl.cs | 2 ++ .../Media/Imaging/D2DRenderTargetBitmapImpl.cs | 2 ++ .../Media/Imaging/WicBitmapImpl.cs | 2 ++ .../Media/Imaging/WicRenderTargetBitmapImpl.cs | 2 ++ .../Media/LinearGradientBrushImpl.cs | 2 ++ .../Media/RadialGradientBrushImpl.cs | 2 ++ .../Media/SolidColorBrushImpl.cs | 2 ++ .../Media/StreamGeometryContextImpl.cs | 2 ++ .../Media/StreamGeometryImpl.cs | 2 ++ .../Media/TransformedGeometryImpl.cs | 2 ++ src/Windows/Avalonia.Win32/ScreenImpl.cs | 2 ++ src/Windows/Avalonia.Win32/TrayIconImpl.cs | 2 ++ src/Windows/Avalonia.Win32/WindowImpl.cs | 2 ++ 175 files changed, 452 insertions(+), 79 deletions(-) create mode 100644 build/ApiCompatAttributeExcludeList.txt create mode 100644 src/Avalonia.Base/Metadata/NotClientImplementableAttribute.cs create mode 100644 src/Avalonia.Base/Metadata/UnstableAttribute.cs diff --git a/build/ApiCompatAttributeExcludeList.txt b/build/ApiCompatAttributeExcludeList.txt new file mode 100644 index 0000000000..1df5a30ec3 --- /dev/null +++ b/build/ApiCompatAttributeExcludeList.txt @@ -0,0 +1,2 @@ +T:Avalonia.Metadata.NotClientImplementableAttribute +T:Avalonia.Metadata.UnstableAttribute diff --git a/src/Avalonia.Base/Animation/IAnimation.cs b/src/Avalonia.Base/Animation/IAnimation.cs index 436a765d27..eda86ed106 100644 --- a/src/Avalonia.Base/Animation/IAnimation.cs +++ b/src/Avalonia.Base/Animation/IAnimation.cs @@ -1,12 +1,14 @@ using System; using System.Threading; using System.Threading.Tasks; +using Avalonia.Metadata; namespace Avalonia.Animation { /// /// Interface for Animation objects /// + [NotClientImplementable] public interface IAnimation { /// diff --git a/src/Avalonia.Base/Animation/IAnimationSetter.cs b/src/Avalonia.Base/Animation/IAnimationSetter.cs index 6a1d3539e2..8c4ba95517 100644 --- a/src/Avalonia.Base/Animation/IAnimationSetter.cs +++ b/src/Avalonia.Base/Animation/IAnimationSetter.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Animation { + [NotClientImplementable] public interface IAnimationSetter { AvaloniaProperty? Property { get; set; } diff --git a/src/Avalonia.Base/Animation/IAnimator.cs b/src/Avalonia.Base/Animation/IAnimator.cs index f64ac9f913..06ba8dc329 100644 --- a/src/Avalonia.Base/Animation/IAnimator.cs +++ b/src/Avalonia.Base/Animation/IAnimator.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using Avalonia.Metadata; namespace Avalonia.Animation { /// /// Interface for Animator objects /// + [NotClientImplementable] public interface IAnimator : IList { /// diff --git a/src/Avalonia.Base/Animation/IClock.cs b/src/Avalonia.Base/Animation/IClock.cs index ae44102077..7b3b7b3924 100644 --- a/src/Avalonia.Base/Animation/IClock.cs +++ b/src/Avalonia.Base/Animation/IClock.cs @@ -1,9 +1,9 @@ using System; -using System.Collections.Generic; -using System.Text; +using Avalonia.Metadata; namespace Avalonia.Animation { + [NotClientImplementable] public interface IClock : IObservable { PlayState PlayState { get; set; } diff --git a/src/Avalonia.Base/Animation/IGlobalClock.cs b/src/Avalonia.Base/Animation/IGlobalClock.cs index b0455e2c80..138dc07539 100644 --- a/src/Avalonia.Base/Animation/IGlobalClock.cs +++ b/src/Avalonia.Base/Animation/IGlobalClock.cs @@ -1,9 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Text; +using Avalonia.Metadata; namespace Avalonia.Animation { + [NotClientImplementable] public interface IGlobalClock : IClock { } diff --git a/src/Avalonia.Base/Animation/ITransition.cs b/src/Avalonia.Base/Animation/ITransition.cs index 241ca208d1..639b92ce35 100644 --- a/src/Avalonia.Base/Animation/ITransition.cs +++ b/src/Avalonia.Base/Animation/ITransition.cs @@ -1,10 +1,12 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Animation { /// /// Interface for Transition objects. /// + [NotClientImplementable] public interface ITransition { /// diff --git a/src/Avalonia.Base/Controls/INameScope.cs b/src/Avalonia.Base/Controls/INameScope.cs index 1ca7db2f37..a12e88c055 100644 --- a/src/Avalonia.Base/Controls/INameScope.cs +++ b/src/Avalonia.Base/Controls/INameScope.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading.Tasks; +using Avalonia.Metadata; using Avalonia.Utilities; namespace Avalonia.Controls @@ -7,6 +6,7 @@ namespace Avalonia.Controls /// /// Defines a name scope. /// + [NotClientImplementable] public interface INameScope { /// diff --git a/src/Avalonia.Base/Controls/IPseudoClasses.cs b/src/Avalonia.Base/Controls/IPseudoClasses.cs index 27290716d0..eda521727f 100644 --- a/src/Avalonia.Base/Controls/IPseudoClasses.cs +++ b/src/Avalonia.Base/Controls/IPseudoClasses.cs @@ -1,9 +1,11 @@ +using Avalonia.Metadata; namespace Avalonia.Controls { /// /// Exposes an interface for setting pseudoclasses on a collection. /// + [NotClientImplementable] public interface IPseudoClasses { /// diff --git a/src/Avalonia.Base/Controls/IResourceHost.cs b/src/Avalonia.Base/Controls/IResourceHost.cs index ea34a8b39a..286f0e36ef 100644 --- a/src/Avalonia.Base/Controls/IResourceHost.cs +++ b/src/Avalonia.Base/Controls/IResourceHost.cs @@ -1,6 +1,5 @@ using System; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Controls { @@ -10,6 +9,7 @@ namespace Avalonia.Controls /// /// This interface is implemented by and `Application`. /// + [NotClientImplementable] public interface IResourceHost : IResourceNode { /// diff --git a/src/Avalonia.Base/Controls/IResourceNode.cs b/src/Avalonia.Base/Controls/IResourceNode.cs index 73bfeaf161..d6c900f97f 100644 --- a/src/Avalonia.Base/Controls/IResourceNode.cs +++ b/src/Avalonia.Base/Controls/IResourceNode.cs @@ -1,6 +1,5 @@ using System; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Controls { @@ -12,6 +11,7 @@ namespace Avalonia.Controls /// () and resource providers such as /// (see ). /// + [NotClientImplementable] public interface IResourceNode { /// diff --git a/src/Avalonia.Base/Controls/ISetInheritanceParent.cs b/src/Avalonia.Base/Controls/ISetInheritanceParent.cs index dbf8c68892..e85e025005 100644 --- a/src/Avalonia.Base/Controls/ISetInheritanceParent.cs +++ b/src/Avalonia.Base/Controls/ISetInheritanceParent.cs @@ -1,4 +1,4 @@ -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Controls { @@ -10,6 +10,7 @@ namespace Avalonia.Controls /// Additionally, also sets the inheritance parent; this /// interface is only needed where the logical and inheritance parents differ. /// + [NotClientImplementable] public interface ISetInheritanceParent { /// diff --git a/src/Avalonia.Base/Controls/ISetLogicalParent.cs b/src/Avalonia.Base/Controls/ISetLogicalParent.cs index 85bda05961..7f1b4b5d87 100644 --- a/src/Avalonia.Base/Controls/ISetLogicalParent.cs +++ b/src/Avalonia.Base/Controls/ISetLogicalParent.cs @@ -1,6 +1,5 @@ using Avalonia.LogicalTree; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Controls { @@ -10,6 +9,7 @@ namespace Avalonia.Controls /// /// You should not usually need to use this interface - it is for advanced scenarios only. /// + [NotClientImplementable] public interface ISetLogicalParent { /// diff --git a/src/Avalonia.Base/Data/Core/IPropertyInfo.cs b/src/Avalonia.Base/Data/Core/IPropertyInfo.cs index 4d80feb4ba..0cb8a937cc 100644 --- a/src/Avalonia.Base/Data/Core/IPropertyInfo.cs +++ b/src/Avalonia.Base/Data/Core/IPropertyInfo.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Data.Core { + [NotClientImplementable] public interface IPropertyInfo { string Name { get; } diff --git a/src/Avalonia.Base/Data/IBinding.cs b/src/Avalonia.Base/Data/IBinding.cs index 9535cf608e..7d44bf09b5 100644 --- a/src/Avalonia.Base/Data/IBinding.cs +++ b/src/Avalonia.Base/Data/IBinding.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Data { /// /// Holds a binding that can be applied to a property on an object. /// + [NotClientImplementable] public interface IBinding { /// diff --git a/src/Avalonia.Base/IAvaloniaObject.cs b/src/Avalonia.Base/IAvaloniaObject.cs index 00f5062f9e..3b0016903b 100644 --- a/src/Avalonia.Base/IAvaloniaObject.cs +++ b/src/Avalonia.Base/IAvaloniaObject.cs @@ -1,11 +1,13 @@ using System; using Avalonia.Data; +using Avalonia.Metadata; namespace Avalonia { /// /// Interface for getting/setting values on an object. /// + [NotClientImplementable] public interface IAvaloniaObject { /// diff --git a/src/Avalonia.Base/IDataContextProvider.cs b/src/Avalonia.Base/IDataContextProvider.cs index 1172adcaa4..1d381cf4a5 100644 --- a/src/Avalonia.Base/IDataContextProvider.cs +++ b/src/Avalonia.Base/IDataContextProvider.cs @@ -1,10 +1,11 @@ -#nullable enable +using Avalonia.Metadata; namespace Avalonia { /// /// Defines an element with a data context that can be used for binding. /// + [NotClientImplementable] public interface IDataContextProvider : IAvaloniaObject { /// diff --git a/src/Avalonia.Base/IDirectPropertyAccessor.cs b/src/Avalonia.Base/IDirectPropertyAccessor.cs index e34483fa7b..476a36f372 100644 --- a/src/Avalonia.Base/IDirectPropertyAccessor.cs +++ b/src/Avalonia.Base/IDirectPropertyAccessor.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Metadata; namespace Avalonia { diff --git a/src/Avalonia.Base/IDirectPropertyMetadata.cs b/src/Avalonia.Base/IDirectPropertyMetadata.cs index 4fd4a3a6b7..7d74470a13 100644 --- a/src/Avalonia.Base/IDirectPropertyMetadata.cs +++ b/src/Avalonia.Base/IDirectPropertyMetadata.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia { /// /// Untyped interface to /// + [NotClientImplementable] public interface IDirectPropertyMetadata { /// diff --git a/src/Avalonia.Base/IStyledElement.cs b/src/Avalonia.Base/IStyledElement.cs index a068d4a5bf..4eed54de45 100644 --- a/src/Avalonia.Base/IStyledElement.cs +++ b/src/Avalonia.Base/IStyledElement.cs @@ -2,12 +2,12 @@ using System.ComponentModel; using Avalonia.Controls; using Avalonia.LogicalTree; +using Avalonia.Metadata; using Avalonia.Styling; -#nullable enable - namespace Avalonia { + [NotClientImplementable] public interface IStyledElement : IStyleable, IStyleHost, diff --git a/src/Avalonia.Base/IStyledPropertyMetadata.cs b/src/Avalonia.Base/IStyledPropertyMetadata.cs index 6b29b5f977..89990338e0 100644 --- a/src/Avalonia.Base/IStyledPropertyMetadata.cs +++ b/src/Avalonia.Base/IStyledPropertyMetadata.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia { /// /// Untyped interface to /// + [NotClientImplementable] public interface IStyledPropertyMetadata { /// diff --git a/src/Avalonia.Base/Input/IAccessKeyHandler.cs b/src/Avalonia.Base/Input/IAccessKeyHandler.cs index e484d003c7..93a50968e2 100644 --- a/src/Avalonia.Base/Input/IAccessKeyHandler.cs +++ b/src/Avalonia.Base/Input/IAccessKeyHandler.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Input { /// /// Defines the interface for classes that handle access keys for a window. /// + [Unstable] public interface IAccessKeyHandler { /// diff --git a/src/Avalonia.Base/Input/IFocusManager.cs b/src/Avalonia.Base/Input/IFocusManager.cs index 2510479a8e..0c85cad2f7 100644 --- a/src/Avalonia.Base/Input/IFocusManager.cs +++ b/src/Avalonia.Base/Input/IFocusManager.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Input { /// /// Manages focus for the application. /// + [NotClientImplementable] public interface IFocusManager { /// diff --git a/src/Avalonia.Base/Input/IInputDevice.cs b/src/Avalonia.Base/Input/IInputDevice.cs index ab0fae65df..fe4f584f18 100644 --- a/src/Avalonia.Base/Input/IInputDevice.cs +++ b/src/Avalonia.Base/Input/IInputDevice.cs @@ -1,7 +1,9 @@ using Avalonia.Input.Raw; +using Avalonia.Metadata; namespace Avalonia.Input { + [NotClientImplementable] public interface IInputDevice { /// diff --git a/src/Avalonia.Base/Input/IInputElement.cs b/src/Avalonia.Base/Input/IInputElement.cs index d1552a3a2a..78001143d7 100644 --- a/src/Avalonia.Base/Input/IInputElement.cs +++ b/src/Avalonia.Base/Input/IInputElement.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Avalonia.Interactivity; +using Avalonia.Metadata; using Avalonia.VisualTree; #nullable enable @@ -10,6 +11,7 @@ namespace Avalonia.Input /// /// Defines input-related functionality for a control. /// + [NotClientImplementable] public interface IInputElement : IInteractive, IVisual { /// diff --git a/src/Avalonia.Base/Input/IInputManager.cs b/src/Avalonia.Base/Input/IInputManager.cs index 80b71d3e47..658226a519 100644 --- a/src/Avalonia.Base/Input/IInputManager.cs +++ b/src/Avalonia.Base/Input/IInputManager.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Input.Raw; +using Avalonia.Metadata; namespace Avalonia.Input { @@ -7,6 +8,7 @@ namespace Avalonia.Input /// Receives input from the windowing subsystem and dispatches it to interested parties /// for processing. /// + [NotClientImplementable] public interface IInputManager { /// diff --git a/src/Avalonia.Base/Input/IInputRoot.cs b/src/Avalonia.Base/Input/IInputRoot.cs index 98e8699573..7edc69df52 100644 --- a/src/Avalonia.Base/Input/IInputRoot.cs +++ b/src/Avalonia.Base/Input/IInputRoot.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Input { /// /// Defines the interface for top-level input elements. /// + [NotClientImplementable] public interface IInputRoot : IInputElement { /// diff --git a/src/Avalonia.Base/Input/IKeyboardDevice.cs b/src/Avalonia.Base/Input/IKeyboardDevice.cs index d0e84e5ad0..c8db8bf16f 100644 --- a/src/Avalonia.Base/Input/IKeyboardDevice.cs +++ b/src/Avalonia.Base/Input/IKeyboardDevice.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using Avalonia.Metadata; namespace Avalonia.Input { @@ -50,6 +51,7 @@ namespace Avalonia.Input KeyboardMask = Alt | Control | Shift | Meta } + [NotClientImplementable] public interface IKeyboardDevice : IInputDevice, INotifyPropertyChanged { IInputElement? FocusedElement { get; } diff --git a/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs b/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs index 88d00b3b50..3bcd6d6206 100644 --- a/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs +++ b/src/Avalonia.Base/Input/IKeyboardNavigationHandler.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Input { /// /// Defines the interface for classes that handle keyboard navigation for a window. /// + [Unstable] public interface IKeyboardNavigationHandler { /// diff --git a/src/Avalonia.Base/Input/IMainMenu.cs b/src/Avalonia.Base/Input/IMainMenu.cs index 67b58c0ffc..213a979c28 100644 --- a/src/Avalonia.Base/Input/IMainMenu.cs +++ b/src/Avalonia.Base/Input/IMainMenu.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Interactivity; +using Avalonia.Metadata; using Avalonia.VisualTree; namespace Avalonia.Input @@ -7,6 +8,7 @@ namespace Avalonia.Input /// /// Defines the interface for a window's main menu. /// + [NotClientImplementable] public interface IMainMenu : IVisual { /// diff --git a/src/Avalonia.Base/Input/IMouseDevice.cs b/src/Avalonia.Base/Input/IMouseDevice.cs index 6b7f0e76e5..2d66397d63 100644 --- a/src/Avalonia.Base/Input/IMouseDevice.cs +++ b/src/Avalonia.Base/Input/IMouseDevice.cs @@ -1,10 +1,12 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Input { /// /// Represents a mouse device. /// + [NotClientImplementable] public interface IMouseDevice : IPointerDevice { /// diff --git a/src/Avalonia.Base/Input/IPointer.cs b/src/Avalonia.Base/Input/IPointer.cs index 7af48cef82..66aeacadc9 100644 --- a/src/Avalonia.Base/Input/IPointer.cs +++ b/src/Avalonia.Base/Input/IPointer.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Input { + [NotClientImplementable] public interface IPointer { int Id { get; } diff --git a/src/Avalonia.Base/Input/IPointerDevice.cs b/src/Avalonia.Base/Input/IPointerDevice.cs index 0096bb77bf..0993835feb 100644 --- a/src/Avalonia.Base/Input/IPointerDevice.cs +++ b/src/Avalonia.Base/Input/IPointerDevice.cs @@ -1,9 +1,11 @@ using System; using Avalonia.VisualTree; using Avalonia.Input.Raw; +using Avalonia.Metadata; namespace Avalonia.Input { + [NotClientImplementable] public interface IPointerDevice : IInputDevice { /// diff --git a/src/Avalonia.Base/Input/Platform/IClipboard.cs b/src/Avalonia.Base/Input/Platform/IClipboard.cs index eb880904eb..bf2a5a8602 100644 --- a/src/Avalonia.Base/Input/Platform/IClipboard.cs +++ b/src/Avalonia.Base/Input/Platform/IClipboard.cs @@ -1,7 +1,9 @@ using System.Threading.Tasks; +using Avalonia.Metadata; namespace Avalonia.Input.Platform { + [NotClientImplementable] public interface IClipboard { Task GetTextAsync(); diff --git a/src/Avalonia.Base/Input/Platform/IPlatformDragSource.cs b/src/Avalonia.Base/Input/Platform/IPlatformDragSource.cs index 30d8ee5337..8d1b93087e 100644 --- a/src/Avalonia.Base/Input/Platform/IPlatformDragSource.cs +++ b/src/Avalonia.Base/Input/Platform/IPlatformDragSource.cs @@ -1,7 +1,9 @@ using System.Threading.Tasks; +using Avalonia.Metadata; namespace Avalonia.Input.Platform { + [Unstable] public interface IPlatformDragSource { Task DoDragDrop(PointerEventArgs triggerEvent, IDataObject data, DragDropEffects allowedEffects); diff --git a/src/Avalonia.Base/Input/Raw/IDragDropDevice.cs b/src/Avalonia.Base/Input/Raw/IDragDropDevice.cs index f7b7914bd1..3bcc9fadd3 100644 --- a/src/Avalonia.Base/Input/Raw/IDragDropDevice.cs +++ b/src/Avalonia.Base/Input/Raw/IDragDropDevice.cs @@ -1,5 +1,8 @@ -namespace Avalonia.Input.Raw +using Avalonia.Metadata; + +namespace Avalonia.Input.Raw { + [NotClientImplementable] public interface IDragDropDevice : IInputDevice { } diff --git a/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs b/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs index 4404c903b7..be7ad81f81 100644 --- a/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs +++ b/src/Avalonia.Base/Input/TextInput/ITextInputMethodImpl.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Input.TextInput { + [Unstable] public interface ITextInputMethodImpl { void SetClient(ITextInputMethodClient? client); @@ -8,6 +11,7 @@ namespace Avalonia.Input.TextInput void Reset(); } + [NotClientImplementable] public interface ITextInputMethodRoot : IInputRoot { ITextInputMethodImpl? InputMethod { get; } diff --git a/src/Avalonia.Base/Interactivity/IInteractive.cs b/src/Avalonia.Base/Interactivity/IInteractive.cs index 6d7dcd64f4..980bf54f1f 100644 --- a/src/Avalonia.Base/Interactivity/IInteractive.cs +++ b/src/Avalonia.Base/Interactivity/IInteractive.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Metadata; #nullable enable @@ -7,6 +8,7 @@ namespace Avalonia.Interactivity /// /// Interface for objects that raise routed events. /// + [NotClientImplementable] public interface IInteractive { /// diff --git a/src/Avalonia.Base/Layout/ILayoutManager.cs b/src/Avalonia.Base/Layout/ILayoutManager.cs index 614670a53b..143ce13a1b 100644 --- a/src/Avalonia.Base/Layout/ILayoutManager.cs +++ b/src/Avalonia.Base/Layout/ILayoutManager.cs @@ -1,12 +1,12 @@ using System; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Layout { /// /// Manages measuring and arranging of controls. /// + [NotClientImplementable] public interface ILayoutManager : IDisposable { /// diff --git a/src/Avalonia.Base/Layout/ILayoutRoot.cs b/src/Avalonia.Base/Layout/ILayoutRoot.cs index e2f16b338a..df15fc1a1d 100644 --- a/src/Avalonia.Base/Layout/ILayoutRoot.cs +++ b/src/Avalonia.Base/Layout/ILayoutRoot.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Layout { /// /// Defines the root of a layoutable tree. /// + [NotClientImplementable] public interface ILayoutRoot : ILayoutable { /// diff --git a/src/Avalonia.Base/Layout/ILayoutable.cs b/src/Avalonia.Base/Layout/ILayoutable.cs index 54d3ba6a11..d8b546b04a 100644 --- a/src/Avalonia.Base/Layout/ILayoutable.cs +++ b/src/Avalonia.Base/Layout/ILayoutable.cs @@ -1,12 +1,12 @@ +using Avalonia.Metadata; using Avalonia.VisualTree; -#nullable enable - namespace Avalonia.Layout { /// /// Defines layout-related functionality for a control. /// + [NotClientImplementable] public interface ILayoutable : IVisual { /// diff --git a/src/Avalonia.Base/LogicalTree/ILogical.cs b/src/Avalonia.Base/LogicalTree/ILogical.cs index caff3d8150..9cc2edff86 100644 --- a/src/Avalonia.Base/LogicalTree/ILogical.cs +++ b/src/Avalonia.Base/LogicalTree/ILogical.cs @@ -1,12 +1,14 @@ using System; using Avalonia.Collections; using Avalonia.Controls; +using Avalonia.Metadata; namespace Avalonia.LogicalTree { /// /// Represents a node in the logical tree. /// + [NotClientImplementable] public interface ILogical { /// diff --git a/src/Avalonia.Base/LogicalTree/ILogicalRoot.cs b/src/Avalonia.Base/LogicalTree/ILogicalRoot.cs index 4a61544a6f..ea0f554e96 100644 --- a/src/Avalonia.Base/LogicalTree/ILogicalRoot.cs +++ b/src/Avalonia.Base/LogicalTree/ILogicalRoot.cs @@ -1,8 +1,11 @@ -namespace Avalonia.LogicalTree +using Avalonia.Metadata; + +namespace Avalonia.LogicalTree { /// /// Represents a root of a logical tree. /// + [NotClientImplementable] public interface ILogicalRoot : ILogical { } diff --git a/src/Avalonia.Base/Media/IBrush.cs b/src/Avalonia.Base/Media/IBrush.cs index 830c066182..10700492d1 100644 --- a/src/Avalonia.Base/Media/IBrush.cs +++ b/src/Avalonia.Base/Media/IBrush.cs @@ -1,4 +1,5 @@ using System.ComponentModel; +using Avalonia.Metadata; namespace Avalonia.Media { @@ -6,6 +7,7 @@ namespace Avalonia.Media /// Describes how an area is painted. /// [TypeConverter(typeof(BrushConverter))] + [NotClientImplementable] public interface IBrush { /// diff --git a/src/Avalonia.Base/Media/IConicGradientBrush.cs b/src/Avalonia.Base/Media/IConicGradientBrush.cs index 5368dd1851..6a397b86d4 100644 --- a/src/Avalonia.Base/Media/IConicGradientBrush.cs +++ b/src/Avalonia.Base/Media/IConicGradientBrush.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media +using Avalonia.Metadata; + +namespace Avalonia.Media { /// /// Paints an area with a conic gradient. /// + [NotClientImplementable] public interface IConicGradientBrush : IGradientBrush { /// diff --git a/src/Avalonia.Base/Media/IDashStyle.cs b/src/Avalonia.Base/Media/IDashStyle.cs index 7835c7a1e9..7208216603 100644 --- a/src/Avalonia.Base/Media/IDashStyle.cs +++ b/src/Avalonia.Base/Media/IDashStyle.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; +using Avalonia.Metadata; namespace Avalonia.Media { /// /// Represents the sequence of dashes and gaps that will be applied by a . /// + [NotClientImplementable] public interface IDashStyle { /// diff --git a/src/Avalonia.Base/Media/IExperimentalAcrylicMaterial.cs b/src/Avalonia.Base/Media/IExperimentalAcrylicMaterial.cs index e71584258a..38048fb255 100644 --- a/src/Avalonia.Base/Media/IExperimentalAcrylicMaterial.cs +++ b/src/Avalonia.Base/Media/IExperimentalAcrylicMaterial.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media +using Avalonia.Metadata; + +namespace Avalonia.Media { /// /// Experimental Interface for producing Acrylic-like materials. /// + [NotClientImplementable] public interface IExperimentalAcrylicMaterial { /// diff --git a/src/Avalonia.Base/Media/IGradientBrush.cs b/src/Avalonia.Base/Media/IGradientBrush.cs index 18db0af660..9b78a4af78 100644 --- a/src/Avalonia.Base/Media/IGradientBrush.cs +++ b/src/Avalonia.Base/Media/IGradientBrush.cs @@ -1,10 +1,12 @@ using System.Collections.Generic; +using Avalonia.Metadata; namespace Avalonia.Media { /// /// A brush that draws with a gradient. /// + [NotClientImplementable] public interface IGradientBrush : IBrush { /// diff --git a/src/Avalonia.Base/Media/IGradientStop.cs b/src/Avalonia.Base/Media/IGradientStop.cs index 22eb9df60d..64b952f3bc 100644 --- a/src/Avalonia.Base/Media/IGradientStop.cs +++ b/src/Avalonia.Base/Media/IGradientStop.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media +using Avalonia.Metadata; + +namespace Avalonia.Media { /// /// Describes the location and color of a transition point in a gradient. /// + [NotClientImplementable] public interface IGradientStop { /// diff --git a/src/Avalonia.Base/Media/IImageBrush.cs b/src/Avalonia.Base/Media/IImageBrush.cs index aaa481bd28..732f1957d0 100644 --- a/src/Avalonia.Base/Media/IImageBrush.cs +++ b/src/Avalonia.Base/Media/IImageBrush.cs @@ -1,10 +1,12 @@ using Avalonia.Media.Imaging; +using Avalonia.Metadata; namespace Avalonia.Media { /// /// Paints an area with an . /// + [NotClientImplementable] public interface IImageBrush : ITileBrush { /// @@ -12,4 +14,4 @@ namespace Avalonia.Media /// IBitmap Source { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Media/ILinearGradientBrush.cs b/src/Avalonia.Base/Media/ILinearGradientBrush.cs index 3e2a5a0e22..4f4a55db36 100644 --- a/src/Avalonia.Base/Media/ILinearGradientBrush.cs +++ b/src/Avalonia.Base/Media/ILinearGradientBrush.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media +using Avalonia.Metadata; + +namespace Avalonia.Media { /// /// A brush that draws with a linear gradient. /// + [NotClientImplementable] public interface ILinearGradientBrush : IGradientBrush { /// @@ -15,4 +18,4 @@ /// RelativePoint EndPoint { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Media/IMutableBrush.cs b/src/Avalonia.Base/Media/IMutableBrush.cs index 415db61d68..fef124ba36 100644 --- a/src/Avalonia.Base/Media/IMutableBrush.cs +++ b/src/Avalonia.Base/Media/IMutableBrush.cs @@ -1,10 +1,12 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Media { /// /// Represents a mutable brush which can return an immutable clone of itself. /// + [NotClientImplementable] public interface IMutableBrush : IBrush, IAffectsRender { /// diff --git a/src/Avalonia.Base/Media/IMutableExperimentalAcrylicMaterial.cs b/src/Avalonia.Base/Media/IMutableExperimentalAcrylicMaterial.cs index fcfe4631a6..f954a8c52a 100644 --- a/src/Avalonia.Base/Media/IMutableExperimentalAcrylicMaterial.cs +++ b/src/Avalonia.Base/Media/IMutableExperimentalAcrylicMaterial.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media +using Avalonia.Metadata; + +namespace Avalonia.Media { /// /// Represents a mutable brush which can return an immutable clone of itself. /// + [NotClientImplementable] public interface IMutableExperimentalAcrylicMaterial : IExperimentalAcrylicMaterial, IAffectsRender { /// diff --git a/src/Avalonia.Base/Media/IMutableTransform.cs b/src/Avalonia.Base/Media/IMutableTransform.cs index 2033c434c0..22526eed17 100644 --- a/src/Avalonia.Base/Media/IMutableTransform.cs +++ b/src/Avalonia.Base/Media/IMutableTransform.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Media { diff --git a/src/Avalonia.Base/Media/IPen.cs b/src/Avalonia.Base/Media/IPen.cs index 1cad9948b4..eca1cb507a 100644 --- a/src/Avalonia.Base/Media/IPen.cs +++ b/src/Avalonia.Base/Media/IPen.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media +using Avalonia.Metadata; + +namespace Avalonia.Media { /// /// Describes how a stroke is drawn. /// + [NotClientImplementable] public interface IPen { /// diff --git a/src/Avalonia.Base/Media/IRadialGradientBrush.cs b/src/Avalonia.Base/Media/IRadialGradientBrush.cs index cadf53cc18..0f025e98bc 100644 --- a/src/Avalonia.Base/Media/IRadialGradientBrush.cs +++ b/src/Avalonia.Base/Media/IRadialGradientBrush.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media +using Avalonia.Metadata; + +namespace Avalonia.Media { /// /// Paints an area with a radial gradient. /// + [NotClientImplementable] public interface IRadialGradientBrush : IGradientBrush { /// @@ -21,4 +24,4 @@ /// double Radius { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Media/ISolidColorBrush.cs b/src/Avalonia.Base/Media/ISolidColorBrush.cs index d0ab00599b..29e11210f1 100644 --- a/src/Avalonia.Base/Media/ISolidColorBrush.cs +++ b/src/Avalonia.Base/Media/ISolidColorBrush.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Media { /// /// Fills an area with a solid color. /// + [NotClientImplementable] public interface ISolidColorBrush : IBrush { /// @@ -10,4 +13,4 @@ namespace Avalonia.Media /// Color Color { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Media/ITileBrush.cs b/src/Avalonia.Base/Media/ITileBrush.cs index 991857eec9..cb5a591003 100644 --- a/src/Avalonia.Base/Media/ITileBrush.cs +++ b/src/Avalonia.Base/Media/ITileBrush.cs @@ -1,10 +1,12 @@ using Avalonia.Media.Imaging; +using Avalonia.Metadata; namespace Avalonia.Media -{ +{ /// /// A brush which displays a repeating image. /// + [NotClientImplementable] public interface ITileBrush : IBrush { /// diff --git a/src/Avalonia.Base/Media/IVisualBrush.cs b/src/Avalonia.Base/Media/IVisualBrush.cs index e74892b218..b8900bbd73 100644 --- a/src/Avalonia.Base/Media/IVisualBrush.cs +++ b/src/Avalonia.Base/Media/IVisualBrush.cs @@ -1,10 +1,12 @@ -using Avalonia.VisualTree; +using Avalonia.Metadata; +using Avalonia.VisualTree; namespace Avalonia.Media { /// /// Paints an area with an . /// + [NotClientImplementable] public interface IVisualBrush : ITileBrush { /// @@ -12,4 +14,4 @@ namespace Avalonia.Media /// IVisual Visual { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Media/Imaging/IBitmap.cs b/src/Avalonia.Base/Media/Imaging/IBitmap.cs index 134bebc002..bd04d5ce86 100644 --- a/src/Avalonia.Base/Media/Imaging/IBitmap.cs +++ b/src/Avalonia.Base/Media/Imaging/IBitmap.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Utilities; @@ -8,6 +9,7 @@ namespace Avalonia.Media.Imaging /// /// Represents a bitmap image. /// + [NotClientImplementable] public interface IBitmap : IImage, IDisposable { /// diff --git a/src/Avalonia.Base/Media/TextFormatting/ITextSource.cs b/src/Avalonia.Base/Media/TextFormatting/ITextSource.cs index 32012ab8e9..85641977e6 100644 --- a/src/Avalonia.Base/Media/TextFormatting/ITextSource.cs +++ b/src/Avalonia.Base/Media/TextFormatting/ITextSource.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Media.TextFormatting +using Avalonia.Metadata; + +namespace Avalonia.Media.TextFormatting { /// /// Produces objects that are used by the . /// + [NotClientImplementable] public interface ITextSource { /// diff --git a/src/Avalonia.Base/Metadata/NotClientImplementableAttribute.cs b/src/Avalonia.Base/Metadata/NotClientImplementableAttribute.cs new file mode 100644 index 0000000000..348c983c03 --- /dev/null +++ b/src/Avalonia.Base/Metadata/NotClientImplementableAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace Avalonia.Metadata +{ + /// + /// This interface is not intended to be implemented outside of the core Avalonia framework as + /// its API may change without warning. + /// + /// + /// This interface is stable for consumption by a client, but should not be implemented as members + /// may be added to its API. + /// + [AttributeUsage(AttributeTargets.Interface)] + public class NotClientImplementableAttribute : Attribute + { + } +} diff --git a/src/Avalonia.Base/Metadata/UnstableAttribute.cs b/src/Avalonia.Base/Metadata/UnstableAttribute.cs new file mode 100644 index 0000000000..3b6fa5168a --- /dev/null +++ b/src/Avalonia.Base/Metadata/UnstableAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace Avalonia.Metadata +{ + /// + /// This API is unstable and is not covered by API compatibility guarantees between minor and + /// patch releases. + /// + public class UnstableAttribute : Attribute + { + } +} diff --git a/src/Avalonia.Base/Platform/IAssetLoader.cs b/src/Avalonia.Base/Platform/IAssetLoader.cs index e3899784ad..b65d61803f 100644 --- a/src/Avalonia.Base/Platform/IAssetLoader.cs +++ b/src/Avalonia.Base/Platform/IAssetLoader.cs @@ -2,12 +2,14 @@ using System; using System.Collections.Generic; using System.IO; using System.Reflection; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Loads assets compiled into the application binary. /// + [Unstable] public interface IAssetLoader { /// diff --git a/src/Avalonia.Base/Platform/IBitmapImpl.cs b/src/Avalonia.Base/Platform/IBitmapImpl.cs index 1e68bc477d..8f11f68e7c 100644 --- a/src/Avalonia.Base/Platform/IBitmapImpl.cs +++ b/src/Avalonia.Base/Platform/IBitmapImpl.cs @@ -1,11 +1,13 @@ using System; using System.IO; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Defines the platform-specific interface for a . /// + [Unstable] public interface IBitmapImpl : IDisposable { /// diff --git a/src/Avalonia.Base/Platform/ICursorImpl.cs b/src/Avalonia.Base/Platform/ICursorImpl.cs index 14235869f7..74e0ba2e5c 100644 --- a/src/Avalonia.Base/Platform/ICursorImpl.cs +++ b/src/Avalonia.Base/Platform/ICursorImpl.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Input; +using Avalonia.Metadata; #nullable enable @@ -8,6 +9,7 @@ namespace Avalonia.Platform /// /// Represents a platform implementation of a . /// + [Unstable] public interface ICursorImpl : IDisposable { } diff --git a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs index 4e6612e908..d84a509234 100644 --- a/src/Avalonia.Base/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Base/Platform/IDrawingContextImpl.cs @@ -3,12 +3,14 @@ using Avalonia.Media; using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; using Avalonia.Media.Imaging; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Defines the interface through which drawing occurs. /// + [Unstable] public interface IDrawingContextImpl : IDisposable { /// diff --git a/src/Avalonia.Base/Platform/IFontManagerImpl.cs b/src/Avalonia.Base/Platform/IFontManagerImpl.cs index 0110287afd..932249bd52 100644 --- a/src/Avalonia.Base/Platform/IFontManagerImpl.cs +++ b/src/Avalonia.Base/Platform/IFontManagerImpl.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; using System.Globalization; using Avalonia.Media; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IFontManagerImpl { /// diff --git a/src/Avalonia.Base/Platform/IGeometryImpl.cs b/src/Avalonia.Base/Platform/IGeometryImpl.cs index ed6de1b5c7..c80f8923ef 100644 --- a/src/Avalonia.Base/Platform/IGeometryImpl.cs +++ b/src/Avalonia.Base/Platform/IGeometryImpl.cs @@ -1,10 +1,12 @@ using Avalonia.Media; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Defines the platform-specific interface for a . /// + [Unstable] public interface IGeometryImpl { /// diff --git a/src/Avalonia.Base/Platform/IGlyphRunImpl.cs b/src/Avalonia.Base/Platform/IGlyphRunImpl.cs index 08786d9689..7801bdd50f 100644 --- a/src/Avalonia.Base/Platform/IGlyphRunImpl.cs +++ b/src/Avalonia.Base/Platform/IGlyphRunImpl.cs @@ -1,9 +1,11 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Actual implementation of a glyph run that stores platform dependent resources. /// + [Unstable] public interface IGlyphRunImpl : IDisposable { } } diff --git a/src/Avalonia.Base/Platform/IGlyphTypefaceImpl.cs b/src/Avalonia.Base/Platform/IGlyphTypefaceImpl.cs index 6afd79d29c..415f34fb29 100644 --- a/src/Avalonia.Base/Platform/IGlyphTypefaceImpl.cs +++ b/src/Avalonia.Base/Platform/IGlyphTypefaceImpl.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IGlyphTypefaceImpl : IDisposable { /// diff --git a/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs b/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs index e399976bbe..b087724079 100644 --- a/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs +++ b/src/Avalonia.Base/Platform/IMacOSTopLevelPlatformHandle.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IMacOSTopLevelPlatformHandle { IntPtr NSView { get; } diff --git a/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs index c46efd46c3..0eeefddf0b 100644 --- a/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Base/Platform/IPlatformRenderInterface.cs @@ -3,12 +3,14 @@ using System.Collections.Generic; using System.IO; using Avalonia.Media; using Avalonia.Media.Imaging; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Defines the main platform-specific interface for the rendering subsystem. /// + [Unstable] public interface IPlatformRenderInterface { /// diff --git a/src/Avalonia.Base/Platform/IPlatformSettings.cs b/src/Avalonia.Base/Platform/IPlatformSettings.cs index e4b28e6575..78d1817312 100644 --- a/src/Avalonia.Base/Platform/IPlatformSettings.cs +++ b/src/Avalonia.Base/Platform/IPlatformSettings.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IPlatformSettings { Size DoubleClickSize { get; } diff --git a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs index 2137f965cc..bf18a7da5b 100644 --- a/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs +++ b/src/Avalonia.Base/Platform/IPlatformThreadingInterface.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using Avalonia.Metadata; using Avalonia.Threading; namespace Avalonia.Platform @@ -7,6 +8,7 @@ namespace Avalonia.Platform /// /// Provides platform-specific services relating to threading. /// + [Unstable] public interface IPlatformThreadingInterface { void RunLoop(CancellationToken cancellationToken); diff --git a/src/Avalonia.Base/Platform/IRenderTargetBitmapImpl.cs b/src/Avalonia.Base/Platform/IRenderTargetBitmapImpl.cs index 9add07afe3..d33c503650 100644 --- a/src/Avalonia.Base/Platform/IRenderTargetBitmapImpl.cs +++ b/src/Avalonia.Base/Platform/IRenderTargetBitmapImpl.cs @@ -1,3 +1,4 @@ +using Avalonia.Metadata; namespace Avalonia.Platform { @@ -5,6 +6,7 @@ namespace Avalonia.Platform /// Defines the platform-specific interface for a /// . /// + [Unstable] public interface IRenderTargetBitmapImpl : IBitmapImpl, IRenderTarget { } diff --git a/src/Avalonia.Base/Platform/IRuntimePlatform.cs b/src/Avalonia.Base/Platform/IRuntimePlatform.cs index 850757a1ee..8ab04f5995 100644 --- a/src/Avalonia.Base/Platform/IRuntimePlatform.cs +++ b/src/Avalonia.Base/Platform/IRuntimePlatform.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IRuntimePlatform { IDisposable StartSystemTimer(TimeSpan interval, Action tick); @@ -9,6 +11,7 @@ namespace Avalonia.Platform IUnmanagedBlob AllocBlob(int size); } + [Unstable] public interface IUnmanagedBlob : IDisposable { IntPtr Address { get; } @@ -17,6 +20,7 @@ namespace Avalonia.Platform } + [Unstable] public struct RuntimePlatformInfo { public OperatingSystemType OperatingSystem { get; set; } @@ -29,6 +33,7 @@ namespace Avalonia.Platform public bool IsUnix { get; set; } } + [Unstable] public enum OperatingSystemType { Unknown, diff --git a/src/Avalonia.Base/Platform/IStreamGeometryContextImpl.cs b/src/Avalonia.Base/Platform/IStreamGeometryContextImpl.cs index 4587979308..3d5ee36608 100644 --- a/src/Avalonia.Base/Platform/IStreamGeometryContextImpl.cs +++ b/src/Avalonia.Base/Platform/IStreamGeometryContextImpl.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Platform { /// /// Describes a geometry using drawing commands. /// + [Unstable] public interface IStreamGeometryContextImpl : IGeometryContext { } diff --git a/src/Avalonia.Base/Platform/IStreamGeometryImpl.cs b/src/Avalonia.Base/Platform/IStreamGeometryImpl.cs index 5b070fde02..bd4411f3a4 100644 --- a/src/Avalonia.Base/Platform/IStreamGeometryImpl.cs +++ b/src/Avalonia.Base/Platform/IStreamGeometryImpl.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Platform { /// /// Defines the platform-specific interface for a . /// + [Unstable] public interface IStreamGeometryImpl : IGeometryImpl { /// diff --git a/src/Avalonia.Base/Platform/ITextShaperImpl.cs b/src/Avalonia.Base/Platform/ITextShaperImpl.cs index 11be9e3f09..10e58b7d0b 100644 --- a/src/Avalonia.Base/Platform/ITextShaperImpl.cs +++ b/src/Avalonia.Base/Platform/ITextShaperImpl.cs @@ -1,4 +1,5 @@ using Avalonia.Media.TextFormatting; +using Avalonia.Metadata; using Avalonia.Utilities; namespace Avalonia.Platform @@ -6,6 +7,7 @@ namespace Avalonia.Platform /// /// An abstraction that is used produce shaped text. /// + [Unstable] public interface ITextShaperImpl { /// diff --git a/src/Avalonia.Base/Platform/ITransformedGeometryImpl.cs b/src/Avalonia.Base/Platform/ITransformedGeometryImpl.cs index 1ed025b571..2754414cd1 100644 --- a/src/Avalonia.Base/Platform/ITransformedGeometryImpl.cs +++ b/src/Avalonia.Base/Platform/ITransformedGeometryImpl.cs @@ -1,4 +1,6 @@ -namespace Avalonia.Platform +using Avalonia.Metadata; + +namespace Avalonia.Platform { /// /// Represents a geometry with a transform applied. @@ -7,6 +9,7 @@ /// An transforms a geometry without transforming its /// stroke thickness. /// + [Unstable] public interface ITransformedGeometryImpl : IGeometryImpl { /// diff --git a/src/Avalonia.Base/Platform/IWriteableBitmapImpl.cs b/src/Avalonia.Base/Platform/IWriteableBitmapImpl.cs index c4e2e4915f..fa1e1862b7 100644 --- a/src/Avalonia.Base/Platform/IWriteableBitmapImpl.cs +++ b/src/Avalonia.Base/Platform/IWriteableBitmapImpl.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Platform +using Avalonia.Metadata; + +namespace Avalonia.Platform { /// /// Defines the platform-specific interface for a . /// + [Unstable] public interface IWriteableBitmapImpl : IBitmapImpl { ILockedFramebuffer Lock(); diff --git a/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs b/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs index 8124ce6bc4..9389ebc703 100644 --- a/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs +++ b/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Platform.Interop { + [Unstable] public interface IDynamicLibraryLoader { IntPtr LoadLibrary(string dll); diff --git a/src/Avalonia.Base/Rendering/IDeferredRendererLock.cs b/src/Avalonia.Base/Rendering/IDeferredRendererLock.cs index eab3dca58e..1c6bd69158 100644 --- a/src/Avalonia.Base/Rendering/IDeferredRendererLock.cs +++ b/src/Avalonia.Base/Rendering/IDeferredRendererLock.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Rendering { + [Unstable] public interface IDeferredRendererLock { IDisposable? TryLock(); diff --git a/src/Avalonia.Base/Rendering/IRenderLoop.cs b/src/Avalonia.Base/Rendering/IRenderLoop.cs index dd7442e7f8..9838967261 100644 --- a/src/Avalonia.Base/Rendering/IRenderLoop.cs +++ b/src/Avalonia.Base/Rendering/IRenderLoop.cs @@ -1,4 +1,6 @@ -namespace Avalonia.Rendering +using Avalonia.Metadata; + +namespace Avalonia.Rendering { /// /// The application render loop. @@ -7,6 +9,7 @@ /// The render loop is responsible for advancing the animation timer and updating the scene /// graph for visible windows. /// + [NotClientImplementable] public interface IRenderLoop { /// diff --git a/src/Avalonia.Base/Rendering/IRenderRoot.cs b/src/Avalonia.Base/Rendering/IRenderRoot.cs index 54e58bf39c..1aa44158b2 100644 --- a/src/Avalonia.Base/Rendering/IRenderRoot.cs +++ b/src/Avalonia.Base/Rendering/IRenderRoot.cs @@ -1,3 +1,4 @@ +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.VisualTree; @@ -6,6 +7,7 @@ namespace Avalonia.Rendering /// /// Represents the root of a renderable tree. /// + [NotClientImplementable] public interface IRenderRoot : IVisual { /// diff --git a/src/Avalonia.Base/Rendering/IRenderTimer.cs b/src/Avalonia.Base/Rendering/IRenderTimer.cs index d333e928a0..ee74c345be 100644 --- a/src/Avalonia.Base/Rendering/IRenderTimer.cs +++ b/src/Avalonia.Base/Rendering/IRenderTimer.cs @@ -1,11 +1,13 @@ using System; using System.Threading.Tasks; +using Avalonia.Metadata; namespace Avalonia.Rendering { /// /// Defines the interface implemented by an application render timer. /// + [NotClientImplementable] public interface IRenderTimer { /// diff --git a/src/Avalonia.Base/Rendering/IVisualBrushInitialize.cs b/src/Avalonia.Base/Rendering/IVisualBrushInitialize.cs index 00449c5344..b5ab8ed0bd 100644 --- a/src/Avalonia.Base/Rendering/IVisualBrushInitialize.cs +++ b/src/Avalonia.Base/Rendering/IVisualBrushInitialize.cs @@ -1,4 +1,5 @@ using Avalonia.Media; +using Avalonia.Metadata; namespace Avalonia.Rendering { @@ -6,6 +7,7 @@ namespace Avalonia.Rendering /// Internal interface for initializing controls that are to be used as the visual in a /// . /// + [Unstable] public interface IVisualBrushInitialize { /// diff --git a/src/Avalonia.Base/Rendering/IVisualBrushRenderer.cs b/src/Avalonia.Base/Rendering/IVisualBrushRenderer.cs index 1cd6515635..f5312ad39b 100644 --- a/src/Avalonia.Base/Rendering/IVisualBrushRenderer.cs +++ b/src/Avalonia.Base/Rendering/IVisualBrushRenderer.cs @@ -1,4 +1,5 @@ using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.Platform; namespace Avalonia.Rendering @@ -6,6 +7,7 @@ namespace Avalonia.Rendering /// /// Defines a renderer used to render a visual brush to a bitmap. /// + [Unstable] public interface IVisualBrushRenderer { /// diff --git a/src/Avalonia.Base/Styling/Activators/IStyleActivator.cs b/src/Avalonia.Base/Styling/Activators/IStyleActivator.cs index 479100ed8a..ac7b8b3ef1 100644 --- a/src/Avalonia.Base/Styling/Activators/IStyleActivator.cs +++ b/src/Avalonia.Base/Styling/Activators/IStyleActivator.cs @@ -1,6 +1,5 @@ -#nullable enable - -using System; +using System; +using Avalonia.Metadata; namespace Avalonia.Styling.Activators { @@ -16,6 +15,7 @@ namespace Avalonia.Styling.Activators /// - The subscription can have a tag associated with it, allowing a subscriber to index /// into a list of subscriptions without having to allocate additional objects. /// + [Unstable] public interface IStyleActivator : IDisposable { /// diff --git a/src/Avalonia.Base/Styling/Activators/IStyleActivatorSink.cs b/src/Avalonia.Base/Styling/Activators/IStyleActivatorSink.cs index a1a6ef5c28..fbb18dc304 100644 --- a/src/Avalonia.Base/Styling/Activators/IStyleActivatorSink.cs +++ b/src/Avalonia.Base/Styling/Activators/IStyleActivatorSink.cs @@ -1,10 +1,11 @@ -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Styling.Activators { /// /// Receives notifications from an . /// + [Unstable] public interface IStyleActivatorSink { /// diff --git a/src/Avalonia.Base/Styling/IGlobalStyles.cs b/src/Avalonia.Base/Styling/IGlobalStyles.cs index ab24e3138c..f9667a8895 100644 --- a/src/Avalonia.Base/Styling/IGlobalStyles.cs +++ b/src/Avalonia.Base/Styling/IGlobalStyles.cs @@ -1,13 +1,13 @@ using System; using System.Collections.Generic; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Styling { /// /// Defines the style host that provides styles global to the application. /// + [NotClientImplementable] public interface IGlobalStyles : IStyleHost { /// diff --git a/src/Avalonia.Base/Styling/ISetter.cs b/src/Avalonia.Base/Styling/ISetter.cs index d588817be8..71ae5d84c0 100644 --- a/src/Avalonia.Base/Styling/ISetter.cs +++ b/src/Avalonia.Base/Styling/ISetter.cs @@ -1,12 +1,12 @@ using System; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Styling { /// /// Represents a setter for a . /// + [NotClientImplementable] public interface ISetter { /// diff --git a/src/Avalonia.Base/Styling/ISetterInstance.cs b/src/Avalonia.Base/Styling/ISetterInstance.cs index a299a87b64..e0d3137619 100644 --- a/src/Avalonia.Base/Styling/ISetterInstance.cs +++ b/src/Avalonia.Base/Styling/ISetterInstance.cs @@ -1,12 +1,12 @@ -#nullable enable - -using System; +using System; +using Avalonia.Metadata; namespace Avalonia.Styling { /// /// Represents a setter that has been instanced on a control. /// + [Unstable] public interface ISetterInstance : IDisposable { /// diff --git a/src/Avalonia.Base/Styling/IStyle.cs b/src/Avalonia.Base/Styling/IStyle.cs index 78fbe0f2b5..fe6e8319ad 100644 --- a/src/Avalonia.Base/Styling/IStyle.cs +++ b/src/Avalonia.Base/Styling/IStyle.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; -using Avalonia.Controls; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Styling { /// /// Defines the interface for styles. /// + [NotClientImplementable] public interface IStyle { /// diff --git a/src/Avalonia.Base/Styling/IStyleHost.cs b/src/Avalonia.Base/Styling/IStyleHost.cs index 360b40d9a1..2ae488825c 100644 --- a/src/Avalonia.Base/Styling/IStyleHost.cs +++ b/src/Avalonia.Base/Styling/IStyleHost.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; +using Avalonia.Metadata; #nullable enable @@ -8,6 +9,7 @@ namespace Avalonia.Styling /// /// Defines an element that has a collection. /// + [NotClientImplementable] public interface IStyleHost { /// diff --git a/src/Avalonia.Base/Styling/IStyleInstance.cs b/src/Avalonia.Base/Styling/IStyleInstance.cs index 8ddb989bc0..5b5b99097c 100644 --- a/src/Avalonia.Base/Styling/IStyleInstance.cs +++ b/src/Avalonia.Base/Styling/IStyleInstance.cs @@ -1,12 +1,12 @@ using System; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Styling { /// /// Represents a style that has been instanced on a control. /// + [Unstable] public interface IStyleInstance : IDisposable { /// diff --git a/src/Avalonia.Base/Styling/IStyleable.cs b/src/Avalonia.Base/Styling/IStyleable.cs index a3df779057..5bc972e7ab 100644 --- a/src/Avalonia.Base/Styling/IStyleable.cs +++ b/src/Avalonia.Base/Styling/IStyleable.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Avalonia.Collections; +using Avalonia.Metadata; #nullable enable @@ -9,6 +10,7 @@ namespace Avalonia.Styling /// /// Interface for styleable elements. /// + [NotClientImplementable] public interface IStyleable : IAvaloniaObject, INamed { /// diff --git a/src/Avalonia.Base/Styling/ITemplatedControl.cs b/src/Avalonia.Base/Styling/ITemplatedControl.cs index 5485babb62..68989c8a5e 100644 --- a/src/Avalonia.Base/Styling/ITemplatedControl.cs +++ b/src/Avalonia.Base/Styling/ITemplatedControl.cs @@ -1,6 +1,8 @@ +using Avalonia.Metadata; namespace Avalonia.Styling { + [NotClientImplementable] public interface ITemplatedControl : IAvaloniaObject { } diff --git a/src/Avalonia.Base/VisualTree/IVisual.cs b/src/Avalonia.Base/VisualTree/IVisual.cs index b1251618c4..3b053fab38 100644 --- a/src/Avalonia.Base/VisualTree/IVisual.cs +++ b/src/Avalonia.Base/VisualTree/IVisual.cs @@ -1,10 +1,9 @@ using System; using Avalonia.Collections; using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.Rendering; -#nullable enable - namespace Avalonia.VisualTree { /// @@ -18,6 +17,7 @@ namespace Avalonia.VisualTree /// implemented by . It should not be necessary to implement it /// anywhere else. /// + [NotClientImplementable] public interface IVisual { /// diff --git a/src/Avalonia.Controls/ApplicationLifetimes/IApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/IApplicationLifetime.cs index 9860d0cb38..b38a539d4a 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/IApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/IApplicationLifetime.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Controls.ApplicationLifetimes { + [NotClientImplementable] public interface IApplicationLifetime { diff --git a/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs index 2bd5c1238d..4b88f6b537 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using Avalonia.Metadata; namespace Avalonia.Controls.ApplicationLifetimes { /// /// Controls application lifetime in classic desktop style /// + [NotClientImplementable] public interface IClassicDesktopStyleApplicationLifetime : IControlledApplicationLifetime { /// diff --git a/src/Avalonia.Controls/ApplicationLifetimes/IControlledApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/IControlledApplicationLifetime.cs index 3f61aeb536..d7eda790df 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/IControlledApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/IControlledApplicationLifetime.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Controls.ApplicationLifetimes { + [NotClientImplementable] public interface IControlledApplicationLifetime : IApplicationLifetime { /// diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs index e25815602e..480c65e5ad 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ISingleViewApplicationLifetime.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Controls.ApplicationLifetimes { + [NotClientImplementable] public interface ISingleViewApplicationLifetime : IApplicationLifetime { Control? MainView { get; set; } diff --git a/src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs b/src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs index 45cd1d727e..64978248e5 100644 --- a/src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs +++ b/src/Avalonia.Controls/Diagnostics/IPopupHostProvider.cs @@ -1,11 +1,13 @@ using System; using Avalonia.Controls.Primitives; +using Avalonia.Metadata; namespace Avalonia.Controls.Diagnostics { /// /// Diagnostics interface to retrieve an associated . /// + [NotClientImplementable] public interface IPopupHostProvider { /// diff --git a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs index 08d559a5c1..1c7bdb9b37 100644 --- a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs +++ b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevelImpl.cs @@ -2,11 +2,13 @@ using System.Collections.Generic; using Avalonia.Input; using Avalonia.Input.Raw; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Rendering; namespace Avalonia.Controls.Embedding.Offscreen { + [Unstable] public abstract class OffscreenTopLevelImplBase : ITopLevelImpl { private double _scaling = 1; diff --git a/src/Avalonia.Controls/IContentControl.cs b/src/Avalonia.Controls/IContentControl.cs index d28b0afb25..b4d8d0f574 100644 --- a/src/Avalonia.Controls/IContentControl.cs +++ b/src/Avalonia.Controls/IContentControl.cs @@ -1,5 +1,6 @@ using Avalonia.Controls.Templates; using Avalonia.Layout; +using Avalonia.Metadata; namespace Avalonia.Controls { @@ -7,6 +8,7 @@ namespace Avalonia.Controls /// Defines a control that displays according to a /// . /// + [NotClientImplementable] public interface IContentControl : IControl { /// diff --git a/src/Avalonia.Controls/IControl.cs b/src/Avalonia.Controls/IControl.cs index b501bc15a7..3395fc1059 100644 --- a/src/Avalonia.Controls/IControl.cs +++ b/src/Avalonia.Controls/IControl.cs @@ -1,6 +1,7 @@ using Avalonia.Controls.Templates; using Avalonia.Input; using Avalonia.Layout; +using Avalonia.Metadata; using Avalonia.VisualTree; namespace Avalonia.Controls @@ -8,6 +9,7 @@ namespace Avalonia.Controls /// /// Interface for Avalonia controls. /// + [NotClientImplementable] public interface IControl : IVisual, IDataTemplateHost, ILayoutable, diff --git a/src/Avalonia.Controls/IGlobalDataTemplates.cs b/src/Avalonia.Controls/IGlobalDataTemplates.cs index 92dcd2c189..f4499ddb5e 100644 --- a/src/Avalonia.Controls/IGlobalDataTemplates.cs +++ b/src/Avalonia.Controls/IGlobalDataTemplates.cs @@ -1,10 +1,12 @@ using Avalonia.Controls.Templates; +using Avalonia.Metadata; namespace Avalonia.Controls { /// /// Defines the application-global data templates. /// + [NotClientImplementable] public interface IGlobalDataTemplates : IDataTemplateHost { } diff --git a/src/Avalonia.Controls/IMenu.cs b/src/Avalonia.Controls/IMenu.cs index 0722a22f08..d90c5ea7a8 100644 --- a/src/Avalonia.Controls/IMenu.cs +++ b/src/Avalonia.Controls/IMenu.cs @@ -1,10 +1,12 @@ using Avalonia.Controls.Platform; +using Avalonia.Metadata; namespace Avalonia.Controls { /// /// Represents a or . /// + [NotClientImplementable] public interface IMenu : IMenuElement { /// diff --git a/src/Avalonia.Controls/IMenuElement.cs b/src/Avalonia.Controls/IMenuElement.cs index a3200d2b1b..c13c20b639 100644 --- a/src/Avalonia.Controls/IMenuElement.cs +++ b/src/Avalonia.Controls/IMenuElement.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; using Avalonia.Input; +using Avalonia.Metadata; namespace Avalonia.Controls { /// /// Represents an or . /// + [NotClientImplementable] public interface IMenuElement : IControl { /// diff --git a/src/Avalonia.Controls/IMenuItem.cs b/src/Avalonia.Controls/IMenuItem.cs index 35e36eb0f4..9d7ef3c18d 100644 --- a/src/Avalonia.Controls/IMenuItem.cs +++ b/src/Avalonia.Controls/IMenuItem.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Controls +using Avalonia.Metadata; + +namespace Avalonia.Controls { /// /// Represents a . /// + [NotClientImplementable] public interface IMenuItem : IMenuElement { /// diff --git a/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs index f492e6ca0f..29963e4821 100644 --- a/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs +++ b/src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Controls { + [Unstable] public interface INativeMenuExporterEventsImplBridge { void RaiseNeedsUpdate (); diff --git a/src/Avalonia.Controls/INativeMenuItemExporterEventsImplBridge.cs b/src/Avalonia.Controls/INativeMenuItemExporterEventsImplBridge.cs index 6cb68d8ddd..a6c7489971 100644 --- a/src/Avalonia.Controls/INativeMenuItemExporterEventsImplBridge.cs +++ b/src/Avalonia.Controls/INativeMenuItemExporterEventsImplBridge.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Controls { + [Unstable] public interface INativeMenuItemExporterEventsImplBridge { void RaiseClicked (); diff --git a/src/Avalonia.Controls/IPanel.cs b/src/Avalonia.Controls/IPanel.cs index 7b9e2c2074..8f2564ec74 100644 --- a/src/Avalonia.Controls/IPanel.cs +++ b/src/Avalonia.Controls/IPanel.cs @@ -1,8 +1,11 @@ +using Avalonia.Metadata; + namespace Avalonia.Controls { /// /// Interface for controls that can contain multiple children. /// + [NotClientImplementable] public interface IPanel : IControl { /// @@ -10,4 +13,4 @@ namespace Avalonia.Controls /// Controls Children { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/IScrollable.cs b/src/Avalonia.Controls/IScrollable.cs index 2a98b3910a..680088290c 100644 --- a/src/Avalonia.Controls/IScrollable.cs +++ b/src/Avalonia.Controls/IScrollable.cs @@ -1,4 +1,3 @@ - namespace Avalonia.Controls.Primitives { /// diff --git a/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs b/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs index 977544674d..b2e6e9e80b 100644 --- a/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs +++ b/src/Avalonia.Controls/Notifications/IManagedNotificationManager.cs @@ -1,4 +1,6 @@ -namespace Avalonia.Controls.Notifications +using Avalonia.Metadata; + +namespace Avalonia.Controls.Notifications { /// /// Represents a notification manager that can show arbitrary content. @@ -9,6 +11,7 @@ /// can display arbitrary content, as opposed to notification managers which display notifications /// using the host operating system's notification mechanism. /// + [NotClientImplementable] public interface IManagedNotificationManager : INotificationManager { /// diff --git a/src/Avalonia.Controls/Notifications/INotification.cs b/src/Avalonia.Controls/Notifications/INotification.cs index fa08233097..9ccce5b2c4 100644 --- a/src/Avalonia.Controls/Notifications/INotification.cs +++ b/src/Avalonia.Controls/Notifications/INotification.cs @@ -1,10 +1,12 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Controls.Notifications { /// /// Represents a notification that can be shown in a window or by the host operating system. /// + [NotClientImplementable] public interface INotification { /// diff --git a/src/Avalonia.Controls/Notifications/INotificationManager.cs b/src/Avalonia.Controls/Notifications/INotificationManager.cs index 72fb8e6c08..5fa479f2c3 100644 --- a/src/Avalonia.Controls/Notifications/INotificationManager.cs +++ b/src/Avalonia.Controls/Notifications/INotificationManager.cs @@ -1,9 +1,12 @@ -namespace Avalonia.Controls.Notifications +using Avalonia.Metadata; + +namespace Avalonia.Controls.Notifications { /// /// Represents a notification manager that can be used to show notifications in a window or using /// the host operating system. /// + [NotClientImplementable] public interface INotificationManager { /// diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index 6e9ac537f1..abef29bbd9 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -4,6 +4,7 @@ using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Interactivity; using Avalonia.LogicalTree; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Threading; @@ -14,6 +15,7 @@ namespace Avalonia.Controls.Platform /// /// Provides the default keyboard and pointer interaction for menus. /// + [Unstable] public class DefaultMenuInteractionHandler : IMenuInteractionHandler { private readonly bool _isContextMenu; diff --git a/src/Avalonia.Controls/Platform/IApplicationPlatformEvents.cs b/src/Avalonia.Controls/Platform/IApplicationPlatformEvents.cs index a8d3a3b3ac..99bbb8b56d 100644 --- a/src/Avalonia.Controls/Platform/IApplicationPlatformEvents.cs +++ b/src/Avalonia.Controls/Platform/IApplicationPlatformEvents.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Platform { + [Unstable] public interface IApplicationPlatformEvents { void RaiseUrlsOpened(string[] urls); diff --git a/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs index dd8503f768..47b5a048b0 100644 --- a/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/IMenuInteractionHandler.cs @@ -1,8 +1,11 @@ -namespace Avalonia.Controls.Platform +using Avalonia.Metadata; + +namespace Avalonia.Controls.Platform { /// /// Handles user interaction for menus. /// + [Unstable] public interface IMenuInteractionHandler { /// diff --git a/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs b/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs index 6e10163175..daeb9076e6 100644 --- a/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs +++ b/src/Avalonia.Controls/Platform/IMountedVolumeInfoProvider.cs @@ -1,13 +1,13 @@ using System; using System.Collections.ObjectModel; -using System.Threading.Tasks; -using Avalonia.Platform; +using Avalonia.Metadata; namespace Avalonia.Controls.Platform { /// /// Defines a platform-specific mount volumes info provider implementation. /// + [Unstable] public interface IMountedVolumeInfoProvider { /// diff --git a/src/Avalonia.Controls/Platform/INativeControlHostImpl.cs b/src/Avalonia.Controls/Platform/INativeControlHostImpl.cs index df13613848..ffa79aa8d6 100644 --- a/src/Avalonia.Controls/Platform/INativeControlHostImpl.cs +++ b/src/Avalonia.Controls/Platform/INativeControlHostImpl.cs @@ -1,10 +1,11 @@ using System; using System.Diagnostics.CodeAnalysis; +using Avalonia.Metadata; using Avalonia.Platform; -using Avalonia.VisualTree; namespace Avalonia.Controls.Platform { + [Unstable] public interface INativeControlHostImpl { INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHandle parent); @@ -13,11 +14,13 @@ namespace Avalonia.Controls.Platform bool IsCompatibleWith(IPlatformHandle handle); } + [Unstable] public interface INativeControlHostDestroyableControlHandle : IPlatformHandle { void Destroy(); } + [Unstable] public interface INativeControlHostControlTopLevelAttachment : IDisposable { INativeControlHostImpl? AttachedTo { get; set; } @@ -27,6 +30,7 @@ namespace Avalonia.Controls.Platform void ShowInBounds(Rect rect); } + [Unstable] public interface ITopLevelImplWithNativeControlHost { INativeControlHostImpl? NativeControlHost { get; } diff --git a/src/Avalonia.Controls/Platform/IPlatformIconLoader.cs b/src/Avalonia.Controls/Platform/IPlatformIconLoader.cs index ecbc6d2234..4c844ce30f 100644 --- a/src/Avalonia.Controls/Platform/IPlatformIconLoader.cs +++ b/src/Avalonia.Controls/Platform/IPlatformIconLoader.cs @@ -1,7 +1,9 @@ using System.IO; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IPlatformIconLoader { IWindowIconImpl LoadIcon(string fileName); diff --git a/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs b/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs index 4cd6640453..0658f9211c 100644 --- a/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs +++ b/src/Avalonia.Controls/Platform/IPlatformLifetimeEventsImpl.cs @@ -1,9 +1,10 @@ using System; -using System.ComponentModel; using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IPlatformLifetimeEventsImpl { /// diff --git a/src/Avalonia.Controls/Platform/IPlatformNativeSurfaceHandle.cs b/src/Avalonia.Controls/Platform/IPlatformNativeSurfaceHandle.cs index 264f5e4667..6ad07b1b13 100644 --- a/src/Avalonia.Controls/Platform/IPlatformNativeSurfaceHandle.cs +++ b/src/Avalonia.Controls/Platform/IPlatformNativeSurfaceHandle.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IPlatformNativeSurfaceHandle : IPlatformHandle { PixelSize Size { get; } diff --git a/src/Avalonia.Controls/Platform/IPopupImpl.cs b/src/Avalonia.Controls/Platform/IPopupImpl.cs index 477d5fab43..cd86045dee 100644 --- a/src/Avalonia.Controls/Platform/IPopupImpl.cs +++ b/src/Avalonia.Controls/Platform/IPopupImpl.cs @@ -1,10 +1,12 @@ using Avalonia.Controls.Primitives.PopupPositioning; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Defines a platform-specific popup window implementation. /// + [Unstable] public interface IPopupImpl : IWindowBaseImpl { IPopupPositioner PopupPositioner { get; } diff --git a/src/Avalonia.Controls/Platform/IScreenImpl.cs b/src/Avalonia.Controls/Platform/IScreenImpl.cs index b68391aa52..fcae3b6493 100644 --- a/src/Avalonia.Controls/Platform/IScreenImpl.cs +++ b/src/Avalonia.Controls/Platform/IScreenImpl.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; - -#nullable enable +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IScreenImpl { int ScreenCount { get; } diff --git a/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs b/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs index 1685a6a38c..715eda5cfa 100644 --- a/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs +++ b/src/Avalonia.Controls/Platform/ISystemDialogImpl.cs @@ -1,10 +1,12 @@ using System.Threading.Tasks; +using Avalonia.Metadata; namespace Avalonia.Controls.Platform { /// /// Defines a platform-specific system dialog implementation. /// + [Unstable] public interface ISystemDialogImpl { /// diff --git a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs index 80434882f7..bd0339f525 100644 --- a/src/Avalonia.Controls/Platform/ITopLevelImpl.cs +++ b/src/Avalonia.Controls/Platform/ITopLevelImpl.cs @@ -4,6 +4,7 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Layout; +using Avalonia.Metadata; using Avalonia.Rendering; using JetBrains.Annotations; @@ -50,6 +51,7 @@ namespace Avalonia.Platform /// This interface is the common interface to and /// . /// + [Unstable] public interface ITopLevelImpl : IDisposable { /// diff --git a/src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs b/src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs index bafb973765..a2e426ca08 100644 --- a/src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs +++ b/src/Avalonia.Controls/Platform/ITopLevelImplWithTextInputMethod.cs @@ -1,9 +1,11 @@ using Avalonia.Input; using Avalonia.Input.TextInput; +using Avalonia.Metadata; using Avalonia.Platform; namespace Avalonia.Controls.Platform { + [Unstable] public interface ITopLevelImplWithTextInputMethod : ITopLevelImpl { public ITextInputMethodImpl? TextInputMethod { get; } diff --git a/src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs b/src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs index 9e72a40439..149a978c54 100644 --- a/src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs +++ b/src/Avalonia.Controls/Platform/ITopLevelNativeMenuExporter.cs @@ -1,13 +1,16 @@ using System; +using Avalonia.Metadata; using Avalonia.Platform; namespace Avalonia.Controls.Platform { + [Unstable] public interface INativeMenuExporter { void SetNativeMenu(NativeMenu? menu); } + [Unstable] public interface ITopLevelNativeMenuExporter : INativeMenuExporter { bool IsNativeMenuExported { get; } @@ -15,11 +18,13 @@ namespace Avalonia.Controls.Platform event EventHandler OnIsNativeMenuExportedChanged; } + [Unstable] public interface INativeMenuExporterProvider { INativeMenuExporter? NativeMenuExporter { get; } } - + + [Unstable] public interface ITopLevelImplWithNativeMenuExporter : ITopLevelImpl { ITopLevelNativeMenuExporter? NativeMenuExporter { get; } diff --git a/src/Avalonia.Controls/Platform/ITrayIconImpl.cs b/src/Avalonia.Controls/Platform/ITrayIconImpl.cs index 289b569645..4ef9397d04 100644 --- a/src/Avalonia.Controls/Platform/ITrayIconImpl.cs +++ b/src/Avalonia.Controls/Platform/ITrayIconImpl.cs @@ -1,8 +1,10 @@ using System; using Avalonia.Controls.Platform; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface ITrayIconImpl : IDisposable { /// diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs index 066f4579c0..512fad6dfc 100644 --- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs @@ -1,8 +1,10 @@ using System; using Avalonia.Automation.Peers; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IWindowBaseImpl : ITopLevelImpl { /// diff --git a/src/Avalonia.Controls/Platform/IWindowIconImpl.cs b/src/Avalonia.Controls/Platform/IWindowIconImpl.cs index 7086b7651c..4bb8844d97 100644 --- a/src/Avalonia.Controls/Platform/IWindowIconImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowIconImpl.cs @@ -1,7 +1,9 @@ using System.IO; +using Avalonia.Metadata; namespace Avalonia.Platform { + [Unstable] public interface IWindowIconImpl { void Save(Stream outputStream); diff --git a/src/Avalonia.Controls/Platform/IWindowImpl.cs b/src/Avalonia.Controls/Platform/IWindowImpl.cs index d4be4f9f45..af9392d440 100644 --- a/src/Avalonia.Controls/Platform/IWindowImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowImpl.cs @@ -1,12 +1,14 @@ using System; using Avalonia.Controls; using Avalonia.Input; +using Avalonia.Metadata; namespace Avalonia.Platform { /// /// Defines a platform-specific window implementation. /// + [Unstable] public interface IWindowImpl : IWindowBaseImpl { /// diff --git a/src/Avalonia.Controls/Platform/IWindowingPlatform.cs b/src/Avalonia.Controls/Platform/IWindowingPlatform.cs index fa26fe8fdd..5acc5adccd 100644 --- a/src/Avalonia.Controls/Platform/IWindowingPlatform.cs +++ b/src/Avalonia.Controls/Platform/IWindowingPlatform.cs @@ -1,5 +1,8 @@ +using Avalonia.Metadata; + namespace Avalonia.Platform { + [Unstable] public interface IWindowingPlatform { IWindowImpl CreateWindow(); diff --git a/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs b/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs index 4e5908456e..630d2d8efb 100644 --- a/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs +++ b/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs @@ -1,14 +1,13 @@ using System; -using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; -using System.Threading.Tasks; +using Avalonia.Metadata; using Avalonia.Platform; -using Avalonia.Rendering; using Avalonia.Threading; namespace Avalonia.Controls.Platform { + [Unstable] public class InternalPlatformThreadingInterface : IPlatformThreadingInterface { public InternalPlatformThreadingInterface() diff --git a/src/Avalonia.Controls/Platform/MountedDriveInfo.cs b/src/Avalonia.Controls/Platform/MountedDriveInfo.cs index f3104e4360..620ac9303f 100644 --- a/src/Avalonia.Controls/Platform/MountedDriveInfo.cs +++ b/src/Avalonia.Controls/Platform/MountedDriveInfo.cs @@ -1,10 +1,12 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Controls.Platform { /// /// Describes a Drive's properties. /// + [Unstable] public class MountedVolumeInfo : IEquatable { public string? VolumeLabel { get; set; } diff --git a/src/Avalonia.Controls/Platform/PlatformManager.cs b/src/Avalonia.Controls/Platform/PlatformManager.cs index ee62316922..92f6f1cb52 100644 --- a/src/Avalonia.Controls/Platform/PlatformManager.cs +++ b/src/Avalonia.Controls/Platform/PlatformManager.cs @@ -1,9 +1,11 @@ using System; using System.Reactive.Disposables; +using Avalonia.Metadata; using Avalonia.Platform; namespace Avalonia.Controls.Platform { + [Unstable] public static partial class PlatformManager { static bool s_designerMode; diff --git a/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs b/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs index 62cd012d51..0a7daeaa24 100644 --- a/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs +++ b/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs @@ -1,7 +1,9 @@ -using Avalonia.Platform; +using Avalonia.Metadata; +using Avalonia.Platform; namespace Avalonia.Controls.Platform.Surfaces { + [Unstable] public interface IFramebufferPlatformSurface { /// diff --git a/src/Avalonia.Controls/Presenters/IContentPresenter.cs b/src/Avalonia.Controls/Presenters/IContentPresenter.cs index ab4d61e3bd..673de4700b 100644 --- a/src/Avalonia.Controls/Presenters/IContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/IContentPresenter.cs @@ -1,4 +1,5 @@ using Avalonia.Controls.Primitives; +using Avalonia.Metadata; namespace Avalonia.Controls.Presenters { @@ -6,6 +7,7 @@ namespace Avalonia.Controls.Presenters /// Interface for controls that present a single item of data inside a /// template. /// + [NotClientImplementable] public interface IContentPresenter : IPresenter { /// diff --git a/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs b/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs index 78c4affe44..562638e94a 100644 --- a/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs +++ b/src/Avalonia.Controls/Presenters/IContentPresenterHost.cs @@ -1,5 +1,6 @@ using Avalonia.Collections; using Avalonia.LogicalTree; +using Avalonia.Metadata; using Avalonia.Styling; namespace Avalonia.Controls.Presenters @@ -15,6 +16,7 @@ namespace Avalonia.Controls.Presenters /// parent control's template is instantiated so they register themselves using this /// interface. /// + [NotClientImplementable] public interface IContentPresenterHost : ITemplatedControl { /// diff --git a/src/Avalonia.Controls/Presenters/IItemsPresenter.cs b/src/Avalonia.Controls/Presenters/IItemsPresenter.cs index e7da3d4618..7cc72ef0a7 100644 --- a/src/Avalonia.Controls/Presenters/IItemsPresenter.cs +++ b/src/Avalonia.Controls/Presenters/IItemsPresenter.cs @@ -1,8 +1,10 @@ using System.Collections; using System.Collections.Specialized; +using Avalonia.Metadata; namespace Avalonia.Controls.Presenters { + [NotClientImplementable] public interface IItemsPresenter : IPresenter { IEnumerable? Items { get; set; } diff --git a/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs b/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs index ba9ee0fe31..db11474871 100644 --- a/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs +++ b/src/Avalonia.Controls/Presenters/IItemsPresenterHost.cs @@ -1,3 +1,4 @@ +using Avalonia.Metadata; using Avalonia.Styling; namespace Avalonia.Controls.Presenters @@ -13,6 +14,7 @@ namespace Avalonia.Controls.Presenters /// parent control's template is instantiated so they register themselves using this /// interface. /// + [NotClientImplementable] public interface IItemsPresenterHost : ITemplatedControl { /// diff --git a/src/Avalonia.Controls/Presenters/IPresenter.cs b/src/Avalonia.Controls/Presenters/IPresenter.cs index 5318ea2757..0399983189 100644 --- a/src/Avalonia.Controls/Presenters/IPresenter.cs +++ b/src/Avalonia.Controls/Presenters/IPresenter.cs @@ -1,4 +1,5 @@ using Avalonia.Controls.Primitives; +using Avalonia.Metadata; namespace Avalonia.Controls.Presenters { @@ -12,6 +13,7 @@ namespace Avalonia.Controls.Presenters /// of a then that signals that the visual child /// of the presenter is not a part of the template. /// + [NotClientImplementable] public interface IPresenter : IControl, INamed { } diff --git a/src/Avalonia.Controls/Primitives/IPopupHost.cs b/src/Avalonia.Controls/Primitives/IPopupHost.cs index 36d2ae9230..99b7be6385 100644 --- a/src/Avalonia.Controls/Primitives/IPopupHost.cs +++ b/src/Avalonia.Controls/Primitives/IPopupHost.cs @@ -2,6 +2,7 @@ using System; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives.PopupPositioning; using Avalonia.Input; +using Avalonia.Metadata; using Avalonia.VisualTree; namespace Avalonia.Controls.Primitives @@ -14,6 +15,7 @@ namespace Avalonia.Controls.Primitives /// () or an which is created /// on an . /// + [NotClientImplementable] public interface IPopupHost : IDisposable, IFocusScope { /// diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs index 8daf1ac68a..8d35a91e00 100644 --- a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs +++ b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs @@ -45,6 +45,7 @@ Copyright © 2019 Nikita Tsukanov */ using System; +using Avalonia.Metadata; using Avalonia.VisualTree; using Avalonia.Media; @@ -61,6 +62,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning /// requirement that a popup must intersect with or be at least partially adjacent to its parent /// surface. /// + [Unstable] public struct PopupPositionerParameters { private PopupGravity _gravity; @@ -429,6 +431,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning /// managed implementation is provided in for platforms /// on which popups can be arbitrarily positioned. /// + [NotClientImplementable] public interface IPopupPositioner { /// @@ -439,6 +442,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning void Update(PopupPositionerParameters parameters); } + [Unstable] static class PopupPositionerExtensions { public static void ConfigurePosition(ref this PopupPositionerParameters positionerParameters, diff --git a/src/Avalonia.Controls/Remote/RemoteServer.cs b/src/Avalonia.Controls/Remote/RemoteServer.cs index f4cc91a0e6..2cf2d2b97d 100644 --- a/src/Avalonia.Controls/Remote/RemoteServer.cs +++ b/src/Avalonia.Controls/Remote/RemoteServer.cs @@ -1,11 +1,12 @@ using System; using Avalonia.Controls.Embedding; using Avalonia.Controls.Remote.Server; -using Avalonia.Platform; +using Avalonia.Metadata; using Avalonia.Remote.Protocol; namespace Avalonia.Controls.Remote { + [Unstable] public class RemoteServer { private EmbeddableControlRoot _topLevel; diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index c9fd1dc3b8..e800f2f4b0 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -6,6 +6,7 @@ using Avalonia.Controls.Platform.Surfaces; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Layout; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Remote.Protocol; using Avalonia.Remote.Protocol.Input; @@ -18,6 +19,7 @@ using ProtocolPixelFormat = Avalonia.Remote.Protocol.Viewport.PixelFormat; namespace Avalonia.Controls.Remote.Server { + [Unstable] public class RemoteServerTopLevelImpl : OffscreenTopLevelImplBase, IFramebufferPlatformSurface { private readonly IAvaloniaRemoteTransportConnection _transport; diff --git a/src/Avalonia.Controls/Templates/IDataTemplateHost.cs b/src/Avalonia.Controls/Templates/IDataTemplateHost.cs index 61986a0661..ce763c3336 100644 --- a/src/Avalonia.Controls/Templates/IDataTemplateHost.cs +++ b/src/Avalonia.Controls/Templates/IDataTemplateHost.cs @@ -1,9 +1,11 @@ - +using Avalonia.Metadata; + namespace Avalonia.Controls.Templates { /// /// Defines an element that has a collection. /// + [NotClientImplementable] public interface IDataTemplateHost { /// diff --git a/src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs b/src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs index aef4f601be..22f0cebf57 100644 --- a/src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs +++ b/src/Avalonia.OpenGL/Imaging/IOpenGlBitmapImpl.cs @@ -1,15 +1,17 @@ using System; -using Avalonia.Media.Imaging; +using Avalonia.Metadata; using Avalonia.Platform; namespace Avalonia.OpenGL.Imaging { + [Unstable] public interface IOpenGlBitmapImpl : IBitmapImpl { IOpenGlBitmapAttachment CreateFramebufferAttachment(IGlContext context, Action presentCallback); bool SupportsContext(IGlContext context); } + [Unstable] public interface IOpenGlBitmapAttachment : IDisposable { void Present(); diff --git a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs index f59a0a32c2..bdc3d075cf 100644 --- a/src/Skia/Avalonia.Skia/GlyphRunImpl.cs +++ b/src/Skia/Avalonia.Skia/GlyphRunImpl.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Metadata; using Avalonia.Platform; using JetBrains.Annotations; using SkiaSharp; @@ -6,6 +7,7 @@ using SkiaSharp; namespace Avalonia.Skia { /// + [Unstable] public class GlyphRunImpl : IGlyphRunImpl { public GlyphRunImpl([NotNull] SKTextBlob textBlob) diff --git a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs index 5b6e5af60f..dcb4eac7ca 100644 --- a/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs +++ b/src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs @@ -1,11 +1,13 @@ using System; using System.Runtime.InteropServices; +using Avalonia.Metadata; using Avalonia.Platform; using HarfBuzzSharp; using SkiaSharp; namespace Avalonia.Skia { + [Unstable] public class GlyphTypefaceImpl : IGlyphTypefaceImpl { private bool _isDisposed; diff --git a/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs index 38fa5a5253..1391a8f195 100644 --- a/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/ISkiaDrawingContextImpl.cs @@ -1,8 +1,10 @@ +using Avalonia.Metadata; using Avalonia.Platform; using SkiaSharp; namespace Avalonia.Skia { + [Unstable] public interface ISkiaDrawingContextImpl : IDrawingContextImpl { SKCanvas SkCanvas { get; } diff --git a/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs index ad609a0810..602ea9b568 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/BrushImpl.cs @@ -1,7 +1,9 @@ using System; +using Avalonia.Metadata; namespace Avalonia.Direct2D1.Media { + [Unstable] public abstract class BrushImpl : IDisposable { public SharpDX.Direct2D1.Brush PlatformBrush { get; set; } diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index a259d8fab9..a0f98bbbc9 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -10,12 +10,14 @@ using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; using BitmapInterpolationMode = Avalonia.Media.Imaging.BitmapInterpolationMode; +using Avalonia.Metadata; namespace Avalonia.Direct2D1.Media { /// /// Draws using Direct2D1. /// + [Unstable] public class DrawingContextImpl : IDrawingContextImpl { private readonly IVisualBrushRenderer _visualBrushRenderer; diff --git a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs index ec88347a17..c84c14daac 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/GeometryImpl.cs @@ -1,4 +1,5 @@ using Avalonia.Logging; +using Avalonia.Metadata; using Avalonia.Platform; using SharpDX.Direct2D1; @@ -7,6 +8,7 @@ namespace Avalonia.Direct2D1.Media /// /// The platform-specific interface for . /// + [Unstable] public abstract class GeometryImpl : IGeometryImpl { private const float ContourApproximation = 0.0001f; diff --git a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs index 4f2ed22a25..4154b44702 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs @@ -1,11 +1,13 @@ using System; using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.Platform; using HarfBuzzSharp; using SharpDX.DirectWrite; namespace Avalonia.Direct2D1.Media { + [Unstable] public class GlyphTypefaceImpl : IGlyphTypefaceImpl { private bool _isDisposed; diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs index 296cefad4e..17dc359ed7 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs @@ -1,10 +1,12 @@ using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.Rendering.Utilities; using Avalonia.Utilities; using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media { + [Unstable] public sealed class ImageBrushImpl : BrushImpl { private readonly OptionalDispose _bitmap; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs index af6d5c5e7b..843efe2cc4 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs @@ -1,10 +1,12 @@ using System; using System.IO; +using Avalonia.Metadata; using Avalonia.Platform; using D2DBitmap = SharpDX.Direct2D1.Bitmap; namespace Avalonia.Direct2D1.Media { + [Unstable] public abstract class BitmapImpl : IBitmapImpl, IDisposable { public abstract Vector Dpi { get; } diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs index 63676e30b5..2656ab4c58 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Avalonia.Metadata; using SharpDX.WIC; using Bitmap = SharpDX.Direct2D1.Bitmap; @@ -8,6 +9,7 @@ namespace Avalonia.Direct2D1.Media /// /// A Direct2D Bitmap implementation that uses a GPU memory bitmap as its image. /// + [Unstable] public class D2DBitmapImpl : BitmapImpl { private readonly Bitmap _direct2DBitmap; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs index 9a0e2ec00c..357e472d34 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Utilities; @@ -9,6 +10,7 @@ using D2DBitmap = SharpDX.Direct2D1.Bitmap; namespace Avalonia.Direct2D1.Media.Imaging { + [Unstable] public class D2DRenderTargetBitmapImpl : D2DBitmapImpl, IDrawingContextLayerImpl, ILayerFactory { private readonly BitmapRenderTarget _renderTarget; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs index df07f7f39c..1156246b29 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -5,12 +5,14 @@ using SharpDX.WIC; using APixelFormat = Avalonia.Platform.PixelFormat; using AlphaFormat = Avalonia.Platform.AlphaFormat; using D2DBitmap = SharpDX.Direct2D1.Bitmap; +using Avalonia.Metadata; namespace Avalonia.Direct2D1.Media { /// /// A WIC implementation of a . /// + [Unstable] public class WicBitmapImpl : BitmapImpl { private readonly BitmapDecoder _decoder; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs index 1265a7bdf0..8c9d01f37d 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicRenderTargetBitmapImpl.cs @@ -1,10 +1,12 @@ using System; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Rendering; using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media { + [Unstable] public class WicRenderTargetBitmapImpl : WicBitmapImpl, IDrawingContextLayerImpl { private readonly WicRenderTarget _renderTarget; diff --git a/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs index 0e63d4cc03..5dfe683f59 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/LinearGradientBrushImpl.cs @@ -1,8 +1,10 @@ using System.Linq; using Avalonia.Media; +using Avalonia.Metadata; namespace Avalonia.Direct2D1.Media { + [Unstable] public class LinearGradientBrushImpl : BrushImpl { public LinearGradientBrushImpl( diff --git a/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs index 1fca6d4e33..0069e47001 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/RadialGradientBrushImpl.cs @@ -1,8 +1,10 @@ using System.Linq; using Avalonia.Media; +using Avalonia.Metadata; namespace Avalonia.Direct2D1.Media { + [Unstable] public class RadialGradientBrushImpl : BrushImpl { public RadialGradientBrushImpl( diff --git a/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs index fea1ca9157..b85494e2c1 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs @@ -1,7 +1,9 @@ using Avalonia.Media; +using Avalonia.Metadata; namespace Avalonia.Direct2D1.Media { + [Unstable] public class SolidColorBrushImpl : BrushImpl { public SolidColorBrushImpl(ISolidColorBrush brush, SharpDX.Direct2D1.RenderTarget target) diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs index e1f7aad1b2..ec8f82556d 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryContextImpl.cs @@ -1,6 +1,7 @@ using System; using Avalonia.Logging; using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.Platform; using SharpDX.Direct2D1; using D2D = SharpDX.Direct2D1; @@ -8,6 +9,7 @@ using SweepDirection = SharpDX.Direct2D1.SweepDirection; namespace Avalonia.Direct2D1.Media { + [Unstable] public class StreamGeometryContextImpl : IStreamGeometryContextImpl { private readonly GeometrySink _sink; diff --git a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs index 2bc2b2db71..e1677c0ed1 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/StreamGeometryImpl.cs @@ -1,3 +1,4 @@ +using Avalonia.Metadata; using Avalonia.Platform; using SharpDX.Direct2D1; @@ -6,6 +7,7 @@ namespace Avalonia.Direct2D1.Media /// /// A Direct2D implementation of a . /// + [Unstable] public class StreamGeometryImpl : GeometryImpl, IStreamGeometryImpl { /// diff --git a/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs index fe274701bf..3ecdb49e46 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/TransformedGeometryImpl.cs @@ -1,8 +1,10 @@ +using Avalonia.Metadata; using Avalonia.Platform; using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media { + [Unstable] public class TransformedGeometryImpl : GeometryImpl, ITransformedGeometryImpl { /// diff --git a/src/Windows/Avalonia.Win32/ScreenImpl.cs b/src/Windows/Avalonia.Win32/ScreenImpl.cs index 96e45927da..f3754cd58f 100644 --- a/src/Windows/Avalonia.Win32/ScreenImpl.cs +++ b/src/Windows/Avalonia.Win32/ScreenImpl.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Linq; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32 { + [Unstable] public class ScreenImpl : IScreenImpl { public int ScreenCount diff --git a/src/Windows/Avalonia.Win32/TrayIconImpl.cs b/src/Windows/Avalonia.Win32/TrayIconImpl.cs index 6484ae6c54..7c3b8cf2d2 100644 --- a/src/Windows/Avalonia.Win32/TrayIconImpl.cs +++ b/src/Windows/Avalonia.Win32/TrayIconImpl.cs @@ -5,6 +5,7 @@ using Avalonia.Controls; using Avalonia.Controls.Platform; using Avalonia.Controls.Primitives.PopupPositioning; using Avalonia.LogicalTree; +using Avalonia.Metadata; using Avalonia.Platform; using Avalonia.Styling; using Avalonia.Win32.Interop; @@ -14,6 +15,7 @@ using static Avalonia.Win32.Interop.UnmanagedMethods; namespace Avalonia.Win32 { + [Unstable] public class TrayIconImpl : ITrayIconImpl { private readonly int _uniqueId; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index f0036236ec..8d836ef452 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -21,12 +21,14 @@ using Avalonia.Win32.OpenGl; using Avalonia.Win32.WinRT; using Avalonia.Win32.WinRT.Composition; using static Avalonia.Win32.Interop.UnmanagedMethods; +using Avalonia.Metadata; namespace Avalonia.Win32 { /// /// Window implementation for Win32 platform. /// + [Unstable] public partial class WindowImpl : IWindowImpl, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo, ITopLevelImplWithNativeControlHost, ITopLevelImplWithTextInputMethod From 9df40a66404cd3530115dfdd403d5aebe6c2e2a4 Mon Sep 17 00:00:00 2001 From: robloo Date: Thu, 28 Apr 2022 00:54:41 -0400 Subject: [PATCH 061/332] Update code for generic virtual method changes --- .../Calendar/CalendarDatePicker.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 0126a0c075..0005e07536 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -202,7 +202,7 @@ namespace Avalonia.Controls } /// - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { // CustomDateFormatString if (change.Property == CustomDateFormatStringProperty) @@ -215,8 +215,8 @@ namespace Avalonia.Controls // IsDropDownOpen else if (change.Property == IsDropDownOpenProperty) { - var oldValue = change.OldValue.GetValueOrDefault(); - var value = change.NewValue.GetValueOrDefault(); + var oldValue = change.GetOldValue(); + var value = change.GetNewValue(); if (_popUp != null && _popUp.Child != null) { @@ -246,8 +246,8 @@ namespace Avalonia.Controls // SelectedDate else if (change.Property == SelectedDateProperty) { - var addedDate = change.NewValue.GetValueOrDefault() as DateTime?; - var removedDate = change.OldValue.GetValueOrDefault() as DateTime?; + var addedDate = change.GetNewValue(); + var removedDate = change.GetOldValue(); if (SelectedDate != null) { @@ -291,8 +291,8 @@ namespace Avalonia.Controls // Text else if (change.Property == TextProperty) { - var oldValue = change.OldValue.GetValueOrDefault() as string; - var value = change.NewValue.GetValueOrDefault() as string; + var oldValue = change.GetOldValue(); + var value = change.GetNewValue(); if (!_suspendTextChangeHandler) { @@ -332,12 +332,14 @@ namespace Avalonia.Controls } /// - protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value) + protected override void UpdateDataValidation(AvaloniaProperty property, BindingValueType state, Exception? error) { if (property == SelectedDateProperty) { DataValidationErrors.SetError(this, error); } + + base.UpdateDataValidation(property, state, error); } /// From 17b9f246f3a2ed510a560584b589e2a170dadce2 Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Fri, 6 May 2022 21:01:07 +0200 Subject: [PATCH 062/332] Text hit testing fixes --- .../Media/TextFormatting/TextLineImpl.cs | 15 ++++-- .../Media/TextFormatting/TextShaperOptions.cs | 4 +- .../Presenters/TextPresenter.cs | 5 -- src/Avalonia.Controls/TextBlock.cs | 6 ++- .../HeadlessPlatformStubs.cs | 2 +- src/Skia/Avalonia.Skia/TextShaperImpl.cs | 2 +- .../Media/TextShaperImpl.cs | 2 +- .../Media/TextFormatting/TextLineTests.cs | 50 ++++++++++++------- .../HarfBuzzTextShaperImpl.cs | 2 +- .../Avalonia.UnitTests/MockTextShaperImpl.cs | 2 +- 10 files changed, 55 insertions(+), 35 deletions(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index 73ec055bbe..26e73cdf3b 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -407,6 +407,7 @@ namespace Avalonia.Media.TextFormatting var currentPosition = FirstTextSourceIndex; var currentRect = Rect.Empty; var startX = Start; + var runStart = startX; //A portion of the line is covered. for (var index = 0; index < TextRuns.Count; index++) @@ -431,7 +432,7 @@ namespace Avalonia.Media.TextFormatting { case ShapedTextCharacters when currentRun is ShapedTextCharacters: { - if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End) + if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End && _flowDirection == FlowDirection.LeftToRight) { goto skip; } @@ -480,7 +481,7 @@ namespace Avalonia.Media.TextFormatting case ShapedTextCharacters shapedRun: { endOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit( - shapedRun.ShapedBuffer.IsLeftToRight ? + shapedRun.ShapedBuffer.IsLeftToRight ? new CharacterHit(firstTextSourceCharacterIndex + textLength) : new CharacterHit(firstTextSourceCharacterIndex)); @@ -493,7 +494,7 @@ namespace Avalonia.Media.TextFormatting startX += startOffset; - var characterHit = shapedRun.GlyphRun.IsLeftToRight ? + var characterHit = _flowDirection == FlowDirection.LeftToRight ? shapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _) : shapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); @@ -580,6 +581,11 @@ namespace Avalonia.Media.TextFormatting { break; } + + if (_flowDirection == FlowDirection.RightToLeft) + { + endX += currentRun.Size.Width - endOffset; + } } else { @@ -591,8 +597,9 @@ namespace Avalonia.Media.TextFormatting endX += currentRun.Size.Width - endOffset; } - lastDirection = currentDirection; startX = endX; + lastDirection = currentDirection; + runStart += currentRun.Size.Width; } return result; diff --git a/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs b/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs index a7fe92dc9a..4e75bb921e 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextShaperOptions.cs @@ -16,7 +16,7 @@ namespace Avalonia.Media.TextFormatting { Typeface = typeface; FontRenderingEmSize = fontRenderingEmSize; - BidLevel = bidiLevel; + BidiLevel = bidiLevel; Culture = culture; IncrementalTabWidth = incrementalTabWidth; } @@ -33,7 +33,7 @@ namespace Avalonia.Media.TextFormatting /// /// Get the bidi level of the text. /// - public sbyte BidLevel { get; } + public sbyte BidiLevel { get; } /// /// Get the culture. diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs index 0785149a73..62ea05c68c 100644 --- a/src/Avalonia.Controls/Presenters/TextPresenter.cs +++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs @@ -515,11 +515,6 @@ namespace Avalonia.Controls.Presenters protected override Size MeasureOverride(Size availableSize) { - if (string.IsNullOrEmpty(Text)) - { - return new Size(); - } - _constraint = availableSize; _textLayout = null; diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index bbe6aeb7ee..1a69d1218c 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -631,7 +631,11 @@ namespace Avalonia.Controls return finalSize; } - _constraint = new Size(finalSize.Width, double.PositiveInfinity); + var scale = LayoutHelper.GetLayoutScale(this); + + var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale); + + _constraint = new Size(finalSize.Deflate(padding).Width, double.PositiveInfinity); _textLayout = null; diff --git a/src/Avalonia.Headless/HeadlessPlatformStubs.cs b/src/Avalonia.Headless/HeadlessPlatformStubs.cs index 083b16c107..22ff8e8f97 100644 --- a/src/Avalonia.Headless/HeadlessPlatformStubs.cs +++ b/src/Avalonia.Headless/HeadlessPlatformStubs.cs @@ -137,7 +137,7 @@ namespace Avalonia.Headless { var typeface = options.Typeface; var fontRenderingEmSize = options.FontRenderingEmSize; - var bidiLevel = options.BidLevel; + var bidiLevel = options.BidiLevel; return new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel); } diff --git a/src/Skia/Avalonia.Skia/TextShaperImpl.cs b/src/Skia/Avalonia.Skia/TextShaperImpl.cs index 908b0ffa47..777e907617 100644 --- a/src/Skia/Avalonia.Skia/TextShaperImpl.cs +++ b/src/Skia/Avalonia.Skia/TextShaperImpl.cs @@ -16,7 +16,7 @@ namespace Avalonia.Skia { var typeface = options.Typeface; var fontRenderingEmSize = options.FontRenderingEmSize; - var bidiLevel = options.BidLevel; + var bidiLevel = options.BidiLevel; var culture = options.Culture; using (var buffer = new Buffer()) diff --git a/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs index f4e4b00147..6e32d32913 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/TextShaperImpl.cs @@ -16,7 +16,7 @@ namespace Avalonia.Direct2D1.Media { var typeface = options.Typeface; var fontRenderingEmSize = options.FontRenderingEmSize; - var bidiLevel = options.BidLevel; + var bidiLevel = options.BidiLevel; var culture = options.Culture; using (var buffer = new Buffer()) diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index a47638d2ec..f29dddf86b 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs @@ -718,31 +718,45 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting using (Start()) { var defaultProperties = new GenericTextRunProperties(Typeface.Default); - var text = "0123".AsMemory(); - var ltrOptions = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 0, CultureInfo.CurrentCulture); - var rtlOptions = new TextShaperOptions(Typeface.Default.GlyphTypeface, 10, 1, CultureInfo.CurrentCulture); - - var textRuns = new List - { - new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text), ltrOptions), defaultProperties), - new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text, text.Length, text.Length), ltrOptions), defaultProperties), - new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text, text.Length * 2, text.Length), rtlOptions), defaultProperties), - new ShapedTextCharacters(TextShaper.Current.ShapeText(new ReadOnlySlice(text, text.Length * 3, text.Length), ltrOptions), defaultProperties) - }; - - - var textSource = new FixedRunsTextSource(textRuns); + var text = "אאא AAA"; + var textSource = new SingleBufferTextSource(text, defaultProperties); var formatter = new TextFormatterImpl(); var textLine = - formatter.FormatLine(textSource, 0, double.PositiveInfinity, - new GenericTextParagraphProperties(defaultProperties)); + formatter.FormatLine(textSource, 0, 200, + new GenericTextParagraphProperties(FlowDirection.RightToLeft, TextAlignment.Left, true, true, defaultProperties, TextWrapping.NoWrap, 0, 0)); - var textBounds = textLine.GetTextBounds(0, text.Length * 4); + var textBounds = textLine.GetTextBounds(0, text.Length); - Assert.Equal(3, textBounds.Count); + Assert.Equal(2, textBounds.Count); Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds.Sum(x => x.Rectangle.Width)); + + textBounds = textLine.GetTextBounds(0, 4); + + var secondRun = textLine.TextRuns[1] as ShapedTextCharacters; + + Assert.Equal(1, textBounds.Count); + Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); + + textBounds = textLine.GetTextBounds(4, 3); + + var firstRun = textLine.TextRuns[0] as ShapedTextCharacters; + + Assert.Equal(1, textBounds.Count); + Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); + + textBounds = textLine.GetTextBounds(0, 5); + + Assert.Equal(2, textBounds.Count); + + Assert.Equal(7.201171875, textBounds[0].Rectangle.Width); + + Assert.Equal(textLine.Start, textBounds[0].Rectangle.Left); + + Assert.Equal(secondRun.Size.Width, textBounds[1].Rectangle.Width); + + Assert.Equal(textLine.Start + firstRun.Size.Width, textBounds[1].Rectangle.Left); } } diff --git a/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs b/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs index 5f8854b3ab..4bc30484e9 100644 --- a/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs +++ b/tests/Avalonia.UnitTests/HarfBuzzTextShaperImpl.cs @@ -15,7 +15,7 @@ namespace Avalonia.UnitTests { var typeface = options.Typeface; var fontRenderingEmSize = options.FontRenderingEmSize; - var bidiLevel = options.BidLevel; + var bidiLevel = options.BidiLevel; var culture = options.Culture; using (var buffer = new Buffer()) diff --git a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs index c4b1e6c154..7c34bd192e 100644 --- a/tests/Avalonia.UnitTests/MockTextShaperImpl.cs +++ b/tests/Avalonia.UnitTests/MockTextShaperImpl.cs @@ -11,7 +11,7 @@ namespace Avalonia.UnitTests { var typeface = options.Typeface; var fontRenderingEmSize = options.FontRenderingEmSize; - var bidiLevel = options.BidLevel; + var bidiLevel = options.BidiLevel; var shapedBuffer = new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel); From 45ed0194254fa28b7a82b25de5f381da6be147a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Sat, 7 May 2022 13:54:55 +0100 Subject: [PATCH 063/332] Respect Window MaxWidth and MaxHeight when using any SizeToContent to Auto --- src/Avalonia.Controls/Window.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index a5f99918b2..d0162bb0de 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -917,6 +917,15 @@ namespace Avalonia.Controls var constraint = clientSize; var maxAutoSize = PlatformImpl?.MaxAutoSizeHint ?? Size.Infinity; + if (MaxWidth > 0 && MaxWidth < maxAutoSize.Width) + { + maxAutoSize = maxAutoSize.WithWidth(MaxWidth); + } + if (MaxHeight > 0 && MaxHeight < maxAutoSize.Height) + { + maxAutoSize = maxAutoSize.WithHeight(MaxHeight); + } + if (sizeToContent.HasAllFlags(SizeToContent.Width)) { constraint = constraint.WithWidth(maxAutoSize.Width); From a92a49b04fb44103c0ec5506564ee7f0ab87dbfa Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 9 May 2022 22:14:35 +0300 Subject: [PATCH 064/332] Updated Rotate3DTransform to the new OnPropertyChanged --- src/Avalonia.Base/Rotate3DTransform.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Rotate3DTransform.cs b/src/Avalonia.Base/Rotate3DTransform.cs index 306363ec39..2c4e515861 100644 --- a/src/Avalonia.Base/Rotate3DTransform.cs +++ b/src/Avalonia.Base/Rotate3DTransform.cs @@ -203,7 +203,7 @@ public class Rotate3DTransform : Transform } } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { if (!_isInitializing) RaiseChanged(); } From c175ef318ea68a5a9e84ea7ff6140119f66627c0 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 10 May 2022 00:26:27 -0400 Subject: [PATCH 065/332] Restructure native embed sample project --- Avalonia.sln | 27 ++++ .../NativeEmbedSample.Desktop.csproj | 15 +++ .../NativeEmbedSample.Desktop/Program.cs | 17 +++ .../Android/EmbedSample.Android.cs | 50 ++++++++ .../NativeEmbedSample/{App.xaml => App.axaml} | 3 +- .../interop/NativeEmbedSample/App.axaml.cs | 23 ++++ samples/interop/NativeEmbedSample/App.xaml.cs | 22 ---- .../interop/NativeEmbedSample/EmbedSample.cs | 115 ++++-------------- .../NativeEmbedSample/Gtk/EmbedSample.Gtk.cs | 41 +++++++ .../NativeEmbedSample/Gtk/GtkHelper.cs | 62 ++++++++++ .../{ => Gtk}/nodes-license.md | 0 .../NativeEmbedSample/{ => Gtk}/nodes.mp4 | Bin .../interop/NativeEmbedSample/GtkHelper.cs | 58 --------- .../NativeEmbedSample/Mac/EmbedSample.Mac.cs | 32 +++++ .../NativeEmbedSample/Mac/MacHelper.cs | 39 ++++++ .../interop/NativeEmbedSample/MacHelper.cs | 39 ------ .../interop/NativeEmbedSample/MainView.axaml | 64 ++++++++++ .../NativeEmbedSample/MainView.axaml.cs | 45 +++++++ .../NativeEmbedSample/MainWindow.axaml | 10 ++ .../NativeEmbedSample/MainWindow.axaml.cs | 17 +++ .../interop/NativeEmbedSample/MainWindow.xaml | 52 -------- .../NativeEmbedSample/MainWindow.xaml.cs | 36 ------ .../NativeEmbedSample.csproj | 24 ++-- samples/interop/NativeEmbedSample/Program.cs | 17 --- .../NativeEmbedSample/Win/EmbedSample.Win.cs | 37 ++++++ .../interop/NativeEmbedSample/Win/WinApi.cs | 75 ++++++++++++ samples/interop/NativeEmbedSample/WinApi.cs | 74 ----------- .../NativeEmbedSample/iOS/EmbedSample.iOS.cs | 65 ++++++++++ 28 files changed, 657 insertions(+), 402 deletions(-) create mode 100644 samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj create mode 100644 samples/interop/NativeEmbedSample.Desktop/Program.cs create mode 100644 samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs rename samples/interop/NativeEmbedSample/{App.xaml => App.axaml} (57%) create mode 100644 samples/interop/NativeEmbedSample/App.axaml.cs delete mode 100644 samples/interop/NativeEmbedSample/App.xaml.cs create mode 100644 samples/interop/NativeEmbedSample/Gtk/EmbedSample.Gtk.cs create mode 100644 samples/interop/NativeEmbedSample/Gtk/GtkHelper.cs rename samples/interop/NativeEmbedSample/{ => Gtk}/nodes-license.md (100%) rename samples/interop/NativeEmbedSample/{ => Gtk}/nodes.mp4 (100%) delete mode 100644 samples/interop/NativeEmbedSample/GtkHelper.cs create mode 100644 samples/interop/NativeEmbedSample/Mac/EmbedSample.Mac.cs create mode 100644 samples/interop/NativeEmbedSample/Mac/MacHelper.cs delete mode 100644 samples/interop/NativeEmbedSample/MacHelper.cs create mode 100644 samples/interop/NativeEmbedSample/MainView.axaml create mode 100644 samples/interop/NativeEmbedSample/MainView.axaml.cs create mode 100644 samples/interop/NativeEmbedSample/MainWindow.axaml create mode 100644 samples/interop/NativeEmbedSample/MainWindow.axaml.cs delete mode 100644 samples/interop/NativeEmbedSample/MainWindow.xaml delete mode 100644 samples/interop/NativeEmbedSample/MainWindow.xaml.cs delete mode 100644 samples/interop/NativeEmbedSample/Program.cs create mode 100644 samples/interop/NativeEmbedSample/Win/EmbedSample.Win.cs create mode 100644 samples/interop/NativeEmbedSample/Win/WinApi.cs delete mode 100644 samples/interop/NativeEmbedSample/WinApi.cs create mode 100644 samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs diff --git a/Avalonia.sln b/Avalonia.sln index c8e513f94c..0adc29ffe8 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -219,6 +219,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.SourceGenerator", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.Desktop", "samples\interop\NativeEmbedSample.Desktop\NativeEmbedSample.Desktop.csproj", "{F2389463-DDB4-4317-B894-D4DF9FF6B763}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -1989,6 +1991,30 @@ Global {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.Build.0 = Release|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhone.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhone.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|Any CPU.Build.0 = Release|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhone.ActiveCfg = Release|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhone.Build.0 = Release|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2048,6 +2074,7 @@ Global {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {CE910927-CE5A-456F-BC92-E4C757354A5C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} + {F2389463-DDB4-4317-B894-D4DF9FF6B763} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj b/samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj new file mode 100644 index 0000000000..1ec852ab6d --- /dev/null +++ b/samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + + + + + + + + + + diff --git a/samples/interop/NativeEmbedSample.Desktop/Program.cs b/samples/interop/NativeEmbedSample.Desktop/Program.cs new file mode 100644 index 0000000000..01684d0301 --- /dev/null +++ b/samples/interop/NativeEmbedSample.Desktop/Program.cs @@ -0,0 +1,17 @@ +using Avalonia; +using NativeEmbedSample; + +namespace NativeEmbedSample.Desktop; + +public class Program +{ + static int Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .With(new AvaloniaNativePlatformOptions() + { + }) + .UsePlatformDetect(); + +} diff --git a/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs b/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs new file mode 100644 index 0000000000..ed3b9aeeb0 --- /dev/null +++ b/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs @@ -0,0 +1,50 @@ +#if __ANDROID__ || ANDROID +using System; +using System.IO; +using System.Diagnostics; +using Android.Views; +using Android.Webkit; +using Avalonia.Controls.Platform; +using Avalonia.Platform; + +namespace NativeEmbedSample; + +public partial class EmbedSample +{ + private IPlatformHandle CreateAndroid(IPlatformHandle parent) + { + var button = new Android.Widget.Button(Android.App.Application.Context) { Text = "Android button" }; + + return new AndroidViewHandle(button); + } + + private void DestroyAndroid(IPlatformHandle control) + { + base.DestroyNativeControlCore(control); + } +} + +internal sealed class AndroidViewHandle : INativeControlHostDestroyableControlHandle +{ + private View _view; + + public AndroidViewHandle(View view) + { + _view = view; + } + + public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; + public string HandleDescriptor => "JavaHandle"; + + public void Destroy() + { + _view?.Dispose(); + _view = null; + } + + ~AndroidViewHandle() + { + Destroy(); + } +} +#endif diff --git a/samples/interop/NativeEmbedSample/App.xaml b/samples/interop/NativeEmbedSample/App.axaml similarity index 57% rename from samples/interop/NativeEmbedSample/App.xaml rename to samples/interop/NativeEmbedSample/App.axaml index e35ade4087..d6f182ed3f 100644 --- a/samples/interop/NativeEmbedSample/App.xaml +++ b/samples/interop/NativeEmbedSample/App.axaml @@ -2,7 +2,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="NativeEmbedSample.App"> - - + diff --git a/samples/interop/NativeEmbedSample/App.axaml.cs b/samples/interop/NativeEmbedSample/App.axaml.cs new file mode 100644 index 0000000000..0a89ea441b --- /dev/null +++ b/samples/interop/NativeEmbedSample/App.axaml.cs @@ -0,0 +1,23 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; + +namespace NativeEmbedSample; + +public class App : Application +{ + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) + desktopLifetime.MainWindow = new MainWindow(); + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime) + singleViewLifetime.MainView = new MainView(); + + base.OnFrameworkInitializationCompleted(); + } +} diff --git a/samples/interop/NativeEmbedSample/App.xaml.cs b/samples/interop/NativeEmbedSample/App.xaml.cs deleted file mode 100644 index cb17cfc35d..0000000000 --- a/samples/interop/NativeEmbedSample/App.xaml.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Markup.Xaml; - -namespace NativeEmbedSample -{ - public class App : Application - { - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - } - - public override void OnFrameworkInitializationCompleted() - { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) - desktopLifetime.MainWindow = new MainWindow(); - - base.OnFrameworkInitializationCompleted(); - } - } -} diff --git a/samples/interop/NativeEmbedSample/EmbedSample.cs b/samples/interop/NativeEmbedSample/EmbedSample.cs index ab9df11e19..340068058f 100644 --- a/samples/interop/NativeEmbedSample/EmbedSample.cs +++ b/samples/interop/NativeEmbedSample/EmbedSample.cs @@ -6,116 +6,49 @@ using System.Text; using Avalonia.Controls; using Avalonia.Platform; using Avalonia.Threading; -using MonoMac.AppKit; -using MonoMac.Foundation; -using MonoMac.WebKit; -using Encoding = SharpDX.Text.Encoding; namespace NativeEmbedSample { - public class EmbedSample : NativeControlHost + public partial class EmbedSample : NativeControlHost { public bool IsSecond { get; set; } - private Process _mplayer; - IPlatformHandle CreateLinux(IPlatformHandle parent) - { - if (IsSecond) - { - var chooser = GtkHelper.CreateGtkFileChooser(parent.Handle); - if (chooser != null) - return chooser; - } - - var control = base.CreateNativeControlCore(parent); - var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, - "..", - "nodes.mp4")); - _mplayer = Process.Start(new ProcessStartInfo("mplayer", - $"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodes}\"") - { - UseShellExecute = false, - - }); - return control; - } - - void DestroyLinux(IPlatformHandle handle) - { - _mplayer?.Kill(); - _mplayer = null; - base.DestroyNativeControlCore(handle); - } - - private const string RichText = - @"{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049{\fonttbl{\f0\fnil\fcharset0 Calibri;}} -{\colortbl ;\red255\green0\blue0;\red0\green77\blue187;\red0\green176\blue80;\red155\green0\blue211;\red247\green150\blue70;\red75\green172\blue198;} -{\*\generator Riched20 6.3.9600}\viewkind4\uc1 -\pard\sa200\sl276\slmult1\f0\fs22\lang9 I \i am\i0 a \cf1\b Rich Text \cf0\b0\fs24 control\cf2\fs28 !\cf3\fs32 !\cf4\fs36 !\cf1\fs40 !\cf5\fs44 !\cf6\fs48 !\cf0\fs44\par -}"; - - IPlatformHandle CreateWin32(IPlatformHandle parent) - { - WinApi.LoadLibrary("Msftedit.dll"); - var handle = WinApi.CreateWindowEx(0, "RICHEDIT50W", - @"Rich Edit", - 0x800000 | 0x10000000 | 0x40000000 | 0x800000 | 0x10000 | 0x0004, 0, 0, 1, 1, parent.Handle, - IntPtr.Zero, WinApi.GetModuleHandle(null), IntPtr.Zero); - var st = new WinApi.SETTEXTEX { Codepage = 65001, Flags = 0x00000008 }; - var text = RichText.Replace("", IsSecond ? "\\qr " : ""); - var bytes = Encoding.UTF8.GetBytes(text); - WinApi.SendMessage(handle, 0x0400 + 97, ref st, bytes); - return new PlatformHandle(handle, "HWND"); - - } - - void DestroyWin32(IPlatformHandle handle) - { - WinApi.DestroyWindow(handle.Handle); - } - - IPlatformHandle CreateOSX(IPlatformHandle parent) - { - // Note: We are using MonoMac for example purposes - // It shouldn't be used in production apps - MacHelper.EnsureInitialized(); - - var webView = new WebView(); - Dispatcher.UIThread.Post(() => - { - webView.MainFrame.LoadRequest(new NSUrlRequest(new NSUrl( - IsSecond ? "https://bing.com": "https://google.com/"))); - }); - return new MacOSViewHandle(webView); - - } - - void DestroyOSX(IPlatformHandle handle) - { - ((MacOSViewHandle)handle).Dispose(); - } - protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) +#if DESKTOP + if (OperatingSystem.IsLinux()) return CreateLinux(parent); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (OperatingSystem.IsWindows()) return CreateWin32(parent); - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + if (OperatingSystem.IsMacOS()) return CreateOSX(parent); +#elif __ANDROID__ || ANDROID + if (OperatingSystem.IsAndroid()) + return CreateAndroid(parent); +#elif IOS + if (OperatingSystem.IsIOS()) + return CreateIOS(parent); +#endif return base.CreateNativeControlCore(parent); } protected override void DestroyNativeControlCore(IPlatformHandle control) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) +#if DESKTOP + if (OperatingSystem.IsLinux()) DestroyLinux(control); - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + else if (OperatingSystem.IsWindows()) DestroyWin32(control); - else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + else if (OperatingSystem.IsMacOS()) DestroyOSX(control); - else - base.DestroyNativeControlCore(control); +#elif __ANDROID__ || ANDROID + if (OperatingSystem.IsAndroid()) + DestroyAndroid(control); +#elif IOS + if (OperatingSystem.IsIOS()) + DestroyIOS(control); +#endif + else base.DestroyNativeControlCore(control); } } } diff --git a/samples/interop/NativeEmbedSample/Gtk/EmbedSample.Gtk.cs b/samples/interop/NativeEmbedSample/Gtk/EmbedSample.Gtk.cs new file mode 100644 index 0000000000..24c9deca36 --- /dev/null +++ b/samples/interop/NativeEmbedSample/Gtk/EmbedSample.Gtk.cs @@ -0,0 +1,41 @@ +#if DESKTOP +using System.IO; +using System.Diagnostics; +using Avalonia.Platform; + +namespace NativeEmbedSample; + +public partial class EmbedSample +{ + private Process _mplayer; + + IPlatformHandle CreateLinux(IPlatformHandle parent) + { + if (IsSecond) + { + var chooser = GtkHelper.CreateGtkFileChooser(parent.Handle); + if (chooser != null) + return chooser; + } + + var control = base.CreateNativeControlCore(parent); + var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, + "..", + "nodes.mp4")); + _mplayer = Process.Start(new ProcessStartInfo("mplayer", + $"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodes}\"") + { + UseShellExecute = false, + + }); + return control; + } + + void DestroyLinux(IPlatformHandle handle) + { + _mplayer?.Kill(); + _mplayer = null; + base.DestroyNativeControlCore(handle); + } +} +#endif diff --git a/samples/interop/NativeEmbedSample/Gtk/GtkHelper.cs b/samples/interop/NativeEmbedSample/Gtk/GtkHelper.cs new file mode 100644 index 0000000000..567bc25acb --- /dev/null +++ b/samples/interop/NativeEmbedSample/Gtk/GtkHelper.cs @@ -0,0 +1,62 @@ +#if DESKTOP + +using System; +using System.Threading.Tasks; +using Avalonia.Controls.Platform; +using Avalonia.Platform; +using Avalonia.Platform.Interop; +using Avalonia.X11.NativeDialogs; +using static Avalonia.X11.NativeDialogs.Gtk; +using static Avalonia.X11.NativeDialogs.Glib; + +namespace NativeEmbedSample; + +internal class GtkHelper +{ + private static Task s_gtkTask; + + class FileChooser : INativeControlHostDestroyableControlHandle + { + private readonly IntPtr _widget; + + public FileChooser(IntPtr widget, IntPtr xid) + { + _widget = widget; + Handle = xid; + } + + public IntPtr Handle { get; } + public string HandleDescriptor => "XID"; + + public void Destroy() + { + RunOnGlibThread(() => + { + gtk_widget_destroy(_widget); + return 0; + }).Wait(); + } + } + + + public static IPlatformHandle CreateGtkFileChooser(IntPtr parentXid) + { + if (s_gtkTask == null) + s_gtkTask = StartGtk(); + if (!s_gtkTask.Result) + return null; + return RunOnGlibThread(() => + { + using (var title = new Utf8Buffer("Embedded")) + { + var widget = gtk_file_chooser_dialog_new(title, IntPtr.Zero, GtkFileChooserAction.SelectFolder, + IntPtr.Zero); + gtk_widget_realize(widget); + var xid = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); + gtk_window_present(widget); + return new FileChooser(widget, xid); + } + }).Result; + } +} +#endif diff --git a/samples/interop/NativeEmbedSample/nodes-license.md b/samples/interop/NativeEmbedSample/Gtk/nodes-license.md similarity index 100% rename from samples/interop/NativeEmbedSample/nodes-license.md rename to samples/interop/NativeEmbedSample/Gtk/nodes-license.md diff --git a/samples/interop/NativeEmbedSample/nodes.mp4 b/samples/interop/NativeEmbedSample/Gtk/nodes.mp4 similarity index 100% rename from samples/interop/NativeEmbedSample/nodes.mp4 rename to samples/interop/NativeEmbedSample/Gtk/nodes.mp4 diff --git a/samples/interop/NativeEmbedSample/GtkHelper.cs b/samples/interop/NativeEmbedSample/GtkHelper.cs deleted file mode 100644 index e389a51ef5..0000000000 --- a/samples/interop/NativeEmbedSample/GtkHelper.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Threading.Tasks; -using Avalonia.Controls.Platform; -using Avalonia.Platform; -using Avalonia.Platform.Interop; -using Avalonia.X11.NativeDialogs; -using static Avalonia.X11.NativeDialogs.Gtk; -using static Avalonia.X11.NativeDialogs.Glib; -namespace NativeEmbedSample -{ - public class GtkHelper - { - private static Task s_gtkTask; - class FileChooser : INativeControlHostDestroyableControlHandle - { - private readonly IntPtr _widget; - - public FileChooser(IntPtr widget, IntPtr xid) - { - _widget = widget; - Handle = xid; - } - - public IntPtr Handle { get; } - public string HandleDescriptor => "XID"; - public void Destroy() - { - RunOnGlibThread(() => - { - gtk_widget_destroy(_widget); - return 0; - }).Wait(); - } - } - - - - public static IPlatformHandle CreateGtkFileChooser(IntPtr parentXid) - { - if (s_gtkTask == null) - s_gtkTask = StartGtk(); - if (!s_gtkTask.Result) - return null; - return RunOnGlibThread(() => - { - using (var title = new Utf8Buffer("Embedded")) - { - var widget = gtk_file_chooser_dialog_new(title, IntPtr.Zero, GtkFileChooserAction.SelectFolder, - IntPtr.Zero); - gtk_widget_realize(widget); - var xid = gdk_x11_window_get_xid(gtk_widget_get_window(widget)); - gtk_window_present(widget); - return new FileChooser(widget, xid); - } - }).Result; - } - } -} diff --git a/samples/interop/NativeEmbedSample/Mac/EmbedSample.Mac.cs b/samples/interop/NativeEmbedSample/Mac/EmbedSample.Mac.cs new file mode 100644 index 0000000000..911a874c27 --- /dev/null +++ b/samples/interop/NativeEmbedSample/Mac/EmbedSample.Mac.cs @@ -0,0 +1,32 @@ +#if DESKTOP +using Avalonia.Platform; +using Avalonia.Threading; +using MonoMac.Foundation; +using MonoMac.WebKit; + +namespace NativeEmbedSample; + +public partial class EmbedSample +{ + IPlatformHandle CreateOSX(IPlatformHandle parent) + { + // Note: We are using MonoMac for example purposes + // It shouldn't be used in production apps + MacHelper.EnsureInitialized(); + + var webView = new WebView(); + Dispatcher.UIThread.Post(() => + { + webView.MainFrame.LoadRequest(new NSUrlRequest(new NSUrl( + IsSecond ? "https://bing.com": "https://google.com/"))); + }); + return new MacOSViewHandle(webView); + + } + + void DestroyOSX(IPlatformHandle handle) + { + ((MacOSViewHandle)handle).Dispose(); + } +} +#endif diff --git a/samples/interop/NativeEmbedSample/Mac/MacHelper.cs b/samples/interop/NativeEmbedSample/Mac/MacHelper.cs new file mode 100644 index 0000000000..d72ef5479c --- /dev/null +++ b/samples/interop/NativeEmbedSample/Mac/MacHelper.cs @@ -0,0 +1,39 @@ +#if DESKTOP +using System; +using Avalonia.Platform; +using MonoMac.AppKit; + +namespace NativeEmbedSample; + +internal class MacHelper +{ + private static bool _isInitialized; + + public static void EnsureInitialized() + { + if (_isInitialized) + return; + _isInitialized = true; + NSApplication.Init(); + } +} + +internal class MacOSViewHandle : IPlatformHandle, IDisposable +{ + private NSView _view; + + public MacOSViewHandle(NSView view) + { + _view = view; + } + + public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; + public string HandleDescriptor => "NSView"; + + public void Dispose() + { + _view.Dispose(); + _view = null; + } +} +#endif diff --git a/samples/interop/NativeEmbedSample/MacHelper.cs b/samples/interop/NativeEmbedSample/MacHelper.cs deleted file mode 100644 index 74a06a0a0c..0000000000 --- a/samples/interop/NativeEmbedSample/MacHelper.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using Avalonia.Platform; -using MonoMac.AppKit; - -namespace NativeEmbedSample -{ - public class MacHelper - { - private static bool _isInitialized; - - public static void EnsureInitialized() - { - if (_isInitialized) - return; - _isInitialized = true; - NSApplication.Init(); - } - } - - class MacOSViewHandle : IPlatformHandle, IDisposable - { - private NSView _view; - - public MacOSViewHandle(NSView view) - { - _view = view; - } - - public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; - public string HandleDescriptor => "NSView"; - - public void Dispose() - { - _view.Dispose(); - _view = null; - } - } - -} diff --git a/samples/interop/NativeEmbedSample/MainView.axaml b/samples/interop/NativeEmbedSample/MainView.axaml new file mode 100644 index 0000000000..4bfb14b2f9 --- /dev/null +++ b/samples/interop/NativeEmbedSample/MainView.axaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + Text + + + Tooltip + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/interop/NativeEmbedSample/MainView.axaml.cs b/samples/interop/NativeEmbedSample/MainView.axaml.cs new file mode 100644 index 0000000000..976de7a97c --- /dev/null +++ b/samples/interop/NativeEmbedSample/MainView.axaml.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; + +namespace NativeEmbedSample; + +public class MainView : UserControl +{ + public MainView() + { + AvaloniaXamlLoader.Load(this); + } + + public async void ShowPopupDelay(object sender, RoutedEventArgs args) + { + await Task.Delay(3000); + ShowPopup(sender, args); + } + + public void ShowPopup(object sender, RoutedEventArgs args) + { + new ContextMenu() + { + Items = new List + { + new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" } + } + }.Open((Control)sender); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == BoundsProperty) + { + var isMobile = change.GetNewValue().Width < 1200; + this.Find("FirstPanel")!.Classes.Set("mobile", isMobile); + this.Find("SecondPanel")!.Classes.Set("mobile", isMobile); + } + } +} diff --git a/samples/interop/NativeEmbedSample/MainWindow.axaml b/samples/interop/NativeEmbedSample/MainWindow.axaml new file mode 100644 index 0000000000..a615428778 --- /dev/null +++ b/samples/interop/NativeEmbedSample/MainWindow.axaml @@ -0,0 +1,10 @@ + + + + diff --git a/samples/interop/NativeEmbedSample/MainWindow.axaml.cs b/samples/interop/NativeEmbedSample/MainWindow.axaml.cs new file mode 100644 index 0000000000..a261dad5ed --- /dev/null +++ b/samples/interop/NativeEmbedSample/MainWindow.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace NativeEmbedSample; + +public class MainWindow : Window +{ + public MainWindow() + { + AvaloniaXamlLoader.Load(this); +#if DEBUG && DESKTOP + this.AttachDevTools(); +#endif + } +} + diff --git a/samples/interop/NativeEmbedSample/MainWindow.xaml b/samples/interop/NativeEmbedSample/MainWindow.xaml deleted file mode 100644 index f2161a1bea..0000000000 --- a/samples/interop/NativeEmbedSample/MainWindow.xaml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - Text - - - Tooltip - - - - - - - - - Visible - - - - - - - - Visible - - - - - - diff --git a/samples/interop/NativeEmbedSample/MainWindow.xaml.cs b/samples/interop/NativeEmbedSample/MainWindow.xaml.cs deleted file mode 100644 index 4324aa2762..0000000000 --- a/samples/interop/NativeEmbedSample/MainWindow.xaml.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; - -namespace NativeEmbedSample -{ - public class MainWindow : Window - { - public MainWindow() - { - AvaloniaXamlLoader.Load(this); - this.AttachDevTools(); - } - - public async void ShowPopupDelay(object sender, RoutedEventArgs args) - { - await Task.Delay(3000); - ShowPopup(sender, args); - } - - public void ShowPopup(object sender, RoutedEventArgs args) - { - - new ContextMenu() - { - Items = new List - { - new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" } - } - }.Open((Control)sender); - } - } -} diff --git a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj index c25442b52c..34206c2b63 100644 --- a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj +++ b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj @@ -1,30 +1,32 @@  - Exe - netcoreapp2.0 - true + net6.0;net6.0-android;net6.0-ios true + + $(DefineConstants);DESKTOP + + + + - - - Designer - - + + + Gtk\Gtk.cs + + + PreserveNewest - - - diff --git a/samples/interop/NativeEmbedSample/Program.cs b/samples/interop/NativeEmbedSample/Program.cs deleted file mode 100644 index baa7837667..0000000000 --- a/samples/interop/NativeEmbedSample/Program.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Avalonia; - -namespace NativeEmbedSample -{ - class Program - { - static int Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - - public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .With(new AvaloniaNativePlatformOptions() - { - }) - .UsePlatformDetect(); - - } -} diff --git a/samples/interop/NativeEmbedSample/Win/EmbedSample.Win.cs b/samples/interop/NativeEmbedSample/Win/EmbedSample.Win.cs new file mode 100644 index 0000000000..2e14e7d766 --- /dev/null +++ b/samples/interop/NativeEmbedSample/Win/EmbedSample.Win.cs @@ -0,0 +1,37 @@ +#if DESKTOP +using System; +using System.Text; +using Avalonia.Platform; + +namespace NativeEmbedSample; + +public partial class EmbedSample +{ + private const string RichText = + @"{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049{\fonttbl{\f0\fnil\fcharset0 Calibri;}} +{\colortbl ;\red255\green0\blue0;\red0\green77\blue187;\red0\green176\blue80;\red155\green0\blue211;\red247\green150\blue70;\red75\green172\blue198;} +{\*\generator Riched20 6.3.9600}\viewkind4\uc1 +\pard\sa200\sl276\slmult1\f0\fs22\lang9 I \i am\i0 a \cf1\b Rich Text \cf0\b0\fs24 control\cf2\fs28 !\cf3\fs32 !\cf4\fs36 !\cf1\fs40 !\cf5\fs44 !\cf6\fs48 !\cf0\fs44\par +}"; + + IPlatformHandle CreateWin32(IPlatformHandle parent) + { + WinApi.LoadLibrary("Msftedit.dll"); + var handle = WinApi.CreateWindowEx(0, "RICHEDIT50W", + @"Rich Edit", + 0x800000 | 0x10000000 | 0x40000000 | 0x800000 | 0x10000 | 0x0004, 0, 0, 1, 1, parent.Handle, + IntPtr.Zero, WinApi.GetModuleHandle(null), IntPtr.Zero); + var st = new WinApi.SETTEXTEX { Codepage = 65001, Flags = 0x00000008 }; + var text = RichText.Replace("", IsSecond ? "\\qr " : ""); + var bytes = Encoding.UTF8.GetBytes(text); + WinApi.SendMessage(handle, 0x0400 + 97, ref st, bytes); + return new PlatformHandle(handle, "HWND"); + + } + + void DestroyWin32(IPlatformHandle handle) + { + WinApi.DestroyWindow(handle.Handle); + } +} +#endif diff --git a/samples/interop/NativeEmbedSample/Win/WinApi.cs b/samples/interop/NativeEmbedSample/Win/WinApi.cs new file mode 100644 index 0000000000..5ec6e6bbeb --- /dev/null +++ b/samples/interop/NativeEmbedSample/Win/WinApi.cs @@ -0,0 +1,75 @@ +#if DESKTOP +using System; +using System.Runtime.InteropServices; + +namespace NativeEmbedSample; + +internal unsafe class WinApi +{ + public enum CommonControls : uint + { + ICC_LISTVIEW_CLASSES = 0x00000001, // listview, header + ICC_TREEVIEW_CLASSES = 0x00000002, // treeview, tooltips + ICC_BAR_CLASSES = 0x00000004, // toolbar, statusbar, trackbar, tooltips + ICC_TAB_CLASSES = 0x00000008, // tab, tooltips + ICC_UPDOWN_CLASS = 0x00000010, // updown + ICC_PROGRESS_CLASS = 0x00000020, // progress + ICC_HOTKEY_CLASS = 0x00000040, // hotkey + ICC_ANIMATE_CLASS = 0x00000080, // animate + ICC_WIN95_CLASSES = 0x000000FF, + ICC_DATE_CLASSES = 0x00000100, // month picker, date picker, time picker, updown + ICC_USEREX_CLASSES = 0x00000200, // comboex + ICC_COOL_CLASSES = 0x00000400, // rebar (coolbar) control + ICC_INTERNET_CLASSES = 0x00000800, + ICC_PAGESCROLLER_CLASS = 0x00001000, // page scroller + ICC_NATIVEFNTCTL_CLASS = 0x00002000, // native font control + ICC_STANDARD_CLASSES = 0x00004000, + ICC_LINK_CLASS = 0x00008000 + } + + [StructLayout(LayoutKind.Sequential)] + public struct INITCOMMONCONTROLSEX + { + public int dwSize; + public uint dwICC; + } + + [DllImport("Comctl32.dll")] + public static extern void InitCommonControlsEx(ref INITCOMMONCONTROLSEX init); + + [DllImport("user32.dll", SetLastError = true)] + public static extern bool DestroyWindow(IntPtr hwnd); + + [DllImport("kernel32.dll")] + public static extern IntPtr LoadLibrary(string lib); + + + [DllImport("kernel32.dll")] + public static extern IntPtr GetModuleHandle(string lpModuleName); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr CreateWindowEx( + int dwExStyle, + string lpClassName, + string lpWindowName, + uint dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam); + + [StructLayout(LayoutKind.Sequential)] + public struct SETTEXTEX + { + public uint Flags; + public uint Codepage; + } + + [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")] + public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, ref SETTEXTEX wParam, byte[] lParam); +} +#endif diff --git a/samples/interop/NativeEmbedSample/WinApi.cs b/samples/interop/NativeEmbedSample/WinApi.cs deleted file mode 100644 index 8e5bcdf49e..0000000000 --- a/samples/interop/NativeEmbedSample/WinApi.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace NativeEmbedSample -{ - public unsafe class WinApi - { - public enum CommonControls : uint - { - ICC_LISTVIEW_CLASSES = 0x00000001, // listview, header - ICC_TREEVIEW_CLASSES = 0x00000002, // treeview, tooltips - ICC_BAR_CLASSES = 0x00000004, // toolbar, statusbar, trackbar, tooltips - ICC_TAB_CLASSES = 0x00000008, // tab, tooltips - ICC_UPDOWN_CLASS = 0x00000010, // updown - ICC_PROGRESS_CLASS = 0x00000020, // progress - ICC_HOTKEY_CLASS = 0x00000040, // hotkey - ICC_ANIMATE_CLASS = 0x00000080, // animate - ICC_WIN95_CLASSES = 0x000000FF, - ICC_DATE_CLASSES = 0x00000100, // month picker, date picker, time picker, updown - ICC_USEREX_CLASSES = 0x00000200, // comboex - ICC_COOL_CLASSES = 0x00000400, // rebar (coolbar) control - ICC_INTERNET_CLASSES = 0x00000800, - ICC_PAGESCROLLER_CLASS = 0x00001000, // page scroller - ICC_NATIVEFNTCTL_CLASS = 0x00002000, // native font control - ICC_STANDARD_CLASSES = 0x00004000, - ICC_LINK_CLASS = 0x00008000 - } - - [StructLayout(LayoutKind.Sequential)] - public struct INITCOMMONCONTROLSEX - { - public int dwSize; - public uint dwICC; - } - - [DllImport("Comctl32.dll")] - public static extern void InitCommonControlsEx(ref INITCOMMONCONTROLSEX init); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool DestroyWindow(IntPtr hwnd); - - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string lib); - - - [DllImport("kernel32.dll")] - public static extern IntPtr GetModuleHandle(string lpModuleName); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr CreateWindowEx( - int dwExStyle, - string lpClassName, - string lpWindowName, - uint dwStyle, - int x, - int y, - int nWidth, - int nHeight, - IntPtr hWndParent, - IntPtr hMenu, - IntPtr hInstance, - IntPtr lpParam); - - [StructLayout(LayoutKind.Sequential)] - public struct SETTEXTEX - { - public uint Flags; - public uint Codepage; - } - - [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")] - public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, ref SETTEXTEX wParam, byte[] lParam); - } -} diff --git a/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs b/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs new file mode 100644 index 0000000000..185c2e6b9f --- /dev/null +++ b/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs @@ -0,0 +1,65 @@ +#if IOS +using System; +using System.IO; +using System.Diagnostics; +using Avalonia.Controls.Platform; +using Avalonia.Platform; +using CoreGraphics; +using Foundation; +using UIKit; +using WebKit; + +namespace NativeEmbedSample; + +public partial class EmbedSample +{ + private IPlatformHandle CreateIOS(IPlatformHandle parent) + { + if (IsSecond) + { + var webView = new WKWebView(CGRect.Empty, new WKWebViewConfiguration()); + webView.LoadRequest(new NSUrlRequest(new NSUrl("https://www.apple.com/"))); + + return new UIViewHandle(webView); + } + else + { + var button = new UIButton(); + var clickCount = 0; + button.SetTitle("Hello world", UIControlState.Normal); + button.BackgroundColor = UIColor.Blue; + button.AddTarget((_, _) => + { + clickCount++; + button.SetTitle($"Click count {clickCount}", UIControlState.Normal); + }, UIControlEvent.TouchDown); + + return new UIViewHandle(button); + } + } + + private void DestroyIOS(IPlatformHandle control) + { + base.DestroyNativeControlCore(control); + } +} + +internal class UIViewHandle : INativeControlHostDestroyableControlHandle +{ + private UIView _view; + + public UIViewHandle(UIView view) + { + _view = view; + } + + public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; + public string HandleDescriptor => "UIView"; + + public void Destroy() + { + _view?.Dispose(); + _view = null; + } +} +#endif From d8d6fa5097c13acbeef998015bfe6295286f2735 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 10 May 2022 00:28:09 -0400 Subject: [PATCH 066/332] Add iOS implementation --- Avalonia.sln | 27 +++ .../NativeEmbedSample.iOS/AppDelegate.cs | 9 + .../AppIcon.appiconset/Contents.json | 117 +++++++++++ .../AppIcon.appiconset/Icon1024.png | Bin 0 -> 70429 bytes .../AppIcon.appiconset/Icon120.png | Bin 0 -> 3773 bytes .../AppIcon.appiconset/Icon152.png | Bin 0 -> 4750 bytes .../AppIcon.appiconset/Icon167.png | Bin 0 -> 4692 bytes .../AppIcon.appiconset/Icon180.png | Bin 0 -> 5192 bytes .../AppIcon.appiconset/Icon20.png | Bin 0 -> 1313 bytes .../AppIcon.appiconset/Icon29.png | Bin 0 -> 845 bytes .../AppIcon.appiconset/Icon40.png | Bin 0 -> 1101 bytes .../AppIcon.appiconset/Icon58.png | Bin 0 -> 1761 bytes .../AppIcon.appiconset/Icon60.png | Bin 0 -> 2537 bytes .../AppIcon.appiconset/Icon76.png | Bin 0 -> 2332 bytes .../AppIcon.appiconset/Icon80.png | Bin 0 -> 2454 bytes .../AppIcon.appiconset/Icon87.png | Bin 0 -> 2758 bytes .../NativeEmbedSample.iOS/Entitlements.plist | 6 + .../interop/NativeEmbedSample.iOS/Info.plist | 42 ++++ samples/interop/NativeEmbedSample.iOS/Main.cs | 6 + .../NativeEmbedSample.iOS.csproj | 16 ++ .../Resources/LaunchScreen.xib | 43 ++++ src/iOS/Avalonia.iOS/AvaloniaView.cs | 4 +- src/iOS/Avalonia.iOS/NativeControlHostImpl.cs | 183 ++++++++++++++++++ 23 files changed, 452 insertions(+), 1 deletion(-) create mode 100644 samples/interop/NativeEmbedSample.iOS/AppDelegate.cs create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png create mode 100644 samples/interop/NativeEmbedSample.iOS/Entitlements.plist create mode 100644 samples/interop/NativeEmbedSample.iOS/Info.plist create mode 100644 samples/interop/NativeEmbedSample.iOS/Main.cs create mode 100644 samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj create mode 100644 samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib create mode 100644 src/iOS/Avalonia.iOS/NativeControlHostImpl.cs diff --git a/Avalonia.sln b/Avalonia.sln index 0adc29ffe8..0a33bc4150 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -221,6 +221,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.Desktop", "samples\interop\NativeEmbedSample.Desktop\NativeEmbedSample.Desktop.csproj", "{F2389463-DDB4-4317-B894-D4DF9FF6B763}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.iOS", "samples\interop\NativeEmbedSample.iOS\NativeEmbedSample.iOS.csproj", "{28DB5AD1-656D-4619-BE0B-5B475E138DF8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -2015,6 +2017,30 @@ Global {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhone.Build.0 = Release|Any CPU {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhone.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhone.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|Any CPU.Build.0 = Release|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhone.ActiveCfg = Release|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhone.Build.0 = Release|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2075,6 +2101,7 @@ Global {CE910927-CE5A-456F-BC92-E4C757354A5C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} {F2389463-DDB4-4317-B894-D4DF9FF6B763} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} + {28DB5AD1-656D-4619-BE0B-5B475E138DF8} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/interop/NativeEmbedSample.iOS/AppDelegate.cs b/samples/interop/NativeEmbedSample.iOS/AppDelegate.cs new file mode 100644 index 0000000000..9ac8ebab2e --- /dev/null +++ b/samples/interop/NativeEmbedSample.iOS/AppDelegate.cs @@ -0,0 +1,9 @@ +using Avalonia.iOS; + +namespace NativeEmbedSample.iOS; + +[Register("AppDelegate")] +public partial class AppDelegate : AvaloniaAppDelegate +{ + +} diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..98f4d035c8 --- /dev/null +++ b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,117 @@ +{ + "images": [ + { + "scale": "2x", + "size": "20x20", + "idiom": "iphone", + "filename": "Icon40.png" + }, + { + "scale": "3x", + "size": "20x20", + "idiom": "iphone", + "filename": "Icon60.png" + }, + { + "scale": "2x", + "size": "29x29", + "idiom": "iphone", + "filename": "Icon58.png" + }, + { + "scale": "3x", + "size": "29x29", + "idiom": "iphone", + "filename": "Icon87.png" + }, + { + "scale": "2x", + "size": "40x40", + "idiom": "iphone", + "filename": "Icon80.png" + }, + { + "scale": "3x", + "size": "40x40", + "idiom": "iphone", + "filename": "Icon120.png" + }, + { + "scale": "2x", + "size": "60x60", + "idiom": "iphone", + "filename": "Icon120.png" + }, + { + "scale": "3x", + "size": "60x60", + "idiom": "iphone", + "filename": "Icon180.png" + }, + { + "scale": "1x", + "size": "20x20", + "idiom": "ipad", + "filename": "Icon20.png" + }, + { + "scale": "2x", + "size": "20x20", + "idiom": "ipad", + "filename": "Icon40.png" + }, + { + "scale": "1x", + "size": "29x29", + "idiom": "ipad", + "filename": "Icon29.png" + }, + { + "scale": "2x", + "size": "29x29", + "idiom": "ipad", + "filename": "Icon58.png" + }, + { + "scale": "1x", + "size": "40x40", + "idiom": "ipad", + "filename": "Icon40.png" + }, + { + "scale": "2x", + "size": "40x40", + "idiom": "ipad", + "filename": "Icon80.png" + }, + { + "scale": "1x", + "size": "76x76", + "idiom": "ipad", + "filename": "Icon76.png" + }, + { + "scale": "2x", + "size": "76x76", + "idiom": "ipad", + "filename": "Icon152.png" + }, + { + "scale": "2x", + "size": "83.5x83.5", + "idiom": "ipad", + "filename": "Icon167.png" + }, + { + "scale": "1x", + "size": "1024x1024", + "idiom": "ios-marketing", + "filename": "Icon1024.png" + } + ], + "properties": {}, + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png new file mode 100644 index 0000000000000000000000000000000000000000..9174c989a9c8b8a5ca133228f4ed7c173fffd2ee GIT binary patch literal 70429 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 z zCn)b8&=oMu6ygwwJfdasJX|@L6?m1Dv0X9t>JAWO^UIj0#&(3UrHx;vP^3g= zL{(XT!?`D*pP8)WoGHYEZZc$!odTzb8n)q0|88*>6P z`?6&CSv_W7r2yF0beQ2*?V^_%pKktVAo`)T^26X@NpK_*-ni{D7{Sp{C0A<|16l(; zOL*xGW|*sKsiwHvE!h3QXe@^a#6W3}8!DQu-h?A_4gkeRYkt4NC~GR5P8eyp;9kVQ8$QG$5ad7Fo23Z~ak1jY~RXG{v?3G$RarFe`XePu3X{R+=mBOw&X zks)|Sc$RcG-jhn!`~-x|vg!&DA&@}QH^RNdyy9nq56yrU$^qAaS+F_NOaeFb)CVaH z?!UvPajgrK&zqdAs>&Def#wkcG_UhmYOVw^M`VZz@+4IWAVzK%`+za9rm2SD9={u@ zlx5D6UDL;lc7#9`+%vnlP3PescU=N`DHQPt_N55GNBMkVCRMR4?fvp zAFsvcHN4c9rb>J@{*IH>RTr9de%9i4Gd(cbFa9SP4anhoP;TA0!oZyB8?lNMDHPHK zCaOaFU9?x2A!o>p>mCF9r+hKs9Czu_P1l$LWU%}q#)=T3p`ZnYyeHmsewqw`}L^4LuHqfo+CG6<2n7#l^3;H^^!1 zsaieYFnN)Kc7Mv}^xE)4kXUw8<9I+jMB@QV9T9I8haLDt1Ne#exWUfGYG$4uMoEu& zo81#2up18Y40h%tIsOZglp(ltVsE*j1~$lVd|;rN)&${~o~-%KZnJp&3|OFR{^8E9 zJ;fCu53Ysw%}@VYWE*z7r)&4P=^B-SF%a@>*9g84<4aFUZT7x)qdsS+#2tu5NbpU@ zg;EwV)l-#sK>#r9>(0Figx{9lKm>KvRj;y<8 zc8SxMW4<11(s@QMV_}n9MRzA*62->vzxmHh1)GVASEJY7LVtRw`Rv{v`(Fuc00(&o z%m>gS2aJekmdNQ4p<{pD3HqZ-%4hdU1__xYhLi9mTJXD|E zE`t6SX)}l_DY5vO0Xrs#O6_DKtPKn0f+e~SprDYmJL_`<053iA5P`zn z4<5etc%aF58sHFr#M;U-9|=;l)J#Q2vS!Q9(d(EX6fubL%uA_lqa2%!cpNIv78QZ}Ayo(>C(ZpsRtKhzD--fpuoCch87cX-Bna9_{z%$b*dHM0?+T&Hk!+^UM`r|vq z2Id$??bX^|tfYaE+h#Nik(ZcN+wt)28q^gWe!y8jDCXrD<2qV#49x@5$8&Zrd5NTs zNYcix;9fe#PQQ;T?!6hG>9K{K+RCPqiGc9z%t{=`QaX>7O{l(+#7mJ1>Rae^J?82e z6cLqLypskTCyu>uc~$0-XZ^1Qvhwr+pKQ#CKImhGu*MGM*ZrROuAHWuT*yM$ieEy8*KLFMMdLZL|D+yDmy@3_PELTEVMI6nwfcYA3ZQ9wwKdtkT z;`;z7fU{U6>CS7kr3=A-()_G*G(Mjf2wXKe

Fpy)y!S(AQHSG#udd_8#b4sQu!R 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 PgFh2POM|ilu9yD@)d*=D literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png new file mode 100644 index 0000000000000000000000000000000000000000..9c60a1761dbf62cc2a45ff98b9fdb63ade16e4d9 GIT binary patch literal 3773 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 Dh-f%Y literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png new file mode 100644 index 0000000000000000000000000000000000000000..448d6efb577d07e227a5c62545173ddf6bd86b55 GIT binary patch literal 4750 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 literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png new file mode 100644 index 0000000000000000000000000000000000000000..8524768f8d764da7e9c452a444208708f2d18ff1 GIT binary patch literal 4692 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 literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png new file mode 100644 index 0000000000000000000000000000000000000000..60a64703c0f11d08705cd607f7751338707f5919 GIT binary patch literal 5192 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 nB>N_)Q7iwV%v7MwAoJ}E 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 T3-0p800000NkvXXu0mjfSlal| literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png new file mode 100644 index 0000000000000000000000000000000000000000..1ad04f004b638bf781012290d78e4138f97bbe5e GIT binary patch literal 1761 zcmV<71|Io|P)4P%ubY|S^%$zf~ zmwTOa@12BA$oV-Y9!V&U%c=j==#_}M2ylE}1m>yyDoGsZ#Yy zNX}RO*f(MzmKS&u`qiajIyW{Y_LC%m2NqT@Ic|QpvYqwNgBK7n5X%c(3k^?2>EOA` zqGaXjE7H9BiJ55fh0iJRW}@=&(@R^E1hLB>kE%PS6eP@VZVdtn(fh;5DPKg!j;fJZ%)wH{Wn#~V&#n(o1URS zsyS`0Tu2m;-H}z9O^h`!UZAFr@?0a7Z;pYOi0uZhgzh=rOEDi`FIkKtVu*gEcSM!h zmb#_XR$akjlg$JI75MXgWkG7IUnYJ+X=1J!qJ%jXVj{L1I2QU%?=?DgV^U?)92DZm zV?>``xT1#kZdgUt!2n?|0>*6ae4tikA9FAlJ}kjmMQm_z3LB5sZYHBKdbex9_Hv@K z%Y?q@9-)b7vJ6X$3h0B4tH__=#*`9^efY@IQfghn*=E2Nb8sR8lrQlu`Ca_Rmm6>Z z7bkEe^w8M>x;hoNUvWu_GZJPVpI;bMTsBpf(@U$Ch(-gk0T#WpsaB1{7ISQ~Y48mW z;Nk?@LjM_?q{BV-D=veoOmJoncVDC1GwGGz(O5@o7ZkGCIJMPO(7K9b6M_wF?Xqd< zo4J6KF0_U2<1=T3x0qc6G6#g+^=N{QTpChC!GZuCY*|eU{Rw)LMN7a2wwbaCdn_dE zzy+Lip(XU4-+SoTFyEcnH3?HRV^%-;Ylx;|>8v&^Dy459ZJ_1zio`68!6s8SO(6sq zaN75WUKiF9+8MruR3=w5)hzA^Z1clVBuXc)+8@e);xX7bfygR&FsIIt-gQ+==(c;S z#J*CO1qZBF&M&6TRmskZXaMOU6&?jn_(BqY5 z>Y|^?uOh;yp6w0QR1`>tiEz_-{Zu!N#(nhRndJV$7;LOgPyZQ*J2yCin+~*u!qKj# zItsG2IDi{ZH+E6j=D|ht=qWxKNxaA6E>3Wna>=z1gy?*#>|g_1^BGspGro&OWRc(k zPP)(*y0WZ7Z-kICr3#g7($P*LCjE>7S`Xh~s!b~bPTo0XSkRm2T(M`QZbv-`Imx*Ulqk*aI* zaqa*=>61?nFb8w3wuiA&zyVyGz>!cm-pY3xEsMEiY)Th4FVrtqWp%V~gxW82)>4^N z*H{>GR?m$^s6BN^M=4^iEjT7(gM(8z7K#9Sn(M_`)oSH2zHDCla&cmK)bb|4nAMIO ze4S3gI9L8AD+T9c#C8K8JF)I68NBWK`5pE`q^OR#h~-u!e7P2i$UDq7^*uZr< zbp8sR<$nYxb8EKH|BltapZ^j3+PZt_u^PR*lT6;TCNxu^yFH$j(!JXvbmHfQ>a0>O z+2k{tOWD%ln$M`tD&>+*KBKvmEgi1;jOwgXF4_DG_&r&PcxYTT00000NkvXXu0mjf DptxI> literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png new file mode 100644 index 0000000000000000000000000000000000000000..2dd52620a8f15577e56ec7fe8e671988dd17ab0f GIT binary patch literal 2537 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 literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png new file mode 100644 index 0000000000000000000000000000000000000000..b058cae2f440e5a5875e45c036c99f1fb6356046 GIT binary patch literal 2332 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 Kc&(xHv;P1B$EH01 literal 0 HcmV?d00001 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png new file mode 100644 index 0000000000000000000000000000000000000000..4954a4bd33f613d45f74dc0b12beb516e3b38661 GIT binary patch literal 2758 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 z + + + + + diff --git a/samples/interop/NativeEmbedSample.iOS/Info.plist b/samples/interop/NativeEmbedSample.iOS/Info.plist new file mode 100644 index 0000000000..b9656e1c20 --- /dev/null +++ b/samples/interop/NativeEmbedSample.iOS/Info.plist @@ -0,0 +1,42 @@ + + + + + CFBundleDisplayName + AvaloniaNative + CFBundleIdentifier + Avalonia.Native.Sample + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/AppIcon.appiconset + + diff --git a/samples/interop/NativeEmbedSample.iOS/Main.cs b/samples/interop/NativeEmbedSample.iOS/Main.cs new file mode 100644 index 0000000000..a1d1502084 --- /dev/null +++ b/samples/interop/NativeEmbedSample.iOS/Main.cs @@ -0,0 +1,6 @@ +using NativeEmbedSample.iOS; + +// This is the main entry point of the application. +// If you want to use a different Application Delegate class from "AppDelegate" +// you can specify it here. +UIApplication.Main(args, null, typeof(AppDelegate)); diff --git a/samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj b/samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj new file mode 100644 index 0000000000..83611c90a1 --- /dev/null +++ b/samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj @@ -0,0 +1,16 @@ + + + net6.0-ios + manual + Exe + enable + true + 11.2 + iossimulator-x64 + + + + + + + diff --git a/samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib b/samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib new file mode 100644 index 0000000000..8190201742 --- /dev/null +++ b/samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.cs b/src/iOS/Avalonia.iOS/AvaloniaView.cs index e8108dd3de..0a47b152ed 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaView.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaView.cs @@ -43,7 +43,7 @@ namespace Avalonia.iOS MultipleTouchEnabled = true; } - internal class TopLevelImpl : ITopLevelImplWithTextInputMethod + internal class TopLevelImpl : ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost { private readonly AvaloniaView _view; public AvaloniaView View => _view; @@ -51,6 +51,7 @@ namespace Avalonia.iOS public TopLevelImpl(AvaloniaView view) { _view = view; + NativeControlHost = new NativeControlHostImpl(_view); } public void Dispose() @@ -112,6 +113,7 @@ namespace Avalonia.iOS new AcrylicPlatformCompensationLevels(); public ITextInputMethodImpl? TextInputMethod => _view; + public INativeControlHostImpl NativeControlHost { get; } } [Export("layerClass")] diff --git a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs new file mode 100644 index 0000000000..c5c632e7f7 --- /dev/null +++ b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs @@ -0,0 +1,183 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using Avalonia.Controls.Platform; +using Avalonia.Platform; +using CoreGraphics; +using ObjCRuntime; +using UIKit; + +namespace Avalonia.iOS +{ + internal class NativeControlHostImpl : INativeControlHostImpl + { + private readonly AvaloniaView _avaloniaView; + + public NativeControlHostImpl(AvaloniaView avaloniaView) + { + _avaloniaView = avaloniaView; + } + + public INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHandle parent) + { + return new UIViewControlHandle(new UIView()); + } + + public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) + { + var holder = new UIViewControlHandle(_avaloniaView); + NativeControlAttachment? attachment = null; + try + { + var child = create(holder); + // It has to be assigned to the variable before property setter is called so we dispose it on exception +#pragma warning disable IDE0017 // Simplify object initialization + attachment = new NativeControlAttachment(holder, child); +#pragma warning restore IDE0017 // Simplify object initialization + attachment.AttachedTo = this; + return attachment; + } + catch + { + attachment?.Dispose(); + holder?.Destroy(); + throw; + } + } + + public INativeControlHostControlTopLevelAttachment CreateNewAttachment(IPlatformHandle handle) + { + return new NativeControlAttachment(new UIViewControlHandle(_avaloniaView), handle) + { + AttachedTo = this + }; + } + + public bool IsCompatibleWith(IPlatformHandle handle) => handle.HandleDescriptor == UIViewControlHandle.UIViewDescriptor; + + private class ViewHolder : UIView + { + public ViewHolder(IntPtr handle) : base(new NativeHandle(handle)) + { + + } + } + + private class NativeControlAttachment : INativeControlHostControlTopLevelAttachment + { + // ReSharper disable once NotAccessedField.Local (keep GC reference) + private IPlatformHandle? _child; + private UIViewControlHandle? _holder; + private UIView? _view; + private NativeControlHostImpl? _attachedTo; + + public NativeControlAttachment(UIViewControlHandle holder, IPlatformHandle child) + { + _holder = holder; + _child = child; + + _view = (child as UIViewControlHandle)?.View ?? new ViewHolder(child.Handle); + _holder.View.AddSubview(_view); + } + + [MemberNotNull(nameof(_view))] + private void CheckDisposed() + { + if (_view == null) + throw new ObjectDisposedException(nameof(NativeControlAttachment)); + } + + public void Dispose() + { + _view?.RemoveFromSuperview(); + _holder = null; + _child = null; + _attachedTo = null; + _view?.Dispose(); + _view = null; + } + + public INativeControlHostImpl? AttachedTo + { + get => _attachedTo; + set + { + CheckDisposed(); + + _attachedTo = (NativeControlHostImpl?)value; + if (_attachedTo == null) + { + _view.RemoveFromSuperview(); + } + else + { + _holder!.View.AddSubview(_view); + } + } + } + + public bool IsCompatibleWith(INativeControlHostImpl host) => host is NativeControlHostImpl; + + public void HideWithSize(Size size) + { + CheckDisposed(); + _view.Hidden = true; + } + + public void ShowInBounds(Rect bounds) + { + CheckDisposed(); + if (_attachedTo == null) + throw new InvalidOperationException("The control isn't currently attached to a toplevel"); + + //bounds = _attachedTo._avaloniaView.ContentScaleFactor; + _view.Frame = new CGRect(bounds.X, bounds.Y, bounds.Width, bounds.Height); + _view.Hidden = false; + } + } + } + + public class UIViewControlHandle : INativeControlHostDestroyableControlHandle, IDisposable + { + internal const string UIViewDescriptor = "UIView"; + + private UIView? _view; + + public UIViewControlHandle(UIView view) + { + _view = view; + } + + public UIView View => _view ?? throw new ObjectDisposedException(nameof(UIViewControlHandle)); + + public string HandleDescriptor => UIViewDescriptor; + + IntPtr IPlatformHandle.Handle => _view?.Handle.Handle ?? default; + + public void Destroy() + { + Dispose(true); + } + + void IDisposable.Dispose() + { + Dispose(true); + } + + ~UIViewControlHandle() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + _view?.Dispose(); + _view = null; + if (disposing) + { + GC.SuppressFinalize(this); + } + } + } +} From fbbd93f4cd19b6b6fa6281ff2a3dad7776324c33 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 10 May 2022 00:50:49 -0400 Subject: [PATCH 067/332] Add android implementation --- Avalonia.sln | 27 +++ .../NativeEmbedSample.Android/MainActivity.cs | 12 ++ .../NativeEmbedSample.Android.csproj | 50 +++++ .../Properties/AndroidManifest.xml | 4 + .../Resources/AboutResources.txt | 44 +++++ .../Resources/drawable/splash_screen.xml | 13 ++ .../Resources/values/colors.xml | 4 + .../Resources/values/styles.xml | 17 ++ .../SplashActivity.cs | 16 ++ .../Android/EmbedSample.Android.cs | 20 +- src/Android/Avalonia.Android/AvaloniaView.cs | 7 +- .../Platform/AndroidNativeControlHostImpl.cs | 187 ++++++++++++++++++ .../Platform/SkiaPlatform/TopLevelImpl.cs | 10 +- 13 files changed, 402 insertions(+), 9 deletions(-) create mode 100644 samples/interop/NativeEmbedSample.Android/MainActivity.cs create mode 100644 samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj create mode 100644 samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml create mode 100644 samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt create mode 100644 samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml create mode 100644 samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml create mode 100644 samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml create mode 100644 samples/interop/NativeEmbedSample.Android/SplashActivity.cs create mode 100644 src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs diff --git a/Avalonia.sln b/Avalonia.sln index 0a33bc4150..4728d25bfa 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -219,6 +219,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.SourceGenerator", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.Android", "samples\interop\NativeEmbedSample.Android\NativeEmbedSample.Android.csproj", "{7D287579-7DB4-4415-A52A-46A5CD6FE30F}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.Desktop", "samples\interop\NativeEmbedSample.Desktop\NativeEmbedSample.Desktop.csproj", "{F2389463-DDB4-4317-B894-D4DF9FF6B763}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.iOS", "samples\interop\NativeEmbedSample.iOS\NativeEmbedSample.iOS.csproj", "{28DB5AD1-656D-4619-BE0B-5B475E138DF8}" @@ -1993,6 +1995,30 @@ Global {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.Build.0 = Release|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhone.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhone.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|Any CPU.Build.0 = Release|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhone.ActiveCfg = Release|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhone.Build.0 = Release|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -2100,6 +2126,7 @@ Global {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {CE910927-CE5A-456F-BC92-E4C757354A5C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} + {7D287579-7DB4-4415-A52A-46A5CD6FE30F} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {F2389463-DDB4-4317-B894-D4DF9FF6B763} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {28DB5AD1-656D-4619-BE0B-5B475E138DF8} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} EndGlobalSection diff --git a/samples/interop/NativeEmbedSample.Android/MainActivity.cs b/samples/interop/NativeEmbedSample.Android/MainActivity.cs new file mode 100644 index 0000000000..5d2e06a330 --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/MainActivity.cs @@ -0,0 +1,12 @@ +using Android.App; +using Android.Content.PM; + +using Avalonia; +using Avalonia.Android; + +namespace NativeEmbedSample.Android; + +[Activity(Label = "NativeEmbedSample", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] +public class MainActivity : AvaloniaActivity +{ +} diff --git a/samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj b/samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj new file mode 100644 index 0000000000..adfd74b9d5 --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj @@ -0,0 +1,50 @@ + + + net6.0-android + 21 + Exe + enable + com.Avalonia.NativeEmbedSample + 1 + 1.0 + apk + true + + + + + + + Resources\drawable\Icon.png + + + + + True + True + True + True + + + + False + False + + + + True + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml b/samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml new file mode 100644 index 0000000000..aa570ec504 --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt b/samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt new file mode 100644 index 0000000000..c2bca974c4 --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt @@ -0,0 +1,44 @@ +Images, layout descriptions, binary blobs and string dictionaries can be included +in your application as resource files. Various Android APIs are designed to +operate on the resource IDs instead of dealing with images, strings or binary blobs +directly. + +For example, a sample Android app that contains a user interface layout (main.axml), +an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) +would keep its resources in the "Resources" directory of the application: + +Resources/ + drawable/ + icon.png + + layout/ + main.axml + + values/ + strings.xml + +In order to get the build system to recognize Android resources, set the build action to +"AndroidResource". The native Android APIs do not operate directly with filenames, but +instead operate on resource IDs. When you compile an Android application that uses resources, +the build system will package the resources for distribution and generate a class called "R" +(this is an Android convention) that contains the tokens for each one of the resources +included. For example, for the above Resources layout, this is what the R class would expose: + +public class R { + public class drawable { + public const int icon = 0x123; + } + + public class layout { + public const int main = 0x456; + } + + public class strings { + public const int first_string = 0xabc; + public const int second_string = 0xbcd; + } +} + +You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main +to reference the layout/main.axml file, or R.strings.first_string to reference the first +string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml b/samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml new file mode 100644 index 0000000000..2e920b4b3b --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml b/samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml new file mode 100644 index 0000000000..59279d5d32 --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml @@ -0,0 +1,4 @@ + + + #FFFFFF + diff --git a/samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml b/samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml new file mode 100644 index 0000000000..2759d2904a --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/samples/interop/NativeEmbedSample.Android/SplashActivity.cs b/samples/interop/NativeEmbedSample.Android/SplashActivity.cs new file mode 100644 index 0000000000..78c555f5c5 --- /dev/null +++ b/samples/interop/NativeEmbedSample.Android/SplashActivity.cs @@ -0,0 +1,16 @@ +using Android.App; +using Android.Content; +using Android.OS; + +namespace NativeEmbedSample.Android; + +[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)] +public class SplashActivity : Activity +{ + protected override void OnResume() + { + base.OnResume(); + + StartActivity(new Intent(Application.Context, typeof(MainActivity))); + } +} diff --git a/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs b/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs index ed3b9aeeb0..4569992f56 100644 --- a/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs +++ b/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs @@ -3,7 +3,6 @@ using System; using System.IO; using System.Diagnostics; using Android.Views; -using Android.Webkit; using Avalonia.Controls.Platform; using Avalonia.Platform; @@ -13,9 +12,24 @@ public partial class EmbedSample { private IPlatformHandle CreateAndroid(IPlatformHandle parent) { - var button = new Android.Widget.Button(Android.App.Application.Context) { Text = "Android button" }; + if (IsSecond) + { + var webView = new Android.Webkit.WebView(Android.App.Application.Context); + webView.LoadUrl("https://www.android.com/"); - return new AndroidViewHandle(button); + return new AndroidViewHandle(webView); + } + else + { + var button = new Android.Widget.Button(Android.App.Application.Context) { Text = "Hello world" }; + var clickCount = 0; + button.Click += (sender, args) => + { + clickCount++; + button.Text = $"Click count {clickCount}"; + }; + return new AndroidViewHandle(button); + } } private void DestroyAndroid(IPlatformHandle control) diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs index 8177cf1f69..be0aa27393 100644 --- a/src/Android/Avalonia.Android/AvaloniaView.cs +++ b/src/Android/Avalonia.Android/AvaloniaView.cs @@ -19,9 +19,8 @@ namespace Avalonia.Android public AvaloniaView(Context context) : base(context) { - _view = new ViewImpl(context); + _view = new ViewImpl(this); AddView(_view.View); - } internal void Prepare () @@ -30,6 +29,8 @@ namespace Avalonia.Android _root.Prepare(); } + internal TopLevelImpl TopLevelImpl => _view; + public object Content { get { return _root.Content; } @@ -73,7 +74,7 @@ namespace Avalonia.Android class ViewImpl : TopLevelImpl { - public ViewImpl(Context context) : base(context) + public ViewImpl(AvaloniaView avaloniaView) : base(avaloniaView) { View.Focusable = true; View.FocusChange += ViewImpl_FocusChange; diff --git a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs new file mode 100644 index 0000000000..57d897f6f5 --- /dev/null +++ b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs @@ -0,0 +1,187 @@ +#nullable enable + +using System; +using System.Diagnostics.CodeAnalysis; +using Android.Views; +using Android.Widget; + +using Avalonia.Controls.Platform; +using Avalonia.Platform; + +namespace Avalonia.Android.Platform +{ + internal class AndroidNativeControlHostImpl : INativeControlHostImpl + { + private readonly AvaloniaView _avaloniaView; + + public AndroidNativeControlHostImpl(AvaloniaView avaloniaView) + { + _avaloniaView = avaloniaView; + } + + public INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHandle parent) + { + return new AndroidViewControlHandle(new FrameLayout(_avaloniaView.Context!), false); + } + + public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) + { + var holder = new AndroidViewControlHandle(_avaloniaView, false); + AndroidNativeControlAttachment? attachment = null; + try + { + var child = create(holder); + // It has to be assigned to the variable before property setter is called so we dispose it on exception +#pragma warning disable IDE0017 // Simplify object initialization + attachment = new AndroidNativeControlAttachment(child); +#pragma warning restore IDE0017 // Simplify object initialization + attachment.AttachedTo = this; + return attachment; + } + catch + { + attachment?.Dispose(); + holder?.Destroy(); + throw; + } + } + + public INativeControlHostControlTopLevelAttachment CreateNewAttachment(IPlatformHandle handle) + { + return new AndroidNativeControlAttachment(handle) + { + AttachedTo = this + }; + } + + public bool IsCompatibleWith(IPlatformHandle handle) => handle.HandleDescriptor == AndroidViewControlHandle.AndroidDescriptor; + + class AndroidNativeControlAttachment : INativeControlHostControlTopLevelAttachment + { + // ReSharper disable once NotAccessedField.Local (keep GC reference) + private IPlatformHandle? _child; + private View? _view; + private AndroidNativeControlHostImpl? _attachedTo; + + public AndroidNativeControlAttachment(IPlatformHandle child) + { + _child = child; + + _view = (child as AndroidViewControlHandle)?.View + ?? Java.Lang.Object.GetObject(child.Handle, global::Android.Runtime.JniHandleOwnership.DoNotTransfer); + } + + [MemberNotNull(nameof(_view))] + private void CheckDisposed() + { + if (_view == null) + throw new ObjectDisposedException(nameof(AndroidNativeControlAttachment)); + } + + public void Dispose() + { + if (_view != null && _attachedTo?._avaloniaView is ViewGroup parent) + { + parent.RemoveView(_view); + } + _child = null; + _attachedTo = null; + _view?.Dispose(); + _view = null; + } + + public INativeControlHostImpl? AttachedTo + { + get => _attachedTo; + set + { + CheckDisposed(); + + var oldAttachedTo = _attachedTo; + _attachedTo = (AndroidNativeControlHostImpl?)value; + if (_attachedTo == null) + { + oldAttachedTo?._avaloniaView.RemoveView(_view); + } + else + { + _attachedTo._avaloniaView.AddView(_view); + } + } + } + + public bool IsCompatibleWith(INativeControlHostImpl host) => host is AndroidNativeControlHostImpl; + + public void HideWithSize(Size size) + { + CheckDisposed(); + _view.Visibility = ViewStates.Gone; + } + + public void ShowInBounds(Rect bounds) + { + CheckDisposed(); + if (_attachedTo == null) + throw new InvalidOperationException("The control isn't currently attached to a toplevel"); + + bounds *= _attachedTo._avaloniaView.TopLevelImpl.RenderScaling; + _view.Visibility = ViewStates.Visible; + _view.LayoutParameters = new FrameLayout.LayoutParams((int)bounds.Width, (int)bounds.Height) + { + LeftMargin = (int)bounds.X, + TopMargin = (int)bounds.Y + }; + _view.RequestLayout(); + } + } + } + + public class AndroidViewControlHandle : INativeControlHostDestroyableControlHandle, IDisposable + { + internal const string AndroidDescriptor = "JavaHandle"; + + private View? _view; + private bool _disposeView; + + public AndroidViewControlHandle(View view, bool disposeView) + { + _view = view; + _disposeView = disposeView; + } + + public View View => _view ?? throw new ObjectDisposedException(nameof(AndroidViewControlHandle)); + + public string HandleDescriptor => AndroidDescriptor; + + IntPtr IPlatformHandle.Handle => _view?.Handle ?? default; + + public void Destroy() + { + Dispose(true); + } + + void IDisposable.Dispose() + { + Dispose(true); + } + + ~AndroidViewControlHandle() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + if (_disposeView) + { + _view?.Dispose(); + } + + _view = null; + if (disposing) + { + GC.SuppressFinalize(this); + } + } + } +} diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 8a475676a5..dbcc9bccdd 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -20,7 +20,7 @@ using Avalonia.Rendering; namespace Avalonia.Android.Platform.SkiaPlatform { - class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo, ITopLevelImplWithTextInputMethod + class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo, ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost { private readonly IGlPlatformSurface _gl; private readonly IFramebufferPlatformSurface _framebuffer; @@ -30,9 +30,9 @@ namespace Avalonia.Android.Platform.SkiaPlatform private readonly ITextInputMethodImpl _textInputMethod; private ViewImpl _view; - public TopLevelImpl(Context context, bool placeOnTop = false) + public TopLevelImpl(AvaloniaView avaloniaView, bool placeOnTop = false) { - _view = new ViewImpl(context, this, placeOnTop); + _view = new ViewImpl(avaloniaView.Context, this, placeOnTop); _textInputMethod = new AndroidInputMethod(_view); _keyboardHelper = new AndroidKeyboardEventsHelper(this); _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, @@ -44,6 +44,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels, _view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling); + + NativeControlHost = new AndroidNativeControlHostImpl(avaloniaView); } public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex) => @@ -222,6 +224,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform public ITextInputMethodImpl TextInputMethod => _textInputMethod; + public INativeControlHostImpl NativeControlHost { get; } + public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { throw new NotImplementedException(); From 7af062e8ba67b8ff8538c8192867ec6de05678ce Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 10 May 2022 00:51:22 -0400 Subject: [PATCH 068/332] Respect actual AttachedTo in ios control host --- src/iOS/Avalonia.iOS/NativeControlHostImpl.cs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs index c5c632e7f7..fc5c90fa4c 100644 --- a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs +++ b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs @@ -21,19 +21,19 @@ namespace Avalonia.iOS public INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHandle parent) { - return new UIViewControlHandle(new UIView()); + return new UIViewControlHandle(new UIView(), true); } public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) { - var holder = new UIViewControlHandle(_avaloniaView); + var holder = new UIViewControlHandle(_avaloniaView, false); NativeControlAttachment? attachment = null; try { var child = create(holder); // It has to be assigned to the variable before property setter is called so we dispose it on exception #pragma warning disable IDE0017 // Simplify object initialization - attachment = new NativeControlAttachment(holder, child); + attachment = new NativeControlAttachment(child); #pragma warning restore IDE0017 // Simplify object initialization attachment.AttachedTo = this; return attachment; @@ -48,7 +48,7 @@ namespace Avalonia.iOS public INativeControlHostControlTopLevelAttachment CreateNewAttachment(IPlatformHandle handle) { - return new NativeControlAttachment(new UIViewControlHandle(_avaloniaView), handle) + return new NativeControlAttachment(handle) { AttachedTo = this }; @@ -68,17 +68,14 @@ namespace Avalonia.iOS { // ReSharper disable once NotAccessedField.Local (keep GC reference) private IPlatformHandle? _child; - private UIViewControlHandle? _holder; private UIView? _view; private NativeControlHostImpl? _attachedTo; - public NativeControlAttachment(UIViewControlHandle holder, IPlatformHandle child) + public NativeControlAttachment(IPlatformHandle child) { - _holder = holder; _child = child; _view = (child as UIViewControlHandle)?.View ?? new ViewHolder(child.Handle); - _holder.View.AddSubview(_view); } [MemberNotNull(nameof(_view))] @@ -91,7 +88,6 @@ namespace Avalonia.iOS public void Dispose() { _view?.RemoveFromSuperview(); - _holder = null; _child = null; _attachedTo = null; _view?.Dispose(); @@ -112,7 +108,7 @@ namespace Avalonia.iOS } else { - _holder!.View.AddSubview(_view); + _attachedTo._avaloniaView.AddSubview(_view); } } } @@ -131,7 +127,6 @@ namespace Avalonia.iOS if (_attachedTo == null) throw new InvalidOperationException("The control isn't currently attached to a toplevel"); - //bounds = _attachedTo._avaloniaView.ContentScaleFactor; _view.Frame = new CGRect(bounds.X, bounds.Y, bounds.Width, bounds.Height); _view.Hidden = false; } @@ -143,10 +138,12 @@ namespace Avalonia.iOS internal const string UIViewDescriptor = "UIView"; private UIView? _view; + private bool _disposeView; - public UIViewControlHandle(UIView view) + public UIViewControlHandle(UIView view, bool disposeView) { _view = view; + _disposeView = disposeView; } public UIView View => _view ?? throw new ObjectDisposedException(nameof(UIViewControlHandle)); @@ -172,7 +169,11 @@ namespace Avalonia.iOS private void Dispose(bool disposing) { - _view?.Dispose(); + if (_disposeView) + { + _view?.Dispose(); + } + _view = null; if (disposing) { From 76c3691fb6b3db593e50a1811e06c2bdb8a86ad0 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 10 May 2022 16:11:16 -0400 Subject: [PATCH 069/332] Resize on HideWithSize --- .../Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs | 4 +++- src/iOS/Avalonia.iOS/NativeControlHostImpl.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs index 57d897f6f5..747c0489ea 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs @@ -116,6 +116,8 @@ namespace Avalonia.Android.Platform { CheckDisposed(); _view.Visibility = ViewStates.Gone; + _view.LayoutParameters = new ViewGroup.LayoutParams(Math.Max(1, (int)size.Width), Math.Max(1, (int)size.Height)); + _view.RequestLayout(); } public void ShowInBounds(Rect bounds) @@ -126,7 +128,7 @@ namespace Avalonia.Android.Platform bounds *= _attachedTo._avaloniaView.TopLevelImpl.RenderScaling; _view.Visibility = ViewStates.Visible; - _view.LayoutParameters = new FrameLayout.LayoutParams((int)bounds.Width, (int)bounds.Height) + _view.LayoutParameters = new ViewGroup.MarginLayoutParams(Math.Max(1, (int)bounds.Width), Math.Max(1, (int)bounds.Height)) { LeftMargin = (int)bounds.X, TopMargin = (int)bounds.Y diff --git a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs index fc5c90fa4c..fc0244fe59 100644 --- a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs +++ b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs @@ -118,7 +118,9 @@ namespace Avalonia.iOS public void HideWithSize(Size size) { CheckDisposed(); + _view.Hidden = true; + _view.Frame = new CGRect(0d, 0d, Math.Max(1d, size.Width), Math.Max(1d, size.Height)); } public void ShowInBounds(Rect bounds) @@ -127,7 +129,7 @@ namespace Avalonia.iOS if (_attachedTo == null) throw new InvalidOperationException("The control isn't currently attached to a toplevel"); - _view.Frame = new CGRect(bounds.X, bounds.Y, bounds.Width, bounds.Height); + _view.Frame = new CGRect(bounds.X, bounds.Y, Math.Max(1d, bounds.Width), Math.Max(1d, bounds.Height)); _view.Hidden = false; } } From 626082970212691af54281d84d65b82f84b50e3e Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 10 May 2022 16:19:06 -0400 Subject: [PATCH 070/332] Simplify UIViewControlHandle/AndroidViewControlHandle --- Avalonia.sln | 55 ++++++++-------- .../Android/EmbedSample.Android.cs | 42 +++--------- .../NativeEmbedSample.csproj | 6 ++ .../NativeEmbedSample/iOS/EmbedSample.iOS.cs | 28 +------- .../AndroidViewControlHandle.cs | 32 ++++++++++ .../Platform/AndroidNativeControlHostImpl.cs | 64 ++----------------- src/iOS/Avalonia.iOS/NativeControlHostImpl.cs | 50 ++++----------- 7 files changed, 94 insertions(+), 183 deletions(-) create mode 100644 src/Android/Avalonia.Android/AndroidViewControlHandle.cs diff --git a/Avalonia.sln b/Avalonia.sln index 4728d25bfa..4432e572bb 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -219,11 +219,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.SourceGenerator", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.Android", "samples\interop\NativeEmbedSample.Android\NativeEmbedSample.Android.csproj", "{7D287579-7DB4-4415-A52A-46A5CD6FE30F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeEmbedSample.Android", "samples\interop\NativeEmbedSample.Android\NativeEmbedSample.Android.csproj", "{7D287579-7DB4-4415-A52A-46A5CD6FE30F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.Desktop", "samples\interop\NativeEmbedSample.Desktop\NativeEmbedSample.Desktop.csproj", "{F2389463-DDB4-4317-B894-D4DF9FF6B763}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeEmbedSample.Desktop", "samples\interop\NativeEmbedSample.Desktop\NativeEmbedSample.Desktop.csproj", "{F2389463-DDB4-4317-B894-D4DF9FF6B763}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NativeEmbedSample.iOS", "samples\interop\NativeEmbedSample.iOS\NativeEmbedSample.iOS.csproj", "{28DB5AD1-656D-4619-BE0B-5B475E138DF8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeEmbedSample.iOS", "samples\interop\NativeEmbedSample.iOS\NativeEmbedSample.iOS.csproj", "{28DB5AD1-656D-4619-BE0B-5B475E138DF8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1419,6 +1419,30 @@ Global {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhone.Build.0 = Release|Any CPU {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.Build.0 = Release|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.ActiveCfg = Release|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.Build.0 = Release|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -1971,30 +1995,6 @@ Global {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhone.Build.0 = Release|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.Build.0 = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.ActiveCfg = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.Build.0 = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -2009,6 +2009,7 @@ Global {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhone.ActiveCfg = Debug|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhone.Build.0 = Debug|Any CPU {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU diff --git a/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs b/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs index 4569992f56..a4bd9b329b 100644 --- a/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs +++ b/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs @@ -1,10 +1,6 @@ #if __ANDROID__ || ANDROID -using System; -using System.IO; -using System.Diagnostics; -using Android.Views; -using Avalonia.Controls.Platform; using Avalonia.Platform; +using Avalonia.Android; namespace NativeEmbedSample; @@ -12,23 +8,27 @@ public partial class EmbedSample { private IPlatformHandle CreateAndroid(IPlatformHandle parent) { + var parentContext = (parent as AndroidViewControlHandle)?.View.Context + ?? Android.App.Application.Context; + if (IsSecond) { - var webView = new Android.Webkit.WebView(Android.App.Application.Context); + var webView = new Android.Webkit.WebView(parentContext); webView.LoadUrl("https://www.android.com/"); - return new AndroidViewHandle(webView); + return new AndroidViewControlHandle(webView); } else { - var button = new Android.Widget.Button(Android.App.Application.Context) { Text = "Hello world" }; + var button = new Android.Widget.Button(parentContext) { Text = "Hello world" }; var clickCount = 0; button.Click += (sender, args) => { clickCount++; button.Text = $"Click count {clickCount}"; }; - return new AndroidViewHandle(button); + + return new AndroidViewControlHandle(button); } } @@ -37,28 +37,4 @@ public partial class EmbedSample base.DestroyNativeControlCore(control); } } - -internal sealed class AndroidViewHandle : INativeControlHostDestroyableControlHandle -{ - private View _view; - - public AndroidViewHandle(View view) - { - _view = view; - } - - public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; - public string HandleDescriptor => "JavaHandle"; - - public void Destroy() - { - _view?.Dispose(); - _view = null; - } - - ~AndroidViewHandle() - { - Destroy(); - } -} #endif diff --git a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj index 34206c2b63..7783b6f43d 100644 --- a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj +++ b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj @@ -27,6 +27,12 @@ PreserveNewest + + + + + + diff --git a/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs b/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs index 185c2e6b9f..c5996e7deb 100644 --- a/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs +++ b/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs @@ -1,13 +1,10 @@ #if IOS -using System; -using System.IO; -using System.Diagnostics; -using Avalonia.Controls.Platform; using Avalonia.Platform; using CoreGraphics; using Foundation; using UIKit; using WebKit; +using Avalonia.iOS; namespace NativeEmbedSample; @@ -20,7 +17,7 @@ public partial class EmbedSample var webView = new WKWebView(CGRect.Empty, new WKWebViewConfiguration()); webView.LoadRequest(new NSUrlRequest(new NSUrl("https://www.apple.com/"))); - return new UIViewHandle(webView); + return new UIViewControlHandle(webView); } else { @@ -34,7 +31,7 @@ public partial class EmbedSample button.SetTitle($"Click count {clickCount}", UIControlState.Normal); }, UIControlEvent.TouchDown); - return new UIViewHandle(button); + return new UIViewControlHandle(button); } } @@ -43,23 +40,4 @@ public partial class EmbedSample base.DestroyNativeControlCore(control); } } - -internal class UIViewHandle : INativeControlHostDestroyableControlHandle -{ - private UIView _view; - - public UIViewHandle(UIView view) - { - _view = view; - } - - public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; - public string HandleDescriptor => "UIView"; - - public void Destroy() - { - _view?.Dispose(); - _view = null; - } -} #endif diff --git a/src/Android/Avalonia.Android/AndroidViewControlHandle.cs b/src/Android/Avalonia.Android/AndroidViewControlHandle.cs new file mode 100644 index 0000000000..e999d198c6 --- /dev/null +++ b/src/Android/Avalonia.Android/AndroidViewControlHandle.cs @@ -0,0 +1,32 @@ +#nullable enable + +using System; + +using Android.Views; + +using Avalonia.Controls.Platform; +using Avalonia.Platform; + +namespace Avalonia.Android +{ + public class AndroidViewControlHandle : INativeControlHostDestroyableControlHandle + { + internal const string AndroidDescriptor = "JavaObjectHandle"; + + public AndroidViewControlHandle(View view) + { + View = view; + } + + public View View { get; } + + public string HandleDescriptor => AndroidDescriptor; + + IntPtr IPlatformHandle.Handle => View.Handle; + + public void Destroy() + { + View?.Dispose(); + } + } +} diff --git a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs index 747c0489ea..b5563d9625 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics.CodeAnalysis; + using Android.Views; using Android.Widget; @@ -21,16 +22,16 @@ namespace Avalonia.Android.Platform public INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHandle parent) { - return new AndroidViewControlHandle(new FrameLayout(_avaloniaView.Context!), false); + return new AndroidViewControlHandle(new FrameLayout(_avaloniaView.Context!)); } public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) { - var holder = new AndroidViewControlHandle(_avaloniaView, false); + var parent = new AndroidViewControlHandle(_avaloniaView); AndroidNativeControlAttachment? attachment = null; try { - var child = create(holder); + var child = create(parent); // It has to be assigned to the variable before property setter is called so we dispose it on exception #pragma warning disable IDE0017 // Simplify object initialization attachment = new AndroidNativeControlAttachment(child); @@ -41,7 +42,6 @@ namespace Avalonia.Android.Platform catch { attachment?.Dispose(); - holder?.Destroy(); throw; } } @@ -56,17 +56,13 @@ namespace Avalonia.Android.Platform public bool IsCompatibleWith(IPlatformHandle handle) => handle.HandleDescriptor == AndroidViewControlHandle.AndroidDescriptor; - class AndroidNativeControlAttachment : INativeControlHostControlTopLevelAttachment + private class AndroidNativeControlAttachment : INativeControlHostControlTopLevelAttachment { - // ReSharper disable once NotAccessedField.Local (keep GC reference) - private IPlatformHandle? _child; private View? _view; private AndroidNativeControlHostImpl? _attachedTo; public AndroidNativeControlAttachment(IPlatformHandle child) { - _child = child; - _view = (child as AndroidViewControlHandle)?.View ?? Java.Lang.Object.GetObject(child.Handle, global::Android.Runtime.JniHandleOwnership.DoNotTransfer); } @@ -84,7 +80,6 @@ namespace Avalonia.Android.Platform { parent.RemoveView(_view); } - _child = null; _attachedTo = null; _view?.Dispose(); _view = null; @@ -137,53 +132,4 @@ namespace Avalonia.Android.Platform } } } - - public class AndroidViewControlHandle : INativeControlHostDestroyableControlHandle, IDisposable - { - internal const string AndroidDescriptor = "JavaHandle"; - - private View? _view; - private bool _disposeView; - - public AndroidViewControlHandle(View view, bool disposeView) - { - _view = view; - _disposeView = disposeView; - } - - public View View => _view ?? throw new ObjectDisposedException(nameof(AndroidViewControlHandle)); - - public string HandleDescriptor => AndroidDescriptor; - - IntPtr IPlatformHandle.Handle => _view?.Handle ?? default; - - public void Destroy() - { - Dispose(true); - } - - void IDisposable.Dispose() - { - Dispose(true); - } - - ~AndroidViewControlHandle() - { - Dispose(false); - } - - private void Dispose(bool disposing) - { - if (_disposeView) - { - _view?.Dispose(); - } - - _view = null; - if (disposing) - { - GC.SuppressFinalize(this); - } - } - } } diff --git a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs index fc0244fe59..d477f81a53 100644 --- a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs +++ b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs @@ -21,16 +21,16 @@ namespace Avalonia.iOS public INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHandle parent) { - return new UIViewControlHandle(new UIView(), true); + return new UIViewControlHandle(new UIView()); } public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) { - var holder = new UIViewControlHandle(_avaloniaView, false); + var parent = new UIViewControlHandle(_avaloniaView); NativeControlAttachment? attachment = null; try { - var child = create(holder); + var child = create(parent); // It has to be assigned to the variable before property setter is called so we dispose it on exception #pragma warning disable IDE0017 // Simplify object initialization attachment = new NativeControlAttachment(child); @@ -41,7 +41,6 @@ namespace Avalonia.iOS catch { attachment?.Dispose(); - holder?.Destroy(); throw; } } @@ -134,53 +133,26 @@ namespace Avalonia.iOS } } } - - public class UIViewControlHandle : INativeControlHostDestroyableControlHandle, IDisposable + + public class UIViewControlHandle : INativeControlHostDestroyableControlHandle { internal const string UIViewDescriptor = "UIView"; + - private UIView? _view; - private bool _disposeView; - - public UIViewControlHandle(UIView view, bool disposeView) + public UIViewControlHandle(UIView view) { - _view = view; - _disposeView = disposeView; + View = view; } - public UIView View => _view ?? throw new ObjectDisposedException(nameof(UIViewControlHandle)); + public UIView View { get; } public string HandleDescriptor => UIViewDescriptor; - IntPtr IPlatformHandle.Handle => _view?.Handle.Handle ?? default; + IntPtr IPlatformHandle.Handle => View.Handle.Handle; public void Destroy() { - Dispose(true); - } - - void IDisposable.Dispose() - { - Dispose(true); - } - - ~UIViewControlHandle() - { - Dispose(false); - } - - private void Dispose(bool disposing) - { - if (_disposeView) - { - _view?.Dispose(); - } - - _view = null; - if (disposing) - { - GC.SuppressFinalize(this); - } + View.Dispose(); } } } From 4315f4728f75a0103662a682b4b7553ced5c694c Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 10 May 2022 16:37:24 -0400 Subject: [PATCH 071/332] Fix android type exception --- .../Platform/AndroidNativeControlHostImpl.cs | 6 ++++-- src/iOS/Avalonia.iOS/NativeControlHostImpl.cs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs index b5563d9625..7d12404090 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs @@ -110,8 +110,10 @@ namespace Avalonia.Android.Platform public void HideWithSize(Size size) { CheckDisposed(); + + size *= _attachedTo?._avaloniaView.TopLevelImpl.RenderScaling ?? 1; _view.Visibility = ViewStates.Gone; - _view.LayoutParameters = new ViewGroup.LayoutParams(Math.Max(1, (int)size.Width), Math.Max(1, (int)size.Height)); + _view.LayoutParameters = new FrameLayout.LayoutParams(Math.Max(1, (int)size.Width), Math.Max(1, (int)size.Height)); _view.RequestLayout(); } @@ -123,7 +125,7 @@ namespace Avalonia.Android.Platform bounds *= _attachedTo._avaloniaView.TopLevelImpl.RenderScaling; _view.Visibility = ViewStates.Visible; - _view.LayoutParameters = new ViewGroup.MarginLayoutParams(Math.Max(1, (int)bounds.Width), Math.Max(1, (int)bounds.Height)) + _view.LayoutParameters = new FrameLayout.LayoutParams(Math.Max(1, (int)bounds.Width), Math.Max(1, (int)bounds.Height)) { LeftMargin = (int)bounds.X, TopMargin = (int)bounds.Y diff --git a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs index d477f81a53..f752936dc8 100644 --- a/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs +++ b/src/iOS/Avalonia.iOS/NativeControlHostImpl.cs @@ -117,6 +117,8 @@ namespace Avalonia.iOS public void HideWithSize(Size size) { CheckDisposed(); + if (_attachedTo == null) + return; _view.Hidden = true; _view.Frame = new CGRect(0d, 0d, Math.Max(1d, size.Width), Math.Max(1d, size.Height)); From 57e852dfc1b47a62c86df14e0f93e5bea94371c8 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 11 May 2022 00:04:05 -0400 Subject: [PATCH 072/332] Move native control samples to the control catalog --- Avalonia.sln | 111 +---------------- .../EmbedSample.Android.cs | 23 ++-- .../ControlCatalog.Android/MainActivity.cs | 6 +- .../ControlCatalog.NetCore.csproj | 13 ++ .../NativeControls}/Gtk/EmbedSample.Gtk.cs | 22 ++-- .../NativeControls}/Gtk/GtkHelper.cs | 8 +- .../NativeControls}/Gtk/nodes-license.md | 0 .../NativeControls}/Gtk/nodes.mp4 | Bin .../NativeControls}/Mac/EmbedSample.Mac.cs | 21 ++-- .../NativeControls}/Mac/MacHelper.cs | 11 +- .../NativeControls}/Win/EmbedSample.Win.cs | 26 ++-- .../NativeControls}/Win/WinApi.cs | 4 +- samples/ControlCatalog.NetCore/Program.cs | 8 +- samples/ControlCatalog.iOS/AppDelegate.cs | 9 +- .../EmbedSample.iOS.cs | 17 +-- samples/ControlCatalog/ControlCatalog.csproj | 15 +++ samples/ControlCatalog/MainView.xaml | 7 +- .../Pages/NativeEmbedPage.xaml} | 22 ++-- .../Pages/NativeEmbedPage.xaml.cs | 84 +++++++++++++ .../NativeEmbedSample.Android/MainActivity.cs | 12 -- .../NativeEmbedSample.Android.csproj | 50 -------- .../Properties/AndroidManifest.xml | 4 - .../Resources/AboutResources.txt | 44 ------- .../Resources/drawable/splash_screen.xml | 13 -- .../Resources/values/colors.xml | 4 - .../Resources/values/styles.xml | 17 --- .../SplashActivity.cs | 16 --- .../NativeEmbedSample.Desktop.csproj | 15 --- .../NativeEmbedSample.Desktop/Program.cs | 17 --- .../NativeEmbedSample.iOS/AppDelegate.cs | 9 -- .../AppIcon.appiconset/Contents.json | 117 ------------------ .../AppIcon.appiconset/Icon1024.png | Bin 70429 -> 0 bytes .../AppIcon.appiconset/Icon120.png | Bin 3773 -> 0 bytes .../AppIcon.appiconset/Icon152.png | Bin 4750 -> 0 bytes .../AppIcon.appiconset/Icon167.png | Bin 4692 -> 0 bytes .../AppIcon.appiconset/Icon180.png | Bin 5192 -> 0 bytes .../AppIcon.appiconset/Icon20.png | Bin 1313 -> 0 bytes .../AppIcon.appiconset/Icon29.png | Bin 845 -> 0 bytes .../AppIcon.appiconset/Icon40.png | Bin 1101 -> 0 bytes .../AppIcon.appiconset/Icon58.png | Bin 1761 -> 0 bytes .../AppIcon.appiconset/Icon60.png | Bin 2537 -> 0 bytes .../AppIcon.appiconset/Icon76.png | Bin 2332 -> 0 bytes .../AppIcon.appiconset/Icon80.png | Bin 2454 -> 0 bytes .../AppIcon.appiconset/Icon87.png | Bin 2758 -> 0 bytes .../NativeEmbedSample.iOS/Entitlements.plist | 6 - .../interop/NativeEmbedSample.iOS/Info.plist | 42 ------- samples/interop/NativeEmbedSample.iOS/Main.cs | 6 - .../NativeEmbedSample.iOS.csproj | 16 --- .../Resources/LaunchScreen.xib | 43 ------- samples/interop/NativeEmbedSample/App.axaml | 7 -- .../interop/NativeEmbedSample/App.axaml.cs | 23 ---- .../interop/NativeEmbedSample/EmbedSample.cs | 54 -------- .../NativeEmbedSample/MainView.axaml.cs | 45 ------- .../NativeEmbedSample/MainWindow.axaml | 10 -- .../NativeEmbedSample/MainWindow.axaml.cs | 17 --- .../NativeEmbedSample.csproj | 38 ------ .../Platform/AndroidNativeControlHostImpl.cs | 4 +- 57 files changed, 211 insertions(+), 825 deletions(-) rename samples/{interop/NativeEmbedSample/Android => ControlCatalog.Android}/EmbedSample.Android.cs (52%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Gtk/EmbedSample.Gtk.cs (63%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Gtk/GtkHelper.cs (91%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Gtk/nodes-license.md (100%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Gtk/nodes.mp4 (100%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Mac/EmbedSample.Mac.cs (60%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Mac/MacHelper.cs (76%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Win/EmbedSample.Win.cs (62%) rename samples/{interop/NativeEmbedSample => ControlCatalog.NetCore/NativeControls}/Win/WinApi.cs (98%) rename samples/{interop/NativeEmbedSample/iOS => ControlCatalog.iOS}/EmbedSample.iOS.cs (75%) rename samples/{interop/NativeEmbedSample/MainView.axaml => ControlCatalog/Pages/NativeEmbedPage.xaml} (82%) create mode 100644 samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs delete mode 100644 samples/interop/NativeEmbedSample.Android/MainActivity.cs delete mode 100644 samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj delete mode 100644 samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml delete mode 100644 samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt delete mode 100644 samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml delete mode 100644 samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml delete mode 100644 samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml delete mode 100644 samples/interop/NativeEmbedSample.Android/SplashActivity.cs delete mode 100644 samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj delete mode 100644 samples/interop/NativeEmbedSample.Desktop/Program.cs delete mode 100644 samples/interop/NativeEmbedSample.iOS/AppDelegate.cs delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png delete mode 100644 samples/interop/NativeEmbedSample.iOS/Entitlements.plist delete mode 100644 samples/interop/NativeEmbedSample.iOS/Info.plist delete mode 100644 samples/interop/NativeEmbedSample.iOS/Main.cs delete mode 100644 samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj delete mode 100644 samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib delete mode 100644 samples/interop/NativeEmbedSample/App.axaml delete mode 100644 samples/interop/NativeEmbedSample/App.axaml.cs delete mode 100644 samples/interop/NativeEmbedSample/EmbedSample.cs delete mode 100644 samples/interop/NativeEmbedSample/MainView.axaml.cs delete mode 100644 samples/interop/NativeEmbedSample/MainWindow.axaml delete mode 100644 samples/interop/NativeEmbedSample/MainWindow.axaml.cs delete mode 100644 samples/interop/NativeEmbedSample/NativeEmbedSample.csproj diff --git a/Avalonia.sln b/Avalonia.sln index 4432e572bb..c3554a7447 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -97,6 +97,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\DevAnalyzers.props = build\DevAnalyzers.props build\EmbedXaml.props = build\EmbedXaml.props build\HarfBuzzSharp.props = build\HarfBuzzSharp.props + build\ImageSharp.props = build\ImageSharp.props build\JetBrains.Annotations.props = build\JetBrains.Annotations.props build\JetBrains.dotMemoryUnit.props = build\JetBrains.dotMemoryUnit.props build\Microsoft.CSharp.props = build\Microsoft.CSharp.props @@ -117,7 +118,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1 build\System.Memory.props = build\System.Memory.props build\UnitTests.NetFX.props = build\UnitTests.NetFX.props build\XUnit.props = build\XUnit.props - build\ImageSharp.props = build\ImageSharp.props EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}" @@ -179,8 +179,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.FreeDesktop", "src EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.DataGrid.UnitTests", "tests\Avalonia.Controls.DataGrid.UnitTests\Avalonia.Controls.DataGrid.UnitTests.csproj", "{351337F5-D66F-461B-A957-4EF60BDB4BA6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeEmbedSample", "samples\interop\NativeEmbedSample\NativeEmbedSample.csproj", "{3C84E04B-36CF-4D0D-B965-C26DD649D1F3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Themes.Fluent", "src\Avalonia.Themes.Fluent\Avalonia.Themes.Fluent.csproj", "{C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Headless", "src\Avalonia.Headless\Avalonia.Headless.csproj", "{8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}" @@ -219,12 +217,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.SourceGenerator", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeEmbedSample.Android", "samples\interop\NativeEmbedSample.Android\NativeEmbedSample.Android.csproj", "{7D287579-7DB4-4415-A52A-46A5CD6FE30F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeEmbedSample.Desktop", "samples\interop\NativeEmbedSample.Desktop\NativeEmbedSample.Desktop.csproj", "{F2389463-DDB4-4317-B894-D4DF9FF6B763}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NativeEmbedSample.iOS", "samples\interop\NativeEmbedSample.iOS\NativeEmbedSample.iOS.csproj", "{28DB5AD1-656D-4619-BE0B-5B475E138DF8}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -1539,30 +1531,6 @@ Global {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhone.Build.0 = Release|Any CPU {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhone.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhone.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|Any CPU.Build.0 = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhone.ActiveCfg = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhone.Build.0 = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -1995,79 +1963,6 @@ Global {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhone.Build.0 = Release|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhone.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhone.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|Any CPU.Build.0 = Release|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhone.ActiveCfg = Release|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhone.Build.0 = Release|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7D287579-7DB4-4415-A52A-46A5CD6FE30F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhone.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhone.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|Any CPU.Build.0 = Release|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhone.ActiveCfg = Release|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhone.Build.0 = Release|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F2389463-DDB4-4317-B894-D4DF9FF6B763}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhone.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhone.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|Any CPU.Build.0 = Release|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhone.ActiveCfg = Release|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhone.Build.0 = Release|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {28DB5AD1-656D-4619-BE0B-5B475E138DF8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2114,7 +2009,6 @@ Global {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C} {11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098} {BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098} @@ -2127,9 +2021,6 @@ Global {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098} {CE910927-CE5A-456F-BC92-E4C757354A5C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} - {7D287579-7DB4-4415-A52A-46A5CD6FE30F} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} - {F2389463-DDB4-4317-B894-D4DF9FF6B763} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} - {28DB5AD1-656D-4619-BE0B-5B475E138DF8} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs b/samples/ControlCatalog.Android/EmbedSample.Android.cs similarity index 52% rename from samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs rename to samples/ControlCatalog.Android/EmbedSample.Android.cs index a4bd9b329b..250121fc53 100644 --- a/samples/interop/NativeEmbedSample/Android/EmbedSample.Android.cs +++ b/samples/ControlCatalog.Android/EmbedSample.Android.cs @@ -1,26 +1,27 @@ -#if __ANDROID__ || ANDROID +using System; using Avalonia.Platform; using Avalonia.Android; +using ControlCatalog.Pages; -namespace NativeEmbedSample; +namespace ControlCatalog.Android; -public partial class EmbedSample +public class EmbedSampleAndroid : INativeDemoControl { - private IPlatformHandle CreateAndroid(IPlatformHandle parent) + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) { var parentContext = (parent as AndroidViewControlHandle)?.View.Context - ?? Android.App.Application.Context; + ?? global::Android.App.Application.Context; - if (IsSecond) + if (isSecond) { - var webView = new Android.Webkit.WebView(parentContext); + var webView = new global::Android.Webkit.WebView(parentContext); webView.LoadUrl("https://www.android.com/"); return new AndroidViewControlHandle(webView); } else { - var button = new Android.Widget.Button(parentContext) { Text = "Hello world" }; + var button = new global::Android.Widget.Button(parentContext) { Text = "Hello world" }; var clickCount = 0; button.Click += (sender, args) => { @@ -31,10 +32,4 @@ public partial class EmbedSample return new AndroidViewControlHandle(button); } } - - private void DestroyAndroid(IPlatformHandle control) - { - base.DestroyNativeControlCore(control); - } } -#endif diff --git a/samples/ControlCatalog.Android/MainActivity.cs b/samples/ControlCatalog.Android/MainActivity.cs index 44290d9816..33ca511340 100644 --- a/samples/ControlCatalog.Android/MainActivity.cs +++ b/samples/ControlCatalog.Android/MainActivity.cs @@ -10,7 +10,11 @@ namespace ControlCatalog.Android { protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) { - return base.CustomizeAppBuilder(builder); + return base.CustomizeAppBuilder(builder) + .AfterSetup(_ => + { + Pages.EmbedSample.Implementation = new EmbedSampleAndroid(); + }); } } } diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj index 2b45ac1508..2db150ec85 100644 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj @@ -4,6 +4,7 @@ WinExe net6.0 true + true @@ -12,6 +13,16 @@ 7.0.0-* + + + + + + + PreserveNewest + + + @@ -20,6 +31,8 @@ + + diff --git a/samples/interop/NativeEmbedSample/Gtk/EmbedSample.Gtk.cs b/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs similarity index 63% rename from samples/interop/NativeEmbedSample/Gtk/EmbedSample.Gtk.cs rename to samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs index 24c9deca36..521d3674eb 100644 --- a/samples/interop/NativeEmbedSample/Gtk/EmbedSample.Gtk.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Gtk/EmbedSample.Gtk.cs @@ -1,24 +1,26 @@ -#if DESKTOP using System.IO; using System.Diagnostics; using Avalonia.Platform; +using Avalonia.Controls.Platform; +using System; +using ControlCatalog.Pages; -namespace NativeEmbedSample; +namespace ControlCatalog.NetCore; -public partial class EmbedSample +public class EmbedSampleGtk : INativeDemoControl { private Process _mplayer; - IPlatformHandle CreateLinux(IPlatformHandle parent) + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) { - if (IsSecond) + if (isSecond) { var chooser = GtkHelper.CreateGtkFileChooser(parent.Handle); if (chooser != null) return chooser; } - var control = base.CreateNativeControlCore(parent); + var control = createDefault(); var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, "..", "nodes.mp4")); @@ -30,12 +32,4 @@ public partial class EmbedSample }); return control; } - - void DestroyLinux(IPlatformHandle handle) - { - _mplayer?.Kill(); - _mplayer = null; - base.DestroyNativeControlCore(handle); - } } -#endif diff --git a/samples/interop/NativeEmbedSample/Gtk/GtkHelper.cs b/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs similarity index 91% rename from samples/interop/NativeEmbedSample/Gtk/GtkHelper.cs rename to samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs index 567bc25acb..456f77a44d 100644 --- a/samples/interop/NativeEmbedSample/Gtk/GtkHelper.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Gtk/GtkHelper.cs @@ -1,15 +1,12 @@ -#if DESKTOP - using System; using System.Threading.Tasks; using Avalonia.Controls.Platform; -using Avalonia.Platform; using Avalonia.Platform.Interop; using Avalonia.X11.NativeDialogs; using static Avalonia.X11.NativeDialogs.Gtk; using static Avalonia.X11.NativeDialogs.Glib; -namespace NativeEmbedSample; +namespace ControlCatalog.NetCore; internal class GtkHelper { @@ -39,7 +36,7 @@ internal class GtkHelper } - public static IPlatformHandle CreateGtkFileChooser(IntPtr parentXid) + public static INativeControlHostDestroyableControlHandle CreateGtkFileChooser(IntPtr parentXid) { if (s_gtkTask == null) s_gtkTask = StartGtk(); @@ -59,4 +56,3 @@ internal class GtkHelper }).Result; } } -#endif diff --git a/samples/interop/NativeEmbedSample/Gtk/nodes-license.md b/samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes-license.md similarity index 100% rename from samples/interop/NativeEmbedSample/Gtk/nodes-license.md rename to samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes-license.md diff --git a/samples/interop/NativeEmbedSample/Gtk/nodes.mp4 b/samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes.mp4 similarity index 100% rename from samples/interop/NativeEmbedSample/Gtk/nodes.mp4 rename to samples/ControlCatalog.NetCore/NativeControls/Gtk/nodes.mp4 diff --git a/samples/interop/NativeEmbedSample/Mac/EmbedSample.Mac.cs b/samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs similarity index 60% rename from samples/interop/NativeEmbedSample/Mac/EmbedSample.Mac.cs rename to samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs index 911a874c27..7967c9c073 100644 --- a/samples/interop/NativeEmbedSample/Mac/EmbedSample.Mac.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Mac/EmbedSample.Mac.cs @@ -1,14 +1,18 @@ -#if DESKTOP +using System; + using Avalonia.Platform; using Avalonia.Threading; + +using ControlCatalog.Pages; + using MonoMac.Foundation; using MonoMac.WebKit; -namespace NativeEmbedSample; +namespace ControlCatalog.NetCore; -public partial class EmbedSample +public class EmbedSampleMac : INativeDemoControl { - IPlatformHandle CreateOSX(IPlatformHandle parent) + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) { // Note: We are using MonoMac for example purposes // It shouldn't be used in production apps @@ -18,15 +22,8 @@ public partial class EmbedSample Dispatcher.UIThread.Post(() => { webView.MainFrame.LoadRequest(new NSUrlRequest(new NSUrl( - IsSecond ? "https://bing.com": "https://google.com/"))); + isSecond ? "https://bing.com" : "https://google.com/"))); }); return new MacOSViewHandle(webView); - - } - - void DestroyOSX(IPlatformHandle handle) - { - ((MacOSViewHandle)handle).Dispose(); } } -#endif diff --git a/samples/interop/NativeEmbedSample/Mac/MacHelper.cs b/samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs similarity index 76% rename from samples/interop/NativeEmbedSample/Mac/MacHelper.cs rename to samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs index d72ef5479c..5b3bc9abf1 100644 --- a/samples/interop/NativeEmbedSample/Mac/MacHelper.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Mac/MacHelper.cs @@ -1,9 +1,9 @@ -#if DESKTOP using System; -using Avalonia.Platform; + +using Avalonia.Controls.Platform; using MonoMac.AppKit; -namespace NativeEmbedSample; +namespace ControlCatalog.NetCore; internal class MacHelper { @@ -18,7 +18,7 @@ internal class MacHelper } } -internal class MacOSViewHandle : IPlatformHandle, IDisposable +internal class MacOSViewHandle : INativeControlHostDestroyableControlHandle { private NSView _view; @@ -30,10 +30,9 @@ internal class MacOSViewHandle : IPlatformHandle, IDisposable public IntPtr Handle => _view?.Handle ?? IntPtr.Zero; public string HandleDescriptor => "NSView"; - public void Dispose() + public void Destroy() { _view.Dispose(); _view = null; } } -#endif diff --git a/samples/interop/NativeEmbedSample/Win/EmbedSample.Win.cs b/samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs similarity index 62% rename from samples/interop/NativeEmbedSample/Win/EmbedSample.Win.cs rename to samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs index 2e14e7d766..77982db0ca 100644 --- a/samples/interop/NativeEmbedSample/Win/EmbedSample.Win.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Win/EmbedSample.Win.cs @@ -1,11 +1,14 @@ -#if DESKTOP using System; using System.Text; + +using Avalonia.Controls.Platform; using Avalonia.Platform; -namespace NativeEmbedSample; +using ControlCatalog.Pages; + +namespace ControlCatalog.NetCore; -public partial class EmbedSample +public class EmbedSampleWin : INativeDemoControl { private const string RichText = @"{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049{\fonttbl{\f0\fnil\fcharset0 Calibri;}} @@ -14,7 +17,7 @@ public partial class EmbedSample \pard\sa200\sl276\slmult1\f0\fs22\lang9 I \i am\i0 a \cf1\b Rich Text \cf0\b0\fs24 control\cf2\fs28 !\cf3\fs32 !\cf4\fs36 !\cf1\fs40 !\cf5\fs44 !\cf6\fs48 !\cf0\fs44\par }"; - IPlatformHandle CreateWin32(IPlatformHandle parent) + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) { WinApi.LoadLibrary("Msftedit.dll"); var handle = WinApi.CreateWindowEx(0, "RICHEDIT50W", @@ -22,16 +25,21 @@ public partial class EmbedSample 0x800000 | 0x10000000 | 0x40000000 | 0x800000 | 0x10000 | 0x0004, 0, 0, 1, 1, parent.Handle, IntPtr.Zero, WinApi.GetModuleHandle(null), IntPtr.Zero); var st = new WinApi.SETTEXTEX { Codepage = 65001, Flags = 0x00000008 }; - var text = RichText.Replace("", IsSecond ? "\\qr " : ""); + var text = RichText.Replace("", isSecond ? "\\qr " : ""); var bytes = Encoding.UTF8.GetBytes(text); WinApi.SendMessage(handle, 0x0400 + 97, ref st, bytes); - return new PlatformHandle(handle, "HWND"); + return new Win32WindowControlHandle(handle, "HWND"); + } +} +internal class Win32WindowControlHandle : PlatformHandle, INativeControlHostDestroyableControlHandle +{ + public Win32WindowControlHandle(IntPtr handle, string descriptor) : base(handle, descriptor) + { } - void DestroyWin32(IPlatformHandle handle) + public void Destroy() { - WinApi.DestroyWindow(handle.Handle); + _ = WinApi.DestroyWindow(Handle); } } -#endif diff --git a/samples/interop/NativeEmbedSample/Win/WinApi.cs b/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs similarity index 98% rename from samples/interop/NativeEmbedSample/Win/WinApi.cs rename to samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs index 5ec6e6bbeb..47d368f7a4 100644 --- a/samples/interop/NativeEmbedSample/Win/WinApi.cs +++ b/samples/ControlCatalog.NetCore/NativeControls/Win/WinApi.cs @@ -1,8 +1,7 @@ -#if DESKTOP using System; using System.Runtime.InteropServices; -namespace NativeEmbedSample; +namespace ControlCatalog.NetCore; internal unsafe class WinApi { @@ -72,4 +71,3 @@ internal unsafe class WinApi [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, ref SETTEXTEX wParam, byte[] lParam); } -#endif diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index 4464413e63..fd080cfc5b 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -7,11 +7,12 @@ using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Dialogs; using Avalonia.Headless; using Avalonia.LogicalTree; using Avalonia.Threading; +using ControlCatalog.Pages; + namespace ControlCatalog.NetCore { static class Program @@ -123,6 +124,11 @@ namespace ControlCatalog.NetCore { StartupScreenIndex = 1, }); + + EmbedSample.Implementation = OperatingSystem.IsWindows() ? (INativeDemoControl)new EmbedSampleWin() + : OperatingSystem.IsMacOS() ? new EmbedSampleMac() + : OperatingSystem.IsLinux() ? new EmbedSampleGtk() + : null; }) .LogToTrace(); diff --git a/samples/ControlCatalog.iOS/AppDelegate.cs b/samples/ControlCatalog.iOS/AppDelegate.cs index f1c2241003..f8caffed14 100644 --- a/samples/ControlCatalog.iOS/AppDelegate.cs +++ b/samples/ControlCatalog.iOS/AppDelegate.cs @@ -13,6 +13,13 @@ namespace ControlCatalog [Register("AppDelegate")] public partial class AppDelegate : AvaloniaAppDelegate { - + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .AfterSetup(_ => + { + Pages.EmbedSample.Implementation = new EmbedSampleIOS(); + }); + } } } diff --git a/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs b/samples/ControlCatalog.iOS/EmbedSample.iOS.cs similarity index 75% rename from samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs rename to samples/ControlCatalog.iOS/EmbedSample.iOS.cs index c5996e7deb..ad86d2b578 100644 --- a/samples/interop/NativeEmbedSample/iOS/EmbedSample.iOS.cs +++ b/samples/ControlCatalog.iOS/EmbedSample.iOS.cs @@ -1,18 +1,19 @@ -#if IOS +using System; using Avalonia.Platform; using CoreGraphics; using Foundation; using UIKit; using WebKit; using Avalonia.iOS; +using ControlCatalog.Pages; -namespace NativeEmbedSample; +namespace ControlCatalog; -public partial class EmbedSample +public class EmbedSampleIOS : INativeDemoControl { - private IPlatformHandle CreateIOS(IPlatformHandle parent) + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) { - if (IsSecond) + if (isSecond) { var webView = new WKWebView(CGRect.Empty, new WKWebViewConfiguration()); webView.LoadRequest(new NSUrlRequest(new NSUrl("https://www.apple.com/"))); @@ -34,10 +35,4 @@ public partial class EmbedSample return new UIViewControlHandle(button); } } - - private void DestroyIOS(IPlatformHandle control) - { - base.DestroyNativeControlCore(control); - } } -#endif diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index 7cbd8a3f9c..31349b4197 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -13,6 +13,9 @@ + + + @@ -29,5 +32,17 @@ + + + MSBuild:Compile + + + + + + %(Filename) + + + diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 59d724db69..d8dc3bad2d 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -2,8 +2,8 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:ControlSamples;assembly=ControlSamples" - xmlns:pages="clr-namespace:ControlCatalog.Pages" - xmlns:models="clr-namespace:ControlCatalog.Models"> + xmlns:models="clr-namespace:ControlCatalog.Models" + xmlns:pages="clr-namespace:ControlCatalog.Pages"> - + @@ -46,7 +50,7 @@ - + diff --git a/samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs b/samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs new file mode 100644 index 0000000000..14310500ab --- /dev/null +++ b/samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +using Avalonia.Platform; +using Avalonia.Interactivity; +using Avalonia.Controls; +using Avalonia.Controls.Platform; +using Avalonia.Markup.Xaml; +using Avalonia; + +namespace ControlCatalog.Pages +{ + public class NativeEmbedPage : UserControl + { + public NativeEmbedPage() + { + this.InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + public async void ShowPopupDelay(object sender, RoutedEventArgs args) + { + await Task.Delay(3000); + ShowPopup(sender, args); + } + + public void ShowPopup(object sender, RoutedEventArgs args) + { + new ContextMenu() + { + Items = new List + { + new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" } + } + }.Open((Control)sender); + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == BoundsProperty) + { + var isMobile = change.GetNewValue().Width < 1200; + this.Find("FirstPanel")!.Classes.Set("mobile", isMobile); + this.Find("SecondPanel")!.Classes.Set("mobile", isMobile); + } + } + } + + public class EmbedSample : NativeControlHost + { + public static INativeDemoControl? Implementation { get; set; } + + static EmbedSample() + { + + } + + public bool IsSecond { get; set; } + + protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent) + { + return Implementation?.CreateControl(IsSecond, parent, () => base.CreateNativeControlCore(parent)) + ?? base.CreateNativeControlCore(parent); + } + + protected override void DestroyNativeControlCore(IPlatformHandle control) + { + base.DestroyNativeControlCore(control); + } + } + + public interface INativeDemoControl + { + /// Used to specify which control should be displayed as a demo + IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault); + } +} diff --git a/samples/interop/NativeEmbedSample.Android/MainActivity.cs b/samples/interop/NativeEmbedSample.Android/MainActivity.cs deleted file mode 100644 index 5d2e06a330..0000000000 --- a/samples/interop/NativeEmbedSample.Android/MainActivity.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Android.App; -using Android.Content.PM; - -using Avalonia; -using Avalonia.Android; - -namespace NativeEmbedSample.Android; - -[Activity(Label = "NativeEmbedSample", Theme = "@style/MyTheme.NoActionBar", Icon = "@drawable/icon", LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize)] -public class MainActivity : AvaloniaActivity -{ -} diff --git a/samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj b/samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj deleted file mode 100644 index adfd74b9d5..0000000000 --- a/samples/interop/NativeEmbedSample.Android/NativeEmbedSample.Android.csproj +++ /dev/null @@ -1,50 +0,0 @@ - - - net6.0-android - 21 - Exe - enable - com.Avalonia.NativeEmbedSample - 1 - 1.0 - apk - true - - - - - - - Resources\drawable\Icon.png - - - - - True - True - True - True - - - - False - False - - - - True - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml b/samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml deleted file mode 100644 index aa570ec504..0000000000 --- a/samples/interop/NativeEmbedSample.Android/Properties/AndroidManifest.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt b/samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt deleted file mode 100644 index c2bca974c4..0000000000 --- a/samples/interop/NativeEmbedSample.Android/Resources/AboutResources.txt +++ /dev/null @@ -1,44 +0,0 @@ -Images, layout descriptions, binary blobs and string dictionaries can be included -in your application as resource files. Various Android APIs are designed to -operate on the resource IDs instead of dealing with images, strings or binary blobs -directly. - -For example, a sample Android app that contains a user interface layout (main.axml), -an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) -would keep its resources in the "Resources" directory of the application: - -Resources/ - drawable/ - icon.png - - layout/ - main.axml - - values/ - strings.xml - -In order to get the build system to recognize Android resources, set the build action to -"AndroidResource". The native Android APIs do not operate directly with filenames, but -instead operate on resource IDs. When you compile an Android application that uses resources, -the build system will package the resources for distribution and generate a class called "R" -(this is an Android convention) that contains the tokens for each one of the resources -included. For example, for the above Resources layout, this is what the R class would expose: - -public class R { - public class drawable { - public const int icon = 0x123; - } - - public class layout { - public const int main = 0x456; - } - - public class strings { - public const int first_string = 0xabc; - public const int second_string = 0xbcd; - } -} - -You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main -to reference the layout/main.axml file, or R.strings.first_string to reference the first -string in the dictionary file values/strings.xml. \ No newline at end of file diff --git a/samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml b/samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml deleted file mode 100644 index 2e920b4b3b..0000000000 --- a/samples/interop/NativeEmbedSample.Android/Resources/drawable/splash_screen.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - diff --git a/samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml b/samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml deleted file mode 100644 index 59279d5d32..0000000000 --- a/samples/interop/NativeEmbedSample.Android/Resources/values/colors.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #FFFFFF - diff --git a/samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml b/samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml deleted file mode 100644 index 2759d2904a..0000000000 --- a/samples/interop/NativeEmbedSample.Android/Resources/values/styles.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - diff --git a/samples/interop/NativeEmbedSample.Android/SplashActivity.cs b/samples/interop/NativeEmbedSample.Android/SplashActivity.cs deleted file mode 100644 index 78c555f5c5..0000000000 --- a/samples/interop/NativeEmbedSample.Android/SplashActivity.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Android.App; -using Android.Content; -using Android.OS; - -namespace NativeEmbedSample.Android; - -[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)] -public class SplashActivity : Activity -{ - protected override void OnResume() - { - base.OnResume(); - - StartActivity(new Intent(Application.Context, typeof(MainActivity))); - } -} diff --git a/samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj b/samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj deleted file mode 100644 index 1ec852ab6d..0000000000 --- a/samples/interop/NativeEmbedSample.Desktop/NativeEmbedSample.Desktop.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net6.0 - - - - - - - - - - diff --git a/samples/interop/NativeEmbedSample.Desktop/Program.cs b/samples/interop/NativeEmbedSample.Desktop/Program.cs deleted file mode 100644 index 01684d0301..0000000000 --- a/samples/interop/NativeEmbedSample.Desktop/Program.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Avalonia; -using NativeEmbedSample; - -namespace NativeEmbedSample.Desktop; - -public class Program -{ - static int Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - - public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .With(new AvaloniaNativePlatformOptions() - { - }) - .UsePlatformDetect(); - -} diff --git a/samples/interop/NativeEmbedSample.iOS/AppDelegate.cs b/samples/interop/NativeEmbedSample.iOS/AppDelegate.cs deleted file mode 100644 index 9ac8ebab2e..0000000000 --- a/samples/interop/NativeEmbedSample.iOS/AppDelegate.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Avalonia.iOS; - -namespace NativeEmbedSample.iOS; - -[Register("AppDelegate")] -public partial class AppDelegate : AvaloniaAppDelegate -{ - -} diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 98f4d035c8..0000000000 --- a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "images": [ - { - "scale": "2x", - "size": "20x20", - "idiom": "iphone", - "filename": "Icon40.png" - }, - { - "scale": "3x", - "size": "20x20", - "idiom": "iphone", - "filename": "Icon60.png" - }, - { - "scale": "2x", - "size": "29x29", - "idiom": "iphone", - "filename": "Icon58.png" - }, - { - "scale": "3x", - "size": "29x29", - "idiom": "iphone", - "filename": "Icon87.png" - }, - { - "scale": "2x", - "size": "40x40", - "idiom": "iphone", - "filename": "Icon80.png" - }, - { - "scale": "3x", - "size": "40x40", - "idiom": "iphone", - "filename": "Icon120.png" - }, - { - "scale": "2x", - "size": "60x60", - "idiom": "iphone", - "filename": "Icon120.png" - }, - { - "scale": "3x", - "size": "60x60", - "idiom": "iphone", - "filename": "Icon180.png" - }, - { - "scale": "1x", - "size": "20x20", - "idiom": "ipad", - "filename": "Icon20.png" - }, - { - "scale": "2x", - "size": "20x20", - "idiom": "ipad", - "filename": "Icon40.png" - }, - { - "scale": "1x", - "size": "29x29", - "idiom": "ipad", - "filename": "Icon29.png" - }, - { - "scale": "2x", - "size": "29x29", - "idiom": "ipad", - "filename": "Icon58.png" - }, - { - "scale": "1x", - "size": "40x40", - "idiom": "ipad", - "filename": "Icon40.png" - }, - { - "scale": "2x", - "size": "40x40", - "idiom": "ipad", - "filename": "Icon80.png" - }, - { - "scale": "1x", - "size": "76x76", - "idiom": "ipad", - "filename": "Icon76.png" - }, - { - "scale": "2x", - "size": "76x76", - "idiom": "ipad", - "filename": "Icon152.png" - }, - { - "scale": "2x", - "size": "83.5x83.5", - "idiom": "ipad", - "filename": "Icon167.png" - }, - { - "scale": "1x", - "size": "1024x1024", - "idiom": "ios-marketing", - "filename": "Icon1024.png" - } - ], - "properties": {}, - "info": { - "version": 1, - "author": "xcode" - } -} \ No newline at end of file diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png deleted file mode 100644 index 9174c989a9c8b8a5ca133228f4ed7c173fffd2ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70429 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 z zCn)b8&=oMu6ygwwJfdasJX|@L6?m1Dv0X9t>JAWO^UIj0#&(3UrHx;vP^3g= zL{(XT!?`D*pP8)WoGHYEZZc$!odTzb8n)q0|88*>6P z`?6&CSv_W7r2yF0beQ2*?V^_%pKktVAo`)T^26X@NpK_*-ni{D7{Sp{C0A<|16l(; zOL*xGW|*sKsiwHvE!h3QXe@^a#6W3}8!DQu-h?A_4gkeRYkt4NC~GR5P8eyp;9kVQ8$QG$5ad7Fo23Z~ak1jY~RXG{v?3G$RarFe`XePu3X{R+=mBOw&X zks)|Sc$RcG-jhn!`~-x|vg!&DA&@}QH^RNdyy9nq56yrU$^qAaS+F_NOaeFb)CVaH z?!UvPajgrK&zqdAs>&Def#wkcG_UhmYOVw^M`VZz@+4IWAVzK%`+za9rm2SD9={u@ zlx5D6UDL;lc7#9`+%vnlP3PescU=N`DHQPt_N55GNBMkVCRMR4?fvp zAFsvcHN4c9rb>J@{*IH>RTr9de%9i4Gd(cbFa9SP4anhoP;TA0!oZyB8?lNMDHPHK zCaOaFU9?x2A!o>p>mCF9r+hKs9Czu_P1l$LWU%}q#)=T3p`ZnYyeHmsewqw`}L^4LuHqfo+CG6<2n7#l^3;H^^!1 zsaieYFnN)Kc7Mv}^xE)4kXUw8<9I+jMB@QV9T9I8haLDt1Ne#exWUfGYG$4uMoEu& zo81#2up18Y40h%tIsOZglp(ltVsE*j1~$lVd|;rN)&${~o~-%KZnJp&3|OFR{^8E9 zJ;fCu53Ysw%}@VYWE*z7r)&4P=^B-SF%a@>*9g84<4aFUZT7x)qdsS+#2tu5NbpU@ zg;EwV)l-#sK>#r9>(0Figx{9lKm>KvRj;y<8 zc8SxMW4<11(s@QMV_}n9MRzA*62->vzxmHh1)GVASEJY7LVtRw`Rv{v`(Fuc00(&o z%m>gS2aJekmdNQ4p<{pD3HqZ-%4hdU1__xYhLi9mTJXD|E zE`t6SX)}l_DY5vO0Xrs#O6_DKtPKn0f+e~SprDYmJL_`<053iA5P`zn z4<5etc%aF58sHFr#M;U-9|=;l)J#Q2vS!Q9(d(EX6fubL%uA_lqa2%!cpNIv78QZ}Ayo(>C(ZpsRtKhzD--fpuoCch87cX-Bna9_{z%$b*dHM0?+T&Hk!+^UM`r|vq z2Id$??bX^|tfYaE+h#Nik(ZcN+wt)28q^gWe!y8jDCXrD<2qV#49x@5$8&Zrd5NTs zNYcix;9fe#PQQ;T?!6hG>9K{K+RCPqiGc9z%t{=`QaX>7O{l(+#7mJ1>Rae^J?82e z6cLqLypskTCyu>uc~$0-XZ^1Qvhwr+pKQ#CKImhGu*MGM*ZrROuAHWuT*yM$ieEy8*KLFMMdLZL|D+yDmy@3_PELTEVMI6nwfcYA3ZQ9wwKdtkT z;`;z7fU{U6>CS7kr3=A-()_G*G(Mjf2wXKe

Fpy)y!S(AQHSG#udd_8#b4sQu!R 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 PgFh2POM|ilu9yD@)d*=D diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png deleted file mode 100644 index 9c60a1761dbf62cc2a45ff98b9fdb63ade16e4d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3773 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 Dh-f%Y diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png deleted file mode 100644 index 448d6efb577d07e227a5c62545173ddf6bd86b55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4750 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 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png deleted file mode 100644 index 8524768f8d764da7e9c452a444208708f2d18ff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4692 zcmdT|XIB&4(xpTN1*K>xQbX^8^b({KIw~rHNC|`@2%(dJ5D-F#1ZfEYiGV0lq(}=W zgc7Psl_H9vHvuJ7z1-)%p)6vnfLQD;Bp4zg1 zAEvXXcM#BG{nP+pdX{>0bT#Q0j$O{s(Q#aW80y^)qu+Solk&js%GX`#>--*?1>hBn zylj2Bl~|w=hswPyL69*gD{tKnqopZQY+Ok0Wi&``_+IL55R?xKc>smnzEfS9yo`Q{=^|^0;fo;{d{hqBCglz?TcMBUE zv9qCXytz?uTg*u4#tlljAzN}Z=2nHzZAGy%_zhVGGpm|P+pa8pAAJpzq()b>@s(R} z>2qXI5%uyKubl;@obSI8@VZc*jSs8>75IYaJwEbpU(ry69>yD|l$U2d20L+%sS>{i zsSICRml49T7GzA*+lM?CZ_~6^^)!No`QYzJ%-}6)O^+lfdl+G z1O?m!ckdDA}b>}*SY^H-eW-!oJ#MwHFg>6&At;9qxdriX`yY1d+lkmMg! zbjZjbS%^n()6yjKE)&;ur^F2bxwkn6FFoM^gqLnWZxS>f|4wJlH=b2o4-Lxfd^<0e zz^_NU*zzAI3jcRGyyy5GjU?&q(WPND9kUGKLz@7}2snY4M}FIf$QH*ghL-*jzPb2$ zfZPGTkTrFubtmHyXOA5Bry1XzDL+p)hmFSY)mk4*gqwlmmF>S zS+6Vi7>oBhNb6~6tX}0;A^WbCa9MbjjVhSa{Lce7miezenM|Mu)0JhdR@?mUvSbZU zq$p{l5F@Ky=t|-zHlfycS;Id~J{+F*3z7_-4P;x;#PucfvxDC!H?r#%l4aoVTO0RK zICSXmLZz1U?=@vc;C3jXDNGe41M&r-BJK&U)ieK&C}}?qHsi?pi^e_1VMxMD55KBE zB4|ats({#-#(#7n`cGza(VjkBI%y5xz`P~Gw7t*%UhwsuXZT$l^}I4|ezRXla$6*= z4b4T>R@8RgoS|5fnHBgyxLA{}I}-vb&NwMmjX5^?-|^eI9q*$!4%Mj`79UNBh{Ebb3Wc!z1tI(1vUyP1+*7^(4&1yM?CgM^mSAh?2hHosE$M}P*C_29}omMN5 z12_~tF)$?J`Pfb7S7Ol;OIJ@M1|NS#swII$?TS%{PGGR-pI^#;tU6fVx1KN#M&@MvKk4-Jp&tj7w$N( zUkNq6ocd|jckZa+JEtTLx!aNEOs^Bx;U<&Y0+esu1>>q8Gzf+)WjZzB%o>4Pa%hEs zY-v}@!TU|d#Z;_FA~>%`Bj(etxw`!TE z-H%3zyd5F`pvUxzP1g=4fBqrm7E#4@pCy5w-?u&S+@c*t46db7I>wgduD$k9F`h-- z8|En#lIX8#wVV`~w(NA8w`dhhGKKqnaE>hM!=Yn0FMfh@Gkd%P`u{M)#cORv1DCHaJUhdI>IC>z+d12<41E>}{%v^kX2{^jY$+)k{d3|iIYJS_{^L+_5#=E11KJ{FDFv1W&0AY z?_TrXK{$m%K3YAMh&%{l+HhC8HZN~!n2Dvl4B5M2+HnTe=D(hG;PCF`n3nVfhI`E= zqU6et<>1JAvWswf$Gis9`hIWZPDAm;X=QS4#pVIEzad@vP>m}p?#Aek% z_oE<(AwZ)LoKljNMO=Ww$VAFkGh#5xWG|&k*1@^banyC+i*vm5P#-}Id8B5y%X|DY z#f|69{Z+KklHPM`$qr8?G)4Uq`pXLeTiA5Z9qy>9xZl-aW2pf0fK=2sz#R(!nxEn= zg|4{|6qU()T5{}Zm{D7MAe%YE0vxST9%ah%YxPXD>yg-N_i1pe=(ffkvz-zQtrLT7 zr&*;O*K(zPbX9?R!@nT$ag3)GY@2TiVN?dlwf9SsC)|KuYe0t8@gphVIGL2MR&-S0LZOfu zz1pW@U*WUq8i7;ht%)tl>?T8(MC|%=G^d7UMC|3L*T#=o zZgwNH`W=8xf=m5JawZUNo$!K%M;#%PPK^?ycT_1pq8>u0la@2o3zUWjc#brSm7Yns z@>;{5shEk+&a{tPfC{A04V<^#jWA@t+n0;TeE#O6TdSxfQKJ8JBm>I*UVU@`baL&PzJInq zmEHH~@Xn9?d+^Wu)}cd+cV*w-;BVhCJ5THdQ9VPAGVf;i?r%LVh@#nk(2Obi-_In; z#Cp=)F|i8DZfV6p`w{%$?4R>|K%=HOwp5eMRQ3CxsHQxDYVZqJaC=&40{Z`OX1{?k zBq8x_(aO(8+8Q|xLo63l>>j<1miKe_As)PSJEw&e1n_LZtz(lyWH*1DR6kIVS^U@EfkZD6pvdN%6MsTLSwv6i5>hgZ=tqX=5=EW7u>)5%{#%5ASh88%@$m94oJE(Rn_ z5@A~q6cEJ!{=%5$(Z~fj#|s7dg2(b+){7cJ%N0WI1NUk2ctkAp(gI0VSU@NCkdH9O zLJ}`)4w!LmPZ0$DqbJm;qDAkVT7x=VmI=j*x64gC?FGFat8!`H?AG2}%!CHki9{$Z zY5iNo6h|!>4}VKwYBdd-U&4kN4UKKcg<(DmXjI6eP@*~#@fCR~2b0@FfMO3*^l8;e zCbDH#c`J>$GNFEMGsFFF38pjXLhJe2WczfNoMDN-(X&P7J+ zwIW5tefQGvw<8!YIzO01{U8I{4Vhae^>xi3dGt-6_q{Hw<}UUW$^1X+R8*qY`#8>8 zUAh{$OyrbULuz`bomFpon_e&@{q<*w@^wBeJxc@~-2?j*?BMSXDjnot?}G(I;+1J049jExcd zo~6IaL@XT@b$mMcO&SYc`8Tot&%9jy5#kg`KMLw>XR(EeyPi}Y zi!B09N~kd3RcxTj;OyZ_8e@xNO`JG?=p^eRV@JZ4!BtZWE0ky9DeY;}?BN`E*4~!3 z=RQN^Hfznx9GdF;o!GzR;ERcn7SD&-T`kuQOVoepQDJjQGyp5;`JFIlS?wrWv&gYF z2_ey|T?4J`Rjyy^UUfRYV^Ba1Hds2^UcQ=>5> zshQcP%=BU~v-du=et;~zUrL>!+37mr7K0NmSfq#=>qAimUWuWmiSy zGC3H`hO(k3JZ4V=XSux+v)F9lrGQq|HRBtUm2Ok>7je;;>tf&P?bS|~6l%uzL1L%O qQuI}W&FnVtX2s7O|6Nb``GoL3$B3jnW^%eFqJtP&8CL2$qy7ci8tmx+ diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png deleted file mode 100644 index 60a64703c0f11d08705cd607f7751338707f5919..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5192 zcmeHLS5y;9w+;kD4Fr&0L?DWV8j6%7By{Nt(lOEzP>>etArLwN=|utr2p||biWI4W z3StaOmEJ-Z5Rf9?oco`L`*TPXnfRFi003BDPwOsq zZ2G4$fT;anpFncdfzAzX1P1`>Q<={mUH||%|LAMM%~3R4_QA;x7F_Bh)~(Y1_|qmr zOwG@mOFLLfIh8siv!wF?msqk6GNH zz zMzoR3xG!B>!EZ7JyBM*WLULAOh19jEFVejCTbeu$}kZ*r!*zIhn8YfeSzT zJrv{Mtv0%v$E-E#`s3MmiVmLW?pG+TgxRKS<8>9cTy`wB)Ee(=^86JLKyq#ROFCTu z(b>|G5Lmd*^uB;+vBV%ov2-gq%?@%x$ukZKnL;mk#a2Xj-YUc7uwwp{Y;}pSr86UH zr(5ET{b5D2$d7r&pWIbt-bYuy{*mo;by@=g3MjlmKN{dI$pS&g1e%#p=x=)!Z&xi` z#05qlK6!9UgAUY%Xsf*Pb0d^>5($ieh=_ z*`rr0BHqmH@=lT043M;5O^G%L^`qU0M{3i!LG&Eb`5k~g7a%|^Nhie_2ay_!6x(Wa z3OoGt?BZxbA0dIs@`-m4>aBRR@rr-GRASi=auvY(u@1>IvSUwe8RBA8rxS*nY{%7fDab3U-G`4j#S*QlsTm=S(E zkLHpY5r4!G-dg=!xY0v}T}e|K>!F4OZ8pX8Bh(vRq_@8OiQ&FX?pe+DH-NGC=Vn(i$eU-LzWr!?{{hya10I`JtD*Vea);p z1?RnPJYUAR4W*y&$9Nn0|0xguYC9g5-|`mzi1CAA*y8ujFyY_GwF3Cv!{28*i|i-6 ze^9SPyIrj)DJOOG?7TJ3H){)JUwDOEcTzgyA|fjaLq>ATH@5H_tA+_pW2sU&&7z{) zg}IDr9-LR_8q9Pr=9!&i4@O?(r*F{SrSH2hhh0^`|7mT^Q+(w!TT2QuHWYDoj;>Mv zdj0xBVKuj@!YqJ+4}!X7RzuN32d&7NDXu?zZ+n``UTc*mE?E>SOPAgC)onMMw1u;8 z3fzBNT+JSmcbP8=d;*~_fTy(>XwOBDWPjctm0=#tm=jR z!1At9ODf*Pd&c0C(3;W6L!YM7jtqzMpT+O9JLleOW$5e<#m|8tT<;T1xj$-6aG+~Q ze61CiCFpZ$Z682|#ADwaV6T2ACAGyW8d+A!shNwM9R*!d`oh@PlJsoNX`S+l(0F&3 zOqk(wDcO`jr;rqW4%dLq_~_qk@4-M_+`Oj}4jdj-dNJ*JPvv#qcq4c&CEHJm+z%n4n zsm|=d<6C#yY)!N$Ieizm+Z}J4ne4q;LyE-naY_MQ^c}yzl_K z<`nR@lO~n>>#lAzFTCOVPHP^$<=MvXA*RHf@ zUPHkcU)b{xN4HC8ilU9VLJ%48_9qO#`*gAXWw2?uskKMrV2W=L*H2PpDt$i`)?3eTtrf8IuZ?(lO>m-gsN-h1)V9)Xibw(T&pr&jRjXaa}!)xaOAzgd$UXYnKS*oO$yh z@KPT$LfxtxZmLW*KCj(7(sR(GZmn44I*R2mTI^O8libszQz<(Z)xYcJ;{*foM)rVi z>#Z>UHXiW}sSf4^!GFKBSjRhz2Us;ZpzORAh;Iv4)AC-5e>bZPCX1S6B8hVT z3~l_zuPc*1?A`A6g6gzKp(B`nn;3d_g~p!f;-@-MIVCR^BzbPdG=6 zSW-e-mq=p3D+Xm5b6-e@b!>lDHPSRFxV)(so5iP^fUT;n@l zl%!X5=(5U~r}xL}5gx4TJaxWf|JJ7~M{?M6-yl;2tMTw_LTj&wN=1gqlPdjjP+g2a z(V!||K;mX2=CSgWzKN(a7jUgzD>;^sCI3>uv*yxxovrz1b7MIP+=#-fsXrX%JO__G z(-EzNWgX0(_)Mzt`VoGY#1l2Rw8CYoNJL|w+nc5%3@t2me9B^ShH`JnlazF~a zsKc#w?U>j=!3Eh_o7@W?bDbkhs4l8TWH792*yjZ!>dD>MPrO}c20L)?;#qgl88`IS9DM+Wx23gIj&&@cAE21d znjU8$`87is(b)iueYqKe#RFJUCnoPfZ(~-olia>6>^67P&qAYs5vID??S7R(bA)-X zaUC?VhneqKU`s02`U{&+ol$?g9|KJ?UpslF^A;gs8G2Rh=zJbALZ|mGy%u6) zQ(oU!$lD**mO*vpcWB1Tt>TZ0hPN{zUVJEtE7t;T3{KM?6!_81i?L@WG|b~*1}g~7 z2KVYAb{j|kS@K*~JzFg{yf;839HvWor2JqF*#zqOY^D`N$K)V z5nA7}C@P_D<9e;$H_e0?VJ;~o_kro}sV||2`vG0pjrQ90BfqCi2L5d$soYP5w^;PJGh#ZZb3`6?6;ajALY==j;l+5#<-*c75 zdg^gPU-X^DSBdursNw5`FTDCt<(y5rr!#g)j7EwovnkU`#0Cr`;Lyui(OWX;oPLEh zj-fJHbu#99AD~gyDwTH1*+S019T3~hW^h#o#j>OqA3D_Fmfk-+9@vg!YhLOIGPH}| zA0o^iQ{#enrg*|JyM=4Xh8J)g(JBlz6T0U7Q667^I4}G%dhTuYKF2kA6=QbPP=5k$ zmp62ETP~?O%5wGlmIi-WmR@@9rSzvz55et!&<(=ccOMhT&iN$wpFAjVUyd7V1MbD$ zN}o5ws*V3R@au`6!7S?mIS^2 zOtlW)OddNDEN4qCx*as5oJg}tpoacZEeI2?4}v*5*$Ajoq>diKC!py@DgT&+-Msv zrQnw9VGh$@3{_16ppy@yJk*x7`8fD)uEdGg${Vo*BM`DHT{Aqpu_VCHm3KVk2K~|- z>evA#EcGi#N!(5_YK%c6*W~RlGTPY;C&`J!FAw%pNtYR>lFsXi+|EF0Qyv|<9y$8l z#e1}O!DRCm`-Xolj)wckm-6+DT;ZaclQ0nd?G&N6r#Eu31E&5T*e`;l7&BYI;^qhV zn3z%V!}l7$YN;jz-PAi5O+|ME*B#agX51f>)6Zqq3%1Sp2xG_PpnfvNnCuuQh6}=g zBs@`sG2T(Z=xljx!rnsPFe*I=-$b~m#qPlGf;UXa>_2-}mQ(f*0RS&_ed+=fzi~Ag ze~BqN$sl>*G1K8Nd7KX%#_{dJp`bu|5Np7V1F{6Ci*7>Fu^FnNMN!K|aH)0h^D>Ps zajddf%fPh@dkpjE}I{$wZ2I#`Fm$EzJh(P=hc;vBMIr#B{eQiDS?3Y z7To8(6bRL6dv!I@@IQn2p#G32$h9_e-)N?Ni*v>0ik-)+5=TVyce-4f3;as*k08Yb zVB7oSq4!V3tLDj9<-?_Sj5|Gs#Y5Kp3ytr)m?ZgCunQB-$B{(7=!t+Fv0dUPcPP z*AtJ|j21oWe*m^54!^Vkhaz#@W}5E2O9Dw!ODIpLI5lj=yB3$JZhJ8D!jOEzbwsaB zZU}$Y{5VR?sF0)z6a$a=|K2s%r7VwJAuFx!x(@ej%!xN%_zfrTb@oQp)97^Fd0r_d z&*Fczb`jS#-P1IB%Uw=IhDNbVue4J9XN=PZPz^Vj-*ciddc>+%w8QNbUKo|6KuQlVrv%d4`HT%YDbk5M!Fv z?Alw7ERh#vzTB*01ouu4*d|oTVh2)f$5Ov~eTkqJm9W=Bya48{l0wqpFNmn%56+M^ zwY16RtPYqAfO}H=FZ{!fe>fwi&~RaK9!#NPdG_N@|G=7d{}(|z|4znU z?(Fnul@zwjsP<4pxi#^5e@% zD`~JK*Z8P>ZmyPrXg%K-zy1pOPL|jBsr~Wc{g5522RGfkCYYexHK{VQdVd0byWFRn zW*MT`4H{^U*$3sV=STqO3sn(7x;{sTw)(WfMaV1rK8)1noD}p(1L<<`IQAB4{RNaF7AGw4IpR<+! zA#;4&WHY3_SHp;-lNrqLrb`rh@3rAE$wwC986`=6?%(ZJ&^+z)51IKYx nB>N_)Q7iwV%v7MwAoJ}E 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 T3-0p800000NkvXXu0mjfSlal| diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png deleted file mode 100644 index 1ad04f004b638bf781012290d78e4138f97bbe5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1761 zcmV<71|Io|P)4P%ubY|S^%$zf~ zmwTOa@12BA$oV-Y9!V&U%c=j==#_}M2ylE}1m>yyDoGsZ#Yy zNX}RO*f(MzmKS&u`qiajIyW{Y_LC%m2NqT@Ic|QpvYqwNgBK7n5X%c(3k^?2>EOA` zqGaXjE7H9BiJ55fh0iJRW}@=&(@R^E1hLB>kE%PS6eP@VZVdtn(fh;5DPKg!j;fJZ%)wH{Wn#~V&#n(o1URS zsyS`0Tu2m;-H}z9O^h`!UZAFr@?0a7Z;pYOi0uZhgzh=rOEDi`FIkKtVu*gEcSM!h zmb#_XR$akjlg$JI75MXgWkG7IUnYJ+X=1J!qJ%jXVj{L1I2QU%?=?DgV^U?)92DZm zV?>``xT1#kZdgUt!2n?|0>*6ae4tikA9FAlJ}kjmMQm_z3LB5sZYHBKdbex9_Hv@K z%Y?q@9-)b7vJ6X$3h0B4tH__=#*`9^efY@IQfghn*=E2Nb8sR8lrQlu`Ca_Rmm6>Z z7bkEe^w8M>x;hoNUvWu_GZJPVpI;bMTsBpf(@U$Ch(-gk0T#WpsaB1{7ISQ~Y48mW z;Nk?@LjM_?q{BV-D=veoOmJoncVDC1GwGGz(O5@o7ZkGCIJMPO(7K9b6M_wF?Xqd< zo4J6KF0_U2<1=T3x0qc6G6#g+^=N{QTpChC!GZuCY*|eU{Rw)LMN7a2wwbaCdn_dE zzy+Lip(XU4-+SoTFyEcnH3?HRV^%-;Ylx;|>8v&^Dy459ZJ_1zio`68!6s8SO(6sq zaN75WUKiF9+8MruR3=w5)hzA^Z1clVBuXc)+8@e);xX7bfygR&FsIIt-gQ+==(c;S z#J*CO1qZBF&M&6TRmskZXaMOU6&?jn_(BqY5 z>Y|^?uOh;yp6w0QR1`>tiEz_-{Zu!N#(nhRndJV$7;LOgPyZQ*J2yCin+~*u!qKj# zItsG2IDi{ZH+E6j=D|ht=qWxKNxaA6E>3Wna>=z1gy?*#>|g_1^BGspGro&OWRc(k zPP)(*y0WZ7Z-kICr3#g7($P*LCjE>7S`Xh~s!b~bPTo0XSkRm2T(M`QZbv-`Imx*Ulqk*aI* zaqa*=>61?nFb8w3wuiA&zyVyGz>!cm-pY3xEsMEiY)Th4FVrtqWp%V~gxW82)>4^N z*H{>GR?m$^s6BN^M=4^iEjT7(gM(8z7K#9Sn(M_`)oSH2zHDCla&cmK)bb|4nAMIO ze4S3gI9L8AD+T9c#C8K8JF)I68NBWK`5pE`q^OR#h~-u!e7P2i$UDq7^*uZr< zbp8sR<$nYxb8EKH|BltapZ^j3+PZt_u^PR*lT6;TCNxu^yFH$j(!JXvbmHfQ>a0>O z+2k{tOWD%ln$M`tD&>+*KBKvmEgi1;jOwgXF4_DG_&r&PcxYTT00000NkvXXu0mjf DptxI> diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png deleted file mode 100644 index 2dd52620a8f15577e56ec7fe8e671988dd17ab0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2537 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 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png deleted file mode 100644 index b058cae2f440e5a5875e45c036c99f1fb6356046..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2332 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 Kc&(xHv;P1B$EH01 diff --git a/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png b/samples/interop/NativeEmbedSample.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png deleted file mode 100644 index 4954a4bd33f613d45f74dc0b12beb516e3b38661..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2758 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 z - - - - - diff --git a/samples/interop/NativeEmbedSample.iOS/Info.plist b/samples/interop/NativeEmbedSample.iOS/Info.plist deleted file mode 100644 index b9656e1c20..0000000000 --- a/samples/interop/NativeEmbedSample.iOS/Info.plist +++ /dev/null @@ -1,42 +0,0 @@ - - - - - CFBundleDisplayName - AvaloniaNative - CFBundleIdentifier - Avalonia.Native.Sample - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - UIDeviceFamily - - 1 - 2 - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset - - diff --git a/samples/interop/NativeEmbedSample.iOS/Main.cs b/samples/interop/NativeEmbedSample.iOS/Main.cs deleted file mode 100644 index a1d1502084..0000000000 --- a/samples/interop/NativeEmbedSample.iOS/Main.cs +++ /dev/null @@ -1,6 +0,0 @@ -using NativeEmbedSample.iOS; - -// This is the main entry point of the application. -// If you want to use a different Application Delegate class from "AppDelegate" -// you can specify it here. -UIApplication.Main(args, null, typeof(AppDelegate)); diff --git a/samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj b/samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj deleted file mode 100644 index 83611c90a1..0000000000 --- a/samples/interop/NativeEmbedSample.iOS/NativeEmbedSample.iOS.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - net6.0-ios - manual - Exe - enable - true - 11.2 - iossimulator-x64 - - - - - - - diff --git a/samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib b/samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib deleted file mode 100644 index 8190201742..0000000000 --- a/samples/interop/NativeEmbedSample.iOS/Resources/LaunchScreen.xib +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/interop/NativeEmbedSample/App.axaml b/samples/interop/NativeEmbedSample/App.axaml deleted file mode 100644 index d6f182ed3f..0000000000 --- a/samples/interop/NativeEmbedSample/App.axaml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/samples/interop/NativeEmbedSample/App.axaml.cs b/samples/interop/NativeEmbedSample/App.axaml.cs deleted file mode 100644 index 0a89ea441b..0000000000 --- a/samples/interop/NativeEmbedSample/App.axaml.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Avalonia; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Markup.Xaml; - -namespace NativeEmbedSample; - -public class App : Application -{ - public override void Initialize() - { - AvaloniaXamlLoader.Load(this); - } - - public override void OnFrameworkInitializationCompleted() - { - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime) - desktopLifetime.MainWindow = new MainWindow(); - else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime) - singleViewLifetime.MainView = new MainView(); - - base.OnFrameworkInitializationCompleted(); - } -} diff --git a/samples/interop/NativeEmbedSample/EmbedSample.cs b/samples/interop/NativeEmbedSample/EmbedSample.cs deleted file mode 100644 index 340068058f..0000000000 --- a/samples/interop/NativeEmbedSample/EmbedSample.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using Avalonia.Controls; -using Avalonia.Platform; -using Avalonia.Threading; - -namespace NativeEmbedSample -{ - public partial class EmbedSample : NativeControlHost - { - public bool IsSecond { get; set; } - - protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle parent) - { -#if DESKTOP - if (OperatingSystem.IsLinux()) - return CreateLinux(parent); - if (OperatingSystem.IsWindows()) - return CreateWin32(parent); - if (OperatingSystem.IsMacOS()) - return CreateOSX(parent); -#elif __ANDROID__ || ANDROID - if (OperatingSystem.IsAndroid()) - return CreateAndroid(parent); -#elif IOS - if (OperatingSystem.IsIOS()) - return CreateIOS(parent); -#endif - return base.CreateNativeControlCore(parent); - } - - protected override void DestroyNativeControlCore(IPlatformHandle control) - { -#if DESKTOP - if (OperatingSystem.IsLinux()) - DestroyLinux(control); - else if (OperatingSystem.IsWindows()) - DestroyWin32(control); - else if (OperatingSystem.IsMacOS()) - DestroyOSX(control); -#elif __ANDROID__ || ANDROID - if (OperatingSystem.IsAndroid()) - DestroyAndroid(control); -#elif IOS - if (OperatingSystem.IsIOS()) - DestroyIOS(control); -#endif - else base.DestroyNativeControlCore(control); - } - } -} diff --git a/samples/interop/NativeEmbedSample/MainView.axaml.cs b/samples/interop/NativeEmbedSample/MainView.axaml.cs deleted file mode 100644 index 976de7a97c..0000000000 --- a/samples/interop/NativeEmbedSample/MainView.axaml.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; - -namespace NativeEmbedSample; - -public class MainView : UserControl -{ - public MainView() - { - AvaloniaXamlLoader.Load(this); - } - - public async void ShowPopupDelay(object sender, RoutedEventArgs args) - { - await Task.Delay(3000); - ShowPopup(sender, args); - } - - public void ShowPopup(object sender, RoutedEventArgs args) - { - new ContextMenu() - { - Items = new List - { - new MenuItem() { Header = "Test" }, new MenuItem() { Header = "Test" } - } - }.Open((Control)sender); - } - - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - - if (change.Property == BoundsProperty) - { - var isMobile = change.GetNewValue().Width < 1200; - this.Find("FirstPanel")!.Classes.Set("mobile", isMobile); - this.Find("SecondPanel")!.Classes.Set("mobile", isMobile); - } - } -} diff --git a/samples/interop/NativeEmbedSample/MainWindow.axaml b/samples/interop/NativeEmbedSample/MainWindow.axaml deleted file mode 100644 index a615428778..0000000000 --- a/samples/interop/NativeEmbedSample/MainWindow.axaml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/samples/interop/NativeEmbedSample/MainWindow.axaml.cs b/samples/interop/NativeEmbedSample/MainWindow.axaml.cs deleted file mode 100644 index a261dad5ed..0000000000 --- a/samples/interop/NativeEmbedSample/MainWindow.axaml.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Markup.Xaml; - -namespace NativeEmbedSample; - -public class MainWindow : Window -{ - public MainWindow() - { - AvaloniaXamlLoader.Load(this); -#if DEBUG && DESKTOP - this.AttachDevTools(); -#endif - } -} - diff --git a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj deleted file mode 100644 index 7783b6f43d..0000000000 --- a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj +++ /dev/null @@ -1,38 +0,0 @@ - - - - net6.0;net6.0-android;net6.0-ios - true - - $(DefineConstants);DESKTOP - - - - - - - - - - - - - - - - Gtk\Gtk.cs - - - - PreserveNewest - - - - - - - - - - - diff --git a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs index 7d12404090..4738bd86f9 100644 --- a/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs +++ b/src/Android/Avalonia.Android/Platform/AndroidNativeControlHostImpl.cs @@ -110,8 +110,10 @@ namespace Avalonia.Android.Platform public void HideWithSize(Size size) { CheckDisposed(); + if (_attachedTo == null) + return; - size *= _attachedTo?._avaloniaView.TopLevelImpl.RenderScaling ?? 1; + size *= _attachedTo._avaloniaView.TopLevelImpl.RenderScaling; _view.Visibility = ViewStates.Gone; _view.LayoutParameters = new FrameLayout.LayoutParams(Math.Max(1, (int)size.Width), Math.Max(1, (int)size.Height)); _view.RequestLayout(); From 9db00cf9ded30a0b0ab49e1633bf082b93a838d9 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 11 May 2022 00:04:32 -0400 Subject: [PATCH 073/332] Solve app.manifest error in Win32NativeControlHost --- .../ControlCatalog.NetCore.csproj | 1 + samples/ControlCatalog.NetCore/app.manifest | 28 +++++++++++++++++++ .../Avalonia.Win32/Win32NativeControlHost.cs | 4 +++ 3 files changed, 33 insertions(+) create mode 100644 samples/ControlCatalog.NetCore/app.manifest diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj index 2db150ec85..0667644643 100644 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj @@ -45,6 +45,7 @@ en + app.manifest diff --git a/samples/ControlCatalog.NetCore/app.manifest b/samples/ControlCatalog.NetCore/app.manifest new file mode 100644 index 0000000000..db90057191 --- /dev/null +++ b/samples/ControlCatalog.NetCore/app.manifest @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs b/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs index 2a1628ea7d..fd05e780bf 100644 --- a/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs +++ b/src/Windows/Avalonia.Win32/Win32NativeControlHost.cs @@ -94,6 +94,10 @@ namespace Avalonia.Win32 IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + + if (Handle == IntPtr.Zero) + throw new InvalidOperationException("Unable to create child window for native control host. Application manifest with supported OS list might be required."); + if (layered) UnmanagedMethods.SetLayeredWindowAttributes(Handle, 0, 255, UnmanagedMethods.LayeredWindowFlags.LWA_ALPHA); From 855dade9d592e0d045599a214f62a3b4c0710298 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 11 May 2022 00:11:47 -0400 Subject: [PATCH 074/332] Add Browser implementation --- samples/ControlCatalog.Web/App.razor.cs | 4 + .../ControlCatalog.Web/EmbedSample.Browser.cs | 34 ++++ .../Shared/MainLayout.razor.css | 70 -------- .../ControlCatalog.Web/wwwroot/css/app.css | 44 +---- samples/ControlCatalog.Web/wwwroot/js/app.js | 11 +- .../Avalonia.Web.Blazor/AvaloniaView.razor | 44 ++++- .../Avalonia.Web.Blazor/AvaloniaView.razor.cs | 43 +++-- .../Interop/NativeControlHostImpl.cs | 152 ++++++++++++++++++ .../Interop/Typescript/NativeControlHost.ts | 56 +++++++ .../JSObjectControlHandle.cs | 35 ++++ .../RazorViewTopLevelImpl.cs | 12 +- 11 files changed, 371 insertions(+), 134 deletions(-) create mode 100644 samples/ControlCatalog.Web/EmbedSample.Browser.cs delete mode 100644 samples/ControlCatalog.Web/Shared/MainLayout.razor.css create mode 100644 src/Web/Avalonia.Web.Blazor/Interop/NativeControlHostImpl.cs create mode 100644 src/Web/Avalonia.Web.Blazor/Interop/Typescript/NativeControlHost.ts create mode 100644 src/Web/Avalonia.Web.Blazor/JSObjectControlHandle.cs diff --git a/samples/ControlCatalog.Web/App.razor.cs b/samples/ControlCatalog.Web/App.razor.cs index a150824ac3..c0b7ddbe1e 100644 --- a/samples/ControlCatalog.Web/App.razor.cs +++ b/samples/ControlCatalog.Web/App.razor.cs @@ -7,6 +7,10 @@ public partial class App protected override void OnParametersSet() { WebAppBuilder.Configure() + .AfterSetup(_ => + { + ControlCatalog.Pages.EmbedSample.Implementation = new EmbedSampleWeb(); + }) .SetupWithSingleViewLifetime(); base.OnParametersSet(); diff --git a/samples/ControlCatalog.Web/EmbedSample.Browser.cs b/samples/ControlCatalog.Web/EmbedSample.Browser.cs new file mode 100644 index 0000000000..5fe14409de --- /dev/null +++ b/samples/ControlCatalog.Web/EmbedSample.Browser.cs @@ -0,0 +1,34 @@ +using System; + +using Avalonia; +using Avalonia.Platform; +using Avalonia.Web.Blazor; + +using ControlCatalog.Pages; + +using Microsoft.JSInterop; + +namespace ControlCatalog.Web; + +public class EmbedSampleWeb : INativeDemoControl +{ + public IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func createDefault) + { + var runtime = AvaloniaLocator.Current.GetRequiredService(); + + if (isSecond) + { + var iframe = runtime.Invoke("document.createElement", "iframe"); + iframe.InvokeVoid("setAttribute", "src", "https://www.youtube.com/embed/kZCIporjJ70"); + + return new JSObjectControlHandle(iframe); + } + else + { + // window.createAppButton source is defined in "app.js" file. + var button = runtime.Invoke("window.createAppButton"); + + return new JSObjectControlHandle(button); + } + } +} diff --git a/samples/ControlCatalog.Web/Shared/MainLayout.razor.css b/samples/ControlCatalog.Web/Shared/MainLayout.razor.css deleted file mode 100644 index 43c355a47a..0000000000 --- a/samples/ControlCatalog.Web/Shared/MainLayout.razor.css +++ /dev/null @@ -1,70 +0,0 @@ -.page { - position: relative; - display: flex; - flex-direction: column; -} - -.main { - flex: 1; -} - -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - -.top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; -} - - .top-row ::deep a, .top-row .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - } - - .top-row a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } - -@media (max-width: 640.98px) { - .top-row:not(.auth) { - display: none; - } - - .top-row.auth { - justify-content: space-between; - } - - .top-row a, .top-row .btn-link { - margin-left: 0; - } -} - -@media (min-width: 641px) { - .page { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .top-row { - position: sticky; - top: 0; - z-index: 1; - } - - .main > div { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } -} diff --git a/samples/ControlCatalog.Web/wwwroot/css/app.css b/samples/ControlCatalog.Web/wwwroot/css/app.css index d2a8dc525c..49ca14e162 100644 --- a/samples/ControlCatalog.Web/wwwroot/css/app.css +++ b/samples/ControlCatalog.Web/wwwroot/css/app.css @@ -44,47 +44,13 @@ a, .btn-link { z-index: 1000; } - #blazor-error-ui .dismiss { - cursor: pointer; - position: absolute; - right: 0.75rem; - top: 0.5rem; - } - -.canvas-container { - opacity:1; - background-color:#ccc; - position:fixed; - width:100%; - height:100%; - top:0px; - left:0px; - z-index:500; -} - -canvas -{ - opacity:1; - background-color:#ccc; - position:fixed; - width:100%; - height:100%; - top:0px; - left:0px; - z-index:500; +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; } #app, .page { height: 100%; } - -.overlay{ - opacity:0.0; - background-color:#ccc; - position:fixed; - width:100vw; - height:100vh; - top:0px; - left:0px; - z-index:1000; -} diff --git a/samples/ControlCatalog.Web/wwwroot/js/app.js b/samples/ControlCatalog.Web/wwwroot/js/app.js index 5f282702bb..29697661a6 100644 --- a/samples/ControlCatalog.Web/wwwroot/js/app.js +++ b/samples/ControlCatalog.Web/wwwroot/js/app.js @@ -1 +1,10 @@ - \ No newline at end of file +window.createAppButton = function () { + var button = document.createElement('button'); + button.innerText = 'Hello world'; + var clickCount = 0; + button.onclick = () => { + clickCount++; + button.innerText = 'Click count ' + clickCount; + }; + return button; +} diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor index 584c77a62c..3dd98f8cd3 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor @@ -10,10 +10,42 @@ onkeydown="@OnKeyDown" onkeyup="@OnKeyUp"> - - - + + +

+ + diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index 1ccf53943a..be58d9d49c 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -1,5 +1,6 @@ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.Embedding; +using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Raw; using Avalonia.Input.TextInput; @@ -18,14 +19,16 @@ namespace Avalonia.Web.Blazor private EmbeddableControlRoot _topLevel; // Interop - private SKHtmlCanvasInterop _interop = null!; - private SizeWatcherInterop _sizeWatcher = null!; - private DpiWatcherInterop _dpiWatcher = null!; - private SKHtmlCanvasInterop.GLInfo? _jsGlInfo = null!; - private InputHelperInterop _inputHelper = null!; - private InputHelperInterop _canvasHelper = null!; + private SKHtmlCanvasInterop? _interop = null; + private SizeWatcherInterop? _sizeWatcher = null; + private DpiWatcherInterop? _dpiWatcher = null; + private SKHtmlCanvasInterop.GLInfo? _jsGlInfo = null; + private InputHelperInterop? _inputHelper = null; + private InputHelperInterop? _canvasHelper = null; + private NativeControlHostInterop? _nativeControlHost = null; private ElementReference _htmlCanvas; private ElementReference _inputElement; + private ElementReference _nativeControlsContainer; private double _dpi = 1; private SKSize _canvasSize = new (100, 100); @@ -49,6 +52,11 @@ namespace Avalonia.Web.Blazor } } + internal INativeControlHostImpl GetNativeControlHostImpl() + { + return _nativeControlHost ?? throw new InvalidOperationException("Blazor View wasn't initialized yet"); + } + private void OnTouchStart(TouchEventArgs e) { foreach (var touch in e.ChangedTouches) @@ -243,7 +251,7 @@ namespace Avalonia.Web.Blazor } } - _inputHelper.Clear(); + _inputHelper?.Clear(); } [Parameter(CaptureUnmatchedValues = true)] @@ -253,6 +261,8 @@ namespace Avalonia.Web.Blazor { if (firstRender) { + AvaloniaLocator.CurrentMutable.Bind().ToConstant((IJSInProcessRuntime)Js); + _inputHelper = await InputHelperInterop.ImportAsync(Js, _inputElement); _canvasHelper = await InputHelperInterop.ImportAsync(Js, _htmlCanvas); @@ -264,6 +274,8 @@ namespace Avalonia.Web.Blazor _canvasHelper.SetCursor(x); //windows }; + _nativeControlHost = await NativeControlHostInterop.ImportAsync(Js, _nativeControlsContainer); + Console.WriteLine("starting html canvas setup"); _interop = await SKHtmlCanvasInterop.ImportAsync(Js, _htmlCanvas, OnRenderFrame); @@ -319,9 +331,9 @@ namespace Avalonia.Web.Blazor public void Dispose() { - _dpiWatcher.Unsubscribe(OnDpiChanged); - _sizeWatcher.Dispose(); - _interop.Dispose(); + _dpiWatcher?.Unsubscribe(OnDpiChanged); + _sizeWatcher?.Dispose(); + _interop?.Dispose(); } private void ForceBlit() @@ -345,7 +357,7 @@ namespace Avalonia.Web.Blazor { _dpi = newDpi; - _interop.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi)); + _interop!.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi)); _topLevelImpl.SetClientSize(_canvasSize, _dpi); @@ -359,7 +371,7 @@ namespace Avalonia.Web.Blazor { _canvasSize = newSize; - _interop.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi)); + _interop!.SetCanvasSize((int)(_canvasSize.Width * _dpi), (int)(_canvasSize.Height * _dpi)); _topLevelImpl.SetClientSize(_canvasSize, _dpi); @@ -369,6 +381,11 @@ namespace Avalonia.Web.Blazor public void SetClient(ITextInputMethodClient? client) { + if (_inputHelper is null) + { + return; + } + _inputHelper.Clear(); var active = client is { }; @@ -394,7 +411,7 @@ namespace Avalonia.Web.Blazor public void Reset() { - _inputHelper.Clear(); + _inputHelper?.Clear(); } } } diff --git a/src/Web/Avalonia.Web.Blazor/Interop/NativeControlHostImpl.cs b/src/Web/Avalonia.Web.Blazor/Interop/NativeControlHostImpl.cs new file mode 100644 index 0000000000..48362b03c4 --- /dev/null +++ b/src/Web/Avalonia.Web.Blazor/Interop/NativeControlHostImpl.cs @@ -0,0 +1,152 @@ +#nullable enable +using System.Diagnostics.CodeAnalysis; + +using Avalonia.Controls.Platform; +using Avalonia.Platform; + +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; + +namespace Avalonia.Web.Blazor.Interop +{ + + internal class NativeControlHostInterop : JSModuleInterop, INativeControlHostImpl + { + private const string JsFilename = "./_content/Avalonia.Web.Blazor/NativeControlHost.js"; + private const string CreateDefaultChildSymbol = "NativeControlHost.CreateDefaultChild"; + private const string CreateAttachmentSymbol = "NativeControlHost.CreateAttachment"; + private const string GetReferenceSymbol = "NativeControlHost.GetReference"; + + private readonly ElementReference hostElement; + + public static async Task ImportAsync(IJSRuntime js, ElementReference element) + { + var interop = new NativeControlHostInterop(js, element); + await interop.ImportAsync(); + return interop; + } + + public NativeControlHostInterop(IJSRuntime js, ElementReference element) + : base(js, JsFilename) + { + hostElement = element; + } + + public INativeControlHostDestroyableControlHandle CreateDefaultChild(IPlatformHandle parent) + { + var element = Invoke(CreateDefaultChildSymbol); + return new JSObjectControlHandle(element); + } + + public INativeControlHostControlTopLevelAttachment CreateNewAttachment(Func create) + { + Attachment? a = null; + try + { + using var hostElementJsReference = Invoke(GetReferenceSymbol, hostElement); + var child = create(new JSObjectControlHandle(hostElementJsReference)); + var attachmenetReference = Invoke(CreateAttachmentSymbol); + // It has to be assigned to the variable before property setter is called so we dispose it on exception +#pragma warning disable IDE0017 // Simplify object initialization + a = new Attachment(attachmenetReference, child); +#pragma warning restore IDE0017 // Simplify object initialization + a.AttachedTo = this; + return a; + } + catch + { + a?.Dispose(); + throw; + } + } + + public INativeControlHostControlTopLevelAttachment CreateNewAttachment(IPlatformHandle handle) + { + var attachmenetReference = Invoke(CreateAttachmentSymbol); + var a = new Attachment(attachmenetReference, handle); + a.AttachedTo = this; + return a; + } + + public bool IsCompatibleWith(IPlatformHandle handle) => handle is JSObjectControlHandle; + + class Attachment : INativeControlHostControlTopLevelAttachment + { + private const string InitializeWithChildHandleSymbol = "InitializeWithChildHandle"; + private const string AttachToSymbol = "AttachTo"; + private const string ShowInBoundsSymbol = "ShowInBounds"; + private const string HideWithSizeSymbol = "HideWithSize"; + private const string ReleaseChildSymbol = "ReleaseChild"; + + private IJSInProcessObjectReference? _native; + private NativeControlHostInterop? _attachedTo; + + public Attachment(IJSInProcessObjectReference native, IPlatformHandle handle) + { + _native = native; + _native.InvokeVoid(InitializeWithChildHandleSymbol, ((JSObjectControlHandle)handle).Object); + } + + public void Dispose() + { + if (_native != null) + { + _native.InvokeVoid(ReleaseChildSymbol); + _native.Dispose(); + _native = null; + } + } + + public INativeControlHostImpl? AttachedTo + { + get => _attachedTo!; + set + { + CheckDisposed(); + + var host = (NativeControlHostInterop?)value; + if (host == null) + { + _native.InvokeVoid(AttachToSymbol); + } + else + { + _native.InvokeVoid(AttachToSymbol, host.hostElement); + } + _attachedTo = host; + } + } + + public bool IsCompatibleWith(INativeControlHostImpl host) => host is NativeControlHostInterop; + + public void HideWithSize(Size size) + { + CheckDisposed(); + if (_attachedTo == null) + return; + + _native.InvokeVoid(HideWithSizeSymbol, Math.Max(1, (float)size.Width), Math.Max(1, (float)size.Height)); + } + + public void ShowInBounds(Rect bounds) + { + CheckDisposed(); + + if (_attachedTo == null) + throw new InvalidOperationException("Native control isn't attached to a toplevel"); + + bounds = new Rect(bounds.X, bounds.Y, Math.Max(1, bounds.Width), + Math.Max(1, bounds.Height)); + + _native.InvokeVoid(ShowInBoundsSymbol, (float)bounds.X, (float)bounds.Y, (float)bounds.Width, (float)bounds.Height); + } + + [MemberNotNull(nameof(_native))] + private void CheckDisposed() + { + if (_native == null) + throw new ObjectDisposedException(nameof(Attachment)); + } + } + } +} diff --git a/src/Web/Avalonia.Web.Blazor/Interop/Typescript/NativeControlHost.ts b/src/Web/Avalonia.Web.Blazor/Interop/Typescript/NativeControlHost.ts new file mode 100644 index 0000000000..baa9191845 --- /dev/null +++ b/src/Web/Avalonia.Web.Blazor/Interop/Typescript/NativeControlHost.ts @@ -0,0 +1,56 @@ +export class NativeControlHost { + public static CreateDefaultChild(parent: HTMLElement): HTMLElement { + return document.createElement("div"); + } + + // Used to convert ElementReference to JSObjectReference. + // Is there a better way? + public static GetReference(element: Element): Element { + return element; + } + + public static CreateAttachment(): NativeControlHostTopLevelAttachment { + return new NativeControlHostTopLevelAttachment(); + } +} + +class NativeControlHostTopLevelAttachment +{ + _child: HTMLElement; + _host: HTMLElement; + + InitializeWithChildHandle(child: HTMLElement) { + this._child = child; + this._child.style.position = "absolute"; + } + + AttachTo(host: HTMLElement): void { + if (this._host) { + this._host.removeChild(this._child); + } + + this._host = host; + + if (this._host) { + this._host.appendChild(this._child); + } + } + + ShowInBounds(x: number, y: number, width: number, height: number): void { + this._child.style.top = y + "px"; + this._child.style.left = x + "px"; + this._child.style.width = width + "px"; + this._child.style.height = height + "px"; + this._child.style.display = "block"; + } + + HideWithSize(width: number, height: number): void { + this._child.style.width = width + "px"; + this._child.style.height = height + "px"; + this._child.style.display = "none"; + } + + ReleaseChild(): void { + this._child = null; + } +} diff --git a/src/Web/Avalonia.Web.Blazor/JSObjectControlHandle.cs b/src/Web/Avalonia.Web.Blazor/JSObjectControlHandle.cs new file mode 100644 index 0000000000..4426c3fbd7 --- /dev/null +++ b/src/Web/Avalonia.Web.Blazor/JSObjectControlHandle.cs @@ -0,0 +1,35 @@ +#nullable enable +using Avalonia.Controls.Platform; + +using Microsoft.JSInterop; + +namespace Avalonia.Web.Blazor +{ + public class JSObjectControlHandle : INativeControlHostDestroyableControlHandle + { + internal const string ElementReferenceDescriptor = "JSObjectReference"; + + public JSObjectControlHandle(IJSObjectReference reference) + { + Object = reference; + } + + public IJSObjectReference Object { get; } + + public IntPtr Handle => throw new NotSupportedException(); + + public string? HandleDescriptor => ElementReferenceDescriptor; + + public void Destroy() + { + if (Object is IJSInProcessObjectReference inProcess) + { + inProcess.Dispose(); + } + else + { + _ = Object.DisposeAsync(); + } + } + } +} diff --git a/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs b/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs index 209a635a7b..50070e6e2c 100644 --- a/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs +++ b/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs @@ -13,19 +13,19 @@ using SkiaSharp; namespace Avalonia.Web.Blazor { - internal class RazorViewTopLevelImpl : ITopLevelImplWithTextInputMethod + internal class RazorViewTopLevelImpl : ITopLevelImplWithTextInputMethod, ITopLevelImplWithNativeControlHost { private Size _clientSize; private BlazorSkiaSurface? _currentSurface; private IInputRoot? _inputRoot; private readonly Stopwatch _sw = Stopwatch.StartNew(); - private readonly ITextInputMethodImpl _textInputMethod; + private readonly AvaloniaView _avaloniaView; private readonly TouchDevice _touchDevice; private string _currentCursor = CssCursor.Default; - public RazorViewTopLevelImpl(ITextInputMethodImpl textInputMethod) + public RazorViewTopLevelImpl(AvaloniaView avaloniaView) { - _textInputMethod = textInputMethod; + _avaloniaView = avaloniaView; TransparencyLevel = WindowTransparencyLevel.None; AcrylicCompensationLevels = new AcrylicPlatformCompensationLevels(1, 1, 1); _touchDevice = new TouchDevice(); @@ -175,6 +175,8 @@ namespace Avalonia.Web.Blazor public WindowTransparencyLevel TransparencyLevel { get; } public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } - public ITextInputMethodImpl TextInputMethod => _textInputMethod; + public ITextInputMethodImpl TextInputMethod => _avaloniaView; + + public INativeControlHostImpl? NativeControlHost => _avaloniaView.GetNativeControlHostImpl(); } } From 35db70c8d4905eba47f0fd73e2de0830d5e8e2fe Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 12 May 2022 14:37:23 +0200 Subject: [PATCH 075/332] Don't expose viewbox container as logical child. #7735 introduced an internal container control which hosts the child, but it exposed this child in the logical tree, breaking any styles which relied on the `Viewbox.Child` being the logical child of the `Viewbox`. Fix this by introducing a simple internal `ViewboxContainer` control as the container. --- src/Avalonia.Controls/Viewbox.cs | 43 +++++++++++++++++-- .../ViewboxTests.cs | 20 +++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs index 33a05f126d..f3ec53ed2d 100644 --- a/src/Avalonia.Controls/Viewbox.cs +++ b/src/Avalonia.Controls/Viewbox.cs @@ -8,7 +8,7 @@ namespace Avalonia.Controls ///
public class Viewbox : Control { - private Decorator _containerVisual; + private ViewboxContainer _containerVisual; /// /// Defines the property. @@ -37,9 +37,8 @@ namespace Avalonia.Controls public Viewbox() { - _containerVisual = new Decorator(); + _containerVisual = new ViewboxContainer(); _containerVisual.RenderTransformOrigin = RelativePoint.TopLeft; - LogicalChildren.Add(_containerVisual); VisualChildren.Add(_containerVisual); } @@ -88,7 +87,22 @@ namespace Avalonia.Controls if (change.Property == ChildProperty) { + var (oldChild, newChild) = change.GetOldAndNewValue(); + + if (oldChild is not null) + { + ((ISetLogicalParent)oldChild).SetParent(null); + LogicalChildren.Remove(oldChild); + } + _containerVisual.Child = change.GetNewValue(); + + if (newChild is not null) + { + ((ISetLogicalParent)newChild).SetParent(this); + LogicalChildren.Add(newChild); + } + InvalidateMeasure(); } } @@ -129,5 +143,28 @@ namespace Avalonia.Controls return finalSize; } + + private class ViewboxContainer : Control + { + private IControl? _child; + + public IControl? Child + { + get => _child; + set + { + if (_child != value) + { + if (_child is not null) + VisualChildren.Remove(_child); + + _child = value; + + if (_child is not null) + VisualChildren.Add(_child); + } + } + } + } } } diff --git a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs index d33e55341b..39a14a6a7e 100644 --- a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs @@ -1,4 +1,5 @@ using Avalonia.Controls.Shapes; +using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.UnitTests; using Xunit; @@ -170,5 +171,24 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(expectedScale, scaleTransform.ScaleX); Assert.Equal(expectedScale, scaleTransform.ScaleY); } + + [Fact] + public void Child_Should_Be_Logical_Child_Of_Viewbox() + { + var target = new Viewbox(); + + Assert.Empty(target.GetLogicalChildren()); + + var child = new Canvas(); + target.Child = child; + + Assert.Single(target.GetLogicalChildren(), child); + Assert.Same(child.GetLogicalParent(), target); + + target.Child = null; + + Assert.Empty(target.GetLogicalChildren()); + Assert.Null(child.GetLogicalParent()); + } } } From 36fefd871704a48ef6fd553845ad6c03e70ea9ad Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 12 May 2022 22:44:29 +0200 Subject: [PATCH 076/332] Fix copypasta. Co-authored-by: Max Katz --- src/Avalonia.Controls/Viewbox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs index f3ec53ed2d..55c52d8ed9 100644 --- a/src/Avalonia.Controls/Viewbox.cs +++ b/src/Avalonia.Controls/Viewbox.cs @@ -95,7 +95,7 @@ namespace Avalonia.Controls LogicalChildren.Remove(oldChild); } - _containerVisual.Child = change.GetNewValue(); + _containerVisual.Child = newChild; if (newChild is not null) { From e4f4837a8d3ac9e8a30cb84c03c6dbcb2da39d0b Mon Sep 17 00:00:00 2001 From: robloo Date: Thu, 12 May 2022 21:52:36 -0400 Subject: [PATCH 077/332] Simplify getting changed property values Co-authored-by: Max Katz --- src/Avalonia.Controls/Calendar/CalendarDatePicker.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs index 0005e07536..8dffc43d91 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDatePicker.cs @@ -291,8 +291,7 @@ namespace Avalonia.Controls // Text else if (change.Property == TextProperty) { - var oldValue = change.GetOldValue(); - var value = change.GetNewValue(); + var (oldValue, value) = change.GetOldAndNewValue(); if (!_suspendTextChangeHandler) { From ccce304c69385fc3f5c41a3646084792c0f37f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 13 May 2022 14:13:20 +0200 Subject: [PATCH 078/332] Fix TimePicker property registrations --- src/Avalonia.Controls/DateTimePickers/TimePicker.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs index f04c79505e..047667567d 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePicker.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePicker.cs @@ -38,13 +38,13 @@ namespace Avalonia.Controls /// Defines the property /// public static readonly StyledProperty HeaderProperty = - AvaloniaProperty.Register(nameof(Header)); + AvaloniaProperty.Register(nameof(Header)); /// /// Defines the property /// public static readonly StyledProperty HeaderTemplateProperty = - AvaloniaProperty.Register(nameof(HeaderTemplate)); + AvaloniaProperty.Register(nameof(HeaderTemplate)); /// /// Defines the property From 2ee94118305364b72aee6865d427f1330314bc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 13 May 2022 14:16:05 +0200 Subject: [PATCH 079/332] Fix SelectingItemsControl WrapSelection property owner --- src/Avalonia.Controls/Primitives/SelectingItemsControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index 164aab32db..a730659330 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -118,7 +118,7 @@ namespace Avalonia.Controls.Primitives /// Defines the property. /// public static readonly StyledProperty WrapSelectionProperty = - AvaloniaProperty.Register(nameof(WrapSelection), defaultValue: false); + AvaloniaProperty.Register(nameof(WrapSelection), defaultValue: false); private static readonly IList Empty = Array.Empty(); private string _textSearchTerm = string.Empty; From 08cbec6f23848dab0680531a059eb8c92babb290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 13 May 2022 14:28:42 +0200 Subject: [PATCH 080/332] Fix ContentPresenter property field types --- .../Presenters/ContentPresenter.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs index 996cb29534..12a8dd747d 100644 --- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs @@ -52,67 +52,67 @@ namespace Avalonia.Controls.Presenters /// /// Defines the property. /// - public static readonly AttachedProperty ForegroundProperty = + public static readonly StyledProperty ForegroundProperty = TextElement.ForegroundProperty.AddOwner(); /// /// Defines the property. /// - public static readonly AttachedProperty FontFamilyProperty = + public static readonly StyledProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(); /// /// Defines the property. /// - public static readonly AttachedProperty FontSizeProperty = + public static readonly StyledProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(); /// /// Defines the property. /// - public static readonly AttachedProperty FontStyleProperty = + public static readonly StyledProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(); /// /// Defines the property. /// - public static readonly AttachedProperty FontWeightProperty = + public static readonly StyledProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(); /// /// Defines the property. /// - public static readonly AttachedProperty FontStretchProperty = + public static readonly StyledProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(); /// /// Defines the property /// - public static readonly AttachedProperty TextAlignmentProperty = + public static readonly StyledProperty TextAlignmentProperty = TextBlock.TextAlignmentProperty.AddOwner(); /// /// Defines the property /// - public static readonly AttachedProperty TextWrappingProperty = + public static readonly StyledProperty TextWrappingProperty = TextBlock.TextWrappingProperty.AddOwner(); /// /// Defines the property /// - public static readonly AttachedProperty TextTrimmingProperty = + public static readonly StyledProperty TextTrimmingProperty = TextBlock.TextTrimmingProperty.AddOwner(); /// /// Defines the property /// - public static readonly AttachedProperty LineHeightProperty = + public static readonly StyledProperty LineHeightProperty = TextBlock.LineHeightProperty.AddOwner(); /// /// Defines the property /// - public static readonly AttachedProperty MaxLinesProperty = + public static readonly StyledProperty MaxLinesProperty = TextBlock.MaxLinesProperty.AddOwner(); /// From b34095fda37618cde431112f0abc3be3056f5ac2 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Fri, 13 May 2022 23:53:26 +0200 Subject: [PATCH 081/332] Optimize memory usage of styles and fix ordering issue in devtools. --- src/Avalonia.Base/Styling/IStyleInstance.cs | 5 +++ .../Styling/PropertySetterInstance.cs | 10 +++--- ...e.cs => PropertySetterTemplateInstance.cs} | 31 ++++++++-------- src/Avalonia.Base/Styling/Setter.cs | 9 ----- src/Avalonia.Base/Styling/StyleInstance.cs | 35 ++++++++++--------- .../ViewModels/ControlDetailsViewModel.cs | 3 +- 6 files changed, 46 insertions(+), 47 deletions(-) rename src/Avalonia.Base/Styling/{PropertySetterLazyInstance.cs => PropertySetterTemplateInstance.cs} (79%) diff --git a/src/Avalonia.Base/Styling/IStyleInstance.cs b/src/Avalonia.Base/Styling/IStyleInstance.cs index 8ddb989bc0..d4f7510eb3 100644 --- a/src/Avalonia.Base/Styling/IStyleInstance.cs +++ b/src/Avalonia.Base/Styling/IStyleInstance.cs @@ -14,6 +14,11 @@ namespace Avalonia.Styling /// IStyle Source { get; } + /// + /// Gets a value indicating whether this style has an activator. + /// + bool HasActivator { get; } + /// /// Gets a value indicating whether this style is active. /// diff --git a/src/Avalonia.Base/Styling/PropertySetterInstance.cs b/src/Avalonia.Base/Styling/PropertySetterInstance.cs index 48f462d006..c4e8f47e67 100644 --- a/src/Avalonia.Base/Styling/PropertySetterInstance.cs +++ b/src/Avalonia.Base/Styling/PropertySetterInstance.cs @@ -44,7 +44,7 @@ namespace Avalonia.Styling { if (hasActivator) { - if (_styledProperty is object) + if (_styledProperty is not null) { _subscription = _target.Bind(_styledProperty, this, BindingPriority.StyleTrigger); } @@ -55,13 +55,15 @@ namespace Avalonia.Styling } else { - if (_styledProperty is object) + var target = (AvaloniaObject) _target; + + if (_styledProperty is not null) { - _subscription = _target.SetValue(_styledProperty!, _value, BindingPriority.Style); + _subscription = target.SetValue(_styledProperty!, _value, BindingPriority.Style); } else { - _target.SetValue(_directProperty!, _value); + target.SetValue(_directProperty!, _value); } } } diff --git a/src/Avalonia.Base/Styling/PropertySetterLazyInstance.cs b/src/Avalonia.Base/Styling/PropertySetterTemplateInstance.cs similarity index 79% rename from src/Avalonia.Base/Styling/PropertySetterLazyInstance.cs rename to src/Avalonia.Base/Styling/PropertySetterTemplateInstance.cs index 92653d0064..0f6efef1be 100644 --- a/src/Avalonia.Base/Styling/PropertySetterLazyInstance.cs +++ b/src/Avalonia.Base/Styling/PropertySetterTemplateInstance.cs @@ -11,42 +11,42 @@ namespace Avalonia.Styling /// evaluated. /// /// The target property type. - internal class PropertySetterLazyInstance : SingleSubscriberObservableBase>, + internal class PropertySetterTemplateInstance : SingleSubscriberObservableBase>, ISetterInstance { private readonly IStyleable _target; private readonly StyledPropertyBase? _styledProperty; private readonly DirectPropertyBase? _directProperty; - private readonly Func _valueFactory; + private readonly ITemplate _template; private BindingValue _value; private IDisposable? _subscription; private bool _isActive; - public PropertySetterLazyInstance( + public PropertySetterTemplateInstance( IStyleable target, StyledPropertyBase property, - Func valueFactory) + ITemplate template) { _target = target; _styledProperty = property; - _valueFactory = valueFactory; + _template = template; } - public PropertySetterLazyInstance( + public PropertySetterTemplateInstance( IStyleable target, DirectPropertyBase property, - Func valueFactory) + ITemplate template) { _target = target; _directProperty = property; - _valueFactory = valueFactory; + _template = template; } public void Start(bool hasActivator) { _isActive = !hasActivator; - if (_styledProperty is object) + if (_styledProperty is not null) { var priority = hasActivator ? BindingPriority.StyleTrigger : BindingPriority.Style; _subscription = _target.Bind(_styledProperty, this, priority); @@ -77,7 +77,7 @@ namespace Avalonia.Styling public override void Dispose() { - if (_subscription is object) + if (_subscription is not null) { var sub = _subscription; _subscription = null; @@ -85,7 +85,7 @@ namespace Avalonia.Styling } else if (_isActive) { - if (_styledProperty is object) + if (_styledProperty is not null) { _target.ClearValue(_styledProperty); } @@ -101,22 +101,21 @@ namespace Avalonia.Styling protected override void Subscribed() => PublishNext(); protected override void Unsubscribed() { } - private T GetValue() + private void EnsureTemplate() { if (_value.HasValue) { - return _value.Value; + return; } - _value = _valueFactory(); - return _value.Value; + _value = (T) _template.Build(); } private void PublishNext() { if (_isActive) { - GetValue(); + EnsureTemplate(); PublishNext(_value); } else diff --git a/src/Avalonia.Base/Styling/Setter.cs b/src/Avalonia.Base/Styling/Setter.cs index b4b3399022..d989bb0706 100644 --- a/src/Avalonia.Base/Styling/Setter.cs +++ b/src/Avalonia.Base/Styling/Setter.cs @@ -1,9 +1,7 @@ using System; using Avalonia.Animation; using Avalonia.Data; -using Avalonia.Data.Core; using Avalonia.Metadata; -using Avalonia.Utilities; #nullable enable @@ -70,12 +68,5 @@ namespace Avalonia.Styling return Property.CreateSetterInstance(target, Value); } - - private struct SetterVisitorData - { - public IStyleable target; - public object? value; - public ISetterInstance? result; - } } } diff --git a/src/Avalonia.Base/Styling/StyleInstance.cs b/src/Avalonia.Base/Styling/StyleInstance.cs index 830cf49a0d..db96da6821 100644 --- a/src/Avalonia.Base/Styling/StyleInstance.cs +++ b/src/Avalonia.Base/Styling/StyleInstance.cs @@ -11,10 +11,10 @@ namespace Avalonia.Styling /// /// A which has been instanced on a control. /// - internal class StyleInstance : IStyleInstance, IStyleActivatorSink + internal sealed class StyleInstance : IStyleInstance, IStyleActivatorSink { - private readonly List? _setters; - private readonly List? _animations; + private readonly ISetterInstance[]? _setters; + private readonly IDisposable[]? _animations; private readonly IStyleActivator? _activator; private readonly Subject? _animationTrigger; @@ -30,41 +30,42 @@ namespace Avalonia.Styling _activator = activator; IsActive = _activator is null; - if (setters is object) + if (setters is not null) { var setterCount = setters.Count; - _setters = new List(setterCount); + _setters = new ISetterInstance[setterCount]; for (var i = 0; i < setterCount; ++i) { - _setters.Add(setters[i].Instance(Target)); + _setters[i] = setters[i].Instance(Target); } } - if (animations is object && target is Animatable animatable) + if (animations is not null && target is Animatable animatable) { var animationsCount = animations.Count; - _animations = new List(animationsCount); + _animations = new IDisposable[animationsCount]; _animationTrigger = new Subject(); for (var i = 0; i < animationsCount; ++i) { - _animations.Add(animations[i].Apply(animatable, null, _animationTrigger)); + _animations[i] = animations[i].Apply(animatable, null, _animationTrigger); } } } + public bool HasActivator => _activator is not null; public bool IsActive { get; private set; } public IStyle Source { get; } public IStyleable Target { get; } public void Start() { - var hasActivator = _activator is object; + var hasActivator = HasActivator; - if (_setters is object) + if (_setters is not null) { foreach (var setter in _setters) { @@ -76,7 +77,7 @@ namespace Avalonia.Styling { _activator!.Subscribe(this, 0); } - else if (_animationTrigger != null) + else if (_animationTrigger is not null) { _animationTrigger.OnNext(true); } @@ -84,7 +85,7 @@ namespace Avalonia.Styling public void Dispose() { - if (_setters is object) + if (_setters is not null) { foreach (var setter in _setters) { @@ -92,11 +93,11 @@ namespace Avalonia.Styling } } - if (_animations is object) + if (_animations is not null) { - foreach (var subscripion in _animations) + foreach (var subscription in _animations) { - subscripion.Dispose(); + subscription.Dispose(); } } @@ -111,7 +112,7 @@ namespace Avalonia.Styling _animationTrigger?.OnNext(value); - if (_setters is object) + if (_setters is not null) { if (IsActive) { diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs index a1fd425571..e383c160e3 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs @@ -60,7 +60,8 @@ namespace Avalonia.Diagnostics.ViewModels var styleDiagnostics = styledElement.GetStyleDiagnostics(); - foreach (var appliedStyle in styleDiagnostics.AppliedStyles) + // We need to place styles without activator first, such styles will be overwritten by ones with activators. + foreach (var appliedStyle in styleDiagnostics.AppliedStyles.OrderBy(s => s.HasActivator)) { var styleSource = appliedStyle.Source; From 6c7dc426fcec124fcb2edb75be0ec1fa0bdb0afc Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Fri, 13 May 2022 23:59:09 +0200 Subject: [PATCH 082/332] Missing property changes. --- src/Avalonia.Base/DirectPropertyBase.cs | 5 ++--- src/Avalonia.Base/StyledPropertyBase.cs | 8 +++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs index 9c1ffce24c..efcb7dfecb 100644 --- a/src/Avalonia.Base/DirectPropertyBase.cs +++ b/src/Avalonia.Base/DirectPropertyBase.cs @@ -2,7 +2,6 @@ using Avalonia.Data; using Avalonia.Reactive; using Avalonia.Styling; -using Avalonia.Utilities; namespace Avalonia { @@ -188,10 +187,10 @@ namespace Avalonia } else if (value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(PropertyType)) { - return new PropertySetterLazyInstance( + return new PropertySetterTemplateInstance( target, this, - () => (TValue)template.Build()); + template); } else { diff --git a/src/Avalonia.Base/StyledPropertyBase.cs b/src/Avalonia.Base/StyledPropertyBase.cs index dd5eb703ea..da607720ff 100644 --- a/src/Avalonia.Base/StyledPropertyBase.cs +++ b/src/Avalonia.Base/StyledPropertyBase.cs @@ -1,9 +1,7 @@ using System; -using System.Diagnostics; using Avalonia.Data; using Avalonia.Reactive; using Avalonia.Styling; -using Avalonia.Utilities; namespace Avalonia { @@ -12,7 +10,7 @@ namespace Avalonia /// public abstract class StyledPropertyBase : AvaloniaProperty, IStyledPropertyAccessor { - private bool _inherits; + private readonly bool _inherits; /// /// Initializes a new instance of the class. @@ -243,10 +241,10 @@ namespace Avalonia } else if (value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(PropertyType)) { - return new PropertySetterLazyInstance( + return new PropertySetterTemplateInstance( target, this, - () => (TValue)template.Build()); + template); } else { From 90b67c3b9f73f2dfc6698f5f43486b0367c986cf Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sat, 14 May 2022 01:22:34 +0200 Subject: [PATCH 083/332] Modify test setup so actual framework classes are used. --- tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs index ef2586fcb7..ed4c78aa3e 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs @@ -91,16 +91,13 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Setter_Should_Apply_Value_Without_Activator_With_Style_Priority() { - var control = new Mock(); - var style = Mock.Of - - - - - - From 3fccb1417459a5cb96fedb156895af11ec460a0c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 19 May 2022 16:43:58 +0200 Subject: [PATCH 140/332] Added style caching to Style children. Extracted out the caching code from `Styles` and reuse for `Style.Children`. --- src/Avalonia.Base/Styling/Style.cs | 11 +++-- src/Avalonia.Base/Styling/StyleCache.cs | 58 +++++++++++++++++++++++++ src/Avalonia.Base/Styling/Styles.cs | 41 ++--------------- 3 files changed, 66 insertions(+), 44 deletions(-) create mode 100644 src/Avalonia.Base/Styling/StyleCache.cs diff --git a/src/Avalonia.Base/Styling/Style.cs b/src/Avalonia.Base/Styling/Style.cs index a8707e00c0..8fcf5eec8a 100644 --- a/src/Avalonia.Base/Styling/Style.cs +++ b/src/Avalonia.Base/Styling/Style.cs @@ -16,6 +16,7 @@ namespace Avalonia.Styling private IResourceDictionary? _resources; private List? _setters; private List? _animations; + private StyleCache? _childCache; /// /// Initializes a new instance of the class. @@ -124,12 +125,10 @@ namespace Avalonia.Styling if (_children is not null) { - foreach (var child in _children) - { - var childResult = child.TryAttach(target, host); - if (childResult > result) - result = childResult; - } + _childCache ??= new StyleCache(); + var childResult = _childCache.TryAttach(_children, target, host); + if (childResult > result) + result = childResult; } return result; diff --git a/src/Avalonia.Base/Styling/StyleCache.cs b/src/Avalonia.Base/Styling/StyleCache.cs new file mode 100644 index 0000000000..3285476880 --- /dev/null +++ b/src/Avalonia.Base/Styling/StyleCache.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; + +namespace Avalonia.Styling +{ + /// + /// Simple cache for improving performance of applying styles. + /// + /// + /// Maps to a list of styles that are known be be possible + /// matches. + /// + internal class StyleCache : Dictionary?> + { + public SelectorMatchResult TryAttach(IList styles, IStyleable target, IStyleHost? host) + { + if (TryGetValue(target.StyleKey, out var cached)) + { + if (cached is object) + { + var result = SelectorMatchResult.NeverThisType; + + foreach (var style in cached) + { + var childResult = style.TryAttach(target, host); + if (childResult > result) + result = childResult; + } + + return result; + } + else + { + return SelectorMatchResult.NeverThisType; + } + } + else + { + List? matches = null; + + foreach (var child in styles) + { + if (child.TryAttach(target, host) != SelectorMatchResult.NeverThisType) + { + matches ??= new List(); + matches.Add(child); + } + } + + Add(target.StyleKey, matches); + + return matches is null ? + SelectorMatchResult.NeverThisType : + SelectorMatchResult.AlwaysThisType; + } + } + } +} diff --git a/src/Avalonia.Base/Styling/Styles.cs b/src/Avalonia.Base/Styling/Styles.cs index d79081152e..7c0bc4ad7f 100644 --- a/src/Avalonia.Base/Styling/Styles.cs +++ b/src/Avalonia.Base/Styling/Styles.cs @@ -20,7 +20,7 @@ namespace Avalonia.Styling private readonly AvaloniaList _styles = new AvaloniaList(); private IResourceHost? _owner; private IResourceDictionary? _resources; - private Dictionary?>? _cache; + private StyleCache? _cache; public Styles() { @@ -111,43 +111,8 @@ namespace Avalonia.Styling public SelectorMatchResult TryAttach(IStyleable target, IStyleHost? host) { - _cache ??= new Dictionary?>(); - - if (_cache.TryGetValue(target.StyleKey, out var cached)) - { - if (cached is object) - { - foreach (var style in cached) - { - style.TryAttach(target, host); - } - - return SelectorMatchResult.AlwaysThisType; - } - else - { - return SelectorMatchResult.NeverThisType; - } - } - else - { - List? matches = null; - - foreach (var child in this) - { - if (child.TryAttach(target, host) != SelectorMatchResult.NeverThisType) - { - matches ??= new List(); - matches.Add(child); - } - } - - _cache.Add(target.StyleKey, matches); - - return matches is null ? - SelectorMatchResult.NeverThisType : - SelectorMatchResult.AlwaysThisType; - } + _cache ??= new StyleCache(); + return _cache.TryAttach(this, target, host); } /// From 0a7f34f4c681d0e445d91637cfc54108006c56d9 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 19 May 2022 20:25:14 +0200 Subject: [PATCH 141/332] Use nested styles in CheckBox template. --- .../Controls/CheckBox.xaml | 603 +++++++++--------- 1 file changed, 315 insertions(+), 288 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml b/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml index f16e1ed99f..2d70a35b13 100644 --- a/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml @@ -1,294 +1,321 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 75a10efcf10860c3644d6a2639f2b70355bd7617 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 19 May 2022 23:55:48 -0400 Subject: [PATCH 142/332] Avoid static references in DataGrid fluent theme --- .../Themes/Fluent.xaml | 141 +++++++----------- 1 file changed, 53 insertions(+), 88 deletions(-) diff --git a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml index 8243d9c22d..2baa8c88c9 100644 --- a/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml +++ b/src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml @@ -1,87 +1,51 @@ - + - 12,0,12,0 - 0.6 0.8 + 12,0,12,0 M1875 1011l-787 787v-1798h-128v1798l-787 -787l-90 90l941 941l941 -941z M1965 947l-941 -941l-941 941l90 90l787 -787v1798h128v-1798l787 787z M515 93l930 931l-930 931l90 90l1022 -1021l-1022 -1021z M1939 1581l90 -90l-1005 -1005l-1005 1005l90 90l915 -915z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Opacity="0.4" + Color="{DynamicResource SystemBaseMediumLowColor}" /> + + + From 55b19b445f210d579fad8105baaa9acbc3a12f9e Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 20 May 2022 16:59:53 +0200 Subject: [PATCH 143/332] Remove unused vars. --- .../Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs b/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs index c5f779cbbb..d49fcf03a2 100644 --- a/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs +++ b/tests/Avalonia.Base.UnitTests/Styling/SelectorTests_Nesting.cs @@ -222,7 +222,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Adding_Child_With_No_Nesting_Selector_Fails() { - var control = new Control1(); var parent = new Style(x => x.OfType()); var child = new Style(x => x.Class("foo")); @@ -232,7 +231,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Adding_Combinator_Selector_Child_With_No_Nesting_Selector_Fails() { - var control = new Control1(); var parent = new Style(x => x.OfType()); var child = new Style(x => x.Class("foo").Descendant().Class("bar")); @@ -242,7 +240,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Adding_Or_Selector_Child_With_No_Nesting_Selector_Fails() { - var control = new Control1(); var parent = new Style(x => x.OfType()); var child = new Style(x => Selectors.Or( x.Nesting().Class("foo"), @@ -254,7 +251,6 @@ namespace Avalonia.Base.UnitTests.Styling [Fact] public void Can_Add_Child_Without_Nesting_Selector_To_Style_Without_Selector() { - var control = new Control1(); var parent = new Style(); var child = new Style(x => x.Class("foo")); From 060ec9694b62d74a21ccef2420feb53c3ccb78cf Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 20 May 2022 19:50:41 +0100 Subject: [PATCH 144/332] Merge pull request #8165 from AvaloniaUI/fixes/position-osx Fix more OSX regressions --- native/Avalonia.Native/src/OSX/PopupImpl.mm | 17 ----------------- native/Avalonia.Native/src/OSX/WindowBaseImpl.h | 1 + .../Avalonia.Native/src/OSX/WindowBaseImpl.mm | 15 +++++++++------ 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/PopupImpl.mm b/native/Avalonia.Native/src/OSX/PopupImpl.mm index cf3ecefb3c..cb52047148 100644 --- a/native/Avalonia.Native/src/OSX/PopupImpl.mm +++ b/native/Avalonia.Native/src/OSX/PopupImpl.mm @@ -34,23 +34,6 @@ protected: return NSWindowStyleMaskBorderless; } - virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override - { - START_COM_CALL; - - @autoreleasepool - { - if (Window != nullptr) - { - [Window setContentSize:NSSize{x, y}]; - - [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))]; - } - - return S_OK; - } - } - public: virtual bool ShouldTakeFocusOnShow() override { diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 0e482f9f30..e3e646ff2a 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -35,6 +35,7 @@ BEGIN_INTERFACE_MAP() ComPtr _glContext; NSObject *renderTarget; AvnPoint lastPositionSet; + bool hasPosition; NSSize lastSize; NSSize lastMinSize; NSSize lastMaxSize; diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index b84e999825..bc512f80d8 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -30,8 +30,8 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) View = [[AvnView alloc] initWithParent:this]; StandardContainer = [[AutoFitContentView new] initWithContent:View]; - lastPositionSet.X = -1; - lastPositionSet.Y = -1; + lastPositionSet = { 0, 0 }; + hasPosition = false; lastSize = NSSize { 100, 100 }; lastMaxSize = NSSize { CGFLOAT_MAX, CGFLOAT_MAX}; lastMinSize = NSSize { 0, 0 }; @@ -92,9 +92,12 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { CreateNSWindow(isDialog); InitialiseNSWindow(); - if(lastPositionSet.X >= 0 && lastPositionSet.Y >= 0) + if(hasPosition) { SetPosition(lastPositionSet); + } else + { + [Window center]; } UpdateStyle(); @@ -288,12 +291,12 @@ HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reaso } @try { + lastSize = NSSize {x, y}; + if (!_shown) { BaseEvents->Resized(AvnSize{x, y}, reason); } - lastSize = NSSize {x, y}; - if(Window != nullptr) { [Window setContentSize:lastSize]; } @@ -385,6 +388,7 @@ HRESULT WindowBaseImpl::SetPosition(AvnPoint point) { @autoreleasepool { lastPositionSet = point; + hasPosition = true; if(Window != nullptr) { [Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(point))]; @@ -577,7 +581,6 @@ void WindowBaseImpl::InitialiseNSWindow() { [Window setContentMaxSize:lastMaxSize]; [Window setOpaque:false]; - [Window center]; if (lastMenu != nullptr) { [GetWindowProtocol() applyMenu:lastMenu]; From 4845c10d881d7aa3bdf10e4e417f0755a6b0c2c4 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Sat, 21 May 2022 11:36:57 +0200 Subject: [PATCH 145/332] fix(ExpressionNode): ensure _subscriber do not change during ValueChanged --- src/Avalonia.Base/Data/Core/ExpressionNode.cs | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Base/Data/Core/ExpressionNode.cs b/src/Avalonia.Base/Data/Core/ExpressionNode.cs index 54785f18e8..4f755ff140 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionNode.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionNode.cs @@ -98,36 +98,36 @@ namespace Avalonia.Data.Core private void ValueChanged(object? value, bool notify) { - if (_subscriber is null) - return; - - var notification = value as BindingNotification; - - if (notification == null) + if (_subscriber is { } subscriber) { - LastValue = value != null ? new WeakReference(value) : NullReference; + var notification = value as BindingNotification; + var next = Next; - if (Next != null) + if (notification == null) { - Next.Target = LastValue; + LastValue = value != null ? new WeakReference(value) : NullReference; + if (next != null) + { + next.Target = LastValue; + } + else if (notify) + { + subscriber(value); + } } - else if (notify) + else { - _subscriber(value); - } - } - else - { - LastValue = notification.Value != null ? new WeakReference(notification.Value) : NullReference; + LastValue = notification.Value != null ? new WeakReference(notification.Value) : NullReference; - if (Next != null) - { - Next.Target = LastValue; - } + if (next != null) + { + next.Target = LastValue; + } - if (Next == null || notification.Error != null) - { - _subscriber(value); + if (next == null || notification.Error != null) + { + subscriber(value); + } } } } From 81eb964ae6082bd4aac045000146f6d756fb8683 Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Mon, 23 May 2022 19:19:19 +0300 Subject: [PATCH 146/332] Fix Menu selection to match UWP. --- .../Platform/DefaultMenuInteractionHandler.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index 3b38750de7..66b2a84e6b 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -56,6 +56,7 @@ namespace Avalonia.Controls.Platform Menu.AddHandler(Avalonia.Controls.Menu.MenuOpenedEvent, this.MenuOpened); Menu.AddHandler(MenuItem.PointerEnterItemEvent, PointerEnter); Menu.AddHandler(MenuItem.PointerLeaveItemEvent, PointerLeave); + Menu.AddHandler(InputElement.PointerMovedEvent, PointerMoved); _root = Menu.VisualRoot; @@ -91,6 +92,7 @@ namespace Avalonia.Controls.Platform Menu.RemoveHandler(Avalonia.Controls.Menu.MenuOpenedEvent, this.MenuOpened); Menu.RemoveHandler(MenuItem.PointerEnterItemEvent, PointerEnter); Menu.RemoveHandler(MenuItem.PointerLeaveItemEvent, PointerLeave); + Menu.RemoveHandler(InputElement.PointerMovedEvent, PointerMoved); if (_root is InputElement inputRoot) { @@ -340,6 +342,21 @@ namespace Avalonia.Controls.Platform } } + protected internal virtual void PointerMoved(object? sender, PointerEventArgs e) + { + var item = GetMenuItem(e.Source as IControl) as MenuItem; + if (item?.TransformedBounds == null) + { + return; + } + var point = e.GetCurrentPoint(null); + + if (point.Properties.IsLeftButtonPressed && item.TransformedBounds.Value.Contains(point.Position) == false) + { + e.Pointer.Capture(null); + } + } + protected internal virtual void PointerLeave(object? sender, PointerEventArgs e) { var item = GetMenuItem(e.Source as IControl); From 40a4ea745bd93929d7e645f5cbaeaf4805886b0f Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Mon, 23 May 2022 21:43:27 +0300 Subject: [PATCH 147/332] replacement of ViewboxContainer inheritance from Control to Layoutable --- src/Avalonia.Controls/Viewbox.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs index 01a41a0157..01667c5136 100644 --- a/src/Avalonia.Controls/Viewbox.cs +++ b/src/Avalonia.Controls/Viewbox.cs @@ -1,6 +1,7 @@ using Avalonia.Media; using Avalonia.Media.Immutable; using Avalonia.Metadata; +using Avalonia.Layout; namespace Avalonia.Controls { @@ -150,7 +151,7 @@ namespace Avalonia.Controls /// /// A simple container control which hosts its child as a visual but not logical child. /// - private class ViewboxContainer : Control + private class ViewboxContainer : Layoutable { private IControl? _child; From ac24ee467ad565accf6bcd47f6901d6db07c0696 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 24 May 2022 01:35:08 -0400 Subject: [PATCH 148/332] Update TopLevelImpl.cs --- .../Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 8a475676a5..65a9adc937 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -40,7 +40,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform _gl = GlPlatformSurface.TryCreate(this); _framebuffer = new FramebufferManager(this); - RenderScaling = (int)_view.Scaling; + RenderScaling = _view.Scaling; MaxClientSize = new PixelSize(_view.Resources.DisplayMetrics.WidthPixels, _view.Resources.DisplayMetrics.HeightPixels).ToSize(RenderScaling); From 1c2da897e5bdea98100ef1f0c4f6ce0364010d76 Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Tue, 24 May 2022 15:18:56 +0300 Subject: [PATCH 149/332] Add comment. --- src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs index 66b2a84e6b..3a6d06f150 100644 --- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs +++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs @@ -344,6 +344,7 @@ namespace Avalonia.Controls.Platform protected internal virtual void PointerMoved(object? sender, PointerEventArgs e) { + // HACK: #8179 needs to be addressed to correctly implement it in the PointerPressed method. var item = GetMenuItem(e.Source as IControl) as MenuItem; if (item?.TransformedBounds == null) { From 0654d636932c863897121e3d66c6226c7a1cdd94 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 24 May 2022 15:13:19 +0200 Subject: [PATCH 150/332] Added failing tests for #8178. --- tests/Avalonia.LeakTests/ControlTests.cs | 66 ++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 3a5a8f1474..09d6764bae 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -6,6 +6,7 @@ using System.Runtime.Remoting.Contexts; using Avalonia.Controls; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; +using Avalonia.Data; using Avalonia.Diagnostics; using Avalonia.Input; using Avalonia.Layout; @@ -661,6 +662,70 @@ namespace Avalonia.LeakTests } } + [Fact] + public void ElementName_Binding_In_DataTemplate_Is_Freed() + { + using (Start()) + { + var items = new ObservableCollection(Enumerable.Range(0, 10)); + NameScope ns; + TextBox tb; + ListBox lb; + var window = new Window + { + [NameScope.NameScopeProperty] = ns = new NameScope(), + Width = 100, + Height = 100, + Content = new StackPanel + { + Children = + { + (tb = new TextBox + { + Name = "tb", + Text = "foo", + }), + (lb = new ListBox + { + Items = items, + ItemTemplate = new FuncDataTemplate((_, _) => + new Canvas + { + Width = 10, + Height = 10, + [!Control.TagProperty] = new Binding + { + ElementName = "tb", + Path = "Text", + NameScope = new WeakReference(ns), + } + }) + }), + } + } + }; + + tb.RegisterInNameScope(ns); + + window.Show(); + window.LayoutManager.ExecuteInitialLayoutPass(); + + Assert.Equal(10, lb.ItemContainerGenerator.Containers.Count()); + + var item0 = (ListBoxItem)lb.ItemContainerGenerator.Containers.First().ContainerControl; + var canvas0 = (Canvas)item0.Presenter.Child; + Assert.Equal("foo", canvas0.Tag); + + items.Clear(); + window.LayoutManager.ExecuteLayoutPass(); + + Assert.Empty(lb.ItemContainerGenerator.Containers); + + dotMemory.Check(memory => + Assert.Equal(0, memory.GetObjects(where => where.Type.Is()).ObjectsCount)); + } + } + private IDisposable Start() { return UnitTestApplication.Start(TestServices.StyledWindow.With( @@ -669,6 +734,7 @@ namespace Avalonia.LeakTests inputManager: new InputManager())); } + private class Node { public string Name { get; set; } From 69f5f7a48e695bf54d33ba49d5ae74b7d93be22a Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 24 May 2022 15:17:52 +0200 Subject: [PATCH 151/332] Use weak events in AvaloniaProperty plugin. Fixes #8178. --- .../Plugins/AvaloniaPropertyAccessorPlugin.cs | 40 +++++++++++++------ src/Avalonia.Base/Utilities/WeakEvents.cs | 15 ++++++- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs index 3c4120ad0b..cc6d92ceb7 100644 --- a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs +++ b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.ExceptionServices; +using Avalonia.Utilities; namespace Avalonia.Data.Core.Plugins { @@ -60,11 +61,10 @@ namespace Avalonia.Data.Core.Plugins return AvaloniaPropertyRegistry.Instance.FindRegistered(o, propertyName); } - private class Accessor : PropertyAccessorBase, IObserver + private class Accessor : PropertyAccessorBase, IWeakEventSubscriber { private readonly WeakReference _reference; private readonly AvaloniaProperty _property; - private IDisposable? _subscription; public Accessor(WeakReference reference, AvaloniaProperty property) { @@ -95,29 +95,45 @@ namespace Avalonia.Data.Core.Plugins return false; } - protected override void SubscribeCore() + void IWeakEventSubscriber. + OnEvent(object? notifyPropertyChanged, WeakEvent ev, AvaloniaPropertyChangedEventArgs e) { - _subscription = Instance?.GetObservable(_property).Subscribe(this); + if (e.Property == _property) + { + SendCurrentValue(); + } } - protected override void UnsubscribeCore() + protected override void SubscribeCore() { - _subscription?.Dispose(); - _subscription = null; + SubscribeToChanges(); + SendCurrentValue(); } - void IObserver.OnCompleted() + protected override void UnsubscribeCore() { + var instance = Instance; + + if (instance != null) + WeakEvents.AvaloniaPropertyChanged.Unsubscribe(instance, this); } - void IObserver.OnError(Exception error) + private void SendCurrentValue() { - ExceptionDispatchInfo.Capture(error).Throw(); + try + { + var value = Value; + PublishValue(value); + } + catch { } } - void IObserver.OnNext(object? value) + private void SubscribeToChanges() { - PublishValue(value); + var instance = Instance; + + if (instance != null) + WeakEvents.AvaloniaPropertyChanged.Subscribe(instance, this); } } } diff --git a/src/Avalonia.Base/Utilities/WeakEvents.cs b/src/Avalonia.Base/Utilities/WeakEvents.cs index d1b5e7f12d..6da899bab2 100644 --- a/src/Avalonia.Base/Utilities/WeakEvents.cs +++ b/src/Avalonia.Base/Utilities/WeakEvents.cs @@ -31,10 +31,23 @@ public class WeakEvents return () => s.PropertyChanged -= handler; }); + + /// + /// Represents PropertyChanged event from + /// + public static readonly WeakEvent + AvaloniaPropertyChanged = WeakEvent.Register( + (s, h) => + { + EventHandler handler = (_, e) => h(s, e); + s.PropertyChanged += handler; + return () => s.PropertyChanged -= handler; + }); + /// /// Represents CanExecuteChanged event from /// public static readonly WeakEvent CommandCanExecuteChanged = WeakEvent.Register((s, h) => s.CanExecuteChanged += h, (s, h) => s.CanExecuteChanged -= h); -} \ No newline at end of file +} From 006aef23886ad3699a8fb68b7fab89d09b1d6ece Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Tue, 24 May 2022 19:11:24 +0200 Subject: [PATCH 152/332] Rework hit testing to not rely on cluster values and instead use the currently covered TextSourceLength --- .../Media/TextFormatting/TextBounds.cs | 11 +- .../Media/TextFormatting/TextLayout.cs | 29 +- .../Media/TextFormatting/TextLineImpl.cs | 383 +++++++++++------- .../Media/TextFormatting/TextLineTests.cs | 164 +++++++- 4 files changed, 420 insertions(+), 167 deletions(-) diff --git a/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs b/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs index a0b51671f0..93edf68348 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextBounds.cs @@ -10,20 +10,27 @@ namespace Avalonia.Media.TextFormatting /// /// Constructing TextBounds object /// - internal TextBounds(Rect bounds, FlowDirection flowDirection) + internal TextBounds(Rect bounds, FlowDirection flowDirection, IList runBounds) { Rectangle = bounds; FlowDirection = flowDirection; + TextRunBounds = runBounds; } /// /// Bounds rectangle /// - public Rect Rectangle { get; } + public Rect Rectangle { get; internal set; } /// /// Text flow direction inside the boundary rectangle /// public FlowDirection FlowDirection { get; } + + /// + /// Get a list of run bounding rectangles + /// + /// Array of text run bounds + public IList TextRunBounds { get; } } } diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs index 5d5d45db2d..4f7c43a6d1 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLayout.cs @@ -230,7 +230,7 @@ namespace Avalonia.Media.TextFormatting foreach (var textLine in TextLines) { //Current line isn't covered. - if (textLine.FirstTextSourceIndex + textLine.Length <= start) + if (textLine.FirstTextSourceIndex + textLine.Length < start) { currentY += textLine.Height; @@ -239,18 +239,27 @@ namespace Avalonia.Media.TextFormatting var textBounds = textLine.GetTextBounds(start, length); - foreach (var bounds in textBounds) + if(textBounds.Count > 0) { - Rect? last = result.Count > 0 ? result[result.Count - 1] : null; - - if (last.HasValue && MathUtilities.AreClose(last.Value.Right, bounds.Rectangle.Left) && MathUtilities.AreClose(last.Value.Top, currentY)) + foreach (var bounds in textBounds) { - result[result.Count - 1] = last.Value.WithWidth(last.Value.Width + bounds.Rectangle.Width); + Rect? last = result.Count > 0 ? result[result.Count - 1] : null; + + if (last.HasValue && MathUtilities.AreClose(last.Value.Right, bounds.Rectangle.Left) && MathUtilities.AreClose(last.Value.Top, currentY)) + { + result[result.Count - 1] = last.Value.WithWidth(last.Value.Width + bounds.Rectangle.Width); + } + else + { + result.Add(bounds.Rectangle.WithY(currentY)); + } + + foreach (var runBounds in bounds.TextRunBounds) + { + start += runBounds.Length; + length -= runBounds.Length; + } } - else - { - result.Add(bounds.Rectangle.WithY(currentY)); - } } if(textLine.FirstTextSourceIndex + textLine.Length >= start + length) diff --git a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs index 26e73cdf3b..8b5e2cc2ce 100644 --- a/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs +++ b/src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs @@ -184,6 +184,10 @@ namespace Avalonia.Media.TextFormatting { characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); + var offset = Math.Max(0, currentPosition - shapedRun.Text.Start); + + characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); + break; } default: @@ -215,9 +219,11 @@ namespace Avalonia.Media.TextFormatting /// public override double GetDistanceFromCharacterHit(CharacterHit characterHit) { - var characterIndex = characterHit.FirstCharacterIndex + (characterHit.TrailingLength != 0 ? 1 : 0); + var isTrailingHit = characterHit.TrailingLength > 0; + var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength; var currentDistance = Start; var currentPosition = FirstTextSourceIndex; + var remainingLength = characterIndex - FirstTextSourceIndex; GlyphRun? lastRun = null; @@ -242,8 +248,10 @@ namespace Avalonia.Media.TextFormatting } //Look for a hit in within the current run - if (characterIndex >= textRun.Text.Start && characterIndex <= textRun.Text.Start + textRun.Text.Length) + if (currentPosition + remainingLength <= currentPosition + textRun.Text.Length) { + characterHit = new CharacterHit(textRun.Text.Start + remainingLength); + var distance = currentRun.GetDistanceFromCharacterHit(characterHit); return currentDistance + distance; @@ -254,28 +262,27 @@ namespace Avalonia.Media.TextFormatting { if (_flowDirection == FlowDirection.LeftToRight && (lastRun == null || lastRun.IsLeftToRight)) { - if (characterIndex <= textRun.Text.Start) + if (characterIndex <= currentPosition) { return currentDistance; } } else { - if (characterIndex == textRun.Text.Start) + if (characterIndex == currentPosition) { return currentDistance; } } - if (characterIndex == textRun.Text.Start + textRun.Text.Length && - characterHit.TrailingLength > 0) + if (characterIndex == currentPosition + textRun.Text.Length && isTrailingHit) { return currentDistance + currentRun.Size.Width; } } else { - if (characterIndex == textRun.Text.Start) + if (characterIndex == currentPosition) { return currentDistance + currentRun.Size.Width; } @@ -286,20 +293,24 @@ namespace Avalonia.Media.TextFormatting if (nextRun != null) { - if (characterHit.FirstCharacterIndex == textRun.Text.End && - nextRun.ShapedBuffer.IsLeftToRight) + if (nextRun.ShapedBuffer.IsLeftToRight) { - return currentDistance; + if (characterIndex == currentPosition + textRun.Text.Length) + { + return currentDistance; + } } - - if (characterIndex > textRun.Text.End && nextRun.Text.End < textRun.Text.End) + else { - return currentDistance; + if (currentPosition + nextRun.Text.Length == characterIndex) + { + return currentDistance; + } } } else { - if (characterIndex > textRun.Text.End) + if (characterIndex > currentPosition + textRun.Text.Length) { return currentDistance; } @@ -329,6 +340,12 @@ namespace Avalonia.Media.TextFormatting //No hit hit found so we add the full width currentDistance += textRun.Size.Width; currentPosition += textRun.TextSourceLength; + remainingLength -= textRun.TextSourceLength; + + if (remainingLength <= 0) + { + break; + } } return currentDistance; @@ -394,217 +411,299 @@ namespace Avalonia.Media.TextFormatting return GetPreviousCaretCharacterHit(characterHit); } - public override IReadOnlyList GetTextBounds(int firstTextSourceCharacterIndex, int textLength) + private IReadOnlyList GetTextBoundsLeftToRight(int firstTextSourceIndex, int textLength) { - if (firstTextSourceCharacterIndex + textLength <= FirstTextSourceIndex) - { - return Array.Empty(); - } + var characterIndex = firstTextSourceIndex + textLength; var result = new List(TextRuns.Count); - var lastDirection = _flowDirection; + var lastDirection = FlowDirection.LeftToRight; var currentDirection = lastDirection; + var currentPosition = FirstTextSourceIndex; - var currentRect = Rect.Empty; + var remainingLength = textLength; + var startX = Start; - var runStart = startX; + double currentWidth = 0; + var currentRect = Rect.Empty; - //A portion of the line is covered. for (var index = 0; index < TextRuns.Count; index++) { - var currentRun = TextRuns[index] as DrawableTextRun; - - if (currentRun is null) + if (TextRuns[index] is not DrawableTextRun currentRun) { continue; } - TextRun? nextRun = null; - - if (index + 1 < TextRuns.Count) + if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) { - nextRun = TextRuns[index + 1]; + startX += currentRun.Size.Width; + + currentPosition += currentRun.TextSourceLength; + + continue; } - if (nextRun != null) + var characterLength = 0; + var endX = startX; + + if (currentRun is ShapedTextCharacters currentShapedRun) { - switch (nextRun) - { - case ShapedTextCharacters when currentRun is ShapedTextCharacters: - { - if (nextRun.Text.Start < currentRun.Text.Start && firstTextSourceCharacterIndex + textLength < currentRun.Text.End && _flowDirection == FlowDirection.LeftToRight) - { - goto skip; - } + var offset = Math.Max(0, firstTextSourceIndex - currentPosition); - if (currentRun.Text.Start >= firstTextSourceCharacterIndex + textLength) - { - goto skip; - } + currentPosition += offset; - if (currentRun.Text.Start > nextRun.Text.Start && currentRun.Text.Start < firstTextSourceCharacterIndex) - { - goto skip; - } + var startIndex = currentRun.Text.Start + offset; - if (currentRun.Text.End < firstTextSourceCharacterIndex) - { - goto skip; - } + var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( + currentShapedRun.ShapedBuffer.IsLeftToRight ? + new CharacterHit(startIndex + remainingLength) : + new CharacterHit(startIndex)); - goto noop; - } - default: - { - goto noop; - } - } + endX += endOffset; - skip: + var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( + currentShapedRun.ShapedBuffer.IsLeftToRight ? + new CharacterHit(startIndex) : + new CharacterHit(startIndex + remainingLength)); + + startX += startOffset; + + var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); + var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); + + characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength); + + currentDirection = currentShapedRun.ShapedBuffer.IsLeftToRight ? + FlowDirection.LeftToRight : + FlowDirection.RightToLeft; + } + else + { + if (currentPosition < firstTextSourceIndex) { startX += currentRun.Size.Width; - currentPosition += currentRun.TextSourceLength; } - continue; - - noop: + if (currentPosition + currentRun.TextSourceLength <= characterIndex) { + endX += currentRun.Size.Width; + + characterLength = currentRun.TextSourceLength; } } - var endX = startX; - var endOffset = 0d; + if (endX < startX) + { + (endX, startX) = (startX, endX); + } - switch (currentRun) + //Lines that only contain a linebreak need to be covered here + if(characterLength == 0) { - case ShapedTextCharacters shapedRun: - { - endOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit( - shapedRun.ShapedBuffer.IsLeftToRight ? - new CharacterHit(firstTextSourceCharacterIndex + textLength) : - new CharacterHit(firstTextSourceCharacterIndex)); + characterLength = NewLineLength; + } - endX += endOffset; + var runwidth = endX - startX; + var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runwidth, Height), currentPosition, characterLength, currentRun); - var startOffset = shapedRun.GlyphRun.GetDistanceFromCharacterHit( - shapedRun.ShapedBuffer.IsLeftToRight ? - new CharacterHit(firstTextSourceCharacterIndex) : - new CharacterHit(firstTextSourceCharacterIndex + textLength)); + if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) + { + currentRect = currentRect.WithWidth(currentWidth + runwidth); - startX += startOffset; + var textBounds = result[result.Count - 1]; - var characterHit = _flowDirection == FlowDirection.LeftToRight ? - shapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _) : - shapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); + textBounds.Rectangle = currentRect; - currentPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength; + textBounds.TextRunBounds.Add(currentRunBounds); + } + else + { + currentRect = currentRunBounds.Rectangle; - currentDirection = shapedRun.ShapedBuffer.IsLeftToRight ? - FlowDirection.LeftToRight : - FlowDirection.RightToLeft; + result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds })); + } - if (nextRun is ShapedTextCharacters nextShaped) - { - if (shapedRun.ShapedBuffer.IsLeftToRight == nextShaped.ShapedBuffer.IsLeftToRight) - { - endOffset = nextShaped.GlyphRun.GetDistanceFromCharacterHit( - nextShaped.ShapedBuffer.IsLeftToRight ? - new CharacterHit(firstTextSourceCharacterIndex + textLength) : - new CharacterHit(firstTextSourceCharacterIndex)); + currentWidth += runwidth; + currentPosition += characterLength; - index++; + if (currentDirection == FlowDirection.LeftToRight) + { + if (currentPosition > characterIndex) + { + break; + } + } + else + { + if (currentPosition <= firstTextSourceIndex) + { + break; + } + } - endX += endOffset; + startX = endX; + lastDirection = currentDirection; + remainingLength -= characterLength; - currentRun = nextShaped; + if (remainingLength <= 0) + { + break; + } + } - if (nextShaped.ShapedBuffer.IsLeftToRight) - { - characterHit = nextShaped.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); + return result; + } - currentPosition = characterHit.FirstCharacterIndex + characterHit.TrailingLength; - } - } - } + private IReadOnlyList GetTextBoundsRightToLeft(int firstTextSourceIndex, int textLength) + { + var characterIndex = firstTextSourceIndex + textLength; - break; - } - default: - { - if (currentPosition + currentRun.TextSourceLength <= firstTextSourceCharacterIndex + textLength) - { - endX += currentRun.Size.Width; - } + var result = new List(TextRuns.Count); + var lastDirection = FlowDirection.LeftToRight; + var currentDirection = lastDirection; - if (currentPosition < firstTextSourceCharacterIndex) - { - startX += currentRun.Size.Width; - } + var currentPosition = FirstTextSourceIndex; + var remainingLength = textLength; - currentPosition += currentRun.TextSourceLength; + var startX = Start + WidthIncludingTrailingWhitespace; + double currentWidth = 0; + var currentRect = Rect.Empty; - break; - } + for (var index = TextRuns.Count - 1; index >= 0; index--) + { + if (TextRuns[index] is not DrawableTextRun currentRun) + { + continue; } - if (endX < startX) + if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) { - (endX, startX) = (startX, endX); + startX -= currentRun.Size.Width; + + currentPosition += currentRun.TextSourceLength; + + continue; } - var width = endX - startX; + var characterLength = 0; + var endX = startX; - if (!MathUtilities.IsZero(width)) + if (currentRun is ShapedTextCharacters currentShapedRun) { - if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) - { - currentRect = currentRect.WithWidth(currentRect.Width + width); + var offset = Math.Max(0, firstTextSourceIndex - currentPosition); + + currentPosition += offset; + + var startIndex = currentRun.Text.Start + offset; + + var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( + currentShapedRun.ShapedBuffer.IsLeftToRight ? + new CharacterHit(startIndex + remainingLength) : + new CharacterHit(startIndex)); + + endX += endOffset - currentShapedRun.Size.Width; + + var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( + currentShapedRun.ShapedBuffer.IsLeftToRight ? + new CharacterHit(startIndex) : + new CharacterHit(startIndex + remainingLength)); + + startX += startOffset - currentShapedRun.Size.Width; + + var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); + var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); - var textBounds = new TextBounds(currentRect, currentDirection); + characterLength = Math.Abs(startHit.FirstCharacterIndex + startHit.TrailingLength - endHit.FirstCharacterIndex - endHit.TrailingLength); - result[result.Count - 1] = textBounds; + currentDirection = currentShapedRun.ShapedBuffer.IsLeftToRight ? + FlowDirection.LeftToRight : + FlowDirection.RightToLeft; + } + else + { + if (currentPosition + currentRun.TextSourceLength <= characterIndex) + { + endX -= currentRun.Size.Width; } - else + + if (currentPosition < firstTextSourceIndex) { + startX -= currentRun.Size.Width; - currentRect = new Rect(startX, 0, width, Height); + characterLength = currentRun.TextSourceLength; + } + } - result.Add(new TextBounds(currentRect, currentDirection)); + if (endX < startX) + { + (endX, startX) = (startX, endX); + } - } + //Lines that only contain a linebreak need to be covered here + if (characterLength == 0) + { + characterLength = NewLineLength; } + var runWidth = endX - startX; + var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); + + if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) + { + currentRect = currentRect.WithWidth(currentWidth + runWidth); + + var textBounds = result[result.Count - 1]; + + textBounds.Rectangle = currentRect; + + textBounds.TextRunBounds.Add(currentRunBounds); + } + else + { + currentRect = currentRunBounds.Rectangle; + + result.Add(new TextBounds(currentRect, currentDirection, new List { currentRunBounds })); + } + + currentWidth += runWidth; + currentPosition += characterLength; + if (currentDirection == FlowDirection.LeftToRight) { - if (currentPosition > firstTextSourceCharacterIndex + textLength) + if (currentPosition > characterIndex) { break; } - - if (_flowDirection == FlowDirection.RightToLeft) - { - endX += currentRun.Size.Width - endOffset; - } } else { - if (currentPosition <= firstTextSourceCharacterIndex) + if (currentPosition <= firstTextSourceIndex) { break; } - - endX += currentRun.Size.Width - endOffset; } - startX = endX; lastDirection = currentDirection; - runStart += currentRun.Size.Width; + remainingLength -= characterLength; + + if (remainingLength <= 0) + { + break; + } } return result; } + public override IReadOnlyList GetTextBounds(int firstTextSourceIndex, int textLength) + { + if (_paragraphProperties.FlowDirection == FlowDirection.LeftToRight) + { + return GetTextBoundsLeftToRight(firstTextSourceIndex, textLength); + } + + return GetTextBoundsRightToLeft(firstTextSourceIndex, textLength); + } + public TextLineImpl FinalizeLine() { _textLineMetrics = CreateLineMetrics(); diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index f29dddf86b..a974e06385 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs @@ -543,6 +543,98 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting } } + [Fact] + public void Should_Get_Distance_From_CharacterHit_Mixed_TextBuffer() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + var textSource = new MixedTextBufferTextSource(); + + var formatter = new TextFormatterImpl(); + + var textLine = + formatter.FormatLine(textSource, 0, double.PositiveInfinity, + new GenericTextParagraphProperties(defaultProperties)); + + var distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(10)); + + Assert.Equal(72.01171875, distance); + + distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(20)); + + Assert.Equal(144.0234375, distance); + + distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(30)); + + Assert.Equal(216.03515625, distance); + + distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(40)); + + Assert.Equal(textLine.WidthIncludingTrailingWhitespace, distance); + } + } + + [Fact] + public void Should_Get_TextBounds_From_Mixed_TextBuffer() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + var textSource = new MixedTextBufferTextSource(); + + var formatter = new TextFormatterImpl(); + + var textLine = + formatter.FormatLine(textSource, 0, double.PositiveInfinity, + new GenericTextParagraphProperties(defaultProperties)); + + var textBounds = textLine.GetTextBounds(0, 10); + + Assert.Equal(1, textBounds.Count); + + Assert.Equal(72.01171875, textBounds[0].Rectangle.Width); + + textBounds = textLine.GetTextBounds(0, 20); + + Assert.Equal(1, textBounds.Count); + + Assert.Equal(144.0234375, textBounds[0].Rectangle.Width); + + textBounds = textLine.GetTextBounds(0, 30); + + Assert.Equal(1, textBounds.Count); + + Assert.Equal(216.03515625, textBounds[0].Rectangle.Width); + + textBounds = textLine.GetTextBounds(0, 40); + + Assert.Equal(1, textBounds.Count); + + Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds[0].Rectangle.Width); + } + } + + private class MixedTextBufferTextSource : ITextSource + { + public TextRun? GetTextRun(int textSourceIndex) + { + switch (textSourceIndex) + { + case 0: + return new TextCharacters(new ReadOnlySlice("aaaaaaaaaa".AsMemory()), new GenericTextRunProperties(Typeface.Default)); + case 10: + return new TextCharacters(new ReadOnlySlice("bbbbbbbbbb".AsMemory()), new GenericTextRunProperties(Typeface.Default)); + case 20: + return new TextCharacters(new ReadOnlySlice("cccccccccc".AsMemory()), new GenericTextRunProperties(Typeface.Default)); + case 30: + return new TextCharacters(new ReadOnlySlice("dddddddddd".AsMemory()), new GenericTextRunProperties(Typeface.Default)); + default: + return null; + } + } + } + private class DrawableRunTextSource : ITextSource { const string Text = "_A_A"; @@ -713,7 +805,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting } [Fact] - public void Should_Get_TextBounds_BiDi() + public void Should_Get_TextBounds_BiDi_LeftToRight() { using (Start()) { @@ -725,38 +817,84 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting var textLine = formatter.FormatLine(textSource, 0, 200, - new GenericTextParagraphProperties(FlowDirection.RightToLeft, TextAlignment.Left, true, true, defaultProperties, TextWrapping.NoWrap, 0, 0)); + new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left, true, true, defaultProperties, TextWrapping.NoWrap, 0, 0)); - var textBounds = textLine.GetTextBounds(0, text.Length); + var textBounds = textLine.GetTextBounds(0, 3); - Assert.Equal(2, textBounds.Count); - Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds.Sum(x => x.Rectangle.Width)); + var firstRun = textLine.TextRuns[0] as ShapedTextCharacters; - textBounds = textLine.GetTextBounds(0, 4); + Assert.Equal(1, textBounds.Count); + Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); + + textBounds = textLine.GetTextBounds(3, 4); var secondRun = textLine.TextRuns[1] as ShapedTextCharacters; Assert.Equal(1, textBounds.Count); Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); - textBounds = textLine.GetTextBounds(4, 3); + textBounds = textLine.GetTextBounds(0, 4); - var firstRun = textLine.TextRuns[0] as ShapedTextCharacters; + Assert.Equal(2, textBounds.Count); + + Assert.Equal(firstRun.Size.Width, textBounds[0].Rectangle.Width); + + Assert.Equal(7.201171875, textBounds[1].Rectangle.Width); + + Assert.Equal(firstRun.Size.Width, textBounds[1].Rectangle.Left); + + textBounds = textLine.GetTextBounds(0, text.Length); + + Assert.Equal(2, textBounds.Count); + Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds.Sum(x => x.Rectangle.Width)); + } + } + + [Fact] + public void Should_Get_TextBounds_BiDi_RightToLeft() + { + using (Start()) + { + var defaultProperties = new GenericTextRunProperties(Typeface.Default); + var text = "אאא AAA"; + var textSource = new SingleBufferTextSource(text, defaultProperties); + + var formatter = new TextFormatterImpl(); + + var textLine = + formatter.FormatLine(textSource, 0, 200, + new GenericTextParagraphProperties(FlowDirection.RightToLeft, TextAlignment.Left, true, true, defaultProperties, TextWrapping.NoWrap, 0, 0)); + + var textBounds = textLine.GetTextBounds(0, 4); + + var firstRun = textLine.TextRuns[1] as ShapedTextCharacters; Assert.Equal(1, textBounds.Count); Assert.Equal(firstRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); + textBounds = textLine.GetTextBounds(4, 3); + + var secondRun = textLine.TextRuns[0] as ShapedTextCharacters; + + Assert.Equal(1, textBounds.Count); + + Assert.Equal(3, textBounds[0].TextRunBounds.Sum(x=> x.Length)); + Assert.Equal(secondRun.Size.Width, textBounds.Sum(x => x.Rectangle.Width)); + textBounds = textLine.GetTextBounds(0, 5); Assert.Equal(2, textBounds.Count); + Assert.Equal(5, textBounds.Sum(x=> x.TextRunBounds.Sum(x => x.Length))); - Assert.Equal(7.201171875, textBounds[0].Rectangle.Width); - - Assert.Equal(textLine.Start, textBounds[0].Rectangle.Left); + Assert.Equal(firstRun.Size.Width, textBounds[0].Rectangle.Width); + Assert.Equal(7.201171875, textBounds[1].Rectangle.Width); + Assert.Equal(textLine.Start + 7.201171875, textBounds[1].Rectangle.Right); - Assert.Equal(secondRun.Size.Width, textBounds[1].Rectangle.Width); + textBounds = textLine.GetTextBounds(0, text.Length); - Assert.Equal(textLine.Start + firstRun.Size.Width, textBounds[1].Rectangle.Left); + Assert.Equal(2, textBounds.Count); + Assert.Equal(7, textBounds.Sum(x => x.TextRunBounds.Sum(x => x.Length))); + Assert.Equal(textLine.WidthIncludingTrailingWhitespace, textBounds.Sum(x => x.Rectangle.Width)); } } From e4bbebac7d0e1f97f9864439f67e50e797110a85 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 24 May 2022 20:48:19 +0100 Subject: [PATCH 153/332] restore _canBecomeKeyWindow flag, important to distinguish behavior of a window and a popup. --- native/Avalonia.Native/src/OSX/AvnWindow.mm | 34 +++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 54bfe6e38a..7c1f548786 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -31,6 +31,7 @@ ComPtr _parent; bool _closed; bool _isEnabled; + bool _canBecomeKeyWindow; bool _isExtended; AvnMenu* _menu; } @@ -216,29 +217,38 @@ -(BOOL)canBecomeKeyWindow { - // If the window has a child window being shown as a dialog then don't allow it to become the key window. - for(NSWindow* uch in [self childWindows]) + if(_canBecomeKeyWindow) { - if (![uch conformsToProtocol:@protocol(AvnWindowProtocol)]) + // If the window has a child window being shown as a dialog then don't allow it to become the key window. + for(NSWindow* uch in [self childWindows]) { - continue; - } + if (![uch conformsToProtocol:@protocol(AvnWindowProtocol)]) + { + continue; + } - id ch = (id ) uch; + id ch = (id ) uch; - return !ch.isDialog; - } + if(ch.isDialog) + return true; + } - return true; + return true; + } + + return false; } +#ifndef IS_NSPANEL -(BOOL)canBecomeMainWindow { -#ifdef IS_NSPANEL - return false; -#else return true; +} #endif + +-(void)setCanBecomeKeyWindow:(bool)value +{ + _canBecomeKeyWindow = value; } -(bool)shouldTryToHandleEvents From aa06e02c6d8bdd775350926da702d9fb29206c22 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 24 May 2022 20:48:41 +0100 Subject: [PATCH 154/332] arrange fields nicely. --- .../Avalonia.Native/src/OSX/WindowBaseImpl.h | 39 ++++++++++--------- .../Avalonia.Native/src/OSX/WindowBaseImpl.mm | 3 -- native/Avalonia.Native/src/OSX/WindowImpl.h | 3 ++ native/Avalonia.Native/src/OSX/WindowImpl.mm | 1 + 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index e3e646ff2a..a879fecc21 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -16,8 +16,6 @@ class WindowBaseImpl : public virtual ComObject, public virtual IAvnWindowBase, public INSWindowHolder { -private: - NSCursor *cursor; public: FORWARD_IUNKNOWN() @@ -28,23 +26,6 @@ BEGIN_INTERFACE_MAP() virtual ~WindowBaseImpl(); - AutoFitContentView *StandardContainer; - AvnView *View; - NSWindow * Window; - ComPtr BaseEvents; - ComPtr _glContext; - NSObject *renderTarget; - AvnPoint lastPositionSet; - bool hasPosition; - NSSize lastSize; - NSSize lastMinSize; - NSSize lastMaxSize; - AvnMenu* lastMenu; - NSString *_lastTitle; - - bool _shown; - bool _inResize; - WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl); virtual HRESULT ObtainNSWindowHandle(void **ret) override; @@ -128,6 +109,26 @@ private: void CreateNSWindow (bool isDialog); void CleanNSWindow (); void InitialiseNSWindow (); + + NSCursor *cursor; + ComPtr _glContext; + bool hasPosition; + NSSize lastSize; + NSSize lastMinSize; + NSSize lastMaxSize; + AvnMenu* lastMenu; + bool _inResize; + +protected: + AvnPoint lastPositionSet; + AutoFitContentView *StandardContainer; + bool _shown; + +public: + NSObject *renderTarget; + NSWindow * Window; + ComPtr BaseEvents; + AvnView *View; }; #endif //AVALONIA_NATIVE_OSX_WINDOWBASEIMPL_H diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index bc512f80d8..c97989556f 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -35,7 +35,6 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) lastSize = NSSize { 100, 100 }; lastMaxSize = NSSize { CGFLOAT_MAX, CGFLOAT_MAX}; lastMinSize = NSSize { 0, 0 }; - _lastTitle = @""; Window = nullptr; lastMenu = nullptr; @@ -102,8 +101,6 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { UpdateStyle(); - [Window setTitle:_lastTitle]; - if (ShouldTakeFocusOnShow() && activate) { [Window orderFront:Window]; [Window makeKeyAndOrderFront:Window]; diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index a4ee4f447c..dc82ee59c2 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -91,6 +91,9 @@ BEGIN_INTERFACE_MAP() protected: virtual NSWindowStyleMask GetStyle() override; + +private: + NSString *_lastTitle; }; #endif //AVALONIA_NATIVE_OSX_WINDOWIMPL_H diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 5b15b4cdfc..5bb739d369 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -19,6 +19,7 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase _inSetWindowState = false; _lastWindowState = Normal; _actualWindowState = Normal; + _lastTitle = @""; WindowEvents = events; [Window disableCursorRects]; [Window setTabbingMode:NSWindowTabbingModeDisallowed]; From a77f9d3e54d580a41290654b4872064b053bf1f6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 24 May 2022 20:49:42 +0100 Subject: [PATCH 155/332] add setCanBecomeKeyWindow to protocol --- native/Avalonia.Native/src/OSX/WindowProtocol.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/WindowProtocol.h b/native/Avalonia.Native/src/OSX/WindowProtocol.h index 92194706de..0e5c5869e7 100644 --- a/native/Avalonia.Native/src/OSX/WindowProtocol.h +++ b/native/Avalonia.Native/src/OSX/WindowProtocol.h @@ -22,4 +22,6 @@ -(void) setIsExtended:(bool)value; -(void) disconnectParent; -(bool) isDialog; -@end \ No newline at end of file + +-(void) setCanBecomeKeyWindow:(bool)value; +@end From 02b3bf253af52c3c08ade06fba827dce7d3cf93b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 24 May 2022 20:50:39 +0100 Subject: [PATCH 156/332] add OnInitialiseNSWindow to allow inheritors to hook into NSWindow/Panel setup before being shown. --- native/Avalonia.Native/src/OSX/PopupImpl.mm | 8 +++-- .../Avalonia.Native/src/OSX/WindowBaseImpl.h | 2 ++ .../Avalonia.Native/src/OSX/WindowBaseImpl.mm | 7 +++++ native/Avalonia.Native/src/OSX/WindowImpl.h | 2 ++ native/Avalonia.Native/src/OSX/WindowImpl.mm | 29 ++++++++++--------- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/PopupImpl.mm b/native/Avalonia.Native/src/OSX/PopupImpl.mm index cb52047148..3c5afd9424 100644 --- a/native/Avalonia.Native/src/OSX/PopupImpl.mm +++ b/native/Avalonia.Native/src/OSX/PopupImpl.mm @@ -26,13 +26,17 @@ private: PopupImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl) { WindowEvents = events; - [Window setLevel:NSPopUpMenuWindowLevel]; } protected: virtual NSWindowStyleMask GetStyle() override { return NSWindowStyleMaskBorderless; } + + virtual void OnInitialiseNSWindow () override + { + [Window setLevel:NSPopUpMenuWindowLevel]; + } public: virtual bool ShouldTakeFocusOnShow() override @@ -54,4 +58,4 @@ extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events, IAvnGlContext* gl) IAvnPopup* ptr = dynamic_cast(new PopupImpl(events, gl)); return ptr; } -} \ No newline at end of file +} diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index a879fecc21..83850e780c 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -104,6 +104,8 @@ protected: virtual NSWindowStyleMask GetStyle(); void UpdateStyle(); + + virtual void OnInitialiseNSWindow (); private: void CreateNSWindow (bool isDialog); diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index c97989556f..022769bad0 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -567,6 +567,11 @@ void WindowBaseImpl::CreateNSWindow(bool isDialog) { } } +void WindowBaseImpl::OnInitialiseNSWindow() +{ + +} + void WindowBaseImpl::InitialiseNSWindow() { if(Window != nullptr) { [Window setContentView:StandardContainer]; @@ -586,6 +591,8 @@ void WindowBaseImpl::InitialiseNSWindow() { [GetWindowProtocol() showWindowMenuWithAppMenu]; } } + + OnInitialiseNSWindow(); } } diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index dc82ee59c2..db19497b29 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -88,6 +88,8 @@ BEGIN_INTERFACE_MAP() virtual HRESULT SetWindowState (AvnWindowState state) override; virtual bool IsDialog() override; + + virtual void OnInitialiseNSWindow() override; protected: virtual NSWindowStyleMask GetStyle() override; diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 5bb739d369..d43a8beee4 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -21,9 +21,6 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase _actualWindowState = Normal; _lastTitle = @""; WindowEvents = events; - [Window disableCursorRects]; - [Window setTabbingMode:NSWindowTabbingModeDisallowed]; - [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; } void WindowImpl::HideOrShowTrafficLights() { @@ -51,25 +48,29 @@ void WindowImpl::HideOrShowTrafficLights() { } } +void WindowImpl::OnInitialiseNSWindow(){ + [GetWindowProtocol() setCanBecomeKeyWindow:true]; + [Window disableCursorRects]; + [Window setTabbingMode:NSWindowTabbingModeDisallowed]; + [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + + [Window setTitle:_lastTitle]; + + if(_isClientAreaExtended) + { + [GetWindowProtocol() setIsExtended:true]; + SetExtendClientArea(true); + } +} + HRESULT WindowImpl::Show(bool activate, bool isDialog) { START_COM_CALL; @autoreleasepool { _isDialog = isDialog; - bool created = Window == nullptr; - WindowBaseImpl::Show(activate, isDialog); - if(created) - { - if(_isClientAreaExtended) - { - [GetWindowProtocol() setIsExtended:true]; - SetExtendClientArea(true); - } - } - HideOrShowTrafficLights(); return SetWindowState(_lastWindowState); From 30377966e6b0623df63b7f620cd5dcc39de7ac90 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 24 May 2022 21:02:52 +0100 Subject: [PATCH 157/332] fix incorrect return value. --- native/Avalonia.Native/src/OSX/AvnWindow.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 7c1f548786..f51c693777 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -230,7 +230,7 @@ id ch = (id ) uch; if(ch.isDialog) - return true; + return false; } return true; From 8e4d904a5af3d71bfdaee77daf2f319961f4b619 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 24 May 2022 22:49:09 -0400 Subject: [PATCH 158/332] Simplify some runtime platform interfaces and prefer net6 alternatives --- .../Platform/Interop/IDynamicLibraryLoader.cs | 5 + src/Avalonia.PlatformSupport/DynLoader.cs | 56 ++++--- .../Internal/AssemblyDescriptorResolver.cs | 4 +- .../StandardRuntimePlatform.cs | 146 +++--------------- .../StandardRuntimePlatformServices.cs | 11 +- 5 files changed, 65 insertions(+), 157 deletions(-) diff --git a/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs b/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs index 9389ebc703..d9db4b71d5 100644 --- a/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs +++ b/src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs @@ -16,5 +16,10 @@ namespace Avalonia.Platform.Interop { } + + public DynamicLibraryLoaderException(string message, Exception innerException) : base(message, innerException) + { + + } } } diff --git a/src/Avalonia.PlatformSupport/DynLoader.cs b/src/Avalonia.PlatformSupport/DynLoader.cs index ad76ac4724..ef2166d943 100644 --- a/src/Avalonia.PlatformSupport/DynLoader.cs +++ b/src/Avalonia.PlatformSupport/DynLoader.cs @@ -26,25 +26,6 @@ namespace Avalonia.PlatformSupport } } - static class AndroidImports - { - [DllImport("libdl.so")] - private static extern IntPtr dlopen(string path, int flags); - - [DllImport("libdl.so")] - private static extern IntPtr dlsym(IntPtr handle, string symbol); - - [DllImport("libdl.so")] - private static extern IntPtr dlerror(); - - public static void Init() - { - DlOpen = dlopen; - DlSym = dlsym; - DlError = dlerror; - } - } - static class OsXImports { [DllImport("/usr/lib/libSystem.dylib")] @@ -77,10 +58,6 @@ namespace Avalonia.PlatformSupport Marshal.FreeHGlobal(buffer); if (unixName == "Darwin") OsXImports.Init(); -#if NET6_0_OR_GREATER - else if (OperatingSystem.IsAndroid()) - AndroidImports.Init(); -#endif else LinuxImports.Init(); } @@ -135,6 +112,39 @@ namespace Avalonia.PlatformSupport return ptr; } } + +#if NET6_0_OR_GREATER + internal class Net6Loader : IDynamicLibraryLoader + { + public IntPtr LoadLibrary(string dll) + { + try + { + return NativeLibrary.Load(dll); + } + catch (Exception ex) + { + throw new DynamicLibraryLoaderException("Error loading " + dll, ex); + } + } + + public IntPtr GetProcAddress(IntPtr dll, string proc, bool optional) + { + try + { + if (optional) + { + return NativeLibrary.TryGetExport(dll, proc, out var address) ? address : default; + } + return NativeLibrary.GetExport(dll, proc); + } + catch (Exception ex) + { + throw new DynamicLibraryLoaderException("Error " + dll, ex); + } + } + } +#endif internal class NotSupportedLoader : IDynamicLibraryLoader { diff --git a/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs b/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs index 28ae35d57d..6b85200c76 100644 --- a/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs +++ b/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; namespace Avalonia.PlatformSupport.Internal; @@ -29,9 +30,8 @@ internal class AssemblyDescriptorResolver: IAssemblyDescriptorResolver } else { - // iOS does not support loading assemblies dynamically! #if NET6_0_OR_GREATER - if (OperatingSystem.IsIOS()) + if (!RuntimeFeature.IsDynamicCodeSupported) { throw new InvalidOperationException( $"Assembly {name} needs to be referenced and explicitly loaded before loading resources"); diff --git a/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs b/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs index 4eeb9232cf..048f09570f 100644 --- a/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs +++ b/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using Avalonia.Platform; @@ -14,45 +12,20 @@ namespace Avalonia.PlatformSupport return new Timer(_ => tick(), null, interval, interval); } - public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(this, size); + public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(size); private class UnmanagedBlob : IUnmanagedBlob { - private readonly StandardRuntimePlatform _plat; private IntPtr _address; private readonly object _lock = new object(); -#if DEBUG - private static readonly List Backtraces = new List(); - private static Thread? GCThread; - private readonly string _backtrace; - private static readonly object _btlock = new object(); - class GCThreadDetector - { - ~GCThreadDetector() - { - GCThread = Thread.CurrentThread; - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - static void Spawn() => new GCThreadDetector(); - - static UnmanagedBlob() - { - Spawn(); - GC.WaitForPendingFinalizers(); - } -#endif - - public UnmanagedBlob(StandardRuntimePlatform plat, int size) + public UnmanagedBlob(int size) { try { if (size <= 0) throw new ArgumentException("Positive number required", nameof(size)); - _plat = plat; - _address = plat.Alloc(size); + _address = Marshal.AllocHGlobal(size); GC.AddMemoryPressure(size); Size = size; } @@ -61,24 +34,15 @@ namespace Avalonia.PlatformSupport GC.SuppressFinalize(this); throw; } -#if DEBUG - _backtrace = Environment.StackTrace; - lock (_btlock) - Backtraces.Add(_backtrace); -#endif } - void DoDispose() + private void DoDispose() { lock (_lock) { if (!IsDisposed) { -#if DEBUG - lock (_btlock) - Backtraces.Remove(_backtrace); -#endif - _plat?.Free(_address, Size); + Marshal.FreeHGlobal(_address); GC.RemoveMemoryPressure(Size); IsDisposed = true; _address = IntPtr.Zero; @@ -89,29 +53,12 @@ namespace Avalonia.PlatformSupport public void Dispose() { -#if DEBUG - if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId) - { - lock (_lock) - { - if (!IsDisposed) - { - Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: " - + Environment.StackTrace - + "\n\nBlob created by " + _backtrace); - } - } - } -#endif DoDispose(); GC.SuppressFinalize(this); } ~UnmanagedBlob() { -#if DEBUG - Console.Error.WriteLine("Undisposed native blob created by " + _backtrace); -#endif DoDispose(); } @@ -119,82 +66,25 @@ namespace Avalonia.PlatformSupport public int Size { get; private set; } public bool IsDisposed { get; private set; } } - -#if NET461 || NETCOREAPP2_0_OR_GREATER - [DllImport("libc", SetLastError = true)] - private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset); - [DllImport("libc", SetLastError = true)] - private static extern int munmap(IntPtr addr, IntPtr length); - [DllImport("libc", SetLastError = true)] - private static extern long sysconf(int name); - - private bool? _useMmap; - private bool UseMmap - => _useMmap ?? ((_useMmap = GetRuntimeInfo().OperatingSystem == OperatingSystemType.Linux)).Value; - - IntPtr Alloc(int size) - { - if (UseMmap) - { - var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero); - if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff) - { - var errno = Marshal.GetLastWin32Error(); - throw new Exception("Unable to allocate memory: " + errno); - } - return rv; - } - else - return Marshal.AllocHGlobal(size); - } - - void Free(IntPtr ptr, int len) - { - if (UseMmap) - { - if (munmap(ptr, new IntPtr(len)) == -1) - { - var errno = Marshal.GetLastWin32Error(); - throw new Exception("Unable to free memory: " + errno); - } - } - else - Marshal.FreeHGlobal(ptr); - } -#else - IntPtr Alloc(int size) => Marshal.AllocHGlobal(size); - void Free(IntPtr ptr, int len) => Marshal.FreeHGlobal(ptr); -#endif - - private static readonly Lazy Info = new Lazy(() => + + private static readonly Lazy Info = new(() => { OperatingSystemType os; -#if NET5_0_OR_GREATER - if (OperatingSystem.IsWindows()) - os = OperatingSystemType.WinNT; - else if (OperatingSystem.IsMacOS()) - os = OperatingSystemType.OSX; - else if (OperatingSystem.IsLinux() || OperatingSystem.IsFreeBSD()) - os = OperatingSystemType.Linux; - else if (OperatingSystem.IsAndroid()) - os = OperatingSystemType.Android; - else if (OperatingSystem.IsIOS()) - os = OperatingSystemType.iOS; - else if (OperatingSystem.IsBrowser()) - os = OperatingSystemType.Browser; - else - throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription); -#else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) os = OperatingSystemType.OSX; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"))) os = OperatingSystemType.Linux; else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) os = OperatingSystemType.WinNT; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("Android"))) + os = OperatingSystemType.Android; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("iOS"))) + os = OperatingSystemType.iOS; + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("Browser"))) + os = OperatingSystemType.Browser; else throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription); -#endif return new RuntimePlatformInfo { @@ -203,10 +93,10 @@ namespace Avalonia.PlatformSupport #elif NETFRAMEWORK IsDotNetFramework = true, #endif - IsDesktop = os == OperatingSystemType.Linux || os == OperatingSystemType.OSX || os == OperatingSystemType.WinNT, - IsMono = os == OperatingSystemType.Android || os == OperatingSystemType.iOS || os == OperatingSystemType.Browser, - IsMobile = os == OperatingSystemType.Android || os == OperatingSystemType.iOS, - IsUnix = os == OperatingSystemType.Linux || os == OperatingSystemType.OSX || os == OperatingSystemType.Android, + IsDesktop = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.WinNT, + IsMono = os is OperatingSystemType.Android or OperatingSystemType.iOS or OperatingSystemType.Browser, + IsMobile = os is OperatingSystemType.Android or OperatingSystemType.iOS, + IsUnix = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.Android, IsBrowser = os == OperatingSystemType.Browser, OperatingSystem = os, }; diff --git a/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs b/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs index ae7478feb9..11ca906782 100644 --- a/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs +++ b/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs @@ -9,22 +9,25 @@ namespace Avalonia.PlatformSupport public static void Register(Assembly? assembly = null) { var standardPlatform = new StandardRuntimePlatform(); - var os = standardPlatform.GetRuntimeInfo().OperatingSystem; AssetLoader.RegisterResUriParsers(); AvaloniaLocator.CurrentMutable .Bind().ToConstant(standardPlatform) .Bind().ToConstant(new AssetLoader(assembly)) .Bind().ToConstant( - os switch +#if NET6_0_OR_GREATER + new Net6Loader() +#else + standardPlatform.GetRuntimeInfo().OperatingSystem switch { - OperatingSystemType.WinNT => new Win32Loader(), + OperatingSystemType.WinNT => (IDynamicLibraryLoader)new Win32Loader(), OperatingSystemType.OSX => new UnixLoader(), OperatingSystemType.Linux => new UnixLoader(), OperatingSystemType.Android => new UnixLoader(), // iOS, WASM, ... - _ => (IDynamicLibraryLoader)new NotSupportedLoader() + _ => new NotSupportedLoader() } +#endif ); } } From ad0a06bf24732d0d7505951184bfc89e936d53b7 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 24 May 2022 23:35:32 -0400 Subject: [PATCH 159/332] Merge PlatformSupport project into Avalonia.Base --- Avalonia.sln | 53 ------------------- build/CoreLibraries.props | 1 - src/Avalonia.Base/Media/PathGeometry.cs | 1 - .../Media/PathGeometryCollections.cs | 2 +- .../Platform}/AssetLoader.cs | 5 +- .../Platform}/Internal/AssemblyDescriptor.cs | 2 +- .../Internal/AssemblyDescriptorResolver.cs | 2 +- .../Platform}/Internal/AssetDescriptor.cs | 2 +- .../Platform}/Internal/Constants.cs | 2 +- .../Platform/Internal}/DynLoader.cs | 2 +- .../Platform}/Internal/SlicedStream.cs | 2 +- .../Platform/PathGeometryContext.cs | 3 +- .../Platform}/StandardRuntimePlatform.cs | 3 +- .../StandardRuntimePlatformServices.cs | 4 +- src/Avalonia.Base/Properties/AssemblyInfo.cs | 1 - .../AppBuilder.cs | 2 +- src/Avalonia.Controls/AppBuilderBase.cs | 36 ++----------- .../Avalonia.Web.Blazor.csproj | 1 - .../AvaloniaBlazorAppBuilder.cs | 1 - .../AssetLoaderTests.cs | 5 +- .../Media/PathMarkupParserTests.cs | 1 - .../Styling/ResourceBenchmarks.cs | 1 - .../Themes/FluentBenchmark.cs | 1 - .../Themes/ThemeBenchmark.cs | 2 +- tests/Avalonia.RenderTests/TestBase.cs | 2 - .../Avalonia.UnitTests.csproj | 1 - tests/Avalonia.UnitTests/TestServices.cs | 1 - .../Avalonia.UnitTests/UnitTestApplication.cs | 1 - 28 files changed, 22 insertions(+), 118 deletions(-) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/AssetLoader.cs (98%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/Internal/AssemblyDescriptor.cs (97%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/Internal/AssemblyDescriptorResolver.cs (96%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/Internal/AssetDescriptor.cs (96%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/Internal/Constants.cs (69%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform/Internal}/DynLoader.cs (99%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/Internal/SlicedStream.cs (97%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/StandardRuntimePlatform.cs (98%) rename src/{Avalonia.PlatformSupport => Avalonia.Base/Platform}/StandardRuntimePlatformServices.cs (95%) rename src/{Avalonia.PlatformSupport => Avalonia.Controls}/AppBuilder.cs (94%) rename tests/{Avalonia.PlatformSupport.UnitTests => Avalonia.Base.UnitTests}/AssetLoaderTests.cs (95%) diff --git a/Avalonia.sln b/Avalonia.sln index c8e513f94c..1df0209b8d 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -209,12 +209,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WindowsInteropTest", "sampl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlSamples", "samples\SampleControls\ControlSamples.csproj", "{A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport", "src\Avalonia.PlatformSupport\Avalonia.PlatformSupport.csproj", "{E8A597F0-2AB5-4BDA-A235-41162DAF53CF}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport.UnitTests", "tests\Avalonia.PlatformSupport.UnitTests\Avalonia.PlatformSupport.UnitTests.csproj", "{CE910927-CE5A-456F-BC92-E4C757354A5C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.SourceGenerator", "src\Avalonia.SourceGenerator\Avalonia.SourceGenerator.csproj", "{CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\DevAnalyzers\DevAnalyzers.csproj", "{2B390431-288C-435C-BB6B-A374033BD8D1}" @@ -1845,30 +1841,6 @@ Global {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.Build.0 = Release|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhone.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhone.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|Any CPU.Build.0 = Release|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.ActiveCfg = Release|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhone.Build.0 = Release|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E8A597F0-2AB5-4BDA-A235-41162DAF53CF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -1893,30 +1865,6 @@ Global {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhone.Build.0 = Release|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.AppStore|iPhone.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Debug|iPhone.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|Any CPU.Build.0 = Release|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhone.ActiveCfg = Release|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhone.Build.0 = Release|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CE910927-CE5A-456F-BC92-E4C757354A5C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU @@ -2046,7 +1994,6 @@ Global {26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098} {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {CE910927-CE5A-456F-BC92-E4C757354A5C} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B} {2B390431-288C-435C-BB6B-A374033BD8D1} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/build/CoreLibraries.props b/build/CoreLibraries.props index 9448a31d73..00a1e3094b 100644 --- a/build/CoreLibraries.props +++ b/build/CoreLibraries.props @@ -8,6 +8,5 @@ - diff --git a/src/Avalonia.Base/Media/PathGeometry.cs b/src/Avalonia.Base/Media/PathGeometry.cs index 2c8a51c541..8662c3351d 100644 --- a/src/Avalonia.Base/Media/PathGeometry.cs +++ b/src/Avalonia.Base/Media/PathGeometry.cs @@ -2,7 +2,6 @@ using System; using Avalonia.Collections; using Avalonia.Metadata; using Avalonia.Platform; -using Avalonia.Visuals.Platform; namespace Avalonia.Media { diff --git a/src/Avalonia.Base/Media/PathGeometryCollections.cs b/src/Avalonia.Base/Media/PathGeometryCollections.cs index 1165b192a7..c663b1ebe5 100644 --- a/src/Avalonia.Base/Media/PathGeometryCollections.cs +++ b/src/Avalonia.Base/Media/PathGeometryCollections.cs @@ -1,5 +1,5 @@ using Avalonia.Collections; -using Avalonia.Visuals.Platform; +using Avalonia.Platform; namespace Avalonia.Media { diff --git a/src/Avalonia.PlatformSupport/AssetLoader.cs b/src/Avalonia.Base/Platform/AssetLoader.cs similarity index 98% rename from src/Avalonia.PlatformSupport/AssetLoader.cs rename to src/Avalonia.Base/Platform/AssetLoader.cs index 0e33c3d4c7..a74da2a178 100644 --- a/src/Avalonia.PlatformSupport/AssetLoader.cs +++ b/src/Avalonia.Base/Platform/AssetLoader.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using Avalonia.Platform; -using Avalonia.PlatformSupport.Internal; +using Avalonia.Platform.Internal; using Avalonia.Utilities; -namespace Avalonia.PlatformSupport +namespace Avalonia.Platform { /// /// Loads assets compiled into the application binary. diff --git a/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptor.cs b/src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs similarity index 97% rename from src/Avalonia.PlatformSupport/Internal/AssemblyDescriptor.cs rename to src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs index 64ffec8482..df2a26ddd3 100644 --- a/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptor.cs +++ b/src/Avalonia.Base/Platform/Internal/AssemblyDescriptor.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Reflection; using Avalonia.Utilities; -namespace Avalonia.PlatformSupport.Internal; +namespace Avalonia.Platform.Internal; internal interface IAssemblyDescriptor { diff --git a/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs b/src/Avalonia.Base/Platform/Internal/AssemblyDescriptorResolver.cs similarity index 96% rename from src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs rename to src/Avalonia.Base/Platform/Internal/AssemblyDescriptorResolver.cs index 6b85200c76..b12130b1f7 100644 --- a/src/Avalonia.PlatformSupport/Internal/AssemblyDescriptorResolver.cs +++ b/src/Avalonia.Base/Platform/Internal/AssemblyDescriptorResolver.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; -namespace Avalonia.PlatformSupport.Internal; +namespace Avalonia.Platform.Internal; internal interface IAssemblyDescriptorResolver { diff --git a/src/Avalonia.PlatformSupport/Internal/AssetDescriptor.cs b/src/Avalonia.Base/Platform/Internal/AssetDescriptor.cs similarity index 96% rename from src/Avalonia.PlatformSupport/Internal/AssetDescriptor.cs rename to src/Avalonia.Base/Platform/Internal/AssetDescriptor.cs index baae1f99e7..52f8f5e68d 100644 --- a/src/Avalonia.PlatformSupport/Internal/AssetDescriptor.cs +++ b/src/Avalonia.Base/Platform/Internal/AssetDescriptor.cs @@ -2,7 +2,7 @@ using System.IO; using System.Reflection; -namespace Avalonia.PlatformSupport.Internal; +namespace Avalonia.Platform.Internal; internal interface IAssetDescriptor { diff --git a/src/Avalonia.PlatformSupport/Internal/Constants.cs b/src/Avalonia.Base/Platform/Internal/Constants.cs similarity index 69% rename from src/Avalonia.PlatformSupport/Internal/Constants.cs rename to src/Avalonia.Base/Platform/Internal/Constants.cs index c8a0f7b1ce..cad864e7e3 100644 --- a/src/Avalonia.PlatformSupport/Internal/Constants.cs +++ b/src/Avalonia.Base/Platform/Internal/Constants.cs @@ -1,4 +1,4 @@ -namespace Avalonia.PlatformSupport.Internal; +namespace Avalonia.Platform.Internal; internal static class Constants { diff --git a/src/Avalonia.PlatformSupport/DynLoader.cs b/src/Avalonia.Base/Platform/Internal/DynLoader.cs similarity index 99% rename from src/Avalonia.PlatformSupport/DynLoader.cs rename to src/Avalonia.Base/Platform/Internal/DynLoader.cs index ef2166d943..07903669b1 100644 --- a/src/Avalonia.PlatformSupport/DynLoader.cs +++ b/src/Avalonia.Base/Platform/Internal/DynLoader.cs @@ -3,7 +3,7 @@ using System.Runtime.InteropServices; using Avalonia.Platform.Interop; // ReSharper disable InconsistentNaming -namespace Avalonia.PlatformSupport +namespace Avalonia.Platform.Internal { class UnixLoader : IDynamicLibraryLoader { diff --git a/src/Avalonia.PlatformSupport/Internal/SlicedStream.cs b/src/Avalonia.Base/Platform/Internal/SlicedStream.cs similarity index 97% rename from src/Avalonia.PlatformSupport/Internal/SlicedStream.cs rename to src/Avalonia.Base/Platform/Internal/SlicedStream.cs index e310db964a..124c248aa8 100644 --- a/src/Avalonia.PlatformSupport/Internal/SlicedStream.cs +++ b/src/Avalonia.Base/Platform/Internal/SlicedStream.cs @@ -1,7 +1,7 @@ using System; using System.IO; -namespace Avalonia.PlatformSupport.Internal; +namespace Avalonia.Platform.Internal; internal class SlicedStream : Stream { diff --git a/src/Avalonia.Base/Platform/PathGeometryContext.cs b/src/Avalonia.Base/Platform/PathGeometryContext.cs index 694e9f8d80..6c0bbe0f3f 100644 --- a/src/Avalonia.Base/Platform/PathGeometryContext.cs +++ b/src/Avalonia.Base/Platform/PathGeometryContext.cs @@ -1,9 +1,8 @@ using System; using System.Diagnostics.CodeAnalysis; using Avalonia.Media; -using Avalonia.Platform; -namespace Avalonia.Visuals.Platform +namespace Avalonia.Platform { public class PathGeometryContext : IGeometryContext { diff --git a/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs similarity index 98% rename from src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs rename to src/Avalonia.Base/Platform/StandardRuntimePlatform.cs index 048f09570f..fdbd48a9f8 100644 --- a/src/Avalonia.PlatformSupport/StandardRuntimePlatform.cs +++ b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs @@ -1,9 +1,8 @@ using System; using System.Runtime.InteropServices; using System.Threading; -using Avalonia.Platform; -namespace Avalonia.PlatformSupport +namespace Avalonia.Platform { public class StandardRuntimePlatform : IRuntimePlatform { diff --git a/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs b/src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs similarity index 95% rename from src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs rename to src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs index 11ca906782..65d6733399 100644 --- a/src/Avalonia.PlatformSupport/StandardRuntimePlatformServices.cs +++ b/src/Avalonia.Base/Platform/StandardRuntimePlatformServices.cs @@ -1,8 +1,8 @@ using System.Reflection; -using Avalonia.Platform; +using Avalonia.Platform.Internal; using Avalonia.Platform.Interop; -namespace Avalonia.PlatformSupport +namespace Avalonia.Platform { public static class StandardRuntimePlatformServices { diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs index 2c40c768f5..c8368e6d7a 100644 --- a/src/Avalonia.Base/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs @@ -26,7 +26,6 @@ using Avalonia.Metadata; [assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.PlatformSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] diff --git a/src/Avalonia.PlatformSupport/AppBuilder.cs b/src/Avalonia.Controls/AppBuilder.cs similarity index 94% rename from src/Avalonia.PlatformSupport/AppBuilder.cs rename to src/Avalonia.Controls/AppBuilder.cs index 136f1f39b3..5bcd87162e 100644 --- a/src/Avalonia.PlatformSupport/AppBuilder.cs +++ b/src/Avalonia.Controls/AppBuilder.cs @@ -1,5 +1,5 @@ using Avalonia.Controls; -using Avalonia.PlatformSupport; +using Avalonia.Platform; namespace Avalonia { diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs index 8779ae9122..6b7101cd49 100644 --- a/src/Avalonia.Controls/AppBuilderBase.cs +++ b/src/Avalonia.Controls/AppBuilderBase.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Reflection; using System.Linq; using Avalonia.Controls.ApplicationLifetimes; @@ -120,38 +119,8 @@ namespace Avalonia.Controls return Self; } - /// - /// Starts the application with an instance of . - /// - /// The window type. - /// A delegate that will be called to create a data context for the window (optional). - [Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")] - public void Start(Func? dataContextProvider = null) - where TMainWindow : Window, new() - { - AfterSetup(builder => - { - var window = new TMainWindow(); - if (dataContextProvider != null) - window.DataContext = dataContextProvider(); - ((IClassicDesktopStyleApplicationLifetime)builder.Instance!.ApplicationLifetime!) - .MainWindow = window; - }); - - // Copy-pasted because we can't call extension methods due to generic constraints - var lifetime = new ClassicDesktopStyleApplicationLifetime() {ShutdownMode = ShutdownMode.OnMainWindowClose}; - SetupWithLifetime(lifetime); - lifetime.Start(Array.Empty()); - } - public delegate void AppMainDelegate(Application app, string[] args); - - [Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details", true)] - public void Start() - { - throw new NotSupportedException(); - } - + public void Start(AppMainDelegate main, string[] args) { Setup(); @@ -234,6 +203,9 @@ namespace Avalonia.Controls protected virtual bool CheckSetup => true; + /// + /// Searches and initiates modules included with attribute. + /// private void SetupAvaloniaModules() { var moduleInitializers = from assembly in AppDomain.CurrentDomain.GetAssemblies() diff --git a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj index 98fdccfe83..1531c95830 100644 --- a/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj +++ b/src/Web/Avalonia.Web.Blazor/Avalonia.Web.Blazor.csproj @@ -51,7 +51,6 @@ - diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs index 2eb340406b..11d9bcc98f 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaBlazorAppBuilder.cs @@ -1,6 +1,5 @@ using Avalonia.Controls; using Avalonia.Platform; -using Avalonia.PlatformSupport; namespace Avalonia.Web.Blazor { diff --git a/tests/Avalonia.PlatformSupport.UnitTests/AssetLoaderTests.cs b/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs similarity index 95% rename from tests/Avalonia.PlatformSupport.UnitTests/AssetLoaderTests.cs rename to tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs index dfd195073b..06b7a4ce94 100644 --- a/tests/Avalonia.PlatformSupport.UnitTests/AssetLoaderTests.cs +++ b/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs @@ -1,10 +1,11 @@ using System; using System.Reflection; -using Avalonia.PlatformSupport.Internal; +using Avalonia.Platform; +using Avalonia.Platform.Internal; using Moq; using Xunit; -namespace Avalonia.PlatformSupport.UnitTests; +namespace Avalonia.Base.UnitTests; public class AssetLoaderTests { diff --git a/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs b/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs index c829690eb4..73e97bf13c 100644 --- a/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs +++ b/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.IO; using Avalonia.Media; using Avalonia.Platform; -using Avalonia.Visuals.Platform; using Moq; using Xunit; diff --git a/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs b/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs index 2a048beefa..b16e891924 100644 --- a/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs +++ b/tests/Avalonia.Benchmarks/Styling/ResourceBenchmarks.cs @@ -1,7 +1,6 @@ using System; using Avalonia.Controls; using Avalonia.Platform; -using Avalonia.PlatformSupport; using Avalonia.Styling; using Avalonia.UnitTests; using BenchmarkDotNet.Attributes; diff --git a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs index 6f04bb5206..ceb015ee63 100644 --- a/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs +++ b/tests/Avalonia.Benchmarks/Themes/FluentBenchmark.cs @@ -1,7 +1,6 @@ using System; using Avalonia.Controls; using Avalonia.Platform; -using Avalonia.PlatformSupport; using Avalonia.Styling; using Avalonia.UnitTests; using BenchmarkDotNet.Attributes; diff --git a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs index 81264f109c..9a5b49790d 100644 --- a/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs +++ b/tests/Avalonia.Benchmarks/Themes/ThemeBenchmark.cs @@ -2,7 +2,7 @@ using Avalonia.Controls; using Avalonia.Markup.Xaml.Styling; -using Avalonia.PlatformSupport; +using Avalonia.Platform; using Avalonia.Styling; using Avalonia.UnitTests; diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index 523876500f..39250f2aa7 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/tests/Avalonia.RenderTests/TestBase.cs @@ -25,8 +25,6 @@ namespace Avalonia.Skia.RenderTests namespace Avalonia.Direct2D1.RenderTests #endif { - using Avalonia.PlatformSupport; - public class TestBase { #if AVALONIA_SKIA diff --git a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj index f54ccaa857..52ef23c966 100644 --- a/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj +++ b/tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj @@ -14,7 +14,6 @@ - diff --git a/tests/Avalonia.UnitTests/TestServices.cs b/tests/Avalonia.UnitTests/TestServices.cs index 1d55b77aab..c1be745aca 100644 --- a/tests/Avalonia.UnitTests/TestServices.cs +++ b/tests/Avalonia.UnitTests/TestServices.cs @@ -5,7 +5,6 @@ using Avalonia.Layout; using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.Platform; -using Avalonia.PlatformSupport; using Avalonia.Styling; using Avalonia.Themes.Default; using Avalonia.Rendering; diff --git a/tests/Avalonia.UnitTests/UnitTestApplication.cs b/tests/Avalonia.UnitTests/UnitTestApplication.cs index bb6e53d74f..63c2832b92 100644 --- a/tests/Avalonia.UnitTests/UnitTestApplication.cs +++ b/tests/Avalonia.UnitTests/UnitTestApplication.cs @@ -10,7 +10,6 @@ using System.Reactive.Disposables; using System.Reactive.Concurrency; using Avalonia.Input.Platform; using Avalonia.Animation; -using Avalonia.PlatformSupport; namespace Avalonia.UnitTests { From 2538d2cde662d601bd3d2af436443c25ae752043 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 24 May 2022 23:36:05 -0400 Subject: [PATCH 160/332] Copy runtime detection from dotnet/runtime repository --- .../Platform/StandardRuntimePlatform.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs index fdbd48a9f8..3acb5f6330 100644 --- a/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs +++ b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs @@ -85,15 +85,18 @@ namespace Avalonia.Platform else throw new Exception("Unknown OS platform " + RuntimeInformation.OSDescription); + // Source: https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs + var isCoreClr = Environment.Version.Major >= 5 || RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase); + var isMonoRuntime = Type.GetType("Mono.RuntimeStructs") != null; + var isFramework = !isCoreClr && RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase); + return new RuntimePlatformInfo { -#if NETCOREAPP - IsCoreClr = true, -#elif NETFRAMEWORK - IsDotNetFramework = true, -#endif + IsCoreClr = isCoreClr, + IsDotNetFramework = isFramework, + IsMono = isMonoRuntime, + IsDesktop = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.WinNT, - IsMono = os is OperatingSystemType.Android or OperatingSystemType.iOS or OperatingSystemType.Browser, IsMobile = os is OperatingSystemType.Android or OperatingSystemType.iOS, IsUnix = os is OperatingSystemType.Linux or OperatingSystemType.OSX or OperatingSystemType.Android, IsBrowser = os == OperatingSystemType.Browser, From 7fee2359dce9e8cb12f97400ec6e7f4319fb8ccf Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 24 May 2022 23:42:36 -0400 Subject: [PATCH 161/332] Remove Ad-Hoc/AppStore/iPhone/iPhoneSimulator configurations --- Avalonia.sln | 1431 -------------------------------------------------- 1 file changed, 1431 deletions(-) diff --git a/Avalonia.sln b/Avalonia.sln index 1df0209b8d..04aad99211 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -217,1726 +217,296 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevAnalyzers", "src\tools\D EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Ad-Hoc|Any CPU = Ad-Hoc|Any CPU - Ad-Hoc|iPhone = Ad-Hoc|iPhone - Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator - AppStore|Any CPU = AppStore|Any CPU - AppStore|iPhone = AppStore|iPhone - AppStore|iPhoneSimulator = AppStore|iPhoneSimulator Debug|Any CPU = Debug|Any CPU - Debug|iPhone = Debug|iPhone - Debug|iPhoneSimulator = Debug|iPhoneSimulator Release|Any CPU = Release|Any CPU - Release|iPhone = Release|iPhone - Release|iPhoneSimulator = Release|iPhoneSimulator EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhone.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhone.Build.0 = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.ActiveCfg = Release|Any CPU {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|Any CPU.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhone.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhone.Build.0 = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|Any CPU.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhone.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|Any CPU.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhone.Build.0 = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.ActiveCfg = Release|Any CPU {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|Any CPU.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhone.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhone.Build.0 = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {811A76CF-1CF6-440F-963B-BBE31BD72A82}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhone.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhone.Build.0 = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|Any CPU.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhone.Build.0 = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E908F67-5543-4879-A1DC-08EACE79B3CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|Any CPU.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhone.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhone.Build.0 = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.ActiveCfg = Release|Any CPU {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|Any CPU.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhone.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhone.Build.0 = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D2221C82-4A25-4583-9B43-D791E3F6820C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhone.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhone.Build.0 = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|Any CPU.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhone.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhone.Build.0 = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|Any CPU.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhone.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhone.Build.0 = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.ActiveCfg = Release|Any CPU {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|Any CPU.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhone.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhone.Build.0 = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7062AE20-5DCC-4442-9645-8195BDECE63E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|Any CPU.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhone.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhone.Build.0 = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|Any CPU.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhone.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhone.Build.0 = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {5CCB5571-7C30-4E7D-967D-0E2158EBD91F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|Any CPU.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhone.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhone.Build.0 = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhone.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhone.Build.0 = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhone.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhone.Build.0 = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.ActiveCfg = Release|Any CPU {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|Any CPU.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhone.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhone.Build.0 = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {DABFD304-D6A4-4752-8123-C2CCF7AC7831}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhone.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhone.Build.0 = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.ActiveCfg = Release|Any CPU {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|Any CPU.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhone.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhone.Build.0 = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {EFB11458-9CDF-41C0-BE4F-44AF45A4CAB8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|Any CPU.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhone.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhone.Build.0 = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.ActiveCfg = Release|Any CPU {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|Any CPU.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhone.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhone.Build.0 = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {99135EAB-653D-47E4-A378-C96E1278CA44}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|Any CPU.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhone.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhone.Build.0 = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.ActiveCfg = Release|Any CPU {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|Any CPU.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhone.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhone.Build.0 = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3E53A01A-B331-47F3-B828-4A5717E77A24}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|Any CPU.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhone.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhone.Build.0 = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.ActiveCfg = Release|Any CPU {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhone.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhone.Build.0 = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|Any CPU.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhone.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhone.Build.0 = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.ActiveCfg = Release|Any CPU {6417E941-21BC-467B-A771-0DE389353CE6}.Release|Any CPU.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhone.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhone.Build.0 = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6417E941-21BC-467B-A771-0DE389353CE6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|Any CPU.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhone.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhone.Build.0 = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.ActiveCfg = Release|Any CPU {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|Any CPU.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhone.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhone.Build.0 = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8EF392D5-1416-45AA-9956-7CBBC3229E8A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|Any CPU.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhone.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|Any CPU.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhone.Build.0 = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.ActiveCfg = Release|Any CPU {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|Any CPU.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhone.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhone.Build.0 = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.ActiveCfg = Release|Any CPU {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|Any CPU.Build.0 = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhone.ActiveCfg = Release|Any CPU - {7B92AF71-6287-4693-9DCB-BD5B6E927E23}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|Any CPU.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhone.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhone.Build.0 = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.ActiveCfg = Release|Any CPU {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|Any CPU.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhone.Build.0 = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4488AD85-1495-4809-9AA4-DDFE0A48527E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|Any CPU.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhone.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhone.Build.0 = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|Any CPU.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhone.Build.0 = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1AA3DBF-9056-4530-9376-18119A7A3FFE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|Any CPU.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhone.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhone.Build.0 = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.ActiveCfg = Release|Any CPU {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|Any CPU.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhone.Build.0 = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {88060192-33D5-4932-B0F9-8BD2763E857D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|Any CPU.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhone.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhone.Build.0 = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|Any CPU.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhone.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhone.Build.0 = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {410AC439-81A1-4EB5-B5E9-6A7FC6B77F4B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|Any CPU.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhone.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhone.Build.0 = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.ActiveCfg = Release|Any CPU {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|Any CPU.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhone.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhone.Build.0 = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {799A7BB5-3C2C-48B6-85A7-406A12C420DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|Any CPU.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhone.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhone.Build.0 = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.ActiveCfg = Release|Any CPU {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|Any CPU.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhone.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhone.Build.0 = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D0A739B9-3C68-4BA6-A328-41606954B6BD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|Any CPU.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhone.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhone.Build.0 = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|Any CPU.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhone.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhone.Build.0 = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2B888490-D14A-4BCA-AB4B-48676FA93C9B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.AppStore|Any CPU.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.AppStore|iPhone.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {52F55355-D120-42AC-8116-8410A7D602FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {52F55355-D120-42AC-8116-8410A7D602FA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Debug|iPhone.Build.0 = Debug|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {52F55355-D120-42AC-8116-8410A7D602FA}.Release|Any CPU.ActiveCfg = Release|Any CPU {52F55355-D120-42AC-8116-8410A7D602FA}.Release|Any CPU.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Release|iPhone.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Release|iPhone.Build.0 = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {52F55355-D120-42AC-8116-8410A7D602FA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.AppStore|Any CPU.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.AppStore|iPhone.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|iPhone.Build.0 = Debug|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|Any CPU.ActiveCfg = Release|Any CPU {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|Any CPU.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|iPhone.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|iPhone.Build.0 = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1381F98-4D24-409A-A6C5-1C5B1E08BB08}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.AppStore|Any CPU.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.AppStore|iPhone.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|iPhone.Build.0 = Debug|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|Any CPU.ActiveCfg = Release|Any CPU {FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|Any CPU.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|iPhone.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|iPhone.Build.0 = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.AppStore|Any CPU.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.AppStore|iPhone.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|iPhone.Build.0 = Debug|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|Any CPU.ActiveCfg = Release|Any CPU {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|Any CPU.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|iPhone.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|iPhone.Build.0 = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F1FDC5B0-4654-416F-AE69-E3E9BBD87801}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Any CPU.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|Any CPU.Deploy.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhone.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhone.Deploy.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|Any CPU.Deploy.0 = Debug|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhone.Build.0 = Debug|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhone.Deploy.0 = Debug|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.Build.0 = Release|Any CPU {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|Any CPU.Deploy.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhone.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhone.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhone.Deploy.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {29132311-1848-4FD6-AE0C-4FF841151BD3}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|Any CPU.Build.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhone.Build.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhone.Build.0 = Debug|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|Any CPU.Build.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhone.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhone.Build.0 = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7D2D3083-71DD-4CC9-8907-39A0D86FB322}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhone.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhone.Build.0 = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.Build.0 = Release|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhone.ActiveCfg = Release|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhone.Build.0 = Release|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhone.Build.0 = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhone.Build.0 = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.Build.0 = Release|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhone.ActiveCfg = Release|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhone.Build.0 = Release|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.Build.0 = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.Build.0 = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.ActiveCfg = Release|Any CPU {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.Build.0 = Release|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.ActiveCfg = Release|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.Build.0 = Release|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|Any CPU.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhone.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhone.Build.0 = Debug|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Any CPU.ActiveCfg = Release|Any CPU {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Any CPU.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhone.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhone.Build.0 = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.AppStore|iPhone.Build.0 = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {E1582370-37B3-403C-917F-8209551B1634}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E1582370-37B3-403C-917F-8209551B1634}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Debug|iPhone.Build.0 = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {E1582370-37B3-403C-917F-8209551B1634}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1582370-37B3-403C-917F-8209551B1634}.Release|Any CPU.Build.0 = Release|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Release|iPhone.ActiveCfg = Release|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Release|iPhone.Build.0 = Release|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1582370-37B3-403C-917F-8209551B1634}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhone.Build.0 = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhone.Build.0 = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.ActiveCfg = Release|Any CPU {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|Any CPU.Build.0 = Release|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.ActiveCfg = Release|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhone.Build.0 = Release|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D78A720C-C0C6-478B-8564-F167F9BDD01B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhone.Build.0 = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhone.Build.0 = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|Any CPU.Build.0 = Release|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.ActiveCfg = Release|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhone.Build.0 = Release|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E2999E4A-9086-401F-898C-AEB0AD38E676}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|Any CPU.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhone.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {050CC912-FF49-4A8B-B534-9544017446DD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhone.Build.0 = Debug|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {050CC912-FF49-4A8B-B534-9544017446DD}.Release|Any CPU.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhone.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhone.Build.0 = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {050CC912-FF49-4A8B-B534-9544017446DD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|Any CPU.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhone.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhone.Build.0 = Debug|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|Any CPU.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhone.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhone.Build.0 = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F40FC0A2-1BC3-401C-BFC1-928EC4D4A9CE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.AppStore|iPhone.Build.0 = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|iPhone.Build.0 = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|Any CPU.Build.0 = Release|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhone.ActiveCfg = Release|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhone.Build.0 = Release|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhone.Build.0 = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhone.Build.0 = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.ActiveCfg = Release|Any CPU {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.Build.0 = Release|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.ActiveCfg = Release|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.Build.0 = Release|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhone.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhone.Build.0 = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.ActiveCfg = Release|Any CPU {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|Any CPU.Build.0 = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.ActiveCfg = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhone.Build.0 = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {12A91A62-C064-42CA-9A8C-A1272F354388}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhone.Build.0 = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhone.Build.0 = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|Any CPU.ActiveCfg = Release|Any CPU {D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|Any CPU.Build.0 = Release|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhone.ActiveCfg = Release|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhone.Build.0 = Release|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D49233F8-F29C-47DD-9975-C4C9E4502720}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhone.Build.0 = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhone.Build.0 = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|Any CPU.Build.0 = Release|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhone.ActiveCfg = Release|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhone.Build.0 = Release|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3C471044-3640-45E3-B1B2-16D2FF8399EE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhone.Build.0 = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhone.Build.0 = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|Any CPU.Build.0 = Release|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhone.ActiveCfg = Release|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhone.Build.0 = Release|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {BF28998D-072C-439A-AFBB-2FE5021241E0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|Any CPU.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhone.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhone.Build.0 = Debug|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhone.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhone.Build.0 = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3F00BC43-5095-477F-93D8-E65B08179A00}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhone.Build.0 = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {41B02319-965D-4945-8005-C1A3D1224165}.Debug|Any CPU.Build.0 = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhone.Build.0 = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.ActiveCfg = Release|Any CPU {41B02319-965D-4945-8005-C1A3D1224165}.Release|Any CPU.Build.0 = Release|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhone.ActiveCfg = Release|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhone.Build.0 = Release|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {41B02319-965D-4945-8005-C1A3D1224165}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhone.Build.0 = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhone.Build.0 = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|Any CPU.Build.0 = Release|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhone.ActiveCfg = Release|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhone.Build.0 = Release|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {D775DECB-4E00-4ED5-A75A-5FCE58ADFF0B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhone.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhone.Build.0 = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.ActiveCfg = Release|Any CPU {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|Any CPU.Build.0 = Release|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhone.ActiveCfg = Release|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhone.Build.0 = Release|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {AF915D5C-AB00-4EA0-B5E6-001F4AE84E68}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.AppStore|iPhone.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|iPhone.Build.0 = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Release|Any CPU.ActiveCfg = Release|Any CPU {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Release|Any CPU.Build.0 = Release|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Release|iPhone.ActiveCfg = Release|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Release|iPhone.Build.0 = Release|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3278F3A9-9509-4A3F-A15B-BDC8B5BFF632}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.AppStore|iPhone.Build.0 = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|iPhone.Build.0 = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|Any CPU.Build.0 = Release|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|iPhone.ActiveCfg = Release|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|iPhone.Build.0 = Release|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4D55985A-1EE2-4F25-AD39-6EA8BC04F8FB}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.AppStore|iPhone.Build.0 = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|iPhone.Build.0 = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|Any CPU.Build.0 = Release|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhone.ActiveCfg = Release|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhone.Build.0 = Release|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {4D36CEC8-53F2-40A5-9A37-79AAE356E2DA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhone.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhone.Build.0 = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|Any CPU.ActiveCfg = Release|Any CPU {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|Any CPU.Build.0 = Release|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhone.ActiveCfg = Release|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhone.Build.0 = Release|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {351337F5-D66F-461B-A957-4EF60BDB4BA6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhone.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhone.Build.0 = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|Any CPU.ActiveCfg = Release|Any CPU {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|Any CPU.Build.0 = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhone.ActiveCfg = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhone.Build.0 = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3C84E04B-36CF-4D0D-B965-C26DD649D1F3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.AppStore|iPhone.Build.0 = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|iPhone.Build.0 = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|Any CPU.ActiveCfg = Release|Any CPU {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|Any CPU.Build.0 = Release|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|iPhone.ActiveCfg = Release|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|iPhone.Build.0 = Release|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {C42D2FC1-A531-4ED4-84B9-89AEC7C962FC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.AppStore|iPhone.Build.0 = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|iPhone.Build.0 = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|Any CPU.ActiveCfg = Release|Any CPU {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|Any CPU.Build.0 = Release|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|iPhone.ActiveCfg = Release|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|iPhone.Build.0 = Release|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {8C89950F-F5D9-47FC-8066-CBC1EC3DF8FC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.AppStore|iPhone.Build.0 = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|iPhone.Build.0 = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|Any CPU.Build.0 = Release|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|iPhone.ActiveCfg = Release|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|iPhone.Build.0 = Release|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {B859AE7C-F34F-4A9E-88AE-E0E7229FDE1E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.AppStore|iPhone.Build.0 = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|Any CPU.Build.0 = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|iPhone.Build.0 = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|Any CPU.ActiveCfg = Release|Any CPU {909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|Any CPU.Build.0 = Release|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|iPhone.ActiveCfg = Release|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|iPhone.Build.0 = Release|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {909A8CBD-7D0E-42FD-B841-022AD8925820}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|Any CPU.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|Any CPU.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhone.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhone.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|Any CPU.Build.0 = Debug|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhone.Build.0 = Debug|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|Any CPU.ActiveCfg = Release|Any CPU {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|Any CPU.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhone.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhone.Build.0 = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhone.Build.0 = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhone.Build.0 = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|Any CPU.Build.0 = Release|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.ActiveCfg = Release|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.Build.0 = Release|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.Build.0 = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.Build.0 = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.Build.0 = Release|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.ActiveCfg = Release|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.Build.0 = Release|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.AppStore|iPhone.Build.0 = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|Any CPU.Build.0 = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|iPhone.Build.0 = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|Any CPU.ActiveCfg = Release|Any CPU {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|Any CPU.Build.0 = Release|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|iPhone.ActiveCfg = Release|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|iPhone.Build.0 = Release|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {676D6BFD-029D-4E43-BFC7-3892265CE251}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.AppStore|iPhone.Build.0 = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|iPhone.Build.0 = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|Any CPU.ActiveCfg = Release|Any CPU {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|Any CPU.Build.0 = Release|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|iPhone.ActiveCfg = Release|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|iPhone.Build.0 = Release|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {F2CE566B-E7F6-447A-AB1A-3F574A6FE43A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.AppStore|iPhone.Build.0 = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {25831348-EB2A-483E-9576-E8F6528674A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25831348-EB2A-483E-9576-E8F6528674A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Debug|iPhone.Build.0 = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.ActiveCfg = Release|Any CPU {25831348-EB2A-483E-9576-E8F6528674A5}.Release|Any CPU.Build.0 = Release|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Release|iPhone.ActiveCfg = Release|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Release|iPhone.Build.0 = Release|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {25831348-EB2A-483E-9576-E8F6528674A5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.AppStore|iPhone.Build.0 = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|iPhone.Build.0 = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|Any CPU.ActiveCfg = Release|Any CPU {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|Any CPU.Build.0 = Release|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|iPhone.ActiveCfg = Release|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|iPhone.Build.0 = Release|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {C08E9894-AA92-426E-BF56-033E262CAD3E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.AppStore|iPhone.Build.0 = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|iPhone.Build.0 = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|Any CPU.Build.0 = Release|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|iPhone.ActiveCfg = Release|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|iPhone.Build.0 = Release|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {26A98DA1-D89D-4A95-8152-349F404DA2E2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhone.Build.0 = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhone.Build.0 = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|Any CPU.ActiveCfg = Release|Any CPU {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|Any CPU.Build.0 = Release|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.ActiveCfg = Release|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhone.Build.0 = Release|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.AppStore|iPhone.Build.0 = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|iPhone.Build.0 = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|Any CPU.Build.0 = Release|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhone.ActiveCfg = Release|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhone.Build.0 = Release|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhone.Build.0 = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhone.Build.0 = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|Any CPU.ActiveCfg = Release|Any CPU {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|Any CPU.Build.0 = Release|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhone.ActiveCfg = Release|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhone.Build.0 = Release|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {CA932DF3-2616-4BF6-8F28-1AD0EC40F1FF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhone.Build.0 = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhone.Build.0 = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|Any CPU.Build.0 = Release|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhone.ActiveCfg = Release|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhone.Build.0 = Release|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {2B390431-288C-435C-BB6B-A374033BD8D1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhone.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhone.Build.0 = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.ActiveCfg = Release|Any CPU {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|Any CPU.Build.0 = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.ActiveCfg = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhone.Build.0 = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {1ECC012A-8837-4AE2-9BDA-3E2857898727}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1968,7 +538,6 @@ Global {29132311-1848-4FD6-AE0C-4FF841151BD3} = {9B9E3891-2366-4253-A952-D08BCEB71098} {7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E} {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} = {A689DEF5-D50F-4975-8B72-124C9EB54066} {854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B} {638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888} From 17a2a4e2e03d754923b428960fa63879f397cd78 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 00:01:59 -0400 Subject: [PATCH 162/332] Extract UnmanagedBlob to a separated file --- .../Platform/Internal/UnmanagedBlob.cs | 57 +++++++++++++++++++ .../Platform/StandardRuntimePlatform.cs | 54 +----------------- 2 files changed, 58 insertions(+), 53 deletions(-) create mode 100644 src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs diff --git a/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs new file mode 100644 index 0000000000..eacf79d4f4 --- /dev/null +++ b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs @@ -0,0 +1,57 @@ +using System; +using System.Runtime.InteropServices; + +namespace Avalonia.Platform.Internal; + +internal class UnmanagedBlob : IUnmanagedBlob +{ + private IntPtr _address; + private readonly object _lock = new object(); + + public UnmanagedBlob(int size) + { + try + { + if (size <= 0) + throw new ArgumentException("Positive number required", nameof(size)); + _address = Marshal.AllocHGlobal(size); + GC.AddMemoryPressure(size); + Size = size; + } + catch + { + GC.SuppressFinalize(this); + throw; + } + } + + private void DoDispose() + { + lock (_lock) + { + if (!IsDisposed) + { + Marshal.FreeHGlobal(_address); + GC.RemoveMemoryPressure(Size); + IsDisposed = true; + _address = IntPtr.Zero; + Size = 0; + } + } + } + + public void Dispose() + { + DoDispose(); + GC.SuppressFinalize(this); + } + + ~UnmanagedBlob() + { + DoDispose(); + } + + public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address; + public int Size { get; private set; } + public bool IsDisposed { get; private set; } +} diff --git a/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs index 3acb5f6330..ebda6f453b 100644 --- a/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs +++ b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using System.Threading; +using Avalonia.Platform.Internal; namespace Avalonia.Platform { @@ -12,59 +13,6 @@ namespace Avalonia.Platform } public IUnmanagedBlob AllocBlob(int size) => new UnmanagedBlob(size); - - private class UnmanagedBlob : IUnmanagedBlob - { - private IntPtr _address; - private readonly object _lock = new object(); - - public UnmanagedBlob(int size) - { - try - { - if (size <= 0) - throw new ArgumentException("Positive number required", nameof(size)); - _address = Marshal.AllocHGlobal(size); - GC.AddMemoryPressure(size); - Size = size; - } - catch - { - GC.SuppressFinalize(this); - throw; - } - } - - private void DoDispose() - { - lock (_lock) - { - if (!IsDisposed) - { - Marshal.FreeHGlobal(_address); - GC.RemoveMemoryPressure(Size); - IsDisposed = true; - _address = IntPtr.Zero; - Size = 0; - } - } - } - - public void Dispose() - { - DoDispose(); - GC.SuppressFinalize(this); - } - - ~UnmanagedBlob() - { - DoDispose(); - } - - public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address; - public int Size { get; private set; } - public bool IsDisposed { get; private set; } - } private static readonly Lazy Info = new(() => { From a907b942c5fde9edbb6bdd48bde09480e64f262e Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 03:00:03 -0400 Subject: [PATCH 163/332] Remove platform support projects --- .../Avalonia.PlatformSupport.csproj | 24 ------------------- .../Avalonia.PlatformSupport.UnitTests.csproj | 24 ------------------- 2 files changed, 48 deletions(-) delete mode 100644 src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj delete mode 100644 tests/Avalonia.PlatformSupport.UnitTests/Avalonia.PlatformSupport.UnitTests.csproj diff --git a/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj b/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj deleted file mode 100644 index 5336f1e630..0000000000 --- a/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net6.0;net461;netstandard2.0 - - - - - - - - - - - - - - - - - - - - diff --git a/tests/Avalonia.PlatformSupport.UnitTests/Avalonia.PlatformSupport.UnitTests.csproj b/tests/Avalonia.PlatformSupport.UnitTests/Avalonia.PlatformSupport.UnitTests.csproj deleted file mode 100644 index d714941e5a..0000000000 --- a/tests/Avalonia.PlatformSupport.UnitTests/Avalonia.PlatformSupport.UnitTests.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net6.0 - enable - Library - true - latest - - - - - - - - - - - - - - - - From 7f90e74f254031499774ce13572d49cc38c3ac9d Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 03:09:10 -0400 Subject: [PATCH 164/332] Unwanted namespace changes --- src/Avalonia.Base/Media/PathGeometry.cs | 1 + src/Avalonia.Base/Media/PathGeometryCollections.cs | 2 +- src/Avalonia.Base/Platform/PathGeometryContext.cs | 3 ++- tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Media/PathGeometry.cs b/src/Avalonia.Base/Media/PathGeometry.cs index 8662c3351d..2c8a51c541 100644 --- a/src/Avalonia.Base/Media/PathGeometry.cs +++ b/src/Avalonia.Base/Media/PathGeometry.cs @@ -2,6 +2,7 @@ using System; using Avalonia.Collections; using Avalonia.Metadata; using Avalonia.Platform; +using Avalonia.Visuals.Platform; namespace Avalonia.Media { diff --git a/src/Avalonia.Base/Media/PathGeometryCollections.cs b/src/Avalonia.Base/Media/PathGeometryCollections.cs index c663b1ebe5..1165b192a7 100644 --- a/src/Avalonia.Base/Media/PathGeometryCollections.cs +++ b/src/Avalonia.Base/Media/PathGeometryCollections.cs @@ -1,5 +1,5 @@ using Avalonia.Collections; -using Avalonia.Platform; +using Avalonia.Visuals.Platform; namespace Avalonia.Media { diff --git a/src/Avalonia.Base/Platform/PathGeometryContext.cs b/src/Avalonia.Base/Platform/PathGeometryContext.cs index 6c0bbe0f3f..694e9f8d80 100644 --- a/src/Avalonia.Base/Platform/PathGeometryContext.cs +++ b/src/Avalonia.Base/Platform/PathGeometryContext.cs @@ -1,8 +1,9 @@ using System; using System.Diagnostics.CodeAnalysis; using Avalonia.Media; +using Avalonia.Platform; -namespace Avalonia.Platform +namespace Avalonia.Visuals.Platform { public class PathGeometryContext : IGeometryContext { diff --git a/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs b/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs index 73e97bf13c..c829690eb4 100644 --- a/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs +++ b/tests/Avalonia.Base.UnitTests/Media/PathMarkupParserTests.cs @@ -2,6 +2,7 @@ using System.Globalization; using System.IO; using Avalonia.Media; using Avalonia.Platform; +using Avalonia.Visuals.Platform; using Moq; using Xunit; From 0754e29a3c4c1f4b005bacf1ea03812ff2cb15d0 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 03:34:34 -0400 Subject: [PATCH 165/332] Address the review --- src/Avalonia.Base/Platform/StandardRuntimePlatform.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs index ebda6f453b..4df9e8e917 100644 --- a/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs +++ b/src/Avalonia.Base/Platform/StandardRuntimePlatform.cs @@ -20,7 +20,7 @@ namespace Avalonia.Platform if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) os = OperatingSystemType.OSX; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD"))) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) os = OperatingSystemType.Linux; else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) os = OperatingSystemType.WinNT; @@ -35,7 +35,7 @@ namespace Avalonia.Platform // Source: https://github.com/dotnet/runtime/blob/main/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs var isCoreClr = Environment.Version.Major >= 5 || RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase); - var isMonoRuntime = Type.GetType("Mono.RuntimeStructs") != null; + var isMonoRuntime = Type.GetType("Mono.Runtime") != null; var isFramework = !isCoreClr && RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase); return new RuntimePlatformInfo From 12fd9491265a3e9f8721050498982ee4ef8e3fcd Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 04:21:17 -0400 Subject: [PATCH 166/332] Disable AssemblyName_With_Non_ASCII_Should_Load_Avares test --- tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs b/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs index 06b7a4ce94..c590a763b2 100644 --- a/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs +++ b/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs @@ -39,7 +39,7 @@ public class AssetLoaderTests Assert.Equal(AssemblyNameWithWhitespace, assemblyActual?.FullName); } - [Fact] + [Fact(Skip = "RegisterResUriParsers breaks this test. Investigate.")] public void AssemblyName_With_Non_ASCII_Should_Load_Avares() { var uri = new Uri($"avares://{AssemblyNameWithNonAscii}/Assets/something"); From 39d9a014b7b337750d1c84d39d3ced96741920f7 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 04:42:19 -0400 Subject: [PATCH 167/332] Fix static SetAssemblyDescriptorResolver usage in tests --- tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs b/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs index c590a763b2..28fb19e119 100644 --- a/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs +++ b/tests/Avalonia.Base.UnitTests/AssetLoaderTests.cs @@ -7,7 +7,7 @@ using Xunit; namespace Avalonia.Base.UnitTests; -public class AssetLoaderTests +public class AssetLoaderTests : IDisposable { public class MockAssembly : Assembly {} @@ -15,7 +15,7 @@ public class AssetLoaderTests private const string AssemblyNameWithNonAscii = "Какое-то-название"; - static AssetLoaderTests() + public AssetLoaderTests() { var resolver = Mock.Of(); @@ -39,7 +39,7 @@ public class AssetLoaderTests Assert.Equal(AssemblyNameWithWhitespace, assemblyActual?.FullName); } - [Fact(Skip = "RegisterResUriParsers breaks this test. Investigate.")] + [Fact(Skip = "RegisterResUriParsers breaks this test. See https://github.com/AvaloniaUI/Avalonia/issues/2555.")] public void AssemblyName_With_Non_ASCII_Should_Load_Avares() { var uri = new Uri($"avares://{AssemblyNameWithNonAscii}/Assets/something"); @@ -60,4 +60,9 @@ public class AssetLoaderTests Mock.Get(descriptor).Setup(x => x.Assembly).Returns(assembly); return descriptor; } + + public void Dispose() + { + AssetLoader.SetAssemblyDescriptorResolver(new AssemblyDescriptorResolver()); + } } From 2fb68a43a663b6aa4f37bbb9570932e76f104eac Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 04:53:38 -0400 Subject: [PATCH 168/332] Do not run Avalonia.PlatformSupport.UnitTests tests --- nukebuild/Build.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index f0f677b844..9fcb9d6b7f 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -221,7 +221,6 @@ partial class Build : NukeBuild RunCoreTest("Avalonia.Markup.Xaml.UnitTests"); RunCoreTest("Avalonia.Skia.UnitTests"); RunCoreTest("Avalonia.ReactiveUI.UnitTests"); - RunCoreTest("Avalonia.PlatformSupport.UnitTests"); }); Target RunRenderTests => _ => _ From 25efb6bec6a1b2a72ecc245346279e4583f7f421 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 25 May 2022 11:07:09 +0200 Subject: [PATCH 169/332] Fix pooled list bug. Ported from upstream: https://github.com/jtmueller/Collections.Pooled/pull/44 --- src/Avalonia.Base/Collections/Pooled/PooledList.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Collections/Pooled/PooledList.cs b/src/Avalonia.Base/Collections/Pooled/PooledList.cs index 200a52fb0d..803b8d60dc 100644 --- a/src/Avalonia.Base/Collections/Pooled/PooledList.cs +++ b/src/Avalonia.Base/Collections/Pooled/PooledList.cs @@ -587,7 +587,7 @@ namespace Avalonia.Collections.Pooled if (size > 0 && _clearOnFree) { // Clear the elements so that the gc can reclaim the references. - Array.Clear(_items, 0, _size); + Array.Clear(_items, 0, size); } } From 61ee2d18e9186cdd76fad89217581cb281880bc6 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 25 May 2022 11:11:49 +0200 Subject: [PATCH 170/332] Move assert of initial item state into method. So that we don't keep a reference to the item. --- tests/Avalonia.LeakTests/ControlTests.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 09d6764bae..3971cddecf 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -2,14 +2,12 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Runtime.Remoting.Contexts; using Avalonia.Controls; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Diagnostics; using Avalonia.Input; -using Avalonia.Layout; using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; @@ -710,11 +708,15 @@ namespace Avalonia.LeakTests window.Show(); window.LayoutManager.ExecuteInitialLayoutPass(); + void AssertInitialItemState() + { + var item0 = (ListBoxItem)lb.ItemContainerGenerator.Containers.First().ContainerControl; + var canvas0 = (Canvas)item0.Presenter.Child; + Assert.Equal("foo", canvas0.Tag); + } + Assert.Equal(10, lb.ItemContainerGenerator.Containers.Count()); - - var item0 = (ListBoxItem)lb.ItemContainerGenerator.Containers.First().ContainerControl; - var canvas0 = (Canvas)item0.Presenter.Child; - Assert.Equal("foo", canvas0.Tag); + AssertInitialItemState(); items.Clear(); window.LayoutManager.ExecuteLayoutPass(); From 5aa7de52e787787ba702e3c614b370b587af2e8c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 25 May 2022 12:17:17 +0200 Subject: [PATCH 171/332] Add cleanup step to leak tests. Because previously failures could occur depending on the order that leak tests were run in. --- tests/Avalonia.LeakTests/ControlTests.cs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 3971cddecf..bb520c16aa 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Reactive.Disposables; using Avalonia.Controls; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; @@ -12,6 +13,7 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Styling; +using Avalonia.Threading; using Avalonia.UnitTests; using Avalonia.VisualTree; using JetBrains.dotMemoryUnit; @@ -730,10 +732,23 @@ namespace Avalonia.LeakTests private IDisposable Start() { - return UnitTestApplication.Start(TestServices.StyledWindow.With( - focusManager: new FocusManager(), - keyboardDevice: () => new KeyboardDevice(), - inputManager: new InputManager())); + void Cleanup() + { + // KeyboardDevice holds a reference to the focused item. + KeyboardDevice.Instance.SetFocusedElement(null, NavigationMethod.Unspecified, KeyModifiers.None); + + // Empty the dispatcher queue. + Dispatcher.UIThread.RunJobs(); + } + + return new CompositeDisposable + { + Disposable.Create(Cleanup), + UnitTestApplication.Start(TestServices.StyledWindow.With( + focusManager: new FocusManager(), + keyboardDevice: () => new KeyboardDevice(), + inputManager: new InputManager())) + }; } From af237c6dd7067b7b5f43961f4fd64b635a2d20fc Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 25 May 2022 11:24:53 +0100 Subject: [PATCH 172/332] fix file dialog filter nullable annotation, and osx platform. --- samples/ControlCatalog/ControlCatalog.csproj | 3 ++- samples/ControlCatalog/Pages/DialogsPage.xaml.cs | 3 +-- src/Avalonia.Controls/SystemDialog.cs | 2 +- src/Avalonia.Native/SystemDialogs.cs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj index e5f07c90c3..bce924a3f2 100644 --- a/samples/ControlCatalog/ControlCatalog.csproj +++ b/samples/ControlCatalog/ControlCatalog.csproj @@ -1,7 +1,8 @@  netstandard2.0 - true + true + enable diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index 3cadc7243a..fd908a33b6 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -8,7 +8,6 @@ using Avalonia.Dialogs; using Avalonia.Layout; using Avalonia.Markup.Xaml; #pragma warning disable 4014 - namespace ControlCatalog.Pages { public class DialogsPage : UserControl @@ -22,7 +21,7 @@ namespace ControlCatalog.Pages string lastSelectedDirectory = null; - List GetFilters() + List? GetFilters() { if (this.FindControl("UseFilters").IsChecked != true) return null; diff --git a/src/Avalonia.Controls/SystemDialog.cs b/src/Avalonia.Controls/SystemDialog.cs index 4a9e745e30..093f10be51 100644 --- a/src/Avalonia.Controls/SystemDialog.cs +++ b/src/Avalonia.Controls/SystemDialog.cs @@ -15,7 +15,7 @@ namespace Avalonia.Controls /// Gets or sets a collection of filters which determine the types of files displayed in an /// or an . /// - public List Filters { get; set; } = new List(); + public List? Filters { get; set; } = new List(); /// /// Gets or sets initial file name that is displayed when the dialog is opened. diff --git a/src/Avalonia.Native/SystemDialogs.cs b/src/Avalonia.Native/SystemDialogs.cs index 4372829df1..d1d9c17ae3 100644 --- a/src/Avalonia.Native/SystemDialogs.cs +++ b/src/Avalonia.Native/SystemDialogs.cs @@ -30,7 +30,7 @@ namespace Avalonia.Native ofd.Title ?? "", ofd.Directory ?? "", ofd.InitialFileName ?? "", - string.Join(";", dialog.Filters.SelectMany(f => f.Extensions))); + string.Join(";", dialog.Filters?.SelectMany(f => f.Extensions) ?? Array.Empty())); } else { @@ -39,7 +39,7 @@ namespace Avalonia.Native dialog.Title ?? "", dialog.Directory ?? "", dialog.InitialFileName ?? "", - string.Join(";", dialog.Filters.SelectMany(f => f.Extensions))); + string.Join(";", dialog.Filters?.SelectMany(f => f.Extensions) ?? Array.Empty())); } return events.Task.ContinueWith(t => { events.Dispose(); return t.Result; }); From 5b66f260657190e09698254cf5059b3efa8ef6df Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 25 May 2022 11:38:50 +0100 Subject: [PATCH 173/332] Fix osx dialog style mask. makes the titlebar look like normal window. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index d43a8beee4..d96fe717ab 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -523,7 +523,7 @@ bool WindowImpl::IsDialog() { } NSWindowStyleMask WindowImpl::GetStyle() { - unsigned long s = this->_isDialog ? NSWindowStyleMaskUtilityWindow : NSWindowStyleMaskBorderless; + unsigned long s = this->_isDialog ? NSWindowStyleMaskDocModalWindow : NSWindowStyleMaskBorderless; switch (_decorations) { case SystemDecorationsNone: From 8aa64bf839d26e3971456157038a717fc1a0562f Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Wed, 25 May 2022 12:48:22 +0200 Subject: [PATCH 174/332] Update SkiaSharp. --- build/SkiaSharp.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props index a217a8272d..1ee4aa56a2 100644 --- a/build/SkiaSharp.props +++ b/build/SkiaSharp.props @@ -1,7 +1,7 @@  - - - + + + From ea9bd40dbd4c3f576f8e6a4efa14987983983fdd Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Wed, 25 May 2022 12:57:02 +0200 Subject: [PATCH 175/332] Update HarfBuzzSharp. --- build/HarfBuzzSharp.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props index e10de93530..85e7a1f34d 100644 --- a/build/HarfBuzzSharp.props +++ b/build/HarfBuzzSharp.props @@ -1,7 +1,7 @@  - - - + + + From 3a2e13be2265b5af07cdd533545b58ed2139f84c Mon Sep 17 00:00:00 2001 From: Benedikt Stebner Date: Wed, 25 May 2022 15:10:43 +0200 Subject: [PATCH 176/332] Add missing file --- .../Media/TextFormatting/TextRunBounds.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/Avalonia.Base/Media/TextFormatting/TextRunBounds.cs diff --git a/src/Avalonia.Base/Media/TextFormatting/TextRunBounds.cs b/src/Avalonia.Base/Media/TextFormatting/TextRunBounds.cs new file mode 100644 index 0000000000..91150160ed --- /dev/null +++ b/src/Avalonia.Base/Media/TextFormatting/TextRunBounds.cs @@ -0,0 +1,39 @@ +namespace Avalonia.Media.TextFormatting +{ + /// + /// The bounding rectangle of text run + /// + public sealed class TextRunBounds + { + /// + /// Constructing TextRunBounds + /// + internal TextRunBounds(Rect bounds, int firstCharacterIndex, int length, TextRun textRun) + { + Rectangle = bounds; + TextSourceCharacterIndex = firstCharacterIndex; + Length = length; + TextRun = textRun; + } + + /// + /// First text source character index of text run + /// + public int TextSourceCharacterIndex { get; } + + /// + /// character length of bounded text run + /// + public int Length { get; } + + /// + /// Text run bounding rectangle + /// + public Rect Rectangle { get; } + + /// + /// text run + /// + public TextRun TextRun { get; } + } +} From ba7fd6c9e8be304db7bdc22900f22ead2efcd799 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 25 May 2022 15:30:24 +0200 Subject: [PATCH 177/332] fix: some xml comment --- src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs | 1 + src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs | 2 +- src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs b/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs index 60c7a97ced..239f3aea08 100644 --- a/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs +++ b/src/Avalonia.Base/Animation/Transitions/Rotate3DTransition.cs @@ -14,6 +14,7 @@ public class Rotate3DTransition: PageSlide /// /// How long the rotation should take place /// The orientation of the rotation + /// Defines the depth of the 3D Effect. If null, depth will be calculated automatically from the width or height of the common parent of the visual being rotated public Rotate3DTransition(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal, double? depth = null) : base(duration, orientation) { diff --git a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs index 445f35aad2..45c67b9f48 100644 --- a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs +++ b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs @@ -55,7 +55,7 @@ namespace Avalonia /// /// /// This will usually be true, except in - /// + /// /// which receives notifications for all changes to property values, whether a value with a higher /// priority is present or not. When this property is false, the change that is being signaled /// has not resulted in a change to the property value on the object. diff --git a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs index a3095ad214..ae52e5f970 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs @@ -193,8 +193,11 @@ namespace Avalonia.Controls } } + /// Try get number of DataSource itmes. /// When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead. /// If "getAny" is true, method can use Linq.Any() method to speedup. + /// number of DataSource itmes. + /// true if able to retrieve number of DataSource itmes; otherwise, false. internal bool TryGetCount(bool allowSlow, bool getAny, out int count) { bool result; From 543fe599c691403514fb0000a1bcee2904556ebb Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 25 May 2022 16:32:56 +0200 Subject: [PATCH 178/332] fix: some nullable annotation warnings --- .../ViewModels/TransitioningContentControlPageViewModel.cs | 6 +++--- src/Avalonia.Controls/Avalonia.Controls.csproj | 3 --- src/Avalonia.Themes.Default/SimpleTheme.cs | 2 +- src/Avalonia.Themes.Fluent/FluentTheme.cs | 6 ++++-- .../CompiledBindings/PropertyInfoAccessorFactory.cs | 4 +--- .../MarkupExtensions/ResourceInclude.cs | 4 ++-- src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs | 2 +- src/Windows/Avalonia.Win32/TrayIconImpl.cs | 2 +- src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs | 2 +- tests/Avalonia.Benchmarks/TestBindingObservable.cs | 3 ++- .../Media/TextFormatting/TextFormatterTests.cs | 4 ++-- .../Media/TextFormatting/TextLineTests.cs | 4 ++-- 12 files changed, 20 insertions(+), 22 deletions(-) diff --git a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs index b092a07f4a..0e9522acab 100644 --- a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs @@ -45,12 +45,12 @@ namespace ControlCatalog.ViewModels public List Images { get; } = new List(); - private Bitmap? _SelectedImage; + private Bitmap _SelectedImage; /// /// Gets or Sets the selected image /// - public Bitmap? SelectedImage + public Bitmap SelectedImage { get { return _SelectedImage; } set { this.RaiseAndSetIfChanged(ref _SelectedImage, value); } @@ -293,7 +293,7 @@ namespace ControlCatalog.ViewModels /// /// Any one of the parameters may be null, but not both. /// - private static IVisual GetVisualParent(IVisual? from, IVisual? to) + private static IVisual GetVisualParent(IVisual from, IVisual to) { var p1 = (from ?? to)!.VisualParent; var p2 = (to ?? from)!.VisualParent; diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 4d239e69f4..3896dc2735 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -2,9 +2,6 @@ net6.0;netstandard2.0 - - - diff --git a/src/Avalonia.Themes.Default/SimpleTheme.cs b/src/Avalonia.Themes.Default/SimpleTheme.cs index 6929660757..664c95644f 100644 --- a/src/Avalonia.Themes.Default/SimpleTheme.cs +++ b/src/Avalonia.Themes.Default/SimpleTheme.cs @@ -44,7 +44,7 @@ namespace Avalonia.Themes.Default InitStyles(_baseUri); } - public event EventHandler OwnerChanged + public event EventHandler? OwnerChanged { add { diff --git a/src/Avalonia.Themes.Fluent/FluentTheme.cs b/src/Avalonia.Themes.Fluent/FluentTheme.cs index f6b47a5466..2a8e045c48 100644 --- a/src/Avalonia.Themes.Fluent/FluentTheme.cs +++ b/src/Avalonia.Themes.Fluent/FluentTheme.cs @@ -50,7 +50,9 @@ namespace Avalonia.Themes.Fluent /// The XAML service provider. public FluentTheme(IServiceProvider serviceProvider) { - _baseUri = ((IUriContext)serviceProvider.GetService(typeof(IUriContext))).BaseUri; + var ctx = serviceProvider.GetService(typeof(IUriContext)) as IUriContext + ?? throw new NullReferenceException("Unable retrive UriContext"); + _baseUri = ctx.BaseUri; InitStyles(_baseUri); } @@ -146,7 +148,7 @@ namespace Avalonia.Themes.Fluent IReadOnlyList IStyle.Children => _loaded?.Children ?? Array.Empty(); - public event EventHandler OwnerChanged + public event EventHandler? OwnerChanged { add { diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs index c21a2d4299..ef11b06369 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/PropertyInfoAccessorFactory.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; -using System.Text; using Avalonia.Data; using Avalonia.Data.Core; using Avalonia.Data.Core.Plugins; @@ -174,7 +172,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings WeakEvents.CollectionChanged.Unsubscribe(incc, this); } - public void OnEvent(object? sender, WeakEvent ev, NotifyCollectionChangedEventArgs args) + public void OnEvent(object sender, WeakEvent ev, NotifyCollectionChangedEventArgs args) { if (ShouldNotifyListeners(args)) { diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs index b6137aa89f..1091b3ec7e 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResourceInclude.cs @@ -42,7 +42,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions bool IResourceNode.HasResources => Loaded.HasResources; - public event EventHandler OwnerChanged + public event EventHandler? OwnerChanged { add => Loaded.OwnerChanged += value; remove => Loaded.OwnerChanged -= value; @@ -52,7 +52,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions { if (!_isLoading) { - return Loaded.TryGetResource(key, out value); + return Loaded.TryGetResource(key, out value); } value = null; diff --git a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs index fa4a27fc50..46b5bc0c40 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Styling/StyleInclude.cs @@ -64,7 +64,7 @@ namespace Avalonia.Markup.Xaml.Styling IReadOnlyList IStyle.Children => _loaded ?? Array.Empty(); - public event EventHandler OwnerChanged + public event EventHandler? OwnerChanged { add { diff --git a/src/Windows/Avalonia.Win32/TrayIconImpl.cs b/src/Windows/Avalonia.Win32/TrayIconImpl.cs index 1c2dd92219..4d537a16a4 100644 --- a/src/Windows/Avalonia.Win32/TrayIconImpl.cs +++ b/src/Windows/Avalonia.Win32/TrayIconImpl.cs @@ -195,7 +195,7 @@ namespace Avalonia.Win32 ShowActivated = true; } - private void TrayPopupRoot_Deactivated(object sender, EventArgs e) + private void TrayPopupRoot_Deactivated(object? sender, EventArgs e) { Close(); } diff --git a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs index 48f5f8f871..e864f32138 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.CustomCaptionProc.cs @@ -109,7 +109,7 @@ namespace Avalonia.Win32 if (_owner is Window window) { - var visual = window.Renderer.HitTestFirst(position, _owner as Window, x => + var visual = window.Renderer.HitTestFirst(position, _owner, x => { if (x is IInputElement ie && (!ie.IsHitTestVisible || !ie.IsVisible)) { diff --git a/tests/Avalonia.Benchmarks/TestBindingObservable.cs b/tests/Avalonia.Benchmarks/TestBindingObservable.cs index 0721ca9855..653959ba18 100644 --- a/tests/Avalonia.Benchmarks/TestBindingObservable.cs +++ b/tests/Avalonia.Benchmarks/TestBindingObservable.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using Avalonia.Data; namespace Avalonia.Benchmarks diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs index 9d40898608..d395f68f96 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextFormatterTests.cs @@ -602,7 +602,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting private class EndOfLineTextSource : ITextSource { - public TextRun? GetTextRun(int textSourceIndex) + public TextRun GetTextRun(int textSourceIndex) { return new TextEndOfLine(); } @@ -617,7 +617,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting _text = text; } - public TextRun? GetTextRun(int textSourceIndex) + public TextRun GetTextRun(int textSourceIndex) { if (textSourceIndex >= _text.Length + TextRun.DefaultTextSourceLength + _text.Length) { diff --git a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs index a47638d2ec..6321e8a336 100644 --- a/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs +++ b/tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs @@ -547,7 +547,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting { const string Text = "_A_A"; - public TextRun? GetTextRun(int textSourceIndex) + public TextRun GetTextRun(int textSourceIndex) { switch (textSourceIndex) { @@ -755,7 +755,7 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting _textRuns = textRuns; } - public TextRun? GetTextRun(int textSourceIndex) + public TextRun GetTextRun(int textSourceIndex) { var currentPosition = 0; From 19ebf5ad7d8356b9f88716223d1c37759fcb41d6 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Wed, 25 May 2022 23:44:47 -0400 Subject: [PATCH 179/332] Bring back blob disposal checks --- .../Platform/Internal/UnmanagedBlob.cs | 64 +++++++++++++++++-- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs index eacf79d4f4..ed0862c06c 100644 --- a/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs +++ b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs @@ -1,5 +1,8 @@ using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; namespace Avalonia.Platform.Internal; @@ -7,7 +10,30 @@ internal class UnmanagedBlob : IUnmanagedBlob { private IntPtr _address; private readonly object _lock = new object(); - +#if DEBUG + private static readonly List Backtraces = new List(); + private static Thread? GCThread; + private readonly string _backtrace; + private static readonly object _btlock = new object(); + + class GCThreadDetector + { + ~GCThreadDetector() + { + GCThread = Thread.CurrentThread; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Spawn() => new GCThreadDetector(); + + static UnmanagedBlob() + { + Spawn(); + GC.WaitForPendingFinalizers(); + } +#endif + public UnmanagedBlob(int size) { try @@ -23,14 +49,23 @@ internal class UnmanagedBlob : IUnmanagedBlob GC.SuppressFinalize(this); throw; } +#if DEBUG + _backtrace = Environment.StackTrace; + lock (_btlock) + Backtraces.Add(_backtrace); +#endif } - - private void DoDispose() + + void DoDispose() { lock (_lock) { if (!IsDisposed) { +#if DEBUG + lock (_btlock) + Backtraces.Remove(_backtrace); +#endif Marshal.FreeHGlobal(_address); GC.RemoveMemoryPressure(Size); IsDisposed = true; @@ -39,18 +74,35 @@ internal class UnmanagedBlob : IUnmanagedBlob } } } - + public void Dispose() { +#if DEBUG + if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId) + { + lock (_lock) + { + if (!IsDisposed) + { + Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: " + + Environment.StackTrace + + "\n\nBlob created by " + _backtrace); + } + } + } +#endif DoDispose(); GC.SuppressFinalize(this); } - + ~UnmanagedBlob() { +#if DEBUG + Console.Error.WriteLine("Undisposed native blob created by " + _backtrace); +#endif DoDispose(); } - + public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address; public int Size { get; private set; } public bool IsDisposed { get; private set; } From 62078d2cc3a2e1ffa7bbc77a910b5a8a43488e11 Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Thu, 26 May 2022 09:59:58 +0300 Subject: [PATCH 180/332] calculate mirrorTransform before renderTransform --- src/Avalonia.Base/Rendering/ImmediateRenderer.cs | 16 +++++++++------- .../Rendering/SceneGraph/SceneBuilder.cs | 16 +++++++++------- src/Avalonia.Base/VisualExtensions.cs | 13 +++++++------ src/Avalonia.Controls/Viewbox.cs | 3 +-- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs index 2c0298affa..54b2ce5a25 100644 --- a/src/Avalonia.Base/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Base/Rendering/ImmediateRenderer.cs @@ -277,18 +277,20 @@ namespace Avalonia.Rendering var m = Matrix.CreateTranslation(visual.Bounds.Position); var renderTransform = Matrix.Identity; + + // this should be calculated BEFORE renderTransform + if (visual.HasMirrorTransform) + { + var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0); + renderTransform *= mirrorMatrix; + } if (visual.RenderTransform != null) { var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height)); var offset = Matrix.CreateTranslation(origin); - renderTransform = (-offset) * visual.RenderTransform.Value * (offset); - } - - if (visual.HasMirrorTransform) - { - var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0); - renderTransform *= mirrorMatrix; + var finalTransform = (-offset) * visual.RenderTransform.Value * (offset); + renderTransform *= finalTransform; } m = renderTransform * m; diff --git a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs index 019c3e0e9b..5dc426ab06 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs @@ -188,19 +188,21 @@ namespace Avalonia.Rendering.SceneGraph var renderTransform = Matrix.Identity; - if (visual.RenderTransform != null) - { - var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height)); - var offset = Matrix.CreateTranslation(origin); - renderTransform = (-offset) * visual.RenderTransform.Value * (offset); - } - + // this should be calculated BEFORE renderTransform if (visual.HasMirrorTransform) { var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0); renderTransform *= mirrorMatrix; } + if (visual.RenderTransform != null) + { + var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height)); + var offset = Matrix.CreateTranslation(origin); + var finalTransform = (-offset) * visual.RenderTransform.Value * (offset); + renderTransform *= finalTransform; + } + m = renderTransform * m; using (contextImpl.BeginUpdate(node)) diff --git a/src/Avalonia.Base/VisualExtensions.cs b/src/Avalonia.Base/VisualExtensions.cs index 3a3c2693d0..7a5bbb105c 100644 --- a/src/Avalonia.Base/VisualExtensions.cs +++ b/src/Avalonia.Base/VisualExtensions.cs @@ -101,6 +101,13 @@ namespace Avalonia while (v != ancestor) { + // this should be calculated BEFORE renderTransform + if (v.HasMirrorTransform) + { + var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, v.Bounds.Width, 0); + result *= mirrorMatrix; + } + if (v.RenderTransform?.Value != null) { var origin = v.RenderTransformOrigin.ToPixels(v.Bounds.Size); @@ -110,12 +117,6 @@ namespace Avalonia result *= renderTransform; } - if (v.HasMirrorTransform) - { - var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, v.Bounds.Width, 0); - result *= mirrorMatrix; - } - var topLeft = v.Bounds.TopLeft; if (topLeft != default) diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs index 01667c5136..01a41a0157 100644 --- a/src/Avalonia.Controls/Viewbox.cs +++ b/src/Avalonia.Controls/Viewbox.cs @@ -1,7 +1,6 @@ using Avalonia.Media; using Avalonia.Media.Immutable; using Avalonia.Metadata; -using Avalonia.Layout; namespace Avalonia.Controls { @@ -151,7 +150,7 @@ namespace Avalonia.Controls /// /// A simple container control which hosts its child as a visual but not logical child. /// - private class ViewboxContainer : Layoutable + private class ViewboxContainer : Control { private IControl? _child; From f1a2716858fc90067ffe6fa0651ee2a04f43c36a Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 26 May 2022 03:36:49 -0400 Subject: [PATCH 181/332] Inherit DataType from template without hardcoding on specific DataTemplate implementation --- .../Metadata/TemplateDataTypeAttribute.cs | 9 ++ ...valoniaXamlIlDataContextTypeTransformer.cs | 5 +- .../AvaloniaXamlIlWellKnownTypes.cs | 2 + .../Templates/DataTemplate.cs | 1 + .../Templates/TreeDataTemplate.cs | 1 + .../CompiledBindingExtensionTests.cs | 122 +++++++++++++++++- 6 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs diff --git a/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs b/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs new file mode 100644 index 0000000000..29e8cf4a06 --- /dev/null +++ b/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Avalonia.Metadata; + +[AttributeUsage(AttributeTargets.Property)] +public class TemplateDataTypeAttribute : Attribute +{ + +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs index cf691db860..75859a0a18 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs @@ -49,6 +49,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } else if (child is XamlPropertyAssignmentNode pa) { + var templateDataTypeAttribute = context.GetAvaloniaTypes().TemplateDataTypeAttribute; + if (pa.Property.Name == "DataContext" && pa.Property.DeclaringType.Equals(context.GetAvaloniaTypes().StyledElement) && pa.Values[0] is XamlMarkupExtensionNode ext @@ -56,8 +58,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { inferredDataContextTypeNode = ParseDataContext(context, on, obj); } - else if(context.GetAvaloniaTypes().DataTemplate.IsAssignableFrom(on.Type.GetClrType()) - && pa.Property.Name == "DataType" + else if(pa.Property.CustomAttributes.Any(a => a.Type == templateDataTypeAttribute) && pa.Values[0] is XamlTypeExtensionNode dataTypeNode) { inferredDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on, dataTypeNode.Value.GetClrType()); diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index 5da40035d2..da28891968 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -26,6 +26,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlType Transitions { get; } public IXamlType AssignBindingAttribute { get; } public IXamlType DependsOnAttribute { get; } + public IXamlType TemplateDataTypeAttribute { get; } public IXamlType UnsetValueType { get; } public IXamlType StyledElement { get; } public IXamlType IStyledElement { get; } @@ -112,6 +113,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Transitions = cfg.TypeSystem.GetType("Avalonia.Animation.Transitions"); AssignBindingAttribute = cfg.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute"); DependsOnAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.DependsOnAttribute"); + TemplateDataTypeAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.TemplateDataTypeAttribute"); AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, IAvaloniaObject, AvaloniaProperty, IBinding, cfg.WellKnownTypes.Object); diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs index b7db1a3fbb..1dd3cddf9a 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs @@ -7,6 +7,7 @@ namespace Avalonia.Markup.Xaml.Templates { public class DataTemplate : IRecyclingDataTemplate { + [TemplateDataType] public Type DataType { get; set; } [Content] diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs index 7b065c7f47..b07e501fde 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs @@ -11,6 +11,7 @@ namespace Avalonia.Markup.Xaml.Templates { public class TreeDataTemplate : ITreeDataTemplate { + [TemplateDataType] public Type DataType { get; set; } [Content] diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index c1c2284372..fe3df7d189 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -8,11 +8,14 @@ using System.Text; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Presenters; +using Avalonia.Controls.Templates; using Avalonia.Data.Converters; using Avalonia.Data.Core; using Avalonia.Input; using Avalonia.Markup.Data; +using Avalonia.Markup.Xaml.Templates; using Avalonia.Media; +using Avalonia.Metadata; using Avalonia.UnitTests; using XamlX; using Xunit; @@ -455,7 +458,106 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions ThrowsXamlTransformException(() => AvaloniaRuntimeXamlLoader.Load(xaml)); } } + + [Fact] + public void IgnoresDataTemplateTypeFromDataTypePropertyIfXDataTypeDefined() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var target = window.FindControl("target"); + + var dataContext = new TestDataContext(); + + dataContext.StringProperty = "Initial Value"; + + window.DataContext = dataContext; + window.ApplyTemplate(); + target.ApplyTemplate(); + ((ContentPresenter)target.Presenter).UpdateChild(); + + Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child).Text); + } + } + + [Fact] + public void InfersCustomDataTemplateBasedOnAttribute() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var target = window.FindControl("target"); + + var dataContext = new TestDataContext(); + + dataContext.StringProperty = "Initial Value"; + + window.DataContext = dataContext; + + window.ApplyTemplate(); + target.ApplyTemplate(); + ((ContentPresenter)target.Presenter).UpdateChild(); + + Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child).Text); + } + } + + [Fact] + public void InfersCustomDataTemplateBasedOnAttributeFromBaseClass() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var target = window.FindControl("target"); + + var dataContext = new TestDataContext(); + + dataContext.StringProperty = "Initial Value"; + + window.DataContext = dataContext; + + window.ApplyTemplate(); + target.ApplyTemplate(); + ((ContentPresenter)target.Presenter).UpdateChild(); + + Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child).Text); + } + } + [Fact] public void ResolvesElementNameBinding() { @@ -1324,7 +1426,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions public string StringProperty { get; set; } } - public class TestDataContext : IHasPropertyDerived + public class TestDataContextBaseClass {} + + public class TestDataContext : TestDataContextBaseClass, IHasPropertyDerived { public string StringProperty { get; set; } @@ -1413,4 +1517,20 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions return ReferenceEquals(null, parameter) == false; } } + + public class CustomDataTemplate : IDataTemplate + { + [TemplateDataType] + public Type FancyDataType { get; set; } + + [Content] + [TemplateContent] + public object Content { get; set; } + + public bool Match(object data) => FancyDataType.IsInstanceOfType(data); + + public IControl Build(object data) => TemplateContent.Load(Content)?.Control; + } + + public class CustomDataTemplateInherit : CustomDataTemplate { } } From 9126edca7003c698f4f8a60e0ee10cd5c54605ec Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 26 May 2022 03:40:05 -0400 Subject: [PATCH 182/332] Add documentation --- src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs b/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs index 29e8cf4a06..51899bd03c 100644 --- a/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs +++ b/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs @@ -2,6 +2,9 @@ namespace Avalonia.Metadata; +/// +/// Defines the property that contains type of the data passed to the implementation. +/// [AttributeUsage(AttributeTargets.Property)] public class TemplateDataTypeAttribute : Attribute { From b567fcebf58a3afc8b08f31996110f31fdb139e6 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 26 May 2022 04:15:29 -0400 Subject: [PATCH 183/332] Rename TemplateDataTypeAttribute to DataTypeAttribute --- src/Avalonia.Base/Metadata/DataTypeAttribute.cs | 15 +++++++++++++++ .../Metadata/TemplateDataTypeAttribute.cs | 12 ------------ .../AvaloniaXamlIlDataContextTypeTransformer.cs | 2 +- .../Transformers/AvaloniaXamlIlWellKnownTypes.cs | 4 ++-- .../Templates/DataTemplate.cs | 2 +- .../Templates/TreeDataTemplate.cs | 2 +- .../CompiledBindingExtensionTests.cs | 2 +- 7 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 src/Avalonia.Base/Metadata/DataTypeAttribute.cs delete mode 100644 src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs diff --git a/src/Avalonia.Base/Metadata/DataTypeAttribute.cs b/src/Avalonia.Base/Metadata/DataTypeAttribute.cs new file mode 100644 index 0000000000..ac46a0d30a --- /dev/null +++ b/src/Avalonia.Base/Metadata/DataTypeAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Avalonia.Metadata; + +/// +/// Defines the property that contains type that should be used as a type information for compiled bindings. +/// +/// +/// Used on DataTemplate.DataType property so it can be inherited in compiled bindings inside of the template. +/// +[AttributeUsage(AttributeTargets.Property)] +public class DataTypeAttribute : Attribute +{ + +} diff --git a/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs b/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs deleted file mode 100644 index 51899bd03c..0000000000 --- a/src/Avalonia.Base/Metadata/TemplateDataTypeAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Avalonia.Metadata; - -/// -/// Defines the property that contains type of the data passed to the implementation. -/// -[AttributeUsage(AttributeTargets.Property)] -public class TemplateDataTypeAttribute : Attribute -{ - -} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs index 75859a0a18..d4dfcf9c4b 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs @@ -49,7 +49,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers } else if (child is XamlPropertyAssignmentNode pa) { - var templateDataTypeAttribute = context.GetAvaloniaTypes().TemplateDataTypeAttribute; + var templateDataTypeAttribute = context.GetAvaloniaTypes().DataTypeAttribute; if (pa.Property.Name == "DataContext" && pa.Property.DeclaringType.Equals(context.GetAvaloniaTypes().StyledElement) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs index da28891968..28787d9b84 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs @@ -26,7 +26,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers public IXamlType Transitions { get; } public IXamlType AssignBindingAttribute { get; } public IXamlType DependsOnAttribute { get; } - public IXamlType TemplateDataTypeAttribute { get; } + public IXamlType DataTypeAttribute { get; } public IXamlType UnsetValueType { get; } public IXamlType StyledElement { get; } public IXamlType IStyledElement { get; } @@ -113,7 +113,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers Transitions = cfg.TypeSystem.GetType("Avalonia.Animation.Transitions"); AssignBindingAttribute = cfg.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute"); DependsOnAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.DependsOnAttribute"); - TemplateDataTypeAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.TemplateDataTypeAttribute"); + DataTypeAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.DataTypeAttribute"); AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, IAvaloniaObject, AvaloniaProperty, IBinding, cfg.WellKnownTypes.Object); diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs index 1dd3cddf9a..d2b24979cc 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs @@ -7,7 +7,7 @@ namespace Avalonia.Markup.Xaml.Templates { public class DataTemplate : IRecyclingDataTemplate { - [TemplateDataType] + [DataType] public Type DataType { get; set; } [Content] diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs index b07e501fde..10061c3d48 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs @@ -11,7 +11,7 @@ namespace Avalonia.Markup.Xaml.Templates { public class TreeDataTemplate : ITreeDataTemplate { - [TemplateDataType] + [DataType] public Type DataType { get; set; } [Content] diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index fe3df7d189..7e721fd7b2 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -1520,7 +1520,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions public class CustomDataTemplate : IDataTemplate { - [TemplateDataType] + [DataType] public Type FancyDataType { get; set; } [Content] From 60d0e2f1c383159288f6fbb243bfc8d078f129cb Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 25 May 2022 17:30:25 +0200 Subject: [PATCH 184/332] fix: Consolidate JetBrains.DotMemoryUnit --- build/JetBrains.dotMemoryUnit.props | 2 +- nukebuild/_build.csproj | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/build/JetBrains.dotMemoryUnit.props b/build/JetBrains.dotMemoryUnit.props index eb4e2b6f15..5d74d474cf 100644 --- a/build/JetBrains.dotMemoryUnit.props +++ b/build/JetBrains.dotMemoryUnit.props @@ -1,5 +1,5 @@ - + diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 52b60b7d0f..b2c58e2292 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -8,11 +8,10 @@ False CS0649;CS0169 - + - From d3b09a7d741bd33b7c615e54d4792c02aa6a8d20 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 25 May 2022 17:42:03 +0200 Subject: [PATCH 185/332] fix: Update SourceLink --- build/SourceLink.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/SourceLink.props b/build/SourceLink.props index 9f05848881..dd7ecc8d2a 100644 --- a/build/SourceLink.props +++ b/build/SourceLink.props @@ -19,7 +19,7 @@ - + From 1d8e3cabe7476c1c82e5b3ba60735a975bdb68cb Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 26 May 2022 11:53:38 +0200 Subject: [PATCH 186/332] fix: update Microsoft.NETFramework.ReferenceAssemblies --- build/NetFX.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/NetFX.props b/build/NetFX.props index 8ffc9ec561..27bac831b8 100644 --- a/build/NetFX.props +++ b/build/NetFX.props @@ -1,7 +1,7 @@  - + From a25ce2fb08c0bcfe4eb05c04418f7df73770a2cc Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 26 May 2022 12:43:52 +0200 Subject: [PATCH 187/332] feat: move InternalsVisibleTo in csproj --- Directory.Build.props | 1 + build/AvaloniaPrublicKey.props | 5 +++++ src/Avalonia.Base/Avalonia.Base.csproj | 17 +++++++++++++++++ src/Avalonia.Base/Properties/AssemblyInfo.cs | 14 -------------- .../Avalonia.Controls.ColorPicker.csproj | 5 +++++ .../Properties/AssemblyInfo.cs | 3 --- .../Avalonia.Controls.DataGrid.csproj | 5 +++++ .../Properties/AssemblyInfo.cs | 4 ---- src/Avalonia.Controls/Avalonia.Controls.csproj | 6 ++++++ .../Properties/AssemblyInfo.cs | 5 ----- .../Avalonia.FreeDesktop.csproj | 4 +++- src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs | 4 ---- .../Avalonia.PlatformSupport.csproj | 2 +- .../Avalonia.Markup.Xaml.csproj | 4 ++++ .../Properties/AssemblyInfo.cs | 3 --- .../Avalonia.Markup/Avalonia.Markup.csproj | 4 ++++ .../Avalonia.Markup/Properties/AssemblyInfo.cs | 3 --- src/Skia/Avalonia.Skia/Avalonia.Skia.csproj | 9 +++++++++ .../Avalonia.Skia/Properties/AssemblyInfo.cs | 5 ----- .../Avalonia.Direct2D1.csproj | 10 ++++++++++ .../Properties/AssemblyInfo.cs | 4 ---- 21 files changed, 70 insertions(+), 47 deletions(-) create mode 100644 build/AvaloniaPrublicKey.props delete mode 100644 src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs delete mode 100644 src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs diff --git a/Directory.Build.props b/Directory.Build.props index 97781b7517..adfb985d2b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,4 +1,5 @@ + $(MSBuildThisFileDirectory)build-intermediate/nuget $(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netcoreapp2.0\Avalonia.Designer.HostApp.dll diff --git a/build/AvaloniaPrublicKey.props b/build/AvaloniaPrublicKey.props new file mode 100644 index 0000000000..89215635c0 --- /dev/null +++ b/build/AvaloniaPrublicKey.props @@ -0,0 +1,5 @@ + + + 0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87 + + diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 8e4755b4b7..5bd733a17e 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -17,4 +17,21 @@ + + + + + + + + + + + + + + + + + diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs index 2c40c768f5..3753588fce 100644 --- a/src/Avalonia.Base/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs @@ -17,18 +17,4 @@ using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Transformation")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")] -[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls.ColorPicker, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.PlatformSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Web.Blazor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj b/src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj index 0952c899d4..e0790795c5 100644 --- a/src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj +++ b/src/Avalonia.Controls.ColorPicker/Avalonia.Controls.ColorPicker.csproj @@ -22,4 +22,9 @@ + + + + + diff --git a/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs index 0135541349..64769303d6 100644 --- a/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs @@ -1,8 +1,5 @@ -using System.Runtime.CompilerServices; using Avalonia.Metadata; -[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] - [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")] diff --git a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj index 410cac72fc..6369961f0f 100644 --- a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj +++ b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj @@ -18,4 +18,9 @@ + + + + + diff --git a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs index d61c05ab6e..64769303d6 100644 --- a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs @@ -1,9 +1,5 @@ -using System.Runtime.CompilerServices; using Avalonia.Metadata; -[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] - [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")] diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 4d239e69f4..00f094f508 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -14,4 +14,10 @@ + + + + + + diff --git a/src/Avalonia.Controls/Properties/AssemblyInfo.cs b/src/Avalonia.Controls/Properties/AssemblyInfo.cs index 25330614cf..0f3da91107 100644 --- a/src/Avalonia.Controls/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls/Properties/AssemblyInfo.cs @@ -1,10 +1,5 @@ -using System.Runtime.CompilerServices; using Avalonia.Metadata; -[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] - [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Automation")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] diff --git a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj index bcb63783a4..e9d6394aa5 100644 --- a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj +++ b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj @@ -8,5 +8,7 @@ - + + + diff --git a/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs b/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs index a7cc4f4cc2..4a55212de3 100644 --- a/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs +++ b/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs @@ -12,10 +12,6 @@ using Tmds.DBus; [assembly: InternalsVisibleTo(Connection.DynamicAssemblyName)] -[assembly: - InternalsVisibleTo( - "Avalonia.X11, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] - namespace Avalonia.FreeDesktop { internal class DBusTrayIconImpl : ITrayIconImpl diff --git a/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj b/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj index 5336f1e630..98839b7af3 100644 --- a/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj +++ b/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj index 622ec416e8..30d321426f 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj +++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj @@ -63,4 +63,8 @@ + + + + diff --git a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs index cee4d90917..7e5b3159d4 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs @@ -1,9 +1,6 @@ using Avalonia.Metadata; -using System.Runtime.CompilerServices; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Styling")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Templates")] -[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] - diff --git a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj index f7f1a111ba..6711c3dd3d 100644 --- a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj +++ b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj @@ -17,4 +17,8 @@ + + + + diff --git a/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs index 46e2925f92..36ca2784da 100644 --- a/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs +++ b/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs @@ -1,8 +1,5 @@ using Avalonia.Metadata; -using System.Runtime.CompilerServices; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Data")] -[assembly: InternalsVisibleTo("Avalonia.Markup.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] - diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj index 26c0fb756e..413c2ba4d4 100644 --- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj +++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj @@ -18,4 +18,13 @@ + + + + + + + + + diff --git a/src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs b/src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs deleted file mode 100644 index a7e556ee84..0000000000 --- a/src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] - diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj index bd1f05b30f..03b3ebec0d 100644 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj @@ -19,4 +19,14 @@ + + + + + + + + + + diff --git a/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs b/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs deleted file mode 100644 index 89fd6c2dd8..0000000000 --- a/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] -[assembly: InternalsVisibleTo("Avalonia.Direct2D1.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] From ea4d92ddafcb74e58357729383376e7b5037e950 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Thu, 26 May 2022 23:12:21 +0200 Subject: [PATCH 188/332] Clear IMM state when window is closed. --- .../Avalonia.Win32/Input/Imm32InputMethod.cs | 18 ++++++++++++++++++ .../Avalonia.Win32/WindowImpl.AppWndProc.cs | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs index 9ff6f76ac4..3adefd965f 100644 --- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs +++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs @@ -37,6 +37,24 @@ namespace Avalonia.Win32.Input IsComposing = false; } + public void ClearLanguageAndWindow() + { + if (HWND != IntPtr.Zero && _defaultImc != IntPtr.Zero) + { + ImmReleaseContext(HWND, _defaultImc); + } + + _defaultImc = IntPtr.Zero; + HWND = IntPtr.Zero; + _parent = null; + _active = false; + _langId = 0; + _showCompositionWindow = false; + _showCandidateList = false; + + IsComposing = false; + } + //Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers - //every Dispatcher should have their own InputMethod. public static Imm32InputMethod Current { get; } = new Imm32InputMethod(); diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs index 64ab15bc30..cae8834550 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs @@ -82,6 +82,12 @@ namespace Avalonia.Win32 case WindowsMessage.WM_DESTROY: { UiaCoreProviderApi.UiaReturnRawElementProvider(_hwnd, IntPtr.Zero, IntPtr.Zero, null); + + // We need to release IMM context and state to avoid leaks. + if (Imm32InputMethod.Current.HWND == _hwnd) + { + Imm32InputMethod.Current.ClearLanguageAndWindow(); + } //Window doesn't exist anymore _hwnd = IntPtr.Zero; From 51789f56a629ead42483d3cacfedca229374ac9d Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 27 May 2022 01:20:53 -0400 Subject: [PATCH 189/332] Bring back mmap for linux as discussed --- .../Platform/Internal/UnmanagedBlob.cs | 50 ++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs index ed0862c06c..a56d9ffd1c 100644 --- a/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs +++ b/src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs @@ -40,7 +40,7 @@ internal class UnmanagedBlob : IUnmanagedBlob { if (size <= 0) throw new ArgumentException("Positive number required", nameof(size)); - _address = Marshal.AllocHGlobal(size); + _address = Alloc(size); GC.AddMemoryPressure(size); Size = size; } @@ -66,7 +66,7 @@ internal class UnmanagedBlob : IUnmanagedBlob lock (_btlock) Backtraces.Remove(_backtrace); #endif - Marshal.FreeHGlobal(_address); + Free(_address, Size); GC.RemoveMemoryPressure(Size); IsDisposed = true; _address = IntPtr.Zero; @@ -106,4 +106,50 @@ internal class UnmanagedBlob : IUnmanagedBlob public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address; public int Size { get; private set; } public bool IsDisposed { get; private set; } + + [DllImport("libc", SetLastError = true)] + private static extern IntPtr mmap(IntPtr addr, IntPtr length, int prot, int flags, int fd, IntPtr offset); + [DllImport("libc", SetLastError = true)] + private static extern int munmap(IntPtr addr, IntPtr length); + [DllImport("libc", SetLastError = true)] + private static extern long sysconf(int name); + + private bool? _useMmap; + private bool UseMmap + => _useMmap ?? ((_useMmap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)).Value); + + // Could be replaced with https://github.com/dotnet/runtime/issues/40892 when it will be available. + private IntPtr Alloc(int size) + { + if (!UseMmap) + { + return Marshal.AllocHGlobal(size); + } + else + { + var rv = mmap(IntPtr.Zero, new IntPtr(size), 3, 0x22, -1, IntPtr.Zero); + if (rv.ToInt64() == -1 || (ulong)rv.ToInt64() == 0xffffffff) + { + var errno = Marshal.GetLastWin32Error(); + throw new Exception("Unable to allocate memory: " + errno); + } + return rv; + } + } + + private void Free(IntPtr ptr, int len) + { + if (!UseMmap) + { + Marshal.FreeHGlobal(ptr); + } + else + { + if (munmap(ptr, new IntPtr(len)) == -1) + { + var errno = Marshal.GetLastWin32Error(); + throw new Exception("Unable to free memory: " + errno); + } + } + } } From 74d951235fad07ae507c4c870c4b69e55578a15e Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 09:09:58 +0200 Subject: [PATCH 190/332] fix: move DynamicProxyGenAssembly2 InternalsVisibleTo to csproj --- src/Avalonia.Base/Avalonia.Base.csproj | 1 + src/Avalonia.Base/Properties/AssemblyInfo.cs | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj index 5bd733a17e..16a91b10d6 100644 --- a/src/Avalonia.Base/Avalonia.Base.csproj +++ b/src/Avalonia.Base/Avalonia.Base.csproj @@ -33,5 +33,6 @@ + diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs index 3753588fce..9a62f94e35 100644 --- a/src/Avalonia.Base/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs @@ -17,4 +17,3 @@ using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Media.Transformation")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] From cc91c3002fea1c50893d2c7e2b5e36637ab1922a Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 09:12:56 +0200 Subject: [PATCH 191/332] fix: AvaloniaPublicKey.props file name typo --- Directory.Build.props | 2 +- build/{AvaloniaPrublicKey.props => AvaloniaPublicKey.props} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename build/{AvaloniaPrublicKey.props => AvaloniaPublicKey.props} (100%) diff --git a/Directory.Build.props b/Directory.Build.props index adfb985d2b..42daa2df7f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - + $(MSBuildThisFileDirectory)build-intermediate/nuget $(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netcoreapp2.0\Avalonia.Designer.HostApp.dll diff --git a/build/AvaloniaPrublicKey.props b/build/AvaloniaPublicKey.props similarity index 100% rename from build/AvaloniaPrublicKey.props rename to build/AvaloniaPublicKey.props From b2714472fea7c4f329b8f1c53ee28a9ee73356d0 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 09:28:52 +0200 Subject: [PATCH 192/332] fix: remove Microsoft.NETFramework.ReferenceAssemblies package --- build/NetFX.props | 1 - 1 file changed, 1 deletion(-) diff --git a/build/NetFX.props b/build/NetFX.props index 27bac831b8..14adb54035 100644 --- a/build/NetFX.props +++ b/build/NetFX.props @@ -1,7 +1,6 @@  - From bb796a1a7374d4652ab453df53b3499747bf46d2 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 09:44:42 +0200 Subject: [PATCH 193/332] fix(Carousel): PageTransition nullable --- src/Avalonia.Controls/Carousel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Controls/Carousel.cs b/src/Avalonia.Controls/Carousel.cs index 4cacf51fa1..28a4aa6436 100644 --- a/src/Avalonia.Controls/Carousel.cs +++ b/src/Avalonia.Controls/Carousel.cs @@ -20,8 +20,8 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly StyledProperty PageTransitionProperty = - AvaloniaProperty.Register(nameof(PageTransition)); + public static readonly StyledProperty PageTransitionProperty = + AvaloniaProperty.Register(nameof(PageTransition)); /// /// The default value of for @@ -54,7 +54,7 @@ namespace Avalonia.Controls /// /// Gets or sets the transition to use when moving between pages. /// - public IPageTransition PageTransition + public IPageTransition? PageTransition { get { return GetValue(PageTransitionProperty); } set { SetValue(PageTransitionProperty, value); } From 0223eb371616722e941025b2a761112c37392069 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 10:25:48 +0200 Subject: [PATCH 194/332] fix: Android nullable --- src/Android/Avalonia.Android/AvaloniaView.cs | 2 +- .../Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Android/Avalonia.Android/AvaloniaView.cs b/src/Android/Avalonia.Android/AvaloniaView.cs index 8177cf1f69..bbd3e0af9f 100644 --- a/src/Android/Avalonia.Android/AvaloniaView.cs +++ b/src/Android/Avalonia.Android/AvaloniaView.cs @@ -15,7 +15,7 @@ namespace Avalonia.Android private EmbeddableControlRoot _root; private readonly ViewImpl _view; - private IDisposable? _timerSubscription; + private IDisposable _timerSubscription; public AvaloniaView(Context context) : base(context) { diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs index 2b2a9dd2b4..4cae700c0a 100644 --- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs +++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs @@ -30,7 +30,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers return DispatchKeyEventInternal(e, out callBase); } - string? UnicodeTextInput(KeyEvent keyEvent) + string UnicodeTextInput(KeyEvent keyEvent) { return keyEvent.Action == KeyEventActions.Multiple && keyEvent.RepeatCount == 0 From d51fc3f5e2a6fbce189185b400cb188f1f4c2899 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 10:26:23 +0200 Subject: [PATCH 195/332] fix: X11 nullable --- src/Avalonia.X11/X11Window.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 066156a652..28455d5e31 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -1160,7 +1160,7 @@ namespace Avalonia.X11 } public IntPtr Handle => _owner._renderHandle; - public string? HandleDescriptor => "XID"; + public string HandleDescriptor => "XID"; } } } From 2fa549d62a44c52fb46aba55e8b9e7b4288861ec Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 10:26:54 +0200 Subject: [PATCH 196/332] fix: Win32 nullable --- src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs | 2 +- .../Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs index 1085aa1b42..1ec0ee9e2e 100644 --- a/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs +++ b/src/Windows/Avalonia.Win32/Automation/RootAutomationNode.cs @@ -42,7 +42,7 @@ namespace Avalonia.Win32.Automation return GetOrCreate(focus); } - public void FocusChanged(object sender, EventArgs e) + public void FocusChanged(object? sender, EventArgs e) { RaiseFocusChanged(GetOrCreate(Peer.GetFocus())); } diff --git a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs index 1de0cf0f9b..8d6677315c 100644 --- a/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs +++ b/src/Windows/Avalonia.Win32/Interop/Automation/ISelectionItemProvider.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Runtime.InteropServices; From fb34e56b0770a796c941a9bfd9e13e2a2e3afe59 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 27 May 2022 11:42:43 +0200 Subject: [PATCH 197/332] fix(CarouselPresenter ): PageTransition --- src/Avalonia.Controls/Presenters/CarouselPresenter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs index 3d1e7eb5a8..87bbfce2a2 100644 --- a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs +++ b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs @@ -31,7 +31,7 @@ namespace Avalonia.Controls.Presenters /// /// Defines the property. /// - public static readonly StyledProperty PageTransitionProperty = + public static readonly StyledProperty PageTransitionProperty = Carousel.PageTransitionProperty.AddOwner(); private int _selectedIndex = -1; @@ -85,7 +85,7 @@ namespace Avalonia.Controls.Presenters /// /// Gets or sets a transition to use when switching pages. /// - public IPageTransition PageTransition + public IPageTransition? PageTransition { get { return GetValue(PageTransitionProperty); } set { SetValue(PageTransitionProperty, value); } From b605c5c4527013f568d37b85975103059933b9b3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 27 May 2022 10:51:37 +0100 Subject: [PATCH 198/332] [OSX] fix border shadow invalidation. --- native/Avalonia.Native/src/OSX/WindowBaseImpl.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 022769bad0..6dc59ae4d8 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -296,6 +296,7 @@ HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reaso if(Window != nullptr) { [Window setContentSize:lastSize]; + [Window invalidateShadow]; } } @finally { @@ -583,6 +584,8 @@ void WindowBaseImpl::InitialiseNSWindow() { [Window setContentMaxSize:lastMaxSize]; [Window setOpaque:false]; + + [Window invalidateShadow]; if (lastMenu != nullptr) { [GetWindowProtocol() applyMenu:lastMenu]; From 84ea185f0faf0d39e6d8db8be784913d9fa4dfda Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 27 May 2022 16:10:16 +0100 Subject: [PATCH 199/332] [OSX] dialogs stay ontop of main window when another app is displayed. --- native/Avalonia.Native/src/OSX/AvnView.mm | 4 ++-- native/Avalonia.Native/src/OSX/AvnWindow.mm | 2 ++ native/Avalonia.Native/src/OSX/WindowBaseImpl.mm | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/AvnView.mm b/native/Avalonia.Native/src/OSX/AvnView.mm index 02526afbcb..5436ad22f3 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.mm +++ b/native/Avalonia.Native/src/OSX/AvnView.mm @@ -222,7 +222,7 @@ - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type { - bool triggerInputWhenDisabled = type != Move; + bool triggerInputWhenDisabled = type != Move && type != LeaveWindow; if([self ignoreUserInput: triggerInputWhenDisabled]) { @@ -709,4 +709,4 @@ return [[self accessibilityChild] accessibilityFocusedUIElement]; } -@end \ No newline at end of file +@end diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index f51c693777..590dc5e7ac 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -378,6 +378,8 @@ _parent->BaseEvents->Deactivated(); [self showAppMenuOnly]; + + [self invalidateShadow]; [super resignKeyWindow]; } diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 6dc59ae4d8..121679b942 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -558,6 +558,8 @@ void WindowBaseImpl::CreateNSWindow(bool isDialog) { CleanNSWindow(); Window = [[AvnPanel alloc] initWithParent:this contentRect:NSRect{0, 0, lastSize} styleMask:GetStyle()]; + + [Window setHidesOnDeactivate:false]; } } else { if (![Window isKindOfClass:[AvnWindow class]]) { From 960ea2260cebf30d7f79d4d6e85cb96afdd2271c Mon Sep 17 00:00:00 2001 From: affederaffe <68356204+affederaffe@users.noreply.github.com> Date: Sat, 28 May 2022 16:45:55 +0200 Subject: [PATCH 200/332] Add xdg-desktop-portal file chooser --- src/Avalonia.FreeDesktop/DBusFileChooser.cs | 32 ++++++++ src/Avalonia.FreeDesktop/DBusRequest.cs | 16 ++++ src/Avalonia.FreeDesktop/DBusSystemDialog.cs | 80 ++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 src/Avalonia.FreeDesktop/DBusFileChooser.cs create mode 100644 src/Avalonia.FreeDesktop/DBusRequest.cs create mode 100644 src/Avalonia.FreeDesktop/DBusSystemDialog.cs diff --git a/src/Avalonia.FreeDesktop/DBusFileChooser.cs b/src/Avalonia.FreeDesktop/DBusFileChooser.cs new file mode 100644 index 0000000000..996f5dfe86 --- /dev/null +++ b/src/Avalonia.FreeDesktop/DBusFileChooser.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Tmds.DBus; + +[assembly: InternalsVisibleTo(Connection.DynamicAssemblyName)] +namespace Avalonia.FreeDesktop +{ + [DBusInterface("org.freedesktop.portal.FileChooser")] + public interface IFileChooser : IDBusObject + { + Task OpenFileAsync(string ParentWindow, string Title, IDictionary Options); + Task SaveFileAsync(string ParentWindow, string Title, IDictionary Options); + Task SaveFilesAsync(string ParentWindow, string Title, IDictionary Options); + Task GetAsync(string prop); + Task GetAllAsync(); + Task SetAsync(string prop, object val); + Task WatchPropertiesAsync(Action handler); + } + + [Dictionary] + public class FileChooserProperties + { + public uint Version { get; set; } + } + + public static class FileChooserExtensions + { + public static Task GetVersionAsync(this IFileChooser o) => o.GetAsync("version"); + } +} diff --git a/src/Avalonia.FreeDesktop/DBusRequest.cs b/src/Avalonia.FreeDesktop/DBusRequest.cs new file mode 100644 index 0000000000..940a476916 --- /dev/null +++ b/src/Avalonia.FreeDesktop/DBusRequest.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Tmds.DBus; + +[assembly: InternalsVisibleTo(Connection.DynamicAssemblyName)] +namespace Avalonia.FreeDesktop +{ + [DBusInterface("org.freedesktop.portal.Request")] + internal interface IRequest : IDBusObject + { + Task CloseAsync(); + Task WatchResponseAsync(Action<(uint response, IDictionary results)> handler, Action onError = null); + } +} diff --git a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs new file mode 100644 index 0000000000..d76e22b113 --- /dev/null +++ b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Controls.Platform; +using Tmds.DBus; + +namespace Avalonia.FreeDesktop +{ + public class DBusSystemDialog : ISystemDialogImpl + { + private readonly IFileChooser _fileChooser; + + public DBusSystemDialog() + { + _fileChooser = DBusHelper.Connection.CreateProxy("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); + } + + public async Task ShowFileDialogAsync(FileDialog dialog, Window parent) + { + var parentWindow = $"x11:{parent.PlatformImpl!.Handle.Handle.ToString("X")}"; + ObjectPath objectPath; + var options = new Dictionary(); + if (dialog.Filters is not null) + options.Add("filters", ParseFilters(dialog)); + + switch (dialog) + { + case OpenFileDialog openFileDialog: + options.Add("multiple", openFileDialog.AllowMultiple); + objectPath = await _fileChooser.OpenFileAsync(parentWindow, openFileDialog.Title ?? string.Empty, options); + break; + case SaveFileDialog saveFileDialog: + if (saveFileDialog.InitialFileName is not null) + options.Add("current_name", saveFileDialog.InitialFileName); + if (saveFileDialog.Directory is not null) + options.Add("current_folder", Encoding.UTF8.GetBytes(saveFileDialog.Directory)); + objectPath = await _fileChooser.SaveFileAsync(parentWindow, saveFileDialog.Title ?? string.Empty, options); + break; + } + + var request = DBusHelper.Connection.CreateProxy("org.freedesktop.portal.Request", objectPath); + var tsc = new TaskCompletionSource(); + using var disposable = await request.WatchResponseAsync(x => tsc.TrySetResult(x.results["uris"] as string[])); + var uris = await tsc.Task; + for (var i = 0; i < uris.Length; i++) + uris[i] = new Uri(uris[i]).AbsolutePath; + return uris; + } + + public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) + { + var parentWindow = $"x11:{parent.PlatformImpl!.Handle.Handle.ToString("X")}"; + var options = new Dictionary + { + { "directory", true } + }; + var objectPath = await _fileChooser.OpenFileAsync(parentWindow, dialog.Title ?? string.Empty, options); + var request = DBusHelper.Connection.CreateProxy("org.freedesktop.portal.Request", objectPath); + var tsc = new TaskCompletionSource(); + using var disposable = await request.WatchResponseAsync(x => tsc.TrySetResult(x.results["uris"] as string[])); + var uris = await tsc.Task; + return uris.Length != 1 ? string.Empty : new Uri(uris[0]).AbsolutePath; + } + + private static (string name, (uint style, string extension)[])[] ParseFilters(FileDialog dialog) + { + var filters = new (string name, (uint style, string extension)[])[dialog.Filters!.Count]; + for (var i = 0; i < filters.Length; i++) + { + var extensions = dialog.Filters[i].Extensions.Select(static x => (0u, x)).ToArray(); + filters[i] = (dialog.Filters[i].Name, extensions); + } + + return filters; + } + } +} From 4c0fda3495d14b5357a161218aca67592b3663aa Mon Sep 17 00:00:00 2001 From: affederaffe <68356204+affederaffe@users.noreply.github.com> Date: Sat, 28 May 2022 22:54:14 +0200 Subject: [PATCH 201/332] Make classes internal --- src/Avalonia.FreeDesktop/DBusFileChooser.cs | 6 +++--- src/Avalonia.FreeDesktop/DBusSystemDialog.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.FreeDesktop/DBusFileChooser.cs b/src/Avalonia.FreeDesktop/DBusFileChooser.cs index 996f5dfe86..24db614a02 100644 --- a/src/Avalonia.FreeDesktop/DBusFileChooser.cs +++ b/src/Avalonia.FreeDesktop/DBusFileChooser.cs @@ -8,7 +8,7 @@ using Tmds.DBus; namespace Avalonia.FreeDesktop { [DBusInterface("org.freedesktop.portal.FileChooser")] - public interface IFileChooser : IDBusObject + internal interface IFileChooser : IDBusObject { Task OpenFileAsync(string ParentWindow, string Title, IDictionary Options); Task SaveFileAsync(string ParentWindow, string Title, IDictionary Options); @@ -20,12 +20,12 @@ namespace Avalonia.FreeDesktop } [Dictionary] - public class FileChooserProperties + internal class FileChooserProperties { public uint Version { get; set; } } - public static class FileChooserExtensions + internal static class FileChooserExtensions { public static Task GetVersionAsync(this IFileChooser o) => o.GetAsync("version"); } diff --git a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs index d76e22b113..88f3e528e5 100644 --- a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs +++ b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs @@ -9,11 +9,11 @@ using Tmds.DBus; namespace Avalonia.FreeDesktop { - public class DBusSystemDialog : ISystemDialogImpl + internal class DBusSystemDialog : ISystemDialogImpl { private readonly IFileChooser _fileChooser; - public DBusSystemDialog() + internal DBusSystemDialog() { _fileChooser = DBusHelper.Connection.CreateProxy("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); } From 8026fb1047e9ce309056787d7277aa36ff631c70 Mon Sep 17 00:00:00 2001 From: affederaffe <68356204+affederaffe@users.noreply.github.com> Date: Sun, 29 May 2022 12:15:00 +0200 Subject: [PATCH 202/332] Fall back to managed dialogs when xdg-desktop-portal is unavailable --- .../ManagedFileDialogExtensions.cs | 8 ++- .../Avalonia.FreeDesktop.csproj | 2 + src/Avalonia.FreeDesktop/DBusHelper.cs | 24 +++---- src/Avalonia.FreeDesktop/DBusSystemDialog.cs | 68 +++++++++++++++---- src/Avalonia.X11/X11Platform.cs | 9 ++- 5 files changed, 78 insertions(+), 33 deletions(-) diff --git a/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs b/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs index 1970c5557d..effdc847a0 100644 --- a/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs +++ b/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs @@ -139,9 +139,15 @@ namespace Avalonia.Dialogs return builder; } + public static Task ShowManagedAsync(this FileDialog dialog, Window parent) + => new ManagedSystemDialogImpl().ShowFileDialogAsync(dialog, parent); + + public static Task ShowManagedAsync(this OpenFolderDialog dialog, Window parent) + => new ManagedSystemDialogImpl().ShowFolderDialogAsync(dialog, parent); + public static Task ShowManagedAsync(this OpenFileDialog dialog, Window parent, ManagedFileDialogOptions options = null) => ShowManagedAsync(dialog, parent, options); - + public static Task ShowManagedAsync(this OpenFileDialog dialog, Window parent, ManagedFileDialogOptions options = null) where TWindow : Window, new() { diff --git a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj index e9d6394aa5..a5cb207223 100644 --- a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj +++ b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj @@ -2,10 +2,12 @@ net6.0;netstandard2.0 + enable + diff --git a/src/Avalonia.FreeDesktop/DBusHelper.cs b/src/Avalonia.FreeDesktop/DBusHelper.cs index c14539d7bf..7204e51dbd 100644 --- a/src/Avalonia.FreeDesktop/DBusHelper.cs +++ b/src/Avalonia.FreeDesktop/DBusHelper.cs @@ -6,7 +6,7 @@ using Tmds.DBus; namespace Avalonia.FreeDesktop { - public class DBusHelper + public static class DBusHelper { /// /// This class uses synchronous execution at DBus connection establishment stage @@ -14,14 +14,14 @@ namespace Avalonia.FreeDesktop /// private class DBusSyncContext : SynchronizationContext { - private SynchronizationContext _ctx; - private object _lock = new object(); + private readonly object _lock = new(); + private SynchronizationContext? _ctx; public override void Post(SendOrPostCallback d, object state) { lock (_lock) { - if (_ctx != null) + if (_ctx is not null) _ctx?.Post(d, state); else lock (_lock) @@ -33,10 +33,9 @@ namespace Avalonia.FreeDesktop { lock (_lock) { - if (_ctx != null) + if (_ctx is not null) _ctx?.Send(d, state); else - d(state); } } @@ -47,15 +46,14 @@ namespace Avalonia.FreeDesktop _ctx = new AvaloniaSynchronizationContext(); } } - public static Connection Connection { get; private set; } - public static Connection TryInitialize(string dbusAddress = null) + public static Connection? Connection { get; private set; } + + public static Connection? TryInitialize(string? dbusAddress = null) + => Connection ?? TryCreateNewConnection(dbusAddress); + + public static Connection? TryCreateNewConnection(string? dbusAddress = null) { - return Connection ?? TryCreateNewConnection(dbusAddress); - } - - public static Connection TryCreateNewConnection(string dbusAddress = null) - { var oldContext = SynchronizationContext.Current; try { diff --git a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs index 88f3e528e5..7bc287ea28 100644 --- a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs +++ b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs @@ -5,20 +5,56 @@ using System.Text; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Platform; +using Avalonia.Dialogs; +using Avalonia.Logging; using Tmds.DBus; namespace Avalonia.FreeDesktop { internal class DBusSystemDialog : ISystemDialogImpl { - private readonly IFileChooser _fileChooser; + private readonly IFileChooser? _fileChooser; + private bool _isDbusAvailable; internal DBusSystemDialog() { - _fileChooser = DBusHelper.Connection.CreateProxy("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); + _fileChooser = DBusHelper.Connection?.CreateProxy("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); + _isDbusAvailable = _fileChooser is not null; } - public async Task ShowFileDialogAsync(FileDialog dialog, Window parent) + public async Task ShowFileDialogAsync(FileDialog dialog, Window parent) + { + if (!_isDbusAvailable) + return await dialog.ShowManagedAsync(parent); + try + { + return await ShowNativeFileDialogAsync(dialog, parent); + } + catch (Exception e) + { + Logger.TryGet(LogEventLevel.Error, LogArea.X11Platform)?.Log(this, e.Message); + _isDbusAvailable = false; + return await dialog.ShowManagedAsync(parent); + } + } + + public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) + { + if (!_isDbusAvailable) + return await dialog.ShowManagedAsync(parent); + try + { + return await ShowNativeFolderDialogAsync(dialog, parent); + } + catch (Exception e) + { + Logger.TryGet(LogEventLevel.Error, LogArea.X11Platform)?.Log(this, e.Message); + _isDbusAvailable = false; + return await dialog.ShowManagedAsync(parent); + } + } + + private async Task ShowNativeFileDialogAsync(FileDialog dialog, Window parent) { var parentWindow = $"x11:{parent.PlatformImpl!.Handle.Handle.ToString("X")}"; ObjectPath objectPath; @@ -30,38 +66,42 @@ namespace Avalonia.FreeDesktop { case OpenFileDialog openFileDialog: options.Add("multiple", openFileDialog.AllowMultiple); - objectPath = await _fileChooser.OpenFileAsync(parentWindow, openFileDialog.Title ?? string.Empty, options); + objectPath = await _fileChooser!.OpenFileAsync(parentWindow, openFileDialog.Title ?? string.Empty, options); break; case SaveFileDialog saveFileDialog: if (saveFileDialog.InitialFileName is not null) options.Add("current_name", saveFileDialog.InitialFileName); if (saveFileDialog.Directory is not null) options.Add("current_folder", Encoding.UTF8.GetBytes(saveFileDialog.Directory)); - objectPath = await _fileChooser.SaveFileAsync(parentWindow, saveFileDialog.Title ?? string.Empty, options); + objectPath = await _fileChooser!.SaveFileAsync(parentWindow, saveFileDialog.Title ?? string.Empty, options); break; } - var request = DBusHelper.Connection.CreateProxy("org.freedesktop.portal.Request", objectPath); - var tsc = new TaskCompletionSource(); - using var disposable = await request.WatchResponseAsync(x => tsc.TrySetResult(x.results["uris"] as string[])); + var request = DBusHelper.Connection!.CreateProxy("org.freedesktop.portal.Request", objectPath); + var tsc = new TaskCompletionSource(); + using var disposable = await request.WatchResponseAsync(x => tsc.SetResult(x.results["uris"] as string[]), tsc.SetException); var uris = await tsc.Task; + if (uris is null) + return null; for (var i = 0; i < uris.Length; i++) uris[i] = new Uri(uris[i]).AbsolutePath; return uris; } - public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) + private async Task ShowNativeFolderDialogAsync(OpenFolderDialog dialog, Window parent) { var parentWindow = $"x11:{parent.PlatformImpl!.Handle.Handle.ToString("X")}"; var options = new Dictionary { { "directory", true } }; - var objectPath = await _fileChooser.OpenFileAsync(parentWindow, dialog.Title ?? string.Empty, options); - var request = DBusHelper.Connection.CreateProxy("org.freedesktop.portal.Request", objectPath); - var tsc = new TaskCompletionSource(); - using var disposable = await request.WatchResponseAsync(x => tsc.TrySetResult(x.results["uris"] as string[])); + var objectPath = await _fileChooser!.OpenFileAsync(parentWindow, dialog.Title ?? string.Empty, options); + var request = DBusHelper.Connection!.CreateProxy("org.freedesktop.portal.Request", objectPath); + var tsc = new TaskCompletionSource(); + using var disposable = await request.WatchResponseAsync(x => tsc.SetResult(x.results["uris"] as string[]), tsc.SetException); var uris = await tsc.Task; + if (uris is null) + return null; return uris.Length != 1 ? string.Empty : new Uri(uris[0]).AbsolutePath; } @@ -71,7 +111,7 @@ namespace Avalonia.FreeDesktop for (var i = 0; i < filters.Length; i++) { var extensions = dialog.Filters[i].Extensions.Select(static x => (0u, x)).ToArray(); - filters[i] = (dialog.Filters[i].Name, extensions); + filters[i] = (dialog.Filters[i].Name ?? string.Empty, extensions); } return filters; diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index ec3f29c806..8765299d1d 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -15,7 +15,6 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.X11; using Avalonia.X11.Glx; -using Avalonia.X11.NativeDialogs; using static Avalonia.X11.XLib; namespace Avalonia.X11 @@ -80,7 +79,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new X11Clipboard(this)) .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new X11IconLoader(Info)) - .Bind().ToConstant(new GtkSystemDialog()) + .Bind().ToConstant(new DBusSystemDialog()) .Bind().ToConstant(new LinuxMountedVolumeInfoProvider()) .Bind().ToConstant(new X11PlatformLifetimeEvents(this)); @@ -209,10 +208,10 @@ namespace Avalonia public bool OverlayPopups { get; set; } /// - /// Enables global menu support on Linux desktop environments where it's supported (e. g. XFCE and MATE with plugin, KDE, etc). - /// The default value is false. + /// Enables native file dialogs as well as global menu support on Linux desktop environments where it's supported (e. g. XFCE and MATE with plugin, KDE, etc). + /// The default value is true. /// - public bool UseDBusMenu { get; set; } + public bool UseDBusMenu { get; set; } = true; /// /// Deferred renderer would be used when set to true. Immediate renderer when set to false. The default value is true. From 0a4b3386d5e06f49d123ac49cdc4105a316c4a19 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Sun, 29 May 2022 22:02:18 +0100 Subject: [PATCH 203/332] [OSX] fix SetParent --- native/Avalonia.Native/src/OSX/WindowImpl.h | 1 + native/Avalonia.Native/src/OSX/WindowImpl.mm | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index db19497b29..35627685a2 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -22,6 +22,7 @@ private: bool _transitioningWindowState; bool _isClientAreaExtended; bool _isDialog; + WindowImpl* _lastParent; AvnExtendClientAreaChromeHints _extendClientHints; FORWARD_IUNKNOWN() diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index d96fe717ab..ad804eb280 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -20,6 +20,7 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase _lastWindowState = Normal; _actualWindowState = Normal; _lastTitle = @""; + _lastParent = nullptr; WindowEvents = events; } @@ -61,6 +62,11 @@ void WindowImpl::OnInitialiseNSWindow(){ [GetWindowProtocol() setIsExtended:true]; SetExtendClientArea(true); } + + if(_lastParent != nullptr) + { + SetParent(_lastParent); + } } HRESULT WindowImpl::Show(bool activate, bool isDialog) { @@ -97,6 +103,10 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { if (cparent == nullptr) return E_INVALIDARG; + + _lastParent = cparent; + + if(Window != nullptr){ // If one tries to show a child window with a minimized parent window, then the parent window will be // restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive // state. Detect this and explicitly restore the parent window ourselves to avoid this situation. @@ -107,6 +117,7 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { [cparent->Window addChildWindow:Window ordered:NSWindowAbove]; UpdateStyle(); + } return S_OK; } @@ -535,7 +546,7 @@ NSWindowStyleMask WindowImpl::GetStyle() { break; case SystemDecorationsFull: - s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskBorderless; + s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable; if (_canResize) { s = s | NSWindowStyleMaskResizable; From d2af5dbcac4427c22830d0bb6a2764befa180a72 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 29 May 2022 22:59:50 -0400 Subject: [PATCH 204/332] Implicitly map x:DataType to a DataType on a DataTemplate. --- .../AvaloniaXamlIlCompiler.cs | 8 +- .../Transformers/XDataTypeTransformer.cs | 79 +++++++++++++++++++ .../Xaml/DataTemplateTests.cs | 58 ++++++++++++++ .../Xaml/TreeDataTemplateTests.cs | 17 ++++ 4 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index 1ca7be67a7..7514b0e12e 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -31,10 +31,10 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions // Before everything else Transformers.Insert(0, new XNameTransformer()); - Transformers.Insert(1, new IgnoredDirectivesTransformer()); - Transformers.Insert(2, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer()); - Transformers.Insert(3, _bindingTransformer = new AvaloniaBindingExtensionTransformer()); - + Transformers.Insert(1, new XDataTypeTransformer()); + Transformers.Insert(2, new IgnoredDirectivesTransformer()); + Transformers.Insert(3, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer()); + Transformers.Insert(4, _bindingTransformer = new AvaloniaBindingExtensionTransformer()); // Targeted InsertBefore( diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs new file mode 100644 index 0000000000..7b90164974 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using XamlX; +using XamlX.Ast; +using XamlX.Transform; +using XamlX.Transform.Transformers; +using XamlX.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers +{ + internal class XDataTypeTransformer : IXamlAstTransformer + { + private const string DataTypePropertyName = "DataType"; + + /// + /// Converts x:DataType directives to regular DataType assignments if property with Avalonia.Metadata.DataTypeAttribute exists. + /// + /// + public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) + { + if (node is XamlAstObjectNode on) + { + for (var c = 0; c < on.Children.Count; c++) + { + var ch = on.Children[c]; + if (ch is XamlAstXmlDirective { Namespace: XamlNamespaces.Xaml2006, Name: DataTypePropertyName } d) + { + if (on.Children.OfType() + .Any(p => ((XamlAstNamePropertyReference)p.Property)?.Name == DataTypePropertyName)) + { + // Break iteration if any DataType property was already set by user code. + break; + } + + var templateDataTypeAttribute = context.GetAvaloniaTypes().DataTypeAttribute; + + var clrType = on.Type switch + { + XamlAstClrTypeReference clrRef => clrRef.Type, + XamlAstXmlTypeReference xmlRef => TypeReferenceResolver.ResolveType(context, xmlRef.Name, + on.Type.IsMarkupExtension, on, strict: false).Type, + _ => null + }; + if (clrType is null) + { + break; + } + + // Technically it's possible to map "x:DataType" to a property with [DataType] attribute regardless of its name, + // but we go explicitly strict here and check the name as well. + var (declaringType, dataTypeProperty) = GetAllProperties(clrType) + .FirstOrDefault(t => t.property.Name == DataTypePropertyName && t.property.CustomAttributes + .Any(a => a.Type == templateDataTypeAttribute)); + + if (dataTypeProperty is not null) + { + on.Children[c] = new XamlAstXamlPropertyValueNode(d, + new XamlAstNamePropertyReference(d, + new XamlAstClrTypeReference(ch, declaringType, false), dataTypeProperty.Name, + on.Type), + d.Values); + } + } + } + } + + return node; + } + + private static IEnumerable<(IXamlType declaringType, IXamlProperty property)> GetAllProperties(IXamlType t) + { + foreach (var p in t.Properties) + yield return (t, p); + if(t.BaseType!=null) + foreach (var tuple in GetAllProperties(t.BaseType)) + yield return tuple; + } + } +} diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs index 53881467e7..f9e1ce3054 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs @@ -1,5 +1,7 @@ +using System.Linq; using Avalonia.Controls; using Avalonia.Controls.Presenters; +using Avalonia.Markup.Xaml.Templates; using Avalonia.UnitTests; using Xunit; @@ -89,6 +91,62 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml } } + [Fact] + public void XDataType_Should_Be_Assigned_To_Clr_Property() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var target = window.FindControl("target"); + var template = (DataTemplate)window.DataTemplates.First(); + + window.ApplyTemplate(); + target.ApplyTemplate(); + ((ContentPresenter)target.Presenter).UpdateChild(); + + Assert.Equal(typeof(string), template.DataType); + Assert.IsType(target.Presenter.Child); + } + } + + [Fact] + public void XDataType_Should_Be_Ignored_If_DataType_Already_Set() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var target = window.FindControl("target"); + + window.ApplyTemplate(); + target.ApplyTemplate(); + ((ContentPresenter)target.Presenter).UpdateChild(); + + Assert.IsType(target.Presenter.Child); + } + } + [Fact] public void Can_Set_DataContext_In_DataTemplate() { diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs index 3fdac49f31..d4ab473d67 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs @@ -21,5 +21,22 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml Assert.IsType(template.ItemsSource); } } + + [Fact] + public void XDataType_Should_Be_Assigned_To_Clr_Property() + { + using (UnitTestApplication.Start(TestServices.MockPlatformWrapper)) + { + var xaml = @" + + +"; + var templates = (DataTemplates)AvaloniaRuntimeXamlLoader.Load(xaml); + var template = (TreeDataTemplate)(templates.First()); + + Assert.Equal(typeof(string), template.DataType); + } + } } } From 1d9645f01fda85fcbc80e11090cd672b536a559b Mon Sep 17 00:00:00 2001 From: Max Katz Date: Sun, 29 May 2022 23:38:20 -0400 Subject: [PATCH 205/332] Validate DataTemplates --- .../Templates/DataTemplates.cs | 17 +++++++++++++++ .../Templates/ITypedDataTemplate.cs | 10 +++++++++ .../Templates/DataTemplate.cs | 2 +- .../Templates/TreeDataTemplate.cs | 2 +- .../CompiledBindingExtensionTests.cs | 4 ++-- .../Xaml/ControlBindingTests.cs | 8 +++---- .../Xaml/DataTemplateTests.cs | 21 +++++++++++++++++++ .../Xaml/TreeDataTemplateTests.cs | 2 +- 8 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 src/Avalonia.Controls/Templates/ITypedDataTemplate.cs diff --git a/src/Avalonia.Controls/Templates/DataTemplates.cs b/src/Avalonia.Controls/Templates/DataTemplates.cs index f203539536..d4eeda7908 100644 --- a/src/Avalonia.Controls/Templates/DataTemplates.cs +++ b/src/Avalonia.Controls/Templates/DataTemplates.cs @@ -1,3 +1,4 @@ +using System; using Avalonia.Collections; namespace Avalonia.Controls.Templates @@ -13,6 +14,22 @@ namespace Avalonia.Controls.Templates public DataTemplates() { ResetBehavior = ResetBehavior.Remove; + + Validate += ValidateDataTemplate; + } + + private static void ValidateDataTemplate(IDataTemplate template) + { + var valid = template switch + { + ITypedDataTemplate typed => typed.DataType is not null, + _ => true + }; + + if (!valid) + { + throw new InvalidOperationException("DataTemplate inside of DataTemplates must have a DataType set. Set DataType property or use ItemTemplate with single template instead."); + } } } } \ No newline at end of file diff --git a/src/Avalonia.Controls/Templates/ITypedDataTemplate.cs b/src/Avalonia.Controls/Templates/ITypedDataTemplate.cs new file mode 100644 index 0000000000..239dbd79f4 --- /dev/null +++ b/src/Avalonia.Controls/Templates/ITypedDataTemplate.cs @@ -0,0 +1,10 @@ +using System; +using Avalonia.Metadata; + +namespace Avalonia.Controls.Templates; + +public interface ITypedDataTemplate : IDataTemplate +{ + [DataType] + Type? DataType { get; } +} diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs index d2b24979cc..4da6b1b791 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs @@ -5,7 +5,7 @@ using Avalonia.Metadata; namespace Avalonia.Markup.Xaml.Templates { - public class DataTemplate : IRecyclingDataTemplate + public class DataTemplate : IRecyclingDataTemplate, ITypedDataTemplate { [DataType] public Type DataType { get; set; } diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs index 10061c3d48..04e8b0a9c0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs @@ -9,7 +9,7 @@ using Avalonia.Metadata; namespace Avalonia.Markup.Xaml.Templates { - public class TreeDataTemplate : ITreeDataTemplate + public class TreeDataTemplate : ITreeDataTemplate, ITypedDataTemplate { [DataType] public Type DataType { get; set; } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index 7e721fd7b2..555a05638b 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -413,11 +413,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests' x:DataType='local:TestDataContext'> - + - + "; var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs index 8188b212e1..affa292a7d 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs @@ -74,18 +74,18 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml - + - + - + - + "; diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs index 53881467e7..abbcf6c5a8 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs @@ -1,3 +1,4 @@ +using System; using Avalonia.Controls; using Avalonia.Controls.Presenters; using Avalonia.UnitTests; @@ -132,5 +133,25 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml Assert.Same(viewModel.Child.Child, canvas.DataContext); } } + + [Fact] + public void DataTemplates_Without_Type_Should_Throw() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + +"; + Assert.Throws(() => (Window)AvaloniaRuntimeXamlLoader.Load(xaml)); + } + } } } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs index 3fdac49f31..807b37517a 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs @@ -14,7 +14,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml { using (UnitTestApplication.Start(TestServices.MockPlatformWrapper)) { - var xaml = ""; + var xaml = ""; var templates = (DataTemplates)AvaloniaRuntimeXamlLoader.Load(xaml); var template = (TreeDataTemplate)(templates.First()); From 03e01a6e554227613ce5579cf24884e8a94ad629 Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Mon, 30 May 2022 13:04:46 +0300 Subject: [PATCH 206/332] initial working --- src/Avalonia.Controls/ComboBox.cs | 21 ++-- src/Avalonia.Controls/Control.cs | 7 +- .../Rendering/SceneGraph/SceneBuilderTests.cs | 33 +++++++ .../ComboBoxTests.cs | 99 +++++++++++++++++++ .../FlowDirectionTests.cs | 41 ++++++++ 5 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index cbf9b35a05..1f46a3b292 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -184,23 +184,10 @@ namespace Avalonia.Controls this.UpdateSelectionBoxItem(SelectedItem); } - // Because the SelectedItem isn't connected to the visual tree public override void InvalidateMirrorTransform() { base.InvalidateMirrorTransform(); - - if (SelectedItem is Control selectedControl) - { - selectedControl.InvalidateMirrorTransform(); - - foreach (var visual in selectedControl.GetVisualDescendants()) - { - if (visual is Control childControl) - { - childControl.InvalidateMirrorTransform(); - } - } - } + UpdateSelectionBoxItem(SelectedItem); } /// @@ -365,6 +352,8 @@ namespace Avalonia.Controls { parent.GetObservable(IsVisibleProperty).Subscribe(IsVisibleChanged).DisposeWith(_subscriptionsOnOpen); } + + UpdateSelectionBoxItem(SelectedItem); } private void IsVisibleChanged(bool isVisible) @@ -420,8 +409,12 @@ namespace Avalonia.Controls { control.Measure(Size.Infinity); + var flowDirection = control.IsAttachedToVisualTree ? + (control.VisualParent as Control)!.FlowDirection : FlowDirection.LeftToRight; + SelectionBoxItem = new Rectangle { + FlowDirection = flowDirection, Width = control.DesiredSize.Width, Height = control.DesiredSize.Height, Fill = new VisualBrush diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index d6a5fa0727..16d4ef5c15 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -378,17 +378,12 @@ namespace Avalonia.Controls bool bypassFlowDirectionPolicies = BypassFlowDirectionPolicies; bool parentBypassFlowDirectionPolicies = false; - var parent = this.FindAncestorOfType(); + var parent = ((IVisual)this).VisualParent as Control; if (parent != null) { parentFlowDirection = parent.FlowDirection; parentBypassFlowDirectionPolicies = parent.BypassFlowDirectionPolicies; } - else if (Parent is Control logicalParent) - { - parentFlowDirection = logicalParent.FlowDirection; - parentBypassFlowDirectionPolicies = logicalParent.BypassFlowDirectionPolicies; - } bool thisShouldBeMirrored = flowDirection == FlowDirection.RightToLeft && !bypassFlowDirectionPolicies; bool parentShouldBeMirrored = parentFlowDirection == FlowDirection.RightToLeft && !parentBypassFlowDirectionPolicies; diff --git a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs index 01afe85b8b..5cc9f57c8e 100644 --- a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs +++ b/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs @@ -349,6 +349,39 @@ namespace Avalonia.Base.UnitTests.Rendering.SceneGraph } } + [Fact] + public void MirrorTransform_For_Control_With_RenderTransform_Should_Be_Correct() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + Border border; + var tree = new TestRoot + { + Width = 400, + Height = 200, + Child = border = new Border + { + HorizontalAlignment = HorizontalAlignment.Left, + Background = Brushes.Red, + Width = 100, + RenderTransform = new ScaleTransform(0.5, 1), + FlowDirection = FlowDirection.RightToLeft + } + }; + + tree.Measure(Size.Infinity); + tree.Arrange(new Rect(tree.DesiredSize)); + + var scene = new Scene(tree); + var sceneBuilder = new SceneBuilder(); + sceneBuilder.UpdateAll(scene); + + var expectedTransform = new Matrix(-1, 0, 0, 1, 100, 0) * Matrix.CreateScale(0.5, 1) * Matrix.CreateTranslation(25, 0); + var borderNode = scene.FindNode(border); + Assert.Equal(expectedTransform, borderNode.Transform); + } + } + [Fact] public void Should_Update_Border_Background_Node() { diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs index 98695fe88e..0f1925f628 100644 --- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs @@ -336,5 +336,104 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(1, count); } } + + [Fact] + public void FlowDirection_Of_RectangleContent_Shuold_Be_LeftToRight() + { + using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + { + var items = new[] + { + new ComboBoxItem() + { + Content = new Control() + } + }; + var target = new ComboBox + { + Items = items, + Template = GetTemplate() + }; + + var root = new TestRoot(target); + target.ApplyTemplate(); + target.SelectedIndex = 0; + + var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; + + Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection); + } + } + + [Fact] + public void FlowDirection_Of_RectangleContent_Updated_After_Change_ComboBox() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var items = new[] + { + new ComboBoxItem() + { + Content = new Control() + } + }; + var target = new ComboBox + { + FlowDirection = FlowDirection.RightToLeft, + Items = items, + Template = GetTemplate() + }; + + var root = new TestRoot(target); + + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + target.SelectedIndex = 0; + + var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; + + // need help here, the 'rectangle' isn't connected to visual tree for some reason + + Assert.True(rectangle.HasMirrorTransform); + + target.FlowDirection = FlowDirection.LeftToRight; + + Assert.False(rectangle.HasMirrorTransform); + } + } + + [Fact] + public void FlowDirection_Of_RectangleContent_Updated_After_Content_In_VisualTree() + { + using (UnitTestApplication.Start(TestServices.RealFocus)) + { + Control content; + var items = new[] + { + new ComboBoxItem() + { + Content = content = new Control() + } + }; + var target = new ComboBox + { + FlowDirection = FlowDirection.RightToLeft, + Items = items, + Template = GetTemplate() + }; + + var root = new TestRoot(target); + target.ApplyTemplate(); + target.Presenter.ApplyTemplate(); + target.SelectedIndex = 0; + + // need help here how to connect 'content' tio visual tree, or how to + + + var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; + + Assert.Equal(FlowDirection.RightToLeft, rectangle.FlowDirection); + } + } } } diff --git a/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs b/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs new file mode 100644 index 0000000000..6739eff638 --- /dev/null +++ b/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs @@ -0,0 +1,41 @@ +using Avalonia.Media; +using Xunit; + +namespace Avalonia.Controls.UnitTests +{ + public class FlowDirectionTests + { + [Fact] + public void HasMirrorTransform_Should_Be_True() + { + var target = new Control + { + FlowDirection = FlowDirection.RightToLeft, + }; + + Assert.True(target.HasMirrorTransform); + } + + [Fact] + public void HasMirrorTransform_Of_Children_Is_Updated_After_Change() + { + Control child; + var target = new Decorator + { + FlowDirection = FlowDirection.LeftToRight, + Child = child = new Control() + { + FlowDirection = FlowDirection.LeftToRight, + } + }; + + Assert.False(target.HasMirrorTransform); + Assert.False(child.HasMirrorTransform); + + target.FlowDirection = FlowDirection.RightToLeft; + + Assert.True(target.HasMirrorTransform); + Assert.True(child.HasMirrorTransform); + } + } +} From 05db047d2909b96b264ffded9e882bb62278ba25 Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Mon, 30 May 2022 13:09:20 +0300 Subject: [PATCH 207/332] typo --- tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs index 0f1925f628..905ded193c 100644 --- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs @@ -427,7 +427,7 @@ namespace Avalonia.Controls.UnitTests target.Presenter.ApplyTemplate(); target.SelectedIndex = 0; - // need help here how to connect 'content' tio visual tree, or how to + // need help here how to connect 'content' to visual tree, or how to open popup var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; From ee4c0f97e6e4000f01a46b591ed43afa4eba939b Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Mon, 30 May 2022 14:23:13 +0300 Subject: [PATCH 208/332] remove OnAttachedToVisualTree because bug --- src/Avalonia.Controls/ComboBox.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 1f46a3b292..8a6fb361da 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -178,16 +178,10 @@ namespace Avalonia.Controls ComboBoxItem.ContentTemplateProperty); } - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - this.UpdateSelectionBoxItem(SelectedItem); - } - public override void InvalidateMirrorTransform() { base.InvalidateMirrorTransform(); - UpdateSelectionBoxItem(SelectedItem); + UpdateSelectionBoxItem(SelectedItem); } /// From b0f7871eecd9380f81a111de001b32a4cdd821fa Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Mon, 30 May 2022 19:14:37 +0300 Subject: [PATCH 209/332] Don't allow bindings to private methods. --- .../Data/Converters/DefaultValueConverter.cs | 9 +++++- .../Data/BindingTests_Method.cs | 32 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/Avalonia.Markup.UnitTests/Data/BindingTests_Method.cs diff --git a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs index 11d50afe93..e531cfd7be 100644 --- a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs +++ b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs @@ -33,7 +33,14 @@ namespace Avalonia.Data.Converters if (typeof(ICommand).IsAssignableFrom(targetType) && value is Delegate d && d.Method.GetParameters().Length <= 1) { - return new MethodToCommandConverter(d); + if (d.Method.Attributes.HasFlag(System.Reflection.MethodAttributes.Private) == false) + { + return new MethodToCommandConverter(d); + } + else + { + return new BindingNotification(new InvalidCastException("You can't bind to private methods!"), BindingErrorType.Error); + } } if (TypeUtilities.TryConvert(targetType, value, culture, out var result)) diff --git a/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Method.cs b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Method.cs new file mode 100644 index 0000000000..e613a178d5 --- /dev/null +++ b/tests/Avalonia.Markup.UnitTests/Data/BindingTests_Method.cs @@ -0,0 +1,32 @@ +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Input; +using Avalonia.Interactivity; +using Xunit; + +namespace Avalonia.Markup.UnitTests.Data +{ + public class BindingTests_Method + { + [Fact] + public void Binding_To_Private_Methods_Shouldnt_Work() + { + var vm = new TestClass(); + var target = new Button + { + DataContext = vm, + [!Button.CommandProperty] = new Binding("MyMethod"), + }; + target.RaiseEvent(new RoutedEventArgs(AccessKeyHandler.AccessKeyPressedEvent)); + + Assert.False(vm.IsSet); + } + + + class TestClass + { + public bool IsSet { get; set; } + private void MyMethod() => IsSet = true; + } + } +} From 83b5338a2855b7a0e1643c810895ebd3f765d1bc Mon Sep 17 00:00:00 2001 From: Takoooooo Date: Mon, 30 May 2022 19:51:36 +0300 Subject: [PATCH 210/332] Check for method being Private correctly. --- src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs index e531cfd7be..c4f4362537 100644 --- a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs +++ b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs @@ -33,7 +33,7 @@ namespace Avalonia.Data.Converters if (typeof(ICommand).IsAssignableFrom(targetType) && value is Delegate d && d.Method.GetParameters().Length <= 1) { - if (d.Method.Attributes.HasFlag(System.Reflection.MethodAttributes.Private) == false) + if (d.Method.IsPrivate == false) { return new MethodToCommandConverter(d); } From 421b8227c5bb2a6544ac1f494759766db3e99bb8 Mon Sep 17 00:00:00 2001 From: Mike James Date: Mon, 30 May 2022 18:43:01 +0100 Subject: [PATCH 211/332] Updating the readme to clarify donations vs support agreements I've attempted to clarify that donations are separate from commercial support in the hope of minimising any future confusion. --- readme.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 1cdaf3b8f8..a8043b8690 100644 --- a/readme.md +++ b/readme.md @@ -70,11 +70,13 @@ For more information see the [.NET Foundation Code of Conduct](https://dotnetfou Avalonia is licenced under the [MIT licence](licence.md). -## Support Avalonia +## Donate -**BTC**: bc1q05wx78qemgy9x6ytl5ljk2xrt00yqargyjm8gx +Donating to the project is a fantastic way to thank our valued contributors for their hard work. Your donations are shared among our community and awarded for significant contributions. + +Donate with BTC or use [Open Collective](https://opencollective.com/avalonia). -This will be shared with the community and awarded for significant contributions. +**BTC**: bc1q05wx78qemgy9x6ytl5ljk2xrt00yqargyjm8gx ### Backers @@ -98,6 +100,11 @@ Support this project by becoming a sponsor. Your logo will show up here with a l +## Commercial Support + +We have a range of [support plans available](https://avaloniaui.net/support.html) for those looking to partner with the creators of Avalonia, enabling access to the best support at every step of the development process. + +*Please note that donations are not considered payment for commercial support agreements.* ## .NET Foundation This project is supported by the [.NET Foundation](https://dotnetfoundation.org). From 3c3fc4521ea31cf9c6562065a1552b4e2932e1c1 Mon Sep 17 00:00:00 2001 From: affederaffe <68356204+affederaffe@users.noreply.github.com> Date: Mon, 30 May 2022 20:20:27 +0200 Subject: [PATCH 212/332] Clean up DBusSystemDialog.cs + add factory method --- src/Avalonia.Dialogs/Avalonia.Dialogs.csproj | 4 ++ .../ManagedFileDialogExtensions.cs | 8 +-- src/Avalonia.FreeDesktop/DBusSystemDialog.cs | 50 ++++++------------- src/Avalonia.X11/X11Platform.cs | 3 +- 4 files changed, 23 insertions(+), 42 deletions(-) diff --git a/src/Avalonia.Dialogs/Avalonia.Dialogs.csproj b/src/Avalonia.Dialogs/Avalonia.Dialogs.csproj index a311efdfb0..80159c82d7 100644 --- a/src/Avalonia.Dialogs/Avalonia.Dialogs.csproj +++ b/src/Avalonia.Dialogs/Avalonia.Dialogs.csproj @@ -14,6 +14,10 @@ + + + + diff --git a/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs b/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs index effdc847a0..e4025453c4 100644 --- a/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs +++ b/src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs @@ -8,7 +8,7 @@ namespace Avalonia.Dialogs { public static class ManagedFileDialogExtensions { - private class ManagedSystemDialogImpl : ISystemDialogImpl where T : Window, new() + internal class ManagedSystemDialogImpl : ISystemDialogImpl where T : Window, new() { async Task Show(SystemDialog d, Window parent, ManagedFileDialogOptions options = null) { @@ -139,12 +139,6 @@ namespace Avalonia.Dialogs return builder; } - public static Task ShowManagedAsync(this FileDialog dialog, Window parent) - => new ManagedSystemDialogImpl().ShowFileDialogAsync(dialog, parent); - - public static Task ShowManagedAsync(this OpenFolderDialog dialog, Window parent) - => new ManagedSystemDialogImpl().ShowFolderDialogAsync(dialog, parent); - public static Task ShowManagedAsync(this OpenFileDialog dialog, Window parent, ManagedFileDialogOptions options = null) => ShowManagedAsync(dialog, parent, options); diff --git a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs index 7bc287ea28..d1905a4569 100644 --- a/src/Avalonia.FreeDesktop/DBusSystemDialog.cs +++ b/src/Avalonia.FreeDesktop/DBusSystemDialog.cs @@ -5,7 +5,6 @@ using System.Text; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Platform; -using Avalonia.Dialogs; using Avalonia.Logging; using Tmds.DBus; @@ -13,48 +12,31 @@ namespace Avalonia.FreeDesktop { internal class DBusSystemDialog : ISystemDialogImpl { - private readonly IFileChooser? _fileChooser; - private bool _isDbusAvailable; + private readonly IFileChooser _fileChooser; - internal DBusSystemDialog() + internal static DBusSystemDialog? TryCreate() { - _fileChooser = DBusHelper.Connection?.CreateProxy("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); - _isDbusAvailable = _fileChooser is not null; - } - - public async Task ShowFileDialogAsync(FileDialog dialog, Window parent) - { - if (!_isDbusAvailable) - return await dialog.ShowManagedAsync(parent); + var fileChooser = DBusHelper.Connection?.CreateProxy("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop"); + if (fileChooser is null) + return null; try { - return await ShowNativeFileDialogAsync(dialog, parent); + fileChooser.GetVersionAsync().GetAwaiter().GetResult(); + return new DBusSystemDialog(fileChooser); } catch (Exception e) { - Logger.TryGet(LogEventLevel.Error, LogArea.X11Platform)?.Log(this, e.Message); - _isDbusAvailable = false; - return await dialog.ShowManagedAsync(parent); + Logger.TryGet(LogEventLevel.Error, LogArea.X11Platform)?.Log(null, $"Unable to connect to org.freedesktop.portal.Desktop: {e.Message}"); + return null; } } - public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) + private DBusSystemDialog(IFileChooser fileChooser) { - if (!_isDbusAvailable) - return await dialog.ShowManagedAsync(parent); - try - { - return await ShowNativeFolderDialogAsync(dialog, parent); - } - catch (Exception e) - { - Logger.TryGet(LogEventLevel.Error, LogArea.X11Platform)?.Log(this, e.Message); - _isDbusAvailable = false; - return await dialog.ShowManagedAsync(parent); - } + _fileChooser = fileChooser; } - private async Task ShowNativeFileDialogAsync(FileDialog dialog, Window parent) + public async Task ShowFileDialogAsync(FileDialog dialog, Window parent) { var parentWindow = $"x11:{parent.PlatformImpl!.Handle.Handle.ToString("X")}"; ObjectPath objectPath; @@ -66,14 +48,14 @@ namespace Avalonia.FreeDesktop { case OpenFileDialog openFileDialog: options.Add("multiple", openFileDialog.AllowMultiple); - objectPath = await _fileChooser!.OpenFileAsync(parentWindow, openFileDialog.Title ?? string.Empty, options); + objectPath = await _fileChooser.OpenFileAsync(parentWindow, openFileDialog.Title ?? string.Empty, options); break; case SaveFileDialog saveFileDialog: if (saveFileDialog.InitialFileName is not null) options.Add("current_name", saveFileDialog.InitialFileName); if (saveFileDialog.Directory is not null) options.Add("current_folder", Encoding.UTF8.GetBytes(saveFileDialog.Directory)); - objectPath = await _fileChooser!.SaveFileAsync(parentWindow, saveFileDialog.Title ?? string.Empty, options); + objectPath = await _fileChooser.SaveFileAsync(parentWindow, saveFileDialog.Title ?? string.Empty, options); break; } @@ -88,14 +70,14 @@ namespace Avalonia.FreeDesktop return uris; } - private async Task ShowNativeFolderDialogAsync(OpenFolderDialog dialog, Window parent) + public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent) { var parentWindow = $"x11:{parent.PlatformImpl!.Handle.Handle.ToString("X")}"; var options = new Dictionary { { "directory", true } }; - var objectPath = await _fileChooser!.OpenFileAsync(parentWindow, dialog.Title ?? string.Empty, options); + var objectPath = await _fileChooser.OpenFileAsync(parentWindow, dialog.Title ?? string.Empty, options); var request = DBusHelper.Connection!.CreateProxy("org.freedesktop.portal.Request", objectPath); var tsc = new TaskCompletionSource(); using var disposable = await request.WatchResponseAsync(x => tsc.SetResult(x.results["uris"] as string[]), tsc.SetException); diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 8765299d1d..fa7ae69759 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Runtime.InteropServices; using Avalonia.Controls; using Avalonia.Controls.Platform; +using Avalonia.Dialogs; using Avalonia.FreeDesktop; using Avalonia.FreeDesktop.DBusIme; using Avalonia.Input; @@ -79,7 +80,7 @@ namespace Avalonia.X11 .Bind().ToConstant(new X11Clipboard(this)) .Bind().ToConstant(new PlatformSettingsStub()) .Bind().ToConstant(new X11IconLoader(Info)) - .Bind().ToConstant(new DBusSystemDialog()) + .Bind().ToConstant(DBusSystemDialog.TryCreate() as ISystemDialogImpl ?? new ManagedFileDialogExtensions.ManagedSystemDialogImpl()) .Bind().ToConstant(new LinuxMountedVolumeInfoProvider()) .Bind().ToConstant(new X11PlatformLifetimeEvents(this)); From 18814cf948e363eb5b8b5fbd6a63a9016ebac376 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 30 May 2022 19:32:21 +0100 Subject: [PATCH 213/332] add contact address for support. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a8043b8690..67faaba10f 100644 --- a/readme.md +++ b/readme.md @@ -104,7 +104,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l We have a range of [support plans available](https://avaloniaui.net/support.html) for those looking to partner with the creators of Avalonia, enabling access to the best support at every step of the development process. -*Please note that donations are not considered payment for commercial support agreements.* +*Please note that donations are not considered payment for commercial support agreements. Please contact us to discuss your needs first. [team@avaloniaui.net](mailto://team@avaloniaui.net)* ## .NET Foundation This project is supported by the [.NET Foundation](https://dotnetfoundation.org). From d7d6a8353ef493a2b9645e6406b18b792e737d60 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Mon, 30 May 2022 19:33:53 +0100 Subject: [PATCH 214/332] make it really clear. --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 67faaba10f..1009e86c29 100644 --- a/readme.md +++ b/readme.md @@ -74,6 +74,8 @@ Avalonia is licenced under the [MIT licence](licence.md). Donating to the project is a fantastic way to thank our valued contributors for their hard work. Your donations are shared among our community and awarded for significant contributions. +If you need support see Commercial Support section below. + Donate with BTC or use [Open Collective](https://opencollective.com/avalonia). **BTC**: bc1q05wx78qemgy9x6ytl5ljk2xrt00yqargyjm8gx From 33f6974df15221b4cddd71ee8a3e6f2b226d5ef0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 30 May 2022 21:12:43 +0200 Subject: [PATCH 215/332] Added failing test for Viewbox layout. --- .../ViewboxTests.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs index 3cebe142b6..4ffd314857 100644 --- a/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ViewboxTests.cs @@ -181,6 +181,32 @@ namespace Avalonia.Controls.UnitTests Assert.Null(child.GetLogicalParent()); } + [Fact] + public void Changing_Child_Should_Invalidate_Layout() + { + var target = new Viewbox(); + + target.Child = new Canvas + { + Width = 100, + Height = 100, + }; + + target.Measure(Size.Infinity); + target.Arrange(new Rect(target.DesiredSize)); + Assert.Equal(new Size(100, 100), target.DesiredSize); + + target.Child = new Canvas + { + Width = 200, + Height = 200, + }; + + target.Measure(Size.Infinity); + target.Arrange(new Rect(target.DesiredSize)); + Assert.Equal(new Size(200, 200), target.DesiredSize); + } + private bool TryGetScale(Viewbox viewbox, out Vector scale) { if (viewbox.InternalTransform is null) From 06e0fae71774a67597503ab1cd58ea8238bf20eb Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Mon, 30 May 2022 21:13:09 +0200 Subject: [PATCH 216/332] Invalidate measure when Viewbox child changes. --- src/Avalonia.Controls/Viewbox.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs index 01a41a0157..aabfd3ef18 100644 --- a/src/Avalonia.Controls/Viewbox.cs +++ b/src/Avalonia.Controls/Viewbox.cs @@ -168,6 +168,8 @@ namespace Avalonia.Controls if (_child is not null) VisualChildren.Add(_child); + + InvalidateMeasure(); } } } From 7e6edb0f32b753d226aba58889d56c2875b6f282 Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Mon, 30 May 2022 23:42:05 +0300 Subject: [PATCH 217/332] fixes bugs --- src/Avalonia.Controls/ComboBox.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 8a6fb361da..a3f87f7695 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -403,8 +403,8 @@ namespace Avalonia.Controls { control.Measure(Size.Infinity); - var flowDirection = control.IsAttachedToVisualTree ? - (control.VisualParent as Control)!.FlowDirection : FlowDirection.LeftToRight; + var flowDirection = + (control.VisualParent as Control)?.FlowDirection ?? FlowDirection.LeftToRight; SelectionBoxItem = new Rectangle { From 496b978cdbb830a0eb44d2b11915ff3c615c492a Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 30 May 2022 18:36:14 -0400 Subject: [PATCH 218/332] Run xDataType after TypeReferenceResolver --- .../CompilerExtensions/AvaloniaXamlIlCompiler.cs | 10 ++++++---- .../Transformers/XDataTypeTransformer.cs | 8 +------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index 7514b0e12e..04a61e5f10 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -31,10 +31,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions // Before everything else Transformers.Insert(0, new XNameTransformer()); - Transformers.Insert(1, new XDataTypeTransformer()); - Transformers.Insert(2, new IgnoredDirectivesTransformer()); - Transformers.Insert(3, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer()); - Transformers.Insert(4, _bindingTransformer = new AvaloniaBindingExtensionTransformer()); + Transformers.Insert(1, new IgnoredDirectivesTransformer()); + Transformers.Insert(2, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer()); + Transformers.Insert(3, _bindingTransformer = new AvaloniaBindingExtensionTransformer()); // Targeted InsertBefore( @@ -57,6 +56,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions new AvaloniaXamlIlResolveByNameMarkupExtensionReplacer() ); + InsertAfter( + new XDataTypeTransformer()); + // After everything else InsertBefore( new AddNameScopeRegistration(), diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs index 7b90164974..845dc5f831 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs @@ -34,13 +34,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers var templateDataTypeAttribute = context.GetAvaloniaTypes().DataTypeAttribute; - var clrType = on.Type switch - { - XamlAstClrTypeReference clrRef => clrRef.Type, - XamlAstXmlTypeReference xmlRef => TypeReferenceResolver.ResolveType(context, xmlRef.Name, - on.Type.IsMarkupExtension, on, strict: false).Type, - _ => null - }; + var clrType = (on.Type as XamlAstClrTypeReference)?.Type; if (clrType is null) { break; From bc2179b337e969838942fcfea868934536d9ef33 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Mon, 30 May 2022 18:49:21 -0400 Subject: [PATCH 219/332] Add XDataType_Should_Be_Ignored_If_DataType_Has_Non_Standard_Name test --- .../CompiledBindingExtensionTests.cs | 3 +- .../Xaml/DataTemplateTests.cs | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs index 7e721fd7b2..a8b95d3aaa 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs @@ -17,6 +17,7 @@ using Avalonia.Markup.Xaml.Templates; using Avalonia.Media; using Avalonia.Metadata; using Avalonia.UnitTests; +using JetBrains.Annotations; using XamlX; using Xunit; @@ -1527,7 +1528,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions [TemplateContent] public object Content { get; set; } - public bool Match(object data) => FancyDataType.IsInstanceOfType(data); + public bool Match(object data) => FancyDataType?.IsInstanceOfType(data) ?? true; public IControl Build(object data) => TemplateContent.Load(Content)?.Control; } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs index f9e1ce3054..6e99d9e3a6 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs @@ -1,7 +1,11 @@ +using System; using System.Linq; using Avalonia.Controls; using Avalonia.Controls.Presenters; +using Avalonia.Controls.Templates; using Avalonia.Markup.Xaml.Templates; +using Avalonia.Markup.Xaml.UnitTests.MarkupExtensions; +using Avalonia.Metadata; using Avalonia.UnitTests; using Xunit; @@ -147,6 +151,37 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml } } + [Fact] + public void XDataType_Should_Be_Ignored_If_DataType_Has_Non_Standard_Name() + { + // We don't want DataType to be mapped to FancyDataType, avoid possible confusion. + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + + +"; + var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); + var target = window.FindControl("target"); + + window.ApplyTemplate(); + target.ApplyTemplate(); + ((ContentPresenter)target.Presenter).UpdateChild(); + + var dataTemplate = (CustomDataTemplate)target.ContentTemplate; + Assert.Null(dataTemplate.FancyDataType); + } + } + [Fact] public void Can_Set_DataContext_In_DataTemplate() { From 402790ba86bfb6fc0f9de817cb3032b681175f38 Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Tue, 31 May 2022 07:53:59 +0300 Subject: [PATCH 220/332] improve UpdateFlowDirection --- src/Avalonia.Controls/ComboBox.cs | 28 +++++++++++++++---- .../ComboBoxTests.cs | 5 ++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index a3f87f7695..fc7feca7f1 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -178,10 +178,16 @@ namespace Avalonia.Controls ComboBoxItem.ContentTemplateProperty); } + protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnAttachedToVisualTree(e); + UpdateSelectionBoxItem(SelectedItem); + } + public override void InvalidateMirrorTransform() { base.InvalidateMirrorTransform(); - UpdateSelectionBoxItem(SelectedItem); + UpdateFlowDirection(); } /// @@ -347,7 +353,7 @@ namespace Avalonia.Controls parent.GetObservable(IsVisibleProperty).Subscribe(IsVisibleChanged).DisposeWith(_subscriptionsOnOpen); } - UpdateSelectionBoxItem(SelectedItem); + UpdateFlowDirection(); } private void IsVisibleChanged(bool isVisible) @@ -403,12 +409,8 @@ namespace Avalonia.Controls { control.Measure(Size.Infinity); - var flowDirection = - (control.VisualParent as Control)?.FlowDirection ?? FlowDirection.LeftToRight; - SelectionBoxItem = new Rectangle { - FlowDirection = flowDirection, Width = control.DesiredSize.Width, Height = control.DesiredSize.Height, Fill = new VisualBrush @@ -419,6 +421,8 @@ namespace Avalonia.Controls } }; } + + UpdateFlowDirection(); } else { @@ -426,6 +430,18 @@ namespace Avalonia.Controls } } + private void UpdateFlowDirection() + { + var rectangle = SelectionBoxItem as Rectangle; + if (rectangle != null) + { + var content = (rectangle.Fill as VisualBrush)!.Visual as Control; + var flowDirection = (((IVisual)content!).VisualParent as Control)?.FlowDirection ?? FlowDirection.LeftToRight; + + rectangle.FlowDirection = flowDirection; + } + } + private void SelectFocusedItem() { foreach (ItemContainerInfo dropdownItem in ItemContainerGenerator.Containers) diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs index 905ded193c..0804de3174 100644 --- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs @@ -351,6 +351,7 @@ namespace Avalonia.Controls.UnitTests }; var target = new ComboBox { + FlowDirection = FlowDirection.RightToLeft, Items = items, Template = GetTemplate() }; @@ -368,7 +369,7 @@ namespace Avalonia.Controls.UnitTests [Fact] public void FlowDirection_Of_RectangleContent_Updated_After_Change_ComboBox() { - using (UnitTestApplication.Start(TestServices.StyledWindow)) + using (UnitTestApplication.Start(TestServices.RealStyler)) { var items = new[] { @@ -385,10 +386,10 @@ namespace Avalonia.Controls.UnitTests }; var root = new TestRoot(target); - target.ApplyTemplate(); target.Presenter.ApplyTemplate(); target.SelectedIndex = 0; + ((ContentPresenter)target.Presenter).UpdateChild(); var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; From c77c500bcd373fa3715cce5d5a851eaab89da408 Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Tue, 31 May 2022 14:35:55 +0300 Subject: [PATCH 221/332] fixes tests --- src/Avalonia.Controls/ComboBox.cs | 6 +- .../ComboBoxTests.cs | 116 +++++++++--------- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index fc7feca7f1..5ba1195159 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -432,11 +432,11 @@ namespace Avalonia.Controls private void UpdateFlowDirection() { - var rectangle = SelectionBoxItem as Rectangle; - if (rectangle != null) + if (SelectionBoxItem is Rectangle rectangle) { var content = (rectangle.Fill as VisualBrush)!.Visual as Control; - var flowDirection = (((IVisual)content!).VisualParent as Control)?.FlowDirection ?? FlowDirection.LeftToRight; + var flowDirection = (((IVisual)content!).VisualParent as Control)?.FlowDirection ?? + FlowDirection.LeftToRight; rectangle.FlowDirection = flowDirection; } diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs index 0804de3174..70b713d6d0 100644 --- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs @@ -8,7 +8,7 @@ using Avalonia.Data; using Avalonia.Input; using Avalonia.LogicalTree; using Avalonia.Media; -using Avalonia.Threading; +using Avalonia.VisualTree; using Avalonia.UnitTests; using Xunit; @@ -340,80 +340,77 @@ namespace Avalonia.Controls.UnitTests [Fact] public void FlowDirection_Of_RectangleContent_Shuold_Be_LeftToRight() { - using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface)) + var items = new[] { - var items = new[] - { - new ComboBoxItem() - { - Content = new Control() - } - }; - var target = new ComboBox - { - FlowDirection = FlowDirection.RightToLeft, - Items = items, - Template = GetTemplate() - }; + new ComboBoxItem() + { + Content = new Control() + } + }; + var target = new ComboBox + { + FlowDirection = FlowDirection.RightToLeft, + Items = items, + Template = GetTemplate() + }; - var root = new TestRoot(target); - target.ApplyTemplate(); - target.SelectedIndex = 0; + var root = new TestRoot(target); + target.ApplyTemplate(); + target.SelectedIndex = 0; - var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; + var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; - Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection); - } + Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection); } [Fact] - public void FlowDirection_Of_RectangleContent_Updated_After_Change_ComboBox() + public void FlowDirection_Of_RectangleContent_Updated_After_InvalidateMirrorTransform() { - using (UnitTestApplication.Start(TestServices.RealStyler)) + var parentContent = new Decorator() { - var items = new[] - { - new ComboBoxItem() - { - Content = new Control() - } - }; - var target = new ComboBox + Child = new Control() + }; + var items = new[] + { + new ComboBoxItem() { - FlowDirection = FlowDirection.RightToLeft, - Items = items, - Template = GetTemplate() - }; - - var root = new TestRoot(target); - target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); - target.SelectedIndex = 0; - ((ContentPresenter)target.Presenter).UpdateChild(); - - var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; - - // need help here, the 'rectangle' isn't connected to visual tree for some reason + Content = parentContent.Child + } + }; + var target = new ComboBox + { + FlowDirection = FlowDirection.RightToLeft, + Items = items, + Template = GetTemplate() + }; - Assert.True(rectangle.HasMirrorTransform); + var root = new TestRoot(target); + target.ApplyTemplate(); + target.SelectedIndex = 0; - target.FlowDirection = FlowDirection.LeftToRight; + var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; + Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection); - Assert.False(rectangle.HasMirrorTransform); - } + parentContent.FlowDirection = FlowDirection.RightToLeft; + target.InvalidateMirrorTransform(); + + Assert.Equal(FlowDirection.RightToLeft, rectangle.FlowDirection); } [Fact] - public void FlowDirection_Of_RectangleContent_Updated_After_Content_In_VisualTree() + public void FlowDirection_Of_RectangleContent_Updated_After_OpenPopup() { - using (UnitTestApplication.Start(TestServices.RealFocus)) + using (UnitTestApplication.Start(TestServices.StyledWindow)) { - Control content; - var items = new[] + var parentContent = new Decorator() { + Child = new Control() + }; + var items = new[] + { new ComboBoxItem() { - Content = content = new Control() + Content = parentContent.Child } }; var target = new ComboBox @@ -425,14 +422,17 @@ namespace Avalonia.Controls.UnitTests var root = new TestRoot(target); target.ApplyTemplate(); - target.Presenter.ApplyTemplate(); target.SelectedIndex = 0; - // need help here how to connect 'content' to visual tree, or how to open popup - - var rectangle = target.GetValue(ComboBox.SelectionBoxItemProperty) as Rectangle; + Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection); + parentContent.FlowDirection = FlowDirection.RightToLeft; + + var popup = target.GetVisualDescendants().OfType().First(); + popup.PlacementTarget = new Window(); + popup.Open(); + Assert.Equal(FlowDirection.RightToLeft, rectangle.FlowDirection); } } From 020fa3030a45c759e350c8136128930833c17cf3 Mon Sep 17 00:00:00 2001 From: Adir Hudayfi Date: Tue, 31 May 2022 18:45:32 +0300 Subject: [PATCH 222/332] Upgraded SkiaSharp packages --- build/SkiaSharp.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props index 1ee4aa56a2..d54cffba08 100644 --- a/build/SkiaSharp.props +++ b/build/SkiaSharp.props @@ -1,7 +1,7 @@  - - - + + + From 5bf28b671d42b5682930e27014d5897fe90bda73 Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Tue, 31 May 2022 20:42:16 +0300 Subject: [PATCH 223/332] some fixes --- tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs index 70b713d6d0..aa32af7e51 100644 --- a/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs @@ -379,7 +379,6 @@ namespace Avalonia.Controls.UnitTests }; var target = new ComboBox { - FlowDirection = FlowDirection.RightToLeft, Items = items, Template = GetTemplate() }; @@ -392,7 +391,7 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(FlowDirection.LeftToRight, rectangle.FlowDirection); parentContent.FlowDirection = FlowDirection.RightToLeft; - target.InvalidateMirrorTransform(); + target.FlowDirection = FlowDirection.RightToLeft; Assert.Equal(FlowDirection.RightToLeft, rectangle.FlowDirection); } From 2e555be4020afca57fc9d5bea68920544405d69b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 31 May 2022 13:11:07 +0100 Subject: [PATCH 224/332] [OSX] programatically implement child window relationship --- native/Avalonia.Native/src/OSX/AvnView.mm | 5 ++ native/Avalonia.Native/src/OSX/AvnWindow.mm | 38 +++++------ .../Avalonia.Native/src/OSX/WindowBaseImpl.h | 2 + .../Avalonia.Native/src/OSX/WindowBaseImpl.mm | 7 +- native/Avalonia.Native/src/OSX/WindowImpl.h | 8 ++- native/Avalonia.Native/src/OSX/WindowImpl.mm | 66 +++++++++++++------ .../Avalonia.Native/src/OSX/WindowProtocol.h | 1 - 7 files changed, 81 insertions(+), 46 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/AvnView.mm b/native/Avalonia.Native/src/OSX/AvnView.mm index 5436ad22f3..bbb4d59adb 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.mm +++ b/native/Avalonia.Native/src/OSX/AvnView.mm @@ -300,6 +300,11 @@ - (void)mouseDown:(NSEvent *)event { + if(_parent != nullptr) + { + _parent->BringToFront(); + } + _isLeftPressed = true; _lastMouseDownEvent = event; [self mouseEvent:event withType:LeftButtonDown]; diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 590dc5e7ac..1445227cf5 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -183,6 +183,11 @@ return self; } +- (void)mouseDown:(NSEvent *)event +{ + _parent->BringToFront(); +} + - (BOOL)windowShouldClose:(NSWindow *)sender { auto window = dynamic_cast(_parent.getRaw()); @@ -209,7 +214,14 @@ { ComPtr parent = _parent; _parent = NULL; - [self restoreParentWindow]; + + auto window = dynamic_cast(parent.getRaw()); + + if(window != nullptr) + { + window->SetParent(nullptr); + } + parent->BaseEvents->Closed(); [parent->View onClosed]; } @@ -220,17 +232,11 @@ if(_canBecomeKeyWindow) { // If the window has a child window being shown as a dialog then don't allow it to become the key window. - for(NSWindow* uch in [self childWindows]) + auto parent = dynamic_cast(_parent.getRaw()); + + if(parent != nullptr) { - if (![uch conformsToProtocol:@protocol(AvnWindowProtocol)]) - { - continue; - } - - id ch = (id ) uch; - - if(ch.isDialog) - return false; + return parent->CanBecomeKeyWindow(); } return true; @@ -273,16 +279,6 @@ [super becomeKeyWindow]; } --(void) restoreParentWindow; -{ - auto parent = [self parentWindow]; - - if(parent != nil) - { - [parent removeChildWindow:self]; - } -} - - (void)windowDidMiniaturize:(NSNotification *)notification { auto parent = dynamic_cast(_parent.operator->()); diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 83850e780c..62c0e2069d 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -99,6 +99,8 @@ BEGIN_INTERFACE_MAP() virtual bool IsDialog(); id GetWindowProtocol (); + + virtual void BringToFront (); protected: virtual NSWindowStyleMask GetStyle(); diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 121679b942..77f0f47934 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -143,8 +143,6 @@ HRESULT WindowBaseImpl::Hide() { @autoreleasepool { if (Window != nullptr) { [Window orderOut:Window]; - - [GetWindowProtocol() restoreParentWindow]; } return S_OK; @@ -610,6 +608,11 @@ id WindowBaseImpl::GetWindowProtocol() { return (id ) Window; } +void WindowBaseImpl::BringToFront() +{ + // do nothing. +} + extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events, IAvnGlContext* gl) { @autoreleasepool diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index 35627685a2..76d5cbf6ea 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -8,6 +8,7 @@ #import "WindowBaseImpl.h" #include "IWindowStateChanged.h" +#include class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged { @@ -22,7 +23,8 @@ private: bool _transitioningWindowState; bool _isClientAreaExtended; bool _isDialog; - WindowImpl* _lastParent; + WindowImpl* _parent; + std::list _children; AvnExtendClientAreaChromeHints _extendClientHints; FORWARD_IUNKNOWN() @@ -91,6 +93,10 @@ BEGIN_INTERFACE_MAP() virtual bool IsDialog() override; virtual void OnInitialiseNSWindow() override; + + virtual void BringToFront () override; + + bool CanBecomeKeyWindow (); protected: virtual NSWindowStyleMask GetStyle() override; diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index ad804eb280..5333cb23c8 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -10,6 +10,7 @@ #include "WindowProtocol.h" WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) { + _children = std::list(); _isClientAreaExtended = false; _extendClientHints = AvnDefaultChrome; _fullScreenActive = false; @@ -20,7 +21,7 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase _lastWindowState = Normal; _actualWindowState = Normal; _lastTitle = @""; - _lastParent = nullptr; + _parent = nullptr; WindowEvents = events; } @@ -63,9 +64,9 @@ void WindowImpl::OnInitialiseNSWindow(){ SetExtendClientArea(true); } - if(_lastParent != nullptr) + if(_parent != nullptr) { - SetParent(_lastParent); + SetParent(_parent); } } @@ -96,33 +97,56 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { START_COM_CALL; @autoreleasepool { - if (parent == nullptr) - return E_POINTER; + if(_parent != nullptr) + { + _parent->_children.remove(this); + } auto cparent = dynamic_cast(parent); - if (cparent == nullptr) - return E_INVALIDARG; - - _lastParent = cparent; + _parent = cparent; - if(Window != nullptr){ - // If one tries to show a child window with a minimized parent window, then the parent window will be - // restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive - // state. Detect this and explicitly restore the parent window ourselves to avoid this situation. - if (cparent->WindowState() == Minimized) - cparent->SetWindowState(Normal); - - [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; - [cparent->Window addChildWindow:Window ordered:NSWindowAbove]; - - UpdateStyle(); + if(_parent != nullptr && Window != nullptr){ + // If one tries to show a child window with a minimized parent window, then the parent window will be + // restored but macOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive + // state. Detect this and explicitly restore the parent window ourselves to avoid this situation. + if (cparent->WindowState() == Minimized) + cparent->SetWindowState(Normal); + + [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + + cparent->_children.push_back(this); + + UpdateStyle(); } return S_OK; } } +void WindowImpl::BringToFront() +{ + Activate(); + + for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) + { + (*iterator)->BringToFront(); + } +} + +bool WindowImpl::CanBecomeKeyWindow() +{ + for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) + { + if((*iterator)->IsDialog()) + { + return false; + } + } + + return true; +} + void WindowImpl::StartStateTransition() { _transitioningWindowState = true; } @@ -534,7 +558,7 @@ bool WindowImpl::IsDialog() { } NSWindowStyleMask WindowImpl::GetStyle() { - unsigned long s = this->_isDialog ? NSWindowStyleMaskDocModalWindow : NSWindowStyleMaskBorderless; + unsigned long s = NSWindowStyleMaskBorderless; switch (_decorations) { case SystemDecorationsNone: diff --git a/native/Avalonia.Native/src/OSX/WindowProtocol.h b/native/Avalonia.Native/src/OSX/WindowProtocol.h index 0e5c5869e7..cb5f86bdb9 100644 --- a/native/Avalonia.Native/src/OSX/WindowProtocol.h +++ b/native/Avalonia.Native/src/OSX/WindowProtocol.h @@ -11,7 +11,6 @@ @protocol AvnWindowProtocol -(void) pollModalSession: (NSModalSession _Nonnull) session; --(void) restoreParentWindow; -(bool) shouldTryToHandleEvents; -(void) setEnabled: (bool) enable; -(void) showAppMenuOnly; From 8a39240eea1f04a1d0971e3be2f693f97e56f985 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 31 May 2022 13:50:01 +0100 Subject: [PATCH 225/332] [osx] make bringtofront work correctly for owned and modal windows. --- native/Avalonia.Native/src/OSX/AvnView.mm | 5 ----- native/Avalonia.Native/src/OSX/AvnWindow.mm | 9 +++------ native/Avalonia.Native/src/OSX/WindowImpl.mm | 9 ++++++++- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/AvnView.mm b/native/Avalonia.Native/src/OSX/AvnView.mm index bbb4d59adb..5436ad22f3 100644 --- a/native/Avalonia.Native/src/OSX/AvnView.mm +++ b/native/Avalonia.Native/src/OSX/AvnView.mm @@ -300,11 +300,6 @@ - (void)mouseDown:(NSEvent *)event { - if(_parent != nullptr) - { - _parent->BringToFront(); - } - _isLeftPressed = true; _lastMouseDownEvent = event; [self mouseEvent:event withType:LeftButtonDown]; diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 1445227cf5..60fdb26121 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -183,11 +183,6 @@ return self; } -- (void)mouseDown:(NSEvent *)event -{ - _parent->BringToFront(); -} - - (BOOL)windowShouldClose:(NSWindow *)sender { auto window = dynamic_cast(_parent.getRaw()); @@ -435,8 +430,10 @@ _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast([event timestamp] * 1000), AvnInputModifiersNone, point, delta); } + + _parent->BringToFront(); } - break; + break; case NSEventTypeMouseEntered: { diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 5333cb23c8..8330f4ed86 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -126,7 +126,14 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { void WindowImpl::BringToFront() { - Activate(); + if(IsDialog()) + { + Activate(); + } + else + { + [Window orderFront:nullptr]; + } for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) { From 61449dc40169145c0d4a05c25d5c58f46a8e26e4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 31 May 2022 14:10:33 +0100 Subject: [PATCH 226/332] dont create nspanel / nswindow at show. --- native/Avalonia.Native/src/OSX/WindowBaseImpl.mm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 77f0f47934..d105f4cf38 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -36,8 +36,10 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) lastMaxSize = NSSize { CGFLOAT_MAX, CGFLOAT_MAX}; lastMinSize = NSSize { 0, 0 }; - Window = nullptr; lastMenu = nullptr; + + CreateNSWindow(false); + InitialiseNSWindow(); } HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) { @@ -88,7 +90,6 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { START_COM_CALL; @autoreleasepool { - CreateNSWindow(isDialog); InitialiseNSWindow(); if(hasPosition) @@ -585,6 +586,7 @@ void WindowBaseImpl::InitialiseNSWindow() { [Window setOpaque:false]; + [Window setHasShadow:true]; [Window invalidateShadow]; if (lastMenu != nullptr) { From 2cd8ee003fd2ab660a7260af804dccbab8aa35d1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 31 May 2022 14:11:19 +0100 Subject: [PATCH 227/332] call bring to front when window is made key. --- native/Avalonia.Native/src/OSX/AvnWindow.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 60fdb26121..52ee48317c 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -274,6 +274,11 @@ [super becomeKeyWindow]; } +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + _parent->BringToFront(); +} + - (void)windowDidMiniaturize:(NSNotification *)notification { auto parent = dynamic_cast(_parent.operator->()); From b48888e9bf04ba725353c4009d5f17c20b600a94 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 31 May 2022 14:28:44 +0100 Subject: [PATCH 228/332] [osx] easily support using nspanel from windowbaseimpl. --- native/Avalonia.Native/src/OSX/WindowBaseImpl.h | 2 +- native/Avalonia.Native/src/OSX/WindowBaseImpl.mm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 62c0e2069d..4220811fc7 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -26,7 +26,7 @@ BEGIN_INTERFACE_MAP() virtual ~WindowBaseImpl(); - WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl); + WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl, bool usePanel = false); virtual HRESULT ObtainNSWindowHandle(void **ret) override; diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index d105f4cf38..e88c7f208c 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -21,7 +21,7 @@ WindowBaseImpl::~WindowBaseImpl() { Window = nullptr; } -WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) { +WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl, bool usePanel) { _shown = false; _inResize = false; BaseEvents = events; @@ -38,7 +38,7 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl) lastMenu = nullptr; - CreateNSWindow(false); + CreateNSWindow(usePanel); InitialiseNSWindow(); } From 131c81ad22f91d9d54fdfb1412aa6947f391764b Mon Sep 17 00:00:00 2001 From: Todd Date: Tue, 31 May 2022 11:51:54 -0700 Subject: [PATCH 229/332] replace mouse and touch events to pointer event to fix issue #8200 --- .../Avalonia.Web.Blazor/AvaloniaView.razor | 10 +- .../Avalonia.Web.Blazor/AvaloniaView.razor.cs | 103 +++++++++--------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor index 3dd98f8cd3..3fe4c299cf 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor @@ -1,14 +1,12 @@ 
+ onkeyup="@OnKeyUp" + onpointerdown="@OnPointerDown" + onpointerup="@OnPointerUp" + onpointermove="@OnPointerMove"> diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index be58d9d49c..766aeb6d19 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -56,90 +56,91 @@ namespace Avalonia.Web.Blazor { return _nativeControlHost ?? throw new InvalidOperationException("Blazor View wasn't initialized yet"); } - - private void OnTouchStart(TouchEventArgs e) + + private void OnTouchCancel(TouchEventArgs e) { foreach (var touch in e.ChangedTouches) { - _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchBegin, new Point(touch.ClientX, touch.ClientY), + _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchCancel, new Point(touch.ClientX, touch.ClientY), GetModifiers(e), touch.Identifier); } } - private void OnTouchEnd(TouchEventArgs e) + private void OnTouchMove(TouchEventArgs e) { foreach (var touch in e.ChangedTouches) { - _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchEnd, new Point(touch.ClientX, touch.ClientY), + _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchUpdate, new Point(touch.ClientX, touch.ClientY), GetModifiers(e), touch.Identifier); } } - private void OnTouchCancel(TouchEventArgs e) + private void OnPointerMove(Microsoft.AspNetCore.Components.Web.PointerEventArgs e) { - foreach (var touch in e.ChangedTouches) + if (e.PointerType == "mouse") { - _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchCancel, new Point(touch.ClientX, touch.ClientY), - GetModifiers(e), touch.Identifier); + _topLevelImpl.RawMouseEvent(RawPointerEventType.Move, new Point(e.ClientX, e.ClientY), GetModifiers(e)); } } - private void OnTouchMove(TouchEventArgs e) + private void OnPointerUp(Microsoft.AspNetCore.Components.Web.PointerEventArgs e) { - foreach (var touch in e.ChangedTouches) + if (e.PointerType == "touch") { - _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchUpdate, new Point(touch.ClientX, touch.ClientY), - GetModifiers(e), touch.Identifier); + _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchEnd, new Point(e.ClientX, e.ClientY), + GetModifiers(e), e.PointerId); } - } - - private void OnMouseMove(MouseEventArgs e) - { - _topLevelImpl.RawMouseEvent(RawPointerEventType.Move, new Point(e.ClientX, e.ClientY), GetModifiers(e)); - } + else if (e.PointerType == "mouse") + { + RawPointerEventType type = default; - private void OnMouseUp(MouseEventArgs e) - { - RawPointerEventType type = default; + switch (e.Button) + { + case 0: + type = RawPointerEventType.LeftButtonUp; + break; - switch (e.Button) - { - case 0: - type = RawPointerEventType.LeftButtonUp; - break; + case 1: + type = RawPointerEventType.MiddleButtonUp; + break; - case 1: - type = RawPointerEventType.MiddleButtonUp; - break; + case 2: + type = RawPointerEventType.RightButtonUp; + break; + } - case 2: - type = RawPointerEventType.RightButtonUp; - break; + _topLevelImpl.RawMouseEvent(type, new Point(e.ClientX, e.ClientY), GetModifiers(e)); } - - _topLevelImpl.RawMouseEvent(type, new Point(e.ClientX, e.ClientY), GetModifiers(e)); } - private void OnMouseDown(MouseEventArgs e) + private void OnPointerDown(Microsoft.AspNetCore.Components.Web.PointerEventArgs e) { - RawPointerEventType type = default; - - switch (e.Button) + if (e.PointerType == "touch") + { + _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchBegin, new Point(e.ClientX, e.ClientY), + GetModifiers(e), e.PointerId); + } + else if (e.PointerType == "mouse") { - case 0: - type = RawPointerEventType.LeftButtonDown; - break; + RawPointerEventType type = default; + + switch (e.Button) + { + case 0: + type = RawPointerEventType.LeftButtonDown; + break; - case 1: - type = RawPointerEventType.MiddleButtonDown; - break; + case 1: + type = RawPointerEventType.MiddleButtonDown; + break; - case 2: - type = RawPointerEventType.RightButtonDown; - break; - } + case 2: + type = RawPointerEventType.RightButtonDown; + break; + } - _topLevelImpl.RawMouseEvent(type, new Point(e.ClientX, e.ClientY), GetModifiers(e)); + _topLevelImpl.RawMouseEvent(type, new Point(e.ClientX, e.ClientY), GetModifiers(e)); + } } private void OnWheel(WheelEventArgs e) @@ -189,7 +190,7 @@ namespace Avalonia.Web.Blazor return modifiers; } - private static RawInputModifiers GetModifiers(MouseEventArgs e) + private static RawInputModifiers GetModifiers(Microsoft.AspNetCore.Components.Web.PointerEventArgs e) { var modifiers = RawInputModifiers.None; From 53f6b62b4394a29311778d26a025af8e6931aab9 Mon Sep 17 00:00:00 2001 From: Oxc3 <61174136+Oxc3@users.noreply.github.com> Date: Tue, 31 May 2022 13:13:16 -0700 Subject: [PATCH 230/332] Update AvaloniaView.razor.cs modified pointer up, down, move to handle touch device specifically and all other devices as mouse event --- src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index 766aeb6d19..1f411d0cee 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -56,7 +56,7 @@ namespace Avalonia.Web.Blazor { return _nativeControlHost ?? throw new InvalidOperationException("Blazor View wasn't initialized yet"); } - + private void OnTouchCancel(TouchEventArgs e) { foreach (var touch in e.ChangedTouches) @@ -77,7 +77,7 @@ namespace Avalonia.Web.Blazor private void OnPointerMove(Microsoft.AspNetCore.Components.Web.PointerEventArgs e) { - if (e.PointerType == "mouse") + if (e.PointerType != "touch") { _topLevelImpl.RawMouseEvent(RawPointerEventType.Move, new Point(e.ClientX, e.ClientY), GetModifiers(e)); } @@ -90,7 +90,7 @@ namespace Avalonia.Web.Blazor _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchEnd, new Point(e.ClientX, e.ClientY), GetModifiers(e), e.PointerId); } - else if (e.PointerType == "mouse") + else { RawPointerEventType type = default; @@ -120,7 +120,7 @@ namespace Avalonia.Web.Blazor _topLevelImpl.RawTouchEvent(RawPointerEventType.TouchBegin, new Point(e.ClientX, e.ClientY), GetModifiers(e), e.PointerId); } - else if (e.PointerType == "mouse") + else { RawPointerEventType type = default; From 6dbb828b60042677b5fc2a92d810f2fabbf0d965 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 31 May 2022 21:58:00 -0400 Subject: [PATCH 231/332] Reset popup parent on flyout hidden --- src/Avalonia.Controls/Flyouts/FlyoutBase.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index d024f86b32..dfbd3f9a36 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -175,7 +175,8 @@ namespace Avalonia.Controls.Primitives IsOpen = false; Popup.IsOpen = false; - + ((ISetLogicalParent)Popup).SetParent(null); + // Ensure this isn't active _transientDisposable?.Dispose(); _transientDisposable = null; From 5ab8b06dce55f3c1294540e959182faad839bccf Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 31 May 2022 21:58:19 -0400 Subject: [PATCH 232/332] Reset popup parent on context menu target detached --- src/Avalonia.Controls/ContextMenu.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index 2b122d4174..7b35e35278 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -450,6 +450,11 @@ namespace Avalonia.Controls if (sender is Control control && control.ContextMenu is ContextMenu contextMenu) { + if (contextMenu._popup?.Parent == control) + { + ((ISetLogicalParent)contextMenu._popup).SetParent(null); + } + contextMenu.Close(); } } From bc6d5ec87d125936ed4892dae020bf4de82c668e Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 31 May 2022 22:17:33 -0400 Subject: [PATCH 233/332] Add tests --- .../ContextMenuTests.cs | 21 ++++++++++++++++ .../FlyoutTests.cs | 25 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs index ba01f3db40..b63cbd286e 100644 --- a/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs @@ -446,6 +446,27 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Should_Reset_Popup_Parent_On_Target_Detached() + { + using (Application()) + { + var userControl = new UserControl(); + var window = PreparedWindow(userControl); + window.Show(); + + var menu = new ContextMenu(); + userControl.ContextMenu = menu; + menu.Open(); + + var popup = Assert.IsType(menu.Parent); + Assert.NotNull(popup.Parent); + + window.Content = null; + Assert.Null(popup.Parent); + } + } + [Fact] public void Context_Menu_In_Resources_Can_Be_Shared() { diff --git a/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs b/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs index c2dd8cf01a..8b77074960 100644 --- a/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs +++ b/tests/Avalonia.Controls.UnitTests/FlyoutTests.cs @@ -432,6 +432,26 @@ namespace Avalonia.Controls.UnitTests } } + [Fact] + public void Should_Reset_Popup_Parent_On_Target_Detached() + { + using (CreateServicesWithFocus()) + { + var userControl = new UserControl(); + var window = PreparedWindow(userControl); + window.Show(); + + var flyout = new TestFlyout(); + flyout.ShowAt(userControl); + + var popup = Assert.IsType(flyout.Popup); + Assert.NotNull(popup.Parent); + + window.Content = null; + Assert.Null(popup.Parent); + } + } + [Fact] public void ContextFlyout_Can_Be_Set_In_Styles() { @@ -549,5 +569,10 @@ namespace Avalonia.Controls.UnitTests new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed), KeyModifiers.None); } + + public class TestFlyout : Flyout + { + public new Popup Popup => base.Popup; + } } } From 05be2056e8160ce64a427f8a9154c51f3df3d36a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jun 2022 10:10:43 +0100 Subject: [PATCH 234/332] dispatch bring to front parent when removing a child window. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 8330f4ed86..7776b2912d 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -100,6 +100,11 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { if(_parent != nullptr) { _parent->_children.remove(this); + auto parent = _parent; + + dispatch_async(dispatch_get_main_queue(), ^{ + parent->BringToFront(); + }); } auto cparent = dynamic_cast(parent); From 32a61c0ea400542dd8b78be64d64652412c16a25 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jun 2022 10:15:54 +0100 Subject: [PATCH 235/332] dialogs should not be minimizable. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 7776b2912d..8520e3e470 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -590,7 +590,7 @@ NSWindowStyleMask WindowImpl::GetStyle() { break; } - if ([Window parentWindow] == nullptr) { + if (!IsDialog()) { s |= NSWindowStyleMaskMiniaturizable; } From 0ab383ed8995d51e2a71b74a25211751e1b1e088 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jun 2022 10:32:02 +0100 Subject: [PATCH 236/332] fix build warnings. --- .../Avalonia.Native/src/OSX/AvnPanelWindow.mm | 2 -- native/Avalonia.Native/src/OSX/AvnWindow.mm | 34 +++++++++---------- .../Avalonia.Native/src/OSX/INSWindowHolder.h | 2 +- .../Avalonia.Native/src/OSX/WindowBaseImpl.h | 2 +- .../Avalonia.Native/src/OSX/WindowBaseImpl.mm | 2 +- 5 files changed, 20 insertions(+), 22 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/AvnPanelWindow.mm b/native/Avalonia.Native/src/OSX/AvnPanelWindow.mm index 2365189010..b49005de8a 100644 --- a/native/Avalonia.Native/src/OSX/AvnPanelWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnPanelWindow.mm @@ -3,8 +3,6 @@ // Copyright (c) 2022 Avalonia. All rights reserved. // -#pragma once - #define IS_NSPANEL #include "AvnWindow.mm" diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 52ee48317c..0b9ea093ac 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -68,7 +68,7 @@ } } -- (void)performClose:(id)sender +- (void)performClose:(id _Nullable )sender { if([[self delegate] respondsToSelector:@selector(windowShouldClose:)]) { @@ -147,7 +147,7 @@ } } --(void) applyMenu:(AvnMenu *)menu +-(void) applyMenu:(AvnMenu *_Nullable)menu { if(menu == nullptr) { @@ -157,7 +157,7 @@ _menu = menu; } --(CLASS_NAME*) initWithParent: (WindowBaseImpl*) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask; +-(CLASS_NAME*_Nonnull) initWithParent: (WindowBaseImpl*_Nonnull) parent contentRect: (NSRect)contentRect styleMask: (NSWindowStyleMask)styleMask; { // https://jameshfisher.com/2020/07/10/why-is-the-contentrect-of-my-nswindow-ignored/ // create nswindow with specific contentRect, otherwise we wont be able to resize the window @@ -183,7 +183,7 @@ return self; } -- (BOOL)windowShouldClose:(NSWindow *)sender +- (BOOL)windowShouldClose:(NSWindow *_Nonnull)sender { auto window = dynamic_cast(_parent.getRaw()); @@ -195,14 +195,14 @@ return true; } -- (void)windowDidChangeBackingProperties:(NSNotification *)notification +- (void)windowDidChangeBackingProperties:(NSNotification *_Nonnull)notification { [self backingScaleFactor]; } -- (void)windowWillClose:(NSNotification *)notification +- (void)windowWillClose:(NSNotification *_Nonnull)notification { _closed = true; if(_parent) @@ -274,12 +274,12 @@ [super becomeKeyWindow]; } -- (void)windowDidBecomeKey:(NSNotification *)notification +- (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification { _parent->BringToFront(); } -- (void)windowDidMiniaturize:(NSNotification *)notification +- (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification { auto parent = dynamic_cast(_parent.operator->()); @@ -289,7 +289,7 @@ } } -- (void)windowDidDeminiaturize:(NSNotification *)notification +- (void)windowDidDeminiaturize:(NSNotification *_Nonnull)notification { auto parent = dynamic_cast(_parent.operator->()); @@ -299,7 +299,7 @@ } } -- (void)windowDidResize:(NSNotification *)notification +- (void)windowDidResize:(NSNotification *_Nonnull)notification { auto parent = dynamic_cast(_parent.operator->()); @@ -309,7 +309,7 @@ } } -- (void)windowWillExitFullScreen:(NSNotification *)notification +- (void)windowWillExitFullScreen:(NSNotification *_Nonnull)notification { auto parent = dynamic_cast(_parent.operator->()); @@ -319,7 +319,7 @@ } } -- (void)windowDidExitFullScreen:(NSNotification *)notification +- (void)windowDidExitFullScreen:(NSNotification *_Nonnull)notification { auto parent = dynamic_cast(_parent.operator->()); @@ -342,7 +342,7 @@ } } -- (void)windowWillEnterFullScreen:(NSNotification *)notification +- (void)windowWillEnterFullScreen:(NSNotification *_Nonnull)notification { auto parent = dynamic_cast(_parent.operator->()); @@ -352,7 +352,7 @@ } } -- (void)windowDidEnterFullScreen:(NSNotification *)notification +- (void)windowDidEnterFullScreen:(NSNotification *_Nonnull)notification { auto parent = dynamic_cast(_parent.operator->()); @@ -363,7 +363,7 @@ } } -- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame +- (BOOL)windowShouldZoom:(NSWindow *_Nonnull)window toFrame:(NSRect)newFrame { return true; } @@ -380,7 +380,7 @@ [super resignKeyWindow]; } -- (void)windowDidMove:(NSNotification *)notification +- (void)windowDidMove:(NSNotification *_Nonnull)notification { AvnPoint position; @@ -412,7 +412,7 @@ return pt; } -- (void)sendEvent:(NSEvent *)event +- (void)sendEvent:(NSEvent *_Nonnull)event { [super sendEvent:event]; diff --git a/native/Avalonia.Native/src/OSX/INSWindowHolder.h b/native/Avalonia.Native/src/OSX/INSWindowHolder.h index ae64a53e7d..3c5010966b 100644 --- a/native/Avalonia.Native/src/OSX/INSWindowHolder.h +++ b/native/Avalonia.Native/src/OSX/INSWindowHolder.h @@ -11,7 +11,7 @@ struct INSWindowHolder { virtual NSWindow* _Nonnull GetNSWindow () = 0; - virtual NSView* _Nonnull GetNSView () = 0; + virtual AvnView* _Nonnull GetNSView () = 0; }; #endif //AVALONIA_NATIVE_OSX_INSWINDOWHOLDER_H diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 4220811fc7..040ba39b6d 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -38,7 +38,7 @@ BEGIN_INTERFACE_MAP() virtual NSWindow *GetNSWindow() override; - virtual NSView *GetNSView() override; + virtual AvnView *GetNSView() override; virtual HRESULT Show(bool activate, bool isDialog) override; diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index e88c7f208c..c420736b46 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -70,7 +70,7 @@ NSWindow *WindowBaseImpl::GetNSWindow() { return Window; } -NSView *WindowBaseImpl::GetNSView() { +AvnView *WindowBaseImpl::GetNSView() { return View; } From b6e66047f21cec797302c305b487b93881b7fa1c Mon Sep 17 00:00:00 2001 From: daniel mayost Date: Wed, 1 Jun 2022 13:54:50 +0300 Subject: [PATCH 237/332] add fixes --- src/Avalonia.Controls/ComboBox.cs | 11 ++++++----- .../FlowDirectionTests.cs | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs index 5ba1195159..05be5ad00d 100644 --- a/src/Avalonia.Controls/ComboBox.cs +++ b/src/Avalonia.Controls/ComboBox.cs @@ -434,11 +434,12 @@ namespace Avalonia.Controls { if (SelectionBoxItem is Rectangle rectangle) { - var content = (rectangle.Fill as VisualBrush)!.Visual as Control; - var flowDirection = (((IVisual)content!).VisualParent as Control)?.FlowDirection ?? - FlowDirection.LeftToRight; - - rectangle.FlowDirection = flowDirection; + if ((rectangle.Fill as VisualBrush)?.Visual is Control content) + { + var flowDirection = (((IVisual)content!).VisualParent as Control)?.FlowDirection ?? + FlowDirection.LeftToRight; + rectangle.FlowDirection = flowDirection; + } } } diff --git a/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs b/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs index 6739eff638..6c43103ecb 100644 --- a/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs +++ b/tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs @@ -17,7 +17,23 @@ namespace Avalonia.Controls.UnitTests } [Fact] - public void HasMirrorTransform_Of_Children_Is_Updated_After_Change() + public void HasMirrorTransform_Of_LTR_Children_Should_Be_True_For_RTL_Parent() + { + Control child; + var target = new Decorator + { + FlowDirection = FlowDirection.RightToLeft, + Child = child = new Control() + }; + + child.FlowDirection = FlowDirection.LeftToRight; + + Assert.True(target.HasMirrorTransform); + Assert.True(child.HasMirrorTransform); + } + + [Fact] + public void HasMirrorTransform_Of_Children_Is_Updated_After_Parent_Changeed() { Control child; var target = new Decorator From 2f1ada6892537f871705b829b565379d2411af88 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jun 2022 13:47:56 +0100 Subject: [PATCH 238/332] Merge pull request #8239 from AvaloniaUI/fixes/osx-shadow-invalidation OSX Shadow invalidation when window sized --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 8520e3e470..d1d5c2a014 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -140,6 +140,8 @@ void WindowImpl::BringToFront() [Window orderFront:nullptr]; } + [Window invalidateShadow]; + for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) { (*iterator)->BringToFront(); From cea6bc27a06f25b4f2d3a73d3411e904b1767e74 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 1 Jun 2022 13:49:00 +0100 Subject: [PATCH 239/332] Merge pull request #8238 from AvaloniaUI/fixes/disable-parent-chrome-buttons-when-modal-is-shown OSX: Disable parent chrome buttons when modal is shown --- native/Avalonia.Native/src/OSX/AvnWindow.mm | 11 ++++++--- native/Avalonia.Native/src/OSX/WindowImpl.mm | 24 +++++-------------- samples/ControlCatalog/Pages/DialogsPage.xaml | 2 +- .../ControlCatalog/Pages/DialogsPage.xaml.cs | 13 ++++++++++ 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 0b9ea093ac..9fc7ec4fec 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -176,9 +176,10 @@ _isExtended = false; -#ifdef IS_NSPANEL - [self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorFullScreenAuxiliary]; -#endif + if(self.isDialog) + { + [self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorFullScreenAuxiliary]; + } return self; } @@ -260,6 +261,10 @@ -(void) setEnabled:(bool)enable { _isEnabled = enable; + + [[self standardWindowButton:NSWindowCloseButton] setEnabled:enable]; + [[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:enable]; + [[self standardWindowButton:NSWindowZoomButton] setEnabled:enable]; } -(void)becomeKeyWindow diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index d1d5c2a014..555e9dff9b 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -30,24 +30,12 @@ void WindowImpl::HideOrShowTrafficLights() { return; } - for (id subview in Window.contentView.superview.subviews) { - if ([subview isKindOfClass:NSClassFromString(@"NSTitlebarContainerView")]) { - NSView *titlebarView = [subview subviews][0]; - for (id button in titlebarView.subviews) { - if ([button isKindOfClass:[NSButton class]]) { - if (_isClientAreaExtended) { - auto wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); - - [button setHidden:!wantsChrome]; - } else { - [button setHidden:(_decorations != SystemDecorationsFull)]; - } - - [button setWantsLayer:true]; - } - } - } - } + bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); + bool hasTrafficLights = _isClientAreaExtended ? !wantsChrome : _decorations != SystemDecorationsFull; + + [[Window standardWindowButton:NSWindowCloseButton] setHidden:hasTrafficLights]; + [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:hasTrafficLights]; + [[Window standardWindowButton:NSWindowZoomButton] setHidden:hasTrafficLights]; } void WindowImpl::OnInitialiseNSWindow(){ diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml b/samples/ControlCatalog/Pages/DialogsPage.xaml index 6ac9dcfe22..8a835867b3 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml @@ -20,7 +20,7 @@ Text="Window dialogs" /> - + diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs index bed9f4c62a..1853c83365 100644 --- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs @@ -151,6 +151,7 @@ namespace ControlCatalog.Pages private Window CreateSampleWindow() { Button button; + Button dialogButton; var window = new Window { @@ -167,6 +168,12 @@ namespace ControlCatalog.Pages HorizontalAlignment = HorizontalAlignment.Center, Content = "Click to close", IsDefault = true + }), + (dialogButton = new Button + { + HorizontalAlignment = HorizontalAlignment.Center, + Content = "Dialog", + IsDefault = false }) } }, @@ -174,6 +181,12 @@ namespace ControlCatalog.Pages }; button.Click += (_, __) => window.Close(); + dialogButton.Click += (_, __) => + { + var dialog = CreateSampleWindow(); + dialog.Height = 200; + dialog.ShowDialog(window); + }; return window; } From 9cc69eec227ed01bb14c15c9e665b2fd02ba19eb Mon Sep 17 00:00:00 2001 From: Oxc3 <61174136+Oxc3@users.noreply.github.com> Date: Wed, 1 Jun 2022 14:27:38 -0700 Subject: [PATCH 240/332] added ClipboardImpl with hooks to navigator.clipboard.readtext and naviagot.clipboard.writeText so Avalonia web can TextBox copy-paste works --- .../Avalonia.Web.Blazor/AvaloniaView.razor | 5 ++- src/Web/Avalonia.Web.Blazor/ClipboardImpl.cs | 34 +++++++++++++++++++ src/Web/Avalonia.Web.Blazor/WinStubs.cs | 15 -------- .../Avalonia.Web.Blazor/WindowingPlatform.cs | 2 +- 4 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 src/Web/Avalonia.Web.Blazor/ClipboardImpl.cs diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor index 3fe4c299cf..dd7eb0ec54 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor @@ -12,7 +12,10 @@
- +
+ + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + - + - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - + + + + + + + + + + diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs index bdd5cbbe2b..682fc622b8 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs @@ -628,11 +628,9 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'> - + From 5520706a954eef81fe5073d5a57c9634df0b6a18 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 2 Jun 2022 17:14:50 +0200 Subject: [PATCH 245/332] Fix formatting. --- src/Avalonia.Themes.Fluent/Controls/Button.xaml | 3 ++- src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Themes.Fluent/Controls/Button.xaml b/src/Avalonia.Themes.Fluent/Controls/Button.xaml index d8d7ab3696..3fb0d43342 100644 --- a/src/Avalonia.Themes.Fluent/Controls/Button.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/Button.xaml @@ -82,7 +82,8 @@ - + + - + + From 84a7d31f180f3fe5d88f08ad6e2a1b7fc04dff84 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 2 Jun 2022 16:30:50 +0100 Subject: [PATCH 246/332] Merge pull request #8248 from AvaloniaUI/fixes/prevent-parent-resizing-when-modal-opened [OSX] dont allow disabled windows to resize. --- native/Avalonia.Native/src/OSX/WindowImpl.h | 1 + native/Avalonia.Native/src/OSX/WindowImpl.mm | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index 76d5cbf6ea..627e29c03d 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -13,6 +13,7 @@ class WindowImpl : public virtual WindowBaseImpl, public virtual IAvnWindow, public IWindowStateChanged { private: + bool _isEnabled; bool _canResize; bool _fullScreenActive; SystemDecorations _decorations; diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 555e9dff9b..3c2224876a 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -10,6 +10,7 @@ #include "WindowProtocol.h" WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBaseImpl(events, gl) { + _isEnabled = true; _children = std::list(); _isClientAreaExtended = false; _extendClientHints = AvnDefaultChrome; @@ -76,7 +77,9 @@ HRESULT WindowImpl::SetEnabled(bool enable) { START_COM_CALL; @autoreleasepool { + _isEnabled = enable; [GetWindowProtocol() setEnabled:enable]; + UpdateStyle(); return S_OK; } } @@ -574,7 +577,7 @@ NSWindowStyleMask WindowImpl::GetStyle() { case SystemDecorationsFull: s = s | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable; - if (_canResize) { + if (_canResize && _isEnabled) { s = s | NSWindowStyleMaskResizable; } break; From 643fe6675e2ee7735cc106b4b63f83faf2680676 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 2 Jun 2022 18:39:16 +0100 Subject: [PATCH 247/332] prevent segfault when closing app with child windows open. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 3c2224876a..e6e704e149 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -91,11 +91,8 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { if(_parent != nullptr) { _parent->_children.remove(this); - auto parent = _parent; - dispatch_async(dispatch_get_main_queue(), ^{ - parent->BringToFront(); - }); + _parent->BringToFront(); } auto cparent = dynamic_cast(parent); @@ -122,20 +119,23 @@ HRESULT WindowImpl::SetParent(IAvnWindow *parent) { void WindowImpl::BringToFront() { - if(IsDialog()) + if(Window != nullptr) { - Activate(); - } - else - { - [Window orderFront:nullptr]; - } - - [Window invalidateShadow]; - - for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) - { - (*iterator)->BringToFront(); + if(IsDialog()) + { + Activate(); + } + else + { + [Window orderFront:nullptr]; + } + + [Window invalidateShadow]; + + for(auto iterator = _children.begin(); iterator != _children.end(); iterator++) + { + (*iterator)->BringToFront(); + } } } From 9e03c05713e1817243f580943c4ed178ec7b42e3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 2 Jun 2022 23:03:31 +0100 Subject: [PATCH 248/332] osx: fix crash when modal dialog is opened over fullscreen parent. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index e6e704e149..cae1c09513 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -564,6 +564,11 @@ bool WindowImpl::IsDialog() { NSWindowStyleMask WindowImpl::GetStyle() { unsigned long s = NSWindowStyleMaskBorderless; + + if(_actualWindowState == FullScreen) + { + s |= NSWindowStyleMaskFullScreen; + } switch (_decorations) { case SystemDecorationsNone: From a6d1e74b4fa1d14e7c9e2047865ec253558b0eca Mon Sep 17 00:00:00 2001 From: Oxc3 Date: Thu, 2 Jun 2022 16:22:44 -0700 Subject: [PATCH 249/332] RazorViewTopLevel will now test keys first on Code, then Key as a backup This is an android specific hack. the chrome browser event sends an empty string on Code property so this will test both Code and Key properties to match to an Avalonia key. If the user is on a sane system then Code will be used to Key match, else it will failover to try and match with Key. --- src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs | 4 ++-- src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index 1f411d0cee..7531dbf681 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -233,12 +233,12 @@ namespace Avalonia.Web.Blazor private void OnKeyDown(KeyboardEventArgs e) { - _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, e.Code, GetModifiers(e)); + _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyDown, e.Code, e.Key, GetModifiers(e)); } private void OnKeyUp(KeyboardEventArgs e) { - _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyUp, e.Code, GetModifiers(e)); + _topLevelImpl.RawKeyboardEvent(RawKeyEventType.KeyUp, e.Code, e.Key, GetModifiers(e)); } private void OnInput(ChangeEventArgs e) diff --git a/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs b/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs index 50070e6e2c..a8a1a970dc 100644 --- a/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs +++ b/src/Web/Avalonia.Web.Blazor/RazorViewTopLevelImpl.cs @@ -91,9 +91,16 @@ namespace Avalonia.Web.Blazor } } - public void RawKeyboardEvent(RawKeyEventType type, string key, RawInputModifiers modifiers) + public void RawKeyboardEvent(RawKeyEventType type, string code, string key, RawInputModifiers modifiers) { - if (Keycodes.KeyCodes.TryGetValue(key, out var avkey)) + if (Keycodes.KeyCodes.TryGetValue(code, out var avkey)) + { + if (_inputRoot is { }) + { + Input?.Invoke(new RawKeyEventArgs(KeyboardDevice, Timestamp, _inputRoot, type, avkey, modifiers)); + } + } + else if (Keycodes.KeyCodes.TryGetValue(key, out avkey)) { if (_inputRoot is { }) { From bd3bb6e47e8d7a8c61430a6aeeffa1489649ad60 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 2 Jun 2022 22:15:12 -0400 Subject: [PATCH 250/332] Check if BindingValue actually has a value --- src/Avalonia.Base/Reactive/TypedBindingAdapter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Reactive/TypedBindingAdapter.cs b/src/Avalonia.Base/Reactive/TypedBindingAdapter.cs index f60ef247d5..f75917a00e 100644 --- a/src/Avalonia.Base/Reactive/TypedBindingAdapter.cs +++ b/src/Avalonia.Base/Reactive/TypedBindingAdapter.cs @@ -30,13 +30,15 @@ namespace Avalonia.Reactive } catch (InvalidCastException e) { + var unwrappedValue = value.HasValue ? value.Value : null; + Logger.TryGet(LogEventLevel.Error, LogArea.Binding)?.Log( _target, "Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})", _property.Name, _property.PropertyType, - value.Value, - value.Value?.GetType()); + unwrappedValue, + unwrappedValue?.GetType()); PublishNext(BindingValue.BindingError(e)); } } From 2a2779f2487bcf306796436d016ec243e3aa1ce3 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 2 Jun 2022 22:57:01 -0400 Subject: [PATCH 251/332] Stop listening for IsCancel on button detached --- src/Avalonia.Controls/Button.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs index db4ca6bc43..6dba33516b 100644 --- a/src/Avalonia.Controls/Button.cs +++ b/src/Avalonia.Controls/Button.cs @@ -232,6 +232,13 @@ namespace Avalonia.Controls StopListeningForDefault(inputElement); } } + if (IsCancel) + { + if (e.Root is IInputElement inputElement) + { + StopListeningForCancel(inputElement); + } + } } /// From 210727175aead0e15d77eba795e579b3f4177e83 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Thu, 2 Jun 2022 23:11:44 -0400 Subject: [PATCH 252/332] Add simple IsDefault/IsCancel tests --- .../ButtonTests.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs index f4acf5ea37..2e3623cc3c 100644 --- a/tests/Avalonia.Controls.UnitTests/ButtonTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ButtonTests.cs @@ -309,6 +309,80 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(0, raised); } + + [Fact] + public void Button_IsDefault_Works() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var raised = 0; + var target = new Button(); + var window = new Window { Content = target }; + window.Show(); + + target.Click += (s, e) => ++raised; + + target.IsDefault = false; + window.RaiseEvent(CreateKeyDownEvent(Key.Enter)); + Assert.Equal(0, raised); + + target.IsDefault = true; + window.RaiseEvent(CreateKeyDownEvent(Key.Enter)); + Assert.Equal(1, raised); + + target.IsDefault = false; + window.RaiseEvent(CreateKeyDownEvent(Key.Enter)); + Assert.Equal(1, raised); + + target.IsDefault = true; + window.RaiseEvent(CreateKeyDownEvent(Key.Enter)); + Assert.Equal(2, raised); + + window.Content = null; + // To check if handler was raised on the button, when it's detached, we need to pass it as a source manually. + window.RaiseEvent(CreateKeyDownEvent(Key.Enter, target)); + Assert.Equal(2, raised); + } + } + + [Fact] + public void Button_IsCancel_Works() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var raised = 0; + var target = new Button(); + var window = new Window { Content = target }; + window.Show(); + + target.Click += (s, e) => ++raised; + + target.IsCancel = false; + window.RaiseEvent(CreateKeyDownEvent(Key.Escape)); + Assert.Equal(0, raised); + + target.IsCancel = true; + window.RaiseEvent(CreateKeyDownEvent(Key.Escape)); + Assert.Equal(1, raised); + + target.IsCancel = false; + window.RaiseEvent(CreateKeyDownEvent(Key.Escape)); + Assert.Equal(1, raised); + + target.IsCancel = true; + window.RaiseEvent(CreateKeyDownEvent(Key.Escape)); + Assert.Equal(2, raised); + + window.Content = null; + window.RaiseEvent(CreateKeyDownEvent(Key.Escape, target)); + Assert.Equal(2, raised); + } + } + + private KeyEventArgs CreateKeyDownEvent(Key key, IInteractive source = null) + { + return new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key, Source = source }; + } private class TestButton : Button, IRenderRoot { From bd0d81d6afea1554a8f79d1a432d86de9838efe5 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 11:08:32 +0100 Subject: [PATCH 253/332] fix logic for deciding if chrome buttons should be shown or not in extended mode. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index cae1c09513..ef2a91ef14 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -32,7 +32,7 @@ void WindowImpl::HideOrShowTrafficLights() { } bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); - bool hasTrafficLights = _isClientAreaExtended ? !wantsChrome : _decorations != SystemDecorationsFull; + bool hasTrafficLights = _isClientAreaExtended ? wantsChrome : _decorations != SystemDecorationsFull; [[Window standardWindowButton:NSWindowCloseButton] setHidden:hasTrafficLights]; [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:hasTrafficLights]; From e446a66d6ab48ba0ab5982a6a379efe7d401d85b Mon Sep 17 00:00:00 2001 From: kaminova Date: Fri, 3 Jun 2022 12:29:39 +0200 Subject: [PATCH 254/332] Fix calculation of inverted matrix --- src/Avalonia.Base/Matrix.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Matrix.cs b/src/Avalonia.Base/Matrix.cs index 5bbc657385..8d3227378f 100644 --- a/src/Avalonia.Base/Matrix.cs +++ b/src/Avalonia.Base/Matrix.cs @@ -450,13 +450,13 @@ namespace Avalonia inverted = new Matrix( (_m22 * _m33 - _m32 * _m23) * invdet, - (_m13 * _m31 - _m12 * _m33) * invdet, + (_m13 * _m32 - _m12 * _m33) * invdet, (_m12 * _m23 - _m13 * _m22) * invdet, (_m23 * _m31 - _m21 * _m33) * invdet, (_m11 * _m33 - _m13 * _m31) * invdet, (_m21 * _m13 - _m11 * _m23) * invdet, (_m21 * _m32 - _m31 * _m22) * invdet, - (_m21 * _m12 - _m11 * _m32) * invdet, + (_m31 * _m12 - _m11 * _m32) * invdet, (_m11 * _m22 - _m21 * _m12) * invdet ); From 6a848a389fb2ca600ed4173d5f121b14b97e24cb Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 11:34:20 +0100 Subject: [PATCH 255/332] dont re-initialise nswindow on show. --- native/Avalonia.Native/src/OSX/WindowBaseImpl.mm | 2 -- 1 file changed, 2 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index c420736b46..bf221047f9 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -90,8 +90,6 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { START_COM_CALL; @autoreleasepool { - InitialiseNSWindow(); - if(hasPosition) { SetPosition(lastPositionSet); From 809f459233f018111cacb39e2564ff242b612b4a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 11:39:03 +0100 Subject: [PATCH 256/332] fix osx thick titlebar setting. --- samples/ControlCatalog/MainWindow.xaml.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs index 20591103b7..8ee8b2ebd4 100644 --- a/samples/ControlCatalog/MainWindow.xaml.cs +++ b/samples/ControlCatalog/MainWindow.xaml.cs @@ -29,8 +29,6 @@ namespace ControlCatalog DataContext = new MainWindowViewModel(_notificationArea); _recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu; - - ExtendClientAreaChromeHints = Avalonia.Platform.ExtendClientAreaChromeHints.OSXThickTitleBar; } public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit"; From 11595184d5e87520073dbba37b0afd8cce1d3a2e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 11:39:14 +0100 Subject: [PATCH 257/332] fix traffic light setting. --- native/Avalonia.Native/src/OSX/WindowImpl.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index ef2a91ef14..f49b676ce6 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -32,11 +32,11 @@ void WindowImpl::HideOrShowTrafficLights() { } bool wantsChrome = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome); - bool hasTrafficLights = _isClientAreaExtended ? wantsChrome : _decorations != SystemDecorationsFull; + bool hasTrafficLights = _isClientAreaExtended ? wantsChrome : _decorations == SystemDecorationsFull; - [[Window standardWindowButton:NSWindowCloseButton] setHidden:hasTrafficLights]; - [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:hasTrafficLights]; - [[Window standardWindowButton:NSWindowZoomButton] setHidden:hasTrafficLights]; + [[Window standardWindowButton:NSWindowCloseButton] setHidden:!hasTrafficLights]; + [[Window standardWindowButton:NSWindowMiniaturizeButton] setHidden:!hasTrafficLights]; + [[Window standardWindowButton:NSWindowZoomButton] setHidden:!hasTrafficLights]; } void WindowImpl::OnInitialiseNSWindow(){ From 6e916c21e5d5effba473013086b111123c38cf26 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 11:46:30 +0100 Subject: [PATCH 258/332] fix transition to fullscreen mode. --- native/Avalonia.Native/src/OSX/AvnWindow.mm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index 9fc7ec4fec..f6dcd0cabf 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -33,6 +33,7 @@ bool _isEnabled; bool _canBecomeKeyWindow; bool _isExtended; + bool _isTransitioningToFullScreen; AvnMenu* _menu; } @@ -175,6 +176,7 @@ [self setBackgroundColor: [NSColor clearColor]]; _isExtended = false; + _isTransitioningToFullScreen = false; if(self.isDialog) { @@ -349,6 +351,7 @@ - (void)windowWillEnterFullScreen:(NSNotification *_Nonnull)notification { + _isTransitioningToFullScreen = true; auto parent = dynamic_cast(_parent.operator->()); if(parent != nullptr) @@ -359,6 +362,7 @@ - (void)windowDidEnterFullScreen:(NSNotification *_Nonnull)notification { + _isTransitioningToFullScreen = false; auto parent = dynamic_cast(_parent.operator->()); if(parent != nullptr) @@ -441,7 +445,10 @@ _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast([event timestamp] * 1000), AvnInputModifiersNone, point, delta); } - _parent->BringToFront(); + if(!_isTransitioningToFullScreen) + { + _parent->BringToFront(); + } } break; From e2dbf68b02b3a67079d84ef7d2815ace38843b20 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 12:20:25 +0100 Subject: [PATCH 259/332] fix call to virtual method from ctor. --- native/Avalonia.Native/src/OSX/PopupImpl.mm | 6 +----- native/Avalonia.Native/src/OSX/WindowBaseImpl.h | 2 -- native/Avalonia.Native/src/OSX/WindowBaseImpl.mm | 7 ------- native/Avalonia.Native/src/OSX/WindowImpl.h | 3 +-- native/Avalonia.Native/src/OSX/WindowImpl.mm | 3 +++ 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/PopupImpl.mm b/native/Avalonia.Native/src/OSX/PopupImpl.mm index 3c5afd9424..9820a9f052 100644 --- a/native/Avalonia.Native/src/OSX/PopupImpl.mm +++ b/native/Avalonia.Native/src/OSX/PopupImpl.mm @@ -26,17 +26,13 @@ private: PopupImpl(IAvnWindowEvents* events, IAvnGlContext* gl) : WindowBaseImpl(events, gl) { WindowEvents = events; + [Window setLevel:NSPopUpMenuWindowLevel]; } protected: virtual NSWindowStyleMask GetStyle() override { return NSWindowStyleMaskBorderless; } - - virtual void OnInitialiseNSWindow () override - { - [Window setLevel:NSPopUpMenuWindowLevel]; - } public: virtual bool ShouldTakeFocusOnShow() override diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 040ba39b6d..787827c9b4 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -106,8 +106,6 @@ protected: virtual NSWindowStyleMask GetStyle(); void UpdateStyle(); - - virtual void OnInitialiseNSWindow (); private: void CreateNSWindow (bool isDialog); diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index bf221047f9..ea9ef3c9de 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -567,11 +567,6 @@ void WindowBaseImpl::CreateNSWindow(bool isDialog) { } } -void WindowBaseImpl::OnInitialiseNSWindow() -{ - -} - void WindowBaseImpl::InitialiseNSWindow() { if(Window != nullptr) { [Window setContentView:StandardContainer]; @@ -594,8 +589,6 @@ void WindowBaseImpl::InitialiseNSWindow() { [GetWindowProtocol() showWindowMenuWithAppMenu]; } } - - OnInitialiseNSWindow(); } } diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.h b/native/Avalonia.Native/src/OSX/WindowImpl.h index 627e29c03d..b4b1d4e70b 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowImpl.h @@ -93,8 +93,6 @@ BEGIN_INTERFACE_MAP() virtual bool IsDialog() override; - virtual void OnInitialiseNSWindow() override; - virtual void BringToFront () override; bool CanBecomeKeyWindow (); @@ -103,6 +101,7 @@ protected: virtual NSWindowStyleMask GetStyle() override; private: + void OnInitialiseNSWindow(); NSString *_lastTitle; }; diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index f49b676ce6..382cd0db95 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -24,6 +24,8 @@ WindowImpl::WindowImpl(IAvnWindowEvents *events, IAvnGlContext *gl) : WindowBase _lastTitle = @""; _parent = nullptr; WindowEvents = events; + + OnInitialiseNSWindow(); } void WindowImpl::HideOrShowTrafficLights() { @@ -41,6 +43,7 @@ void WindowImpl::HideOrShowTrafficLights() { void WindowImpl::OnInitialiseNSWindow(){ [GetWindowProtocol() setCanBecomeKeyWindow:true]; + [Window disableCursorRects]; [Window setTabbingMode:NSWindowTabbingModeDisallowed]; [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; From 164757c915ec36e422231479c24676b0640ee0bd Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 3 Jun 2022 13:41:09 +0200 Subject: [PATCH 260/332] Make NumericUpDown nullable --- .../NumericUpDown/NumericUpDown.cs | 111 +++++++++++------- .../NumericUpDownValueChangedEventArgs.cs | 6 +- 2 files changed, 73 insertions(+), 44 deletions(-) diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index 4d86a0f17c..705e68e3ea 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -107,8 +107,8 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly DirectProperty ValueProperty = - AvaloniaProperty.RegisterDirect(nameof(Value), updown => updown.Value, + public static readonly DirectProperty ValueProperty = + AvaloniaProperty.RegisterDirect(nameof(Value), updown => updown.Value, (updown, v) => updown.Value = v, defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); /// @@ -131,7 +131,7 @@ namespace Avalonia.Controls private IDisposable? _textBoxTextChangedSubscription; - private decimal _value; + private decimal? _value; private string? _text; private bool _internalValueSet; private bool _clipValueToMinMax; @@ -277,7 +277,7 @@ namespace Avalonia.Controls /// /// Gets or sets the value. /// - public decimal Value + public decimal? Value { get { return _value; } set @@ -351,7 +351,7 @@ namespace Avalonia.Controls /// protected override void OnLostFocus(RoutedEventArgs e) { - CommitInput(); + CommitInput(true); base.OnLostFocus(e); } @@ -489,9 +489,9 @@ namespace Avalonia.Controls { SetValidSpinDirection(); } - if (ClipValueToMinMax) + if (ClipValueToMinMax && Value.HasValue) { - Value = MathUtilities.Clamp(Value, Minimum, Maximum); + Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum); } } @@ -506,9 +506,9 @@ namespace Avalonia.Controls { SetValidSpinDirection(); } - if (ClipValueToMinMax) + if (ClipValueToMinMax && Value.HasValue) { - Value = MathUtilities.Clamp(Value, Minimum, Maximum); + Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum); } } @@ -530,7 +530,7 @@ namespace Avalonia.Controls /// /// The old value. /// The new value. - protected virtual void OnValueChanged(decimal oldValue, decimal newValue) + protected virtual void OnValueChanged(decimal? oldValue, decimal? newValue) { if (!_internalValueSet && IsInitialized) { @@ -573,7 +573,7 @@ namespace Avalonia.Controls /// Called when the property has to be coerced. ///
/// The value. - protected virtual decimal OnCoerceValue(decimal baseValue) + protected virtual decimal? OnCoerceValue(decimal? baseValue) { return baseValue; } @@ -607,7 +607,7 @@ namespace Avalonia.Controls ///
/// The old value. /// The new value. - protected virtual void RaiseValueChangedEvent(decimal oldValue, decimal newValue) + protected virtual void RaiseValueChangedEvent(decimal? oldValue, decimal? newValue) { var e = new NumericUpDownValueChangedEventArgs(ValueChangedEvent, oldValue, newValue); RaiseEvent(e); @@ -616,9 +616,9 @@ namespace Avalonia.Controls /// /// Converts the formatted text to a value. /// - private decimal ConvertTextToValue(string text) + private decimal? ConvertTextToValue(string? text) { - decimal result = 0; + decimal? result = null; if (string.IsNullOrEmpty(text)) { @@ -635,9 +635,9 @@ namespace Avalonia.Controls result = ConvertTextToValueCore(currentValueText, text); - if (ClipValueToMinMax) + if (ClipValueToMinMax && result.HasValue) { - return MathUtilities.Clamp(result, Minimum, Maximum); + return MathUtilities.Clamp(result.Value, Minimum, Maximum); } ValidateMinMax(result); @@ -649,7 +649,7 @@ namespace Avalonia.Controls /// Converts the value to formatted text. /// /// - private string ConvertValueToText() + private string? ConvertValueToText() { //Manage FormatString of type "{}{0:N2} °" (in xaml) or "{0:N2} °" in code-behind. if (FormatString.Contains("{0")) @@ -657,7 +657,7 @@ namespace Avalonia.Controls return string.Format(NumberFormat, FormatString, Value); } - return Value.ToString(FormatString, NumberFormat); + return Value?.ToString(FormatString, NumberFormat); } /// @@ -665,7 +665,16 @@ namespace Avalonia.Controls /// private void OnIncrement() { - var result = Value + Increment; + decimal result; + if (Value.HasValue) + { + result = Value.Value + Increment; + } + else + { + result = Minimum; + } + Value = MathUtilities.Clamp(result, Minimum, Maximum); } @@ -674,7 +683,17 @@ namespace Avalonia.Controls /// private void OnDecrement() { - var result = Value - Increment; + decimal result; + + if (Value.HasValue) + { + result = Value.Value - Increment; + } + else + { + result = Maximum; + } + Value = MathUtilities.Clamp(result, Minimum, Maximum); } @@ -688,6 +707,11 @@ namespace Avalonia.Controls // Zero increment always prevents spin. if (Increment != 0 && !IsReadOnly) { + if (!Value.HasValue) + { + validDirections = ValidSpinDirections.Increase | ValidSpinDirections.Decrease; + } + if (Value < Maximum) { validDirections = validDirections | ValidSpinDirections.Increase; @@ -825,13 +849,13 @@ namespace Avalonia.Controls { if (e.Sender is NumericUpDown upDown) { - var oldValue = (decimal)e.OldValue!; - var newValue = (decimal)e.NewValue!; + var oldValue = (decimal?)e.OldValue; + var newValue = (decimal?)e.NewValue; upDown.OnValueChanged(oldValue, newValue); } } - private void SetValueInternal(decimal value) + private void SetValueInternal(decimal? value) { _internalValueSet = true; try @@ -946,9 +970,9 @@ namespace Avalonia.Controls remove { RemoveHandler(ValueChangedEvent, value); } } - private bool CommitInput() + private bool CommitInput(bool forceTextUpdate = false) { - return SyncTextAndValueProperties(true, Text); + return SyncTextAndValueProperties(true, Text, forceTextUpdate); } /// @@ -978,28 +1002,24 @@ namespace Avalonia.Controls { if (updateValueFromText) { - if (!string.IsNullOrEmpty(text)) + try { - try + var newValue = ConvertTextToValue(text); + if (!Equals(newValue, Value)) { - var newValue = ConvertTextToValue(text); - if (!Equals(newValue, Value)) - { - SetValueInternal(newValue); - } - } - catch - { - parsedTextIsValid = false; + SetValueInternal(newValue); } } + catch + { + parsedTextIsValid = false; + } } // Do not touch the ongoing text input from user. if (!_isTextChangedFromUI) { - var keepEmpty = !forceTextUpdate && string.IsNullOrEmpty(Text); - if (!keepEmpty) + if (forceTextUpdate) { var newText = ConvertValueToText(); if (!Equals(Text, newText)) @@ -1036,10 +1056,15 @@ namespace Avalonia.Controls return parsedTextIsValid; } - private decimal ConvertTextToValueCore(string currentValueText, string text) + private decimal? ConvertTextToValueCore(string? currentValueText, string? text) { decimal result; + if (string.IsNullOrEmpty(text)) + { + return null; + } + if (IsPercent(FormatString)) { result = ParsePercent(text, NumberFormat); @@ -1052,7 +1077,7 @@ namespace Avalonia.Controls var shouldThrow = true; // Check if CurrentValueText is also failing => it also contains special characters. ex : 90° - if (!decimal.TryParse(currentValueText, ParsingNumberStyle, NumberFormat, out var _)) + if (!string.IsNullOrEmpty(currentValueText) && !decimal.TryParse(currentValueText, ParsingNumberStyle, NumberFormat, out var _)) { // extract non-digit characters var currentValueTextSpecialCharacters = currentValueText.Where(c => !char.IsDigit(c)); @@ -1082,8 +1107,12 @@ namespace Avalonia.Controls return result; } - private void ValidateMinMax(decimal value) + private void ValidateMinMax(decimal? value) { + if (!value.HasValue) + { + return; + } if (value < Minimum) { throw new ArgumentOutOfRangeException(nameof(value), string.Format("Value must be greater than Minimum value of {0}", Minimum)); diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDownValueChangedEventArgs.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDownValueChangedEventArgs.cs index 9b467d682c..af835541ae 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDownValueChangedEventArgs.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDownValueChangedEventArgs.cs @@ -4,13 +4,13 @@ namespace Avalonia.Controls { public class NumericUpDownValueChangedEventArgs : RoutedEventArgs { - public NumericUpDownValueChangedEventArgs(RoutedEvent routedEvent, decimal oldValue, decimal newValue) : base(routedEvent) + public NumericUpDownValueChangedEventArgs(RoutedEvent routedEvent, decimal? oldValue, decimal? newValue) : base(routedEvent) { OldValue = oldValue; NewValue = newValue; } - public decimal OldValue { get; } - public decimal NewValue { get; } + public decimal? OldValue { get; } + public decimal? NewValue { get; } } } From 43cf66fc49fa6f6e431e26fd747d2bb6edd02eae Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 3 Jun 2022 13:41:28 +0200 Subject: [PATCH 261/332] Update demo to reflect actual selected value --- samples/ControlCatalog/Pages/NumericUpDownPage.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml index 9ddc6b6228..e32632dac2 100644 --- a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml +++ b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml @@ -65,7 +65,7 @@ Margin="2" HorizontalAlignment="Center"/> Value: - From e47b742d3eb5e2fe8b0ddf0a1b65b8c999aa35bd Mon Sep 17 00:00:00 2001 From: Patrick Tellier Date: Fri, 3 Jun 2022 14:35:46 +0200 Subject: [PATCH 262/332] Use own Pen (if set) in GeometryDrawing.GetBounds --- src/Avalonia.Base/Media/GeometryDrawing.cs | 3 +- .../Media/GeometryDrawingTests.cs | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs diff --git a/src/Avalonia.Base/Media/GeometryDrawing.cs b/src/Avalonia.Base/Media/GeometryDrawing.cs index e46e3a7d5f..08e62df2cc 100644 --- a/src/Avalonia.Base/Media/GeometryDrawing.cs +++ b/src/Avalonia.Base/Media/GeometryDrawing.cs @@ -68,7 +68,8 @@ namespace Avalonia.Media public override Rect GetBounds() { - return Geometry?.GetRenderBounds(s_boundsPen) ?? Rect.Empty; + IPen pen = Pen ?? s_boundsPen; + return Geometry?.GetRenderBounds(pen) ?? Rect.Empty; } } } diff --git a/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs b/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs new file mode 100644 index 0000000000..06e46c1a06 --- /dev/null +++ b/tests/Avalonia.RenderTests/Media/GeometryDrawingTests.cs @@ -0,0 +1,52 @@ +using Avalonia.Media; +using Xunit; + +#if AVALONIA_SKIA +namespace Avalonia.Skia.RenderTests +#else + +using Avalonia.Direct2D1.RenderTests; + +namespace Avalonia.Direct2D1.RenderTests.Media +#endif +{ + public class GeometryDrawingTests : TestBase + { + public GeometryDrawingTests() + : base(@"Media\GeometryDrawing") + { + } + + private GeometryDrawing CreateGeometryDrawing() + { + GeometryDrawing geometryDrawing = new GeometryDrawing(); + EllipseGeometry ellipse = new EllipseGeometry(); + ellipse.RadiusX = 100; + ellipse.RadiusY = 100; + geometryDrawing.Geometry = ellipse; + return geometryDrawing; + } + + [Fact] + public void DrawingGeometry_WithPen() + { + GeometryDrawing geometryDrawing = CreateGeometryDrawing(); + geometryDrawing.Pen = new Pen(new SolidColorBrush(Color.FromArgb(255, 0, 0, 0)), 10); + + Assert.Equal(210, geometryDrawing.GetBounds().Height); + Assert.Equal(210, geometryDrawing.GetBounds().Width); + + } + + [Fact] + public void DrawingGeometry_WithoutPen() + { + GeometryDrawing geometryDrawing = CreateGeometryDrawing(); + + Assert.Equal(200, geometryDrawing.GetBounds().Height); + Assert.Equal(200, geometryDrawing.GetBounds().Width); + } + + + } +} From 0470369af056c13d5af388e827cf39eaf394cec1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 15:20:22 +0100 Subject: [PATCH 263/332] osx: ensure shadow is invalidated on show. --- native/Avalonia.Native/src/OSX/WindowBaseImpl.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index ea9ef3c9de..46f2ac0092 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -99,6 +99,8 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { } UpdateStyle(); + + [Window invalidateShadow]; if (ShouldTakeFocusOnShow() && activate) { [Window orderFront:Window]; From e5a3820fbb05fe57de89353a2d58bf504b92e648 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 15:40:01 +0100 Subject: [PATCH 264/332] whenever we become key... dispatch invalidateShadow --- native/Avalonia.Native/src/OSX/AvnWindow.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/AvnWindow.mm b/native/Avalonia.Native/src/OSX/AvnWindow.mm index f6dcd0cabf..ebd9f39d30 100644 --- a/native/Avalonia.Native/src/OSX/AvnWindow.mm +++ b/native/Avalonia.Native/src/OSX/AvnWindow.mm @@ -284,6 +284,14 @@ - (void)windowDidBecomeKey:(NSNotification *_Nonnull)notification { _parent->BringToFront(); + + dispatch_async(dispatch_get_main_queue(), ^{ + @try { + [self invalidateShadow]; + } + @finally{ + } + }); } - (void)windowDidMiniaturize:(NSNotification *_Nonnull)notification From eaf8fec5cfaa6e195afeaedded1ac0234f73b4ec Mon Sep 17 00:00:00 2001 From: kaminova Date: Fri, 3 Jun 2022 18:10:50 +0200 Subject: [PATCH 265/332] Test for matrix inversion --- tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs b/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs index 98b1ff0e28..f25047c5c5 100644 --- a/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs +++ b/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs @@ -30,6 +30,16 @@ namespace Avalonia.Base.UnitTests.Media Assert.True(matrix.HasInverse); } + [Fact] + public void Invert_Should_Work() + { + var matrix = new Matrix(1, 2, 3, 0, 1, 4,5,6,0); + var inverted = matrix.Invert(); + var expected = new Matrix(-24, 18, 5, 20, -15, -4, -5, 4, 1); + + Assert.Equal(expected, inverted); + } + [Fact] public void Can_Decompose_Translation() { From 987a69aafb2097c0b6c9e2bfadeb9b7f415fa727 Mon Sep 17 00:00:00 2001 From: kaminova Date: Fri, 3 Jun 2022 18:12:39 +0200 Subject: [PATCH 266/332] spaces --- tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs b/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs index f25047c5c5..b30996ca1e 100644 --- a/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs +++ b/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs @@ -33,7 +33,7 @@ namespace Avalonia.Base.UnitTests.Media [Fact] public void Invert_Should_Work() { - var matrix = new Matrix(1, 2, 3, 0, 1, 4,5,6,0); + var matrix = new Matrix(1, 2, 3, 0, 1, 4, 5, 6, 0); var inverted = matrix.Invert(); var expected = new Matrix(-24, 18, 5, 20, -15, -4, -5, 4, 1); From 5f5fc6e01fd7717d7ba3b463b72e3e80c70f09e8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 17:22:33 +0100 Subject: [PATCH 267/332] osx: restore missing api for cef - electron compatibility --- native/Avalonia.Native/src/OSX/app.mm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/native/Avalonia.Native/src/OSX/app.mm b/native/Avalonia.Native/src/OSX/app.mm index 14f1f6888c..a15d0c9601 100644 --- a/native/Avalonia.Native/src/OSX/app.mm +++ b/native/Avalonia.Native/src/OSX/app.mm @@ -82,6 +82,17 @@ ComPtr _events; _isHandlingSendEvent = oldHandling; } } + +// This is needed for certain embedded controls DO NOT REMOVE.. +- (BOOL) isHandlingSendEvent +{ + return _isHandlingSendEvent; +} + +- (void)setHandlingSendEvent:(BOOL)handlingSendEvent +{ + _isHandlingSendEvent = handlingSendEvent; +} @end extern void InitializeAvnApp(IAvnApplicationEvents* events) From 0907e9519a11f2b830592e96b07daebfba179dad Mon Sep 17 00:00:00 2001 From: kaminova Date: Fri, 3 Jun 2022 19:44:41 +0200 Subject: [PATCH 268/332] Fix test --- tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs b/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs index b30996ca1e..4aa13fab3a 100644 --- a/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs +++ b/tests/Avalonia.Base.UnitTests/Media/MatrixTests.cs @@ -35,9 +35,9 @@ namespace Avalonia.Base.UnitTests.Media { var matrix = new Matrix(1, 2, 3, 0, 1, 4, 5, 6, 0); var inverted = matrix.Invert(); - var expected = new Matrix(-24, 18, 5, 20, -15, -4, -5, 4, 1); - Assert.Equal(expected, inverted); + Assert.Equal(matrix * inverted, Matrix.Identity); + Assert.Equal(inverted * matrix, Matrix.Identity); } [Fact] From 8c6759990d38119eed7a40b9ac9c4027bb2864d1 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 3 Jun 2022 20:45:35 +0300 Subject: [PATCH 269/332] [X11] Added support for the basic version of _NET_WM_SYNC_REQUEST protocol --- src/Avalonia.X11/X11Atoms.cs | 1 + src/Avalonia.X11/X11Info.cs | 10 ++++++++ src/Avalonia.X11/X11Window.cs | 44 +++++++++++++++++++++++++++-------- src/Avalonia.X11/XLib.cs | 17 ++++++++++++++ 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.X11/X11Atoms.cs b/src/Avalonia.X11/X11Atoms.cs index b59883ef94..cfda68f9e8 100644 --- a/src/Avalonia.X11/X11Atoms.cs +++ b/src/Avalonia.X11/X11Atoms.cs @@ -155,6 +155,7 @@ namespace Avalonia.X11 public readonly IntPtr _NET_FRAME_EXTENTS; public readonly IntPtr _NET_WM_PING; public readonly IntPtr _NET_WM_SYNC_REQUEST; + public readonly IntPtr _NET_WM_SYNC_REQUEST_COUNTER; public readonly IntPtr _NET_SYSTEM_TRAY_S; public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION; public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE; diff --git a/src/Avalonia.X11/X11Info.cs b/src/Avalonia.X11/X11Info.cs index 9920907601..13dc460f45 100644 --- a/src/Avalonia.X11/X11Info.cs +++ b/src/Avalonia.X11/X11Info.cs @@ -33,6 +33,7 @@ namespace Avalonia.X11 public IntPtr LastActivityTimestamp { get; set; } public XVisualInfo? TransparentVisualInfo { get; set; } public bool HasXim { get; set; } + public bool HasXSync { get; set; } public IntPtr DefaultFontSet { get; set; } public unsafe X11Info(IntPtr display, IntPtr deferredDisplay, bool useXim) @@ -101,6 +102,15 @@ namespace Avalonia.X11 { //Ignore, XI is not supported } + + try + { + HasXSync = XSyncInitialize(display, out _, out _) != Status.Success; + } + catch + { + //Ignore, XSync is not supported + } } } } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 066156a652..6d0ca9422b 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -45,6 +45,8 @@ namespace Avalonia.X11 private IntPtr _handle; private IntPtr _xic; private IntPtr _renderHandle; + private IntPtr _xSyncCounter; + private XSyncValue _xSyncValue; private bool _mapped; private bool _wasMappedAtLeastOnce = false; private double? _scalingOverride; @@ -190,6 +192,16 @@ namespace Avalonia.X11 NativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle); NativeControlHost = new X11NativeControlHost(_platform, this); InitializeIme(); + + XChangeProperty(_x11.Display, _handle, _x11.Atoms.WM_PROTOCOLS, _x11.Atoms.XA_ATOM, 32, + PropertyMode.Replace, new[] { _x11.Atoms.WM_DELETE_WINDOW, _x11.Atoms._NET_WM_SYNC_REQUEST }, 2); + + if (_x11.HasXSync) + { + _xSyncCounter = XSyncCreateCounter(_x11.Display, _xSyncValue); + XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_SYNC_REQUEST_COUNTER, + _x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1); + } } class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo @@ -383,15 +395,7 @@ namespace Avalonia.X11 (ev.type == XEventName.VisibilityNotify && ev.VisibilityEvent.state < 2)) { - if (!_triggeredExpose) - { - _triggeredExpose = true; - Dispatcher.UIThread.Post(() => - { - _triggeredExpose = false; - DoPaint(); - }, DispatcherPriority.Render); - } + EnqueuePaint(); } else if (ev.type == XEventName.FocusIn) { @@ -503,6 +507,7 @@ namespace Avalonia.X11 if (_useRenderWindow) XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width, ev.ConfigureEvent.height); + EnqueuePaint(); } else if (ev.type == XEventName.DestroyNotify && ev.DestroyWindowEvent.window == _handle) @@ -518,7 +523,11 @@ namespace Avalonia.X11 if (Closing?.Invoke() != true) Dispose(); } - + else if (ev.ClientMessageEvent.ptr1 == _x11.Atoms._NET_WM_SYNC_REQUEST) + { + _xSyncValue.Lo = new UIntPtr(ev.ClientMessageEvent.ptr3.ToPointer()).ToUInt32(); + _xSyncValue.Hi = ev.ClientMessageEvent.ptr4.ToInt32(); + } } } else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease) @@ -730,9 +739,24 @@ namespace Avalonia.X11 ScheduleInput(mev, ref ev); } + void EnqueuePaint() + { + if (!_triggeredExpose) + { + _triggeredExpose = true; + Dispatcher.UIThread.Post(() => + { + _triggeredExpose = false; + DoPaint(); + }, DispatcherPriority.Render); + } + } + void DoPaint() { Paint?.Invoke(new Rect()); + if (_xSyncCounter != IntPtr.Zero) + XSyncSetCounter(_x11.Display, _xSyncCounter, _xSyncValue); } public void Invalidate(Rect rect) diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index e2b370821f..464ec4f1c8 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -542,6 +542,18 @@ namespace Avalonia.X11 public static extern int XRRQueryExtension (IntPtr dpy, out int event_base_return, out int error_base_return); + + [DllImport(libX11Ext)] + public static extern Status XSyncInitialize(IntPtr dpy, out int event_base_return, out int error_base_return); + + [DllImport(libX11Ext)] + public static extern IntPtr XSyncCreateCounter(IntPtr dpy, XSyncValue initialValue); + + [DllImport(libX11Ext)] + public static extern int XSyncDestroyCounter(IntPtr dpy, IntPtr counter); + + [DllImport(libX11Ext)] + public static extern int XSyncSetCounter(IntPtr dpy, IntPtr counter, XSyncValue value); [DllImport(libX11Randr)] public static extern int XRRQueryVersion(IntPtr dpy, @@ -627,6 +639,11 @@ namespace Avalonia.X11 public int bw; public int d; } + + public struct XSyncValue { + public int Hi; + public uint Lo; + } public static bool XGetGeometry(IntPtr display, IntPtr window, out XGeometry geo) { From 485d9b04a9ffd779055903a2b3b16273a75b86d9 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 3 Jun 2022 19:51:47 +0100 Subject: [PATCH 270/332] Merge pull request #8269 from AvaloniaUI/fixes/osx-setcontent-size-shadow-invalidation Fixes/osx setcontent size shadow invalidation --- .../Avalonia.Native/src/OSX/WindowBaseImpl.h | 1 - .../Avalonia.Native/src/OSX/WindowBaseImpl.mm | 41 ++++++------------- native/Avalonia.Native/src/OSX/WindowImpl.mm | 5 --- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h index 787827c9b4..2baf3b09b5 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.h +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.h @@ -110,7 +110,6 @@ protected: private: void CreateNSWindow (bool isDialog); void CleanNSWindow (); - void InitialiseNSWindow (); NSCursor *cursor; ComPtr _glContext; diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm index 46f2ac0092..7f2bb128da 100644 --- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm @@ -39,7 +39,16 @@ WindowBaseImpl::WindowBaseImpl(IAvnWindowBaseEvents *events, IAvnGlContext *gl, lastMenu = nullptr; CreateNSWindow(usePanel); - InitialiseNSWindow(); + + [Window setContentView:StandardContainer]; + [Window setStyleMask:NSWindowStyleMaskBorderless]; + [Window setBackingType:NSBackingStoreBuffered]; + + [Window setContentMinSize:lastMinSize]; + [Window setContentMaxSize:lastMaxSize]; + + [Window setOpaque:false]; + [Window setHasShadow:true]; } HRESULT WindowBaseImpl::ObtainNSViewHandle(void **ret) { @@ -90,6 +99,8 @@ HRESULT WindowBaseImpl::Show(bool activate, bool isDialog) { START_COM_CALL; @autoreleasepool { + [Window setContentSize:lastSize]; + if(hasPosition) { SetPosition(lastPositionSet); @@ -292,8 +303,7 @@ HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reaso if (!_shown) { BaseEvents->Resized(AvnSize{x, y}, reason); } - - if(Window != nullptr) { + else if(Window != nullptr) { [Window setContentSize:lastSize]; [Window invalidateShadow]; } @@ -569,31 +579,6 @@ void WindowBaseImpl::CreateNSWindow(bool isDialog) { } } -void WindowBaseImpl::InitialiseNSWindow() { - if(Window != nullptr) { - [Window setContentView:StandardContainer]; - [Window setStyleMask:NSWindowStyleMaskBorderless]; - [Window setBackingType:NSBackingStoreBuffered]; - - [Window setContentSize:lastSize]; - [Window setContentMinSize:lastMinSize]; - [Window setContentMaxSize:lastMaxSize]; - - [Window setOpaque:false]; - - [Window setHasShadow:true]; - [Window invalidateShadow]; - - if (lastMenu != nullptr) { - [GetWindowProtocol() applyMenu:lastMenu]; - - if ([Window isKeyWindow]) { - [GetWindowProtocol() showWindowMenuWithAppMenu]; - } - } - } -} - id WindowBaseImpl::GetWindowProtocol() { if(Window == nullptr) { diff --git a/native/Avalonia.Native/src/OSX/WindowImpl.mm b/native/Avalonia.Native/src/OSX/WindowImpl.mm index 382cd0db95..6db586f3ca 100644 --- a/native/Avalonia.Native/src/OSX/WindowImpl.mm +++ b/native/Avalonia.Native/src/OSX/WindowImpl.mm @@ -55,11 +55,6 @@ void WindowImpl::OnInitialiseNSWindow(){ [GetWindowProtocol() setIsExtended:true]; SetExtendClientArea(true); } - - if(_parent != nullptr) - { - SetParent(_parent); - } } HRESULT WindowImpl::Show(bool activate, bool isDialog) { From 9a82e65f5323bd3a3ff04b11a7e7dba0d6399f50 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 3 Jun 2022 23:53:01 +0300 Subject: [PATCH 271/332] [X11] Improve _NET_WM_SYNC_REQUEST handling --- src/Avalonia.X11/X11Window.cs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 6d0ca9422b..e7c4a37ea2 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -47,6 +47,7 @@ namespace Avalonia.X11 private IntPtr _renderHandle; private IntPtr _xSyncCounter; private XSyncValue _xSyncValue; + private XSyncState _xSyncState = 0; private bool _mapped; private bool _wasMappedAtLeastOnce = false; private double? _scalingOverride; @@ -54,6 +55,14 @@ namespace Avalonia.X11 private TransparencyHelper _transparencyHelper; private RawEventGrouper _rawEventGrouper; private bool _useRenderWindow = false; + + enum XSyncState + { + None, + WaitConfigure, + WaitPaint + } + public X11Window(AvaloniaX11Platform platform, IWindowImpl popupParent) { _platform = platform; @@ -507,7 +516,11 @@ namespace Avalonia.X11 if (_useRenderWindow) XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width, ev.ConfigureEvent.height); - EnqueuePaint(); + if (_xSyncState == XSyncState.WaitConfigure) + { + _xSyncState = XSyncState.WaitPaint; + EnqueuePaint(); + } } else if (ev.type == XEventName.DestroyNotify && ev.DestroyWindowEvent.window == _handle) @@ -527,6 +540,7 @@ namespace Avalonia.X11 { _xSyncValue.Lo = new UIntPtr(ev.ClientMessageEvent.ptr3.ToPointer()).ToUInt32(); _xSyncValue.Hi = ev.ClientMessageEvent.ptr4.ToInt32(); + _xSyncState = XSyncState.WaitConfigure; } } } @@ -755,8 +769,11 @@ namespace Avalonia.X11 void DoPaint() { Paint?.Invoke(new Rect()); - if (_xSyncCounter != IntPtr.Zero) + if (_xSyncCounter != IntPtr.Zero && _xSyncState == XSyncState.WaitPaint) + { + _xSyncState = XSyncState.None; XSyncSetCounter(_x11.Display, _xSyncCounter, _xSyncValue); + } } public void Invalidate(Rect rect) @@ -802,6 +819,12 @@ namespace Avalonia.X11 XDestroyIC(_xic); _xic = IntPtr.Zero; } + + if (_xSyncCounter != IntPtr.Zero) + { + XSyncDestroyCounter(_x11.Display, _xSyncCounter); + _xSyncCounter = IntPtr.Zero; + } if (_handle != IntPtr.Zero) { From a34e03d7f5ee0a67b00ddf8f2dac4d42a497df58 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 3 Jun 2022 19:12:12 -0400 Subject: [PATCH 272/332] Fix android service initialization order --- src/Android/Avalonia.Android/AndroidPlatform.cs | 2 -- src/Android/Avalonia.Android/AvaloniaActivity.cs | 7 ++++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index 61aa6ce946..c7dd896cb8 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/src/Android/Avalonia.Android/AndroidPlatform.cs @@ -61,8 +61,6 @@ namespace Avalonia.Android .Bind().ToConstant(new RenderLoop()) .Bind().ToSingleton(); - SkiaPlatform.Initialize(); - if (options.UseGpu) { EglPlatformOpenGlInterface.TryInitialize(); diff --git a/src/Android/Avalonia.Android/AvaloniaActivity.cs b/src/Android/Avalonia.Android/AvaloniaActivity.cs index f5d620a97a..f3692d33d7 100644 --- a/src/Android/Avalonia.Android/AvaloniaActivity.cs +++ b/src/Android/Avalonia.Android/AvaloniaActivity.cs @@ -31,21 +31,22 @@ namespace Avalonia.Android CustomizeAppBuilder(builder); - View = new AvaloniaView(this); - SetContentView(View); var lifetime = new SingleViewLifetime(); - lifetime.View = View; builder.AfterSetup(x => { _viewModel = new ViewModelProvider(this).Get(Java.Lang.Class.FromType(typeof(AvaloniaViewModel))) as AvaloniaViewModel; + View = new AvaloniaView(this); if (_viewModel.Content != null) { View.Content = _viewModel.Content; } + SetContentView(View); + lifetime.View = View; + View.Prepare(); }); From b277db43bd88c860ff998796570fd5540a8b4342 Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 3 Jun 2022 21:02:09 -0400 Subject: [PATCH 273/332] Update release build parameters --- .../ControlCatalog.Android/ControlCatalog.Android.csproj | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj index 04c67e84e8..ec88852feb 100644 --- a/samples/ControlCatalog.Android/ControlCatalog.Android.csproj +++ b/samples/ControlCatalog.Android/ControlCatalog.Android.csproj @@ -20,10 +20,13 @@ - True + False + False True True - True + no-write-symbols,nodebug + Hybrid + True From 5c7a399630edde5b6fd50c70fbb3e547572fc38e Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Sat, 4 Jun 2022 10:42:54 +0200 Subject: [PATCH 274/332] fix: Suppress CA1416 on Avalonia.Win32 --- src/Windows/Avalonia.Win32/Avalonia.Win32.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj index b9a1880435..55d02b5d31 100644 --- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj +++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj @@ -18,4 +18,8 @@ + + CA1416 + $(NoWarn),CA1416 + From dba9f9832e1a709d2491fb30c9d554f574920374 Mon Sep 17 00:00:00 2001 From: Oxc3 Date: Sat, 4 Jun 2022 17:03:21 -0700 Subject: [PATCH 275/332] Update AvaloniaView.razor change to the razor code so the events are invoked by the AspNetCore.EventCallbackFactory rather then an action pointer attached to the event --- src/Web/Avalonia.Web.Blazor/AvaloniaView.razor | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor index dd7eb0ec54..31425fe438 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor @@ -1,18 +1,18 @@ 
+ @ontouchcancel="OnTouchCancel" + @ontouchmove="OnTouchMove" + @onwheel="OnWheel" + @onkeydown="OnKeyDown" + @onkeyup="OnKeyUp" + @onpointerdown="OnPointerDown" + @onpointerup="OnPointerUp" + @onpointermove="OnPointerMove">
- From 040fe4a60307d93d8776def47c3fc9215b46bf29 Mon Sep 17 00:00:00 2001 From: Dariusz Komosinski Date: Sun, 5 Jun 2022 16:18:21 +0200 Subject: [PATCH 276/332] Fix missing PooledList usage in Calendar. --- src/Avalonia.Controls/Calendar/CalendarItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs index 32fdaceacb..bcac6324ba 100644 --- a/src/Avalonia.Controls/Calendar/CalendarItem.cs +++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs @@ -218,7 +218,7 @@ namespace Avalonia.Controls.Primitives if (YearView != null) { var childCount = Calendar.RowsPerYear * Calendar.ColumnsPerYear; - var children = new List(childCount); + using var children = new PooledList(childCount); EventHandler monthCalendarButtonMouseDown = Month_CalendarButtonMouseDown; EventHandler monthCalendarButtonMouseUp = Month_CalendarButtonMouseUp; From 38b88825261005a7a53507be30aa2a45fa63c276 Mon Sep 17 00:00:00 2001 From: Oxc3 Date: Sun, 5 Jun 2022 07:21:20 -0700 Subject: [PATCH 277/332] mixing touch and pointer breaks gestures --- .../Avalonia.Web.Blazor/AvaloniaView.razor | 8 ++-- .../Avalonia.Web.Blazor/AvaloniaView.razor.cs | 38 +++++-------------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor index 31425fe438..68662bd931 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor @@ -1,12 +1,11 @@ 
+ @onpointermove="OnPointerMove" + @onpointercancel="OnPointerCancel"> @@ -19,6 +18,9 @@