Files
bluflame/intromat/Intromat/ViewModels/CodeGenNetworkViewModel.cs
2026-04-18 22:31:51 +02:00

176 lines
6.9 KiB
C#

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<MainEntryPointNode?> _entryPoint;
private readonly ObservableAsPropertyHelper<IRefreshProperties?> _selectedObject;
private string? _name;
private CodeGenNetworkViewModel? _parentNetwork;
private int _defaultWidth = 10;
private int _defaultHeight = 10;
static CodeGenNetworkViewModel()
{
NNViewRegistrar.AddRegistration(() => new CodeGenNetworkView(), typeof(IViewFor<CodeGenNetworkViewModel>));
}
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<IRefreshProperties>()
.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<PropertyDescriptor>? 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<Unit, Unit> GroupNodes { get; }
public ReactiveCommand<Unit, Unit> UngroupNodes { get; }
public ReactiveCommand<Unit, Unit> OpenGroup { get; }
}
}