Browse Source

Merge branch 'master' into refactor/ilogicalroot

pull/3346/head
Steven Kirk 6 years ago
committed by GitHub
parent
commit
7773c0dc8f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      src/Avalonia.Base/Collections/AvaloniaList.cs
  2. 30
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  3. 2
      src/Avalonia.Input/Gestures.cs
  4. 13
      src/Avalonia.Themes.Default/ItemsControl.xaml
  5. 12
      tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs
  6. 4
      tests/Avalonia.Input.UnitTests/GesturesTests.cs

20
src/Avalonia.Base/Collections/AvaloniaList.cs

@ -327,6 +327,8 @@ namespace Avalonia.Collections
}
else
{
EnsureCapacity(_inner.Count + list.Count);
using (IEnumerator<T> en = items.GetEnumerator())
{
int insertIndex = index;
@ -550,6 +552,24 @@ namespace Avalonia.Collections
/// <inheritdoc/>
Delegate[] INotifyCollectionChangedDebug.GetCollectionChangedSubscribers() => _collectionChanged?.GetInvocationList();
private void EnsureCapacity(int capacity)
{
// Adapted from List<T> implementation.
var currentCapacity = _inner.Capacity;
if (currentCapacity < capacity)
{
var newCapacity = currentCapacity == 0 ? 4 : currentCapacity * 2;
if (newCapacity < capacity)
{
newCapacity = capacity;
}
_inner.Capacity = newCapacity;
}
}
/// <summary>
/// Raises the <see cref="CollectionChanged"/> event with an add action.
/// </summary>

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

@ -6,6 +6,8 @@ using Avalonia.LogicalTree;
using Avalonia.Rendering;
using Avalonia.Threading;
#nullable enable
namespace Avalonia.Controls.Platform
{
/// <summary>
@ -14,8 +16,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)
@ -24,9 +26,11 @@ namespace Avalonia.Controls.Platform
public DefaultMenuInteractionHandler(
bool isContextMenu,
IInputManager inputManager,
IInputManager? inputManager,
Action<Action, TimeSpan> delayRun)
{
delayRun = delayRun ?? throw new ArgumentNullException(nameof(delayRun));
_isContextMenu = isContextMenu;
InputManager = inputManager;
DelayRun = delayRun;
@ -92,7 +96,7 @@ namespace Avalonia.Controls.Platform
root.Deactivated -= WindowDeactivated;
}
_inputManagerSubscription.Dispose();
_inputManagerSubscription!.Dispose();
Menu = null;
_root = null;
@ -100,9 +104,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);
@ -131,7 +135,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)
{
@ -200,7 +204,7 @@ namespace Avalonia.Controls.Platform
}
else
{
Menu.Close();
Menu!.Close();
}
e.Handled = true;
@ -213,12 +217,12 @@ 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;
}
}
else if (item.Parent?.MoveSelection(direction.Value, true) == true)
else if (item?.Parent?.MoveSelection(direction.Value, true) == true)
{
// If the the parent is an IMenu which successfully moved its selection,
// and the current menu is open then close the current menu and open the
@ -408,7 +412,7 @@ namespace Avalonia.Controls.Platform
protected void CloseMenu(IMenuItem item)
{
var current = (IMenuElement)item;
var current = (IMenuElement?)item;
while (current != null && !(current is IMenu))
{
@ -456,7 +460,7 @@ namespace Avalonia.Controls.Platform
protected void SelectItemAndAncestors(IMenuItem item)
{
var current = item;
var current = (IMenuItem?)item;
while (current?.Parent != null)
{
@ -465,7 +469,7 @@ namespace Avalonia.Controls.Platform
}
}
protected static IMenuItem GetMenuItem(IControl item)
protected static IMenuItem? GetMenuItem(IControl? item)
{
while (true)
{

2
src/Avalonia.Input/Gestures.cs

@ -79,7 +79,7 @@ namespace Avalonia.Input
{
s_lastPress = new WeakReference<IInteractive>(e.Source);
}
else if (s_lastPress != null && e.ClickCount == 2 && e.MouseButton != MouseButton.Right)
else if (s_lastPress != null && e.ClickCount == 2 && e.MouseButton == MouseButton.Left)
{
if (s_lastPress.TryGetTarget(out var target) && target == e.Source)
{

13
src/Avalonia.Themes.Default/ItemsControl.xaml

@ -1,10 +1,15 @@
<Style xmlns="https://github.com/avaloniaui" Selector="ItemsControl">
<Setter Property="Template">
<ControlTemplate>
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"/>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"/>
</Border>
</ControlTemplate>
</Setter>
</Style>

12
tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

@ -199,6 +199,18 @@ namespace Avalonia.Controls.UnitTests.Platform
menu.VerifySet(x => x.SelectedItem = null, Times.Never);
Assert.False(e.Handled);
}
[Fact]
public void Doesnt_Throw_On_Menu_Keypress()
{
// Issue #3459
var target = new DefaultMenuInteractionHandler(false);
var menu = Mock.Of<IMenu>();
var item = Mock.Of<IMenuItem>(x => x.IsTopLevel == true && x.Parent == menu);
var e = new KeyEventArgs { Key = Key.Tab, Source = menu };
target.KeyDown(menu, e);
}
}
public class NonTopLevel

4
tests/Avalonia.Input.UnitTests/GesturesTests.cs

@ -135,7 +135,7 @@ namespace Avalonia.Interactivity.UnitTests
}
[Fact]
public void DoubleTapped_Should_Be_Raised_For_Middle_Button()
public void DoubleTapped_Should_Not_Be_Raised_For_Middle_Button()
{
Border border = new Border();
var decorator = new Decorator
@ -149,7 +149,7 @@ namespace Avalonia.Interactivity.UnitTests
_mouse.Click(border, MouseButton.Middle);
_mouse.Down(border, MouseButton.Middle, clickCount: 2);
Assert.True(raised);
Assert.False(raised);
}
[Fact]

Loading…
Cancel
Save