diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 39333f37ba..3f4fbb0d50 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -32,7 +32,7 @@ jobs: - job: macOS pool: - vmImage: 'xcode9-macos10.13' + vmImage: 'macOS-10.14' steps: - task: DotNetCoreInstaller@0 inputs: @@ -49,7 +49,7 @@ jobs: inputs: actions: 'build' scheme: '' - sdk: 'macosx10.13' + sdk: 'macosx10.14' configuration: 'Release' xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' xcodeVersion: 'default' # Options: 8, 9, default, specifyPath diff --git a/nukebuild/Numerge b/nukebuild/Numerge index 4464343aef..aef10ae67d 160000 --- a/nukebuild/Numerge +++ b/nukebuild/Numerge @@ -1 +1 @@ -Subproject commit 4464343aef5c8ab7a42fcb20a483a6058199f8b8 +Subproject commit aef10ae67dc55c95f49b52a505a0be33bfa297a5 diff --git a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs index 4b4203ba40..92734b128d 100644 --- a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs +++ b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs @@ -927,7 +927,7 @@ namespace Avalonia.Collections /// ///

/// Clear a sort criteria by assigning SortDescription.Empty to this property. - /// One or more sort criteria in form of + /// One or more sort criteria in form of /// can be used, each specifying a property and direction to sort by. ///

