Browse Source

Merge branch 'master' into DisableButtonOnNullCommandBinding

pull/894/head
Jeremy Koritzinsky 9 years ago
committed by GitHub
parent
commit
3dd86d47a2
  1. 1
      samples/RenderTest/MainWindow.xaml
  2. 132
      samples/RenderTest/Pages/DrawingPage.xaml
  3. 18
      samples/RenderTest/Pages/DrawingPage.xaml.cs
  4. 8
      samples/RenderTest/RenderTest.csproj
  5. 59
      src/Avalonia.Controls/DrawingPresenter.cs
  6. 28
      src/Avalonia.Controls/Shapes/Shape.cs
  7. 3
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  8. 21
      src/Avalonia.DotNetFrameworkRuntime/Properties/AssemblyInfo.cs
  9. 3
      src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
  10. 27
      src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs
  11. 1
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  12. 24
      src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs
  13. 29
      src/Avalonia.Visuals/Matrix.cs
  14. 9
      src/Avalonia.Visuals/Media/Drawing.cs
  15. 58
      src/Avalonia.Visuals/Media/DrawingGroup.cs
  16. 51
      src/Avalonia.Visuals/Media/EllipseGeometry.cs
  17. 43
      src/Avalonia.Visuals/Media/GeometryDrawing.cs
  18. 80
      src/Avalonia.Visuals/Media/LineGeometry.cs
  19. 1
      src/Avalonia.Visuals/Media/PathMarkupParser.cs
  20. 115
      src/Avalonia.Visuals/Media/PolylineGeometry.cs
  21. 51
      src/Avalonia.Visuals/Media/RectangleGeometry.cs
  22. 2
      src/Avalonia.Visuals/Point.cs
  23. 9
      src/Avalonia.Visuals/Points.cs
  24. 26
      src/Avalonia.Visuals/Rect.cs
  25. 2
      src/Avalonia.Visuals/RelativeRect.cs
  26. 42
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  27. 6
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  28. 3
      src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj
  29. 20
      src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs
  30. 3
      src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj
  31. 13
      src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs
  32. 1
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj
  33. 25
      src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs
  34. 2
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  35. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs
  36. 23
      src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs
  37. 2
      src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs
  38. 5
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  39. 16
      tests/Avalonia.Visuals.UnitTests/Media/MatrixTests.cs
  40. 1
      tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs
  41. 16
      tests/Avalonia.Visuals.UnitTests/Media/RectTests.cs
  42. 27
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs

1
samples/RenderTest/MainWindow.xaml

@ -27,6 +27,7 @@
</TabControl.Transition>
<TabItem Header="Animations"><pages:AnimationsPage/></TabItem>
<TabItem Header="Clipping"><pages:ClippingPage/></TabItem>
<TabItem Header="Drawing"><pages:DrawingPage/></TabItem>
</TabControl>
</DockPanel>
</Window>

132
samples/RenderTest/Pages/DrawingPage.xaml

