using System.Collections.ObjectModel; using Avalonia; using ChunkyImageLib; using CommunityToolkit.Mvvm.ComponentModel; using PixiEditor.AvaloniaUI.Models.DocumentModels; using PixiEditor.AvaloniaUI.Models.Handlers; using PixiEditor.AvaloniaUI.Models.Structures; using PixiEditor.AvaloniaUI.ViewModels.Document; using PixiEditor.ChangeableDocument.Actions.Generated; using PixiEditor.ChangeableDocument.Changeables.Interfaces; using PixiEditor.Numerics; namespace PixiEditor.AvaloniaUI.ViewModels.Nodes; internal class NodeViewModel : ObservableObject, INodeHandler { private string nodeName; private VecD position; private ObservableRangeCollection inputs = new(); private ObservableRangeCollection outputs = new(); private Surface resultPreview; private bool isSelected; protected Guid id; public Guid Id { get => id; init => id = value; } public string NodeName { get => nodeName; set => SetProperty(ref nodeName, value); } public VecD PositionBindable { get => position; set { if (!Document.UpdateableChangeActive) { Internals.ActionAccumulator.AddFinishedActions( new NodePosition_Action(Id, value), new EndNodePosition_Action()); } } } public ObservableRangeCollection Inputs { get => inputs; set => SetProperty(ref inputs, value); } public ObservableRangeCollection Outputs { get => outputs; set => SetProperty(ref outputs, value); } public Surface ResultPreview { get => resultPreview; set => SetProperty(ref resultPreview, value); } public bool IsSelected { get => isSelected; set => SetProperty(ref isSelected, value); } internal DocumentViewModel Document { get; init; } internal DocumentInternalParts Internals { get; init; } public NodeViewModel() { } public NodeViewModel(string nodeName, Guid id, VecD position, DocumentViewModel document, DocumentInternalParts internals) { this.nodeName = nodeName; this.id = id; this.position = position; Document = document; Internals = internals; } public void SetPosition(VecD newPosition) { position = newPosition; OnPropertyChanged(nameof(PositionBindable)); } public void TraverseBackwards(Func func) { var visited = new HashSet(); var queueNodes = new Queue(); queueNodes.Enqueue(this); while (queueNodes.Count > 0) { var node = queueNodes.Dequeue(); if (!visited.Add(node)) { continue; } if (!func(node)) { return; } foreach (var inputProperty in node.Inputs) { if (inputProperty.ConnectedOutput != null) { queueNodes.Enqueue(inputProperty.ConnectedOutput.Node); } } } } public void TraverseForwards(Func func) { var visited = new HashSet(); var queueNodes = new Queue(); queueNodes.Enqueue(this); while (queueNodes.Count > 0) { var node = queueNodes.Dequeue(); if (!visited.Add(node)) { continue; } if (!func(node)) { return; } foreach (var outputProperty in node.Outputs) { foreach (var connection in outputProperty.ConnectedInputs) { queueNodes.Enqueue(connection.Node); } } } } public NodePropertyViewModel FindInputProperty(string propName) { return Inputs.FirstOrDefault(x => x.PropertyName == propName) as NodePropertyViewModel; } public NodePropertyViewModel FindOutputProperty(string propName) { return Outputs.FirstOrDefault(x => x.PropertyName == propName) as NodePropertyViewModel; } }