Browse Source

refactor mirror engine

pull/7810/head
daniel mayost 5 years ago
parent
commit
b025186af0
  1. 85
      src/Avalonia.Controls/Control.cs
  2. 5
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  3. 18
      src/Avalonia.Visuals/Media/TransformExtensions.cs
  4. 18
      src/Avalonia.Visuals/Media/TransformGroup.cs
  5. 6
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  6. 23
      src/Avalonia.Visuals/Visual.cs
  7. 6
      src/Avalonia.Visuals/VisualExtensions.cs
  8. 5
      src/Avalonia.Visuals/VisualTree/IVisual.cs

85
src/Avalonia.Controls/Control.cs

@ -67,17 +67,10 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public static readonly AttachedProperty<FlowDirection> FlowDirectionProperty = public static readonly AttachedProperty<FlowDirection> FlowDirectionProperty =
AvaloniaProperty.RegisterAttached<Control, Control, FlowDirection>(nameof(FlowDirection), inherits: true); AvaloniaProperty.RegisterAttached<Control, Control, FlowDirection>(nameof(FlowDirection), inherits: true);
/// <summary>
/// Defines the <see cref="RenderTransform"/> property.
/// </summary>
public static new readonly StyledProperty<ITransform?> RenderTransformProperty =
Visual.RenderTransformProperty.AddOwner<Control>();
private DataTemplates? _dataTemplates; private DataTemplates? _dataTemplates;
private IControl? _focusAdorner; private IControl? _focusAdorner;
private AutomationPeer? _automationPeer; private AutomationPeer? _automationPeer;
private bool _hasMirrorTransform;
/// <summary> /// <summary>
/// Gets or sets the control's focus adorner. /// Gets or sets the control's focus adorner.
@ -133,28 +126,6 @@ namespace Avalonia.Controls
set => SetValue(FlowDirectionProperty, value); set => SetValue(FlowDirectionProperty, value);
} }
/// <inheritdoc/>
public override ITransform? RenderTransform
{
get => base.RenderTransform;
set
{
if (_hasMirrorTransform)
{
if (value == null)
{
value = MirrorTrasform();
}
else
{
value = MirrorTrasform().MergeTransforms(value);
}
}
base.RenderTransform = value;
}
}
/// <summary> /// <summary>
/// Occurs when the user has completed a context input gesture, such as a right-click. /// Occurs when the user has completed a context input gesture, such as a right-click.
/// </summary> /// </summary>
@ -375,13 +346,15 @@ namespace Avalonia.Controls
bool shouldApplyMirrorTransform = thisShouldGetMirrored != parentShouldGetMirrored; bool shouldApplyMirrorTransform = thisShouldGetMirrored != parentShouldGetMirrored;
if (this is IRenderRoot) shouldApplyMirrorTransform = false;
if (shouldApplyMirrorTransform) if (shouldApplyMirrorTransform)
{ {
AddMirrorTransform(); IsMirrorTransform = true;
} }
else else
{ {
RemoveMirrorTransform(); IsMirrorTransform = false;
} }
} }
@ -396,57 +369,15 @@ namespace Avalonia.Controls
} }
} }
private void AddMirrorTransform()
{
if (_hasMirrorTransform)
{
return;
}
var mirrorTransform = MirrorTrasform();
var renderTransform = RenderTransform;
ITransform? finalTransform = mirrorTransform;
if (renderTransform != null)
{
finalTransform = mirrorTransform.MergeTransforms(renderTransform);
}
base.RenderTransform = finalTransform;
_hasMirrorTransform = true;
}
private void RemoveMirrorTransform()
{
if (!_hasMirrorTransform)
{
return;
}
ITransform mirrorTransform = MirrorTrasform();
ITransform renderTransform = RenderTransform!;
ITransform? finalTransform = mirrorTransform.MergeTransforms(renderTransform);
if (finalTransform!.Value == Matrix.Identity)
{
finalTransform = null;
}
_hasMirrorTransform = false;
base.RenderTransform = finalTransform;
}
/// <summary> /// <summary>
/// Determines whether the element should be presented mirrored /// Determines whether the element should be presented mirrored, this
/// if FlowDirection is RightToLeft /// method related to FlowDirection system and as return true if FlowDirection
/// is RightToLeft. For controls that want to avoid this behavior, it is
/// possible to override this method and return false.
/// </summary> /// </summary>
protected virtual bool ShouldPresentedMirrored() protected virtual bool ShouldPresentedMirrored()
{ {
return FlowDirection == FlowDirection.RightToLeft; return FlowDirection == FlowDirection.RightToLeft;
} }
static ITransform MirrorTrasform() =>
new MatrixTransform(new Avalonia.Matrix(-1, 0, 0, 1, 0.0, 0.0));
} }
} }