@ -0,0 +1,132 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Styles>
<Style>
<Style.Resources>
<DrawingGroup x:Key="Bulb">
<DrawingGroup.Transform>
<MatrixTransform Matrix="1,0,0,1,0,-1028.4" />
</DrawingGroup.Transform>
<DrawingGroup>
<DrawingGroup.Transform>
<MatrixTransform Matrix="1,0,0,1.25,-10,1031.4" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FF7F8C8D"
Geometry="F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z" />
</DrawingGroup>
<GeometryDrawing Brush="#FFF39C12"
Geometry="F1 M12,1030.4 C8.134,1030.4 5,1033.6 5,1037.6 5,1040.7 8.125,1043.5 9,1045.4 9.875,1047.2 9,1050.4 9,1050.4 L12,1049.9 15,1050.4 C15,1050.4 14.125,1047.2 15,1045.4 15.875,1043.5 19,1040.7 19,1037.6 19,1033.6 15.866,1030.4 12,1030.4 z" />
<GeometryDrawing Brush="#FFF1C40F"
Geometry="F1 M12,1030.4 C15.866,1030.4 19,1033.6 19,1037.6 19,1040.7 15.875,1043.5 15,1045.4 14.125,1047.2 15,1050.4 15,1050.4 L12,1049.9 12,1030.4 z" />
<GeometryDrawing Brush="#FFE67E22"
Geometry="F1 M9,1036.4 L8,1037.4 12,1049.4 16,1037.4 15,1036.4 14,1037.4 13,1036.4 12,1037.4 11,1036.4 10,1037.4 9,1036.4 z M9,1037.4 L10,1038.4 10.5,1037.9 11,1037.4 11.5,1037.9 12,1038.4 12.5,1037.9 13,1037.4 13.5,1037.9 14,1038.4 15,1037.4 15.438,1037.8 12,1048.1 8.5625,1037.8 9,1037.4 z" />
<DrawingGroup>
<DrawingGroup.Transform>
<MatrixTransform Matrix="1,0,0,1,9,1045.4" />
</DrawingGroup.Transform>
<GeometryDrawing Brush="#FFBDC3C7">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,6,5" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
<GeometryDrawing Brush="#FF95A5A6"
Geometry="F1 M9,1045.4 L9,1050.4 12,1050.4 12,1049.4 15,1049.4 15,1048.4 12,1048.4 12,1047.4 15,1047.4 15,1046.4 12,1046.4 12,1045.4 9,1045.4 z" />
<GeometryDrawing Brush="#FF7F8C8D"
Geometry="F1 M9,1046.4 L9,1047.4 12,1047.4 12,1046.4 9,1046.4 z M9,1048.4 L9,1049.4 12,1049.4 12,1048.4 9,1048.4 z" />
</DrawingGroup>
</Style.Resources>
</Style>
</UserControl.Styles>
<Grid RowDefinitions="Auto,Auto,Auto"
ColumnDefinitions="Auto,Auto,Auto,Auto">
<TextBlock Text="None"
Margin="3" />
<Border Grid.Column="0"
Grid.Row="1"
VerticalAlignment="Top"
HorizontalAlignment="Left"
BorderThickness="1"
BorderBrush="Gray"
Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}" />
</Border>
<TextBlock Text="Fill"
Margin="3"
Grid.Column="1" />
<Border Grid.Column="1"
Grid.Row="1"
VerticalAlignment="Top"
HorizontalAlignment="Left"
BorderThickness="1"
BorderBrush="Gray"
Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}"
Width="100"
Height="50"
Stretch="Fill" />
</Border>
<TextBlock Text="Uniform"
Margin="3"
Grid.Column="2" />
<Border Grid.Column="2"
Grid.Row="1"
VerticalAlignment="Top"
HorizontalAlignment="Left"
BorderThickness="1"
BorderBrush="Gray"
Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}"
Width="100"
Height="50"
Stretch="Uniform" />
</Border>
<TextBlock Text="UniformToFill"
Margin="3"
Grid.Column="3" />
<Border Grid.Column="3"
Grid.Row="1"
VerticalAlignment="Top"
HorizontalAlignment="Left"
BorderThickness="1"
BorderBrush="Gray"
Margin="5">
<DrawingPresenter Drawing="{StyleResource Bulb}"
Width="100"
Height="50"
Stretch="UniformToFill" />
</Border>
<!-- For comparison -->
<Ellipse Grid.Row="2"
Grid.Column="0"
Width="100"
Height="50"
Stretch="None"
Fill="Blue"
Margin="5"/>
<Ellipse Grid.Row="2"
Grid.Column="1"
Width="100"
Height="50"
Stretch="Fill"
Fill="Blue"
Margin="5" />
<Ellipse Grid.Row="2"
Grid.Column="2"
Width="100"
Height="50"
Stretch="Uniform"
Fill="Blue"
Margin="5" />
<Ellipse Grid.Row="2"
Grid.Column="3"
Width="100"
Height="50"
Stretch="UniformToFill"
Fill="Blue"
Margin="5" />
</Grid>
</UserControl>

18
samples/RenderTest/Pages/DrawingPage.xaml.cs

