Browse Source

Merge branch 'master' into wip-animations

pull/1461/head
Jumar Macato 8 years ago
committed by GitHub
parent
commit
586f345940
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      parameters.cake
  2. 5
      src/Avalonia.Base/AvaloniaObject.cs
  3. 2
      src/Avalonia.Controls/Avalonia.Controls.csproj
  4. 28
      src/Avalonia.Controls/Border.cs
  5. 17
      src/Avalonia.Controls/Decorator.cs
  6. 5
      src/Avalonia.Controls/Platform/IWindowImpl.cs
  7. 142
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  8. 254
      src/Avalonia.Controls/Utils/BorderRenderHelper.cs
  9. 26
      src/Avalonia.Controls/Window.cs
  10. 1
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  11. 1
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  12. 1
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  13. 1
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  14. 1
      src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
  15. 29
      src/Avalonia.Layout/LayoutHelper.cs
  16. 18
      src/Avalonia.Themes.Default/ButtonSpinner.xaml
  17. 4
      src/Avalonia.Themes.Default/ContentControl.xaml
  18. 25
      src/Avalonia.Themes.Default/Expander.xaml
  19. 4
      src/Avalonia.Themes.Default/ListBoxItem.xaml
  20. 2
      src/Avalonia.Themes.Default/RepeatButton.xaml
  21. 2
      src/Avalonia.Themes.Default/TabStripItem.xaml
  22. 2
      src/Avalonia.Themes.Default/TreeViewItem.xaml
  23. 8
      src/Avalonia.Themes.Default/Window.xaml
  24. 2
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  25. 24
      src/Gtk/Avalonia.Gtk3/WindowImpl.cs
  26. 1
      src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
  27. 1
      src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs
  28. 1
      src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
  29. 1
      src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj
  30. 16
      src/OSX/Avalonia.MonoMac/WindowImpl.cs
  31. 1
      src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
  32. 4
      src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
  33. 1
      src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs
  34. 19
      src/Windows/Avalonia.Win32/WindowImpl.cs
  35. 46
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs
  36. 2
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs
  37. 4
      tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs
  38. 2
      tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs

2
parameters.cake

@ -115,7 +115,7 @@ public class Parameters
FileZipSuffix = Version + ".zip";
ZipCoreArtifacts = ZipRoot.CombineWithFilePath("Avalonia-" + FileZipSuffix);
ZipSourceControlCatalogDesktopDirs = (DirectoryPath)context.Directory("./samples/ControlCatalog.Desktop/bin/" + DirSuffix);
ZipSourceControlCatalogDesktopDirs = (DirectoryPath)context.Directory("./samples/ControlCatalog.Desktop/bin/" + DirSuffix + "/net461");
ZipTargetControlCatalogDesktopDirs = ZipRoot.CombineWithFilePath("ControlCatalog.Desktop-" + FileZipSuffix);
}
}

5
src/Avalonia.Base/AvaloniaObject.cs

@ -139,8 +139,9 @@ namespace Avalonia
{
_inheritanceParent.PropertyChanged -= ParentPropertyChanged;
}
var inherited = (from property in AvaloniaPropertyRegistry.Instance.GetRegistered(this)
var properties = AvaloniaPropertyRegistry.Instance.GetRegistered(this)
.Concat(AvaloniaPropertyRegistry.Instance.GetRegisteredAttached(this.GetType()));
var inherited = (from property in properties
where property.Inherits
select new
{

2
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -1,8 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />

28
src/Avalonia.Controls/Border.cs

@ -3,6 +3,7 @@
using Avalonia;
using Avalonia.Controls.Utils;
using Avalonia.Layout;
using Avalonia.Media;
namespace Avalonia.Controls
@ -99,7 +100,7 @@ namespace Avalonia.Controls
/// <returns>The desired size of the control.</returns>
protected override Size MeasureOverride(Size availableSize)
{
return MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
}
/// <summary>
@ -109,32 +110,9 @@ namespace Avalonia.Controls
/// <returns>The space taken.</returns>
protected override Size ArrangeOverride(Size finalSize)
{
if (Child != null)
{
var padding = Padding + BorderThickness;
Child.Arrange(new Rect(finalSize).Deflate(padding));
}
_borderRenderHelper.Update(finalSize, BorderThickness, CornerRadius);
return finalSize;
}
internal static Size MeasureOverrideImpl(
Size availableSize,
IControl child,
Thickness padding,
Thickness borderThickness)
{
padding += borderThickness;
if (child != null)
{
child.Measure(availableSize.Deflate(padding));
return child.DesiredSize.Inflate(padding);
}
return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
return LayoutHelper.ArrangeChild(Child, finalSize, Padding, BorderThickness);
}
}
}

17
src/Avalonia.Controls/Decorator.cs

@ -1,6 +1,7 @@
// 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.Layout;
using Avalonia.Metadata;
namespace Avalonia.Controls
@ -53,25 +54,13 @@ namespace Avalonia.Controls
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
var content = Child;
var padding = Padding;
if (content != null)
{
content.Measure(availableSize.Deflate(padding));
return content.DesiredSize.Inflate(padding);
}
else
{
return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
}
return LayoutHelper.MeasureChild(Child, availableSize, Padding);
}
/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
Child?.Arrange(new Rect(finalSize).Deflate(Padding));
return finalSize;
return LayoutHelper.ArrangeChild(Child, finalSize, Padding);
}
/// <summary>

5
src/Avalonia.Controls/Platform/IWindowImpl.cs

