From 0f35059055bfa7def57950cc2a778464e2e78703 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 8 Apr 2020 15:25:08 -0300 Subject: [PATCH] move code to own files. --- .../AvaloniaNativeMenuExporter.cs | 212 +----------------- src/Avalonia.Native/IAvnAppMenu.cs | 118 ++++++++++ src/Avalonia.Native/IAvnAppMenuItem.cs | 83 +++++++ src/Avalonia.Native/MenuActionCallback.cs | 20 ++ src/Avalonia.Native/PredicateCallback.cs | 20 ++ 5 files changed, 242 insertions(+), 211 deletions(-) create mode 100644 src/Avalonia.Native/IAvnAppMenu.cs create mode 100644 src/Avalonia.Native/IAvnAppMenuItem.cs create mode 100644 src/Avalonia.Native/MenuActionCallback.cs create mode 100644 src/Avalonia.Native/PredicateCallback.cs diff --git a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs index 14eb4b03ce..a074092792 100644 --- a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs +++ b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs @@ -1,222 +1,13 @@ using System; -using System.Collections.Generic; -using System.Collections.Specialized; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.Platform; using Avalonia.Dialogs; using Avalonia.Native.Interop; -using Avalonia.Platform.Interop; using Avalonia.Threading; -namespace Avalonia.Native.Interop -{ - public partial class IAvnAppMenuItem - { - private IAvnAppMenu _subMenu; - private AvaloniaNativeMenuExporter _exporter; - - public NativeMenuItemBase Managed { get; set; } - - internal void Update(AvaloniaNativeMenuExporter exporter, IAvaloniaNativeFactory factory, NativeMenuItem item) - { - _exporter = exporter; - - Managed = item; - - Managed.PropertyChanged += Item_PropertyChanged; - - using (var buffer = new Utf8Buffer(item.Header)) - { - Title = buffer.DangerousGetHandle(); - } - - if (item.Gesture != null) - { - using (var buffer = new Utf8Buffer(OsxUnicodeKeys.ConvertOSXSpecialKeyCodes(item.Gesture.Key))) - { - SetGesture(buffer.DangerousGetHandle(), (AvnInputModifiers)item.Gesture.KeyModifiers); - } - } - - SetAction(new PredicateCallback(() => - { - if (item.Command != null || item.HasClickHandlers) - { - return item.Enabled; - } - - return false; - }), new MenuActionCallback(() => { item.RaiseClick(); })); - - if (item.Menu != null) - { - if (_subMenu == null) - { - _subMenu = factory.CreateMenu(); - } - - _subMenu.Update(exporter, factory, item.Menu); - } - - if (item.Menu == null && _subMenu != null) - { - _subMenu.Remove(); - - // todo remove submenu. - - // needs implementing on native side also. - } - } - - private void Item_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) - { - _exporter.QueueReset(); - } - - internal void Remove() - { - _exporter = null; - Managed = null; - Managed.PropertyChanged -= Item_PropertyChanged; - } - } - - public partial class IAvnAppMenu - { - private AvaloniaNativeMenuExporter _exporter; - private NativeMenu _menu; - private List _menuItems = new List(); - private Dictionary _menuItemLookup = new Dictionary(); - - private void Remove(IAvnAppMenuItem item) - { - _menuItemLookup.Remove(item.Managed); - _menuItems.Remove(item); - item.Remove(); - - RemoveItem(item); - } - - internal void Remove() - { - ((INotifyCollectionChanged)_menu.Items).CollectionChanged -= IAvnAppMenu_CollectionChanged; - _exporter = null; - _menu = null; - } - - private void InsertAt(int index, IAvnAppMenuItem item) - { - if (item.Managed == null) - { - throw new InvalidOperationException("Cannot insert item that with Managed link null"); - } - - _menuItemLookup.Add(item.Managed, item); - _menuItems.Insert(index, item); - - AddItem(item); // todo change to insertatimpl - } - - private IAvnAppMenuItem CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item) - { - var nativeItem = item is NativeMenuItemSeperator ? factory.CreateMenuItemSeperator() : factory.CreateMenuItem(); - nativeItem.Managed = item; - - return nativeItem; - } - - internal void Update(AvaloniaNativeMenuExporter exporter, IAvaloniaNativeFactory factory, NativeMenu menu, string title = "") - { - if (_menu == null) - { - _menu = menu; - } - else if (_menu != menu) - { - throw new Exception("Cannot update a menu from another instance"); - } - - _exporter = exporter; - - ((INotifyCollectionChanged)_menu.Items).CollectionChanged += IAvnAppMenu_CollectionChanged; - - if (!string.IsNullOrWhiteSpace(title)) - { - using (var buffer = new Utf8Buffer(title)) - { - Title = buffer.DangerousGetHandle(); - } - } - - for (int i = 0; i < menu.Items.Count; i++) - { - IAvnAppMenuItem nativeItem = null; - if (i >= _menuItems.Count || menu.Items[i] != _menuItems[i].Managed) - { - if (_menuItemLookup.TryGetValue(menu.Items[i], out nativeItem)) - { - Remove(nativeItem); - InsertAt(i, nativeItem); - } - else - { - nativeItem = CreateNew(factory, menu.Items[i]); - InsertAt(i, nativeItem); - } - } - - if (menu.Items[i] is NativeMenuItem nmi) - { - nativeItem.Update(exporter, factory, nmi); - } - } - - for (int i = menu.Items.Count; i < _menuItems.Count; i++) - { - _menuItems.Remove(_menuItems[i]); - } - } - - private void IAvnAppMenu_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - _exporter.QueueReset(); - } - } -} - namespace Avalonia.Native { - public class MenuActionCallback : CallbackBase, IAvnActionCallback - { - private Action _action; - - public MenuActionCallback(Action action) - { - _action = action; - } - - void IAvnActionCallback.Run() - { - _action?.Invoke(); - } - } - - public class PredicateCallback : CallbackBase, IAvnPredicateCallback - { - private Func _predicate; - - public PredicateCallback(Func predicate) - { - _predicate = predicate; - } - - bool IAvnPredicateCallback.Evaluate() - { - return _predicate(); - } - } - class AvaloniaNativeMenuExporter : ITopLevelNativeMenuExporter { private IAvaloniaNativeFactory _factory; @@ -246,8 +37,7 @@ namespace Avalonia.Native public void SetNativeMenu(NativeMenu menu) { - if (_menu == null) - _menu = new NativeMenu(); + _menu = menu == null ? new NativeMenu() : menu; DoLayoutReset(); } diff --git a/src/Avalonia.Native/IAvnAppMenu.cs b/src/Avalonia.Native/IAvnAppMenu.cs new file mode 100644 index 0000000000..8ec6e8d5fa --- /dev/null +++ b/src/Avalonia.Native/IAvnAppMenu.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using Avalonia.Controls; +using Avalonia.Platform.Interop; + +namespace Avalonia.Native.Interop +{ + public partial class IAvnAppMenu + { + private AvaloniaNativeMenuExporter _exporter; + private NativeMenu _menu; + private List _menuItems = new List(); + private Dictionary _menuItemLookup = new Dictionary(); + + private void Remove(IAvnAppMenuItem item) + { + _menuItemLookup.Remove(item.Managed); + _menuItems.Remove(item); + + RemoveItem(item); + } + + internal void Cleanup() + { + foreach(var item in _menuItems) + { + item.Cleanup(); + } + + ((INotifyCollectionChanged)_menu.Items).CollectionChanged -= IAvnAppMenu_CollectionChanged; + _exporter = null; + _menu = null; + } + + private void InsertAt(int index, IAvnAppMenuItem item) + { + if (item.Managed == null) + { + throw new InvalidOperationException("Cannot insert item that with Managed link null"); + } + + _menuItemLookup.Add(item.Managed, item); + _menuItems.Insert(index, item); + + AddItem(item); // todo change to insertatimpl + } + + private IAvnAppMenuItem CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item) + { + var nativeItem = item is NativeMenuItemSeperator ? factory.CreateMenuItemSeperator() : factory.CreateMenuItem(); + nativeItem.Managed = item; + + return nativeItem; + } + + internal void Update(AvaloniaNativeMenuExporter exporter, IAvaloniaNativeFactory factory, NativeMenu menu, string title = "") + { + if (_menu == null) + { + _menu = menu; + } + else if (_menu != menu) + { + Cleanup(); + _menu = menu; + } + + _exporter = exporter; + + ((INotifyCollectionChanged)_menu.Items).CollectionChanged += IAvnAppMenu_CollectionChanged; + + if (!string.IsNullOrWhiteSpace(title)) + { + using (var buffer = new Utf8Buffer(title)) + { + Title = buffer.DangerousGetHandle(); + } + } + + for (int i = 0; i < menu.Items.Count; i++) + { + IAvnAppMenuItem nativeItem = null; + + if (i >= _menuItems.Count || menu.Items[i] != _menuItems[i].Managed) + { + if (_menuItemLookup.TryGetValue(menu.Items[i], out nativeItem)) + { + Remove(nativeItem); + InsertAt(i, nativeItem); + } + else + { + nativeItem = CreateNew(factory, menu.Items[i]); + InsertAt(i, nativeItem); + } + } + + if (menu.Items[i] is NativeMenuItem nmi) + { + nativeItem.Update(exporter, factory, nmi); + } + } + + for (int i = menu.Items.Count; i < _menuItems.Count; i++) + { + Remove(_menuItems[i]); + + _menuItems[i].Cleanup(); + } + } + + private void IAvnAppMenu_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + _exporter.QueueReset(); + } + } +} diff --git a/src/Avalonia.Native/IAvnAppMenuItem.cs b/src/Avalonia.Native/IAvnAppMenuItem.cs new file mode 100644 index 0000000000..f349c59470 --- /dev/null +++ b/src/Avalonia.Native/IAvnAppMenuItem.cs @@ -0,0 +1,83 @@ +using Avalonia.Controls; +using Avalonia.Platform.Interop; + +namespace Avalonia.Native.Interop +{ + public partial class IAvnAppMenuItem + { + private IAvnAppMenu _subMenu; + private AvaloniaNativeMenuExporter _exporter; + + public NativeMenuItemBase Managed { get; set; } + + internal void Update(AvaloniaNativeMenuExporter exporter, IAvaloniaNativeFactory factory, NativeMenuItem item) + { + _exporter = exporter; + + Managed = item; + + Managed.PropertyChanged += Item_PropertyChanged; + + using (var buffer = new Utf8Buffer(item.Header)) + { + Title = buffer.DangerousGetHandle(); + } + + if (item.Gesture != null) + { + using (var buffer = new Utf8Buffer(OsxUnicodeKeys.ConvertOSXSpecialKeyCodes(item.Gesture.Key))) + { + SetGesture(buffer.DangerousGetHandle(), (AvnInputModifiers)item.Gesture.KeyModifiers); + } + } + + SetAction(new PredicateCallback(() => + { + if (item.Command != null || item.HasClickHandlers) + { + return item.Enabled; + } + + return false; + }), new MenuActionCallback(() => { item.RaiseClick(); })); + + if (item.Menu != null) + { + if (_subMenu == null) + { + _subMenu = factory.CreateMenu(); + } + + _subMenu.Update(exporter, factory, item.Menu); + } + + if (item.Menu == null && _subMenu != null) + { + _subMenu.Cleanup(); + + // todo remove submenu. + + // needs implementing on native side also. + } + } + + private void Item_PropertyChanged(object sender, AvaloniaPropertyChangedEventArgs e) + { + _exporter.QueueReset(); + } + + internal void Cleanup() + { + Managed.PropertyChanged -= Item_PropertyChanged; + + if (_subMenu != null) + { + _subMenu.Cleanup(); + } + + _subMenu = null; + _exporter = null; + Managed = null; + } + } +} diff --git a/src/Avalonia.Native/MenuActionCallback.cs b/src/Avalonia.Native/MenuActionCallback.cs new file mode 100644 index 0000000000..5318195f30 --- /dev/null +++ b/src/Avalonia.Native/MenuActionCallback.cs @@ -0,0 +1,20 @@ +using System; +using Avalonia.Native.Interop; + +namespace Avalonia.Native +{ + public class MenuActionCallback : CallbackBase, IAvnActionCallback + { + private Action _action; + + public MenuActionCallback(Action action) + { + _action = action; + } + + void IAvnActionCallback.Run() + { + _action?.Invoke(); + } + } +} diff --git a/src/Avalonia.Native/PredicateCallback.cs b/src/Avalonia.Native/PredicateCallback.cs new file mode 100644 index 0000000000..1ed2ae36af --- /dev/null +++ b/src/Avalonia.Native/PredicateCallback.cs @@ -0,0 +1,20 @@ +using System; +using Avalonia.Native.Interop; + +namespace Avalonia.Native +{ + public class PredicateCallback : CallbackBase, IAvnPredicateCallback + { + private Func _predicate; + + public PredicateCallback(Func predicate) + { + _predicate = predicate; + } + + bool IAvnPredicateCallback.Evaluate() + { + return _predicate(); + } + } +}