@ -0,0 +1,18 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace RenderTest.Pages
{
public class DrawingPage : UserControl
{
public DrawingPage()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

8
samples/RenderTest/RenderTest.csproj

@ -51,6 +51,9 @@
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\DrawingPage.xaml.cs">
<DependentUpon>DrawingPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\ClippingPage.xaml.cs">
<DependentUpon>ClippingPage.xaml</DependentUpon>
</Compile>
@ -178,6 +181,11 @@
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Pages\DrawingPage.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\build\Serilog.props" />
<Import Project="..\..\build\Serilog.Sinks.Trace.props" />

59
src/Avalonia.Controls/DrawingPresenter.cs

@ -0,0 +1,59 @@
using Avalonia.Controls.Shapes;
using Avalonia.Media;
using Avalonia.Metadata;
namespace Avalonia.Controls
{
public class DrawingPresenter : Control
{
static DrawingPresenter()
{
AffectsMeasure(DrawingProperty);
AffectsRender(DrawingProperty);
}
public static readonly StyledProperty<Drawing> DrawingProperty =
AvaloniaProperty.Register<DrawingPresenter, Drawing>(nameof(Drawing));
public static readonly StyledProperty<Stretch> StretchProperty =
AvaloniaProperty.Register<DrawingPresenter, Stretch>(nameof(Stretch), Stretch.Uniform);
[Content]
public Drawing Drawing
{
get => GetValue(DrawingProperty);
set => SetValue(DrawingProperty, value);
}
public Stretch Stretch
{
get => GetValue(StretchProperty);
set => SetValue(StretchProperty, value);
}
private Matrix _transform = Matrix.Identity;
protected override Size MeasureOverride(Size availableSize)
{
if (Drawing == null) return new Size();
var (size, transform) = Shape.CalculateSizeAndTransform(availableSize, Drawing.GetBounds(), Stretch);
_transform = transform;
return size;
}
public override void Render(DrawingContext context)
{
if (Drawing != null)
{
using (context.PushPreTransform(_transform))
using (context.PushClip(Bounds))
{
Drawing.Draw(context);
}
}
}
}
}

28
src/Avalonia.Controls/Shapes/Shape.cs

@ -155,11 +155,21 @@ namespace Avalonia.Controls.Shapes
{
// This should probably use GetRenderBounds(strokeThickness) but then the calculations
// will multiply the stroke thickness as well, which isn't correct.
Rect shapeBounds = DefiningGeometry.Bounds;
var (size, transform) = CalculateSizeAndTransform(availableSize, DefiningGeometry.Bounds, Stretch);
if (_transform != transform)
{
_transform = transform;
_renderedGeometry = null;
}
return size;
}
internal static (Size, Matrix) CalculateSizeAndTransform(Size availableSize, Rect shapeBounds, Stretch Stretch)
{
Size shapeSize = new Size(shapeBounds.Right, shapeBounds.Bottom);
Matrix translate = Matrix.Identity;
double width = Width;
double height = Height;
double desiredX = availableSize.Width;
double desiredY = availableSize.Height;
double sx = 0.0;
@ -226,15 +236,9 @@ namespace Avalonia.Controls.Shapes
break;
}
var t = translate * Matrix.CreateScale(sx, sy);
if (_transform != t)
{
_transform = t;
_renderedGeometry = null;
}
return new Size(shapeSize.Width * sx, shapeSize.Height * sy);
var transform = translate * Matrix.CreateScale(sx, sy);
var size = new Size(shapeSize.Width * sx, shapeSize.Height * sy);
return (size, transform);
}
private static void AffectsGeometryInvalidate(AvaloniaPropertyChangedEventArgs e)

3
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@ -44,6 +44,9 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AppBuilder.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RuntimeInfo.cs" />

21
src/Avalonia.DotNetFrameworkRuntime/Properties/AssemblyInfo.cs

@ -1,18 +1,10 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Avalonia.DotNetFrameworkRuntime")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Avalonia.DotNetFrameworkRuntime")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
@ -21,16 +13,3 @@ using System.Runtime.InteropServices;
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("4a1abb09-9047-4bd5-a4ad-a055e52c5ee0")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

3
src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj

@ -23,6 +23,9 @@
<DocumentationFile>bin\Release\Avalonia.Logging.Serilog.XML</DocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
</ItemGroup>

27
src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs

@ -1,30 +1,3 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Avalonia.Serilog")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Avalonia.Serilog")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

1
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -25,6 +25,7 @@
<None Remove="Shims.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>

24
src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs

@ -1,33 +1,9 @@
// 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 System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Avalonia.ReactiveUI")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Avalonia.ReactiveUI")]
[assembly: AssemblyCopyright("Copyright \u00A9 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

29
src/Avalonia.Visuals/Matrix.cs

@ -3,6 +3,7 @@
using System;
using System.Globalization;
using System.Linq;
namespace Avalonia
{
@ -295,5 +296,33 @@ namespace Avalonia
((_m21 * _m32) - (_m22 * _m31)) / d,
((_m12 * _m31) - (_m11 * _m32)) / d);
}
/// <summary>
/// Parses a <see cref="Matrix"/> string.
/// </summary>
/// <param name="s">The string.</param>
/// <param name="culture">The current culture.</param>
/// <returns>The <see cref="Matrix"/>.</returns>
public static Matrix Parse(string s, CultureInfo culture)
{
var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.ToArray();
if (parts.Length == 6)
{
return new Matrix(
double.Parse(parts[0], culture),
double.Parse(parts[1], culture),
double.Parse(parts[2], culture),
double.Parse(parts[3], culture),
double.Parse(parts[4], culture),
double.Parse(parts[5], culture));
}
else
{
throw new FormatException("Invalid Matrix.");
}
}
}
}

9
src/Avalonia.Visuals/Media/Drawing.cs

@ -0,0 +1,9 @@
namespace Avalonia.Media
{
public abstract class Drawing : AvaloniaObject
{
public abstract void Draw(DrawingContext context);
public abstract Rect GetBounds();
}
}

58
src/Avalonia.Visuals/Media/DrawingGroup.cs

@ -0,0 +1,58 @@
using Avalonia.Collections;
using Avalonia.Metadata;
namespace Avalonia.Media
{
public class DrawingGroup : Drawing
{
public static readonly StyledProperty<double> OpacityProperty =
AvaloniaProperty.Register<DrawingGroup, double>(nameof(Opacity), 1);
public static readonly StyledProperty<Transform> TransformProperty =
AvaloniaProperty.Register<DrawingGroup, Transform>(nameof(Transform));
public double Opacity
{
get => GetValue(OpacityProperty);
set => SetValue(OpacityProperty, value);
}
public Transform Transform
{
get => GetValue(TransformProperty);
set => SetValue(TransformProperty, value);
}
[Content]
public AvaloniaList<Drawing> Children { get; } = new AvaloniaList<Drawing>();
public override void Draw(DrawingContext context)
{
using (context.PushPreTransform(Transform?.Value ?? Matrix.Identity))
using (context.PushOpacity(Opacity))
{
foreach (var drawing in Children)
{
drawing.Draw(context);
}
}
}
public override Rect GetBounds()
{
var rect = new Rect();
foreach (var drawing in Children)
{
rect = rect.Union(drawing.GetBounds());
}
if (Transform != null)
{
rect = rect.TransformToAABB(Transform.Value);
}
return rect;
}
}
}