@ -16,6 +16,11 @@ namespace Avalonia.Platform
/// </summary>
WindowState WindowState { get; set; }
/// <summary>
/// Gets or sets a method called when the minimized/maximized state of the window changes.
/// </summary>
Action<WindowState> WindowStateChanged { get; set; }
/// <summary>
/// Sets the title of the window.
/// </summary>

142
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@ -35,6 +35,13 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty<Thickness> BorderThicknessProperty =
Border.BorderThicknessProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="CornerRadius"/> property.
/// </summary>
public static readonly StyledProperty<CornerRadius> CornerRadiusProperty =
Border.CornerRadiusProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="Child"/> property.
/// </summary>
@ -55,12 +62,6 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty<IDataTemplate> ContentTemplateProperty =
ContentControl.ContentTemplateProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="CornerRadius"/> property.
/// </summary>
public static readonly StyledProperty<CornerRadius> CornerRadiusProperty =
Border.CornerRadiusProperty.AddOwner<ContentPresenter>();
/// <summary>
/// Defines the <see cref="HorizontalContentAlignment"/> property.
/// </summary>
@ -90,19 +91,12 @@ namespace Avalonia.Controls.Presenters
static ContentPresenter()
{
AffectsRender(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty);
AffectsMeasure(BorderThicknessProperty);
AffectsMeasure(BorderThicknessProperty, PaddingProperty);
ContentProperty.Changed.AddClassHandler<ContentPresenter>(x => x.ContentChanged);
ContentTemplateProperty.Changed.AddClassHandler<ContentPresenter>(x => x.ContentChanged);
TemplatedParentProperty.Changed.AddClassHandler<ContentPresenter>(x => x.TemplatedParentChanged);
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentPresenter"/> class.
/// </summary>
public ContentPresenter()
{
}
/// <summary>
/// Gets or sets a brush with which to paint the background.
/// </summary>
@ -130,6 +124,15 @@ namespace Avalonia.Controls.Presenters
set { SetValue(BorderThicknessProperty, value); }
}
/// <summary>
/// Gets or sets the radius of the border rounded corners.
/// </summary>
public CornerRadius CornerRadius
{
get { return GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Gets the control displayed by the presenter.
/// </summary>
@ -159,16 +162,7 @@ namespace Avalonia.Controls.Presenters
}
/// <summary>
/// Gets or sets the radius of the border rounded corners.
/// </summary>
public CornerRadius CornerRadius
{
get { return GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Gets or sets the horizontal alignment of the content within the control.
/// Gets or sets the horizontal alignment of the content within the border the control.
/// </summary>
public HorizontalAlignment HorizontalContentAlignment
{
@ -177,7 +171,7 @@ namespace Avalonia.Controls.Presenters
}
/// <summary>
/// Gets or sets the vertical alignment of the content within the control.
/// Gets or sets the vertical alignment of the content within the border of the control.
/// </summary>
public VerticalAlignment VerticalContentAlignment
{
@ -186,7 +180,7 @@ namespace Avalonia.Controls.Presenters
}
/// <summary>
/// Gets or sets the padding to place around the <see cref="Child"/> control.
/// Gets or sets the space between the border and the <see cref="Child"/> control.
/// </summary>
public Thickness Padding
{
@ -195,7 +189,7 @@ namespace Avalonia.Controls.Presenters
}
/// <inheritdoc/>
public override sealed void ApplyTemplate()
public sealed override void ApplyTemplate()
{
if (!_createdChild && ((ILogical)this).IsAttachedToLogicalTree)
{
@ -328,96 +322,68 @@ namespace Avalonia.Controls.Presenters
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
return Border.MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
}
/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
finalSize = ArrangeOverrideImpl(finalSize, new Vector());
_borderRenderer.Update(finalSize, BorderThickness, CornerRadius);
return finalSize;
}
/// <summary>
/// Called when the <see cref="Content"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private void ContentChanged(AvaloniaPropertyChangedEventArgs e)
{
_createdChild = false;
if (((ILogical)this).IsAttachedToLogicalTree)
{
UpdateChild();
}
else if (Child != null)
{
VisualChildren.Remove(Child);
LogicalChildren.Remove(Child);
Child = null;
_dataTemplate = null;
}
InvalidateMeasure();
return ArrangeOverrideImpl(finalSize, new Vector());
}
internal Size ArrangeOverrideImpl(Size finalSize, Vector offset)
{
if (Child == null) return finalSize;
var padding = Padding;
var borderThickness = BorderThickness;
var padding = Padding + BorderThickness;
var horizontalContentAlignment = HorizontalContentAlignment;
var verticalContentAlignment = VerticalContentAlignment;
var useLayoutRounding = UseLayoutRounding;
var availableSizeMinusMargins = new Size(
Math.Max(0, finalSize.Width - padding.Left - padding.Right - borderThickness.Left - borderThickness.Right),
Math.Max(0, finalSize.Height - padding.Top - padding.Bottom - borderThickness.Top - borderThickness.Bottom));
var size = availableSizeMinusMargins;
var availableSize = finalSize;
var sizeForChild = availableSize;
var scale = GetLayoutScale();
var originX = offset.X + padding.Left + borderThickness.Left;
var originY = offset.Y + padding.Top + borderThickness.Top;
var originX = offset.X;
var originY = offset.Y;
if (horizontalContentAlignment != HorizontalAlignment.Stretch)
{
size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width - padding.Left - padding.Right));
sizeForChild = sizeForChild.WithWidth(Math.Min(sizeForChild.Width, DesiredSize.Width));
}
if (verticalContentAlignment != VerticalAlignment.Stretch)
{
size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height - padding.Top - padding.Bottom));
sizeForChild = sizeForChild.WithHeight(Math.Min(sizeForChild.Height, DesiredSize.Height));
}
if (useLayoutRounding)
{
size = new Size(
Math.Ceiling(size.Width * scale) / scale,
Math.Ceiling(size.Height * scale) / scale);
availableSizeMinusMargins = new Size(
Math.Ceiling(availableSizeMinusMargins.Width * scale) / scale,
Math.Ceiling(availableSizeMinusMargins.Height * scale) / scale);
sizeForChild = new Size(
Math.Ceiling(sizeForChild.Width * scale) / scale,
Math.Ceiling(sizeForChild.Height * scale) / scale);
availableSize = new Size(
Math.Ceiling(availableSize.Width * scale) / scale,
Math.Ceiling(availableSize.Height * scale) / scale);
}
switch (horizontalContentAlignment)
{
case HorizontalAlignment.Center:
originX += (availableSizeMinusMargins.Width - size.Width) / 2;
originX += (availableSize.Width - sizeForChild.Width) / 2;
break;
case HorizontalAlignment.Right:
originX += availableSizeMinusMargins.Width - size.Width;
originX += availableSize.Width - sizeForChild.Width;
break;
}
switch (verticalContentAlignment)
{
case VerticalAlignment.Center:
originY += (availableSizeMinusMargins.Height - size.Height) / 2;
originY += (availableSize.Height - sizeForChild.Height) / 2;
break;
case VerticalAlignment.Bottom:
originY += availableSizeMinusMargins.Height - size.Height;
originY += availableSize.Height - sizeForChild.Height;
break;
}
@ -427,11 +393,37 @@ namespace Avalonia.Controls.Presenters
originY = Math.Floor(originY * scale) / scale;
}
Child.Arrange(new Rect(originX, originY, Math.Max(0, size.Width), Math.Max(0, size.Height)));
var boundsForChild =
new Rect(originX, originY, sizeForChild.Width, sizeForChild.Height).Deflate(padding);
Child.Arrange(boundsForChild);
return finalSize;
}
/// <summary>
/// Called when the <see cref="Content"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private void ContentChanged(AvaloniaPropertyChangedEventArgs e)
{
_createdChild = false;
if (((ILogical)this).IsAttachedToLogicalTree)
{
UpdateChild();
}
else if (Child != null)
{
VisualChildren.Remove(Child);
LogicalChildren.Remove(Child);
Child = null;
_dataTemplate = null;
}
InvalidateMeasure();
}
private double GetLayoutScale()
{
var result = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;

254
src/Avalonia.Controls/Utils/BorderRenderHelper.cs

@ -26,17 +26,17 @@ namespace Avalonia.Controls.Utils
var boundRect = new Rect(finalSize);
var innerRect = boundRect.Deflate(borderThickness);
var innerCoordinates = new BorderCoordinates(cornerRadius, borderThickness, false);
BorderGeometryKeypoints backgroundKeypoints = null;
StreamGeometry backgroundGeometry = null;
if (innerRect.Width != 0 && innerRect.Height != 0)
{
backgroundGeometry = new StreamGeometry();
backgroundKeypoints = new BorderGeometryKeypoints(innerRect, borderThickness, cornerRadius, true);
using (var ctx = backgroundGeometry.Open())
{
CreateGeometry(ctx, innerRect, innerCoordinates);
CreateGeometry(ctx, innerRect, backgroundKeypoints);
}
_backgroundGeometryCache = backgroundGeometry;
@ -48,16 +48,16 @@ namespace Avalonia.Controls.Utils
if (boundRect.Width != 0 && innerRect.Height != 0)
{
var outerCoordinates = new BorderCoordinates(cornerRadius, borderThickness, true);
var borderGeometryKeypoints = new BorderGeometryKeypoints(boundRect, borderThickness, cornerRadius, false);
var borderGeometry = new StreamGeometry();
using (var ctx = borderGeometry.Open())
{
CreateGeometry(ctx, boundRect, outerCoordinates);
CreateGeometry(ctx, boundRect, borderGeometryKeypoints);
if (backgroundGeometry != null)
{
CreateGeometry(ctx, innerRect, innerCoordinates);
CreateGeometry(ctx, innerRect, backgroundKeypoints);
}
}
@ -104,176 +104,156 @@ namespace Avalonia.Controls.Utils
}
}
private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderCoordinates borderCoordinates)
{
var topLeft = new Point(borderCoordinates.LeftTop, 0);
var topRight = new Point(boundRect.Width - borderCoordinates.RightTop, 0);
var rightTop = new Point(boundRect.Width, borderCoordinates.TopRight);
var rightBottom = new Point(boundRect.Width, boundRect.Height - borderCoordinates.BottomRight);
var bottomRight = new Point(boundRect.Width - borderCoordinates.RightBottom, boundRect.Height);
var bottomLeft = new Point(borderCoordinates.LeftBottom, boundRect.Height);
var leftBottom = new Point(0, boundRect.Height - borderCoordinates.BottomLeft);
var leftTop = new Point(0, borderCoordinates.TopLeft);
private class BorderGeometryKeypoints
{
internal BorderGeometryKeypoints(Rect boundRect, Thickness borderThickness, CornerRadius cornerRadius, bool inner)
{
var left = 0.5 * borderThickness.Left;
var top = 0.5 * borderThickness.Top;
var right = 0.5 * borderThickness.Right;
var bottom = 0.5 * borderThickness.Bottom;
double leftTopY;
double topLeftX;
double topRightX;
double rightTopY;
double rightBottomY;
double bottomRightX;
double bottomLeftX;
double leftBottomY;
if (topLeft.X > topRight.X)
{
var scaledX = borderCoordinates.LeftTop / (borderCoordinates.LeftTop + borderCoordinates.RightTop) * boundRect.Width;
topLeft = new Point(scaledX, topLeft.Y);
topRight = new Point(scaledX, topRight.Y);
}
if (inner)
{
leftTopY = Math.Max(0, cornerRadius.TopLeft - top) + boundRect.TopLeft.Y;
topLeftX = Math.Max(0, cornerRadius.TopLeft - left) + boundRect.TopLeft.X;
topRightX = boundRect.Width - Math.Max(0, cornerRadius.TopRight - top) + boundRect.TopLeft.X;
rightTopY = Math.Max(0, cornerRadius.TopRight - right) + boundRect.TopLeft.Y;
rightBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomRight - bottom) + boundRect.TopLeft.Y;
bottomRightX = boundRect.Width - Math.Max(0, cornerRadius.BottomRight - right) + boundRect.TopLeft.X;
bottomLeftX = Math.Max(0, cornerRadius.BottomLeft - left) + boundRect.TopLeft.X;
leftBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomLeft - bottom) + boundRect.TopLeft.Y;
}
else
{
leftTopY = cornerRadius.TopLeft + top + boundRect.TopLeft.Y;
topLeftX = cornerRadius.TopLeft + left + boundRect.TopLeft.X;
topRightX = boundRect.Width - (cornerRadius.TopRight + right) + boundRect.TopLeft.X;
rightTopY = cornerRadius.TopRight + top + boundRect.TopLeft.Y;
rightBottomY = boundRect.Height - (cornerRadius.BottomRight + bottom) + boundRect.TopLeft.Y;
bottomRightX = boundRect.Width - (cornerRadius.BottomRight + right) + boundRect.TopLeft.X;
bottomLeftX = cornerRadius.BottomLeft + left + boundRect.TopLeft.X;
leftBottomY = boundRect.Height - (cornerRadius.BottomLeft + bottom) + boundRect.TopLeft.Y;
}
var leftTopX = boundRect.TopLeft.X;
var topLeftY = boundRect.TopLeft.Y;
var topRightY = boundRect.TopLeft.Y;
var rightTopX = boundRect.Width + boundRect.TopLeft.X;
var rightBottomX = boundRect.Width + boundRect.TopLeft.X;
var bottomRightY = boundRect.Height + boundRect.TopLeft.Y;
var bottomLeftY = boundRect.Height + boundRect.TopLeft.Y;
var leftBottomX = boundRect.TopLeft.X;
LeftTop = new Point(leftTopX, leftTopY);
TopLeft = new Point(topLeftX, topLeftY);
TopRight = new Point(topRightX, topRightY);
RightTop = new Point(rightTopX, rightTopY);
RightBottom = new Point(rightBottomX, rightBottomY);
BottomRight = new Point(bottomRightX, bottomRightY);
BottomLeft = new Point(bottomLeftX, bottomLeftY);
LeftBottom = new Point(leftBottomX, leftBottomY);
//Fix overlap
if (TopLeft.X > TopRight.X)
{
var scaledX = topLeftX / (topLeftX + topRightX) * boundRect.Width;
TopLeft = new Point(scaledX, TopLeft.Y);
TopRight = new Point(scaledX, TopRight.Y);
}
if (rightTop.Y > rightBottom.Y)
{
var scaledY = borderCoordinates.TopRight / (borderCoordinates.TopRight + borderCoordinates.BottomRight) * boundRect.Height;
rightTop = new Point(rightTop.X, scaledY);
rightBottom = new Point(rightBottom.X, scaledY);
}
if (RightTop.Y > RightBottom.Y)
{
var scaledY = rightBottomY / (rightTopY + rightBottomY) * boundRect.Height;
RightTop = new Point(RightTop.X, scaledY);
RightBottom = new Point(RightBottom.X, scaledY);
}
if (bottomRight.X < bottomLeft.X)
{
var scaledX = borderCoordinates.LeftBottom / (borderCoordinates.LeftBottom + borderCoordinates.RightBottom) * boundRect.Width;
bottomRight = new Point(scaledX, bottomRight.Y);
bottomLeft = new Point(scaledX, bottomLeft.Y);
}
if (BottomRight.X < BottomLeft.X)
{
var scaledX = bottomLeftX / (bottomLeftX + bottomRightX) * boundRect.Width;
BottomRight = new Point(scaledX, BottomRight.Y);
BottomLeft = new Point(scaledX, BottomLeft.Y);
}
if (leftBottom.Y < leftTop.Y)
{
var scaledY = borderCoordinates.TopLeft / (borderCoordinates.TopLeft + borderCoordinates.BottomLeft) * boundRect.Height;
leftBottom = new Point(leftBottom.X, scaledY);
leftTop = new Point(leftTop.X, scaledY);
if (LeftBottom.Y < LeftTop.Y)
{
var scaledY = leftTopY / (leftTopY + leftBottomY) * boundRect.Height;
LeftBottom = new Point(LeftBottom.X, scaledY);
LeftTop = new Point(LeftTop.X, scaledY);
}
}
var offset = new Vector(boundRect.TopLeft.X, boundRect.TopLeft.Y);
topLeft += offset;
topRight += offset;
rightTop += offset;
rightBottom += offset;
bottomRight += offset;
bottomLeft += offset;
leftBottom += offset;
leftTop += offset;
internal Point LeftTop { get; private set; }
internal Point TopLeft { get; private set; }
internal Point TopRight { get; private set; }
internal Point RightTop { get; private set; }
internal Point RightBottom { get; private set; }
internal Point BottomRight { get; private set; }
internal Point BottomLeft { get; private set; }
internal Point LeftBottom { get; private set; }
}
context.BeginFigure(topLeft, true);
private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints)
{
context.BeginFigure(keypoints.TopLeft, true);
//Top
context.LineTo(topRight);
context.LineTo(keypoints.TopRight);
//TopRight corner
var radiusX = boundRect.TopRight.X - topRight.X;
var radiusY = rightTop.Y - boundRect.TopRight.Y;
var radiusX = boundRect.TopRight.X - keypoints.TopRight.X;
var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(rightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
}
//Right
context.LineTo(rightBottom);
context.LineTo(keypoints.RightBottom);
//BottomRight corner
radiusX = boundRect.BottomRight.X - bottomRight.X;
radiusY = boundRect.BottomRight.Y - rightBottom.Y;
radiusX = boundRect.BottomRight.X - keypoints.BottomRight.X;
radiusY = boundRect.BottomRight.Y - keypoints.RightBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(bottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
context.ArcTo(keypoints.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
//Bottom
context.LineTo(bottomLeft);
context.LineTo(keypoints.BottomLeft);
//BottomLeft corner
radiusX = bottomLeft.X - boundRect.BottomLeft.X;
radiusY = boundRect.BottomLeft.Y - leftBottom.Y;
radiusX = keypoints.BottomLeft.X - boundRect.BottomLeft.X;
radiusY = boundRect.BottomLeft.Y - keypoints.LeftBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(leftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
context.ArcTo(keypoints.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
//Left
context.LineTo(leftTop);
context.LineTo(keypoints.LeftTop);
//TopLeft corner
radiusX = topLeft.X - boundRect.TopLeft.X;
radiusY = leftTop.Y - boundRect.TopLeft.Y;
radiusX = keypoints.TopLeft.X - boundRect.TopLeft.X;
radiusY = keypoints.LeftTop.Y - boundRect.TopLeft.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(topLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
context.ArcTo(keypoints.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
context.EndFigure(true);
}
private struct BorderCoordinates
{
internal BorderCoordinates(CornerRadius cornerRadius, Thickness borderThickness, bool isOuter)
{
var left = 0.5 * borderThickness.Left;
var top = 0.5 * borderThickness.Top;
var right = 0.5 * borderThickness.Right;
var bottom = 0.5 * borderThickness.Bottom;
if (isOuter)
{
if (cornerRadius.TopLeft == 0)
{
LeftTop = TopLeft = 0.0;
}
else
{
LeftTop = cornerRadius.TopLeft + left;
TopLeft = cornerRadius.TopLeft + top;
}
if (cornerRadius.TopRight == 0)
{
TopRight = RightTop = 0;
}
else
{
TopRight = cornerRadius.TopRight + top;
RightTop = cornerRadius.TopRight + right;
}
if (cornerRadius.BottomRight == 0)
{
RightBottom = BottomRight = 0;
}
else
{
RightBottom = cornerRadius.BottomRight + right;
BottomRight = cornerRadius.BottomRight + bottom;
}
if (cornerRadius.BottomLeft == 0)
{
BottomLeft = LeftBottom = 0;
}
else
{
BottomLeft = cornerRadius.BottomLeft + bottom;
LeftBottom = cornerRadius.BottomLeft + left;
}
}
else
{
LeftTop = Math.Max(0, cornerRadius.TopLeft - left);
TopLeft = Math.Max(0, cornerRadius.TopLeft - top);
TopRight = Math.Max(0, cornerRadius.TopRight - top);
RightTop = Math.Max(0, cornerRadius.TopRight - right);
RightBottom = Math.Max(0, cornerRadius.BottomRight - right);
BottomRight = Math.Max(0, cornerRadius.BottomRight - bottom);
BottomLeft = Math.Max(0, cornerRadius.BottomLeft - bottom);
LeftBottom = Math.Max(0, cornerRadius.BottomLeft - left);
}
}
internal readonly double LeftTop;
internal readonly double TopLeft;
internal readonly double TopRight;
internal readonly double RightTop;
internal readonly double RightBottom;
internal readonly double BottomRight;
internal readonly double BottomLeft;
internal readonly double LeftBottom;
}
}
}

26
src/Avalonia.Controls/Window.cs

@ -67,13 +67,19 @@ namespace Avalonia.Controls
/// </summary>
public static readonly StyledProperty<bool> HasSystemDecorationsProperty =
AvaloniaProperty.Register<Window, bool>(nameof(HasSystemDecorations), true);
/// <summary>
/// Enables or disables the taskbar icon
/// </summary>
public static readonly StyledProperty<bool> ShowInTaskbarProperty =
AvaloniaProperty.Register<Window, bool>(nameof(ShowInTaskbar), true);
/// <summary>
/// Enables or disables the taskbar icon
/// </summary>
public static readonly StyledProperty<WindowState> WindowStateProperty =
AvaloniaProperty.Register<Window, WindowState>(nameof(WindowState));
/// <summary>
/// Defines the <see cref="Title"/> property.
/// </summary>
@ -118,6 +124,9 @@ namespace Avalonia.Controls
IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
CanResizeProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.CanResize((bool)e.NewValue));
WindowStateProperty.Changed.AddClassHandler<Window>(
(w, e) => { if (w.PlatformImpl != null) w.PlatformImpl.WindowState = (WindowState)e.NewValue; });
}
/// <summary>
@ -138,8 +147,11 @@ namespace Avalonia.Controls
impl.Closing = HandleClosing;
_maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
Screens = new Screens(PlatformImpl?.Screen);
}
if (PlatformImpl != null)
PlatformImpl.WindowStateChanged = s => WindowState = s;
}
/// <inheritdoc/>
event EventHandler<NameScopeEventArgs> INameScope.Registered
{
@ -205,12 +217,8 @@ namespace Avalonia.Controls
/// </summary>
public WindowState WindowState
{
get { return PlatformImpl?.WindowState ?? WindowState.Normal; }
set
{
if (PlatformImpl != null)
PlatformImpl.WindowState = value;
}
get { return GetValue(WindowStateProperty); }
set { SetValue(WindowStateProperty, value); }
}
/// <summary>

1
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@ -42,6 +42,7 @@ namespace Avalonia.DesignerSupport.Remote
public Func<bool> Closing { get; set; }
public IPlatformHandle Handle { get; }
public WindowState WindowState { get; set; }
public Action<WindowState> WindowStateChanged { get; set; }
public Size MaxClientSize { get; } = new Size(4096, 4096);
public event Action LostFocus;

1
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -32,6 +32,7 @@ namespace Avalonia.DesignerSupport.Remote
public Point Position { get; set; }
public Action<Point> PositionChanged { get; set; }
public WindowState WindowState { get; set; }
public Action<WindowState> WindowStateChanged { get; set; }
public IRenderer CreateRenderer(IRenderRoot root) => new ImmediateRenderer(root);
public void Dispose()
{

1
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<DefineConstants>$(DefineConstants);DOTNETCORE</DefineConstants>
</PropertyGroup>
<ItemGroup>

1
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<DocumentationFile>bin\$(Configuration)\Avalonia.DotNetFrameworkRuntime.xml</DocumentationFile>
<DefineConstants>$(DefineConstants);FULLDOTNET</DefineConstants>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

1
src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj

@ -3,7 +3,6 @@
<TargetFramework>netstandard2.0</TargetFramework>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<EnableDefaultItems>False</EnableDefaultItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<NoWarn>CS0436</NoWarn>
</PropertyGroup>
<ItemGroup>

29
src/Avalonia.Layout/LayoutHelper.cs

@ -29,5 +29,34 @@ namespace Avalonia.Layout
height = Math.Max(height, control.MinHeight);
return new Size(width, height);
}
public static Size MeasureChild(ILayoutable control, Size availableSize, Thickness padding,
Thickness borderThickness)
{
return MeasureChild(control, availableSize, padding + borderThickness);
}
public static Size MeasureChild(ILayoutable control, Size availableSize, Thickness padding)
{
if (control != null)
{
control.Measure(availableSize.Deflate(padding));
return control.DesiredSize.Inflate(padding);
}
return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
}
public static Size ArrangeChild(ILayoutable child, Size availableSize, Thickness padding, Thickness borderThickness)
{
return ArrangeChild(child, availableSize, padding + borderThickness);
}
public static Size ArrangeChild(ILayoutable child, Size availableSize, Thickness padding)
{
child?.Arrange(new Rect(availableSize).Deflate(padding));
return availableSize;
}
}
}

