diff --git a/readme.md b/readme.md
index 3efc3211ee..b38552a010 100644
--- a/readme.md
+++ b/readme.md
@@ -3,9 +3,6 @@
[](https://www.nuget.org/packages/Avalonia) [](https://www.nuget.org/packages/Avalonia) [](https://www.myget.org/gallery/avalonia-ci) 
-Tips: BTC: bc1q05wx78qemgy9x6ytl5ljk2xrt00yqargyjm8gx
-This will be shared with the community and awarded for significant contributions.
-
## 📖 About AvaloniaUI
Avalonia is a cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows via .NET Framework and .NET Core, Linux via Xorg, macOS. Avalonia is ready for **General-Purpose Desktop App Development**. However, there may be some bugs and breaking changes as we continue along into this project's development.
@@ -78,6 +75,12 @@ For more information see the [.NET Foundation Code of Conduct](https://dotnetfou
Avalonia is licenced under the [MIT licence](licence.md).
+## Support Avalonia
+
+**BTC**: bc1q05wx78qemgy9x6ytl5ljk2xrt00yqargyjm8gx
+
+This will be shared with the community and awarded for significant contributions.
+
### Backers
Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/Avalonia#backer)]
diff --git a/src/Avalonia.Input/Gestures.cs b/src/Avalonia.Input/Gestures.cs
index 639b4ef117..a5ee558f47 100644
--- a/src/Avalonia.Input/Gestures.cs
+++ b/src/Avalonia.Input/Gestures.cs
@@ -6,6 +6,7 @@ namespace Avalonia.Input
{
public static class Gestures
{
+ private static bool s_isDoubleTapped = false;
public static readonly RoutedEvent TappedEvent = RoutedEvent.Register(
"Tapped",
RoutingStrategies.Bubble,
@@ -81,20 +82,23 @@ namespace Avalonia.Input
var e = (PointerPressedEventArgs)ev;
var visual = (IVisual)ev.Source;
-#pragma warning disable CS0618 // Type or member is obsolete
- var clickCount = e.ClickCount;
-#pragma warning restore CS0618 // Type or member is obsolete
- if (clickCount <= 1)
+ if (e.ClickCount <= 1)
{
+ s_isDoubleTapped = false;
s_lastPress.SetTarget(ev.Source);
}
- else if (clickCount == 2 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
+ else if (e.ClickCount % 2 == 0 && e.GetCurrentPoint(visual).Properties.IsLeftButtonPressed)
{
if (s_lastPress.TryGetTarget(out var target) && target == e.Source)
{
+ s_isDoubleTapped = true;
e.Source.RaiseEvent(new TappedEventArgs(DoubleTappedEvent, e));
}
}
+ else
+ {
+ s_isDoubleTapped = false;
+ }
}
}
@@ -112,7 +116,9 @@ namespace Avalonia.Input
{
e.Source.RaiseEvent(new TappedEventArgs(RightTappedEvent, e));
}
- else
+ //s_isDoubleTapped needed here to prevent invoking Tapped event when DoubleTapped is called.
+ //This behaviour matches UWP behaviour.
+ else if (s_isDoubleTapped == false)
{
e.Source.RaiseEvent(new TappedEventArgs(TappedEvent, e));
}
diff --git a/src/Avalonia.Input/PointerEventArgs.cs b/src/Avalonia.Input/PointerEventArgs.cs
index ba39f7ca8e..8c86cd4637 100644
--- a/src/Avalonia.Input/PointerEventArgs.cs
+++ b/src/Avalonia.Input/PointerEventArgs.cs
@@ -114,7 +114,7 @@ namespace Avalonia.Input
public class PointerPressedEventArgs : PointerEventArgs
{
- private readonly int _obsoleteClickCount;
+ private readonly int _clickCount;
public PointerPressedEventArgs(
IInteractive source,
@@ -123,15 +123,14 @@ namespace Avalonia.Input
ulong timestamp,
PointerPointProperties properties,
KeyModifiers modifiers,
- int obsoleteClickCount = 1)
+ int clickCount = 1)
: base(InputElement.PointerPressedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers)
{
- _obsoleteClickCount = obsoleteClickCount;
+ _clickCount = clickCount;
}
- [Obsolete("Use DoubleTapped event or Gestures.DoubleRightTapped attached event")]
- public int ClickCount => _obsoleteClickCount;
+ public int ClickCount => _clickCount;
[Obsolete("Use PointerPressedEventArgs.GetCurrentPoint(this).Properties")]
public MouseButton MouseButton => Properties.PointerUpdateKind.GetMouseButton();
diff --git a/src/Avalonia.Input/TouchDevice.cs b/src/Avalonia.Input/TouchDevice.cs
index d6ad836f37..0f832d9add 100644
--- a/src/Avalonia.Input/TouchDevice.cs
+++ b/src/Avalonia.Input/TouchDevice.cs
@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Input.Raw;
-using Avalonia.VisualTree;
+using Avalonia.Platform;
namespace Avalonia.Input
{
@@ -16,7 +16,9 @@ namespace Avalonia.Input
{
private readonly Dictionary _pointers = new Dictionary();
private bool _disposed;
-
+ private int _clickCount;
+ private Rect _lastClickRect;
+ private ulong _lastClickTime;
KeyModifiers GetKeyModifiers(RawInputModifiers modifiers) =>
(KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask);
@@ -27,10 +29,10 @@ namespace Avalonia.Input
rv |= RawInputModifiers.LeftMouseButton;
return rv;
}
-
+
public void ProcessRawEvent(RawInputEventArgs ev)
{
- if(_disposed)
+ if (_disposed)
return;
var args = (RawTouchEventArgs)ev;
if (!_pointers.TryGetValue(args.TouchPointId, out var pointer))
@@ -43,16 +45,40 @@ namespace Avalonia.Input
PointerType.Touch, _pointers.Count == 0);
pointer.Capture(hit);
}
-
+
var target = pointer.Captured ?? args.Root;
if (args.Type == RawPointerEventType.TouchBegin)
{
+ if (_pointers.Count > 1)
+ {
+ _clickCount = 1;
+ _lastClickTime = 0;
+ _lastClickRect = new Rect();
+ }
+ else
+ {
+ var settings = AvaloniaLocator.Current.GetService();
+ if (settings == null)
+ {
+ throw new Exception("IPlatformSettings can not be null");
+ }
+ if (!_lastClickRect.Contains(args.Position)
+ || ev.Timestamp - _lastClickTime > settings.DoubleClickTime.TotalMilliseconds)
+ {
+ _clickCount = 0;
+ }
+ ++_clickCount;
+ _lastClickTime = ev.Timestamp;
+ _lastClickRect = new Rect(args.Position, new Size())
+ .Inflate(new Thickness(16, 16));
+ }
+
target.RaiseEvent(new PointerPressedEventArgs(target, pointer,
args.Root, args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, true),
PointerUpdateKind.LeftButtonPressed),
- GetKeyModifiers(args.InputModifiers)));
+ GetKeyModifiers(args.InputModifiers), _clickCount));
}
if (args.Type == RawPointerEventType.TouchEnd)
@@ -84,12 +110,12 @@ namespace Avalonia.Input
GetKeyModifiers(args.InputModifiers)));
}
-
+
}
public void Dispose()
{
- if(_disposed)
+ if (_disposed)
return;
var values = _pointers.Values.ToList();
_pointers.Clear();
@@ -97,6 +123,6 @@ namespace Avalonia.Input
foreach (var p in values)
p.Dispose();
}
-
+
}
}
diff --git a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs
index b9d8fd3711..bda1c91750 100644
--- a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs
+++ b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs
@@ -142,6 +142,13 @@ namespace Avalonia.Native
private void DoLayoutReset(bool forceUpdate = false)
{
+ var macOpts = AvaloniaLocator.Current.GetService();
+
+ if (macOpts != null && macOpts.DisableNativeMenus)
+ {
+ return;
+ }
+
if (_resetQueued || forceUpdate)
{
_resetQueued = false;
diff --git a/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs b/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
index eef765e7ec..10619d675b 100644
--- a/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
+++ b/src/Avalonia.Native/AvaloniaNativePlatformExtensions.cs
@@ -73,5 +73,10 @@ namespace Avalonia
/// You can prevent Avalonia from adding those items to the OSX Application Menu with this property. The default value is false.
///
public bool DisableDefaultApplicationMenuItems { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the native macOS menu bar will be enabled for the application.
+ ///
+ public bool DisableNativeMenus { get; set; }
}
}
diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj
index 20b3183b00..3548749846 100644
--- a/src/Avalonia.Styling/Avalonia.Styling.csproj
+++ b/src/Avalonia.Styling/Avalonia.Styling.csproj
@@ -9,4 +9,5 @@
+
diff --git a/src/Avalonia.Styling/Controls/ChildNameScope.cs b/src/Avalonia.Styling/Controls/ChildNameScope.cs
index e6707e71db..58114a57fd 100644
--- a/src/Avalonia.Styling/Controls/ChildNameScope.cs
+++ b/src/Avalonia.Styling/Controls/ChildNameScope.cs
@@ -15,20 +15,20 @@ namespace Avalonia.Controls
public void Register(string name, object element) => _inner.Register(name, element);
- public SynchronousCompletionAsyncResult