Browse Source

Merge pull request #9622 from danielmayost/fixes/moveFlowDirection

Move FlowFirection to Visual
pull/9464/head
Max Katz 3 years ago
committed by GitHub
parent
commit
511d7b5957
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 90
      src/Avalonia.Base/Visual.cs
  2. 5
      src/Avalonia.Controls/ComboBox.cs
  3. 85
      src/Avalonia.Controls/Control.cs
  4. 6
      src/Avalonia.Controls/TopLevel.cs
  5. 27
      tests/Avalonia.Base.UnitTests/FlowDirectionTests.cs

90
src/Avalonia.Base/Visual.cs

@ -89,6 +89,14 @@ namespace Avalonia
public static readonly StyledProperty<RelativePoint> RenderTransformOriginProperty =
AvaloniaProperty.Register<Visual, RelativePoint>(nameof(RenderTransformOrigin), defaultValue: RelativePoint.Center);
/// <summary>
/// Defines the <see cref="FlowDirection"/> property.
/// </summary>
public static readonly AttachedProperty<FlowDirection> FlowDirectionProperty =
AvaloniaProperty.RegisterAttached<Visual, Visual, FlowDirection>(
nameof(FlowDirection),
inherits: true);
/// <summary>
/// Defines the <see cref="VisualParent"/> property.
/// </summary>
@ -263,6 +271,15 @@ namespace Avalonia
set { SetValue(RenderTransformOriginProperty, value); }
}
/// <summary>
/// Gets or sets the text flow direction.
/// </summary>
public FlowDirection FlowDirection
{
get => GetValue(FlowDirectionProperty);
set => SetValue(FlowDirectionProperty, value);
}
/// <summary>
/// Gets or sets the Z index of the control.
/// </summary>
@ -306,6 +323,36 @@ namespace Avalonia
/// </summary>
internal Visual? VisualParent => _visualParent;
/// <summary>
/// Gets a value indicating whether control bypass FlowDirecton policies.
/// </summary>
/// <remarks>
/// Related to FlowDirection system and returns false as default, so if
/// <see cref="FlowDirection"/> is RTL then control will get a mirror presentation.
/// For controls that want to avoid this behavior, override this property and return true.
/// </remarks>
protected virtual bool BypassFlowDirectionPolicies => false;
/// <summary>
/// Gets the value of the attached <see cref="FlowDirectionProperty"/> on a control.
/// </summary>
/// <param name="visual">The control.</param>
/// <returns>The flow direction.</returns>
public static FlowDirection GetFlowDirection(Visual visual)
{
return visual.GetValue(FlowDirectionProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FlowDirectionProperty"/> on a control.
/// </summary>
/// <param name="visual">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFlowDirection(Visual visual, FlowDirection value)
{
visual.SetValue(FlowDirectionProperty, value);
}
/// <summary>
/// Invalidates the visual and queues a repaint.
/// </summary>
@ -387,6 +434,22 @@ namespace Avalonia
}
}
/// <inheritdoc/>
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == FlowDirectionProperty)
{
InvalidateMirrorTransform();
foreach (var child in VisualChildren)
{
child.InvalidateMirrorTransform();
}
}
}
protected override void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
base.LogicalChildrenCollectionChanged(sender, e);
@ -682,5 +745,32 @@ namespace Avalonia
visual.SetVisualParent(parent);
}
}
/// <summary>
/// Computes the <see cref="HasMirrorTransform"/> value according to the
/// <see cref="FlowDirection"/> and <see cref="BypassFlowDirectionPolicies"/>
/// </summary>
public virtual void InvalidateMirrorTransform()
{
var flowDirection = this.FlowDirection;
var parentFlowDirection = FlowDirection.LeftToRight;
bool bypassFlowDirectionPolicies = BypassFlowDirectionPolicies;
bool parentBypassFlowDirectionPolicies = false;
var parent = VisualParent;
if (parent != null)
{
parentFlowDirection = parent.FlowDirection;
parentBypassFlowDirectionPolicies = parent.BypassFlowDirectionPolicies;
}
bool thisShouldBeMirrored = flowDirection == FlowDirection.RightToLeft && !bypassFlowDirectionPolicies;
bool parentShouldBeMirrored = parentFlowDirection == FlowDirection.RightToLeft && !parentBypassFlowDirectionPolicies;
bool shouldApplyMirrorTransform = thisShouldBeMirrored != parentShouldBeMirrored;
HasMirrorTransform = shouldApplyMirrorTransform;
}
}
}

5
src/Avalonia.Controls/ComboBox.cs

