Browse Source

Merge pull request #11564 from AvaloniaUI/platform-settings

Return PlatformSettings API after being previously hidden
pull/11585/head
Max Katz 3 years ago
committed by GitHub
parent
commit
1183ef69d7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      src/Avalonia.Base/Input/Gestures.cs
  2. 11
      src/Avalonia.Base/Input/IInputRoot.cs
  3. 17
      src/Avalonia.Base/Input/MouseDevice.cs
  4. 27
      src/Avalonia.Base/Input/PenDevice.cs
  5. 10
      src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs
  6. 29
      src/Avalonia.Base/Input/TouchDevice.cs
  7. 9
      src/Avalonia.Base/Platform/DefaultPlatformSettings.cs
  8. 12
      src/Avalonia.Base/Platform/IPlatformSettings.cs
  9. 24
      src/Avalonia.Base/Utilities/ThrowHelper.cs
  10. 19
      src/Avalonia.Base/VisualTree/VisualExtensions.cs
  11. 30
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  12. 2
      src/Avalonia.Controls.DataGrid/DataGridColumn.cs
  13. 2
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  14. 16
      src/Avalonia.Controls.DataGrid/Utils/KeyboardHelper.cs
  15. 23
      src/Avalonia.Controls/Application.cs
  16. 2
      src/Avalonia.Controls/ContextMenu.cs
  17. 2
      src/Avalonia.Controls/Control.cs
  18. 3
      src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs
  19. 5
      src/Avalonia.Controls/ListBox.cs
  20. 2
      src/Avalonia.Controls/ListBoxItem.cs
  21. 3
      src/Avalonia.Controls/MaskedTextBox.cs
  22. 2
      src/Avalonia.Controls/SelectableTextBlock.cs
  23. 11
      src/Avalonia.Controls/TextBox.cs
  24. 5
      src/Avalonia.Controls/TopLevel.cs
  25. 5
      src/Avalonia.Controls/TreeView.cs
  26. 18
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  27. 34
      src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs
  28. 82
      tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs
  29. 76
      tests/Avalonia.Controls.UnitTests/ButtonTests.cs
  30. 24
      tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs
  31. 14
      tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs
  32. 8
      tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs
  33. 6
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  34. 1
      tests/Avalonia.UnitTests/TestRoot.cs
  35. 3
      tests/Avalonia.UnitTests/UnitTestApplication.cs

10
src/Avalonia.Base/Input/Gestures.cs