18
src/Avalonia.Themes.Default/ButtonSpinner.xaml

@ -46,12 +46,15 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}">
<Grid ColumnDefinitions="*,Auto">
<ContentPresenter Name="PART_ContentPresenter" Grid.Column="0"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"/>
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"/>
<Grid Grid.Column="1" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/>
<RepeatButton Grid.Row="1" Name="PART_DecreaseButton"/>
@ -68,8 +71,8 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}">
<Grid ColumnDefinitions="Auto,*">
<Grid Grid.Column="0" RowDefinitions="*,*" IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Grid.Row="0" Name="PART_IncreaseButton"/>
@ -77,7 +80,10 @@
</Grid>
<ContentPresenter Name="PART_ContentPresenter" Grid.Column="1"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"/>
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"/>
</Grid>
</Border>
</ControlTemplate>

4
src/Avalonia.Themes.Default/ContentControl.xaml

@ -7,7 +7,9 @@
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>

25
src/Avalonia.Themes.Default/Expander.xaml

@ -18,8 +18,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}" />
</Grid>
</Border>
</ControlTemplate>
@ -36,8 +37,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}" />
</Grid>
</Border>
</ControlTemplate>
@ -54,8 +56,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}" />
</Grid>
</Border>
</ControlTemplate>
@ -72,8 +75,9 @@
IsVisible="{TemplateBinding IsExpanded}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}" />
</Grid>
</Border>
</ControlTemplate>
@ -94,7 +98,10 @@
Grid.Column="1"
Background="Transparent"
Content="{TemplateBinding Content}"
VerticalAlignment="Center" />
VerticalAlignment="Center"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"/>
</Grid>
</Border>
</ControlTemplate>