51
src/Avalonia.Visuals/Media/EllipseGeometry.cs

@ -11,16 +11,51 @@ namespace Avalonia.Media
/// </summary>
public class EllipseGeometry : Geometry
{
/// <summary>
/// Defines the <see cref="Rect"/> property.
/// </summary>
public static readonly StyledProperty<Rect> RectProperty =
AvaloniaProperty.Register<EllipseGeometry, Rect>(nameof(Rect));
public Rect Rect
{
get => GetValue(RectProperty);
set => SetValue(RectProperty, value);
}
static EllipseGeometry()
{
RectProperty.Changed.AddClassHandler<EllipseGeometry>(x => x.RectChanged);
}
/// <summary>
/// Initializes a new instance of the <see cref="EllipseGeometry"/> class.
/// </summary>
/// <param name="rect">The rectangle that the ellipse should fill.</param>
public EllipseGeometry(Rect rect)
public EllipseGeometry()
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
IStreamGeometryImpl impl = factory.CreateStreamGeometry();
PlatformImpl = factory.CreateStreamGeometry();
}
/// <summary>
/// Initializes a new instance of the <see cref="EllipseGeometry"/> class.
/// </summary>
/// <param name="rect">The rectangle that the ellipse should fill.</param>
public EllipseGeometry(Rect rect) : this()
{
Rect = rect;
}
/// <inheritdoc/>
public override Geometry Clone()
{
return new EllipseGeometry(Rect);
}
using (IStreamGeometryContextImpl ctx = impl.Open())
private void RectChanged(AvaloniaPropertyChangedEventArgs e)
{
var rect = (Rect)e.NewValue;
using (var ctx = ((IStreamGeometryImpl)PlatformImpl).Open())
{
double controlPointRatio = (Math.Sqrt(2) - 1) * 4 / 3;
var center = rect.Center;
@ -45,14 +80,6 @@ namespace Avalonia.Media
ctx.CubicBezierTo(new Point(x0, y1), new Point(x1, y0), new Point(x2, y0));
ctx.EndFigure(true);
}
PlatformImpl = impl;
}
/// <inheritdoc/>
public override Geometry Clone()
{
return new EllipseGeometry(Bounds);
}
}
}

43
src/Avalonia.Visuals/Media/GeometryDrawing.cs

@ -0,0 +1,43 @@
namespace Avalonia.Media
{
public class GeometryDrawing : Drawing
{
public static readonly StyledProperty<Geometry> GeometryProperty =
AvaloniaProperty.Register<GeometryDrawing, Geometry>(nameof(Geometry));
public Geometry Geometry
{
get => GetValue(GeometryProperty);
set => SetValue(GeometryProperty, value);
}
public static readonly StyledProperty<IBrush> BrushProperty =
AvaloniaProperty.Register<GeometryDrawing, IBrush>(nameof(Brush), Brushes.Transparent);
public IBrush Brush
{
get => GetValue(BrushProperty);
set => SetValue(BrushProperty, value);
}
public static readonly StyledProperty<Pen> PenProperty =
AvaloniaProperty.Register<GeometryDrawing, Pen>(nameof(Pen));
public Pen Pen
{
get => GetValue(PenProperty);
set => SetValue(PenProperty, value);
}
public override void Draw(DrawingContext context)
{
context.DrawGeometry(Brush, Pen, Geometry);
}
public override Rect GetBounds()
{
// adding the Pen's stroke thickness here could yield wrong results due to transforms
return Geometry?.GetRenderBounds(0) ?? new Rect();
}
}
}

80
src/Avalonia.Visuals/Media/LineGeometry.cs