@ -182,7 +182,7 @@ namespace Avalonia.Input
s_lastPressPoint = e.GetPosition((Visual)ev.Source); s_lastPressPoint = e.GetPosition((Visual)ev.Source);
s_holdCancellationToken = new CancellationTokenSource(); s_holdCancellationToken = new CancellationTokenSource();
var token = s_holdCancellationToken.Token; var token = s_holdCancellationToken.Token;
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>(); var settings = ((IInputRoot?)visual.GetVisualRoot())?.PlatformSettings;
if (settings != null) if (settings != null)
{ {
@ -221,7 +221,7 @@ namespace Avalonia.Input
e.Source is Interactive i) e.Source is Interactive i)
{ {
var point = e.GetCurrentPoint((Visual)target); var point = e.GetCurrentPoint((Visual)target);
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>(); var settings = ((IInputRoot?)i.GetVisualRoot())?.PlatformSettings;
var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4); var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
var tapRect = new Rect(s_lastPressPoint, new Size()) var tapRect = new Rect(s_lastPressPoint, new Size())
.Inflate(new Thickness(tapSize.Width, tapSize.Height)); .Inflate(new Thickness(tapSize.Width, tapSize.Height));
@ -260,10 +260,10 @@ namespace Avalonia.Input
var e = (PointerEventArgs)ev; var e = (PointerEventArgs)ev;
if (s_lastPress.TryGetTarget(out var target)) if (s_lastPress.TryGetTarget(out var target))
{ {
if (e.Pointer == s_lastPointer) if (e.Pointer == s_lastPointer && ev.Source is Interactive i)
{ {
var point = e.GetCurrentPoint((Visual)target); var point = e.GetCurrentPoint((Visual)target);
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>(); var settings = ((IInputRoot?)i.GetVisualRoot())?.PlatformSettings;
var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4); var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
var tapRect = new Rect(s_lastPressPoint, new Size()) var tapRect = new Rect(s_lastPressPoint, new Size())
.Inflate(new Thickness(tapSize.Width, tapSize.Height)); .Inflate(new Thickness(tapSize.Width, tapSize.Height));
@ -273,7 +273,7 @@ namespace Avalonia.Input
return; return;
} }
if (s_isHolding && ev.Source is Interactive i) if (s_isHolding)
{ {
i.RaiseEvent(new HoldingRoutedEventArgs(HoldingState.Cancelled, s_lastPressPoint, s_lastPointer!.Type)); i.RaiseEvent(new HoldingRoutedEventArgs(HoldingState.Cancelled, s_lastPressPoint, s_lastPointer!.Type));
} }

11
src/Avalonia.Base/Input/IInputRoot.cs

@ -1,4 +1,5 @@
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Platform;
namespace Avalonia.Input namespace Avalonia.Input
{ {
@ -17,10 +18,18 @@ namespace Avalonia.Input
/// Gets focus manager of the root. /// Gets focus manager of the root.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// Focus manager can be null only if application wasn't initialized yet. /// Focus manager can be null only if window wasn't initialized yet.
/// </remarks> /// </remarks>
IFocusManager? FocusManager { get; } IFocusManager? FocusManager { get; }
/// <summary>
/// Represents a contract for accessing top-level platform-specific settings.
/// </summary>
/// <remarks>
/// PlatformSettings can be null only if window wasn't initialized yet.
/// </remarks>
IPlatformSettings? PlatformSettings { get; }
/// <summary> /// <summary>
/// Gets or sets the input element that the pointer is currently over. /// Gets or sets the input element that the pointer is currently over.
/// </summary> /// </summary>

17
src/Avalonia.Base/Input/MouseDevice.cs

@ -2,9 +2,12 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Reactive; using Avalonia.Reactive;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.VisualTree;
#pragma warning disable CS0618 #pragma warning disable CS0618
namespace Avalonia.Input namespace Avalonia.Input
@ -126,9 +129,10 @@ namespace Avalonia.Input
if (source != null) if (source != null)
{ {
_pointer.Capture(source); _pointer.Capture(source);
if (source != null)
var settings = ((IInputRoot?)(source as Interactive)?.GetVisualRoot())?.PlatformSettings;
if (settings is not null)
{ {
var settings = AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>();
var doubleClickTime = settings.GetDoubleTapTime(PointerType.Mouse).TotalMilliseconds; var doubleClickTime = settings.GetDoubleTapTime(PointerType.Mouse).TotalMilliseconds;
var doubleClickSize = settings.GetDoubleTapSize(PointerType.Mouse); var doubleClickSize = settings.GetDoubleTapSize(PointerType.Mouse);
@ -141,11 +145,12 @@ namespace Avalonia.Input
_lastClickTime = timestamp; _lastClickTime = timestamp;
_lastClickRect = new Rect(p, new Size()) _lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2)); .Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
_lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
var e = new PointerPressedEventArgs(source, _pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
source.RaiseEvent(e);
return e.Handled;
} }
_lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
var e = new PointerPressedEventArgs(source, _pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
source.RaiseEvent(e);
return e.Handled;
} }
return false; return false;

27
src/Avalonia.Base/Input/PenDevice.cs

@ -3,8 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
#pragma warning disable CS0618 #pragma warning disable CS0618
namespace Avalonia.Input namespace Avalonia.Input
@ -80,19 +83,23 @@ namespace Avalonia.Input
if (source != null) if (source != null)
{ {
pointer.Capture(source); pointer.Capture(source);
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>(); var settings = ((IInputRoot?)(source as Interactive)?.GetVisualRoot())?.PlatformSettings;
var doubleClickTime = settings?.GetDoubleTapTime(PointerType.Pen).TotalMilliseconds ?? 500; if (settings is not null)
var doubleClickSize = settings?.GetDoubleTapSize(PointerType.Pen) ?? new Size(4, 4);
if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime)
{ {
_clickCount = 0; var doubleClickTime = settings.GetDoubleTapTime(PointerType.Pen).TotalMilliseconds;
var doubleClickSize = settings.GetDoubleTapSize(PointerType.Pen);
if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime)
{
_clickCount = 0;
}
++_clickCount;
_lastClickTime = timestamp;
_lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
} }
++_clickCount;
_lastClickTime = timestamp;
_lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
_lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton(); _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
var e = new PointerPressedEventArgs(source, pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount); var e = new PointerPressedEventArgs(source, pointer, (Visual)root, p, timestamp, properties, inputModifiers, _clickCount);
source.RaiseEvent(e); source.RaiseEvent(e);

10
src/Avalonia.Base/Input/Platform/PlatformHotkeyConfiguration.cs

@ -1,16 +1,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using Avalonia.Metadata;
#nullable enable
namespace Avalonia.Input.Platform namespace Avalonia.Input.Platform
{ {
public class PlatformHotkeyConfiguration /// <summary>
/// The PlatformHotkeyConfiguration class represents a configuration for platform-specific hotkeys in an Avalonia application.
/// </summary>
public sealed class PlatformHotkeyConfiguration
{ {
[PrivateApi]
public PlatformHotkeyConfiguration() : this(KeyModifiers.Control) public PlatformHotkeyConfiguration() : this(KeyModifiers.Control)
{ {
} }
[PrivateApi]
public PlatformHotkeyConfiguration(KeyModifiers commandModifiers, public PlatformHotkeyConfiguration(KeyModifiers commandModifiers,
KeyModifiers selectionModifiers = KeyModifiers.Shift, KeyModifiers selectionModifiers = KeyModifiers.Shift,
KeyModifiers wholeWordTextActionModifiers = KeyModifiers.Control) KeyModifiers wholeWordTextActionModifiers = KeyModifiers.Control)

29
src/Avalonia.Base/Input/TouchDevice.cs

@ -3,8 +3,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
#pragma warning disable CS0618 #pragma warning disable CS0618
namespace Avalonia.Input namespace Avalonia.Input
@ -62,19 +65,23 @@ namespace Avalonia.Input
} }
else else
{ {
var settings = AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>(); var settings = ((IInputRoot?)(target as Interactive)?.GetVisualRoot())?.PlatformSettings;
var doubleClickTime = settings.GetDoubleTapTime(PointerType.Touch).TotalMilliseconds; if (settings is not null)
var doubleClickSize = settings.GetDoubleTapSize(PointerType.Touch);
if (!_lastClickRect.Contains(args.Position)
|| ev.Timestamp - _lastClickTime > doubleClickTime)
{ {
_clickCount = 0; var doubleClickTime = settings.GetDoubleTapTime(PointerType.Touch).TotalMilliseconds;
var doubleClickSize = settings.GetDoubleTapSize(PointerType.Touch);
if (!_lastClickRect.Contains(args.Position)
|| ev.Timestamp - _lastClickTime > doubleClickTime)
{
_clickCount = 0;
}
++_clickCount;
_lastClickTime = ev.Timestamp;
_lastClickRect = new Rect(args.Position, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
} }
++_clickCount;
_lastClickTime = ev.Timestamp;
_lastClickRect = new Rect(args.Position, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
} }
target.RaiseEvent(new PointerPressedEventArgs(target, pointer, target.RaiseEvent(new PointerPressedEventArgs(target, pointer,

9
src/Avalonia.Base/Platform/DefaultPlatformSettings.cs

@ -1,12 +1,16 @@
using System; using System;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.VisualTree;
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
/// <summary> /// <summary>
/// A default implementation of <see cref="IPlatformSettings"/> for platforms. /// A default implementation of <see cref="IPlatformSettings"/> for platforms.
/// </summary> /// </summary>
[PrivateApi]
public class DefaultPlatformSettings : IPlatformSettings public class DefaultPlatformSettings : IPlatformSettings
{ {
public virtual Size GetTapSize(PointerType type) public virtual Size GetTapSize(PointerType type)
@ -28,7 +32,10 @@ namespace Avalonia.Platform
public virtual TimeSpan GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(500); public virtual TimeSpan GetDoubleTapTime(PointerType type) => TimeSpan.FromMilliseconds(500);
public virtual TimeSpan HoldWaitDuration => TimeSpan.FromMilliseconds(300); public virtual TimeSpan HoldWaitDuration => TimeSpan.FromMilliseconds(300);
public PlatformHotkeyConfiguration HotkeyConfiguration =>
AvaloniaLocator.Current.GetRequiredService<PlatformHotkeyConfiguration>();
public virtual PlatformColorValues GetColorValues() public virtual PlatformColorValues GetColorValues()
{ {
return new PlatformColorValues return new PlatformColorValues

12
src/Avalonia.Base/Platform/IPlatformSettings.cs

@ -1,10 +1,15 @@
using System; using System;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Metadata; using Avalonia.Metadata;
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
[Unstable] /// <summary>
/// The <see cref="IPlatformSettings"/> interface represents a contract for accessing platform-specific settings and information.
/// Some of these settings might be changed by used globally in the OS in runtime.
/// </summary>
[NotClientImplementable]
public interface IPlatformSettings public interface IPlatformSettings
{ {
/// <summary> /// <summary>
@ -33,6 +38,11 @@ namespace Avalonia.Platform
/// </summary> /// </summary>
TimeSpan HoldWaitDuration { get; } TimeSpan HoldWaitDuration { get; }
/// <summary>
/// Get a configuration for platform-specific hotkeys in an Avalonia application.
/// </summary>
PlatformHotkeyConfiguration HotkeyConfiguration { get; }
/// <summary> /// <summary>
/// Gets current system color values including dark mode and accent colors. /// Gets current system color values including dark mode and accent colors.
/// </summary> /// </summary>

24
src/Avalonia.Base/Utilities/ThrowHelper.cs

@ -0,0 +1,24 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
namespace Avalonia.Utilities;
/// <summary>
/// Helper method to help inlining methods that do a throw check.
/// Equivalent of .NET6+ ArgumentNullException.ThrowIfNull() for netstandard2.0+
/// </summary>
internal class ThrowHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ThrowIfNull([NotNull] object? argument, string paramName)
{
if (argument is null)
{
ThrowArgumentNullException(paramName);
}
}
[DoesNotReturn]
private static void ThrowArgumentNullException(string paramName) => throw new ArgumentNullException(paramName);
}

19
src/Avalonia.Base/VisualTree/VisualExtensions.cs

@ -1,7 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Utilities;
namespace Avalonia.VisualTree namespace Avalonia.VisualTree
{ {
@ -125,9 +128,9 @@ namespace Avalonia.VisualTree
/// <returns>The visual's ancestors.</returns> /// <returns>The visual's ancestors.</returns>
public static IEnumerable<Visual> GetVisualAncestors(this Visual visual) public static IEnumerable<Visual> GetVisualAncestors(this Visual visual)
{ {
Visual? v = visual ?? throw new ArgumentNullException(nameof(visual)); ThrowHelper.ThrowIfNull(visual, nameof(visual));
v = v.VisualParent; var v = visual.VisualParent;
while (v != null) while (v != null)
{ {
@ -194,7 +197,7 @@ namespace Avalonia.VisualTree
/// <returns>The visual and its ancestors.</returns> /// <returns>The visual and its ancestors.</returns>
public static IEnumerable<Visual> GetSelfAndVisualAncestors(this Visual visual) public static IEnumerable<Visual> GetSelfAndVisualAncestors(this Visual visual)
{ {
_ = visual ?? throw new ArgumentNullException(nameof(visual)); ThrowHelper.ThrowIfNull(visual, nameof(visual));
yield return visual; yield return visual;
@ -275,7 +278,7 @@ namespace Avalonia.VisualTree
/// <returns>The visual at the requested point.</returns> /// <returns>The visual at the requested point.</returns>
public static Visual? GetVisualAt(this Visual visual, Point p) public static Visual? GetVisualAt(this Visual visual, Point p)
{ {
_ = visual ?? throw new ArgumentNullException(nameof(visual)); ThrowHelper.ThrowIfNull(visual, nameof(visual));
return visual.GetVisualAt(p, x => x.IsVisible); return visual.GetVisualAt(p, x => x.IsVisible);
} }
@ -292,7 +295,7 @@ namespace Avalonia.VisualTree
/// <returns>The visual at the requested point.</returns> /// <returns>The visual at the requested point.</returns>
public static Visual? GetVisualAt(this Visual visual, Point p, Func<Visual, bool> filter) public static Visual? GetVisualAt(this Visual visual, Point p, Func<Visual, bool> filter)
{ {
_ = visual ?? throw new ArgumentNullException(nameof(visual)); ThrowHelper.ThrowIfNull(visual, nameof(visual));
var root = visual.GetVisualRoot(); var root = visual.GetVisualRoot();
@ -321,7 +324,7 @@ namespace Avalonia.VisualTree
this Visual visual, this Visual visual,
Point p) Point p)
{ {
_ = visual ?? throw new ArgumentNullException(nameof(visual)); ThrowHelper.ThrowIfNull(visual, nameof(visual));
return visual.GetVisualsAt(p, x => x.IsVisible); return visual.GetVisualsAt(p, x => x.IsVisible);
} }
@ -341,7 +344,7 @@ namespace Avalonia.VisualTree
Point p, Point p,
Func<Visual, bool> filter) Func<Visual, bool> filter)
{ {
_ = visual ?? throw new ArgumentNullException(nameof(visual)); ThrowHelper.ThrowIfNull(visual, nameof(visual));
var root = visual.GetVisualRoot(); var root = visual.GetVisualRoot();
@ -435,7 +438,7 @@ namespace Avalonia.VisualTree
/// </returns> /// </returns>
public static IRenderRoot? GetVisualRoot(this Visual visual) public static IRenderRoot? GetVisualRoot(this Visual visual)
{ {
_ = visual ?? throw new ArgumentNullException(nameof(visual)); ThrowHelper.ThrowIfNull(visual, nameof(visual));
return visual as IRenderRoot ?? visual.VisualRoot; return visual as IRenderRoot ?? visual.VisualRoot;
} }

30
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -2660,25 +2660,25 @@ namespace Avalonia.Controls
internal bool ProcessDownKey(KeyEventArgs e) internal bool ProcessDownKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessDownKeyInternal(shift, ctrl); return ProcessDownKeyInternal(shift, ctrl);
} }
internal bool ProcessEndKey(KeyEventArgs e) internal bool ProcessEndKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessEndKey(shift, ctrl); return ProcessEndKey(shift, ctrl);
} }
internal bool ProcessEnterKey(KeyEventArgs e) internal bool ProcessEnterKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessEnterKey(shift, ctrl); return ProcessEnterKey(shift, ctrl);
} }
internal bool ProcessHomeKey(KeyEventArgs e) internal bool ProcessHomeKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessHomeKey(shift, ctrl); return ProcessHomeKey(shift, ctrl);
} }
@ -2718,25 +2718,25 @@ namespace Avalonia.Controls
internal bool ProcessLeftKey(KeyEventArgs e) internal bool ProcessLeftKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessLeftKey(shift, ctrl); return ProcessLeftKey(shift, ctrl);
} }
internal bool ProcessNextKey(KeyEventArgs e) internal bool ProcessNextKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessNextKey(shift, ctrl); return ProcessNextKey(shift, ctrl);
} }
internal bool ProcessPriorKey(KeyEventArgs e) internal bool ProcessPriorKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessPriorKey(shift, ctrl); return ProcessPriorKey(shift, ctrl);
} }
internal bool ProcessRightKey(KeyEventArgs e) internal bool ProcessRightKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessRightKey(shift, ctrl); return ProcessRightKey(shift, ctrl);
} }
@ -2854,7 +2854,7 @@ namespace Avalonia.Controls
internal bool ProcessUpKey(KeyEventArgs e) internal bool ProcessUpKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessUpKey(shift, ctrl); return ProcessUpKey(shift, ctrl);
} }
@ -3124,13 +3124,13 @@ namespace Avalonia.Controls
//TODO: Ensure right button is checked for //TODO: Ensure right button is checked for
internal bool UpdateStateOnMouseRightButtonDown(PointerPressedEventArgs pointerPressedEventArgs, int columnIndex, int slot, bool allowEdit) internal bool UpdateStateOnMouseRightButtonDown(PointerPressedEventArgs pointerPressedEventArgs, int columnIndex, int slot, bool allowEdit)
{ {
KeyboardHelper.GetMetaKeyState(pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift);
return UpdateStateOnMouseRightButtonDown(pointerPressedEventArgs, columnIndex, slot, allowEdit, shift, ctrl); return UpdateStateOnMouseRightButtonDown(pointerPressedEventArgs, columnIndex, slot, allowEdit, shift, ctrl);
} }
//TODO: Ensure left button is checked for //TODO: Ensure left button is checked for
internal bool UpdateStateOnMouseLeftButtonDown(PointerPressedEventArgs pointerPressedEventArgs, int columnIndex, int slot, bool allowEdit) internal bool UpdateStateOnMouseLeftButtonDown(PointerPressedEventArgs pointerPressedEventArgs, int columnIndex, int slot, bool allowEdit)
{ {
KeyboardHelper.GetMetaKeyState(pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, pointerPressedEventArgs.KeyModifiers, out bool ctrl, out bool shift);
return UpdateStateOnMouseLeftButtonDown(pointerPressedEventArgs, columnIndex, slot, allowEdit, shift, ctrl); return UpdateStateOnMouseLeftButtonDown(pointerPressedEventArgs, columnIndex, slot, allowEdit, shift, ctrl);
} }
@ -4654,7 +4654,7 @@ namespace Avalonia.Controls
private bool ProcessAKey(KeyEventArgs e) private bool ProcessAKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift, out bool alt); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift, out bool alt);
if (ctrl && !shift && !alt && SelectionMode == DataGridSelectionMode.Extended) if (ctrl && !shift && !alt && SelectionMode == DataGridSelectionMode.Extended)
{ {
@ -4923,7 +4923,7 @@ namespace Avalonia.Controls
private bool ProcessF2Key(KeyEventArgs e) private bool ProcessF2Key(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
if (!shift && !ctrl && if (!shift && !ctrl &&
_editingColumnIndex == -1 && CurrentColumnIndex != -1 && GetRowSelection(CurrentSlot) && _editingColumnIndex == -1 && CurrentColumnIndex != -1 && GetRowSelection(CurrentSlot) &&
@ -5280,7 +5280,7 @@ namespace Avalonia.Controls
private bool ProcessTabKey(KeyEventArgs e) private bool ProcessTabKey(KeyEventArgs e)
{ {
KeyboardHelper.GetMetaKeyState(e.KeyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, e.KeyModifiers, out bool ctrl, out bool shift);
return ProcessTabKey(e, shift, ctrl); return ProcessTabKey(e, shift, ctrl);
} }
@ -6099,7 +6099,7 @@ namespace Avalonia.Controls
/// <returns>Whether or not the DataGrid handled the key press.</returns> /// <returns>Whether or not the DataGrid handled the key press.</returns>
private bool ProcessCopyKey(KeyModifiers modifiers) private bool ProcessCopyKey(KeyModifiers modifiers)
{ {
KeyboardHelper.GetMetaKeyState(modifiers, out bool ctrl, out bool shift, out bool alt); KeyboardHelper.GetMetaKeyState(this, modifiers, out bool ctrl, out bool shift, out bool alt);
if (ctrl && !shift && !alt && ClipboardCopyMode != DataGridClipboardCopyMode.None && SelectedItems.Count > 0) if (ctrl && !shift && !alt && ClipboardCopyMode != DataGridClipboardCopyMode.None && SelectedItems.Count > 0)
{ {

2
src/Avalonia.Controls.DataGrid/DataGridColumn.cs

@ -703,7 +703,7 @@ namespace Avalonia.Controls
public void ClearSort() public void ClearSort()
{ {
//InvokeProcessSort is already validating if sorting is possible //InvokeProcessSort is already validating if sorting is possible
_headerCell?.InvokeProcessSort(KeyboardHelper.GetPlatformCtrlOrCmdKeyModifier()); _headerCell?.InvokeProcessSort(KeyboardHelper.GetPlatformCtrlOrCmdKeyModifier(OwningGrid));
} }
/// <summary> /// <summary>

2
src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs

@ -241,7 +241,7 @@ namespace Avalonia.Controls
DataGrid owningGrid = OwningGrid; DataGrid owningGrid = OwningGrid;
DataGridSortDescription newSort; DataGridSortDescription newSort;
KeyboardHelper.GetMetaKeyState(keyModifiers, out bool ctrl, out bool shift); KeyboardHelper.GetMetaKeyState(this, keyModifiers, out bool ctrl, out bool shift);
DataGridSortDescription sort = OwningColumn.GetSortDescription(); DataGridSortDescription sort = OwningColumn.GetSortDescription();
IDataGridCollectionView collectionView = owningGrid.DataConnection.CollectionView; IDataGridCollectionView collectionView = owningGrid.DataConnection.CollectionView;

16
src/Avalonia.Controls.DataGrid/Utils/KeyboardHelper.cs

@ -10,23 +10,23 @@ namespace Avalonia.Controls.Utils
{ {
internal static class KeyboardHelper internal static class KeyboardHelper
{ {
public static void GetMetaKeyState(KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift) public static void GetMetaKeyState(Control target, KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift)
{ {
ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier()); ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier(target));
shift = modifiers.HasFlag(KeyModifiers.Shift); shift = modifiers.HasFlag(KeyModifiers.Shift);
} }
public static void GetMetaKeyState(KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift, out bool alt) public static void GetMetaKeyState(Control target, KeyModifiers modifiers, out bool ctrlOrCmd, out bool shift, out bool alt)
{ {
ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier()); ctrlOrCmd = modifiers.HasFlag(GetPlatformCtrlOrCmdKeyModifier(target));
shift = modifiers.HasFlag(KeyModifiers.Shift); shift = modifiers.HasFlag(KeyModifiers.Shift);
alt = modifiers.HasFlag(KeyModifiers.Alt); alt = modifiers.HasFlag(KeyModifiers.Alt);
} }
public static KeyModifiers GetPlatformCtrlOrCmdKeyModifier() public static KeyModifiers GetPlatformCtrlOrCmdKeyModifier(Control target)
{ {
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var keymap = TopLevel.GetTopLevel(target)!.PlatformSettings!.HotkeyConfiguration;
return keymap?.CommandModifiers ?? KeyModifiers.Control; return keymap.CommandModifiers;
} }
} }
} }

23
src/Avalonia.Controls/Application.cs

@ -180,6 +180,17 @@ namespace Avalonia
/// </summary> /// </summary>
public IApplicationLifetime? ApplicationLifetime { get; set; } public IApplicationLifetime? ApplicationLifetime { get; set; }
/// <summary>
/// Represents a contract for accessing global platform-specific settings.
/// </summary>
/// <remarks>
/// PlatformSettings can be null only if application wasn't initialized yet.
/// <see cref="TopLevel"/>'s <see cref="TopLevel.PlatformSettings"/> is an equivalent API
/// which should always be preferred over a global one,
/// as specific top levels might have different settings set-up.
/// </remarks>
public IPlatformSettings? PlatformSettings => AvaloniaLocator.Current.GetService<IPlatformSettings>();
event Action<IReadOnlyList<IStyle>>? IGlobalStyles.GlobalStylesAdded event Action<IReadOnlyList<IStyle>>? IGlobalStyles.GlobalStylesAdded
{ {
add => _stylesAdded += value; add => _stylesAdded += value;
@ -229,10 +240,12 @@ namespace Avalonia
var focusManager = new FocusManager(); var focusManager = new FocusManager();
InputManager = new InputManager(); InputManager = new InputManager();
var settings = AvaloniaLocator.Current.GetRequiredService<IPlatformSettings>(); if (PlatformSettings is { } settings)
settings.ColorValuesChanged += OnColorValuesChanged; {
OnColorValuesChanged(settings, settings.GetColorValues()); settings.ColorValuesChanged += OnColorValuesChanged;
OnColorValuesChanged(settings, settings.GetColorValues());
}
AvaloniaLocator.CurrentMutable AvaloniaLocator.CurrentMutable
.Bind<IAccessKeyHandler>().ToTransient<AccessKeyHandler>() .Bind<IAccessKeyHandler>().ToTransient<AccessKeyHandler>()
.Bind<IGlobalDataTemplates>().ToConstant(this) .Bind<IGlobalDataTemplates>().ToConstant(this)
@ -242,7 +255,7 @@ namespace Avalonia
.Bind<IInputManager>().ToConstant(InputManager) .Bind<IInputManager>().ToConstant(InputManager)
.Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>() .Bind<IKeyboardNavigationHandler>().ToTransient<KeyboardNavigationHandler>()
.Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance); .Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance);
// TODO: Fix this, for now we keep this behavior since someone might be relying on it in 0.9.x // TODO: Fix this, for now we keep this behavior since someone might be relying on it in 0.9.x
if (AvaloniaLocator.Current.GetService<IPlatformDragSource>() == null) if (AvaloniaLocator.Current.GetService<IPlatformDragSource>() == null)
AvaloniaLocator.CurrentMutable AvaloniaLocator.CurrentMutable

2
src/Avalonia.Controls/ContextMenu.cs

@ -405,7 +405,7 @@ namespace Avalonia.Controls
{ {
if (IsOpen) if (IsOpen)
{ {
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
if (keymap?.OpenContextMenu.Any(k => k.Matches(e)) == true if (keymap?.OpenContextMenu.Any(k => k.Matches(e)) == true
&& !CancelClosing()) && !CancelClosing())

2
src/Avalonia.Controls/Control.cs

@ -480,7 +480,7 @@ namespace Avalonia.Controls
if (e.Source == this if (e.Source == this
&& !e.Handled) && !e.Handled)
{ {
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>()?.OpenContextMenu; var keymap = Application.Current!.PlatformSettings?.HotkeyConfiguration.OpenContextMenu;
if (keymap is null) if (keymap is null)
{ {

3
src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs

@ -9,6 +9,7 @@ using Avalonia.Input.Raw;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Reactive; using Avalonia.Reactive;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
@ -392,7 +393,7 @@ namespace Avalonia.Controls.Primitives
&& IsOpen && IsOpen
&& Target?.ContextFlyout == this) && Target?.ContextFlyout == this)
{ {
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings?.HotkeyConfiguration;
if (keymap?.OpenContextMenu.Any(k => k.Matches(e)) == true) if (keymap?.OpenContextMenu.Any(k => k.Matches(e)) == true)
{ {

5
src/Avalonia.Controls/ListBox.cs

@ -9,6 +9,7 @@ using Avalonia.Controls.Selection;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -127,7 +128,7 @@ namespace Avalonia.Controls
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
var hotkeys = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration;
var ctrl = hotkeys is not null && e.KeyModifiers.HasAllFlags(hotkeys.CommandModifiers); var ctrl = hotkeys is not null && e.KeyModifiers.HasAllFlags(hotkeys.CommandModifiers);
if (!ctrl && if (!ctrl &&
@ -165,7 +166,7 @@ namespace Avalonia.Controls
internal bool UpdateSelectionFromPointerEvent(Control source, PointerEventArgs e) internal bool UpdateSelectionFromPointerEvent(Control source, PointerEventArgs e)
{ {
var hotkeys = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration;
var toggle = hotkeys is not null && e.KeyModifiers.HasAllFlags(hotkeys.CommandModifiers); var toggle = hotkeys is not null && e.KeyModifiers.HasAllFlags(hotkeys.CommandModifiers);
return UpdateSelectionFromEventSource( return UpdateSelectionFromEventSource(

2
src/Avalonia.Controls/ListBoxItem.cs

@ -90,7 +90,7 @@ namespace Avalonia.Controls
e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right) e.InitialPressMouseButton is MouseButton.Left or MouseButton.Right)
{ {
var point = e.GetCurrentPoint(this); var point = e.GetCurrentPoint(this);
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>(); var settings = TopLevel.GetTopLevel(e.Source as Visual)?.PlatformSettings;
var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4); var tapSize = settings?.GetTapSize(point.Pointer.Type) ?? new Size(4, 4);
var tapRect = new Rect(_pointerDownPoint, new Size()) var tapRect = new Rect(_pointerDownPoint, new Size())
.Inflate(new Thickness(tapSize.Width, tapSize.Height)); .Inflate(new Thickness(tapSize.Width, tapSize.Height));

3
src/Avalonia.Controls/MaskedTextBox.cs

@ -7,6 +7,7 @@ using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.VisualTree;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -204,7 +205,7 @@ namespace Avalonia.Controls
return; return;
} }
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings?.HotkeyConfiguration;
bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e)); bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e));

2
src/Avalonia.Controls/SelectableTextBlock.cs

@ -198,7 +198,7 @@ namespace Avalonia.Controls
var handled = false; var handled = false;
var modifiers = e.KeyModifiers; var modifiers = e.KeyModifiers;
var keymap = AvaloniaLocator.Current.GetRequiredService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e)); bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e));

11
src/Avalonia.Controls/TextBox.cs

@ -32,20 +32,17 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets a platform-specific <see cref="KeyGesture"/> for the Cut action /// Gets a platform-specific <see cref="KeyGesture"/> for the Cut action
/// </summary> /// </summary>
public static KeyGesture? CutGesture { get; } = AvaloniaLocator.Current public static KeyGesture? CutGesture => Application.Current?.PlatformSettings?.HotkeyConfiguration.Cut.FirstOrDefault();
.GetService<PlatformHotkeyConfiguration>()?.Cut.FirstOrDefault();
/// <summary> /// <summary>
/// Gets a platform-specific <see cref="KeyGesture"/> for the Copy action /// Gets a platform-specific <see cref="KeyGesture"/> for the Copy action
/// </summary> /// </summary>
public static KeyGesture? CopyGesture { get; } = AvaloniaLocator.Current public static KeyGesture? CopyGesture => Application.Current?.PlatformSettings?.HotkeyConfiguration.Copy.FirstOrDefault();
.GetService<PlatformHotkeyConfiguration>()?.Copy.FirstOrDefault();
/// <summary> /// <summary>
/// Gets a platform-specific <see cref="KeyGesture"/> for the Paste action /// Gets a platform-specific <see cref="KeyGesture"/> for the Paste action
/// </summary> /// </summary>
public static KeyGesture? PasteGesture { get; } = AvaloniaLocator.Current public static KeyGesture? PasteGesture => Application.Current?.PlatformSettings?.HotkeyConfiguration.Paste.FirstOrDefault();
.GetService<PlatformHotkeyConfiguration>()?.Paste.FirstOrDefault();
/// <summary> /// <summary>
/// Defines the <see cref="AcceptsReturn"/> property /// Defines the <see cref="AcceptsReturn"/> property
@ -1103,7 +1100,7 @@ namespace Avalonia.Controls
var handled = false; var handled = false;
var modifiers = e.KeyModifiers; var modifiers = e.KeyModifiers;
var keymap = AvaloniaLocator.Current.GetRequiredService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e)); bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e));
bool DetectSelection() => e.KeyModifiers.HasAllFlags(keymap.SelectionModifiers); bool DetectSelection() => e.KeyModifiers.HasAllFlags(keymap.SelectionModifiers);

5
src/Avalonia.Controls/TopLevel.cs

@ -250,7 +250,7 @@ namespace Avalonia.Controls
if (e is RawKeyEventArgs rawKeyEventArgs && rawKeyEventArgs.Type == RawKeyEventType.KeyDown) if (e is RawKeyEventArgs rawKeyEventArgs && rawKeyEventArgs.Type == RawKeyEventType.KeyDown)
{ {
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>()?.Back; var keymap = PlatformSettings?.HotkeyConfiguration.Back;
if (keymap != null) if (keymap != null)
{ {
@ -487,6 +487,9 @@ namespace Avalonia.Controls
/// <inheritdoc /> /// <inheritdoc />
public IFocusManager? FocusManager => AvaloniaLocator.Current.GetService<IFocusManager>(); public IFocusManager? FocusManager => AvaloniaLocator.Current.GetService<IFocusManager>();
/// <inheritdoc />
public IPlatformSettings? PlatformSettings => AvaloniaLocator.Current.GetService<IPlatformSettings>();
/// <inheritdoc/> /// <inheritdoc/>
Point IRenderRoot.PointToClient(PixelPoint p) Point IRenderRoot.PointToClient(PixelPoint p)
{ {

5
src/Avalonia.Controls/TreeView.cs

@ -571,7 +571,7 @@ namespace Avalonia.Controls
if (!e.Handled) if (!e.Handled)
{ {
var keymap = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
bool Match(List<KeyGesture>? gestures) => gestures?.Any(g => g.Matches(e)) ?? false; bool Match(List<KeyGesture>? gestures) => gestures?.Any(g => g.Matches(e)) ?? false;
if (this.SelectionMode == SelectionMode.Multiple && Match(keymap?.SelectAll)) if (this.SelectionMode == SelectionMode.Multiple && Match(keymap?.SelectAll))
@ -652,11 +652,12 @@ namespace Avalonia.Controls
if (point.Properties.IsLeftButtonPressed || point.Properties.IsRightButtonPressed) if (point.Properties.IsLeftButtonPressed || point.Properties.IsRightButtonPressed)
{ {
var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
e.Handled = UpdateSelectionFromEventSource( e.Handled = UpdateSelectionFromEventSource(
e.Source, e.Source,
true, true,
e.KeyModifiers.HasAllFlags(KeyModifiers.Shift), e.KeyModifiers.HasAllFlags(KeyModifiers.Shift),
e.KeyModifiers.HasAllFlags(AvaloniaLocator.Current.GetRequiredService<PlatformHotkeyConfiguration>().CommandModifiers), e.KeyModifiers.HasAllFlags(keymap.CommandModifiers),
point.Properties.IsRightButtonPressed); point.Properties.IsRightButtonPressed);
} }
} }

18
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -108,20 +108,18 @@ namespace Avalonia.Native
.Bind<IWindowingPlatform>().ToConstant(this) .Bind<IWindowingPlatform>().ToConstant(this)
.Bind<IClipboard>().ToConstant(new ClipboardImpl(_factory.CreateClipboard())) .Bind<IClipboard>().ToConstant(new ClipboardImpl(_factory.CreateClipboard()))
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60)) .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Meta, wholeWordTextActionModifiers: KeyModifiers.Alt))
.Bind<IMountedVolumeInfoProvider>().ToConstant(new MacOSMountedVolumeInfoProvider()) .Bind<IMountedVolumeInfoProvider>().ToConstant(new MacOSMountedVolumeInfoProvider())
.Bind<IPlatformDragSource>().ToConstant(new AvaloniaNativeDragSource(_factory)) .Bind<IPlatformDragSource>().ToConstant(new AvaloniaNativeDragSource(_factory))
.Bind<IPlatformLifetimeEventsImpl>().ToConstant(applicationPlatform) .Bind<IPlatformLifetimeEventsImpl>().ToConstant(applicationPlatform)
.Bind<INativeApplicationCommands>().ToConstant(new MacOSNativeMenuCommands(_factory.CreateApplicationCommands())); .Bind<INativeApplicationCommands>().ToConstant(new MacOSNativeMenuCommands(_factory.CreateApplicationCommands()));
var hotkeys = AvaloniaLocator.Current.GetService<PlatformHotkeyConfiguration>(); var hotkeys = new PlatformHotkeyConfiguration(KeyModifiers.Meta, wholeWordTextActionModifiers: KeyModifiers.Alt);
if (hotkeys is not null) hotkeys.MoveCursorToTheStartOfLine.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers));
{ hotkeys.MoveCursorToTheStartOfLineWithSelection.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers | hotkeys.SelectionModifiers));
hotkeys.MoveCursorToTheStartOfLine.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers)); hotkeys.MoveCursorToTheEndOfLine.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers));
hotkeys.MoveCursorToTheStartOfLineWithSelection.Add(new KeyGesture(Key.Left, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers | hotkeys.SelectionModifiers));
hotkeys.MoveCursorToTheEndOfLine.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers));
hotkeys.MoveCursorToTheEndOfLineWithSelection.Add(new KeyGesture(Key.Right, hotkeys.CommandModifiers | hotkeys.SelectionModifiers)); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(hotkeys);
}
if (_options.UseGpu) if (_options.UseGpu)
{ {

34
src/Avalonia.Themes.Fluent/Accents/SystemAccentColors.cs

@ -16,18 +16,12 @@ internal class SystemAccentColors : IResourceProvider
public const string AccentLight2Key = "SystemAccentColorLight2"; public const string AccentLight2Key = "SystemAccentColorLight2";
public const string AccentLight3Key = "SystemAccentColorLight3"; public const string AccentLight3Key = "SystemAccentColorLight3";
private static readonly Color s_defaultSystemAccentColor = Color.FromRgb(0, 120, 215); private static readonly Color s_defaultSystemAccentColor = Color.FromRgb(0, 120, 215);
private readonly IPlatformSettings? _platformSettings;
private bool _invalidateColors = true; private bool _invalidateColors = true;
private Color _systemAccentColor; private Color _systemAccentColor;
private Color _systemAccentColorDark1, _systemAccentColorDark2, _systemAccentColorDark3; private Color _systemAccentColorDark1, _systemAccentColorDark2, _systemAccentColorDark3;
private Color _systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3; private Color _systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3;
public SystemAccentColors()
{
_platformSettings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
}
public bool HasResources => true; public bool HasResources => true;
public bool TryGetResource(object key, ThemeVariant? theme, out object? value) public bool TryGetResource(object key, ThemeVariant? theme, out object? value)
{ {
@ -96,10 +90,12 @@ internal class SystemAccentColors : IResourceProvider
Owner = owner; Owner = owner;
OwnerChanged?.Invoke(this, EventArgs.Empty); OwnerChanged?.Invoke(this, EventArgs.Empty);
if (_platformSettings is not null) if (GetFromOwner(owner) is { } platformSettings)
{ {
_platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged; platformSettings.ColorValuesChanged += PlatformSettingsOnColorValuesChanged;
} }
_invalidateColors = true;
} }
} }
@ -110,10 +106,12 @@ internal class SystemAccentColors : IResourceProvider
Owner = null; Owner = null;
OwnerChanged?.Invoke(this, EventArgs.Empty); OwnerChanged?.Invoke(this, EventArgs.Empty);
if (_platformSettings is not null) if (GetFromOwner(owner) is { } platformSettings)
{ {
_platformSettings.ColorValuesChanged -= PlatformSettingsOnColorValuesChanged; platformSettings.ColorValuesChanged -= PlatformSettingsOnColorValuesChanged;
} }
_invalidateColors = true;
} }
} }
@ -122,13 +120,25 @@ internal class SystemAccentColors : IResourceProvider
if (_invalidateColors) if (_invalidateColors)
{ {
_invalidateColors = false; _invalidateColors = false;
var platformSettings = GetFromOwner(Owner);
_systemAccentColor = _platformSettings?.GetColorValues().AccentColor1 ?? s_defaultSystemAccentColor; _systemAccentColor = platformSettings?.GetColorValues().AccentColor1 ?? s_defaultSystemAccentColor;
(_systemAccentColorDark1,_systemAccentColorDark2, _systemAccentColorDark3, (_systemAccentColorDark1,_systemAccentColorDark2, _systemAccentColorDark3,
_systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3) = CalculateAccentShades(_systemAccentColor); _systemAccentColorLight1, _systemAccentColorLight2, _systemAccentColorLight3) = CalculateAccentShades(_systemAccentColor);
} }
} }
private static IPlatformSettings? GetFromOwner(IResourceHost? owner)
{
return owner switch
{
Application app => app.PlatformSettings,
Visual visual => TopLevel.GetTopLevel(visual)?.PlatformSettings,
_ => null
};
}
public static (Color d1, Color d2, Color d3, Color l1, Color l2, Color l3) CalculateAccentShades(Color accentColor) public static (Color d1, Color d2, Color d3, Color l1, Color l2, Color l3) CalculateAccentShades(Color accentColor)
{ {
// dark1step = (hslAccent.L - SystemAccentColorDark1.L) * 255 // dark1step = (hslAccent.L - SystemAccentColorDark1.L) * 255

82
tests/Avalonia.Base.UnitTests/Input/GesturesTests.cs

@ -24,13 +24,13 @@ namespace Avalonia.Base.UnitTests.Input
public void Tapped_Should_Follow_Pointer_Pressed_Released() public void Tapped_Should_Follow_Pointer_Pressed_Released()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var result = new List<string>(); var result = new List<string>();
AddHandlers(decorator, border, result, false); AddHandlers(root, border, result, false);
_mouse.Click(border); _mouse.Click(border);
@ -41,13 +41,13 @@ namespace Avalonia.Base.UnitTests.Input
public void Tapped_Should_Be_Raised_Even_When_Pressed_Released_Handled() public void Tapped_Should_Be_Raised_Even_When_Pressed_Released_Handled()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var result = new List<string>(); var result = new List<string>();
AddHandlers(decorator, border, result, true); AddHandlers(root, border, result, true);
_mouse.Click(border); _mouse.Click(border);
@ -58,13 +58,13 @@ namespace Avalonia.Base.UnitTests.Input
public void Tapped_Should_Not_Be_Raised_For_Middle_Button() public void Tapped_Should_Not_Be_Raised_For_Middle_Button()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.TappedEvent, (_, _) => raised = true); root.AddHandler(Gestures.TappedEvent, (_, _) => raised = true);
_mouse.Click(border, MouseButton.Middle); _mouse.Click(border, MouseButton.Middle);
@ -75,13 +75,13 @@ namespace Avalonia.Base.UnitTests.Input
public void Tapped_Should_Not_Be_Raised_For_Right_Button() public void Tapped_Should_Not_Be_Raised_For_Right_Button()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.TappedEvent, (_, _) => raised = true); root.AddHandler(Gestures.TappedEvent, (_, _) => raised = true);
_mouse.Click(border, MouseButton.Right); _mouse.Click(border, MouseButton.Right);
@ -92,13 +92,13 @@ namespace Avalonia.Base.UnitTests.Input
public void RightTapped_Should_Be_Raised_For_Right_Button() public void RightTapped_Should_Be_Raised_For_Right_Button()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.RightTappedEvent, (_, _) => raised = true); root.AddHandler(Gestures.RightTappedEvent, (_, _) => raised = true);
_mouse.Click(border, MouseButton.Right); _mouse.Click(border, MouseButton.Right);
@ -109,13 +109,13 @@ namespace Avalonia.Base.UnitTests.Input
public void DoubleTapped_Should_Follow_Pointer_Pressed_Released_Pressed() public void DoubleTapped_Should_Follow_Pointer_Pressed_Released_Pressed()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var result = new List<string>(); var result = new List<string>();
AddHandlers(decorator, border, result, false); AddHandlers(root, border, result, false);
_mouse.Click(border); _mouse.Click(border);
_mouse.Down(border, clickCount: 2); _mouse.Down(border, clickCount: 2);
@ -127,13 +127,13 @@ namespace Avalonia.Base.UnitTests.Input
public void DoubleTapped_Should_Be_Raised_Even_When_Pressed_Released_Handled() public void DoubleTapped_Should_Be_Raised_Even_When_Pressed_Released_Handled()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var result = new List<string>(); var result = new List<string>();
AddHandlers(decorator, border, result, true); AddHandlers(root, border, result, true);
_mouse.Click(border); _mouse.Click(border);
_mouse.Down(border, clickCount: 2); _mouse.Down(border, clickCount: 2);
@ -145,13 +145,13 @@ namespace Avalonia.Base.UnitTests.Input
public void DoubleTapped_Should_Not_Be_Raised_For_Middle_Button() public void DoubleTapped_Should_Not_Be_Raised_For_Middle_Button()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true); root.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true);
_mouse.Click(border, MouseButton.Middle); _mouse.Click(border, MouseButton.Middle);
_mouse.Down(border, MouseButton.Middle, clickCount: 2); _mouse.Down(border, MouseButton.Middle, clickCount: 2);
@ -163,13 +163,13 @@ namespace Avalonia.Base.UnitTests.Input
public void DoubleTapped_Should_Not_Be_Raised_For_Right_Button() public void DoubleTapped_Should_Not_Be_Raised_For_Right_Button()
{ {
Border border = new Border(); Border border = new Border();
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true); root.AddHandler(Gestures.DoubleTappedEvent, (_, _) => raised = true);
_mouse.Click(border, MouseButton.Right); _mouse.Click(border, MouseButton.Right);
_mouse.Down(border, MouseButton.Right, clickCount: 2); _mouse.Down(border, MouseButton.Right, clickCount: 2);
@ -191,13 +191,13 @@ namespace Avalonia.Base.UnitTests.Input
Border border = new Border(); Border border = new Border();
Gestures.SetIsHoldWithMouseEnabled(border, true); Gestures.SetIsHoldWithMouseEnabled(border, true);
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
HoldingState holding = HoldingState.Cancelled; HoldingState holding = HoldingState.Cancelled;
decorator.AddHandler(Gestures.HoldingEvent, (_, e) => holding = e.HoldingState); root.AddHandler(Gestures.HoldingEvent, (_, e) => holding = e.HoldingState);
_mouse.Down(border); _mouse.Down(border);
Assert.False(holding != HoldingState.Cancelled); Assert.False(holding != HoldingState.Cancelled);
@ -227,13 +227,13 @@ namespace Avalonia.Base.UnitTests.Input
Border border = new Border(); Border border = new Border();
Gestures.SetIsHoldWithMouseEnabled(border, true); Gestures.SetIsHoldWithMouseEnabled(border, true);
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Started); root.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Started);
_mouse.Down(border); _mouse.Down(border);
Assert.False(raised); Assert.False(raised);
@ -262,13 +262,13 @@ namespace Avalonia.Base.UnitTests.Input
Border border = new Border(); Border border = new Border();
Gestures.SetIsHoldWithMouseEnabled(border, true); Gestures.SetIsHoldWithMouseEnabled(border, true);
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed); root.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed);
_mouse.Down(border); _mouse.Down(border);
Assert.False(raised); Assert.False(raised);
@ -297,13 +297,13 @@ namespace Avalonia.Base.UnitTests.Input
Border border = new Border(); Border border = new Border();
Gestures.SetIsHoldWithMouseEnabled(border, true); Gestures.SetIsHoldWithMouseEnabled(border, true);
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var cancelled = false; var cancelled = false;
decorator.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled); root.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled);
_mouse.Down(border); _mouse.Down(border);
Assert.False(cancelled); Assert.False(cancelled);
@ -333,13 +333,13 @@ namespace Avalonia.Base.UnitTests.Input
Border border = new Border(); Border border = new Border();
Gestures.SetIsHoldWithMouseEnabled(border, true); Gestures.SetIsHoldWithMouseEnabled(border, true);
var decorator = new Decorator var root = new TestRoot()
{ {
Child = border Child = border
}; };
var cancelled = false; var cancelled = false;
decorator.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled); root.AddHandler(Gestures.HoldingEvent, (_, e) => cancelled = e.HoldingState == HoldingState.Cancelled);
_mouse.Down(border); _mouse.Down(border);
@ -369,13 +369,13 @@ namespace Avalonia.Base.UnitTests.Input
Border border = new Border(); Border border = new Border();
Gestures.SetIsHoldWithMouseEnabled(border, true); Gestures.SetIsHoldWithMouseEnabled(border, true);
var decorator = new Decorator var testRoot = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed); testRoot.AddHandler(Gestures.HoldingEvent, (_, e) => raised = e.HoldingState == HoldingState.Completed);
var secondMouse = new MouseTestHelper(); var secondMouse = new MouseTestHelper();
@ -392,12 +392,12 @@ namespace Avalonia.Base.UnitTests.Input
} }
private static void AddHandlers( private static void AddHandlers(
Decorator decorator, TestRoot root,
Border border, Border border,
IList<string> result, IList<string> result,
bool markHandled) bool markHandled)
{ {
decorator.AddHandler(InputElement.PointerPressedEvent, (_, e) => root.AddHandler(InputElement.PointerPressedEvent, (_, e) =>
{ {
result.Add("dp"); result.Add("dp");
@ -407,7 +407,7 @@ namespace Avalonia.Base.UnitTests.Input
} }
}); });
decorator.AddHandler(InputElement.PointerReleasedEvent, (_, e) => root.AddHandler(InputElement.PointerReleasedEvent, (_, e) =>
{ {
result.Add("dr"); result.Add("dr");
@ -420,8 +420,8 @@ namespace Avalonia.Base.UnitTests.Input
border.AddHandler(InputElement.PointerPressedEvent, (_, _) => result.Add("bp")); border.AddHandler(InputElement.PointerPressedEvent, (_, _) => result.Add("bp"));
border.AddHandler(InputElement.PointerReleasedEvent, (_, _) => result.Add("br")); border.AddHandler(InputElement.PointerReleasedEvent, (_, _) => result.Add("br"));
decorator.AddHandler(Gestures.TappedEvent, (_, _) => result.Add("dt")); root.AddHandler(Gestures.TappedEvent, (_, _) => result.Add("dt"));
decorator.AddHandler(Gestures.DoubleTappedEvent, (_, _) => result.Add("ddt")); root.AddHandler(Gestures.DoubleTappedEvent, (_, _) => result.Add("ddt"));
border.AddHandler(Gestures.TappedEvent, (_, _) => result.Add("bt")); border.AddHandler(Gestures.TappedEvent, (_, _) => result.Add("bt"));
border.AddHandler(Gestures.DoubleTappedEvent, (_, _) => result.Add("bdt")); border.AddHandler(Gestures.DoubleTappedEvent, (_, _) => result.Add("bdt"));
} }
@ -438,13 +438,13 @@ namespace Avalonia.Base.UnitTests.Input
Background = new SolidColorBrush(Colors.Red) Background = new SolidColorBrush(Colors.Red)
}; };
border.GestureRecognizers.Add(new PinchGestureRecognizer()); border.GestureRecognizers.Add(new PinchGestureRecognizer());
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.PinchEvent, (_, _) => raised = true); root.AddHandler(Gestures.PinchEvent, (_, _) => raised = true);
var firstPoint = new Point(5, 5); var firstPoint = new Point(5, 5);
var secondPoint = new Point(10, 10); var secondPoint = new Point(10, 10);
@ -466,13 +466,13 @@ namespace Avalonia.Base.UnitTests.Input
Background = new SolidColorBrush(Colors.Red) Background = new SolidColorBrush(Colors.Red)
}; };
border.GestureRecognizers.Add(new PinchGestureRecognizer()); border.GestureRecognizers.Add(new PinchGestureRecognizer());
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.PinchEvent, (_, _) => raised = true); root.AddHandler(Gestures.PinchEvent, (_, _) => raised = true);
var firstPoint = new Point(5, 5); var firstPoint = new Point(5, 5);
var secondPoint = new Point(10, 10); var secondPoint = new Point(10, 10);
@ -502,13 +502,13 @@ namespace Avalonia.Base.UnitTests.Input
CanVerticallyScroll = true, CanVerticallyScroll = true,
ScrollStartDistance = 50 ScrollStartDistance = 50
}); });
var decorator = new Decorator var root = new TestRoot
{ {
Child = border Child = border
}; };
var raised = false; var raised = false;
decorator.AddHandler(Gestures.ScrollGestureEvent, (_, _) => raised = true); root.AddHandler(Gestures.ScrollGestureEvent, (_, _) => raised = true);
var firstTouch = new TouchTestHelper(); var firstTouch = new TouchTestHelper();

