Pārlūkot izejas kodu

add support for seperators

Dan Walmsley 6 gadi atpakaļ
vecāks
revīzija
5736a7965d

+ 4 - 0
samples/ControlCatalog/App.xaml

@@ -24,7 +24,9 @@
         <NativeMenuItem.Menu>
           <NativeMenu>
             <NativeMenuItem Header="About Avalonia" />
+            <NativeMenuItemSeperator />
             <NativeMenuItem Header="Preferences" Gesture="CMD + ," />
+            <NativeMenuItemSeperator />
             <NativeMenuItem Header="Services">
               <NativeMenuItem.Menu>
                 <NativeMenu>
@@ -34,9 +36,11 @@
                 </NativeMenu>
               </NativeMenuItem.Menu>
             </NativeMenuItem>
+            <NativeMenuItemSeperator />
             <NativeMenuItem Header="Hide Avalonia" Gesture="CMD + H" />
             <NativeMenuItem Header="Hide Others" Gesture="ALT + CMD + H" />
             <NativeMenuItem Header="Show All" />
+            <NativeMenuItemSeperator />
             <NativeMenuItem Header="Quit Avalonia" Gesture="CMD + Q" />
           </NativeMenu>
         </NativeMenuItem.Menu>

+ 7 - 7
src/Avalonia.Controls/NativeMenu.cs

