Browse Source

Added adorner support

pull/8105/head
Nikita Tsukanov 4 years ago
parent
commit
6e2214b6d4
  1. 19
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
  2. 14
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  3. 18
      src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs
  4. 5
      src/Avalonia.Base/Rendering/Composition/Server/ServerSolidColorVisual.cs
  5. 4
      src/Avalonia.Base/Rendering/Composition/Server/ServerSpriteVisual.cs
  6. 12
      src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs
  7. 2
      src/Avalonia.Base/Visual.cs
  8. 1
      src/Avalonia.Base/composition-schema.xml
  9. 20
      src/Avalonia.Controls/Primitives/AdornerLayer.cs
  10. 2
      src/Avalonia.SourceGenerator/CompositionGenerator/Config.cs
  11. 2
      src/Avalonia.SourceGenerator/CompositionGenerator/Generator.cs

19
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs

@ -11,10 +11,16 @@ namespace Avalonia.Rendering.Composition.Server;
internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisual
{
#if DEBUG
public readonly Visual UiVisual;
#endif
private CompositionDrawList? _renderCommands;
public ServerCompositionDrawListVisual(ServerCompositor compositor) : base(compositor)
public ServerCompositionDrawListVisual(ServerCompositor compositor, Visual v) : base(compositor)
{
#if DEBUG
UiVisual = v;
#endif
}
Rect? _contentBounds;
@ -47,12 +53,19 @@ internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisua
base.DeserializeChangesCore(reader, commitedAt);
}
protected override void RenderCore(CompositorDrawingContextProxy canvas, Matrix4x4 transform)
protected override void RenderCore(CompositorDrawingContextProxy canvas)
{
if (_renderCommands != null)
{
_renderCommands.Render(canvas);
}
base.RenderCore(canvas, transform);
base.RenderCore(canvas);
}
#if DEBUG
public override string ToString()
{
return UiVisual.GetType().ToString();
}
#endif
}

14
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs

@ -26,6 +26,7 @@ namespace Avalonia.Rendering.Composition.Server
private bool _redrawRequested;
private bool _disposed;
private HashSet<ServerCompositionVisual> _attachedVisuals = new();
private Queue<ServerCompositionVisual> _adornerUpdateQueue = new();
public ReadbackIndices Readback { get; } = new();
@ -80,6 +81,12 @@ namespace Avalonia.Rendering.Composition.Server
// Update happens in a separate phase to extend dirty rect if needed
Root.Update(this, Matrix4x4.Identity);
while (_adornerUpdateQueue.Count > 0)
{
var adorner = _adornerUpdateQueue.Dequeue();
adorner.Update(this, adorner.AdornedVisual?.GlobalTransformMatrix ?? Matrix4x4.Identity);
}
Readback.CompleteWrite(Revision);
@ -108,7 +115,7 @@ namespace Avalonia.Rendering.Composition.Server
{
context.PushClip(_dirtyRect);
context.Clear(Colors.Transparent);
Root.Render(new CompositorDrawingContextProxy(context, visualBrushHelper), Root.CombinedTransformMatrix);
Root.Render(new CompositorDrawingContextProxy(context, visualBrushHelper));
context.PopClip();
}
}
@ -147,6 +154,7 @@ namespace Avalonia.Rendering.Composition.Server
{
var snapped = SnapToDevicePixels(rect, Scaling);
_dirtyRect = _dirtyRect.Union(snapped);
_redrawRequested = true;
}
public void Invalidate()
@ -176,6 +184,10 @@ namespace Avalonia.Rendering.Composition.Server
{
if (_attachedVisuals.Remove(visual) && IsEnabled)
visual.Deactivate();
if(visual.IsVisibleInFrame)
AddDirtyRect(visual.TransformedBounds);
}
public void EnqueueAdornerUpdate(ServerCompositionVisual visual) => _adornerUpdateQueue.Enqueue(visual);
}
}