4
src/Avalonia.Themes.Default/ListBoxItem.xaml

@ -9,7 +9,9 @@
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>

2
src/Avalonia.Themes.Default/RepeatButton.xaml

@ -25,7 +25,7 @@
Padding="{TemplateBinding Padding}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter>
</Style>

2
src/Avalonia.Themes.Default/TabStripItem.xaml

@ -11,6 +11,8 @@
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter>

2
src/Avalonia.Themes.Default/TreeViewItem.xaml

@ -13,6 +13,8 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Header}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"
TemplatedControl.IsTemplateFocusTarget="True"
Grid.Column="1"/>

8
src/Avalonia.Themes.Default/Window.xaml

@ -6,10 +6,12 @@
<ControlTemplate>
<Border Background="{TemplateBinding Background}">
<AdornerDecorator>
<ContentPresenter Name="PART_ContentPresenter"
<ContentPresenter Name="PART_ContentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
</AdornerDecorator>
</Border>
</ControlTemplate>

2
src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs

@ -241,7 +241,7 @@ namespace Avalonia.Gtk3
return true;
}
void ConnectEvent(string name, Native.D.signal_onevent handler)
protected void ConnectEvent(string name, Native.D.signal_onevent handler)
=> Disposables.Add(Signal.Connect<Native.D.signal_onevent>(GtkWidget, name, handler));
void Connect<T>(string name, T handler) => Disposables.Add(Signal.Connect(GtkWidget, name, handler));