5
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -176,5 +176,6 @@ InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.GlyphR
MembersMustExist : Member 'public Avalonia.Media.GlyphRun Avalonia.Platform.ITextShaperImpl.ShapeText(Avalonia.Utilities.ReadOnlySlice<System.Char>, Avalonia.Media.Typeface, System.Double, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Media.GlyphRun Avalonia.Platform.ITextShaperImpl.ShapeText(Avalonia.Utilities.ReadOnlySlice<System.Char>, Avalonia.Media.Typeface, System.Double, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.Rendering.RendererBase.RenderFps(Avalonia.Platform.IDrawingContextImpl, Avalonia.Rect, System.Nullable<System.Int32>)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Rendering.RendererBase.RenderFps(Avalonia.Platform.IDrawingContextImpl, Avalonia.Rect, System.Nullable<System.Int32>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Utilities.ReadOnlySlice<T>..ctor(System.ReadOnlyMemory<T>, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Utilities.ReadOnlySlice<T>..ctor(System.ReadOnlyMemory<T>, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract.
CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Media.Transforms' does not inherit from base type 'Avalonia.Collections.AvaloniaList<Avalonia.Media.Transform>' in the implementation but it does in the contract. InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.VisualTree.IVisual.IsMirrorTransform' is present in the implementation but not in the contract.
Total Issues: 178 InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.VisualTree.IVisual.IsMirrorTransform.get()' is present in the implementation but not in the contract.
Total Issues: 179

18
src/Avalonia.Visuals/Media/TransformExtensions.cs

@ -22,23 +22,5 @@ namespace Avalonia.Media
return (transform as Transform)?.ToImmutable() ?? new ImmutableTransform(transform.Value); return (transform as Transform)?.ToImmutable() ?? new ImmutableTransform(transform.Value);
} }
/// <summary>
/// Merge two transforms to an one transform.
/// </summary>
/// <param name="srcTransform">The original transform.</param>
/// <param name="additionalTransform">The additional transform to be added.</param>
/// <returns>
/// One ITransform that includes both.
/// </returns>
public static ITransform MergeTransforms(this ITransform srcTransform, ITransform additionalTransform)
{
TransformGroup groupTransform = new TransformGroup();
groupTransform.Children.Add(srcTransform);
groupTransform.Children.Add(additionalTransform);
return groupTransform;
}
} }
} }

18
src/Avalonia.Visuals/Media/TransformGroup.cs

@ -18,20 +18,8 @@ namespace Avalonia.Media
Children.CollectionChanged += delegate Children.CollectionChanged += delegate
{ {
Children.ForEachItem( Children.ForEachItem(
(tr) => (tr) => tr.Changed += ChildTransform_Changed,
{ (tr) => tr.Changed -= ChildTransform_Changed,
if (tr is IMutableTransform mutTr)
{
mutTr.Changed += ChildTransform_Changed;
}
},
(tr) =>
{
if (tr is IMutableTransform mutTr)
{
mutTr.Changed -= ChildTransform_Changed;
}
},
() => { }); () => { });
}; };
} }
@ -73,7 +61,7 @@ namespace Avalonia.Media
} }
} }
public sealed class Transforms : AvaloniaList<ITransform> public sealed class Transforms : AvaloniaList<Transform>
{ {
} }
} }

6
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@ -195,6 +195,12 @@ namespace Avalonia.Rendering.SceneGraph
renderTransform = (-offset) * visual.RenderTransform.Value * (offset); renderTransform = (-offset) * visual.RenderTransform.Value * (offset);
} }
if (visual.IsMirrorTransform)
{
var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, visual.Bounds.Width, 0);
renderTransform *= mirrorMatrix;
}
m = renderTransform * m; m = renderTransform * m;
using (contextImpl.BeginUpdate(node)) using (contextImpl.BeginUpdate(node))

23
src/Avalonia.Visuals/Visual.cs

