committed by
GitHub
59 changed files with 1164 additions and 131 deletions
@ -1,5 +1,5 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="ReactiveUI" Version="12.1.1" /> |
|||
<PackageReference Include="ReactiveUI" Version="13.2.10" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,89 @@ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.Drawing.Drawing2D; |
|||
using System.Security.Cryptography; |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.LogicalTree; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Imaging; |
|||
using Avalonia.Media.Immutable; |
|||
using Avalonia.Threading; |
|||
using Avalonia.Visuals.Media.Imaging; |
|||
|
|||
namespace RenderDemo.Pages |
|||
{ |
|||
public class PathMeasurementPage : Control |
|||
{ |
|||
static PathMeasurementPage() |
|||
{ |
|||
AffectsRender<PathMeasurementPage>(BoundsProperty); |
|||
} |
|||
|
|||
private RenderTargetBitmap _bitmap; |
|||
|
|||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) |
|||
{ |
|||
_bitmap = new RenderTargetBitmap(new PixelSize(500, 500), new Vector(96, 96)); |
|||
base.OnAttachedToLogicalTree(e); |
|||
} |
|||
|
|||
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) |
|||
{ |
|||
_bitmap.Dispose(); |
|||
_bitmap = null; |
|||
base.OnDetachedFromLogicalTree(e); |
|||
} |
|||
|
|||
readonly IPen strokePen = new ImmutablePen(Brushes.DarkBlue, 10d, null, PenLineCap.Round, PenLineJoin.Round); |
|||
readonly IPen strokePen1 = new ImmutablePen(Brushes.Purple, 10d, null, PenLineCap.Round, PenLineJoin.Round); |
|||
readonly IPen strokePen2 = new ImmutablePen(Brushes.Green, 10d, null, PenLineCap.Round, PenLineJoin.Round); |
|||
readonly IPen strokePen3 = new ImmutablePen(Brushes.LightBlue, 10d, null, PenLineCap.Round, PenLineJoin.Round); |
|||
readonly IPen strokePen4 = new ImmutablePen(Brushes.Red, 1d, null, PenLineCap.Round, PenLineJoin.Round); |
|||
|
|||
public override void Render(DrawingContext context) |
|||
{ |
|||
using (var ctxi = _bitmap.CreateDrawingContext(null)) |
|||
using (var bitmapCtx = new DrawingContext(ctxi, false)) |
|||
{ |
|||
ctxi.Clear(default); |
|||
|
|||
var basePath = new PathGeometry(); |
|||
|
|||
using (var basePathCtx = basePath.Open()) |
|||
{ |
|||
basePathCtx.BeginFigure(new Point(20, 20), false); |
|||
basePathCtx.LineTo(new Point(400, 50)); |
|||
basePathCtx.LineTo(new Point(80, 100)); |
|||
basePathCtx.LineTo(new Point(300, 150)); |
|||
basePathCtx.EndFigure(false); |
|||
} |
|||
|
|||
bitmapCtx.DrawGeometry(null, strokePen, basePath); |
|||
|
|||
|
|||
var length = basePath.PlatformImpl.ContourLength; |
|||
|
|||
if (basePath.PlatformImpl.TryGetSegment(length * 0.05, length * 0.2, true, out var dst1)) |
|||
bitmapCtx.DrawGeometry(null, strokePen1, dst1); |
|||
|
|||
if (basePath.PlatformImpl.TryGetSegment(length * 0.2, length * 0.8, true, out var dst2)) |
|||
bitmapCtx.DrawGeometry(null, strokePen2, dst2); |
|||
|
|||
if (basePath.PlatformImpl.TryGetSegment(length * 0.8, length * 0.95, true, out var dst3)) |
|||
bitmapCtx.DrawGeometry(null, strokePen3, dst3); |
|||
|
|||
var pathBounds = basePath.GetRenderBounds(strokePen); |
|||
|
|||
bitmapCtx.DrawRectangle(null, strokePen4, pathBounds); |
|||
} |
|||
|
|||
|
|||
context.DrawImage(_bitmap, |
|||
new Rect(0, 0, 500, 500), |
|||
new Rect(0, 0, 500, 500)); |
|||
|
|||
base.Render(context); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System; |
|||
using XamlX.Transform; |
|||
|
|||
namespace Avalonia.Build.Tasks |
|||
{ |
|||
public class DeterministicIdGenerator : IXamlIdentifierGenerator |
|||
{ |
|||
private int _nextId = 1; |
|||
|
|||
public string GenerateIdentifierPart() => (_nextId++).ToString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
using Avalonia.Input; |
|||
|
|||
namespace Avalonia.Diagnostics |
|||
{ |
|||
/// <summary>
|
|||
/// Describes options used to customize DevTools.
|
|||
/// </summary>
|
|||
public class DevToolsOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the key gesture used to open DevTools.
|
|||
/// </summary>
|
|||
public KeyGesture Gesture { get; set; } = new KeyGesture(Key.F12); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value indicating whether DevTools should be displayed as a child window
|
|||
/// of the window being inspected. The default value is true.
|
|||
/// </summary>
|
|||
public bool ShowAsChildWindow { get; set; } = true; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the initial size of the DevTools window. The default value is 1024x512.
|
|||
/// </summary>
|
|||
public Size Size { get; set; } = new Size(1024, 512); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Input |
|||
{ |
|||
public class TappedEventArgs : RoutedEventArgs |
|||
{ |
|||
private readonly PointerEventArgs lastPointerEventArgs; |
|||
|
|||
public TappedEventArgs(RoutedEvent routedEvent, PointerEventArgs lastPointerEventArgs) |
|||
: base(routedEvent) |
|||
{ |
|||
this.lastPointerEventArgs = lastPointerEventArgs; |
|||
} |
|||
|
|||
public Point GetPosition(IVisual? relativeTo) => lastPointerEventArgs.GetPosition(relativeTo); |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Avalonia.Data; |
|||
|
|||
namespace Avalonia |
|||
{ |
|||
internal static class ClassBindingManager |
|||
{ |
|||
private static readonly Dictionary<string, AvaloniaProperty> s_RegisteredProperties = |
|||
new Dictionary<string, AvaloniaProperty>(); |
|||
|
|||
public static IDisposable Bind(IStyledElement target, string className, IBinding source, object anchor) |
|||
{ |
|||
if (!s_RegisteredProperties.TryGetValue(className, out var prop)) |
|||
s_RegisteredProperties[className] = prop = RegisterClassProxyProperty(className); |
|||
return target.Bind(prop, source, anchor); |
|||
} |
|||
|
|||
private static AvaloniaProperty RegisterClassProxyProperty(string className) |
|||
{ |
|||
var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className); |
|||
prop.Changed.Subscribe(args => |
|||
{ |
|||
var classes = ((IStyledElement)args.Sender).Classes; |
|||
classes.Set(className, args.NewValue.GetValueOrDefault()); |
|||
}); |
|||
|
|||
return prop; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using System; |
|||
using Avalonia.Data; |
|||
|
|||
namespace Avalonia |
|||
{ |
|||
public static class StyledElementExtensions |
|||
{ |
|||
public static IDisposable BindClass(this IStyledElement target, string className, IBinding source, object anchor) => |
|||
ClassBindingManager.Bind(target, className, source, anchor); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
Compat issues with assembly Avalonia.Visuals: |
|||
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.PopBitmapBlendMode()' is present in the implementation but not in the contract. |
|||
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.PushBitmapBlendMode(Avalonia.Visuals.Media.Imaging.BitmapBlendingMode)' is present in the implementation but not in the contract. |
|||
InterfacesShouldHaveSameMembers : Interface member 'public System.Double Avalonia.Platform.IGeometryImpl.ContourLength' is present in the implementation but not in the contract. |
|||
InterfacesShouldHaveSameMembers : Interface member 'public System.Double Avalonia.Platform.IGeometryImpl.ContourLength.get()' is present in the implementation but not in the contract. |
|||
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IGeometryImpl.TryGetPointAndTangentAtDistance(System.Double, Avalonia.Point, Avalonia.Point)' is present in the implementation but not in the contract. |
|||
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IGeometryImpl.TryGetPointAtDistance(System.Double, Avalonia.Point)' is present in the implementation but not in the contract. |
|||
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IGeometryImpl.TryGetSegment(System.Double, System.Double, System.Boolean, Avalonia.Platform.IGeometryImpl)' is present in the implementation but not in the contract. |
|||
Total Issues: 7 |
|||
@ -0,0 +1,57 @@ |
|||
namespace Avalonia.Visuals.Media.Imaging |
|||
{ |
|||
/// <summary>
|
|||
/// Controls the way the bitmaps are drawn together.
|
|||
/// </summary>
|
|||
public enum BitmapBlendingMode |
|||
{ |
|||
/// <summary>
|
|||
/// Source is placed over the destination.
|
|||
/// </summary>
|
|||
SourceOver, |
|||
/// <summary>
|
|||
/// Only the source will be present.
|
|||
/// </summary>
|
|||
Source, |
|||
/// <summary>
|
|||
/// Only the destination will be present.
|
|||
/// </summary>
|
|||
Destination, |
|||
/// <summary>
|
|||
/// Destination is placed over the source.
|
|||
/// </summary>
|
|||
DestinationOver, |
|||
/// <summary>
|
|||
/// The source that overlaps the destination, replaces the destination.
|
|||
/// </summary>
|
|||
SourceIn, |
|||
/// <summary>
|
|||
/// Destination which overlaps the source, replaces the source.
|
|||
/// </summary>
|
|||
DestinationIn, |
|||
/// <summary>
|
|||
/// Source is placed, where it falls outside of the destination.
|
|||
/// </summary>
|
|||
SourceOut, |
|||
/// <summary>
|
|||
/// Destination is placed, where it falls outside of the source.
|
|||
/// </summary>
|
|||
DestinationOut, |
|||
/// <summary>
|
|||
/// Source which overlaps the destination, replaces the destination.
|
|||
/// </summary>
|
|||
SourceAtop, |
|||
/// <summary>
|
|||
/// Destination which overlaps the source replaces the source.
|
|||
/// </summary>
|
|||
DestinationAtop, |
|||
/// <summary>
|
|||
/// The non-overlapping regions of source and destination are combined.
|
|||
/// </summary>
|
|||
Xor, |
|||
/// <summary>
|
|||
/// Display the sum of the source image and destination image.
|
|||
/// </summary>
|
|||
Plus, |
|||
} |
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
using Avalonia.Platform; |
|||
using Avalonia.Visuals.Media.Imaging; |
|||
|
|||
namespace Avalonia.Rendering.SceneGraph |
|||
{ |
|||
/// <summary>
|
|||
/// A node in the scene graph which represents an bitmap blending mode push or pop.
|
|||
/// </summary>
|
|||
internal class BitmapBlendModeNode : IDrawOperation |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BitmapBlendModeNode"/> class that represents an
|
|||
/// <see cref="BitmapBlendingMode"/> push.
|
|||
/// </summary>
|
|||
/// <param name="bitmapBlend">The <see cref="BitmapBlendingMode"/> to push.</param>
|
|||
public BitmapBlendModeNode(BitmapBlendingMode bitmapBlend) |
|||
{ |
|||
BlendingMode = bitmapBlend; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BitmapBlendNode"/> class that represents an
|
|||
/// <see cref="BitmapBlendingMode"/> pop.
|
|||
/// </summary>
|
|||
public BitmapBlendModeNode() |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public Rect Bounds => Rect.Empty; |
|||
|
|||
/// <summary>
|
|||
/// Gets the BitmapBlend to be pushed or null if the operation represents a pop.
|
|||
/// </summary>
|
|||
public BitmapBlendingMode? BlendingMode { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public bool HitTest(Point p) => false; |
|||
|
|||
/// <summary>
|
|||
/// Determines if this draw operation equals another.
|
|||
/// </summary>
|
|||
/// <param name="opacity">The opacity of the other draw operation.</param>
|
|||
/// <returns>True if the draw operations are the same, otherwise false.</returns>
|
|||
/// <remarks>
|
|||
/// The properties of the other draw operation are passed in as arguments to prevent
|
|||
/// allocation of a not-yet-constructed draw operation object.
|
|||
/// </remarks>
|
|||
public bool Equals(BitmapBlendingMode? blendingMode) => BlendingMode == blendingMode; |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Render(IDrawingContextImpl context) |
|||
{ |
|||
if (BlendingMode.HasValue) |
|||
{ |
|||
context.PushBitmapBlendMode(BlendingMode.Value); |
|||
} |
|||
else |
|||
{ |
|||
context.PopBitmapBlendMode(); |
|||
} |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
using System.Collections.Generic; |
|||
using XamlX.Ast; |
|||
using XamlX.Emit; |
|||
using XamlX.IL; |
|||
using XamlX.Transform; |
|||
using XamlX.TypeSystem; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers |
|||
{ |
|||
class AvaloniaXamlIlResolveClassesPropertiesTransformer : IXamlAstTransformer |
|||
{ |
|||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstNamePropertyReference prop |
|||
&& prop.TargetType is XamlAstClrTypeReference targetRef |
|||
&& prop.DeclaringType is XamlAstClrTypeReference declaringRef) |
|||
{ |
|||
var types = context.GetAvaloniaTypes(); |
|||
if (types.StyledElement.IsAssignableFrom(targetRef.Type) |
|||
&& types.Classes.Equals(declaringRef.Type)) |
|||
{ |
|||
return new XamlAstClrProperty(node, "class:" + prop.Name, types.Classes, |
|||
null) |
|||
{ |
|||
Setters = { new ClassValueSetter(types, prop.Name), new ClassBindingSetter(types, prop.Name) } |
|||
}; |
|||
} |
|||
} |
|||
return node; |
|||
} |
|||
|
|||
|
|||
class ClassValueSetter : IXamlEmitablePropertySetter<IXamlILEmitter> |
|||
{ |
|||
private readonly AvaloniaXamlIlWellKnownTypes _types; |
|||
private readonly string _className; |
|||
|
|||
public ClassValueSetter(AvaloniaXamlIlWellKnownTypes types, string className) |
|||
{ |
|||
_types = types; |
|||
_className = className; |
|||
Parameters = new[] { types.XamlIlTypes.Boolean }; |
|||
} |
|||
|
|||
public void Emit(IXamlILEmitter emitter) |
|||
{ |
|||
using (var value = emitter.LocalsPool.GetLocal(_types.XamlIlTypes.Boolean)) |
|||
{ |
|||
emitter |
|||
.Stloc(value.Local) |
|||
.EmitCall(_types.StyledElementClassesProperty.Getter) |
|||
.Ldstr(_className) |
|||
.Ldloc(value.Local) |
|||
.EmitCall(_types.Classes.GetMethod(new FindMethodMethodSignature("Set", |
|||
_types.XamlIlTypes.Void, _types.XamlIlTypes.String, _types.XamlIlTypes.Boolean))); |
|||
} |
|||
} |
|||
|
|||
public IXamlType TargetType => _types.StyledElement; |
|||
|
|||
public PropertySetterBinderParameters BinderParameters { get; } = |
|||
new PropertySetterBinderParameters { AllowXNull = false }; |
|||
public IReadOnlyList<IXamlType> Parameters { get; } |
|||
} |
|||
|
|||
class ClassBindingSetter : IXamlEmitablePropertySetter<IXamlILEmitter> |
|||
{ |
|||
private readonly AvaloniaXamlIlWellKnownTypes _types; |
|||
private readonly string _className; |
|||
|
|||
public ClassBindingSetter(AvaloniaXamlIlWellKnownTypes types, string className) |
|||
{ |
|||
_types = types; |
|||
_className = className; |
|||
Parameters = new[] {types.IBinding}; |
|||
} |
|||
|
|||
public void Emit(IXamlILEmitter emitter) |
|||
{ |
|||
using (var bloc = emitter.LocalsPool.GetLocal(_types.IBinding)) |
|||
emitter |
|||
.Stloc(bloc.Local) |
|||
.Ldstr(_className) |
|||
.Ldloc(bloc.Local) |
|||
// TODO: provide anchor?
|
|||
.Ldnull(); |
|||
emitter.EmitCall(_types.ClassesBindMethod, true); |
|||
} |
|||
|
|||
public IXamlType TargetType => _types.StyledElement; |
|||
|
|||
public PropertySetterBinderParameters BinderParameters { get; } = |
|||
new PropertySetterBinderParameters { AllowXNull = false }; |
|||
public IReadOnlyList<IXamlType> Parameters { get; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
using XamlX.Ast; |
|||
using XamlX.Transform; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers |
|||
{ |
|||
class AvaloniaXamlIlReorderClassesPropertiesTransformer : IXamlAstTransformer |
|||
{ |
|||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstObjectNode obj) |
|||
{ |
|||
IXamlAstNode classesNode = null; |
|||
IXamlAstNode firstSingleClassNode = null; |
|||
var types = context.GetAvaloniaTypes(); |
|||
foreach (var child in obj.Children) |
|||
{ |
|||
if (child is XamlAstXamlPropertyValueNode propValue |
|||
&& propValue.Property is XamlAstClrProperty prop) |
|||
{ |
|||
if (prop.DeclaringType.Equals(types.Classes)) |
|||
{ |
|||
if (firstSingleClassNode == null) |
|||
firstSingleClassNode = child; |
|||
} |
|||
else if (prop.Name == "Classes" && prop.DeclaringType.Equals(types.StyledElement)) |
|||
classesNode = child; |
|||
} |
|||
} |
|||
|
|||
if (classesNode != null && firstSingleClassNode != null) |
|||
{ |
|||
obj.Children.Remove(classesNode); |
|||
obj.Children.Insert(obj.Children.IndexOf(firstSingleClassNode), classesNode); |
|||
} |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue