Browse Source

Merge branch 'master' into FixBindingStackOverflow

pull/1214/head
Steven Kirk 9 years ago
committed by GitHub
parent
commit
b2886a5e8a
  1. 5
      .ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject
  2. 1
      .travis.yml
  3. 9
      scripts/ReplaceNugetCache.ps1
  4. 7
      scripts/ReplaceNugetCache.sh
  5. 9
      scripts/ReplaceNugetCacheRelease.ps1
  6. 10
      src/Avalonia.Controls/Control.cs
  7. 20
      src/Avalonia.Controls/DropDown.cs
  8. 22
      src/Avalonia.Input/MouseDevice.cs
  9. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
  10. 7
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  11. 4
      src/Avalonia.Visuals/Visual.cs
  12. 41
      tests/Avalonia.Controls.UnitTests/ControlTests.cs
  13. 26
      tests/Avalonia.Controls.UnitTests/DropDownTests.cs
  14. 4
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs
  15. 19
      tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs
  16. 54
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs

5
.ncrunch/Avalonia.Designer.HostApp.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

1
.travis.yml

@ -1,7 +1,6 @@
language: csharp
os:
- linux
- osx
dist: trusty
osx_image: xcode8.3
env:

9
scripts/ReplaceNugetCache.ps1

@ -1,5 +1,4 @@
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp2.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard2.0\

7
scripts/ReplaceNugetCache.sh

@ -1,7 +1,6 @@
#!/usr/bin/env bash
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp1.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard1.1/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard1.1/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia.desktop/$1/lib/netstandard1.3/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp2.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard2.0/
cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp2.0/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard2.0/

9
scripts/ReplaceNugetCacheRelease.ps1

@ -1,5 +1,4 @@
copy ..\samples\ControlCatalog.NetCore\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\
copy ..\samples\ControlCatalog.NetCore\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp2.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard2.0\

10
src/Avalonia.Controls/Control.cs

@ -656,7 +656,6 @@ namespace Avalonia.Controls
/// <param name="e">The event args.</param>
protected virtual void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
AttachedToLogicalTree?.Invoke(this, e);
}
/// <summary>
@ -665,7 +664,6 @@ namespace Avalonia.Controls
/// <param name="e">The event args.</param>
protected virtual void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
DetachedFromLogicalTree?.Invoke(this, e);
}
/// <inheritdoc/>
@ -773,11 +771,9 @@ namespace Avalonia.Controls
{
while (e != null)
{
var root = e as IStyleRoot;
if (root != null && root.StylingParent == null)
if (e is IRenderRoot root)
{
return root;
return root as IStyleRoot;
}
e = e.StylingParent;
@ -844,6 +840,7 @@ namespace Avalonia.Controls
InitializeStylesIfNeeded(true);
OnAttachedToLogicalTree(e);
AttachedToLogicalTree?.Invoke(this, e);
}
foreach (var child in LogicalChildren.OfType<Control>())
@ -864,6 +861,7 @@ namespace Avalonia.Controls
_isAttachedToLogicalTree = false;
_styleDetach.OnNext(this);
OnDetachedFromLogicalTree(e);
DetachedFromLogicalTree?.Invoke(this, e);
foreach (var child in LogicalChildren.OfType<Control>())
{

20
src/Avalonia.Controls/DropDown.cs

@ -120,21 +120,21 @@ namespace Avalonia.Controls
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (!IsDropDownOpen && ((IVisual)e.Source).GetVisualRoot() is PopupRoot)
{
IsDropDownOpen = true;
e.Handled = true;
}
if (!e.Handled)
{
if (UpdateSelectionFromEventSource(e.Source))
if (((IVisual)e.Source).GetVisualRoot() is PopupRoot)
{
_popup?.Close();
e.Handled = true;
if (UpdateSelectionFromEventSource(e.Source))
{
_popup?.Close();
e.Handled = true;
}
}
else
{
IsDropDownOpen = !IsDropDownOpen;
}
}
base.OnPointerPressed(e);
}

22
src/Avalonia.Input/MouseDevice.cs

@ -20,6 +20,8 @@ namespace Avalonia.Input
private int _clickCount;
private Rect _lastClickRect;
private uint _lastClickTime;
private IInputElement _captured;
private IDisposable _capturedSubscription;
/// <summary>
/// Gets the control that is currently capturing by the mouse, if any.
@ -31,8 +33,23 @@ namespace Avalonia.Input
/// </remarks>
public IInputElement Captured
{
get;
protected set;
get => _captured;
protected set
{
_capturedSubscription?.Dispose();
_capturedSubscription = null;
if (value != null)
{
_capturedSubscription = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => value.DetachedFromVisualTree += x,
x => value.DetachedFromVisualTree -= x)
.Take(1)
.Subscribe(_ => Captured = null);
}
_captured = value;
}
}
/// <summary>
@ -55,6 +72,7 @@ namespace Avalonia.Input
/// </remarks>
public virtual void Capture(IInputElement control)
{
// TODO: Check visibility and enabled state before setting capture.
Captured = control;
}