24
src/Gtk/Avalonia.Gtk3/WindowImpl.cs

@ -1,18 +1,34 @@
using System;
using System.Linq.Expressions;
using Avalonia.Controls;
using Avalonia.Gtk3.Interop;
using Avalonia.Platform;
using System.Runtime.InteropServices;
namespace Avalonia.Gtk3
{
class WindowImpl : WindowBaseImpl, IWindowImpl
{
private WindowState _lastWindowState;
public WindowImpl() : base(Native.GtkWindowNew(GtkWindowType.TopLevel))
{
}
protected unsafe override bool OnStateChanged(IntPtr w, IntPtr pev, IntPtr userData)
{
var windowStateEvent = (GdkEventWindowState*)pev;
var newWindowState = windowStateEvent->new_window_state;
var windowState = newWindowState.HasFlag(GdkWindowState.Iconified) ? WindowState.Minimized
: (newWindowState.HasFlag(GdkWindowState.Maximized) ? WindowState.Maximized : WindowState.Normal);
if (windowState != _lastWindowState)
{
_lastWindowState = windowState;
WindowStateChanged?.Invoke(windowState);
}
return base.OnStateChanged(w, pev, userData);
}
public void SetTitle(string title)
{
using (var t = new Utf8Buffer(title))
@ -43,7 +59,9 @@ namespace Avalonia.Gtk3
}
}
}
public Action<WindowState> WindowStateChanged { get; set; }
public IDisposable ShowDialog()
{
Native.GtkWindowSetModal(GtkWidget, true);

1
src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj

@ -3,7 +3,6 @@
<TargetFramework>netstandard2.0</TargetFramework>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<EnableDefaultItems>false</EnableDefaultItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>

1
src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs

@ -5,7 +5,6 @@ using System.Reflection;
using Avalonia.Metadata;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("Avalonia.Markup.Xaml")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Data")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Styling")]