@ -10,35 +10,89 @@ namespace Avalonia.Media
/// </summary>
public class LineGeometry : Geometry
{
private Point _startPoint;
private Point _endPoint;
/// <summary>
/// Defines the <see cref="StartPoint"/> property.
/// </summary>
public static readonly StyledProperty<Point> StartPointProperty =
AvaloniaProperty.Register<LineGeometry, Point>(nameof(StartPoint));
public Point StartPoint
{
get => GetValue(StartPointProperty);
set => SetValue(StartPointProperty, value);
}
/// <summary>
/// Defines the <see cref="EndPoint"/> property.
/// </summary>
public static readonly StyledProperty<Point> EndPointProperty =
AvaloniaProperty.Register<LineGeometry, Point>(nameof(EndPoint));
private bool _isDirty;
public Point EndPoint
{
get => GetValue(EndPointProperty);
set => SetValue(EndPointProperty, value);
}
static LineGeometry()
{
StartPointProperty.Changed.AddClassHandler<LineGeometry>(x => x.PointsChanged);
EndPointProperty.Changed.AddClassHandler<LineGeometry>(x => x.PointsChanged);
}
/// <summary>
/// Initializes a new instance of the <see cref="LineGeometry"/> class.
/// </summary>
public LineGeometry()
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
PlatformImpl = factory.CreateStreamGeometry();
}
/// <summary>
/// Initializes a new instance of the <see cref="LineGeometry"/> class.
/// </summary>
/// <param name="startPoint">The start point.</param>
/// <param name="endPoint">The end point.</param>
public LineGeometry(Point startPoint, Point endPoint)
public LineGeometry(Point startPoint, Point endPoint) : this()
{
_startPoint = startPoint;
_endPoint = endPoint;
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
IStreamGeometryImpl impl = factory.CreateStreamGeometry();
StartPoint = startPoint;
EndPoint = endPoint;
}
using (IStreamGeometryContextImpl context = impl.Open())
public override IGeometryImpl PlatformImpl
{
get
{
context.BeginFigure(_startPoint, false);
context.LineTo(_endPoint);
context.EndFigure(false);
PrepareIfNeeded();
return base.PlatformImpl;
}
protected set => base.PlatformImpl = value;
}
PlatformImpl = impl;
public void PrepareIfNeeded()
{
if (_isDirty)
{
_isDirty = false;
using (var context = ((IStreamGeometryImpl)PlatformImpl).Open())
{
context.BeginFigure(StartPoint, false);
context.LineTo(EndPoint);
context.EndFigure(false);
}
}
}
/// <inheritdoc/>
public override Geometry Clone()
{
return new LineGeometry(_startPoint, _endPoint);
PrepareIfNeeded();
return new LineGeometry(StartPoint, EndPoint);
}
private void PointsChanged(AvaloniaPropertyChangedEventArgs e) => _isDirty = true;
}
}

1
src/Avalonia.Visuals/Media/PathMarkupParser.cs

@ -141,6 +141,7 @@ namespace Avalonia.Media
bool isLargeArc = ReadBool(reader);
ReadSeparator(reader);
SweepDirection sweepDirection = ReadBool(reader) ? SweepDirection.Clockwise : SweepDirection.CounterClockwise;
ReadSeparator(reader);
point = ReadPoint(reader, point, relative);
_context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection);

115
src/Avalonia.Visuals/Media/PolylineGeometry.cs

@ -3,10 +3,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
using Avalonia.Metadata;
using Avalonia.Collections;
namespace Avalonia.Media
{
@ -15,36 +14,118 @@ namespace Avalonia.Media
/// </summary>
public class PolylineGeometry : Geometry
{
private IList<Point> _points;
private bool _isFilled;
/// <summary>
/// Defines the <see cref="Points"/> property.
/// </summary>
public static readonly DirectProperty<PolylineGeometry, Points> PointsProperty =
AvaloniaProperty.RegisterDirect<PolylineGeometry, Points>(nameof(Points), g => g.Points, (g, f) => g.Points = f);
public PolylineGeometry(IList<Point> points, bool isFilled)
/// <summary>
/// Defines the <see cref="IsFilled"/> property.
/// </summary>
public static readonly AvaloniaProperty<bool> IsFilledProperty =
AvaloniaProperty.Register<PolylineGeometry, bool>(nameof(IsFilled));
private Points _points;
private bool _isDirty;
private IDisposable _pointsObserver;
static PolylineGeometry()
{
PointsProperty.Changed.AddClassHandler<PolylineGeometry>((s, e) =>
s.OnPointsChanged(e.OldValue as Points, e.NewValue as Points));
IsFilledProperty.Changed.AddClassHandler<PolylineGeometry>((s, _) => s.NotifyChanged());
}
/// <summary>
/// Initializes a new instance of the <see cref="PolylineGeometry"/> class.
/// </summary>
public PolylineGeometry()
{
_points = points;
_isFilled = isFilled;
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
IStreamGeometryImpl impl = factory.CreateStreamGeometry();
PlatformImpl = factory.CreateStreamGeometry();
Points = new Points();
}
using (IStreamGeometryContextImpl context = impl.Open())
/// <summary>
/// Initializes a new instance of the <see cref="PolylineGeometry"/> class.
/// </summary>
public PolylineGeometry(IEnumerable<Point> points, bool isFilled) : this()
{
Points.AddRange(points);
IsFilled = isFilled;
}
public void PrepareIfNeeded()
{
if (_isDirty)
{
if (points.Count > 0)
_isDirty = false;
using (var context = ((IStreamGeometryImpl)PlatformImpl).Open())
{
context.BeginFigure(points[0], isFilled);
for (int i = 1; i < points.Count; i++)
var points = Points;
var isFilled = IsFilled;
if (points.Count > 0)
{
context.LineTo(points[i]);
context.BeginFigure(points[0], isFilled);
for (int i = 1; i < points.Count; i++)
{
context.LineTo(points[i]);
}
context.EndFigure(isFilled);
}
context.EndFigure(isFilled);
}
}
}
PlatformImpl = impl;
/// <summary>
/// Gets or sets the figures.
/// </summary>
/// <value>
/// The points.
/// </value>
[Content]
public Points Points
{
get => _points;
set => SetAndRaise(PointsProperty, ref _points, value);
}
public bool IsFilled
{
get => GetValue(IsFilledProperty);
set => SetValue(IsFilledProperty, value);
}
public override IGeometryImpl PlatformImpl
{
get
{
PrepareIfNeeded();
return base.PlatformImpl;
}
protected set => base.PlatformImpl = value;
}
/// <inheritdoc/>
public override Geometry Clone()
{
return new PolylineGeometry(new List<Point>(_points), _isFilled);
PrepareIfNeeded();
return new PolylineGeometry(Points, IsFilled);
}
private void OnPointsChanged(Points oldValue, Points newValue)
{
_pointsObserver?.Dispose();
_pointsObserver = newValue?.ForEachItem(f => NotifyChanged(), f => NotifyChanged(), () => NotifyChanged());
}
internal void NotifyChanged()
{
_isDirty = true;
}
}
}

