committed by
GitHub
26 changed files with 944 additions and 591 deletions
@ -0,0 +1,7 @@ |
|||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
public interface INativeMenuExporterEventsImplBridge |
||||
|
{ |
||||
|
void RaiseNeedsUpdate (); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Avalonia.Controls |
||||
|
{ |
||||
|
public interface INativeMenuItemExporterEventsImplBridge |
||||
|
{ |
||||
|
void RaiseClicked (); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,176 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Specialized; |
||||
|
using System.Reactive.Disposables; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Platform.Interop; |
||||
|
|
||||
|
namespace Avalonia.Native.Interop |
||||
|
{ |
||||
|
class MenuEvents : CallbackBase, IAvnMenuEvents |
||||
|
{ |
||||
|
private IAvnMenu _parent; |
||||
|
|
||||
|
public void Initialise(IAvnMenu parent) |
||||
|
{ |
||||
|
_parent = parent; |
||||
|
} |
||||
|
|
||||
|
public void NeedsUpdate() |
||||
|
{ |
||||
|
_parent?.RaiseNeedsUpdate(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public partial class IAvnMenu |
||||
|
{ |
||||
|
private MenuEvents _events; |
||||
|
private AvaloniaNativeMenuExporter _exporter; |
||||
|
private List<IAvnMenuItem> _menuItems = new List<IAvnMenuItem>(); |
||||
|
private Dictionary<NativeMenuItemBase, IAvnMenuItem> _menuItemLookup = new Dictionary<NativeMenuItemBase, IAvnMenuItem>(); |
||||
|
private CompositeDisposable _propertyDisposables = new CompositeDisposable(); |
||||
|
|
||||
|
internal void RaiseNeedsUpdate() |
||||
|
{ |
||||
|
(ManagedMenu as INativeMenuExporterEventsImplBridge).RaiseNeedsUpdate(); |
||||
|
|
||||
|
_exporter.UpdateIfNeeded(); |
||||
|
} |
||||
|
|
||||
|
internal NativeMenu ManagedMenu { get; private set; } |
||||
|
|
||||
|
public static IAvnMenu Create(IAvaloniaNativeFactory factory) |
||||
|
{ |
||||
|
var events = new MenuEvents(); |
||||
|
|
||||
|
var menu = factory.CreateMenu(events); |
||||
|
|
||||
|
events.Initialise(menu); |
||||
|
|
||||
|
menu._events = events; |
||||
|
|
||||
|
return menu; |
||||
|
} |
||||
|
|
||||
|
protected override void Dispose(bool disposing) |
||||
|
{ |
||||
|
if (disposing) |
||||
|
{ |
||||
|
_events.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void RemoveAndDispose(IAvnMenuItem item) |
||||
|
{ |
||||
|
_menuItemLookup.Remove(item.ManagedMenuItem); |
||||
|
_menuItems.Remove(item); |
||||
|
RemoveItem(item); |
||||
|
|
||||
|
item.Deinitialise(); |
||||
|
item.Dispose(); |
||||
|
} |
||||
|
|
||||
|
private void MoveExistingTo(int index, IAvnMenuItem item) |
||||
|
{ |
||||
|
_menuItems.Remove(item); |
||||
|
_menuItems.Insert(index, item); |
||||
|
|
||||
|
RemoveItem(item); |
||||
|
InsertItem(index, item); |
||||
|
} |
||||
|
|
||||
|
private IAvnMenuItem CreateNewAt(IAvaloniaNativeFactory factory, int index, NativeMenuItemBase item) |
||||
|
{ |
||||
|
var result = CreateNew(factory, item); |
||||
|
|
||||
|
result.Initialise(item); |
||||
|
|
||||
|
_menuItemLookup.Add(result.ManagedMenuItem, result); |
||||
|
_menuItems.Insert(index, result); |
||||
|
|
||||
|
InsertItem(index, result); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private IAvnMenuItem CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item) |
||||
|
{ |
||||
|
var nativeItem = item is NativeMenuItemSeperator ? factory.CreateMenuItemSeperator() : factory.CreateMenuItem(); |
||||
|
nativeItem.ManagedMenuItem = item; |
||||
|
|
||||
|
return nativeItem; |
||||
|
} |
||||
|
|
||||
|
internal void Initialise(AvaloniaNativeMenuExporter exporter, NativeMenu managedMenu, string title) |
||||
|
{ |
||||
|
_exporter = exporter; |
||||
|
ManagedMenu = managedMenu; |
||||
|
|
||||
|
((INotifyCollectionChanged)ManagedMenu.Items).CollectionChanged += OnMenuItemsChanged; |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(title)) |
||||
|
{ |
||||
|
using (var buffer = new Utf8Buffer(title)) |
||||
|
{ |
||||
|
Title = buffer.DangerousGetHandle(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal void Deinitialise() |
||||
|
{ |
||||
|
((INotifyCollectionChanged)ManagedMenu.Items).CollectionChanged -= OnMenuItemsChanged; |
||||
|
|
||||
|
foreach (var item in _menuItems) |
||||
|
{ |
||||
|
item.Deinitialise(); |
||||
|
item.Dispose(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal void Update(IAvaloniaNativeFactory factory, NativeMenu menu) |
||||
|
{ |
||||
|
if (menu != ManagedMenu) |
||||
|
{ |
||||
|
throw new ArgumentException("The menu being updated does not match.", nameof(menu)); |
||||
|
} |
||||
|
|
||||
|
for (int i = 0; i < menu.Items.Count; i++) |
||||
|
{ |
||||
|
IAvnMenuItem nativeItem; |
||||
|
|
||||
|
if (i >= _menuItems.Count) |
||||
|
{ |
||||
|
nativeItem = CreateNewAt(factory, i, menu.Items[i]); |
||||
|
} |
||||
|
else if (menu.Items[i] == _menuItems[i].ManagedMenuItem) |
||||
|
{ |
||||
|
nativeItem = _menuItems[i]; |
||||
|
} |
||||
|
else if (_menuItemLookup.TryGetValue(menu.Items[i], out nativeItem)) |
||||
|
{ |
||||
|
MoveExistingTo(i, nativeItem); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
nativeItem = CreateNewAt(factory, i, menu.Items[i]); |
||||
|
} |
||||
|
|
||||
|
if (menu.Items[i] is NativeMenuItem nmi) |
||||
|
{ |
||||
|
nativeItem.Update(_exporter, factory, nmi); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
while (_menuItems.Count > menu.Items.Count) |
||||
|
{ |
||||
|
RemoveAndDispose(_menuItems[_menuItems.Count - 1]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void OnMenuItemsChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
|
{ |
||||
|
_exporter.QueueReset(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,136 @@ |
|||||
|
using System; |
||||
|
using System.Reactive.Disposables; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Platform.Interop; |
||||
|
|
||||
|
namespace Avalonia.Native.Interop |
||||
|
{ |
||||
|
public partial class IAvnMenuItem |
||||
|
{ |
||||
|
private IAvnMenu _subMenu; |
||||
|
private CompositeDisposable _propertyDisposables = new CompositeDisposable(); |
||||
|
private IDisposable _currentActionDisposable; |
||||
|
|
||||
|
public NativeMenuItemBase ManagedMenuItem { get; set; } |
||||
|
|
||||
|
private void UpdateTitle(string title) |
||||
|
{ |
||||
|
using (var buffer = new Utf8Buffer(string.IsNullOrWhiteSpace(title) ? "" : title)) |
||||
|
{ |
||||
|
Title = buffer.DangerousGetHandle(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void UpdateIsChecked(bool isChecked) |
||||
|
{ |
||||
|
IsChecked = isChecked; |
||||
|
} |
||||
|
|
||||
|
private void UpdateGesture(Input.KeyGesture gesture) |
||||
|
{ |
||||
|
// todo ensure backend can cope with setting null gesture.
|
||||
|
using (var buffer = new Utf8Buffer(gesture == null ? "" : OsxUnicodeKeys.ConvertOSXSpecialKeyCodes(gesture.Key))) |
||||
|
{ |
||||
|
var modifiers = gesture == null ? AvnInputModifiers.AvnInputModifiersNone : (AvnInputModifiers)gesture.KeyModifiers; |
||||
|
SetGesture(buffer.DangerousGetHandle(), modifiers); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void UpdateAction(NativeMenuItem item) |
||||
|
{ |
||||
|
_currentActionDisposable?.Dispose(); |
||||
|
|
||||
|
var action = new PredicateCallback(() => |
||||
|
{ |
||||
|
if (item.Command != null || item.HasClickHandlers) |
||||
|
{ |
||||
|
return item.IsEnabled; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
}); |
||||
|
|
||||
|
var callback = new MenuActionCallback(() => { (item as INativeMenuItemExporterEventsImplBridge)?.RaiseClicked(); }); |
||||
|
|
||||
|
_currentActionDisposable = Disposable.Create(() => |
||||
|
{ |
||||
|
action.Dispose(); |
||||
|
callback.Dispose(); |
||||
|
}); |
||||
|
|
||||
|
SetAction(action, callback); |
||||
|
} |
||||
|
|
||||
|
internal void Initialise(NativeMenuItemBase nativeMenuItem) |
||||
|
{ |
||||
|
ManagedMenuItem = nativeMenuItem; |
||||
|
|
||||
|
if (ManagedMenuItem is NativeMenuItem item) |
||||
|
{ |
||||
|
UpdateTitle(item.Header); |
||||
|
|
||||
|
UpdateGesture(item.Gesture); |
||||
|
|
||||
|
UpdateAction(ManagedMenuItem as NativeMenuItem); |
||||
|
|
||||
|
UpdateIsChecked(item.IsChecked); |
||||
|
|
||||
|
_propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.HeaderProperty) |
||||
|
.Subscribe(x => UpdateTitle(x))); |
||||
|
|
||||
|
_propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.GestureProperty) |
||||
|
.Subscribe(x => UpdateGesture(x))); |
||||
|
|
||||
|
_propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.CommandProperty) |
||||
|
.Subscribe(x => UpdateAction(ManagedMenuItem as NativeMenuItem))); |
||||
|
|
||||
|
_propertyDisposables.Add(ManagedMenuItem.GetObservable(NativeMenuItem.IsCheckedProperty) |
||||
|
.Subscribe(x => UpdateIsChecked(x))); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal void Deinitialise() |
||||
|
{ |
||||
|
if (_subMenu != null) |
||||
|
{ |
||||
|
SetSubMenu(null); |
||||
|
_subMenu.Deinitialise(); |
||||
|
_subMenu.Dispose(); |
||||
|
_subMenu = null; |
||||
|
} |
||||
|
|
||||
|
_propertyDisposables?.Dispose(); |
||||
|
_currentActionDisposable?.Dispose(); |
||||
|
} |
||||
|
|
||||
|
internal void Update(AvaloniaNativeMenuExporter exporter, IAvaloniaNativeFactory factory, NativeMenuItem item) |
||||
|
{ |
||||
|
if (item != ManagedMenuItem) |
||||
|
{ |
||||
|
throw new ArgumentException("The item does not match the menuitem being updated.", nameof(item)); |
||||
|
} |
||||
|
|
||||
|
if (item.Menu != null) |
||||
|
{ |
||||
|
if (_subMenu == null) |
||||
|
{ |
||||
|
_subMenu = IAvnMenu.Create(factory); |
||||
|
|
||||
|
_subMenu.Initialise(exporter, item.Menu, item.Header); |
||||
|
|
||||
|
SetSubMenu(_subMenu); |
||||
|
} |
||||
|
|
||||
|
_subMenu.Update(factory, item.Menu); |
||||
|
} |
||||
|
|
||||
|
if (item.Menu == null && _subMenu != null) |
||||
|
{ |
||||
|
_subMenu.Deinitialise(); |
||||
|
_subMenu.Dispose(); |
||||
|
|
||||
|
SetSubMenu(null); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,147 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using Avalonia.Input; |
||||
|
|
||||
|
namespace Avalonia.Native.Interop |
||||
|
{ |
||||
|
internal static class OsxUnicodeKeys |
||||
|
{ |
||||
|
enum OsxUnicodeSpecialKey |
||||
|
{ |
||||
|
NSUpArrowFunctionKey = 0xF700, |
||||
|
NSDownArrowFunctionKey = 0xF701, |
||||
|
NSLeftArrowFunctionKey = 0xF702, |
||||
|
NSRightArrowFunctionKey = 0xF703, |
||||
|
NSF1FunctionKey = 0xF704, |
||||
|
NSF2FunctionKey = 0xF705, |
||||
|
NSF3FunctionKey = 0xF706, |
||||
|
NSF4FunctionKey = 0xF707, |
||||
|
NSF5FunctionKey = 0xF708, |
||||
|
NSF6FunctionKey = 0xF709, |
||||
|
NSF7FunctionKey = 0xF70A, |
||||
|
NSF8FunctionKey = 0xF70B, |
||||
|
NSF9FunctionKey = 0xF70C, |
||||
|
NSF10FunctionKey = 0xF70D, |
||||
|
NSF11FunctionKey = 0xF70E, |
||||
|
NSF12FunctionKey = 0xF70F, |
||||
|
NSF13FunctionKey = 0xF710, |
||||
|
NSF14FunctionKey = 0xF711, |
||||
|
NSF15FunctionKey = 0xF712, |
||||
|
NSF16FunctionKey = 0xF713, |
||||
|
NSF17FunctionKey = 0xF714, |
||||
|
NSF18FunctionKey = 0xF715, |
||||
|
NSF19FunctionKey = 0xF716, |
||||
|
NSF20FunctionKey = 0xF717, |
||||
|
NSF21FunctionKey = 0xF718, |
||||
|
NSF22FunctionKey = 0xF719, |
||||
|
NSF23FunctionKey = 0xF71A, |
||||
|
NSF24FunctionKey = 0xF71B, |
||||
|
NSF25FunctionKey = 0xF71C, |
||||
|
NSF26FunctionKey = 0xF71D, |
||||
|
NSF27FunctionKey = 0xF71E, |
||||
|
NSF28FunctionKey = 0xF71F, |
||||
|
NSF29FunctionKey = 0xF720, |
||||
|
NSF30FunctionKey = 0xF721, |
||||
|
NSF31FunctionKey = 0xF722, |
||||
|
NSF32FunctionKey = 0xF723, |
||||
|
NSF33FunctionKey = 0xF724, |
||||
|
NSF34FunctionKey = 0xF725, |
||||
|
NSF35FunctionKey = 0xF726, |
||||
|
NSInsertFunctionKey = 0xF727, |
||||
|
NSDeleteFunctionKey = 0xF728, |
||||
|
NSHomeFunctionKey = 0xF729, |
||||
|
NSBeginFunctionKey = 0xF72A, |
||||
|
NSEndFunctionKey = 0xF72B, |
||||
|
NSPageUpFunctionKey = 0xF72C, |
||||
|
NSPageDownFunctionKey = 0xF72D, |
||||
|
NSPrintScreenFunctionKey = 0xF72E, |
||||
|
NSScrollLockFunctionKey = 0xF72F, |
||||
|
NSPauseFunctionKey = 0xF730, |
||||
|
NSSysReqFunctionKey = 0xF731, |
||||
|
NSBreakFunctionKey = 0xF732, |
||||
|
NSResetFunctionKey = 0xF733, |
||||
|
NSStopFunctionKey = 0xF734, |
||||
|
NSMenuFunctionKey = 0xF735, |
||||
|
NSUserFunctionKey = 0xF736, |
||||
|
NSSystemFunctionKey = 0xF737, |
||||
|
NSPrintFunctionKey = 0xF738, |
||||
|
NSClearLineFunctionKey = 0xF739, |
||||
|
NSClearDisplayFunctionKey = 0xF73A, |
||||
|
NSInsertLineFunctionKey = 0xF73B, |
||||
|
NSDeleteLineFunctionKey = 0xF73C, |
||||
|
NSInsertCharFunctionKey = 0xF73D, |
||||
|
NSDeleteCharFunctionKey = 0xF73E, |
||||
|
NSPrevFunctionKey = 0xF73F, |
||||
|
NSNextFunctionKey = 0xF740, |
||||
|
NSSelectFunctionKey = 0xF741, |
||||
|
NSExecuteFunctionKey = 0xF742, |
||||
|
NSUndoFunctionKey = 0xF743, |
||||
|
NSRedoFunctionKey = 0xF744, |
||||
|
NSFindFunctionKey = 0xF745, |
||||
|
NSHelpFunctionKey = 0xF746, |
||||
|
NSModeSwitchFunctionKey = 0xF747 |
||||
|
} |
||||
|
|
||||
|
private static Dictionary<Key, OsxUnicodeSpecialKey> s_osxKeys = new Dictionary<Key, OsxUnicodeSpecialKey> |
||||
|
{ |
||||
|
{Key.Up, OsxUnicodeSpecialKey.NSUpArrowFunctionKey }, |
||||
|
{Key.Down, OsxUnicodeSpecialKey.NSDownArrowFunctionKey }, |
||||
|
{Key.Left, OsxUnicodeSpecialKey.NSLeftArrowFunctionKey }, |
||||
|
{Key.Right, OsxUnicodeSpecialKey.NSRightArrowFunctionKey }, |
||||
|
{ Key.F1, OsxUnicodeSpecialKey.NSF1FunctionKey }, |
||||
|
{ Key.F2, OsxUnicodeSpecialKey.NSF2FunctionKey }, |
||||
|
{ Key.F3, OsxUnicodeSpecialKey.NSF3FunctionKey }, |
||||
|
{ Key.F4, OsxUnicodeSpecialKey.NSF4FunctionKey }, |
||||
|
{ Key.F5, OsxUnicodeSpecialKey.NSF5FunctionKey }, |
||||
|
{ Key.F6, OsxUnicodeSpecialKey.NSF6FunctionKey }, |
||||
|
{ Key.F7, OsxUnicodeSpecialKey.NSF7FunctionKey }, |
||||
|
{ Key.F8, OsxUnicodeSpecialKey.NSF8FunctionKey }, |
||||
|
{ Key.F9, OsxUnicodeSpecialKey.NSF9FunctionKey }, |
||||
|
{ Key.F10, OsxUnicodeSpecialKey.NSF10FunctionKey }, |
||||
|
{ Key.F11, OsxUnicodeSpecialKey.NSF11FunctionKey }, |
||||
|
{ Key.F12, OsxUnicodeSpecialKey.NSF12FunctionKey }, |
||||
|
{ Key.F13, OsxUnicodeSpecialKey.NSF13FunctionKey }, |
||||
|
{ Key.F14, OsxUnicodeSpecialKey.NSF14FunctionKey }, |
||||
|
{ Key.F15, OsxUnicodeSpecialKey.NSF15FunctionKey }, |
||||
|
{ Key.F16, OsxUnicodeSpecialKey.NSF16FunctionKey }, |
||||
|
{ Key.F17, OsxUnicodeSpecialKey.NSF17FunctionKey }, |
||||
|
{ Key.F18, OsxUnicodeSpecialKey.NSF18FunctionKey }, |
||||
|
{ Key.F19, OsxUnicodeSpecialKey.NSF19FunctionKey }, |
||||
|
{ Key.F20, OsxUnicodeSpecialKey.NSF20FunctionKey }, |
||||
|
{ Key.F21, OsxUnicodeSpecialKey.NSF21FunctionKey }, |
||||
|
{ Key.F22, OsxUnicodeSpecialKey.NSF22FunctionKey }, |
||||
|
{ Key.F23, OsxUnicodeSpecialKey.NSF23FunctionKey }, |
||||
|
{ Key.F24, OsxUnicodeSpecialKey.NSF24FunctionKey }, |
||||
|
{ Key.Insert, OsxUnicodeSpecialKey.NSInsertFunctionKey }, |
||||
|
{ Key.Delete, OsxUnicodeSpecialKey.NSDeleteFunctionKey }, |
||||
|
{ Key.Home, OsxUnicodeSpecialKey.NSHomeFunctionKey }, |
||||
|
//{ Key.Begin, OsxUnicodeSpecialKey.NSBeginFunctionKey },
|
||||
|
{ Key.End, OsxUnicodeSpecialKey.NSEndFunctionKey }, |
||||
|
{ Key.PageUp, OsxUnicodeSpecialKey.NSPageUpFunctionKey }, |
||||
|
{ Key.PageDown, OsxUnicodeSpecialKey.NSPageDownFunctionKey }, |
||||
|
{ Key.PrintScreen, OsxUnicodeSpecialKey.NSPrintScreenFunctionKey }, |
||||
|
{ Key.Scroll, OsxUnicodeSpecialKey.NSScrollLockFunctionKey }, |
||||
|
//{ Key.SysReq, OsxUnicodeSpecialKey.NSSysReqFunctionKey },
|
||||
|
//{ Key.Break, OsxUnicodeSpecialKey.NSBreakFunctionKey },
|
||||
|
//{ Key.Reset, OsxUnicodeSpecialKey.NSResetFunctionKey },
|
||||
|
//{ Key.Stop, OsxUnicodeSpecialKey.NSStopFunctionKey },
|
||||
|
//{ Key.Menu, OsxUnicodeSpecialKey.NSMenuFunctionKey },
|
||||
|
//{ Key.UserFunction, OsxUnicodeSpecialKey.NSUserFunctionKey },
|
||||
|
//{ Key.SystemFunction, OsxUnicodeSpecialKey.NSSystemFunctionKey },
|
||||
|
{ Key.Print, OsxUnicodeSpecialKey.NSPrintFunctionKey }, |
||||
|
//{ Key.ClearLine, OsxUnicodeSpecialKey.NSClearLineFunctionKey },
|
||||
|
//{ Key.ClearDisplay, OsxUnicodeSpecialKey.NSClearDisplayFunctionKey },
|
||||
|
}; |
||||
|
|
||||
|
public static string ConvertOSXSpecialKeyCodes(Key key) |
||||
|
{ |
||||
|
if (s_osxKeys.ContainsKey(key)) |
||||
|
{ |
||||
|
return ((char)s_osxKeys[key]).ToString(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return key.ToString().ToLower(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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…
Reference in new issue