76
tests/Avalonia.Controls.UnitTests/ButtonTests.cs

@ -3,9 +3,11 @@ using System.Windows.Input;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering; using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Moq; using Moq;
@ -14,7 +16,7 @@ using MouseButton = Avalonia.Input.MouseButton;
namespace Avalonia.Controls.UnitTests namespace Avalonia.Controls.UnitTests
{ {
public class ButtonTests public class ButtonTests : ScopedTestBase
{ {
private MouseTestHelper _helper = new MouseTestHelper(); private MouseTestHelper _helper = new MouseTestHelper();
@ -139,11 +141,19 @@ namespace Avalonia.Controls.UnitTests
renderer.Setup(r => r.HitTest(It.IsAny<Point>(), It.IsAny<Visual>(), It.IsAny<Func<Visual, bool>>())) renderer.Setup(r => r.HitTest(It.IsAny<Point>(), It.IsAny<Visual>(), It.IsAny<Func<Visual, bool>>()))
.Returns<Point, Visual, Func<Visual, bool>>((p, r, f) => .Returns<Point, Visual, Func<Visual, bool>>((p, r, f) =>
r.Bounds.Contains(p) ? new Visual[] { r } : new Visual[0]); r.Bounds.Contains(p) ? new Visual[] { r } : new Visual[0]);
var target = new TestButton(renderer.Object) using var _ = UnitTestApplication.Start(TestServices.StyledWindow);
var root = new Window() { HitTesterOverride = renderer.Object };
var target = new Button()
{ {
Bounds = new Rect(0, 0, 100, 100) Width = 100,
Height = 100,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left
}; };
root.Content = target;
root.Show();
bool clicked = false; bool clicked = false;
@ -165,16 +175,13 @@ namespace Avalonia.Controls.UnitTests
[Fact] [Fact]
public void Button_Does_Not_Raise_Click_When_PointerReleased_Outside() public void Button_Does_Not_Raise_Click_When_PointerReleased_Outside()
{ {
var renderer = new Mock<IHitTester>(); var root = new TestRoot();
var target = new Button()
renderer.Setup(r => r.HitTest(It.IsAny<Point>(), It.IsAny<Visual>(), It.IsAny<Func<Visual, bool>>()))
.Returns<Point, Visual, Func<Visual, bool>>((p, r, f) =>
r.Bounds.Contains(p) ? new Visual[] { r } : new Visual[0]);
var target = new TestButton(renderer.Object)
{ {
Bounds = new Rect(0, 0, 100, 100) Width = 100,
Height = 100
}; };
root.Child = target;
bool clicked = false; bool clicked = false;
@ -203,12 +210,20 @@ namespace Avalonia.Controls.UnitTests
.Returns<Point, Visual, Func<Visual, bool>>((p, r, f) => .Returns<Point, Visual, Func<Visual, bool>>((p, r, f) =>
r.Bounds.Contains(p.Transform(r.RenderTransform.Value.Invert())) ? r.Bounds.Contains(p.Transform(r.RenderTransform.Value.Invert())) ?
new Visual[] { r } : new Visual[0]); new Visual[] { r } : new Visual[0]);
var target = new TestButton(renderer.Object) using var _ = UnitTestApplication.Start(TestServices.StyledWindow);
var root = new Window() { HitTesterOverride = renderer.Object };
var target = new Button()
{ {
Bounds = new Rect(0, 0, 100, 100), Width = 100,
Height = 100,
VerticalAlignment = VerticalAlignment.Top,
HorizontalAlignment = HorizontalAlignment.Left,
RenderTransform = new TranslateTransform { X = 100, Y = 0 } RenderTransform = new TranslateTransform { X = 100, Y = 0 }
}; };
root.Content = target;
root.Show();
//actual bounds of button should be 100,0,100,100 x -> translated 100 pixels //actual bounds of button should be 100,0,100,100 x -> translated 100 pixels
//so mouse with x=150 coordinates should trigger click //so mouse with x=150 coordinates should trigger click
@ -381,37 +396,6 @@ namespace Avalonia.Controls.UnitTests
return new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key, Source = source }; return new KeyEventArgs { RoutedEvent = InputElement.KeyDownEvent, Key = key, Source = source };
} }
private class TestButton : Button, IRenderRoot
{
public TestButton(IHitTester hit)
{
IsVisible = true;
HitTester = hit;
Renderer = new NullRenderer();
}
public new Rect Bounds
{
get => base.Bounds;
set => base.Bounds = value;
}
public Size ClientSize => throw new NotImplementedException();
public IRenderer Renderer { get; }
public IHitTester HitTester { get; }
public double RenderScaling => throw new NotImplementedException();
public IRenderTarget CreateRenderTarget() => throw new NotImplementedException();
public void Invalidate(Rect rect) => throw new NotImplementedException();
public Point PointToClient(PixelPoint p) => throw new NotImplementedException();
public PixelPoint PointToScreen(Point p) => throw new NotImplementedException();
}
private void RaisePointerPressed(Button button, int clickCount, MouseButton mouseButton, Point position) private void RaisePointerPressed(Button button, int clickCount, MouseButton mouseButton, Point position)
{ {
_helper.Down(button, mouseButton, position, clickCount: clickCount); _helper.Down(button, mouseButton, position, clickCount: clickCount);

24
tests/Avalonia.Controls.UnitTests/ListBoxTests_Multiple.cs

@ -34,7 +34,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Shift); _helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Shift);
Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems); Assert.Equal(new[] { "Foo", "Bar", "Baz" }, target.SelectedItems);
@ -60,7 +60,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
SelectionChangedEventArgs receivedArgs = null; SelectionChangedEventArgs receivedArgs = null;
@ -118,7 +118,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[1]); _helper.Click(target.Presenter.Panel.Children[1]);
_helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); _helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control);
_helper.Click(target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control); _helper.Click(target.Presenter.Panel.Children[3], modifiers: KeyModifiers.Control);
@ -152,7 +152,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[1]); _helper.Click(target.Presenter.Panel.Children[1]);
_helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control); _helper.Click(target.Presenter.Panel.Children[2], modifiers: KeyModifiers.Control);
@ -183,7 +183,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[3]); _helper.Click(target.Presenter.Panel.Children[3]);
_helper.Click(target.Presenter.Panel.Children[4], modifiers: KeyModifiers.Control); _helper.Click(target.Presenter.Panel.Children[4], modifiers: KeyModifiers.Control);
@ -211,7 +211,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[3]); _helper.Click(target.Presenter.Panel.Children[3]);
_helper.Click(target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); _helper.Click(target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift);
@ -239,7 +239,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[0]);
_helper.Click(target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift); _helper.Click(target.Presenter.Panel.Children[5], modifiers: KeyModifiers.Shift);
@ -266,7 +266,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
SelectionChangedEventArgs receivedArgs = null; SelectionChangedEventArgs receivedArgs = null;
@ -319,7 +319,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[0]);
Assert.Equal(new[] { "Foo" }, target.SelectedItems); Assert.Equal(new[] { "Foo" }, target.SelectedItems);
@ -414,7 +414,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[0]);
_helper.Click(target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Shift); _helper.Click(target.Presenter.Panel.Children[1], modifiers: KeyModifiers.Shift);
@ -444,7 +444,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[0]);
_helper.Click(target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Shift); _helper.Click(target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Shift);
@ -471,7 +471,7 @@ namespace Avalonia.Controls.UnitTests
var root = new TestRoot(target); var root = new TestRoot(target);
root.LayoutManager.ExecuteInitialLayoutPass(); root.LayoutManager.ExecuteInitialLayoutPass();
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
_helper.Click(target.Presenter.Panel.Children[0]); _helper.Click(target.Presenter.Panel.Children[0]);
_helper.Click(target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Control); _helper.Click(target.Presenter.Panel.Children[2], MouseButton.Right, modifiers: KeyModifiers.Control);

