Browse Source

move code to own files.

pull/3762/head
Dan Walmsley 6 years ago
parent
commit
0f35059055
  1. 212
      src/Avalonia.Native/AvaloniaNativeMenuExporter.cs
  2. 118
      src/Avalonia.Native/IAvnAppMenu.cs
  3. 83
      src/Avalonia.Native/IAvnAppMenuItem.cs
  4. 20
      src/Avalonia.Native/MenuActionCallback.cs
  5. 20
      src/Avalonia.Native/PredicateCallback.cs

212
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<IAvnAppMenuItem> _menuItems = new List<IAvnAppMenuItem>();
private Dictionary<NativeMenuItemBase, IAvnAppMenuItem> _menuItemLookup = new Dictionary<NativeMenuItemBase, IAvnAppMenuItem>();
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<bool> _predicate;
public PredicateCallback(Func<bool> 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();
}

118
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<IAvnAppMenuItem> _menuItems = new List<IAvnAppMenuItem>();
private Dictionary<NativeMenuItemBase, IAvnAppMenuItem> _menuItemLookup = new Dictionary<NativeMenuItemBase, IAvnAppMenuItem>();
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();
}
}
}

83
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;
}
}
}

20
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();
}
}
}

20
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<bool> _predicate;
public PredicateCallback(Func<bool> predicate)
{
_predicate = predicate;
}
bool IAvnPredicateCallback.Evaluate()
{
return _predicate();
}
}
}
Loading…
Cancel
Save