void ProcessDependencyModel(INodeModel nodeModel, GraphViewStateComponent.StateUpdater graphUpdater, Action <IDependency, INodeModel, GraphViewStateComponent.StateUpdater> dependencyCallback) { Log($"ProcessDependencyModel {nodeModel}"); if (!m_DependenciesByNode.TryGetValue(nodeModel.Guid, out var link)) { return; } foreach (var dependency in link) { if (m_ModelsToMove.Contains(dependency.Value.DependentNode)) { continue; } if (!m_TempMovedModels.Add(dependency.Value.DependentNode)) { Log($"Skip ProcessDependency {dependency.Value.DependentNode}"); continue; } dependencyCallback(dependency.Value, nodeModel, graphUpdater); ProcessDependencyModel(dependency.Value.DependentNode, graphUpdater, dependencyCallback); } }
void AlignDependency(IDependency dependency, INodeModel prev, GraphViewStateComponent.StateUpdater graphUpdater) { // Warning: Don't try to use the VisualElement.layout Rect as it is not up to date yet. // Use Node.GetPosition() when possible var parentUI = prev.GetUI <Node>(m_GraphView); var depUI = dependency.DependentNode.GetUI <Node>(m_GraphView); if (parentUI == null || depUI == null) { return; } switch (dependency) { case LinkedNodesDependency linked: Vector2 position; var input = linked.ParentPort.GetUI <Port>(m_GraphView); var output = linked.DependentPort.GetUI <Port>(m_GraphView); if (input?.Model != null && output?.Model != null && ((IPortModel)input.Model).Orientation == ((IPortModel)output.Model).Orientation) { Vector2 inputPortPos = input.parent.ChangeCoordinatesTo(parentUI, input.layout.center); Vector2 inputPos = prev.Position; Vector2 outputPortPos = output.parent.ChangeCoordinatesTo(depUI, output.layout.center); if (((IPortModel)input.Model).Orientation == PortOrientation.Horizontal) { position = new Vector2( prev.Position.x + (linked.ParentPort.Direction == PortDirection.Output ? parentUI.layout.width + k_AlignHorizontalOffset : -k_AlignHorizontalOffset - depUI.layout.width), inputPos.y + inputPortPos.y - outputPortPos.y ); } else { position = new Vector2( inputPos.x + inputPortPos.x - outputPortPos.x, prev.Position.y + (linked.ParentPort.Direction == PortDirection.Output ? parentUI.layout.height + k_AlignVerticalOffset : -k_AlignVerticalOffset - depUI.layout.height) ); } linked.DependentNode.Position = position; graphUpdater.MarkChanged(linked.DependentNode); } break; } }
internal static void PasteSerializedData(IGraphModel graph, Vector2 delta, GraphViewStateComponent.StateUpdater graphViewUpdater, SelectionStateComponent.StateUpdater selectionStateUpdater, CopyPasteData copyPasteData) { var elementMapping = new Dictionary <string, IGraphElementModel>(); if (copyPasteData.variableDeclarations.Any()) { List <IVariableDeclarationModel> variableDeclarationModels = copyPasteData.variableDeclarations.ToList(); List <IVariableDeclarationModel> duplicatedModels = new List <IVariableDeclarationModel>(); foreach (var sourceModel in variableDeclarationModels) { duplicatedModels.Add(graph.DuplicateGraphVariableDeclaration(sourceModel)); } graphViewUpdater?.MarkNew(duplicatedModels); selectionStateUpdater?.SelectElements(duplicatedModels, true); } var nodeMapping = new Dictionary <INodeModel, INodeModel>(); foreach (var originalModel in copyPasteData.nodes) { if (!graph.Stencil.CanPasteNode(originalModel, graph)) { continue; } var pastedNode = graph.DuplicateNode(originalModel, delta); graphViewUpdater?.MarkNew(pastedNode); selectionStateUpdater?.SelectElements(new[] { pastedNode }, true); nodeMapping[originalModel] = pastedNode; } // PF FIXME we could do this in the foreach above foreach (var nodeModel in nodeMapping) { elementMapping.Add(nodeModel.Key.Guid.ToString(), nodeModel.Value); } foreach (var edge in copyPasteData.edges) { elementMapping.TryGetValue(edge.ToPort.NodeModel.Guid.ToString(), out var newInput); elementMapping.TryGetValue(edge.FromPort.NodeModel.Guid.ToString(), out var newOutput); var copiedEdge = graph.DuplicateEdge(edge, newInput as INodeModel, newOutput as INodeModel); if (copiedEdge != null) { elementMapping.Add(edge.Guid.ToString(), copiedEdge); graphViewUpdater?.MarkNew(copiedEdge); selectionStateUpdater?.SelectElements(new[] { copiedEdge }, true); } } foreach (var stickyNote in copyPasteData.stickyNotes) { var newPosition = new Rect(stickyNote.PositionAndSize.position + delta, stickyNote.PositionAndSize.size); var pastedStickyNote = graph.CreateStickyNote(newPosition); pastedStickyNote.Title = stickyNote.Title; pastedStickyNote.Contents = stickyNote.Contents; pastedStickyNote.Theme = stickyNote.Theme; pastedStickyNote.TextSize = stickyNote.TextSize; graphViewUpdater?.MarkNew(pastedStickyNote); selectionStateUpdater?.SelectElements(new[] { pastedStickyNote }, true); elementMapping.Add(stickyNote.Guid.ToString(), pastedStickyNote); } List <IPlacematModel> pastedPlacemats = new List <IPlacematModel>(); // Keep placemats relative order foreach (var placemat in copyPasteData.placemats.OrderBy(p => p.ZOrder)) { var newPosition = new Rect(placemat.PositionAndSize.position + delta, placemat.PositionAndSize.size); var newTitle = "Copy of " + placemat.Title; var pastedPlacemat = graph.CreatePlacemat(newPosition); pastedPlacemat.Title = newTitle; pastedPlacemat.Color = placemat.Color; pastedPlacemat.Collapsed = placemat.Collapsed; pastedPlacemat.HiddenElements = placemat.HiddenElements; graphViewUpdater?.MarkNew(pastedPlacemat); selectionStateUpdater?.SelectElements(new[] { pastedPlacemat }, true); pastedPlacemats.Add(pastedPlacemat); elementMapping.Add(placemat.Guid.ToString(), pastedPlacemat); } // Update hidden content to new node ids. foreach (var pastedPlacemat in pastedPlacemats) { if (pastedPlacemat.Collapsed) { List <IGraphElementModel> pastedHiddenContent = new List <IGraphElementModel>(); foreach (var elementGUID in pastedPlacemat.HiddenElements.Select(t => t.Guid.ToString())) { if (elementMapping.TryGetValue(elementGUID, out var pastedElement)) { pastedHiddenContent.Add(pastedElement); } } pastedPlacemat.HiddenElements = pastedHiddenContent; } } }
public void AlignNodes(bool follow, IReadOnlyList <IGraphElementModel> entryPoints, GraphViewStateComponent.StateUpdater graphUpdater) { HashSet <INodeModel> topMostModels = new HashSet <INodeModel>(); topMostModels.Clear(); bool anyEdge = false; foreach (var edgeModel in entryPoints.OfType <IEdgeModel>()) { if (!edgeModel.GraphModel.Stencil.CreateDependencyFromEdge(edgeModel, out var dependency, out var parent)) { continue; } anyEdge = true; AlignDependency(dependency, parent, graphUpdater); topMostModels.Add(dependency.DependentNode); } if (anyEdge && !follow) { return; } if (!topMostModels.Any()) { foreach (var nodeModel in entryPoints.OfType <INodeModel>()) { topMostModels.Add(nodeModel); } } if (!anyEdge && !follow) { // Align each top-most node then move dependencies by the same delta foreach (INodeModel model in topMostModels) { if (!m_DependenciesByNode.TryGetValue(model.Guid, out var dependencies)) { continue; } foreach (var dependency in dependencies) { AlignDependency(dependency.Value, model, graphUpdater); } } } else { // Align recursively m_ModelsToMove.AddRangeInternal(topMostModels); ProcessMovedNodeModels(AlignDependency, graphUpdater); } m_ModelsToMove.Clear(); m_TempMovedModels.Clear(); }
void ProcessMovedNodeModels(Action <IDependency, INodeModel, GraphViewStateComponent.StateUpdater> dependencyCallback, GraphViewStateComponent.StateUpdater graphUpdater) { Profiler.BeginSample("GTF.ProcessMovedNodeModel"); m_TempMovedModels.Clear(); foreach (INodeModel nodeModel in m_ModelsToMove) { ProcessDependencyModel(nodeModel, graphUpdater, dependencyCallback); } Profiler.EndSample(); }