2
src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs

@ -173,7 +173,7 @@ namespace Avalonia.Rendering.SceneGraph
}
}
if (node.HitTest(p))
if (node.HitTest(p) && node.Visual.IsAttachedToVisualTree)
{
yield return node.Visual;
}

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

@ -168,11 +168,14 @@ namespace Avalonia.Rendering.SceneGraph
using (context.PushTransformContainer())
{
var startLayer = opacity < 1 || visual.OpacityMask != null;
var clipBounds = bounds.TransformToAABB(contextImpl.Transform).Intersect(clip);
forceRecurse = forceRecurse || node.Transform != contextImpl.Transform;
forceRecurse = forceRecurse ||
node.Transform != contextImpl.Transform ||
node.ClipBounds != clipBounds;
node.Transform = contextImpl.Transform;
node.ClipBounds = bounds.TransformToAABB(node.Transform).Intersect(clip);
node.ClipBounds = clipBounds;
node.ClipToBounds = clipToBounds;
node.GeometryClip = visual.Clip?.PlatformImpl;
node.Opacity = opacity;

4
src/Avalonia.Visuals/Visual.cs

@ -329,6 +329,7 @@ namespace Avalonia
}
OnAttachedToVisualTree(e);
AttachedToVisualTree?.Invoke(this, e);
InvalidateVisual();
if (VisualChildren != null)
@ -357,6 +358,7 @@ namespace Avalonia
}
OnDetachedFromVisualTree(e);
DetachedFromVisualTree?.Invoke(this, e);
e.Root?.Renderer?.AddDirty(this);
if (VisualChildren != null)
@ -374,7 +376,6 @@ namespace Avalonia
/// <param name="e">The event args.</param>
protected virtual void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
AttachedToVisualTree?.Invoke(this, e);
}
/// <summary>
@ -383,7 +384,6 @@ namespace Avalonia
/// <param name="e">The event args.</param>
protected virtual void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
DetachedFromVisualTree?.Invoke(this, e);
}
/// <summary>

41
tests/Avalonia.Controls.UnitTests/ControlTests.cs

