Parcourir la source

continue working

daniel mayost il y a 3 ans
Parent
commit
d5fd84ebc0

+ 1 - 1
samples/ControlCatalog/Pages/ScreenPage.cs

@@ -79,6 +79,6 @@ namespace ControlCatalog.Pages
                 Typeface.Default, 12, Brushes.Green);
         }
 
-        protected override bool ShouldBeMirroredIfRightToLeft() => false;
+        protected override bool ShouldGetMirrored() => false;
     }
 }

+ 134 - 36
src/Avalonia.Controls/Control.cs

@@ -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));
     }
 }

+ 2 - 0
src/Avalonia.Controls/Presenters/TextPresenter.cs

@@ -798,5 +798,7 @@ namespace Avalonia.Controls.Presenters
                 }
             }
         }
+
+        protected override bool ShouldGetMirrored() => false;
     }
 }

+ 1 - 1
src/Avalonia.Controls/TextBlock.cs

@@ -613,6 +613,6 @@ namespace Avalonia.Controls
             InvalidateTextLayout();
         }
 
-        protected override bool ShouldBeMirroredIfRightToLeft() => false;
+        protected override bool ShouldGetMirrored() => false;
     }
 }

+ 0 - 2
src/Avalonia.Controls/TextBox.cs

@@ -1504,7 +1504,5 @@ namespace Avalonia.Controls
                 }
             }
         }
-
-        protected override bool ShouldBeMirroredIfRightToLeft() => false;
     }
 }

+ 2 - 0
src/Avalonia.Controls/TopLevel.cs

@@ -529,5 +529,7 @@ namespace Avalonia.Controls
 
         ITextInputMethodImpl? ITextInputMethodRoot.InputMethod =>
             (PlatformImpl as ITopLevelImplWithTextInputMethod)?.TextInputMethod;
+
+        protected override bool ShouldGetMirrored() => false;
     }
 }

+ 1 - 0
src/Avalonia.Themes.Fluent/Controls/CheckBox.xaml

@@ -152,6 +152,7 @@
     <Setter Property="Data" Value="M1507 31L438 1101L-119 543L-29 453L438 919L1417 -59L1507 31Z" />
     <Setter Property="Width" Value="9" />
     <Setter Property="Opacity" Value="1" />
+    <Setter Property="FlowDirection" Value="LeftToRight" />
   </Style>
 
   <!-- Checked PointerOver State -->

+ 1 - 1
src/Avalonia.Visuals/Visual.cs

@@ -222,7 +222,7 @@ namespace Avalonia
         /// <summary>
         /// Gets or sets the render transform of the control.
         /// </summary>
-        public ITransform? RenderTransform
+        public virtual ITransform? RenderTransform
         {
             get { return GetValue(RenderTransformProperty); }
             set { SetValue(RenderTransformProperty, value); }