|
|
|
@ -67,10 +67,17 @@ namespace Avalonia.Controls |
|
|
|
/// </summary>
|
|
|
|
public static readonly AttachedProperty<FlowDirection> FlowDirectionProperty = |
|
|
|
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 IControl? _focusAdorner; |
|
|
|
private AutomationPeer? _automationPeer; |
|
|
|
private bool _hasMirrorTransform; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets or sets the control's focus adorner.
|
|
|
|
@ -126,6 +133,21 @@ namespace Avalonia.Controls |
|
|
|
set => SetValue(FlowDirectionProperty, value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override ITransform? RenderTransform |
|
|
|
{ |
|
|
|
get => base.RenderTransform; |
|
|
|
set |
|
|
|
{ |
|
|
|
if (_hasMirrorTransform) |
|
|
|
{ |
|
|
|
value = MargeTransforms(MirrorTrasform(), value); |
|
|
|
} |
|
|
|
|
|
|
|
base.RenderTransform = value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Occurs when the user has completed a context input gesture, such as a right-click.
|
|
|
|
/// </summary>
|
|
|
|
@ -312,76 +334,152 @@ namespace Avalonia.Controls |
|
|
|
|
|
|
|
static Control() |
|
|
|
{ |
|
|
|
AffectsArrange<Control>(FlowDirectionProperty); |
|
|
|
//var m = new StyledPropertyMetadata<ITransform?>(coerce: (s, e) => null);
|
|
|
|
//RenderTransformProperty.OverrideMetadata<Control>(m);
|
|
|
|
|
|
|
|
//AffectsRender<Control>(FlowDirectionProperty);
|
|
|
|
//FlowDirectionProperty.Changed.AddClassHandler<Control>((s, e) =>
|
|
|
|
//{
|
|
|
|
// s.InvalidateFlowDirection();
|
|
|
|
// foreach (var logical in LogicalTree.LogicalExtensions.GetLogicalDescendants(s))
|
|
|
|
// {
|
|
|
|
// if (logical is Control control)
|
|
|
|
// {
|
|
|
|
// //if (control)
|
|
|
|
// //control.InvalidateFlowDirection();
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//});
|
|
|
|
} |
|
|
|
|
|
|
|
private bool _mirrorApplied; |
|
|
|
|
|
|
|
protected virtual bool ShouldBeMirroredIfRightToLeft() |
|
|
|
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change) |
|
|
|
{ |
|
|
|
if (Parent is Control parent) |
|
|
|
{ |
|
|
|
return parent.ShouldBeMirroredIfRightToLeft(); |
|
|
|
} |
|
|
|
else |
|
|
|
base.OnPropertyChanged(change); |
|
|
|
|
|
|
|
if (change.Property == FlowDirectionProperty) |
|
|
|
{ |
|
|
|
return true; |
|
|
|
// Avoid inherit value change to invoke this method
|
|
|
|
if (!GetBaseValue(FlowDirectionProperty, change.Priority).HasValue) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
InvalidateFlowDirection(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
protected override void ArrangeCore(Rect finalRect) |
|
|
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) |
|
|
|
{ |
|
|
|
base.ArrangeCore(finalRect); |
|
|
|
base.OnAttachedToVisualTree(e); |
|
|
|
|
|
|
|
InvalidateFlowDirection(); |
|
|
|
} |
|
|
|
|
|
|
|
protected override void OnAttachedToLogicalTree(LogicalTree.LogicalTreeAttachmentEventArgs e) |
|
|
|
{ |
|
|
|
base.OnAttachedToLogicalTree(e); |
|
|
|
//InvalidateFlowDirection();
|
|
|
|
} |
|
|
|
|
|
|
|
protected virtual bool ShouldGetMirrored() => true; |
|
|
|
|
|
|
|
private void InvalidateFlowDirection() |
|
|
|
{ |
|
|
|
FlowDirection parentFD = FlowDirection.LeftToRight; |
|
|
|
FlowDirection thisFD = FlowDirection; |
|
|
|
bool shouldBeMirroredIfRightToLeft = ShouldBeMirroredIfRightToLeft(); |
|
|
|
|
|
|
|
if (Parent is Control control) |
|
|
|
bool parentShouldGetMirrored = true; |
|
|
|
bool thisShouldGetMirrored = ShouldGetMirrored(); |
|
|
|
|
|
|
|
if (((Visual)this).GetVisualParent() is Control control) |
|
|
|
{ |
|
|
|
parentFD = control.FlowDirection; |
|
|
|
parentShouldGetMirrored = control.ShouldGetMirrored(); |
|
|
|
} |
|
|
|
|
|
|
|
bool shouldMirror; |
|
|
|
if (shouldBeMirroredIfRightToLeft) |
|
|
|
else if (Parent is Control logicalControl) |
|
|
|
{ |
|
|
|
shouldMirror = ShuoldApplyMirrorTransform(parentFD, thisFD); |
|
|
|
if (Parent is Popup && thisFD == FlowDirection.RightToLeft) |
|
|
|
{ |
|
|
|
shouldMirror = true; |
|
|
|
} |
|
|
|
parentFD = logicalControl.FlowDirection; |
|
|
|
parentShouldGetMirrored = logicalControl.ShouldGetMirrored(); |
|
|
|
} |
|
|
|
|
|
|
|
bool shouldBeMirrored = thisFD == FlowDirection.RightToLeft && thisShouldGetMirrored; |
|
|
|
bool parentMirrored = parentFD == FlowDirection.RightToLeft && parentShouldGetMirrored; |
|
|
|
|
|
|
|
bool shouldApplyMirrorTransform = shouldBeMirrored != parentMirrored; |
|
|
|
|
|
|
|
if (shouldApplyMirrorTransform) |
|
|
|
{ |
|
|
|
AddMirrorTransform(); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
shouldMirror = ShuoldApplyMirrorTransform(parentFD, FlowDirection.LeftToRight); |
|
|
|
RemoveMirrorTransform(); |
|
|
|
} |
|
|
|
|
|
|
|
if (shouldMirror) |
|
|
|
foreach (var visual in VisualChildren) |
|
|
|
{ |
|
|
|
ApplyMirrorTransform(); |
|
|
|
if (visual is Control child) |
|
|
|
{ |
|
|
|
child.InvalidateFlowDirection(); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
} |
|
|
|
|
|
|
|
private void AddMirrorTransform() |
|
|
|
{ |
|
|
|
if (_hasMirrorTransform) |
|
|
|
{ |
|
|
|
//RenderTransform = null;
|
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var mirrorTransform = MirrorTrasform(); |
|
|
|
|
|
|
|
ITransform? finalTransform = mirrorTransform; |
|
|
|
if (RenderTransform != null) |
|
|
|
{ |
|
|
|
finalTransform = MargeTransforms(RenderTransform, mirrorTransform); |
|
|
|
} |
|
|
|
|
|
|
|
RenderTransform = finalTransform; |
|
|
|
_hasMirrorTransform = true; |
|
|
|
} |
|
|
|
|
|
|
|
private void ApplyMirrorTransform() |
|
|
|
private void RemoveMirrorTransform() |
|
|
|
{ |
|
|
|
if (_mirrorApplied) |
|
|
|
if (!_hasMirrorTransform) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
var transform = new MatrixTransform(new Avalonia.Matrix(-1, 0, 0, 1, 0.0, 0.0)); |
|
|
|
RenderTransform = transform; |
|
|
|
_mirrorApplied = true; |
|
|
|
var mirrorTransform = MirrorTrasform(); |
|
|
|
|
|
|
|
ITransform? finalTransform = MargeTransforms(RenderTransform, mirrorTransform); |
|
|
|
if (finalTransform!.Value == Matrix.Identity) |
|
|
|
{ |
|
|
|
finalTransform = null; |
|
|
|
} |
|
|
|
|
|
|
|
_hasMirrorTransform = false; |
|
|
|
RenderTransform = finalTransform; |
|
|
|
} |
|
|
|
|
|
|
|
internal static bool ShuoldApplyMirrorTransform(FlowDirection parentFD, FlowDirection thisFD) |
|
|
|
static ITransform? MargeTransforms(ITransform? iTransform1, ITransform? iTransform2) |
|
|
|
{ |
|
|
|
return ((parentFD == FlowDirection.LeftToRight && thisFD == FlowDirection.RightToLeft) || |
|
|
|
(parentFD == FlowDirection.RightToLeft && thisFD == FlowDirection.LeftToRight)); |
|
|
|
// don't know how to marge ITransform
|
|
|
|
if (iTransform1 is Transform transform1 && iTransform2 is Transform transform2) |
|
|
|
{ |
|
|
|
TransformGroup groupTransform = new TransformGroup(); |
|
|
|
|
|
|
|
groupTransform.Children.Add(transform1); |
|
|
|
groupTransform.Children.Add(transform2); |
|
|
|
|
|
|
|
return groupTransform; |
|
|
|
} |
|
|
|
|
|
|
|
return iTransform1; |
|
|
|
} |
|
|
|
|
|
|
|
static ITransform MirrorTrasform() => |
|
|
|
new MatrixTransform(new Avalonia.Matrix(-1, 0, 0, 1, 0.0, 0.0)); |
|
|
|
} |
|
|
|
} |
|
|
|
|