///
@@ -4312,4 +4312,4 @@ namespace Avalonia.Collections } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs index d5ad4c75f8..f15442addf 100644 --- a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs @@ -8,7 +8,6 @@ using Avalonia.Metadata; [assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.DesignerSupport")] -[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] -[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")] diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs index b51583d8b3..90a27d0b31 100644 --- a/src/Avalonia.Controls/Grid.cs +++ b/src/Avalonia.Controls/Grid.cs @@ -177,6 +177,17 @@ namespace Avalonia.Controls return element.GetValue(RowSpanProperty); } + + /// + /// Gets the value of the IsSharedSizeScope attached property for a control. + /// + /// The control. + /// The control's IsSharedSizeScope value. + public static bool GetIsSharedSizeScope(AvaloniaObject element) + { + return element.GetValue(IsSharedSizeScopeProperty); + } + /// /// Sets the value of the Column attached property for a control. /// @@ -217,6 +228,16 @@ namespace Avalonia.Controls element.SetValue(RowSpanProperty, value); } + /// + /// Sets the value of IsSharedSizeScope property for a control. + /// + /// The control. + /// The IsSharedSizeScope value. + public static void SetIsSharedSizeScope(AvaloniaObject element, bool value) + { + element.SetValue(IsSharedSizeScopeProperty, value); + } + /// /// Gets the result of the last column measurement. /// Use this result to reduce the arrange calculation. diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index c696fe7975..fa6f5787be 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -81,23 +81,22 @@ namespace Avalonia.Controls protected override Size MeasureOverride(Size availableSize) { var source = Source; + var result = new Size(); if (source != null) { Size sourceSize = new Size(source.PixelSize.Width, source.PixelSize.Height); if (double.IsInfinity(availableSize.Width) || double.IsInfinity(availableSize.Height)) { - return sourceSize; + result = sourceSize; } else { - return Stretch.CalculateSize(availableSize, sourceSize); + result = Stretch.CalculateSize(availableSize, sourceSize); } } - else - { - return new Size(); - } + + return result.Constrain(availableSize); } /// diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index f8ae9f4249..0918da1a90 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -147,7 +147,10 @@ namespace Avalonia.Platform e.Handled = true; } else if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl || e.Key == Key.LeftAlt || e.Key == Key.RightAlt) - RaiseEventAndUpdateCursor(RawDragEventType.DragOver, _lastRoot, _lastPosition, e.Modifiers); + { + if (_lastRoot != null) + RaiseEventAndUpdateCursor(RawDragEventType.DragOver, _lastRoot, _lastPosition, e.Modifiers); + } } private void ProcessMouseEvents(RawMouseEventArgs e) diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs index 57dbeba1cc..499dfb5320 100644 --- a/src/Avalonia.Controls/Shapes/Shape.cs +++ b/src/Avalonia.Controls/Shapes/Shape.cs @@ -21,13 +21,19 @@ namespace Avalonia.Controls.Shapes public static readonly StyledProperty> StrokeDashArrayProperty = AvaloniaProperty.Register>(nameof(StrokeDashArray)); - + public static readonly StyledProperty StrokeDashOffsetProperty = AvaloniaProperty.Register(nameof(StrokeDashOffset)); public static readonly StyledProperty StrokeThicknessProperty = AvaloniaProperty.Register(nameof(StrokeThickness)); + public static readonly StyledProperty StrokeLineCapProperty = + AvaloniaProperty.Register(nameof(StrokeLineCap), PenLineCap.Flat); + + public static readonly StyledProperty StrokeJoinProperty = + AvaloniaProperty.Register(nameof(StrokeJoin), PenLineJoin.Miter); + private Matrix _transform = Matrix.Identity; private Geometry _definingGeometry; private Geometry _renderedGeometry; @@ -36,7 +42,9 @@ namespace Avalonia.Controls.Shapes static Shape() { AffectsMeasure(StretchProperty, StrokeThicknessProperty); - AffectsRender(FillProperty, StrokeProperty, StrokeDashArrayProperty); + + AffectsRender(FillProperty, StrokeProperty, StrokeDashArrayProperty, StrokeDashOffsetProperty, + StrokeThicknessProperty, StrokeLineCapProperty, StrokeJoinProperty); } public Geometry DefiningGeometry @@ -106,7 +114,7 @@ namespace Avalonia.Controls.Shapes get { return GetValue(StrokeDashArrayProperty); } set { SetValue(StrokeDashArrayProperty, value); } } - + public double StrokeDashOffset { get { return GetValue(StrokeDashOffsetProperty); } @@ -119,13 +127,17 @@ namespace Avalonia.Controls.Shapes set { SetValue(StrokeThicknessProperty, value); } } - public PenLineCap StrokeDashCap { get; set; } = PenLineCap.Flat; - - public PenLineCap StrokeStartLineCap { get; set; } = PenLineCap.Flat; - - public PenLineCap StrokeEndLineCap { get; set; } = PenLineCap.Flat; + public PenLineCap StrokeLineCap + { + get { return GetValue(StrokeLineCapProperty); } + set { SetValue(StrokeLineCapProperty, value); } + } - public PenLineJoin StrokeJoin { get; set; } = PenLineJoin.Miter; + public PenLineJoin StrokeJoin + { + get { return GetValue(StrokeJoinProperty); } + set { SetValue(StrokeJoinProperty, value); } + } public override void Render(DrawingContext context) { @@ -133,8 +145,8 @@ namespace Avalonia.Controls.Shapes if (geometry != null) { - var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray, StrokeDashOffset), - StrokeDashCap, StrokeStartLineCap, StrokeEndLineCap, StrokeJoin); + var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray, StrokeDashOffset), + StrokeLineCap, StrokeJoin); context.DrawGeometry(Fill, pen, geometry); } } @@ -169,11 +181,11 @@ namespace Avalonia.Controls.Shapes protected void InvalidateGeometry() { - this._renderedGeometry = null; - this._definingGeometry = null; + _renderedGeometry = null; + _definingGeometry = null; InvalidateMeasure(); } - + protected override Size MeasureOverride(Size availableSize) { bool deferCalculateTransform; @@ -203,10 +215,10 @@ namespace Avalonia.Controls.Shapes return CalculateShapeSizeAndSetTransform(availableSize); } } - + protected override Size ArrangeOverride(Size finalSize) { - if(_calculateTransformOnArrange) + if (_calculateTransformOnArrange) { _calculateTransformOnArrange = false; CalculateShapeSizeAndSetTransform(finalSize); @@ -312,25 +324,25 @@ namespace Avalonia.Controls.Shapes private static void AffectsGeometryInvalidate(AvaloniaPropertyChangedEventArgs e) { - var control = e.Sender as Shape; + if (!(e.Sender is Shape control)) + { + return; + } - if (control != null) + // If the geometry is invalidated when Bounds changes, only invalidate when the Size + // portion changes. + if (e.Property == BoundsProperty) { - // If the geometry is invalidated when Bounds changes, only invalidate when the Size - // portion changes. - if (e.Property == BoundsProperty) - { - var oldBounds = (Rect)e.OldValue; - var newBounds = (Rect)e.NewValue; + var oldBounds = (Rect)e.OldValue; + var newBounds = (Rect)e.NewValue; - if (oldBounds.Size == newBounds.Size) - { - return; - } + if (oldBounds.Size == newBounds.Size) + { + return; } - - control.InvalidateGeometry(); } + + control.InvalidateGeometry(); } } } diff --git a/src/Avalonia.Controls/StackPanel.cs b/src/Avalonia.Controls/StackPanel.cs index df0c113cc0..d89df8556b 100644 --- a/src/Avalonia.Controls/StackPanel.cs +++ b/src/Avalonia.Controls/StackPanel.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using Avalonia.Input; +using Avalonia.Layout; namespace Avalonia.Controls { @@ -219,30 +220,16 @@ namespace Avalonia.Controls measuredWidth -= (hasVisibleChild ? spacing : 0); } - return new Size(measuredWidth, measuredHeight); + return new Size(measuredWidth, measuredHeight).Constrain(availableSize); } - /// - /// Arranges the control's children. - /// - /// The size allocated to the control. - /// The space taken. + /// protected override Size ArrangeOverride(Size finalSize) { var orientation = Orientation; - double arrangedWidth = finalSize.Width; - double arrangedHeight = finalSize.Height; - double spacing = Spacing; - bool hasVisibleChild = Children.Any(c => c.IsVisible); - - if (Orientation == Orientation.Vertical) - { - arrangedHeight = 0; - } - else - { - arrangedWidth = 0; - } + var spacing = Spacing; + var finalRect = new Rect(finalSize); + var pos = 0.0; foreach (Control child in Children) { @@ -251,32 +238,21 @@ namespace Avalonia.Controls if (orientation == Orientation.Vertical) { - double width = Math.Max(childWidth, arrangedWidth); - Rect childFinal = new Rect(0, arrangedHeight, width, childHeight); - ArrangeChild(child, childFinal, finalSize, orientation); - arrangedWidth = Math.Max(arrangedWidth, childWidth); - arrangedHeight += childHeight + (child.IsVisible ? spacing : 0); + var rect = new Rect(0, pos, childWidth, childHeight) + .Align(finalRect, child.HorizontalAlignment, VerticalAlignment.Top); + ArrangeChild(child, rect, finalSize, orientation); + pos += childHeight + spacing; } else { - double height = Math.Max(childHeight, arrangedHeight); - Rect childFinal = new Rect(arrangedWidth, 0, childWidth, height); - ArrangeChild(child, childFinal, finalSize, orientation); - arrangedWidth += childWidth + (child.IsVisible ? spacing : 0); - arrangedHeight = Math.Max(arrangedHeight, childHeight); + var rect = new Rect(pos, 0, childWidth, childHeight) + .Align(finalRect, HorizontalAlignment.Left, child.VerticalAlignment); + ArrangeChild(child, rect, finalSize, orientation); + pos += childWidth + spacing; } } - if (orientation == Orientation.Vertical) - { - arrangedHeight = Math.Max(arrangedHeight - (hasVisibleChild ? spacing : 0), finalSize.Height); - } - else - { - arrangedWidth = Math.Max(arrangedWidth - (hasVisibleChild ? spacing : 0), finalSize.Width); - } - - return new Size(arrangedWidth, arrangedHeight); + return finalSize; } internal virtual void ArrangeChild( diff --git a/src/Avalonia.Controls/Viewbox.cs b/src/Avalonia.Controls/Viewbox.cs index 3a070d07b2..781c93bcbe 100644 --- a/src/Avalonia.Controls/Viewbox.cs +++ b/src/Avalonia.Controls/Viewbox.cs @@ -49,7 +49,7 @@ namespace Avalonia.Controls var scale = GetScale(availableSize, childSize, Stretch); - return childSize * scale; + return (childSize * scale).Constrain(availableSize); } return new Size(); diff --git a/src/Avalonia.Layout/LayoutExtensions.cs b/src/Avalonia.Layout/LayoutExtensions.cs new file mode 100644 index 0000000000..737bbb083c --- /dev/null +++ b/src/Avalonia.Layout/LayoutExtensions.cs @@ -0,0 +1,62 @@ +using System; + +namespace Avalonia.Layout +{ + /// + /// Extension methods for layout types. + /// + public static class LayoutExtensions + { + /// + /// Aligns a rect in a constraining rect according to horizontal and vertical alignment + /// settings. + /// + /// The rect to align. + /// The constraining rect. + /// The horizontal alignment. + /// The vertical alignment. + /// + public static Rect Align( + this Rect rect, + Rect constraint, + HorizontalAlignment horizontalAlignment, + VerticalAlignment verticalAlignment) + { + switch (horizontalAlignment) + { + case HorizontalAlignment.Center: + rect = rect.WithX((constraint.Width - rect.Width) / 2); + break; + case HorizontalAlignment.Right: + rect = rect.WithX(constraint.Width - rect.Width); + break; + case HorizontalAlignment.Stretch: + rect = new Rect( + 0, + rect.Y, + Math.Max(constraint.Width, rect.Width), + rect.Height); + break; + } + + switch (verticalAlignment) + { + case VerticalAlignment.Center: + rect = rect.WithY((constraint.Height - rect.Height) / 2); + break; + case VerticalAlignment.Bottom: + rect = rect.WithY(constraint.Height - rect.Height); + break; + case VerticalAlignment.Stretch: + rect = new Rect( + rect.X, + 0, + rect.Width, + Math.Max(constraint.Height, rect.Height)); + break; + } + + return rect; + } + } +} diff --git a/src/Avalonia.Layout/Layoutable.cs b/src/Avalonia.Layout/Layoutable.cs index d5e3a1631e..662f48ec44 100644 --- a/src/Avalonia.Layout/Layoutable.cs +++ b/src/Avalonia.Layout/Layoutable.cs @@ -314,7 +314,7 @@ namespace Avalonia.Layout try { _measuring = true; - desiredSize = MeasureCore(availableSize).Constrain(availableSize); + desiredSize = MeasureCore(availableSize); } finally { diff --git a/src/Avalonia.Themes.Default/ScrollBar.xaml b/src/Avalonia.Themes.Default/ScrollBar.xaml index 2cb8ce2d24..ca308b33c3 100644 --- a/src/Avalonia.Themes.Default/ScrollBar.xaml +++ b/src/Avalonia.Themes.Default/ScrollBar.xaml @@ -30,13 +30,7 @@ Classes="repeattrack" Focusable="False"/> - - - - - - - + - - - - - - - + + diff --git a/src/Avalonia.Visuals/Media/BrushExtensions.cs b/src/Avalonia.Visuals/Media/BrushExtensions.cs index cd351071dd..522953eb04 100644 --- a/src/Avalonia.Visuals/Media/BrushExtensions.cs +++ b/src/Avalonia.Visuals/Media/BrushExtensions.cs @@ -34,16 +34,14 @@ namespace Avalonia.Media { Contract.Requires(pen != null); - var brush = pen?.Brush?.ToImmutable(); - return pen == null || ReferenceEquals(pen?.Brush, brush) ? + var brush = pen.Brush?.ToImmutable(); + return ReferenceEquals(pen.Brush, brush) ? pen : new Pen( brush, thickness: pen.Thickness, - dashStyle: pen.DashStyle, - dashCap: pen.DashCap, - startLineCap: pen.StartLineCap, - endLineCap: pen.EndLineCap, + dashStyle: pen.DashStyle, + lineCap: pen.LineCap, lineJoin: pen.LineJoin, miterLimit: pen.MiterLimit); } diff --git a/src/Avalonia.Visuals/Media/Pen.cs b/src/Avalonia.Visuals/Media/Pen.cs index ddd8091801..ee427c913b 100644 --- a/src/Avalonia.Visuals/Media/Pen.cs +++ b/src/Avalonia.Visuals/Media/Pen.cs @@ -11,63 +11,45 @@ namespace Avalonia.Media /// /// Initializes a new instance of the class. /// - /// The brush used to draw. + /// The stroke color. /// The stroke thickness. /// The dash style. - /// The dash cap. - /// The start line cap. - /// The end line cap. + /// Specifies the type of graphic shape to use on both ends of a line. /// The line join. /// The miter limit. public Pen( - IBrush brush, + uint color, double thickness = 1.0, - DashStyle dashStyle = null, - PenLineCap dashCap = PenLineCap.Flat, - PenLineCap startLineCap = PenLineCap.Flat, - PenLineCap endLineCap = PenLineCap.Flat, - PenLineJoin lineJoin = PenLineJoin.Miter, - double miterLimit = 10.0) + DashStyle dashStyle = null, + PenLineCap lineCap = PenLineCap.Flat, + PenLineJoin lineJoin = PenLineJoin.Miter, + double miterLimit = 10.0) : this(new SolidColorBrush(color), thickness, dashStyle, lineCap, lineJoin, miterLimit) { - Brush = brush; - Thickness = thickness; - DashCap = dashCap; - StartLineCap = startLineCap; - EndLineCap = endLineCap; - LineJoin = lineJoin; - MiterLimit = miterLimit; - DashStyle = dashStyle; } /// /// Initializes a new instance of the class. /// - /// The stroke color. + /// The brush used to draw. /// The stroke thickness. /// The dash style. - /// The dash cap. - /// The start line cap. - /// The end line cap. + /// The line cap. /// The line join. /// The miter limit. public Pen( - uint color, + IBrush brush, double thickness = 1.0, - DashStyle dashStyle = null, - PenLineCap dashCap = PenLineCap.Flat, - PenLineCap startLineCap = PenLineCap.Flat, - PenLineCap endLineCap = PenLineCap.Flat, - PenLineJoin lineJoin = PenLineJoin.Miter, + DashStyle dashStyle = null, + PenLineCap lineCap = PenLineCap.Flat, + PenLineJoin lineJoin = PenLineJoin.Miter, double miterLimit = 10.0) { - Brush = new SolidColorBrush(color); + Brush = brush; Thickness = thickness; - StartLineCap = startLineCap; - EndLineCap = endLineCap; + LineCap = lineCap; LineJoin = lineJoin; MiterLimit = miterLimit; DashStyle = dashStyle; - DashCap = dashCap; } /// @@ -78,18 +60,26 @@ namespace Avalonia.Media /// /// Gets the stroke thickness. /// - public double Thickness { get; } = 1.0; + public double Thickness { get; } + /// + /// Specifies the style of dashed lines drawn with a object. + /// public DashStyle DashStyle { get; } - public PenLineCap DashCap { get; } - - public PenLineCap StartLineCap { get; } = PenLineCap.Flat; - - public PenLineCap EndLineCap { get; } = PenLineCap.Flat; + /// + /// Specifies the type of graphic shape to use on both ends of a line. + /// + public PenLineCap LineCap { get; } - public PenLineJoin LineJoin { get; } = PenLineJoin.Miter; + /// + /// Specifies how to join consecutive line or curve segments in a (subpath) contained in a object. + /// + public PenLineJoin LineJoin { get; } - public double MiterLimit { get; } = 10.0; + /// + /// The limit on the ratio of the miter length to half this pen's Thickness. + /// + public double MiterLimit { get; } } } diff --git a/src/Avalonia.Visuals/Media/PenLineCap.cs b/src/Avalonia.Visuals/Media/PenLineCap.cs index 56c5c040eb..83d8f11613 100644 --- a/src/Avalonia.Visuals/Media/PenLineCap.cs +++ b/src/Avalonia.Visuals/Media/PenLineCap.cs @@ -4,7 +4,6 @@ namespace Avalonia.Media { Flat, Round, - Square, - Triangle + Square } } diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 5272f4b22d..ee4564ff35 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -578,25 +578,17 @@ namespace Avalonia.Skia // Need to modify dashes due to Skia modifying their lengths // https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/paths/dots // TODO: Still something is off, dashes are now present, but don't look the same as D2D ones. - float dashLengthModifier; - float gapLengthModifier; - switch (pen.StartLineCap) + switch (pen.LineCap) { case PenLineCap.Round: paint.StrokeCap = SKStrokeCap.Round; - dashLengthModifier = -paint.StrokeWidth; - gapLengthModifier = paint.StrokeWidth; break; case PenLineCap.Square: paint.StrokeCap = SKStrokeCap.Square; - dashLengthModifier = -paint.StrokeWidth; - gapLengthModifier = paint.StrokeWidth; break; default: paint.StrokeCap = SKStrokeCap.Butt; - dashLengthModifier = 0.0f; - gapLengthModifier = 0.0f; break; } @@ -622,13 +614,12 @@ namespace Avalonia.Skia for (var i = 0; i < srcDashes.Count; ++i) { - var lengthModifier = i % 2 == 0 ? dashLengthModifier : gapLengthModifier; - - // Avalonia dash lengths are relative, but Skia takes absolute sizes - need to scale - dashesArray[i] = (float) srcDashes[i] * paint.StrokeWidth + lengthModifier; + dashesArray[i] = (float) srcDashes[i] * paint.StrokeWidth; } - var pe = SKPathEffect.CreateDash(dashesArray, (float) pen.DashStyle.Offset); + var offset = (float)(pen.DashStyle.Offset * pen.Thickness); + + var pe = SKPathEffect.CreateDash(dashesArray, offset); paint.PathEffect = pe; rv.AddDisposable(pe); diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs index 5209014271..6b0d30f250 100644 --- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs +++ b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs @@ -122,14 +122,16 @@ namespace Avalonia.Direct2D1 /// The Direct2D brush. public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.Pen pen, Factory factory) { + var d2dLineCap = pen.LineCap.ToDirect2D(); + var properties = new StrokeStyleProperties { DashStyle = DashStyle.Solid, MiterLimit = (float)pen.MiterLimit, LineJoin = pen.LineJoin.ToDirect2D(), - StartCap = pen.StartLineCap.ToDirect2D(), - EndCap = pen.EndLineCap.ToDirect2D(), - DashCap = pen.DashCap.ToDirect2D() + StartCap = d2dLineCap, + EndCap = d2dLineCap, + DashCap = d2dLineCap }; float[] dashes = null; if (pen.DashStyle?.Dashes != null && pen.DashStyle.Dashes.Count > 0) diff --git a/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs b/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs index ba2716775a..722ad1c8ee 100644 --- a/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/StackPanelTests.cs @@ -1,7 +1,8 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Controls; +using System.Linq; +using Avalonia.Layout; using Xunit; namespace Avalonia.Controls.UnitTests @@ -147,6 +148,151 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(new Rect(50, 0, 50, 120), target.Children[2].Bounds); } + [Fact] + public void Arranges_Vertical_Children_With_Correct_Bounds() + { + var target = new StackPanel + { + Orientation = Orientation.Vertical, + Children = + { + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Left, + MeasureSize = new Size(50, 10), + }, + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Left, + MeasureSize = new Size(150, 10), + }, + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Center, + MeasureSize = new Size(50, 10), + }, + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Center, + MeasureSize = new Size(150, 10), + }, + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Right, + MeasureSize = new Size(50, 10), + }, + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Right, + MeasureSize = new Size(150, 10), + }, + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Stretch, + MeasureSize = new Size(50, 10), + }, + new TestControl + { + HorizontalAlignment = HorizontalAlignment.Stretch, + MeasureSize = new Size(150, 10), + }, + } + }; + + target.Measure(new Size(100, 150)); + Assert.Equal(new Size(100, 80), target.DesiredSize); + + target.Arrange(new Rect(target.DesiredSize)); + + var bounds = target.Children.Select(x => x.Bounds).ToArray(); + + Assert.Equal( + new[] + { + new Rect(0, 0, 50, 10), + new Rect(0, 10, 150, 10), + new Rect(25, 20, 50, 10), + new Rect(-25, 30, 150, 10), + new Rect(50, 40, 50, 10), + new Rect(-50, 50, 150, 10), + new Rect(0, 60, 100, 10), + new Rect(0, 70, 150, 10), + + }, bounds); + } + + [Fact] + public void Arranges_Horizontal_Children_With_Correct_Bounds() + { + var target = new StackPanel + { + Orientation = Orientation.Horizontal, + Children = + { + new TestControl + { + VerticalAlignment = VerticalAlignment.Top, + MeasureSize = new Size(10, 50), + }, + new TestControl + { + VerticalAlignment = VerticalAlignment.Top, + MeasureSize = new Size(10, 150), + }, + new TestControl + { + VerticalAlignment = VerticalAlignment.Center, + MeasureSize = new Size(10, 50), + }, + new TestControl + { + VerticalAlignment = VerticalAlignment.Center, + MeasureSize = new Size(10, 150), + }, + new TestControl + { + VerticalAlignment = VerticalAlignment.Bottom, + MeasureSize = new Size(10, 50), + }, + new TestControl + { + VerticalAlignment = VerticalAlignment.Bottom, + MeasureSize = new Size(10, 150), + }, + new TestControl + { + VerticalAlignment = VerticalAlignment.Stretch, + MeasureSize = new Size(10, 50), + }, + new TestControl + { + VerticalAlignment = VerticalAlignment.Stretch, + MeasureSize = new Size(10, 150), + }, + } + }; + + target.Measure(new Size(150, 100)); + Assert.Equal(new Size(80, 100), target.DesiredSize); + + target.Arrange(new Rect(target.DesiredSize)); + + var bounds = target.Children.Select(x => x.Bounds).ToArray(); + + Assert.Equal( + new[] + { + new Rect(0, 0, 10, 50), + new Rect(10, 0, 10, 150), + new Rect(20, 25, 10, 50), + new Rect(30, -25, 10, 150), + new Rect(40, 50, 10, 50), + new Rect(50, -50, 10, 150), + new Rect(60, 0, 10, 100), + new Rect(70, 0, 10, 150), + }, bounds); + } + [Theory] [InlineData(Orientation.Horizontal)] [InlineData(Orientation.Vertical)] @@ -185,5 +331,17 @@ namespace Avalonia.Controls.UnitTests Assert.Equal(sizeWithTwoChildren, sizeWithThreeChildren); } + + private class TestControl : Control + { + public Size MeasureConstraint { get; private set; } + public Size MeasureSize { get; set; } + + protected override Size MeasureOverride(Size availableSize) + { + MeasureConstraint = availableSize; + return MeasureSize; + } + } } } diff --git a/tests/Avalonia.RenderTests/Shapes/PathTests.cs b/tests/Avalonia.RenderTests/Shapes/PathTests.cs index 4703daca25..2fa93b49e2 100644 --- a/tests/Avalonia.RenderTests/Shapes/PathTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PathTests.cs @@ -334,11 +334,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes CompareImages(); } -#if AVALONIA_SKIA_SKIP_FAIL - [Fact(Skip = "FIXME")] -#else [Fact] -#endif public async Task Path_With_PenLineCap() { Decorator target = new Decorator @@ -351,10 +347,8 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes StrokeThickness = 10, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, - StrokeDashCap = PenLineCap.Triangle, StrokeDashArray = new AvaloniaList(3, 1), - StrokeStartLineCap = PenLineCap.Round, - StrokeEndLineCap = PenLineCap.Square, + StrokeLineCap = PenLineCap.Round, Data = StreamGeometry.Parse("M 20,20 L 180,180"), } }; diff --git a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs index 3b586d55ea..8afaeb8838 100644 --- a/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs +++ b/tests/Avalonia.RenderTests/Shapes/PolylineTests.cs @@ -61,8 +61,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes Points = polylinePoints, Stretch = Stretch.Uniform, StrokeJoin = PenLineJoin.Round, - StrokeStartLineCap = PenLineCap.Round, - StrokeEndLineCap = PenLineCap.Round, + StrokeLineCap = PenLineCap.Round, StrokeThickness = 10 } }; diff --git a/tests/TestFiles/Direct2D1/Shapes/Path/Path_With_PenLineCap.expected.png b/tests/TestFiles/Direct2D1/Shapes/Path/Path_With_PenLineCap.expected.png index d33068d62c..a61ba9f080 100644 Binary files a/tests/TestFiles/Direct2D1/Shapes/Path/Path_With_PenLineCap.expected.png and b/tests/TestFiles/Direct2D1/Shapes/Path/Path_With_PenLineCap.expected.png differ diff --git a/tests/TestFiles/Skia/Shapes/Path/Path_With_PenLineCap.expected.png b/tests/TestFiles/Skia/Shapes/Path/Path_With_PenLineCap.expected.png index d33068d62c..a61ba9f080 100644 Binary files a/tests/TestFiles/Skia/Shapes/Path/Path_With_PenLineCap.expected.png and b/tests/TestFiles/Skia/Shapes/Path/Path_With_PenLineCap.expected.png differ