Browse Source

Move FlewDirection to Visual and fix tests

pull/9622/head
daniel mayost 4 years ago
parent
commit
4fae1b6e7a
  1. 90
      src/Avalonia.Base/Visual.cs
  2. 5
      src/Avalonia.Controls/ComboBox.cs
  3. 85
      src/Avalonia.Controls/Control.cs
  4. 27
      tests/Avalonia.Controls.UnitTests/FlowDirectionTests.cs

90
src/Avalonia.Base/Visual.cs

@ -89,6 +89,14 @@ namespace Avalonia
public static readonly StyledProperty<RelativePoint> RenderTransformOriginProperty = public static readonly StyledProperty<RelativePoint> RenderTransformOriginProperty =
AvaloniaProperty.Register<Visual, RelativePoint>(nameof(RenderTransformOrigin), defaultValue: RelativePoint.Center); 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> /// <summary>
/// Defines the <see cref="VisualParent"/> property. /// Defines the <see cref="VisualParent"/> property.
/// </summary> /// </summary>
@ -263,6 +271,15 @@ namespace Avalonia
set { SetValue(RenderTransformOriginProperty, value); } set { SetValue(RenderTransformOriginProperty, value); }
} }
/// <summary>
/// Gets or sets the text flow direction.
/// </summary>
public FlowDirection FlowDirection
{
get => GetValue(FlowDirectionProperty);
set => SetValue(FlowDirectionProperty, value);
}
/// <summary> /// <summary>
/// Gets or sets the Z index of the control. /// Gets or sets the Z index of the control.
/// </summary> /// </summary>
@ -306,6 +323,36 @@ namespace Avalonia
/// </summary> /// </summary>
internal Visual? VisualParent => _visualParent; 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> /// <summary>
/// Invalidates the visual and queues a repaint. /// Invalidates the visual and queues a repaint.
/// </summary> /// </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) protected override void LogicalChildrenCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
base.LogicalChildrenCollectionChanged(sender, e); base.LogicalChildrenCollectionChanged(sender, e);
@ -682,5 +745,32 @@ namespace Avalonia
visual.SetVisualParent(parent); 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 (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 ?? var flowDirection = content.VisualParent?.FlowDirection ?? FlowDirection.LeftToRight;
FlowDirection.LeftToRight;
rectangle.FlowDirection = flowDirection; rectangle.FlowDirection = flowDirection;
} }
} }

85
src/Avalonia.Controls/Control.cs

@ -91,13 +91,6 @@ namespace Avalonia.Controls
RoutedEvent.Register<Control, SizeChangedEventArgs>( RoutedEvent.Register<Control, SizeChangedEventArgs>(
nameof(SizeChanged), RoutingStrategies.Direct); 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: // Note the following:
// _loadedQueue : // _loadedQueue :
@ -170,15 +163,6 @@ namespace Avalonia.Controls
get => GetValue(TagProperty); get => GetValue(TagProperty);
set => SetValue(TagProperty, value); set => SetValue(TagProperty, value);
} }
/// <summary>
/// Gets or sets the text flow direction.
/// </summary>
public FlowDirection FlowDirection
{
get => GetValue(FlowDirectionProperty);
set => SetValue(FlowDirectionProperty, 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.
@ -229,39 +213,9 @@ namespace Avalonia.Controls
public new Control? Parent => (Control?)base.Parent; 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/> /// <inheritdoc/>
bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null; 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/> /// <inheritdoc/>
void ISetterValue.Initialize(ISetter setter) void ISetterValue.Initialize(ISetter setter)
{ {
@ -571,45 +525,6 @@ namespace Avalonia.Controls
RaiseEvent(sizeChangedEventArgs); 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;
} }
} }
} }

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

@ -8,7 +8,7 @@ namespace Avalonia.Controls.UnitTests
[Fact] [Fact]
public void HasMirrorTransform_Should_Be_True() public void HasMirrorTransform_Should_Be_True()
{ {
var target = new Control var target = new Visual
{ {
FlowDirection = FlowDirection.RightToLeft, FlowDirection = FlowDirection.RightToLeft,
}; };
@ -19,31 +19,36 @@ namespace Avalonia.Controls.UnitTests
[Fact] [Fact]
public void HasMirrorTransform_Of_LTR_Children_Should_Be_True_For_RTL_Parent() public void HasMirrorTransform_Of_LTR_Children_Should_Be_True_For_RTL_Parent()
{ {
Control child; var child = new Visual()
var target = new Decorator {
FlowDirection = FlowDirection.LeftToRight,
};
var target = new Visual
{ {
FlowDirection = FlowDirection.RightToLeft, FlowDirection = FlowDirection.RightToLeft,
Child = child = new Control()
}; };
target.VisualChildren.Add(child);
child.FlowDirection = FlowDirection.LeftToRight; child.InvalidateMirrorTransform();
Assert.True(target.HasMirrorTransform); Assert.True(target.HasMirrorTransform);
Assert.True(child.HasMirrorTransform); Assert.True(child.HasMirrorTransform);
} }
[Fact] [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 var target = new Decorator
{ {
FlowDirection = FlowDirection.LeftToRight, FlowDirection = FlowDirection.LeftToRight,
Child = child = new Control()
{
FlowDirection = FlowDirection.LeftToRight,
}
}; };
target.VisualChildren.Add(child);
Assert.False(target.HasMirrorTransform); Assert.False(target.HasMirrorTransform);
Assert.False(child.HasMirrorTransform); Assert.False(child.HasMirrorTransform);

Loading…
Cancel
Save