Browse Source

Merge pull request #5675 from AvaloniaUI/feature/nativemenu-opening-closed

Added Opening/Closed for NativeMenu on OSX.
Dan Walmsley 4 years ago
parent
commit
7842883961

+ 3 - 2
native/Avalonia.Native/src/OSX/menu.h

@@ -60,7 +60,6 @@ public:
     void RaiseOnClicked();
 };
 
-
 class AvnAppMenu : public ComSingleObject<IAvnMenu, &IID_IAvnMenu>
 {
 private:
@@ -71,10 +70,12 @@ public:
     FORWARD_IUNKNOWN()
     
     AvnAppMenu(IAvnMenuEvents* events);
-        
+
     AvnMenu* GetNative();
     
     void RaiseNeedsUpdate ();
+    void RaiseOpening();
+    void RaiseClosed();
     
     virtual HRESULT InsertItem (int index, IAvnMenuItem* item) override;
     

+ 26 - 0
native/Avalonia.Native/src/OSX/menu.mm

@@ -298,6 +298,23 @@ void AvnAppMenu::RaiseNeedsUpdate()
     }
 }
 
+void AvnAppMenu::RaiseOpening()
+{
+    if(_baseEvents != nullptr)
+    {
+        _baseEvents->Opening();
+    }
+}
+
+void AvnAppMenu::RaiseClosed()
+{
+    if(_baseEvents != nullptr)
+    {
+        _baseEvents->Closed();
+    }
+}
+
+
 HRESULT AvnAppMenu::InsertItem(int index, IAvnMenuItem *item)
 {
     @autoreleasepool
@@ -382,6 +399,15 @@ HRESULT AvnAppMenu::Clear()
     _parent->RaiseNeedsUpdate();
 }
 
+- (void)menuWillOpen:(NSMenu *)menu
+{
+    _parent->RaiseOpening();
+}
+
+- (void)menuDidClose:(NSMenu *)menu
+{
+    _parent->RaiseClosed();
+}
 
 @end
 

+ 3 - 1
src/Avalonia.Controls/ApiCompatBaseline.txt

@@ -1,7 +1,9 @@
 Compat issues with assembly Avalonia.Controls:
+InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseClosed()' is present in the implementation but not in the contract.
+InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.INativeMenuExporterEventsImplBridge.RaiseOpening()' is present in the implementation but not in the contract.
 MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.
 MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Notifications.NotificationCard.CloseOnClickProperty' does not exist in the implementation but it does exist in the contract.
 InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.ICursorImpl)' is present in the implementation but not in the contract.
 InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' is present in the contract but not in the implementation.
 MembersMustExist : Member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.
-Total Issues: 5
+Total Issues: 7

+ 2 - 0
src/Avalonia.Controls/INativeMenuExporterEventsImplBridge.cs

@@ -3,5 +3,7 @@ namespace Avalonia.Controls
     public interface INativeMenuExporterEventsImplBridge
     {
         void RaiseNeedsUpdate ();
+        void RaiseOpening();
+        void RaiseClosed();
     }
 }

+ 32 - 1
src/Avalonia.Controls/NativeMenu.cs

@@ -12,13 +12,34 @@ namespace Avalonia.Controls
         private readonly AvaloniaList<NativeMenuItemBase> _items =
             new AvaloniaList<NativeMenuItemBase> { ResetBehavior = ResetBehavior.Remove };
         private NativeMenuItem _parent;
+
         [Content]
         public IList<NativeMenuItemBase> Items => _items;
 
         /// <summary>
-        /// Raised when the user clicks the menu and before its opened. Use this event to update the menu dynamically.
+        /// Raised when the menu requests an update.
+        /// </summary>
+        /// <remarks>
+        /// Use this event to add, remove or modify menu items before a menu is
+        /// shown or a hotkey is pressed.
+        /// </remarks>
+        public event EventHandler<EventArgs> NeedsUpdate;
+
+        /// <summary>
+        /// Raised before the menu is opened.
         /// </summary>
+        /// <remarks>
+        /// Do not update the menu in this event; use <see cref="NeedsUpdate"/>.
+        /// </remarks>
         public event EventHandler<EventArgs> Opening;
+        
+        /// <summary>
+        /// Raised after the menu is closed.
+        /// </summary>
+        /// <remarks>
+        /// Do not update the menu in this event; use <see cref="NeedsUpdate"/>.
+        /// </remarks>
+        public event EventHandler<EventArgs> Closed;
 
         public NativeMenu()
         {
@@ -27,10 +48,20 @@ namespace Avalonia.Controls
         }
 
         void INativeMenuExporterEventsImplBridge.RaiseNeedsUpdate()
+        {
+            NeedsUpdate?.Invoke(this, EventArgs.Empty);
+        }
+
+        void INativeMenuExporterEventsImplBridge.RaiseOpening()
         {
             Opening?.Invoke(this, EventArgs.Empty);
         }
 
+        void INativeMenuExporterEventsImplBridge.RaiseClosed()
+        {
+            Closed?.Invoke(this, EventArgs.Empty);
+        }
+
         private void Validator(NativeMenuItemBase obj)
         {
             if (obj.Parent != null)

+ 22 - 0
src/Avalonia.Native/IAvnMenu.cs

@@ -20,11 +20,23 @@ namespace Avalonia.Native.Interop
         {
             _parent?.RaiseNeedsUpdate();
         }
+
+        public void Opening()
+        {
+            _parent?.RaiseOpening();
+        }
+
+        public void Closed()
+        {
+            _parent?.RaiseClosed();
+        }
     }
 
     partial interface IAvnMenu
     {
         void RaiseNeedsUpdate();
+        void RaiseOpening();
+        void RaiseClosed();
         void Deinitialise();
     }
 }
@@ -45,6 +57,16 @@ namespace Avalonia.Native.Interop.Impl
             _exporter.UpdateIfNeeded();
         }
 
+        public void RaiseOpening()
+        {
+            (ManagedMenu as INativeMenuExporterEventsImplBridge).RaiseOpening();
+        }
+
+        public void RaiseClosed()
+        {
+            (ManagedMenu as INativeMenuExporterEventsImplBridge).RaiseClosed();
+        }
+
         internal NativeMenu ManagedMenu { get; private set; }
 
         public static __MicroComIAvnMenuProxy Create(IAvaloniaNativeFactory factory)

+ 2 - 3
src/Avalonia.Native/avn.idl

@@ -685,10 +685,9 @@ interface IAvnMenuItem : IUnknown
 [uuid(0af7df53-7632-42f4-a650-0992c361b477)]
 interface IAvnMenuEvents : IUnknown
 {
-    /**
-     * NeedsUpdate
-     */
      void NeedsUpdate();
+     void Opening();
+     void Closed();
 }
 
 [uuid(5142bb41-66ab-49e7-bb37-cd079c000f27)]