@ -123,7 +123,26 @@ namespace Avalonia.Controls.UnitTests
}
[Fact]
public void DetachedToLogicalParent_Should_Be_Called_When_Removed_From_Tree()
public void AttachedToLogicalParent_Should_Not_Be_Called_With_GlobalStyles_As_Root()
{
var globalStyles = Mock.Of<IGlobalStyles>();
var root = new TestRoot { StylingParent = globalStyles };
var child = new Border();
var raised = false;
child.AttachedToLogicalTree += (s, e) =>
{
Assert.Equal(root, e.Root);
raised = true;
};
root.Child = child;
Assert.True(raised);
}
[Fact]
public void DetachedFromLogicalParent_Should_Be_Called_When_Removed_From_Tree()
{
var root = new TestRoot();
var parent = new Border();
@ -148,6 +167,26 @@ namespace Avalonia.Controls.UnitTests
Assert.True(grandchildRaised);
}
[Fact]
public void DetachedFromLogicalParent_Should_Not_Be_Called_With_GlobalStyles_As_Root()
{
var globalStyles = Mock.Of<IGlobalStyles>();
var root = new TestRoot { StylingParent = globalStyles };
var child = new Border();
var raised = false;
child.DetachedFromLogicalTree += (s, e) =>
{
Assert.Equal(root, e.Root);
raised = true;
};
root.Child = child;
root.Child = null;
Assert.True(raised);
}
[Fact]
public void Adding_Tree_To_IStyleRoot_Should_Style_Controls()
{

26
tests/Avalonia.Controls.UnitTests/DropDownTests.cs

@ -1,21 +1,43 @@
// 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.Linq;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
namespace Avalonia.Controls.UnitTests
{
public class DropDownTests
{
[Fact]
public void Clicking_On_Control_Toggles_IsDropDownOpen()
{
var target = new DropDown
{
Items = new[] { "Foo", "Bar" },
};
target.RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
});
Assert.True(target.IsDropDownOpen);
target.RaiseEvent(new PointerPressedEventArgs
{
RoutedEvent = InputElement.PointerPressedEvent,
});
Assert.False(target.IsDropDownOpen);
}
[Fact]
public void SelectionBoxItem_Is_Rectangle_With_VisualBrush_When_Selection_Is_Control()
{

4
tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Standalone.cs

@ -12,6 +12,7 @@ using Moq;
using System;
using System.Linq;
using Xunit;
using Avalonia.Rendering;
namespace Avalonia.Controls.UnitTests.Presenters
{
@ -56,6 +57,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
var parentMock = new Mock<Control>();
parentMock.As<IContentPresenterHost>();
parentMock.As<IRenderRoot>();
parentMock.As<IStyleRoot>();
(target as ISetLogicalParent).SetParent(parentMock.Object);
@ -100,6 +102,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
};
var parentMock = new Mock<Control>();
parentMock.As<IRenderRoot>();
parentMock.As<IStyleRoot>();
parentMock.As<ILogical>().SetupGet(l => l.IsAttachedToLogicalTree).Returns(true);
@ -144,6 +147,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
var parentMock = new Mock<Control>();
parentMock.As<IContentPresenterHost>();
parentMock.As<IRenderRoot>();
parentMock.As<IStyleRoot>();
(target as ISetLogicalParent).SetParent(parentMock.Object);

19
tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs

@ -1,6 +1,5 @@
using Avalonia.Controls;
using Avalonia.Input.Raw;
using Avalonia.Layout;
using Avalonia.Rendering;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
@ -12,6 +11,24 @@ namespace Avalonia.Input.UnitTests
{
public class MouseDeviceTests
{
[Fact]
public void Capture_Is_Cleared_When_Control_Removed()
{
Canvas control;
var root = new TestRoot
{
Child = control = new Canvas(),
};
var target = new MouseDevice();
target.Capture(control);
Assert.Same(control, target.Captured);
root.Child = null;
Assert.Null(target.Captured);
}
[Fact]
public void MouseMove_Should_Update_PointerOver()
{

54
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs

@ -143,13 +143,61 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var borderNode = scene.FindNode(border);
Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds);
}
}
[Fact]
public void Should_Update_Descendent_ClipBounds_When_Margin_Changed()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
Border border;
Canvas canvas;
var tree = new TestRoot
{
Width = 200,
Height = 300,
Child = canvas = new Canvas
{
ClipToBounds = true,
Width = 100,
Height = 100,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Children =
{
(border = new Border
{
Background = Brushes.AliceBlue,
Width = 100,
Height = 100,
[Canvas.LeftProperty] = 50,
[Canvas.TopProperty] = 50,
})
}
}
};
tree.Measure(Size.Infinity);
tree.Arrange(new Rect(tree.DesiredSize));
// Initial ClipBounds are correct, make sure they're still correct after updating border.
var scene = new Scene(tree);
var sceneBuilder = new SceneBuilder();
sceneBuilder.UpdateAll(scene);
var borderNode = scene.FindNode(border);
Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds);
canvas.Width = canvas.Height = 125;
canvas.Measure(Size.Infinity);
canvas.Arrange(new Rect(tree.DesiredSize));
// Initial ClipBounds are correct, make sure they're still correct after updating canvas.
scene = scene.Clone();
Assert.True(sceneBuilder.Update(scene, border));
Assert.True(sceneBuilder.Update(scene, canvas));
borderNode = scene.FindNode(border);
Assert.Equal(new Rect(50, 50, 50, 50), borderNode.ClipBounds);
Assert.Equal(new Rect(50, 50, 75, 75), borderNode.ClipBounds);
}
}

Loading…
Cancel
Save