1
src/Markup/Avalonia.Markup/Avalonia.Markup.csproj

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj" />

1
src/OSX/Avalonia.MonoMac/Avalonia.MonoMac.csproj

@ -2,7 +2,6 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\Shared\WindowResizeDragHelper.cs" Link="WindowResizeDragHelper.cs" />

16
src/OSX/Avalonia.MonoMac/WindowImpl.cs

@ -12,10 +12,24 @@ namespace Avalonia.MonoMac
public bool IsResizable = true;
public CGRect? UndecoratedLastUnmaximizedFrame;
private WindowState _lastWindowState;
public WindowImpl()
{
UpdateStyle();
Window.SetCanBecomeKeyAndMain();
Window.DidResize += delegate
{
var windowState = Window.IsMiniaturized ? WindowState.Minimized
: (IsZoomed ? WindowState.Maximized : WindowState.Normal);
if (windowState != _lastWindowState)
{
_lastWindowState = windowState;
WindowStateChanged?.Invoke(windowState);
}
};
}
public WindowState WindowState
@ -49,6 +63,8 @@ namespace Avalonia.MonoMac
}
}
public Action<WindowState> WindowStateChanged { get; set; }
bool IsZoomed => IsDecorated ? Window.IsZoomed : UndecoratedIsMaximized;
public bool UndecoratedIsMaximized => Window.Frame == Window.Screen.VisibleFrame;

