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 @@