@ -68,6 +68,12 @@ namespace Avalonia
public static readonly StyledProperty<IBrush?> OpacityMaskProperty = public static readonly StyledProperty<IBrush?> OpacityMaskProperty =
AvaloniaProperty.Register<Visual, IBrush?>(nameof(OpacityMask)); AvaloniaProperty.Register<Visual, IBrush?>(nameof(OpacityMask));
/// <summary>
/// Defines the <see cref="IsMirrorTransform"/> property.
/// </summary>
public static readonly DirectProperty<Visual, bool> IsMirrorTransformProperty =
AvaloniaProperty.RegisterDirect<Visual, bool>(nameof(IsMirrorTransform), o => o.IsMirrorTransform);
/// <summary> /// <summary>
/// Defines the <see cref="RenderTransform"/> property. /// Defines the <see cref="RenderTransform"/> property.
/// </summary> /// </summary>
@ -96,6 +102,7 @@ namespace Avalonia
private TransformedBounds? _transformedBounds; private TransformedBounds? _transformedBounds;
private IRenderRoot? _visualRoot; private IRenderRoot? _visualRoot;
private IVisual? _visualParent; private IVisual? _visualParent;
private bool _isMirrorTransform;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="Visual"/> class. /// Initializes static members of the <see cref="Visual"/> class.
@ -107,7 +114,8 @@ namespace Avalonia
ClipProperty, ClipProperty,
ClipToBoundsProperty, ClipToBoundsProperty,
IsVisibleProperty, IsVisibleProperty,
OpacityProperty); OpacityProperty,
IsMirrorTransformProperty);
RenderTransformProperty.Changed.Subscribe(RenderTransformChanged); RenderTransformProperty.Changed.Subscribe(RenderTransformChanged);
ZIndexProperty.Changed.Subscribe(ZIndexChanged); ZIndexProperty.Changed.Subscribe(ZIndexChanged);
} }
@ -119,7 +127,7 @@ namespace Avalonia
{ {
// Disable transitions until we're added to the visual tree. // Disable transitions until we're added to the visual tree.
DisableTransitions(); DisableTransitions();
var visualChildren = new AvaloniaList<IVisual>(); var visualChildren = new AvaloniaList<IVisual>();
visualChildren.ResetBehavior = ResetBehavior.Remove; visualChildren.ResetBehavior = ResetBehavior.Remove;
visualChildren.Validate = visual => ValidateVisualChild(visual); visualChildren.Validate = visual => ValidateVisualChild(visual);
@ -219,10 +227,19 @@ namespace Avalonia
set { SetValue(OpacityMaskProperty, value); } set { SetValue(OpacityMaskProperty, value); }
} }
/// <summary>
/// Gets or sets a value indicating whether this control presented as mirror.
/// </summary>
public bool IsMirrorTransform
{
get { return _isMirrorTransform; }
protected set { SetAndRaise(IsMirrorTransformProperty, ref _isMirrorTransform, value); }
}
/// <summary> /// <summary>
/// Gets or sets the render transform of the control. /// Gets or sets the render transform of the control.
/// </summary> /// </summary>
public virtual ITransform? RenderTransform public ITransform? RenderTransform
{ {
get { return GetValue(RenderTransformProperty); } get { return GetValue(RenderTransformProperty); }
set { SetValue(RenderTransformProperty, value); } set { SetValue(RenderTransformProperty, value); }

6
src/Avalonia.Visuals/VisualExtensions.cs

@ -110,6 +110,12 @@ namespace Avalonia
result *= renderTransform; result *= renderTransform;
} }
if (v.IsMirrorTransform)
{
var mirrorMatrix = new Matrix(-1.0, 0.0, 0.0, 1.0, v.Bounds.Width, 0);
result *= mirrorMatrix;
}
var topLeft = v.Bounds.TopLeft; var topLeft = v.Bounds.TopLeft;
if (topLeft != default) if (topLeft != default)

5
src/Avalonia.Visuals/VisualTree/IVisual.cs

@ -75,6 +75,11 @@ namespace Avalonia.VisualTree
/// </summary> /// </summary>
IBrush? OpacityMask { get; set; } IBrush? OpacityMask { get; set; }
/// <summary>
/// Gets a value indicating whether this control presented as mirror.
/// </summary>
bool IsMirrorTransform { get; }
/// <summary> /// <summary>
/// Gets or sets the render transform of the control. /// Gets or sets the render transform of the control.
/// </summary> /// </summary>

Loading…
Cancel
Save