14
tests/Avalonia.Controls.UnitTests/ListBoxTests_Single.cs

@ -49,7 +49,7 @@ namespace Avalonia.Controls.UnitTests
Template = new FuncControlTemplate(CreateListBoxTemplate), Template = new FuncControlTemplate(CreateListBoxTemplate),
ItemsSource = new[] { "Foo", "Bar", "Baz " }, ItemsSource = new[] { "Foo", "Bar", "Baz " },
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
ApplyTemplate(target); ApplyTemplate(target);
target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs
@ -79,7 +79,7 @@ namespace Avalonia.Controls.UnitTests
Template = new FuncControlTemplate(CreateListBoxTemplate), Template = new FuncControlTemplate(CreateListBoxTemplate),
ItemsSource = new[] { "Foo", "Bar", "Baz " }, ItemsSource = new[] { "Foo", "Bar", "Baz " },
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
ApplyTemplate(target); ApplyTemplate(target);
_mouse.Click(target.Presenter.Panel.Children[0]); _mouse.Click(target.Presenter.Panel.Children[0]);
@ -97,7 +97,7 @@ namespace Avalonia.Controls.UnitTests
Template = new FuncControlTemplate(CreateListBoxTemplate), Template = new FuncControlTemplate(CreateListBoxTemplate),
ItemsSource = new[] { "Foo", "Bar", "Baz " }, ItemsSource = new[] { "Foo", "Bar", "Baz " },
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
ApplyTemplate(target); ApplyTemplate(target);
target.SelectedIndex = 0; target.SelectedIndex = 0;
@ -118,7 +118,7 @@ namespace Avalonia.Controls.UnitTests
ItemsSource = new[] { "Foo", "Bar", "Baz " }, ItemsSource = new[] { "Foo", "Bar", "Baz " },
SelectionMode = SelectionMode.Single | SelectionMode.Toggle, SelectionMode = SelectionMode.Single | SelectionMode.Toggle,
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
ApplyTemplate(target); ApplyTemplate(target);
_mouse.Click(target.Presenter.Panel.Children[0]); _mouse.Click(target.Presenter.Panel.Children[0]);
@ -139,7 +139,7 @@ namespace Avalonia.Controls.UnitTests
SelectionMode = SelectionMode.Toggle, SelectionMode = SelectionMode.Toggle,
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
ApplyTemplate(target); ApplyTemplate(target);
target.SelectedIndex = 0; target.SelectedIndex = 0;
@ -160,7 +160,7 @@ namespace Avalonia.Controls.UnitTests
ItemsSource = new[] { "Foo", "Bar", "Baz " }, ItemsSource = new[] { "Foo", "Bar", "Baz " },
SelectionMode = SelectionMode.Toggle | SelectionMode.AlwaysSelected, SelectionMode = SelectionMode.Toggle | SelectionMode.AlwaysSelected,
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
ApplyTemplate(target); ApplyTemplate(target);
target.SelectedIndex = 0; target.SelectedIndex = 0;
@ -181,7 +181,7 @@ namespace Avalonia.Controls.UnitTests
ItemsSource = new[] { "Foo", "Bar", "Baz " }, ItemsSource = new[] { "Foo", "Bar", "Baz " },
SelectionMode = SelectionMode.Single | SelectionMode.Toggle, SelectionMode = SelectionMode.Single | SelectionMode.Toggle,
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
ApplyTemplate(target); ApplyTemplate(target);
target.SelectedIndex = 1; target.SelectedIndex = 1;

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