51
src/Avalonia.Visuals/Media/RectangleGeometry.cs

@ -10,16 +10,51 @@ namespace Avalonia.Media
/// </summary>
public class RectangleGeometry : Geometry
{
/// <summary>
/// Defines the <see cref="Rect"/> property.
/// </summary>
public static readonly StyledProperty<Rect> RectProperty =
AvaloniaProperty.Register<RectangleGeometry, Rect>(nameof(Rect));
public Rect Rect
{
get => GetValue(RectProperty);
set => SetValue(RectProperty, value);
}
static RectangleGeometry()
{
RectProperty.Changed.AddClassHandler<RectangleGeometry>(x => x.RectChanged);
}
/// <summary>
/// Initializes a new instance of the <see cref="RectangleGeometry"/> class.
/// </summary>
/// <param name="rect">The rectangle bounds.</param>
public RectangleGeometry(Rect rect)
public RectangleGeometry()
{
IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>();
IStreamGeometryImpl impl = factory.CreateStreamGeometry();
PlatformImpl = factory.CreateStreamGeometry();
}
/// <summary>
/// Initializes a new instance of the <see cref="RectangleGeometry"/> class.
/// </summary>
/// <param name="rect">The rectangle bounds.</param>
public RectangleGeometry(Rect rect) : this()
{
Rect = rect;
}
/// <inheritdoc/>
public override Geometry Clone()
{
return new RectangleGeometry(Rect);
}
using (IStreamGeometryContextImpl context = impl.Open())
private void RectChanged(AvaloniaPropertyChangedEventArgs e)
{
var rect = (Rect)e.NewValue;
using (var context = ((IStreamGeometryImpl)PlatformImpl).Open())
{
context.BeginFigure(rect.TopLeft, true);
context.LineTo(rect.TopRight);
@ -27,14 +62,6 @@ namespace Avalonia.Media
context.LineTo(rect.BottomLeft);
context.EndFigure(true);
}
PlatformImpl = impl;
}
/// <inheritdoc/>
public override Geometry Clone()
{
return new RectangleGeometry(Bounds);
}
}
}

2
src/Avalonia.Visuals/Point.cs

@ -183,7 +183,7 @@ namespace Avalonia
}
else
{
throw new FormatException("Invalid Thickness.");
throw new FormatException("Invalid Point.");
}
}

9
src/Avalonia.Visuals/Points.cs

@ -0,0 +1,9 @@
// 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.Collections;
namespace Avalonia
{
public sealed class Points : AvaloniaList<Point> { }
}

26
src/Avalonia.Visuals/Rect.cs

@ -481,5 +481,31 @@ namespace Avalonia
_width,
_height);
}
/// <summary>
/// Parses a <see cref="Rect"/> string.
/// </summary>
/// <param name="s">The string.</param>
/// <param name="culture">The current culture.</param>
/// <returns>The parsed <see cref="Rect"/>.</returns>
public static Rect Parse(string s, CultureInfo culture)
{
var parts = s.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.ToList();
if (parts.Count == 4)
{
return new Rect(
double.Parse(parts[0], culture),
double.Parse(parts[1], culture),
double.Parse(parts[2], culture),
double.Parse(parts[3], culture));
}
else
{
throw new FormatException("Invalid Rect.");
}
}
}
}

2
src/Avalonia.Visuals/RelativeRect.cs

@ -203,7 +203,7 @@ namespace Avalonia
}
else
{
throw new FormatException("Invalid Rect.");
throw new FormatException("Invalid RelativeRect.");
}
}
}