1
src/Skia/Avalonia.Skia/Avalonia.Skia.csproj

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<RootNamespace>Avalonia.Skia</RootNamespace>
<AssemblyName>Avalonia.Skia</AssemblyName>
<IncludeLinuxSkia>true</IncludeLinuxSkia>

4
src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj

@ -1,12 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="..\Avalonia.Win32\Interop\UnmanagedMethods.cs">
<Link>UnmanagedMethods.cs</Link>
</Compile>

1
src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs

@ -5,7 +5,6 @@ using System.Reflection;
using Avalonia.Platform;
using Avalonia.Direct2D1;
[assembly: AssemblyTitle("Avalonia.Direct2D1")]
[assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 1, "Direct2D1", typeof(Direct2D1Platform), nameof(Direct2D1Platform.Initialize),
typeof(Direct2DChecker))]

19
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -34,6 +34,7 @@ namespace Avalonia.Win32
private bool _resizable = true;
private double _scaling = 1;
private WindowState _showWindowState;
private WindowState _lastWindowState;
private FramebufferManager _framebuffer;
private OleDropTarget _dropTarget;
private Size _minSize;
@ -77,6 +78,8 @@ namespace Avalonia.Win32
public Action<Point> PositionChanged { get; set; }
public Action<WindowState> WindowStateChanged { get; set; }
public Thickness BorderThickness
{
get
@ -626,14 +629,25 @@ namespace Avalonia.Win32
return IntPtr.Zero;
case UnmanagedMethods.WindowsMessage.WM_SIZE:
var size = (UnmanagedMethods.SizeCommand)wParam;
if (Resized != null &&
(wParam == (IntPtr)UnmanagedMethods.SizeCommand.Restored ||
wParam == (IntPtr)UnmanagedMethods.SizeCommand.Maximized))
(size == UnmanagedMethods.SizeCommand.Restored ||
size == UnmanagedMethods.SizeCommand.Maximized))
{
var clientSize = new Size(ToInt32(lParam) & 0xffff, ToInt32(lParam) >> 16);
Resized(clientSize / Scaling);
}
var windowState = size == SizeCommand.Maximized ? WindowState.Maximized
: (size == SizeCommand.Minimized ? WindowState.Minimized : WindowState.Normal);
if (windowState != _lastWindowState)
{
_lastWindowState = windowState;
WindowStateChanged?.Invoke(windowState);
}
return IntPtr.Zero;
case UnmanagedMethods.WindowsMessage.WM_MOVE:
@ -663,6 +677,7 @@ namespace Avalonia.Win32
(Screen as ScreenImpl)?.InvalidateScreensCache();
return IntPtr.Zero;
}
#if USE_MANAGED_DRAG
if (_managedDrag.PreprocessInputEvent(ref e))

