Browse Source

Merge branch 'stable/0.9' of https://github.com/AvaloniaUI/Avalonia into stable/0.9

release/0.9.5
Dan Walmsley 6 years ago
parent
commit
3e039f5229
  1. 7
      native/Avalonia.Native/src/OSX/platformthreading.mm
  2. 9
      src/Avalonia.Base/Utilities/TypeUtilities.cs
  3. 9
      src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
  4. 5
      src/Avalonia.Controls/ItemsControl.cs
  5. 26
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  6. 4
      src/Avalonia.Controls/Window.cs
  7. 1
      src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs
  8. 12
      src/Avalonia.Layout/LayoutManager.cs
  9. 11
      src/Avalonia.Native/WindowImplBase.cs
  10. 17
      src/Avalonia.X11/X11Window.cs
  11. 2
      src/Windows/Avalonia.Win32/WindowImpl.cs
  12. 12
      tests/Avalonia.Base.UnitTests/Data/DefaultValueConverterTests.cs
  13. 22
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  14. 51
      tests/Avalonia.Controls.UnitTests/WindowTests.cs
  15. 33
      tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs

7
native/Avalonia.Native/src/OSX/platformthreading.mm

@ -157,11 +157,14 @@ NSArray<NSString*>* _modes;
-(void) perform
{
ComPtr<IAvnSignaledCallback> cb;
@synchronized (self) {
_signaled = false;
if(_parent != NULL && _parent->SignaledCallback != NULL)
_parent->SignaledCallback->Signaled(0, false);
if(_parent != NULL)
cb = _parent->SignaledCallback;
}
if(cb != nullptr)
cb->Signaled(0, false);
}
-(void) setParent:(PlatformThreadingInterface *)parent

9
src/Avalonia.Base/Utilities/TypeUtilities.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
@ -188,6 +189,14 @@ namespace Avalonia.Utilities
}
}
var typeConverter = TypeDescriptor.GetConverter(to);
if (typeConverter.CanConvertFrom(from) == true)
{
result = typeConverter.ConvertFrom(null, culture, value);
return true;
}
var cast = FindTypeConversionOperatorMethod(from, to, OperatorType.Implicit | OperatorType.Explicit);
if (cast != null)

9
src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs

