using Eto.Forms; namespace NAPS2.EtoForms; public class MenuProvider { private readonly List _items = []; public MenuProvider Dynamic(ListProvider commandListProvider) { _items.Add(new DynamicItem { CommandListProvider = commandListProvider ?? throw new ArgumentNullException(nameof(commandListProvider)) }); commandListProvider.OnChanged += () => ContentsChanged?.Invoke(); return this; } public MenuProvider Append(Command? command) { if (command == null) { return this; } _items.Add(new CommandItem { Command = command }); return this; } public MenuProvider Separator() { _items.Add(new SeparatorItem()); return this; } public MenuProvider SubMenu(Command command, MenuProvider subMenu) { _items.Add(new SubMenuItem { Command = command ?? throw new ArgumentNullException(nameof(command)), MenuProvider = subMenu }); return this; } private event Action? ContentsChanged; public class Item { } private class DynamicItem : Item { public ListProvider CommandListProvider { get; init; } = null!; } public class CommandItem : Item { public Command Command { get; init; } = null!; } public class SubMenuItem : Item { public Command Command { get; init; } = null!; public MenuProvider MenuProvider { get; init; } = null!; } public class SeparatorItem : Item { } private List GetSubItems() { var actualItems = new List(); Item? lastItem = null; foreach (var item in _items) { if (item is DynamicItem dynamicItem) { var dynamicItemValues = dynamicItem.CommandListProvider.Value.Select(x => new CommandItem { Command = x }).ToList(); if (dynamicItemValues.Any()) { actualItems.AddRange(dynamicItemValues); lastItem = item; } } else if (item is not SeparatorItem || (lastItem != null && lastItem is not SeparatorItem)) { actualItems.Add(item); lastItem = item; } } return actualItems; } public void Handle(Action> subItemsHandler) { subItemsHandler(GetSubItems()); ContentsChanged += () => subItemsHandler(GetSubItems()); } }