@ -1234,7 +1234,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Template = Template(), Template = Template(),
ItemsSource = new[] { "Foo", "Bar", "Baz " }, ItemsSource = new[] { "Foo", "Bar", "Baz " },
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
Prepare(target); Prepare(target);
var container = target.ContainerFromIndex(1)!; var container = target.ContainerFromIndex(1)!;
@ -1258,7 +1258,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Template = Template(), Template = Template(),
ItemsSource = items, ItemsSource = items,
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
Prepare(target); Prepare(target);
_helper.Down(target.Presenter.Panel.Children[1]); _helper.Down(target.Presenter.Panel.Children[1]);
@ -1355,7 +1355,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Template = Template(), Template = Template(),
ItemsSource = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, ItemsSource = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
Prepare(target); Prepare(target);
_helper.Down((Interactive)target.Presenter.Panel.Children[3]); _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
@ -1373,7 +1373,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
Template = Template(), Template = Template(),
ItemsSource = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" }, ItemsSource = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
}; };
AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new Mock<PlatformHotkeyConfiguration>().Object); AvaloniaLocator.CurrentMutable.Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration());
Prepare(target); Prepare(target);
_helper.Down((Interactive)target.Presenter.Panel.Children[3]); _helper.Down((Interactive)target.Presenter.Panel.Children[3]);