46
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Inheritance.cs

@ -38,6 +38,26 @@ namespace Avalonia.Base.UnitTests
Assert.True(raised);
}
[Fact]
public void Setting_InheritanceParent_Raises_PropertyChanged_For_Attached_Property_When_Value_Changed_In_Parent()
{
bool raised = false;
Class1 parent = new Class1();
parent.SetValue(AttachedOwner.AttachedProperty, "changed");
Class2 child = new Class2();
child.PropertyChanged += (s, e) =>
raised = s == child &&
e.Property == AttachedOwner.AttachedProperty &&
(string)e.OldValue == null &&
(string)e.NewValue == "changed";
child.Parent = parent;
Assert.True(raised);
}
[Fact]
public void Setting_InheritanceParent_Doesnt_Raise_PropertyChanged_When_Local_Value_Set()
{
@ -75,6 +95,26 @@ namespace Avalonia.Base.UnitTests
Assert.True(raised);
}
[Fact]
public void Setting_Value_Of_Attached_Property_In_InheritanceParent_Raises_PropertyChanged()
{
bool raised = false;
Class1 parent = new Class1();
Class2 child = new Class2();
child.PropertyChanged += (s, e) =>
raised = s == child &&
e.Property == AttachedOwner.AttachedProperty &&
(string)e.OldValue == null &&
(string)e.NewValue == "changed";
child.Parent = parent;
parent.SetValue(AttachedOwner.AttachedProperty, "changed");
Assert.True(raised);
}
private class Class1 : AvaloniaObject
{
public static readonly StyledProperty<string> FooProperty =
@ -97,5 +137,11 @@ namespace Avalonia.Base.UnitTests
set { InheritanceParent = value; }
}
}
private class AttachedOwner : AvaloniaObject
{
public static readonly AttachedProperty<string> AttachedProperty =
AvaloniaProperty.RegisterAttached<AttachedOwner, Class1, string>("Attached", inherits: true);
}
}
}

2
tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Layout.cs

@ -233,7 +233,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
target.Arrange(new Rect(0, 0, 100, 100));
Assert.Equal(new Rect(48, 48, 0, 0), content.Bounds);
Assert.Equal(new Rect(32, 32, 0, 0), content.Bounds);
}
}
}

4
tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

@ -11,9 +11,9 @@ namespace Avalonia.DesignerSupport.Tests
{
public class DesignerSupportTests
{
[Theory(Skip = "Skipping for now as failing on AppVeyor"),
[Theory,
InlineData(@"Avalonia.DesignerSupport.TestApp.exe", @"..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml"),
InlineData(@"..\..\samples\ControlCatalog.Desktop\bin\$BUILD\ControlCatalog.dll", @"..\..\samples\ControlCatalog\MainWindow.xaml")]
InlineData(@"..\..\samples\ControlCatalog.Desktop\bin\$BUILD\net461\ControlCatalog.dll", @"..\..\samples\ControlCatalog\MainWindow.xaml")]
public void DesignerApiShoudBeOperational(string outputDir, string xamlFile)
{
var xaml = File.ReadAllText(xamlFile);

2
tests/Avalonia.Markup.UnitTests/Data/BindingExpressionTests.cs

@ -296,7 +296,7 @@ namespace Avalonia.Markup.UnitTests.Data
var data = new Class1 { DoubleValue = 5.6 };
var converter = new Mock<IValueConverter>();
var target = new BindingExpression(
new ExpressionObserver(data, "DoubleValue"),
new ExpressionObserver(data, "DoubleValue"),
typeof(string),
converter.Object,
converterParameter: "foo");

Loading…
Cancel
Save