@ -183,11 +183,16 @@ namespace Avalonia.Utilities
for (int c = 0; c < _count; c++)
{
var r = _data[c];
TSubscriber target = null;
r.Subscriber?.TryGetTarget(out target);
//Mark current index as first empty
if (r.Subscriber == null && empty == -1)
if (target == null && empty == -1)
empty = c;
//If current element isn't null and we have an empty one
if (r.Subscriber != null && empty != -1)
if (target != null && empty != -1)
{
_data[c] = default;
_data[empty] = r;

5
src/Avalonia.Controls/ItemsControl.cs

@ -504,7 +504,10 @@ namespace Avalonia.Controls
result = container.GetControl(direction, c, wrap);
from = from ?? result;
if (result?.Focusable == true)
if (result != null &&
result.Focusable &&
result.IsEffectivelyEnabled &&
result.IsEffectivelyVisible)
{
return result;
}

26
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -6,8 +6,6 @@ using Avalonia.LogicalTree;
using Avalonia.Rendering;
using Avalonia.Threading;
#nullable enable
namespace Avalonia.Controls.Platform
{
/// <summary>
@ -16,8 +14,8 @@ namespace Avalonia.Controls.Platform
public class DefaultMenuInteractionHandler : IMenuInteractionHandler
{
private readonly bool _isContextMenu;
private IDisposable? _inputManagerSubscription;
private IRenderRoot? _root;
private IDisposable _inputManagerSubscription;
private IRenderRoot _root;
public DefaultMenuInteractionHandler(bool isContextMenu)
: this(isContextMenu, Input.InputManager.Instance, DefaultDelayRun)
@ -26,7 +24,7 @@ namespace Avalonia.Controls.Platform
public DefaultMenuInteractionHandler(
bool isContextMenu,
IInputManager? inputManager,
IInputManager inputManager,
Action<Action, TimeSpan> delayRun)
{
delayRun = delayRun ?? throw new ArgumentNullException(nameof(delayRun));
@ -96,7 +94,7 @@ namespace Avalonia.Controls.Platform
root.Deactivated -= WindowDeactivated;
}
_inputManagerSubscription!.Dispose();
_inputManagerSubscription.Dispose();
Menu = null;
_root = null;
@ -104,9 +102,9 @@ namespace Avalonia.Controls.Platform
protected Action<Action, TimeSpan> DelayRun { get; }
protected IInputManager? InputManager { get; }
protected IInputManager InputManager { get; }
protected IMenu? Menu { get; private set; }
protected IMenu Menu { get; private set; }
protected static TimeSpan MenuShowDelay { get; } = TimeSpan.FromMilliseconds(400);
@ -135,7 +133,7 @@ namespace Avalonia.Controls.Platform
KeyDown(GetMenuItem(e.Source as IControl), e);
}
protected internal virtual void KeyDown(IMenuItem? item, KeyEventArgs e)
protected internal virtual void KeyDown(IMenuItem item, KeyEventArgs e)
{
switch (e.Key)
{
@ -204,7 +202,7 @@ namespace Avalonia.Controls.Platform
}
else
{
Menu!.Close();
Menu.Close();
}
e.Handled = true;
@ -217,7 +215,7 @@ namespace Avalonia.Controls.Platform
{
if (item == null && _isContextMenu)
{
if (Menu!.MoveSelection(direction.Value, true) == true)
if (Menu.MoveSelection(direction.Value, true) == true)
{
e.Handled = true;
}
@ -412,7 +410,7 @@ namespace Avalonia.Controls.Platform
protected void CloseMenu(IMenuItem item)
{
var current = (IMenuElement?)item;
var current = (IMenuElement)item;
while (current != null && !(current is IMenu))
{
@ -460,7 +458,7 @@ namespace Avalonia.Controls.Platform
protected void SelectItemAndAncestors(IMenuItem item)
{
var current = (IMenuItem?)item;
var current = item;
while (current?.Parent != null)
{
@ -469,7 +467,7 @@ namespace Avalonia.Controls.Platform
}
}
protected static IMenuItem? GetMenuItem(IControl? item)
protected static IMenuItem GetMenuItem(IControl item)
{
while (true)
{

4
src/Avalonia.Controls/Window.cs

@ -129,7 +129,7 @@ namespace Avalonia.Controls
ShowInTaskbarProperty.Changed.AddClassHandler<Window>((w, e) => w.PlatformImpl?.ShowTaskbarIcon((bool)e.NewValue));
IconProperty.Changed.AddClassHandler<Window>((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
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));
@ -529,7 +529,7 @@ namespace Avalonia.Controls
{
var sizeToContent = SizeToContent;
var clientSize = ClientSize;
Size constraint = clientSize;
var constraint = availableSize;
if ((sizeToContent & SizeToContent.Width) != 0)
{

1
src/Avalonia.Input/GestureRecognizers/ScrollGestureRecognizer.cs

@ -148,6 +148,7 @@ namespace Avalonia.Input.GestureRecognizers
EndGesture();
else
{
_tracking = null;
var savedGestureId = _gestureId;
var st = Stopwatch.StartNew();
var lastTime = TimeSpan.Zero;

12
src/Avalonia.Layout/LayoutManager.cs

@ -126,8 +126,16 @@ namespace Avalonia.Layout
/// <inheritdoc/>
public void ExecuteInitialLayoutPass(ILayoutRoot root)
{
Measure(root);
Arrange(root);
try
{
_running = true;
Measure(root);
Arrange(root);
}
finally
{
_running = false;
}
// Running the initial layout pass may have caused some control to be invalidated
// so run a full layout pass now (this usually due to scrollbars; its not known

11
src/Avalonia.Native/WindowImplBase.cs

@ -162,9 +162,12 @@ namespace Avalonia.Native
void IAvnWindowBaseEvents.Resized(AvnSize size)
{
var s = new Size(size.Width, size.Height);
_parent._savedLogicalSize = s;
_parent.Resized?.Invoke(s);
if (_parent._native != null)
{
var s = new Size(size.Width, size.Height);
_parent._savedLogicalSize = s;
_parent.Resized?.Invoke(s);
}
}
void IAvnWindowBaseEvents.PositionChanged(AvnPoint position)
@ -317,7 +320,7 @@ namespace Avalonia.Native
_native.SetTopMost(value);
}
public double Scaling => _native.GetScaling();
public double Scaling => _native?.GetScaling() ?? 1;
public Action Deactivated { get; set; }
public Action Activated { get; set; }

17
src/Avalonia.X11/X11Window.cs

@ -977,11 +977,18 @@ namespace Avalonia.X11
public void SetIcon(IWindowIconImpl icon)
{
var data = ((X11IconData)icon).Data;
fixed (void* pdata = data)
XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON,
new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace,
pdata, data.Length);
if (icon != null)
{
var data = ((X11IconData)icon).Data;
fixed (void* pdata = data)
XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON,
new IntPtr((int)Atom.XA_CARDINAL), 32, PropertyMode.Replace,
pdata, data.Length);
}
else
{
XDeleteProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_ICON);
}
}
public void ShowTaskbarIcon(bool value)

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

@ -926,7 +926,7 @@ namespace Avalonia.Win32
public void SetIcon(IWindowIconImpl icon)
{
var impl = (IconImpl)icon;
var hIcon = impl.HIcon;
var hIcon = impl?.HIcon ?? IntPtr.Zero;
UnmanagedMethods.PostMessage(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_SETICON,
new IntPtr((int)UnmanagedMethods.Icons.ICON_BIG), hIcon);
}

12
tests/Avalonia.Base.UnitTests/Data/DefaultValueConverterTests.cs

@ -50,6 +50,18 @@ namespace Avalonia.Base.UnitTests.Data.Converters
Assert.Equal(TestEnum.Bar, result);
}
[Fact]
public void Can_Convert_String_To_TimeSpan()
{
var result = DefaultValueConverter.Instance.Convert(
"00:00:10",
typeof(TimeSpan),
null,
CultureInfo.InvariantCulture);
Assert.Equal(TimeSpan.FromSeconds(10), result);
}
[Fact]
public void Can_Convert_Int_To_Enum()
{

22
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@ -1202,6 +1202,28 @@ namespace Avalonia.Controls.UnitTests.Primitives
target.MoveSelection(NavigationDirection.Next, true);
}
[Fact]
public void MoveSelection_Does_Select_Disabled_Controls()
{
// Issue #3426.
var target = new TestSelector
{
Template = Template(),
Items = new[]
{
new ListBoxItem(),
new ListBoxItem { IsEnabled = false },
},
SelectedIndex = 0,
};
target.Measure(new Size(100, 100));
target.Arrange(new Rect(0, 0, 100, 100));
target.MoveSelection(NavigationDirection.Next, true);
Assert.Equal(0, target.SelectedIndex);
}
[Fact]
public void Pre_Selecting_Item_Should_Set_Selection_After_It_Was_Added_When_AlwaysSelected()
{

51
tests/Avalonia.Controls.UnitTests/WindowTests.cs

@ -341,11 +341,62 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void Child_Should_Be_Measured_With_Width_And_Height_If_SizeToContent_Is_Manual()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var child = new ChildControl();
var target = new Window
{
Width = 100,
Height = 50,
SizeToContent = SizeToContent.Manual,
Content = child
};
target.Show();
Assert.Equal(new Size(100, 50), child.MeasureSize);
}
}
[Fact]
public void Child_Should_Be_Measured_With_Infinity_If_SizeToContent_Is_WidthAndHeight()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var child = new ChildControl();
var target = new Window
{
Width = 100,
Height = 50,
SizeToContent = SizeToContent.WidthAndHeight,
Content = child
};
target.Show();
Assert.Equal(Size.Infinity, child.MeasureSize);
}
}
private IWindowImpl CreateImpl(Mock<IRenderer> renderer)
{
return Mock.Of<IWindowImpl>(x =>
x.Scaling == 1 &&
x.CreateRenderer(It.IsAny<IRenderRoot>()) == renderer.Object);
}
private class ChildControl : Control
{
public Size MeasureSize { get; private set; }
protected override Size MeasureOverride(Size availableSize)
{
MeasureSize = availableSize;
return base.MeasureOverride(availableSize);
}
}
}
}

33
tests/Avalonia.Layout.UnitTests/LayoutManagerTests.cs

@ -374,5 +374,38 @@ namespace Avalonia.Layout.UnitTests
Assert.True(control.Measured);
Assert.True(control.IsMeasureValid);
}
[Fact]
public void Calling_ExecuteLayoutPass_From_ExecuteInitialLayoutPass_Does_Not_Break_Measure()
{
// Test for issue #3550.
var control = new LayoutTestControl();
var root = new LayoutTestRoot { Child = control };
var count = 0;
root.LayoutManager.ExecuteInitialLayoutPass(root);
control.Measured = false;
control.DoMeasureOverride = (l, s) =>
{
if (count++ == 0)
{
control.InvalidateMeasure();
root.LayoutManager.ExecuteLayoutPass();
return new Size(100, 100);
}
else
{
return new Size(200, 200);
}
};
root.InvalidateMeasure();
control.InvalidateMeasure();
root.LayoutManager.ExecuteInitialLayoutPass(root);
Assert.Equal(new Size(200, 200), control.Bounds.Size);
Assert.Equal(new Size(200, 200), control.DesiredSize);
}
}
}

Loading…
Cancel
Save