using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Reactive; using System.Reactive.Linq; using DynamicData; using DynamicData.Alias; using Intromat.Actions.Network; using Intromat.Interfaces; using Intromat.Nodes; using Intromat.ViewModels.Nodes; using Intromat.Views; using NodeNetwork; using NodeNetwork.ViewModels; using NodeNetwork.Views; using ReactiveUI; namespace Intromat.ViewModels { public class CodeGenNetworkViewModel : NetworkViewModel, IRefreshProperties { private readonly ObservableAsPropertyHelper _entryPoint; private readonly ObservableAsPropertyHelper _selectedObject; private string? _name; private CodeGenNetworkViewModel? _parentNetwork; private int _defaultWidth = 10; private int _defaultHeight = 10; static CodeGenNetworkViewModel() { NNViewRegistrar.AddRegistration(() => new CodeGenNetworkView(), typeof(IViewFor)); } public CodeGenNetworkViewModel(DocumentViewModel document, string name) { _name = name; Document = document; ConnectionFactory = (input, output) => new CodeGenConnectionViewModel(this, input, output); Observable.Select(SelectedNodes.Connect(), _ => SelectedNodes.Count == 1 ? SelectedNodes.Items.First() : (ReactiveObject)this) .StartWith(this) .Cast() .ToProperty(this, vm => vm.SelectedObject, out _selectedObject); var nodes = Nodes.Connect(); Observable.Select(nodes, _ => (MainEntryPointNode?)Nodes.Items.FirstOrDefault(vm => vm is MainEntryPointNode)) .ToProperty(this, vm => vm.EntryPoint, out _entryPoint); nodes.ActOnEveryObject(OnNodeAdded, OnNodeDeleted); var a = Nodes.Connect() .AutoRefreshOnObservable(node => node.Inputs.Connect()) .SelectMany(node => node.Inputs.Items) .AutoRefreshOnObservable(input => input.Connections.Connect()) .SelectMany(input => input.Connections.Items); var b = Nodes.Connect() .AutoRefreshOnObservable(node => node.Outputs.Connect()) .SelectMany(node => node.Outputs.Items) .AutoRefreshOnObservable(output => output.Connections.Connect()) .SelectMany(output => output.Connections.Items); a.Zip(b, (x, _) => x).ActOnEveryObject(OnConnectionAdded, OnConnectionDeleted); GroupNodes = ReactiveCommand.CreateFromTask(async () => { var mainVm = document.MainViewModel; var groupName = await mainVm.SelectName.Handle("Group name:"); if (groupName == null) return; var groupBinding = (CodeNodeGroupIOBinding?)mainVm.Grouper.MergeIntoGroup(this, SelectedNodes.Items); if (groupBinding == null) return; var groupNode = (GroupNodeViewModel)groupBinding.GroupNode; var subNet = (CodeGenNetworkViewModel)groupNode.Subnet!; groupNode.Name = subNet.Name = groupName; groupNode.IOBinding = groupBinding; ((GroupSubnetIONodeViewModel)groupBinding.EntranceNode).IOBinding = groupBinding; ((GroupSubnetIONodeViewModel)groupBinding.ExitNode).IOBinding = groupBinding; }, this.WhenAnyObservable(vm => vm.SelectedNodes.CountChanged).Select(c => c > 1)); var isGroupNodeSelected = this.WhenAnyValue(vm => vm.SelectedNodes.CountChanged).Select(_ => SelectedNodes.Count == 1 && SelectedNodes.Items.First() is GroupNodeViewModel); UngroupNodes = ReactiveCommand.Create(() => { var selectedGroupNode = (GroupNodeViewModel)SelectedNodes.Items.First(); var mainVm = document.MainViewModel; mainVm.Grouper.Ungroup(selectedGroupNode.IOBinding); }, isGroupNodeSelected); OpenGroup = ReactiveCommand.Create(() => { var selectedGroupNode = (GroupNodeViewModel)SelectedNodes.Items.First(); Debug.Assert(selectedGroupNode.Subnet != null, "selectedGroupNode.Subnet != null"); document.NetworkBreadcrumbBar.ActivePath.Add(new NetworkBreadcrumbViewModel { ViewModel = selectedGroupNode.Subnet, Name = selectedGroupNode.Name }); }, isGroupNodeSelected); } public IObservableList? PropertyDescriptors => null; public CodeGenNetworkViewModel? ParentNetwork { get => _parentNetwork; set => this.RaiseAndSetIfChanged(ref _parentNetwork, value); } public IRefreshProperties? SelectedObject => _selectedObject.Value; public MainEntryPointNode? EntryPoint => _entryPoint.Value; public DocumentViewModel Document { get; } public string? Name { get => _name; set => this.RaiseAndSetIfChanged(ref _name, value); } public int DefaultWidth { get => _defaultWidth; set => this.RaiseAndSetIfChanged(ref _defaultWidth, value); } public int DefaultHeight { get => _defaultHeight; set => this.RaiseAndSetIfChanged(ref _defaultHeight, value); } protected override void OnDeleteSelectedNodes() { var undoRedo = Document.MainViewModel.UndoRedo; undoRedo.PushGroup(Document); base.OnDeleteSelectedNodes(); undoRedo.PopGroup(); } public override void FinishCut() { var undoRedo = Document.MainViewModel.UndoRedo; undoRedo.PushGroup(Document); base.FinishCut(); undoRedo.PopGroup(); } private void OnNodeDeleted(NodeViewModel node) { Document.MainViewModel.UndoRedo.Record(new DeleteNodeAction(Document, this, node)); } private void OnNodeAdded(NodeViewModel node) { Document.MainViewModel.UndoRedo.Record(new AddNodeAction(Document, this, node)); } private void OnConnectionDeleted(ConnectionViewModel connection) { Document.MainViewModel.UndoRedo.Record(new DeleteConnectionAction(Document, this, connection)); } private void OnConnectionAdded(ConnectionViewModel connection) { Document.MainViewModel.UndoRedo.Record(new AddConnectionAction(Document, this, connection)); } public ReactiveCommand GroupNodes { get; } public ReactiveCommand UngroupNodes { get; } public ReactiveCommand OpenGroup { get; } } }