6
tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

@ -1045,7 +1045,7 @@ namespace Avalonia.Controls.UnitTests
var data = CreateTestTreeData(); var data = CreateTestTreeData();
var target = CreateTarget(data: data, multiSelect: true); var target = CreateTarget(data: data, multiSelect: true);
var rootNode = data[0]; var rootNode = data[0];
var keymap = AvaloniaLocator.Current.GetRequiredService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
var selectAllGesture = keymap.SelectAll.First(); var selectAllGesture = keymap.SelectAll.First();
var keyEvent = new KeyEventArgs var keyEvent = new KeyEventArgs
@ -1075,7 +1075,7 @@ namespace Avalonia.Controls.UnitTests
ClickContainer(fromContainer, KeyModifiers.None); ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(toContainer, KeyModifiers.Shift); ClickContainer(toContainer, KeyModifiers.Shift);
var keymap = AvaloniaLocator.Current.GetRequiredService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
var selectAllGesture = keymap.SelectAll.First(); var selectAllGesture = keymap.SelectAll.First();
var keyEvent = new KeyEventArgs var keyEvent = new KeyEventArgs
@ -1105,7 +1105,7 @@ namespace Avalonia.Controls.UnitTests
ClickContainer(fromContainer, KeyModifiers.None); ClickContainer(fromContainer, KeyModifiers.None);
ClickContainer(toContainer, KeyModifiers.Shift); ClickContainer(toContainer, KeyModifiers.Shift);
var keymap = AvaloniaLocator.Current.GetRequiredService<PlatformHotkeyConfiguration>(); var keymap = Application.Current!.PlatformSettings!.HotkeyConfiguration;
var selectAllGesture = keymap.SelectAll.First(); var selectAllGesture = keymap.SelectAll.First();
var keyEvent = new KeyEventArgs var keyEvent = new KeyEventArgs

