From e0c6e11a42b2aecc50f4fae013d64fcf03f98041 Mon Sep 17 00:00:00 2001
From: Steveice10 <1269164+Steveice10@users.noreply.github.com>
Date: Mon, 23 Oct 2023 22:12:56 -0700
Subject: [PATCH] Add tooltip support to NativeMenuItem. (#13350)
* Add tooltip support to NativeMenuItem.
* Add support for NativeMenuItem tooltips on macOS.
---
native/Avalonia.Native/src/OSX/menu.h | 4 ++-
native/Avalonia.Native/src/OSX/menu.mm | 14 ++++++++
.../IntegrationTestApp/MainWindow.axaml.cs | 1 +
src/Avalonia.Controls/NativeMenuItem.cs | 17 +++++++++
src/Avalonia.Native/IAvnMenuItem.cs | 7 ++++
src/Avalonia.Native/avn.idl | 1 +
.../Controls/NativeMenuBar.xaml | 1 +
.../NativeMenuTests.cs | 36 ++++++++++++++++++-
8 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h
index 405938318c..1bea2ccc8d 100644
--- a/native/Avalonia.Native/src/OSX/menu.h
+++ b/native/Avalonia.Native/src/OSX/menu.h
@@ -43,7 +43,9 @@ public:
virtual HRESULT SetSubMenu (IAvnMenu* menu) override;
virtual HRESULT SetTitle (char* utf8String) override;
-
+
+ virtual HRESULT SetToolTip (char* utf8String) override;
+
virtual HRESULT SetGesture (AvnKey key, AvnInputModifiers modifiers) override;
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;
diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm
index ef5988bddd..3905987aab 100644
--- a/native/Avalonia.Native/src/OSX/menu.mm
+++ b/native/Avalonia.Native/src/OSX/menu.mm
@@ -127,6 +127,20 @@ HRESULT AvnAppMenuItem::SetTitle (char* utf8String)
}
}
+HRESULT AvnAppMenuItem::SetToolTip (char* utf8String)
+{
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ if (utf8String != nullptr)
+ {
+ [_native setToolTip:[NSString stringWithUTF8String:(const char*)utf8String]];
+ }
+
+ return S_OK;
+ }
+}
HRESULT AvnAppMenuItem::SetGesture (AvnKey key, AvnInputModifiers modifiers)
{
diff --git a/samples/IntegrationTestApp/MainWindow.axaml.cs b/samples/IntegrationTestApp/MainWindow.axaml.cs
index 689cfcb65d..a858686ffb 100644
--- a/samples/IntegrationTestApp/MainWindow.axaml.cs
+++ b/samples/IntegrationTestApp/MainWindow.axaml.cs
@@ -51,6 +51,7 @@ namespace IntegrationTestApp
var menuItem = new NativeMenuItem
{
Header = (string)tabItem.Header!,
+ ToolTip = (string)tabItem.Header!,
IsChecked = tabItem.IsSelected,
ToggleType = NativeMenuItemToggleType.Radio,
};
diff --git a/src/Avalonia.Controls/NativeMenuItem.cs b/src/Avalonia.Controls/NativeMenuItem.cs
index 6cbe666e5a..47fc369859 100644
--- a/src/Avalonia.Controls/NativeMenuItem.cs
+++ b/src/Avalonia.Controls/NativeMenuItem.cs
@@ -72,6 +72,23 @@ namespace Avalonia.Controls
set => SetValue(HeaderProperty, value);
}
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ToolTipProperty =
+ AvaloniaProperty.Register(nameof(ToolTip));
+
+ ///
+ /// Gets or sets the tooltip associated with the menu item.
+ /// This may not be supported by the native menu provider, but
+ /// will be passed on to the non-native fallback menu item if used.
+ ///
+ public string? ToolTip
+ {
+ get => GetValue(ToolTipProperty);
+ set => SetValue(ToolTipProperty, value);
+ }
+
public static readonly StyledProperty GestureProperty =
AvaloniaProperty.Register(nameof(Gesture));
diff --git a/src/Avalonia.Native/IAvnMenuItem.cs b/src/Avalonia.Native/IAvnMenuItem.cs
index 540a4fd8c8..50f64decca 100644
--- a/src/Avalonia.Native/IAvnMenuItem.cs
+++ b/src/Avalonia.Native/IAvnMenuItem.cs
@@ -38,6 +38,8 @@ namespace Avalonia.Native.Interop.Impl
SetTitle(title);
}
+ private void UpdateToolTip(string toolTip) => SetToolTip(toolTip ?? "");
+
private void UpdateIsChecked(bool isChecked) => SetIsChecked(isChecked.AsComBool());
private void UpdateToggleType(NativeMenuItemToggleType toggleType)
@@ -107,6 +109,8 @@ namespace Avalonia.Native.Interop.Impl
{
UpdateTitle(item.Header);
+ UpdateToolTip(item.ToolTip);
+
UpdateGesture(item.Gesture);
UpdateAction(ManagedMenuItem as NativeMenuItem);
@@ -120,6 +124,9 @@ namespace Avalonia.Native.Interop.Impl
_propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.HeaderProperty)
.Subscribe(x => UpdateTitle(x)));
+ _propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.ToolTipProperty)
+ .Subscribe(x => UpdateToolTip(x)));
+
_propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.GestureProperty)
.Subscribe(x => UpdateGesture(x)));
diff --git a/src/Avalonia.Native/avn.idl b/src/Avalonia.Native/avn.idl
index 036273fc01..7583dfdef6 100644
--- a/src/Avalonia.Native/avn.idl
+++ b/src/Avalonia.Native/avn.idl
@@ -1022,6 +1022,7 @@ interface IAvnMenuItem : IUnknown
{
HRESULT SetSubMenu(IAvnMenu* menu);
HRESULT SetTitle(char* utf8String);
+ HRESULT SetToolTip(char* utf8String);
HRESULT SetGesture(AvnKey key, AvnInputModifiers modifiers);
HRESULT SetAction(IAvnPredicateCallback* predicate, IAvnActionCallback* callback);
HRESULT SetIsChecked(bool isChecked);
diff --git a/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml b/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
index 3e28ac3ddd..13809b4350 100644
--- a/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
@@ -12,6 +12,7 @@