@ -454,10 +454,9 @@ namespace Avalonia.Controls
{
if (SelectionBoxItem is Rectangle rectangle)
{
if ((rectangle.Fill as VisualBrush)?.Visual is Control content)
if ((rectangle.Fill as VisualBrush)?.Visual is Visual content)
{
var flowDirection = (((Visual)content!).VisualParent as Control)?.FlowDirection ??
FlowDirection.LeftToRight;
var flowDirection = content.VisualParent?.FlowDirection ?? FlowDirection.LeftToRight;
rectangle.FlowDirection = flowDirection;
}
}

85
src/Avalonia.Controls/Control.cs

@ -91,13 +91,6 @@ namespace Avalonia.Controls
RoutedEvent.Register<Control, SizeChangedEventArgs>(
nameof(SizeChanged), RoutingStrategies.Direct);
/// <summary>
/// Defines the <see cref="FlowDirection"/> property.
/// </summary>
public static readonly AttachedProperty<FlowDirection> FlowDirectionProperty =
AvaloniaProperty.RegisterAttached<Control, Control, FlowDirection>(
nameof(FlowDirection),
inherits: true);
// Note the following:
// _loadedQueue :
@ -170,15 +163,6 @@ namespace Avalonia.Controls
get => GetValue(TagProperty);
set => SetValue(TagProperty, value);
}
/// <summary>
/// Gets or sets the text flow direction.
/// </summary>
public FlowDirection FlowDirection
{
get => GetValue(FlowDirectionProperty);
set => SetValue(FlowDirectionProperty, value);
}
/// <summary>
/// Occurs when the user has completed a context input gesture, such as a right-click.
@ -229,39 +213,9 @@ namespace Avalonia.Controls
public new Control? Parent => (Control?)base.Parent;
/// <summary>
/// Gets the value of the attached <see cref="FlowDirectionProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <returns>The flow direction.</returns>
public static FlowDirection GetFlowDirection(Control control)
{
return control.GetValue(FlowDirectionProperty);
}
/// <summary>
/// Sets the value of the attached <see cref="FlowDirectionProperty"/> on a control.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="value">The property value to set.</param>
public static void SetFlowDirection(Control control, FlowDirection value)
{
control.SetValue(FlowDirectionProperty, value);
}
/// <inheritdoc/>
bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null;
/// <summary>
/// Gets a value indicating whether control bypass FlowDirecton policies.
/// </summary>
/// <remarks>
/// Related to FlowDirection system and returns false as default, so if
/// <see cref="FlowDirection"/> is RTL then control will get a mirror presentation.
/// For controls that want to avoid this behavior, override this property and return true.
/// </remarks>
protected virtual bool BypassFlowDirectionPolicies => false;
/// <inheritdoc/>
void ISetterValue.Initialize(ISetter setter)
{
@ -571,45 +525,6 @@ namespace Avalonia.Controls
RaiseEvent(sizeChangedEventArgs);
}
}
else if (change.Property == FlowDirectionProperty)
{
InvalidateMirrorTransform();
foreach (var visual in VisualChildren)
{
if (visual is Control child)
{
child.InvalidateMirrorTransform();
}
}
}
}
/// <summary>
/// Computes the <see cref="Visual.HasMirrorTransform"/> value according to the
/// <see cref="FlowDirection"/> and <see cref="BypassFlowDirectionPolicies"/>
/// </summary>
public virtual void InvalidateMirrorTransform()
{
var flowDirection = this.FlowDirection;
var parentFlowDirection = FlowDirection.LeftToRight;
bool bypassFlowDirectionPolicies = BypassFlowDirectionPolicies;
bool parentBypassFlowDirectionPolicies = false;
var parent = this.VisualParent as Control;
if (parent != null)
{
parentFlowDirection = parent.FlowDirection;
parentBypassFlowDirectionPolicies = parent.BypassFlowDirectionPolicies;
}
bool thisShouldBeMirrored = flowDirection == FlowDirection.RightToLeft && !bypassFlowDirectionPolicies;
bool parentShouldBeMirrored = parentFlowDirection == FlowDirection.RightToLeft && !parentBypassFlowDirectionPolicies;
bool shouldApplyMirrorTransform = thisShouldBeMirrored != parentShouldBeMirrored;
HasMirrorTransform = shouldApplyMirrorTransform;
}
}
}

6
src/Avalonia.Controls/TopLevel.cs

@ -357,12 +357,6 @@ namespace Avalonia.Controls
/// </summary>
protected virtual ILayoutManager CreateLayoutManager() => new LayoutManager(this);
public override void InvalidateMirrorTransform()
{
}
protected override bool BypassFlowDirectionPolicies => true;
/// <summary>
/// Handles a paint notification from <see cref="ITopLevelImpl.Resized"/>.
/// </summary>

27
tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs → tests/Avalonia.Base.UnitTests/FlowDirectionTests.cs

@ -8,7 +8,7 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void HasMirrorTransform_Should_Be_True()
{
var target = new Control
var target = new Visual
{
FlowDirection = FlowDirection.RightToLeft,
};
@ -19,31 +19,36 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void HasMirrorTransform_Of_LTR_Children_Should_Be_True_For_RTL_Parent()
{
Control child;
var target = new Decorator
var child = new Visual()
{
FlowDirection = FlowDirection.LeftToRight,
};
var target = new Visual
{
FlowDirection = FlowDirection.RightToLeft,
Child = child = new Control()
};
target.VisualChildren.Add(child);
child.FlowDirection = FlowDirection.LeftToRight;
child.InvalidateMirrorTransform();
Assert.True(target.HasMirrorTransform);
Assert.True(child.HasMirrorTransform);
}
[Fact]
public void HasMirrorTransform_Of_Children_Is_Updated_After_Parent_Changeed()
public void HasMirrorTransform_Of_Children_Is_Updated_After_Parent_Changed()
{
Control child;
var child = new Visual()
{
FlowDirection = FlowDirection.LeftToRight,
};
var target = new Decorator
{
FlowDirection = FlowDirection.LeftToRight,
Child = child = new Control()
{
FlowDirection = FlowDirection.LeftToRight,
}
};
target.VisualChildren.Add(child);
Assert.False(target.HasMirrorTransform);
Assert.False(child.HasMirrorTransform);
Loading…
Cancel
Save