From 0d7adc70d9e69334d2109b04a8d2ebade8c6461b Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Fri, 3 Jun 2022 15:47:01 +0300 Subject: [PATCH] Implemented ZIndex support --- .../Composition/CompositingRenderer.cs | 69 ++++++++++++++++--- .../Rendering/ImmediateRenderer.cs | 6 +- .../Rendering/SceneGraph/SceneBuilder.cs | 44 +++++++----- src/Avalonia.Base/Visual.cs | 8 +++ src/Avalonia.Base/VisualTree/IVisual.cs | 5 ++ 5 files changed, 104 insertions(+), 28 deletions(-) diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs index b83f804a8f..5aded281b3 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Numerics; using System.Runtime.InteropServices; using Avalonia.Collections; +using Avalonia.Collections.Pooled; using Avalonia.Media; using Avalonia.Rendering.Composition.Drawing; using Avalonia.Rendering.Composition.Server; @@ -100,26 +101,74 @@ public class CompositingRenderer : RendererBase, IRendererWithCompositor return; var compositionChildren = v.CompositionVisual.Children; var visualChildren = (AvaloniaList)v.GetVisualChildren(); + + PooledList<(IVisual visual, int index)>? sortedChildren = null; + if (v.HasNonUniformZIndexChildren && visualChildren.Count > 1) + { + sortedChildren = new (visualChildren.Count); + for (var c = 0; c < visualChildren.Count; c++) + sortedChildren.Add((visualChildren[c], c)); + + // Regular Array.Sort is unstable, we need to provide indices as well to avoid reshuffling elements. + sortedChildren.Sort(static (lhs, rhs) => + { + var result = lhs.visual.ZIndex.CompareTo(rhs.visual.ZIndex); + return result == 0 ? lhs.index.CompareTo(rhs.index) : result; + }); + } + if (compositionChildren.Count == visualChildren.Count) { bool mismatch = false; - for(var c=0; c x, ZIndexComparer.Instance)) + var childrenEnumerable = visual.HasNonUniformZIndexChildren + ? visual.VisualChildren.OrderBy(x => x, ZIndexComparer.Instance) + : (IEnumerable)visual.VisualChildren; + + foreach (var child in childrenEnumerable) { var childBounds = GetTransformedBounds(child); diff --git a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs index 019c3e0e9b..cc18400a4c 100644 --- a/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Base/Rendering/SceneGraph/SceneBuilder.cs @@ -272,26 +272,36 @@ namespace Avalonia.Rendering.SceneGraph else if (visualChildren.Count > 1) { var count = visualChildren.Count; - var sortedChildren = new (IVisual visual, int index)[count]; - for (var i = 0; i < count; i++) + if (visual.HasNonUniformZIndexChildren) { - sortedChildren[i] = (visualChildren[i], i); - } - - // Regular Array.Sort is unstable, we need to provide indices as well to avoid reshuffling elements. - Array.Sort(sortedChildren, (lhs, rhs) => - { - var result = ZIndexComparer.Instance.Compare(lhs.visual, rhs.visual); - - return result == 0 ? lhs.index.CompareTo(rhs.index) : result; - }); - - foreach (var child in sortedChildren) - { - var childNode = GetOrCreateChildNode(scene, child.Item1, node); - Update(context, scene, (VisualNode)childNode, clip, forceRecurse); + var sortedChildren = new (IVisual visual, int index)[count]; + + for (var i = 0; i < count; i++) + { + sortedChildren[i] = (visualChildren[i], i); + } + + // Regular Array.Sort is unstable, we need to provide indices as well to avoid reshuffling elements. + Array.Sort(sortedChildren, (lhs, rhs) => + { + var result = ZIndexComparer.Instance.Compare(lhs.visual, rhs.visual); + + return result == 0 ? lhs.index.CompareTo(rhs.index) : result; + }); + + foreach (var child in sortedChildren) + { + var childNode = GetOrCreateChildNode(scene, child.Item1, node); + Update(context, scene, (VisualNode)childNode, clip, forceRecurse); + } } + else + foreach (var child in visualChildren) + { + var childNode = GetOrCreateChildNode(scene, child, node); + Update(context, scene, (VisualNode)childNode, clip, forceRecurse); + } } node.SubTreeUpdated = true; diff --git a/src/Avalonia.Base/Visual.cs b/src/Avalonia.Base/Visual.cs index 64341be0c7..c11ea2c40a 100644 --- a/src/Avalonia.Base/Visual.cs +++ b/src/Avalonia.Base/Visual.cs @@ -293,6 +293,8 @@ namespace Avalonia internal CompositionDrawListVisual? CompositionVisual { get; private set; } + public bool HasNonUniformZIndexChildren { get; private set; } + /// /// Gets a value indicating whether this control is attached to a visual root. /// @@ -445,6 +447,9 @@ namespace Avalonia AttachedToVisualTree?.Invoke(this, e); InvalidateVisual(); + if (ZIndex != 0 && this.GetVisualParent() is Visual parent) + parent.HasNonUniformZIndexChildren = true; + var visualChildren = VisualChildren; if (visualChildren != null) @@ -611,6 +616,9 @@ namespace Avalonia { var sender = e.Sender as IVisual; var parent = sender?.VisualParent; + if (sender?.ZIndex != 0 && parent is Visual parentVisual) + parentVisual.HasNonUniformZIndexChildren = true; + sender?.InvalidateVisual(); parent?.VisualRoot?.Renderer?.RecalculateChildren(parent); } diff --git a/src/Avalonia.Base/VisualTree/IVisual.cs b/src/Avalonia.Base/VisualTree/IVisual.cs index 3b053fab38..fdd2d187b8 100644 --- a/src/Avalonia.Base/VisualTree/IVisual.cs +++ b/src/Avalonia.Base/VisualTree/IVisual.cs @@ -79,6 +79,11 @@ namespace Avalonia.VisualTree /// Gets a value indicating whether to apply mirror transform on this control. /// bool HasMirrorTransform { get; } + + /// + /// Gets a value indicating whether to sort children when rendering this control + /// + bool HasNonUniformZIndexChildren { get; } /// /// Gets or sets the render transform of the control.