1
tests/Avalonia.UnitTests/TestRoot.cs

@ -67,6 +67,7 @@ namespace Avalonia.UnitTests
public IKeyboardNavigationHandler KeyboardNavigationHandler => null; public IKeyboardNavigationHandler KeyboardNavigationHandler => null;
public IFocusManager FocusManager => AvaloniaLocator.Current.GetService<IFocusManager>(); public IFocusManager FocusManager => AvaloniaLocator.Current.GetService<IFocusManager>();
public IPlatformSettings PlatformSettings => AvaloniaLocator.Current.GetService<IPlatformSettings>();
public IInputElement PointerOverElement { get; set; } public IInputElement PointerOverElement { get; set; }

3
tests/Avalonia.UnitTests/UnitTestApplication.cs

@ -77,7 +77,8 @@ namespace Avalonia.UnitTests
.Bind<IDispatcherImpl>().ToConstant(Services.DispatcherImpl) .Bind<IDispatcherImpl>().ToConstant(Services.DispatcherImpl)
.Bind<ICursorFactory>().ToConstant(Services.StandardCursorFactory) .Bind<ICursorFactory>().ToConstant(Services.StandardCursorFactory)
.Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform) .Bind<IWindowingPlatform>().ToConstant(Services.WindowingPlatform)
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>(); .Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IPlatformSettings>().ToSingleton<DefaultPlatformSettings>();
// This is a hack to make tests work, we need to refactor the way font manager is registered // This is a hack to make tests work, we need to refactor the way font manager is registered
// See https://github.com/AvaloniaUI/Avalonia/issues/10081 // See https://github.com/AvaloniaUI/Avalonia/issues/10081

Loading…
Cancel
Save