From fbb1ce340b80a12b3341a309d2796637cc9b1ba8 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 28 Apr 2020 16:36:36 -0300 Subject: [PATCH 1/7] Add backend framework for radio buttons in nativemenus. --- native/Avalonia.Native/inc/avalonia-native.h | 8 ++++++ native/Avalonia.Native/src/OSX/menu.h | 3 +++ native/Avalonia.Native/src/OSX/menu.mm | 28 +++++++++++++++++++- src/Avalonia.Native/IAvnMenuItem.cs | 5 ++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 757c0bc85a..7fde6b3360 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -176,6 +176,13 @@ enum AvnWindowEdge WindowEdgeSouthEast }; +enum AvnMenuItemToggleType +{ + None, + CheckMark, + Radio +}; + AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown { public: @@ -407,6 +414,7 @@ AVNCOM(IAvnMenuItem, 19) : IUnknown virtual HRESULT SetGesture (void* utf8String, AvnInputModifiers modifiers) = 0; virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) = 0; virtual HRESULT SetIsChecked (bool isChecked) = 0; + virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) = 0; }; AVNCOM(IAvnMenuEvents, 1A) : IUnknown diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h index 228731cb28..cd464d2169 100644 --- a/native/Avalonia.Native/src/OSX/menu.h +++ b/native/Avalonia.Native/src/OSX/menu.h @@ -32,6 +32,7 @@ private: IAvnActionCallback* _callback; IAvnPredicateCallback* _predicate; bool _isSeperator; + bool _isCheckable; public: FORWARD_IUNKNOWN() @@ -50,6 +51,8 @@ public: virtual HRESULT SetIsChecked (bool isChecked) override; + virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) override; + bool EvaluateItemEnabled(); void RaiseOnClicked(); diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index 1cd9cb0644..6ea7797fa8 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -70,6 +70,7 @@ AvnAppMenuItem::AvnAppMenuItem(bool isSeperator) { + _isCheckable = false; _isSeperator = isSeperator; if(isSeperator) @@ -157,7 +158,32 @@ HRESULT AvnAppMenuItem::SetIsChecked (bool isChecked) { @autoreleasepool { - [_native setState:(isChecked ? NSOnState : NSOffState)]; + [_native setState:(isChecked && _isCheckable ? NSOnState : NSOffState)]; + return S_OK; + } +} + +HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType) +{ + @autoreleasepool + { + switch(toggleType) + { + case AvnMenuItemToggleType::None: + [_native setOnStateImage:nullptr]; + _isCheckable = false; + break; + + case AvnMenuItemToggleType::CheckMark: + [_native setOnStateImage:nullptr]; + _isCheckable = true; + break; + + case AvnMenuItemToggleType::Radio: + [_native setOnStateImage: [NSImage imageNamed:@"NSMenuRadio"]]; + break; + } + return S_OK; } } diff --git a/src/Avalonia.Native/IAvnMenuItem.cs b/src/Avalonia.Native/IAvnMenuItem.cs index a9730920f1..2e829832bf 100644 --- a/src/Avalonia.Native/IAvnMenuItem.cs +++ b/src/Avalonia.Native/IAvnMenuItem.cs @@ -26,6 +26,11 @@ namespace Avalonia.Native.Interop IsChecked = isChecked; } + private void UpdateToggleType(NativeMenuItemToggleType toggleType) + { + + } + private void UpdateGesture(Input.KeyGesture gesture) { // todo ensure backend can cope with setting null gesture. From 6426a206667ddf17efcc6d9bd747b0ad3f9c55a7 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 28 Apr 2020 17:12:49 -0300 Subject: [PATCH 2/7] Implement Radio Toggle type on OSX. --- native/Avalonia.Native/src/OSX/menu.h | 1 - native/Avalonia.Native/src/OSX/menu.mm | 9 +++------ src/Avalonia.Native/IAvnMenuItem.cs | 7 ++++++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h index cd464d2169..2d211e8643 100644 --- a/native/Avalonia.Native/src/OSX/menu.h +++ b/native/Avalonia.Native/src/OSX/menu.h @@ -32,7 +32,6 @@ private: IAvnActionCallback* _callback; IAvnPredicateCallback* _predicate; bool _isSeperator; - bool _isCheckable; public: FORWARD_IUNKNOWN() diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index 6ea7797fa8..62eaffa5b8 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -70,7 +70,6 @@ AvnAppMenuItem::AvnAppMenuItem(bool isSeperator) { - _isCheckable = false; _isSeperator = isSeperator; if(isSeperator) @@ -158,7 +157,7 @@ HRESULT AvnAppMenuItem::SetIsChecked (bool isChecked) { @autoreleasepool { - [_native setState:(isChecked && _isCheckable ? NSOnState : NSOffState)]; + [_native setState:(isChecked ? NSOnState : NSOffState)]; return S_OK; } } @@ -171,16 +170,14 @@ HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType) { case AvnMenuItemToggleType::None: [_native setOnStateImage:nullptr]; - _isCheckable = false; break; case AvnMenuItemToggleType::CheckMark: - [_native setOnStateImage:nullptr]; - _isCheckable = true; + [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]]; break; case AvnMenuItemToggleType::Radio: - [_native setOnStateImage: [NSImage imageNamed:@"NSMenuRadio"]]; + [_native setOnStateImage: [NSImage imageNamed:@"NSMenuItemBullet"]]; break; } diff --git a/src/Avalonia.Native/IAvnMenuItem.cs b/src/Avalonia.Native/IAvnMenuItem.cs index 2e829832bf..df82f3955a 100644 --- a/src/Avalonia.Native/IAvnMenuItem.cs +++ b/src/Avalonia.Native/IAvnMenuItem.cs @@ -28,7 +28,7 @@ namespace Avalonia.Native.Interop private void UpdateToggleType(NativeMenuItemToggleType toggleType) { - + ToggleType = (AvnMenuItemToggleType)toggleType; } private void UpdateGesture(Input.KeyGesture gesture) @@ -78,6 +78,8 @@ namespace Avalonia.Native.Interop UpdateAction(ManagedMenuItem as NativeMenuItem); + UpdateToggleType(item.ToggleType); + UpdateIsChecked(item.IsChecked); _propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.HeaderProperty) @@ -89,6 +91,9 @@ namespace Avalonia.Native.Interop _propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.CommandProperty) .Subscribe(x => UpdateAction(ManagedMenuItem as NativeMenuItem))); + _propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.ToggleTypeProperty) + .Subscribe(x => UpdateToggleType(x))); + _propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.IsCheckedProperty) .Subscribe(x => UpdateIsChecked(x))); } From f05751e567997ba45a93cf45b324b1709bd0aafc Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 28 Apr 2020 17:14:06 -0300 Subject: [PATCH 3/7] improve demo --- samples/ControlCatalog/MainWindow.xaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index e75506624a..6970f7e1be 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -39,10 +39,14 @@ - + From e055474e3e01377d650c5b61ad1efabef8ce48a5 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 28 Apr 2020 17:26:35 -0300 Subject: [PATCH 4/7] support checking CheckMark::None --- native/Avalonia.Native/src/OSX/menu.mm | 3 --- samples/ControlCatalog/MainWindow.xaml | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index 62eaffa5b8..cf4acb822f 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -169,9 +169,6 @@ HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType) switch(toggleType) { case AvnMenuItemToggleType::None: - [_native setOnStateImage:nullptr]; - break; - case AvnMenuItemToggleType::CheckMark: [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]]; break; diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 6970f7e1be..9ebfd4b7ed 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -39,6 +39,10 @@ + Date: Tue, 28 Apr 2020 17:30:55 -0300 Subject: [PATCH 5/7] fix checkmark demo --- samples/ControlCatalog/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml index 9ebfd4b7ed..ca20327e1e 100644 --- a/samples/ControlCatalog/MainWindow.xaml +++ b/samples/ControlCatalog/MainWindow.xaml @@ -41,7 +41,7 @@ Date: Tue, 28 Apr 2020 17:42:58 -0300 Subject: [PATCH 6/7] checkmark == none ignores ischecked. --- native/Avalonia.Native/src/OSX/menu.h | 1 + native/Avalonia.Native/src/OSX/menu.mm | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/native/Avalonia.Native/src/OSX/menu.h b/native/Avalonia.Native/src/OSX/menu.h index 2d211e8643..cd464d2169 100644 --- a/native/Avalonia.Native/src/OSX/menu.h +++ b/native/Avalonia.Native/src/OSX/menu.h @@ -32,6 +32,7 @@ private: IAvnActionCallback* _callback; IAvnPredicateCallback* _predicate; bool _isSeperator; + bool _isCheckable; public: FORWARD_IUNKNOWN() diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm index cf4acb822f..11a8f04ae3 100644 --- a/native/Avalonia.Native/src/OSX/menu.mm +++ b/native/Avalonia.Native/src/OSX/menu.mm @@ -70,6 +70,7 @@ AvnAppMenuItem::AvnAppMenuItem(bool isSeperator) { + _isCheckable = false; _isSeperator = isSeperator; if(isSeperator) @@ -157,7 +158,7 @@ HRESULT AvnAppMenuItem::SetIsChecked (bool isChecked) { @autoreleasepool { - [_native setState:(isChecked ? NSOnState : NSOffState)]; + [_native setState:(isChecked && _isCheckable ? NSOnState : NSOffState)]; return S_OK; } } @@ -169,12 +170,21 @@ HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType) switch(toggleType) { case AvnMenuItemToggleType::None: + [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]]; + + _isCheckable = false; + break; + case AvnMenuItemToggleType::CheckMark: [_native setOnStateImage: [NSImage imageNamed:@"NSMenuCheckmark"]]; + + _isCheckable = true; break; case AvnMenuItemToggleType::Radio: [_native setOnStateImage: [NSImage imageNamed:@"NSMenuItemBullet"]]; + + _isCheckable = true; break; } From 8a6ff82fddbff7be4fbfe180b1064405629150bc Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Tue, 28 Apr 2020 17:44:56 -0300 Subject: [PATCH 7/7] make dbus behavior consistent with osx. --- src/Avalonia.FreeDesktop/DBusMenuExporter.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs index c60c1d396f..3f64c094ab 100644 --- a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs +++ b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs @@ -240,9 +240,6 @@ namespace Avalonia.FreeDesktop return "checkmark"; if (item.ToggleType == NativeMenuItemToggleType.Radio) return "radio"; - // Someone has forgot to set the style - if (item.IsChecked) - return "checkmark"; } if (name == "toggle-state")