@@ -9,13 +9,13 @@ using Avalonia.Metadata;
 
 namespace Avalonia.Controls
 {
-    public partial class NativeMenu : AvaloniaObject, IEnumerable<NativeMenuItem>
+    public partial class NativeMenu : AvaloniaObject, IEnumerable<NativeMenuItemBase>
     {
-        private AvaloniaList<NativeMenuItem> _items =
-            new AvaloniaList<NativeMenuItem> { ResetBehavior = ResetBehavior.Remove };
+        private AvaloniaList<NativeMenuItemBase> _items =
+            new AvaloniaList<NativeMenuItemBase> { ResetBehavior = ResetBehavior.Remove };
         private NativeMenuItem _parent;
         [Content]
-        public IList<NativeMenuItem> Items => _items;
+        public IList<NativeMenuItemBase> Items => _items;
 
         public NativeMenu()
         {
@@ -23,7 +23,7 @@ namespace Avalonia.Controls
             _items.CollectionChanged += ItemsChanged;
         }
 
-        private void Validator(NativeMenuItem obj)
+        private void Validator(NativeMenuItemBase obj)
         {
             if (obj.Parent != null)
                 throw new InvalidOperationException("NativeMenuItem already has a parent");
@@ -48,9 +48,9 @@ namespace Avalonia.Controls
             set => SetAndRaise(ParentProperty, ref _parent, value);
         }
 
-        public void Add(NativeMenuItem item) => _items.Add(item);
+        public void Add(NativeMenuItemBase item) => _items.Add(item);
         
-        public IEnumerator<NativeMenuItem> GetEnumerator() => _items.GetEnumerator();
+        public IEnumerator<NativeMenuItemBase> GetEnumerator() => _items.GetEnumerator();
 
         IEnumerator IEnumerable.GetEnumerator()
         {

+ 5 - 50
src/Avalonia.Controls/NativeMenuItem.cs

@@ -1,20 +1,16 @@
 using System;
-using System.Collections.Generic;
 using System.Windows.Input;
-using Avalonia.Collections;
 using Avalonia.Input;
-using Avalonia.Metadata;
 using Avalonia.Utilities;
 
 namespace Avalonia.Controls
 {
-    public class NativeMenuItem : AvaloniaObject
+    public class NativeMenuItem : NativeMenuItemBase
     {
         private string _header;
         private KeyGesture _gesture;
         private bool _enabled = true;
-        private NativeMenu _menu;
-        private NativeMenu _parent;
+
 
         class CanExecuteChangedSubscriber : IWeakSubscriber<EventArgs>
         {
@@ -33,18 +29,7 @@ namespace Avalonia.Controls
 
         private readonly CanExecuteChangedSubscriber _canExecuteChangedSubscriber;
 
-        static NativeMenuItem()
-        {
-            MenuProperty.Changed.Subscribe(args =>
-            {
-                var item = (NativeMenuItem)args.Sender;
-                var value = (NativeMenu)args.NewValue;
-                if (value.Parent != null && value.Parent != item)
-                    throw new InvalidOperationException("NativeMenu already has a parent");
-                value.Parent = item;
-            });
-        }
-        
+
         public NativeMenuItem()
         {
             _canExecuteChangedSubscriber = new CanExecuteChangedSubscriber(this);
@@ -54,7 +39,7 @@ namespace Avalonia.Controls
         {
             Header = header;
         }
-        
+
         public static readonly DirectProperty<NativeMenuItem, string> HeaderProperty =
             AvaloniaProperty.RegisterDirect<NativeMenuItem, string>(nameof(Header), o => o._header, (o, v) => o._header = v);
 
@@ -65,7 +50,7 @@ namespace Avalonia.Controls
         }
 
         public static readonly DirectProperty<NativeMenuItem, KeyGesture> GestureProperty =
-            AvaloniaProperty.RegisterDirect<NativeMenuItem, KeyGesture>(nameof(Gesture), o => o._gesture, (o,v)=> o._gesture = v);
+            AvaloniaProperty.RegisterDirect<NativeMenuItem, KeyGesture>(nameof(Gesture), o => o._gesture, (o, v) => o._gesture = v);
 
         public KeyGesture Gesture
         {
@@ -128,36 +113,6 @@ namespace Avalonia.Controls
             set { SetValue(CommandParameterProperty, value); }
         }
 
-        public static readonly DirectProperty<NativeMenuItem, NativeMenu> MenuProperty =
-            AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>(nameof(Menu), o => o._menu,
-                (o, v) =>
-                {
-                    if (v.Parent != null && v.Parent != o)
-                        throw new InvalidOperationException("NativeMenu already has a parent");
-                    o._menu = v;
-                });
-
-        public NativeMenu Menu
-        {
-            get => _menu;
-            set
-            {
-                if (value.Parent != null && value.Parent != this)
-                    throw new InvalidOperationException("NativeMenu already has a parent");
-                SetAndRaise(MenuProperty, ref _menu, value);
-            }
-        }
-
-        public static readonly DirectProperty<NativeMenuItem, NativeMenu> ParentProperty =
-            AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>("Parent", o => o.Parent, (o, v) => o.Parent = v);
-
-        public NativeMenu Parent
-        {
-            get => _parent;
-            set => SetAndRaise(ParentProperty, ref _parent, value);
-        }
-
-
         public event EventHandler Clicked;
 
         public void RaiseClick()

+ 56 - 0
src/Avalonia.Controls/NativeMenuItemBase.cs

@@ -0,0 +1,56 @@
+using System;
+
+namespace Avalonia.Controls
+{
+    public class NativeMenuItemBase : AvaloniaObject
+    {
+        private NativeMenu _menu;
+        private NativeMenu _parent;
+
+        static NativeMenuItemBase()
+        {
+            MenuProperty.Changed.Subscribe(args =>
+            {
+                var item = (NativeMenuItem)args.Sender;
+                var value = (NativeMenu)args.NewValue;
+                if (value.Parent != null && value.Parent != item)
+                    throw new InvalidOperationException("NativeMenu already has a parent");
+                value.Parent = item;
+            });
+        }
+
+        internal NativeMenuItemBase()
+        {
+
+        }
+
+        public static readonly DirectProperty<NativeMenuItem, NativeMenu> MenuProperty =
+            AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>(nameof(Menu), o => o._menu,
+                (o, v) =>
+                {
+                    if (v.Parent != null && v.Parent != o)
+                        throw new InvalidOperationException("NativeMenu already has a parent");
+                    o._menu = v;
+                });
+
+        public NativeMenu Menu
+        {
+            get => _menu;
+            set
+            {
+                if (value.Parent != null && value.Parent != this)
+                    throw new InvalidOperationException("NativeMenu already has a parent");
+                SetAndRaise(MenuProperty, ref _menu, value);
+            }
+        }
+
+        public static readonly DirectProperty<NativeMenuItem, NativeMenu> ParentProperty =
+            AvaloniaProperty.RegisterDirect<NativeMenuItem, NativeMenu>("Parent", o => o.Parent, (o, v) => o.Parent = v);
+
+        public NativeMenu Parent
+        {
+            get => _parent;
+            set => SetAndRaise(ParentProperty, ref _parent, value);
+        }
+    }
+}

+ 7 - 0
src/Avalonia.Controls/NativeMenuItemSeperator.cs

@@ -0,0 +1,7 @@
+namespace Avalonia.Controls
+{
+    public class NativeMenuItemSeperator : NativeMenuItemBase
+    {
+
+    }
+}

+ 70 - 71
src/Avalonia.Native/AvaloniaNativeMenuExporter.cs

@@ -98,13 +98,6 @@ namespace Avalonia.Native
             QueueReset();
         }
 
-        /*
-                 This is basic initial implementation, so we don't actually track anything and
-                 just reset the whole layout on *ANY* change
-                 
-                 This is not how it should work and will prevent us from implementing various features,
-                 but that's the fastest way to get things working, so...
-             */
         void DoLayoutReset()
         {
             _resetQueued = false;
@@ -137,7 +130,7 @@ namespace Avalonia.Native
             Dispatcher.UIThread.Post(DoLayoutReset, DispatcherPriority.Background);
         }
 
-        private IAvnAppMenu CreateSubmenu(ICollection<NativeMenuItem> children)
+        private IAvnAppMenu CreateSubmenu(ICollection<NativeMenuItemBase> children)
         {
             var menu = _factory.CreateMenu();
 
@@ -154,108 +147,114 @@ namespace Avalonia.Native
             }
         }
 
-        private void SetChildren(IAvnAppMenu menu, ICollection<NativeMenuItem> children)
+        private void SetChildren(IAvnAppMenu menu, ICollection<NativeMenuItemBase> children)
         {
-            foreach (var item in children)
+            foreach (var i in children)
             {
-                AddMenuItem(item);
-
-                var menuItem = _factory.CreateMenuItem();
-
-                using (var buffer = new Utf8Buffer(item.Header))
+                if (i is NativeMenuItem item)
                 {
-                    menuItem.Title = buffer.DangerousGetHandle();
-                }
+                    AddMenuItem(item);
 
-                if (item.Gesture != null)
-                {
-                    using (var buffer = new Utf8Buffer(item.Gesture.Key.ToString().ToLower()))
+                    var menuItem = _factory.CreateMenuItem();
+
+                    using (var buffer = new Utf8Buffer(item.Header))
                     {
-                        menuItem.SetGesture(buffer.DangerousGetHandle(), (AvnInputModifiers)item.Gesture.KeyModifiers);
+                        menuItem.Title = buffer.DangerousGetHandle();
                     }
-                }
 
-                menuItem.SetAction(new PredicateCallback(() =>
-                {
-                    if (item.Command != null || item.HasClickHandlers)
+                    if (item.Gesture != null)
                     {
-                        return item.Enabled;
+                        using (var buffer = new Utf8Buffer(item.Gesture.Key.ToString().ToLower()))
+                        {
+                            menuItem.SetGesture(buffer.DangerousGetHandle(), (AvnInputModifiers)item.Gesture.KeyModifiers);
+                        }
                     }
 
-                    return false;
-                }), new MenuActionCallback(() => { item.RaiseClick(); }));
-                menu.AddItem(menuItem);
+                    menuItem.SetAction(new PredicateCallback(() =>
+                    {
+                        if (item.Command != null || item.HasClickHandlers)
+                        {
+                            return item.Enabled;
+                        }
 
-                if (item.Menu?.Items?.Count > 0)
-                {
-                    var submenu = _factory.CreateMenu();
+                        return false;
+                    }), new MenuActionCallback(() => { item.RaiseClick(); }));
+                    menu.AddItem(menuItem);
 
-                    using (var buffer = new Utf8Buffer(item.Header))
+                    if (item.Menu?.Items?.Count > 0)
                     {
-                        submenu.Title = buffer.DangerousGetHandle();
-                    }
+                        var submenu = _factory.CreateMenu();
+
+                        using (var buffer = new Utf8Buffer(item.Header))
+                        {
+                            submenu.Title = buffer.DangerousGetHandle();
+                        }
 
-                    menuItem.SetSubMenu(submenu);
+                        menuItem.SetSubMenu(submenu);
 
-                    AddItemsToMenu(submenu, item.Menu?.Items);
+                        AddItemsToMenu(submenu, item.Menu?.Items);
+                    }
                 }
             }
         }
 
-        private void AddItemsToMenu(IAvnAppMenu menu, ICollection<NativeMenuItem> items, bool isMainMenu = false)
+        private void AddItemsToMenu(IAvnAppMenu menu, ICollection<NativeMenuItemBase> items, bool isMainMenu = false)
         {
-            foreach (var item in items)
+            foreach (var i in items)
             {
-                var menuItem = _factory.CreateMenuItem();
+                if (i is NativeMenuItem item)
+                {
+                    var menuItem = _factory.CreateMenuItem();
 
-                AddMenuItem(item);
+                    AddMenuItem(item);
 
-                menuItem.SetAction(new PredicateCallback(() =>
-                {
-                    if (item.Command != null || item.HasClickHandlers)
+                    menuItem.SetAction(new PredicateCallback(() =>
                     {
-                        return item.Enabled;
-                    }
+                        if (item.Command != null || item.HasClickHandlers)
+                        {
+                            return item.Enabled;
+                        }
 
-                    return false;
-                }), new MenuActionCallback(() => { item.RaiseClick(); }));
+                        return false;
+                    }), new MenuActionCallback(() => { item.RaiseClick(); }));
 
-                if (item.Menu?.Items.Count > 0 || isMainMenu)
-                {
-                    var subMenu = CreateSubmenu(item.Menu?.Items);
+                    if (item.Menu?.Items.Count > 0 || isMainMenu)
+                    {
+                        var subMenu = CreateSubmenu(item.Menu?.Items);
 
-                    menuItem.SetSubMenu(subMenu);
+                        menuItem.SetSubMenu(subMenu);
 
-                    using (var buffer = new Utf8Buffer(item.Header))
-                    {
-                        subMenu.Title = buffer.DangerousGetHandle();
+                        using (var buffer = new Utf8Buffer(item.Header))
+                        {
+                            subMenu.Title = buffer.DangerousGetHandle();
+                        }
                     }
-                }
-                else
-                {
-                    using (var buffer = new Utf8Buffer(item.Header))
+                    else
                     {
-                        menuItem.Title = buffer.DangerousGetHandle();
-                    }
+                        using (var buffer = new Utf8Buffer(item.Header))
+                        {
+                            menuItem.Title = buffer.DangerousGetHandle();
+                        }
 
-                    if (item.Gesture != null)
-                    {
-                        using (var buffer = new Utf8Buffer(item.Gesture.Key.ToString().ToLower()))
+                        if (item.Gesture != null)
                         {
-                            menuItem.SetGesture(buffer.DangerousGetHandle(), (AvnInputModifiers)item.Gesture.KeyModifiers);
+                            using (var buffer = new Utf8Buffer(item.Gesture.Key.ToString().ToLower()))
+                            {
+                                menuItem.SetGesture(buffer.DangerousGetHandle(), (AvnInputModifiers)item.Gesture.KeyModifiers);
+                            }
                         }
                     }
-                }
 
-                menu.AddItem(menuItem);
+                    menu.AddItem(menuItem);
+                }
             }
         }
 
-        private void SetMenu(ICollection<NativeMenuItem> menuItems)
+        private void SetMenu(ICollection<NativeMenuItemBase> menuItems)
         {
             if (menuItems is null)
             {
-                menuItems = new List<NativeMenuItem>();
+                menuItems = new List<NativeMenuItemBase>();
             }
 
             var menu = NativeMenu.GetMenu(Application.Current);
@@ -275,11 +274,11 @@ namespace Avalonia.Native
             }
         }
 
-        private void SetMenu(IAvnWindow avnWindow, ICollection<NativeMenuItem> menuItems)
+        private void SetMenu(IAvnWindow avnWindow, ICollection<NativeMenuItemBase> menuItems)
         {
             if (menuItems is null)
             {
-                menuItems = new List<NativeMenuItem>();
+                menuItems = new List<NativeMenuItemBase>();
             }
 
             var appMenu = avnWindow.ObtainMainMenu();