committed by
GitHub
44 changed files with 1300 additions and 316 deletions
@ -1,4 +1,5 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto"> |
|||
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> |
|||
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> |
|||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
|||
</manifest> |
|||
|
|||
@ -0,0 +1 @@ |
|||
DOTNET_DiagnosticPorts=127.0.0.1:9000,suspend |
|||
@ -0,0 +1 @@ |
|||
DOTNET_DiagnosticPorts=10.0.2.2:9001,suspend |
|||
@ -1,37 +0,0 @@ |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using Avalonia.Animation; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Media |
|||
{ |
|||
public class GeometryCollection : Animatable, IList<Geometry>, IReadOnlyList<Geometry> |
|||
{ |
|||
private List<Geometry> _inner; |
|||
|
|||
public GeometryCollection() => _inner = new List<Geometry>(); |
|||
public GeometryCollection(IEnumerable<Geometry> collection) => _inner = new List<Geometry>(collection); |
|||
public GeometryCollection(int capacity) => _inner = new List<Geometry>(capacity); |
|||
|
|||
public Geometry this[int index] |
|||
{ |
|||
get => _inner[index]; |
|||
set => _inner[index] = value; |
|||
} |
|||
|
|||
public int Count => _inner.Count; |
|||
public bool IsReadOnly => false; |
|||
|
|||
public void Add(Geometry item) => _inner.Add(item); |
|||
public void Clear() => _inner.Clear(); |
|||
public bool Contains(Geometry item) => _inner.Contains(item); |
|||
public void CopyTo(Geometry[] array, int arrayIndex) => _inner.CopyTo(array, arrayIndex); |
|||
public IEnumerator<Geometry> GetEnumerator() => _inner.GetEnumerator(); |
|||
public int IndexOf(Geometry item) => _inner.IndexOf(item); |
|||
public void Insert(int index, Geometry item) => _inner.Insert(index, item); |
|||
public bool Remove(Geometry item) => _inner.Remove(item); |
|||
public void RemoveAt(int index) => _inner.RemoveAt(index); |
|||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System.Collections.Generic; |
|||
using Avalonia.Collections; |
|||
|
|||
namespace Avalonia.Media |
|||
{ |
|||
public sealed class DrawingCollection : AvaloniaList<Drawing> |
|||
{ |
|||
public DrawingCollection() |
|||
{ |
|||
ResetBehavior = ResetBehavior.Remove; |
|||
} |
|||
|
|||
public DrawingCollection(IEnumerable<Drawing> items) : base(items) |
|||
{ |
|||
ResetBehavior = ResetBehavior.Remove; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Avalonia.Collections; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Media |
|||
{ |
|||
public sealed class GeometryCollection : AvaloniaList<Geometry> |
|||
{ |
|||
public GeometryCollection() |
|||
{ |
|||
ResetBehavior = ResetBehavior.Remove; |
|||
|
|||
this.ForEachItem( |
|||
x => |
|||
{ |
|||
Parent?.Invalidate(); |
|||
}, |
|||
x => |
|||
{ |
|||
Parent?.Invalidate(); |
|||
}, |
|||
() => throw new NotSupportedException()); |
|||
} |
|||
|
|||
public GeometryCollection(IEnumerable<Geometry> items) : base(items) |
|||
{ |
|||
ResetBehavior = ResetBehavior.Remove; |
|||
|
|||
this.ForEachItem( |
|||
x => |
|||
{ |
|||
Parent?.Invalidate(); |
|||
}, |
|||
x => |
|||
{ |
|||
Parent?.Invalidate(); |
|||
}, |
|||
() => throw new NotSupportedException()); |
|||
} |
|||
|
|||
public GeometryGroup? Parent { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
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"; |
|||
|
|||
/// <summary>
|
|||
/// Converts x:DataType directives to regular DataType assignments if property with Avalonia.Metadata.DataTypeAttribute exists.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
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<XamlAstXamlPropertyValueNode>() |
|||
.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 as XamlAstClrTypeReference)?.Type; |
|||
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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
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_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 |
|||
{ |
|||
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); |
|||
} |
|||
} |
|||
} |
|||
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Loading…
Reference in new issue