42
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.IO;
using Avalonia.Media.Immutable;
using System.Threading;
using System.Linq;
namespace Avalonia.Rendering
{
@ -58,7 +59,6 @@ namespace Avalonia.Rendering
_dispatcher = dispatcher ?? Dispatcher.UIThread;
_root = root;
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
_scene = new Scene(root);
_layerFactory = layerFactory ?? new DefaultRenderLayerFactory();
_layers = new RenderLayers(_layerFactory);
_renderLoop = renderLoop;
@ -86,7 +86,6 @@ namespace Avalonia.Rendering
_root = root;
_renderTarget = renderTarget;
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
_scene = new Scene(root);
_layerFactory = layerFactory ?? new DefaultRenderLayerFactory();
_layers = new RenderLayers(_layerFactory);
}
@ -122,7 +121,7 @@ namespace Avalonia.Rendering
UpdateScene();
}
return _scene.HitTest(p, filter);
return _scene?.HitTest(p, filter) ?? Enumerable.Empty<IVisual>();
}
/// <inheritdoc/>
@ -186,7 +185,7 @@ namespace Avalonia.Rendering
_dirtyRectsDisplay.Tick();
}
if (scene.Size != Size.Empty)
if (scene != null && scene.Size != Size.Empty)
{
if (scene.Generation != _lastSceneId)
{
@ -366,25 +365,32 @@ namespace Avalonia.Rendering
try
{
var scene = _scene.Clone();
if (_dirty == null)
{
_dirty = new DirtyVisuals();
_sceneBuilder.UpdateAll(scene);
}
else if (_dirty.Count > 0)
if (_root.IsVisible)
{
foreach (var visual in _dirty)
var scene = _scene?.Clone() ?? new Scene(_root);
if (_dirty == null)
{
_sceneBuilder.Update(scene, visual);
_dirty = new DirtyVisuals();
_sceneBuilder.UpdateAll(scene);
}
else if (_dirty.Count > 0)
{
foreach (var visual in _dirty)
{
_sceneBuilder.Update(scene, visual);
}
}
}
Interlocked.Exchange(ref _scene, scene);
Interlocked.Exchange(ref _scene, scene);
_dirty.Clear();
(_root as IRenderRoot)?.Invalidate(new Rect(scene.Size));
_dirty.Clear();
(_root as IRenderRoot)?.Invalidate(new Rect(scene.Size));
}
else
{
Interlocked.Exchange(ref _scene, null);
}
}
finally
{

6
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@ -36,8 +36,14 @@ namespace Avalonia.Rendering.SceneGraph
{
Contract.Requires<ArgumentNullException>(scene != null);
Contract.Requires<ArgumentNullException>(visual != null);
Dispatcher.UIThread.VerifyAccess();
if (!scene.Root.Visual.IsVisible)
{
throw new AvaloniaInternalException("Cannot update the scene for an invisible root visual.");
}
var node = (VisualNode)scene.FindNode(visual);
if (visual == scene.Root.Visual)

3
src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj

@ -47,6 +47,9 @@
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="CairoPlatform.cs" />
<Compile Include="Media\DrawingContext.cs" />
<Compile Include="Media\FormattedTextImpl.cs" />

20
src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs

@ -11,13 +11,6 @@ using System.Runtime.InteropServices;
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Avalonia.Cairo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Avalonia.Cairo")]
[assembly: AssemblyCopyright("Copyright \u00A9 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
@ -27,19 +20,6 @@ using System.Runtime.InteropServices;
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f999ba8b-64e7-40cc-98a4-003f1852d2a3")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 3, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
[assembly: ExportRenderingSubsystem(OperatingSystemType.Linux, 2, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
[assembly: ExportRenderingSubsystem(OperatingSystemType.OSX, 3, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]

3
src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj

@ -39,6 +39,9 @@
<Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="ClipboardImpl.cs" />
<Compile Include="EmbeddableImpl.cs" />
<Compile Include="Embedding\GtkAvaloniaControlHost.cs" />

13
src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs

@ -4,23 +4,10 @@
using Avalonia.Gtk;
using Avalonia.Platform;
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("Avalonia.Gtk")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("steven")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
[assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 3, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
[assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 2, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]

1
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@ -24,6 +24,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
<Compile Include="..\Avalonia.Gtk\KeyTransform.cs">
<Link>KeyTransform.cs</Link>
</Compile>

25
src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs

@ -1,7 +1,4 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Reflection;
using Avalonia.Gtk3;
using Avalonia.Platform;
@ -9,27 +6,7 @@ using Avalonia.Platform;
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Avalonia.Gtk3")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Avalonia.Gtk3")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
[assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 1, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
[assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]

2
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -31,6 +31,8 @@
</Compile>
<Compile Include="AvaloniaXamlLoaderPortableXaml.cs" />
<Compile Include="AvaloniaXamlLoader.cs" />
<Compile Include="Converters\MatrixTypeConverter.cs" />
<Compile Include="Converters\RectTypeConverter.cs" />
<Compile Include="Converters\SetterValueTypeConverter.cs" />
<Compile Include="MarkupExtensions\StyleIncludeExtension.cs" />
<Compile Include="PortableXaml\AvaloniaXamlContext.cs" />

23
src/Markup/Avalonia.Markup.Xaml/Converters/MatrixTypeConverter.cs

@ -0,0 +1,23 @@
// 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 System;
using System.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class MatrixTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Matrix.Parse((string)value, culture);
}
}
}

23
src/Markup/Avalonia.Markup.Xaml/Converters/RectTypeConverter.cs

@ -0,0 +1,23 @@
// 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 System;
using System.Globalization;
namespace Avalonia.Markup.Xaml.Converters
{
using System.ComponentModel;
public class RectTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return Rect.Parse((string)value, culture);
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaDefaultTypeConverters.cs

@ -32,12 +32,14 @@ namespace Avalonia.Markup.Xaml.PortableXaml
{ typeof(AvaloniaList<double>), typeof(AvaloniaListTypeConverter<double>) },
{ typeof(IMemberSelector), typeof(MemberSelectorTypeConverter) },
{ typeof(Point), typeof(PointTypeConverter) },
{ typeof(Matrix), typeof(MatrixTypeConverter) },
{ typeof(IList<Point>), typeof(PointsListTypeConverter) },
{ typeof(AvaloniaProperty), typeof(AvaloniaPropertyTypeConverter) },
{ typeof(RelativePoint), typeof(RelativePointTypeConverter) },
{ typeof(RelativeRect), typeof(RelativeRectTypeConverter) },
{ typeof(RowDefinitions), typeof(RowDefinitionsTypeConverter) },
{ typeof(Size), typeof(SizeTypeConverter) },
{ typeof(Rect), typeof(RectTypeConverter) },
{ typeof(Selector), typeof(SelectorTypeConverter)},
{ typeof(SolidColorBrush), typeof(BrushTypeConverter) },
{ typeof(Thickness), typeof(ThicknessTypeConverter) },

5
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -119,7 +119,10 @@ namespace Avalonia.Direct2D1.Media
using (var d2dOpacityMask = CreateBrush(opacityMask, opacityMaskRect.Size))
using (var geometry = new SharpDX.Direct2D1.RectangleGeometry(_renderTarget.Factory, destRect.ToDirect2D()))
{
d2dOpacityMask.PlatformBrush.Transform = Matrix.CreateTranslation(opacityMaskRect.Position).ToDirect2D();
if (d2dOpacityMask.PlatformBrush != null)
{
d2dOpacityMask.PlatformBrush.Transform = Matrix.CreateTranslation(opacityMaskRect.Position).ToDirect2D();
}
_renderTarget.FillGeometry(
geometry,

16
tests/Avalonia.Visuals.UnitTests/Media/MatrixTests.cs

@ -0,0 +1,16 @@
using System.Globalization;
using Xunit;
namespace Avalonia.Visuals.UnitTests.Media
{
public class MatrixTests
{
[Fact]
public void Parse_Parses()
{
var matrix = Matrix.Parse("1,2,3,-4,5 6", CultureInfo.CurrentCulture);
var expected = new Matrix(1, 2, 3, -4, 5, 6);
Assert.Equal(expected, matrix);
}
}
}

1
tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs

@ -56,6 +56,7 @@ namespace Avalonia.Visuals.UnitTests.Media
}
[Theory]
[InlineData("F1 M24,14 A2,2,0,1,1,20,14 A2,2,0,1,1,24,14 z")] // issue #1107
[InlineData("M0 0L10 10z")]
[InlineData("M50 50 L100 100 L150 50")]
[InlineData("M50 50L100 100L150 50")]

16
tests/Avalonia.Visuals.UnitTests/Media/RectTests.cs

@ -0,0 +1,16 @@
using System.Globalization;
using Xunit;
namespace Avalonia.Visuals.UnitTests.Media
{
public class RectTests
{
[Fact]
public void Parse_Parses()
{
var rect = Rect.Parse("1,2 3,-4", CultureInfo.CurrentCulture);
var expected = new Rect(1, 2, 3, -4);
Assert.Equal(expected, rect);
}
}
}

27
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs

@ -273,32 +273,5 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
((MockStreamGeometryImpl)borderLayer.GeometryClip).Transform);
}
}
[Fact]
public void Hiding_Root_Should_Not_Remove_Root_Layer()
{
using (TestApplication())
{
Border border;
var tree = new TestRoot
{
Child = border = new Border()
};
var layout = AvaloniaLocator.Current.GetService<ILayoutManager>();
layout.ExecuteInitialLayoutPass(tree);
var scene = new Scene(tree);
var sceneBuilder = new SceneBuilder();
sceneBuilder.UpdateAll(scene);
tree.IsVisible = false;
scene = scene.Clone();
sceneBuilder.Update(scene, tree);
Assert.Equal(1, scene.Layers.Count);
}
}
}
}

Loading…
Cancel
Save