18
src/Avalonia.Base/Rendering/Composition/Server/ServerContainerVisual.cs

@ -7,24 +7,26 @@ namespace Avalonia.Rendering.Composition.Server
{
public ServerCompositionVisualCollection Children { get; private set; } = null!;
protected override void RenderCore(CompositorDrawingContextProxy canvas, Matrix4x4 transform)
protected override void RenderCore(CompositorDrawingContextProxy canvas)
{
base.RenderCore(canvas, transform);
base.RenderCore(canvas);
foreach (var ch in Children)
{
var t = transform;
t = ch.CombinedTransformMatrix * t;
ch.Render(canvas, t);
ch.Render(canvas);
}
}
public override void Update(ServerCompositionTarget root, Matrix4x4 transform)
{
base.Update(root, transform);
foreach (var child in Children)
child.Update(root, GlobalTransformMatrix);
foreach (var child in Children)
{
if (child.AdornedVisual != null)
root.EnqueueAdornerUpdate(child);
else
child.Update(root, GlobalTransformMatrix);
}
}
partial void Initialize()

5
src/Avalonia.Base/Rendering/Composition/Server/ServerSolidColorVisual.cs

@ -6,11 +6,10 @@ namespace Avalonia.Rendering.Composition.Server
{
internal partial class ServerCompositionSolidColorVisual
{
protected override void RenderCore(CompositorDrawingContextProxy canvas, Matrix4x4 transform)
protected override void RenderCore(CompositorDrawingContextProxy canvas)
{
canvas.Transform = MatrixUtils.ToMatrix(transform);
canvas.DrawRectangle(new ImmutableSolidColorBrush(Color), null, new RoundedRect(new Rect(new Size(Size))));
base.RenderCore(canvas, transform);
base.RenderCore(canvas);
}
}
}

4
src/Avalonia.Base/Rendering/Composition/Server/ServerSpriteVisual.cs

@ -6,7 +6,7 @@ namespace Avalonia.Rendering.Composition.Server
internal partial class ServerCompositionSpriteVisual
{
protected override void RenderCore(CompositorDrawingContextProxy canvas, Matrix4x4 transform)
protected override void RenderCore(CompositorDrawingContextProxy canvas)
{
if (Brush != null)
{
@ -14,7 +14,7 @@ namespace Avalonia.Rendering.Composition.Server
//canvas.FillRect((Vector2)Size, (ICbBrush)Brush.Brush!);
}
base.RenderCore(canvas, transform);
base.RenderCore(canvas);
}
}
}

12
src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs

@ -8,17 +8,18 @@ namespace Avalonia.Rendering.Composition.Server
{
private bool _isDirty;
private bool _isBackface;
protected virtual void RenderCore(CompositorDrawingContextProxy canvas, Matrix4x4 transform)
protected virtual void RenderCore(CompositorDrawingContextProxy canvas)
{
}
public void Render(CompositorDrawingContextProxy canvas, Matrix4x4 transform)
public void Render(CompositorDrawingContextProxy canvas)
{
if(Visible == false)
return;
if(Opacity == 0)
return;
var transform = GlobalTransformMatrix;
canvas.PreTransform = MatrixUtils.ToMatrix(transform);
canvas.Transform = Matrix.Identity;
if (Opacity != 1)
@ -29,8 +30,9 @@ namespace Avalonia.Rendering.Composition.Server
canvas.PushGeometryClip(Clip);
//TODO: Check clip
RenderCore(canvas, transform);
RenderCore(canvas);
// Hack to force invalidation of SKMatrix
canvas.PreTransform = MatrixUtils.ToMatrix(transform);
canvas.Transform = Matrix.Identity;
@ -60,7 +62,9 @@ namespace Avalonia.Rendering.Composition.Server
public virtual void Update(ServerCompositionTarget root, Matrix4x4 transform)
{
// Calculate new parent-relative transform
CombinedTransformMatrix = MatrixUtils.ComputeTransform(Size, AnchorPoint, CenterPoint, TransformMatrix,
CombinedTransformMatrix = MatrixUtils.ComputeTransform(Size, AnchorPoint, CenterPoint,
// HACK: Ignore RenderTransform set by the adorner layer
AdornedVisual != null ? Matrix4x4.Identity : TransformMatrix,
Scale, RotationAngle, Orientation, Offset);
var newTransform = CombinedTransformMatrix * transform;

2
src/Avalonia.Base/Visual.cs

@ -470,7 +470,7 @@ namespace Avalonia
{
if (CompositionVisual == null || CompositionVisual.Compositor != compositor)
CompositionVisual = new CompositionDrawListVisual(compositor,
new ServerCompositionDrawListVisual(compositor.Server), this);
new ServerCompositionDrawListVisual(compositor.Server, this), this);
return CompositionVisual;
}

1
src/Avalonia.Base/composition-schema.xml

@ -22,6 +22,7 @@
<Property Name="Orientation" Type="Quaternion" DefaultValue="Quaternion.Identity" Animated="true"/>
<Property Name="Scale" Type="Vector3" DefaultValue="new Vector3(1, 1, 1)" Animated="true"/>
<Property Name="TransformMatrix" Type="Matrix4x4" DefaultValue="Matrix4x4.Identity" Animated="true"/>
<Property Name="AdornedVisual" Type="CompositionVisual?" Internal="true" />
</Object>
<Object Name="CompositionContainerVisual" Inherits="CompositionVisual"/>
<List Name="CompositionVisualCollection" ItemType="CompositionVisual" CustomCtor="true"/>

20
src/Avalonia.Controls/Primitives/AdornerLayer.cs

@ -164,6 +164,9 @@ namespace Avalonia.Controls.Primitives
private void UpdateAdornedElement(Visual adorner, Visual? adorned)
{
if (adorner.CompositionVisual != null)
adorner.CompositionVisual.AdornedVisual = adorned?.CompositionVisual;
var info = adorner.GetValue(s_adornedElementInfoProperty);
if (info != null)
@ -184,11 +187,18 @@ namespace Avalonia.Controls.Primitives
adorner.SetValue(s_adornedElementInfoProperty, info);
}
info.Subscription = adorned.GetObservable(TransformedBoundsProperty).Subscribe(x =>
{
info.Bounds = x;
InvalidateMeasure();
});
if (adorner.CompositionVisual != null)
info.Subscription = adorned.GetObservable(BoundsProperty).Subscribe(x =>
{
info.Bounds = new TransformedBounds(new Rect(adorned.Bounds.Size), new Rect(adorned.Bounds.Size), Matrix.Identity);
InvalidateMeasure();
});
else
info.Subscription = adorned.GetObservable(TransformedBoundsProperty).Subscribe(x =>
{
info.Bounds = x;
InvalidateMeasure();
});
}
}

2
src/Avalonia.SourceGenerator/CompositionGenerator/Config.cs

@ -110,6 +110,8 @@ namespace Avalonia.SourceGenerator.CompositionGenerator
public bool Animated { get; set; }
[XmlAttribute]
public bool InternalSet { get; set; }
[XmlAttribute]
public bool Internal { get; set; }
}
public class GAnimationType

2
src/Avalonia.SourceGenerator/CompositionGenerator/Generator.cs

@ -378,7 +378,7 @@ namespace Avalonia.SourceGenerator.CompositionGenerator
return client
.AddMembers(DeclareField(prop.Type, fieldName))
.AddMembers(PropertyDeclaration(propType, prop.Name)
.AddModifiers(SyntaxKind.PublicKeyword)
.AddModifiers(prop.Internal ? SyntaxKind.InternalKeyword : SyntaxKind.PublicKeyword)
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration,
Block(ReturnStatement(IdentifierName(fieldName)))),

Loading…
Cancel
Save