void OnPointerMove(PointerMoveEvent e) { VseGraphView graphView = null; Vector2 pointerDelta = Vector2.zero; if (m_DraggingControlPoint || m_DraggingTightness) { graphView = GetFirstAncestorOfType <VseGraphView>(); var pointerPosition = this.ChangeCoordinatesTo(parent, e.localPosition); pointerDelta = new Vector2(pointerPosition.x, pointerPosition.y) - m_OriginalPointerPosition; } if (graphView == null) { return; } if (m_DraggingControlPoint) { var newPosition = m_OriginalElementPosition + pointerDelta; graphView.store.Dispatch(new MoveEdgeControlPointAction(m_EdgeModel, m_ControlPointIndex, newPosition, m_OriginalTightness)); m_EdgeControl.MarkDirtyRepaint(); e.StopPropagation(); } else if (m_DraggingTightness) { var tightnessDelta = pointerDelta.x - pointerDelta.y; var newTightness = m_OriginalTightness + tightnessDelta; graphView.store.Dispatch(new MoveEdgeControlPointAction(m_EdgeModel, m_ControlPointIndex, m_OriginalElementPosition, newTightness)); e.StopPropagation(); m_EdgeControl.MarkDirtyRepaint(); } }
public static List <Tuple <IVariableDeclarationModel, Vector2> > ExtractVariablesFromDroppedElements( IReadOnlyCollection <GraphElement> dropElements, VseGraphView graphView, Vector2 initialPosition) { var elementOffset = Vector2.zero; var variablesToCreate = new List <Tuple <IVariableDeclarationModel, Vector2> >(); foreach (var dropElement in dropElements) { if (dropElement is TokenDeclaration tokenDeclaration) { Vector2 pos = dropElement.GetPosition().position; if (!variablesToCreate.Any(x => ReferenceEquals(x.Item1, tokenDeclaration.Declaration))) { variablesToCreate.Add(new Tuple <IVariableDeclarationModel, Vector2>(tokenDeclaration.Declaration, pos)); } tokenDeclaration.RemoveFromHierarchy(); } else if (dropElement is IVisualScriptingField visualScriptingField) { Vector2 pos = graphView.contentViewContainer.WorldToLocal(initialPosition) + elementOffset; elementOffset.y += ((GraphElement)visualScriptingField).layout.height + VseGraphView.DragDropSpacer; if (!variablesToCreate.Any(x => ReferenceEquals(x.Item1, visualScriptingField.GraphElementModel))) { variablesToCreate.Add(new Tuple <IVariableDeclarationModel, Vector2>(visualScriptingField.GraphElementModel as IVariableDeclarationModel, pos)); } } } return(variablesToCreate); }
public static void HighlightGraphElements(this VseGraphView graphView) { graphView.ClearGraphElementsHighlight(); if (graphView.selection.Count == 0) { return; } IEnumerable <IHighlightable> highlightables = GetHighlightables(graphView, true).ToList(); // For all the selected items, highlight the graphElements that share the same declaration model // Exception: If the graphElement is selected, do not highlight it foreach (ISelectable selectable in graphView.selection) { if (!(selectable is IHasGraphElementModel hasGraphElementModel)) { continue; } foreach (IHighlightable highlightable in highlightables .Where(h => (!Equals(selectable, h) || !ReferenceEquals(selectable, h)) && h.ShouldHighlightItemUsage(hasGraphElementModel.GraphElementModel))) { highlightable.Highlighted = true; } } }
public void DuplicateStackedNode([Values] TestingMode mode) { var stack = GraphModel.CreateStack("stack", Vector2.zero); stack.CreateStackedNode <Type0FakeNodeModel>("test"); TestPrereqActionPostreq(mode, () => { Assert.That(stack.NodeModels.Count, Is.EqualTo(1)); }, () => { var node = stack.NodeModels.Single(); TargetInsertionInfo info; info.OperationName = "Duplicate"; info.Delta = Vector2.one; info.TargetStack = stack; info.TargetStackInsertionIndex = -1; IEditorDataModel editorDataModel = m_Store.GetState().EditorDataModel; VseGraphView.CopyPasteData copyPasteData = VseGraphView.GatherCopiedElementsData(VseGraphView.CopyMode.KeepReference, new List <IGraphElementModel> { node }); Assert.That(copyPasteData.IsEmpty(), Is.False); return(new PasteSerializedDataAction(GraphModel, info, editorDataModel, copyPasteData.ToJson())); }, () => { Assert.That(stack.NodeModels.Count, Is.EqualTo(2)); }); }
public VseContextualMenuBuilder(Store store, ContextualMenuPopulateEvent evt, IList <ISelectable> selection, VseGraphView graphView) { m_Store = store; m_Evt = evt; m_Selection = selection; m_GraphView = graphView; }
public override void OnStartDragging(GraphElement ge) { if (ge is TokenDeclaration tokenDeclaration) { VseGraphView gView = GetFirstOfType <VseGraphView>(); VisualElement tokenParent = tokenDeclaration.parent; int childIndex = tokenDeclaration.FindIndexInParent(); gView.RemoveElement(tokenDeclaration); tokenDeclaration.SetClasses(); gView.AddElement(tokenDeclaration); // By removing the tokenDeclaration from the graph view, we also removed it from the selection. // We need to add the tokenDeclaration back in order to properly drag. tokenDeclaration.Select(gView, true); tokenDeclaration.BringToFront(); TokenDeclaration placeHolderTokenDeclaration = tokenDeclaration.Clone(); placeHolderTokenDeclaration.AddToClassList("placeHolder"); tokenParent.Insert(childIndex, placeHolderTokenDeclaration); placeHolderTokenDeclaration.MarkDirtyRepaint(); gView.AddPlaceholderToken(tokenDeclaration); } else { var originalWidth = ge.resolvedStyle.width; var originalHeight = ge.resolvedStyle.height; base.OnStartDragging(ge); // Revert to same width and height after element became unstacked ge.style.width = originalWidth; ge.style.height = originalHeight; } }
public GtfErrorToolbar(Store store, VseGraphView graphView) { m_Store = store; m_GraphView = graphView; name = "errorToolbar"; AddToClassList("gtf-toolbar"); styleSheets.Add( AssetDatabase.LoadAssetAtPath <StyleSheet>(PackageTransitionHelper.AssetPath + "VisualScripting/Editor/Menu/VseMenu.uss")); AssetDatabase .LoadAssetAtPath <VisualTreeAsset>(PackageTransitionHelper.AssetPath + "VisualScripting/Editor/Menu/GtfErrorToolbar.uxml").CloneTree(this); m_ErrorIconLabel = this.MandatoryQ("errorIconLabel"); m_PreviousErrorButton = this.MandatoryQ <ToolbarButton>("previousErrorButton"); m_PreviousErrorButton.tooltip = "Go To Previous Error"; m_PreviousErrorButton.RemoveManipulator(m_PreviousErrorButton.clickable); m_PreviousErrorButton.AddManipulator(new Clickable(OnPreviousErrorButton)); m_NextErrorButton = this.MandatoryQ <ToolbarButton>("nextErrorButton"); m_NextErrorButton.tooltip = "Go To Next Error"; m_NextErrorButton.RemoveManipulator(m_NextErrorButton.clickable); m_NextErrorButton.AddManipulator(new Clickable(OnNextErrorButton)); m_ErrorCounterLabel = this.MandatoryQ <Label>("errorCounterLabel"); }
public TracingTimeline(VseGraphView vseGraphView, State vsWindowState, IMGUIContainer imguiContainer) { m_VseGraphView = vseGraphView; m_VSWindowState = vsWindowState; m_ImguiContainer = imguiContainer; m_TimeArea = new TimeArea(); m_Overlay = new AnimEditorOverlay() { PlayHeadColor = new Color(0.2117647F, 0.6039216F, 0.8F) }; m_State = new TimelineState(m_TimeArea); m_Overlay.state = m_State; var debugger = m_VSWindowState?.CurrentGraphModel?.Stencil?.Debugger; IGraphTrace trace = debugger?.GetGraphTrace(m_VSWindowState?.CurrentGraphModel, m_VSWindowState.CurrentTracingTarget); if (trace?.AllFrames != null && trace.AllFrames.Count > 0) { int firstFrame = trace.AllFrames[0].Frame; int lastFrame = trace.AllFrames[trace.AllFrames.Count - 1].Frame; m_TimeArea.SetShownRange( firstFrame - k_MinTimeVisibleOnTheRight, lastFrame + k_MinTimeVisibleOnTheRight); } }
public void Test_DuplicateAction_OneNode([Values] TestingMode mode) { GraphModel.CreateNode <Type0FakeNodeModel>("Node0", Vector2.zero); TestPrereqActionPostreq(mode, () => { Assert.That(GetNodeCount(), Is.EqualTo(1)); var nodeModel = GetNode(0); Assert.That(nodeModel, Is.TypeOf <Type0FakeNodeModel>()); TargetInsertionInfo info = new TargetInsertionInfo(); info.OperationName = "Duplicate"; info.Delta = Vector2.one; info.TargetStackInsertionIndex = -1; IEditorDataModel editorDataModel = m_Store.GetState().EditorDataModel; VseGraphView.CopyPasteData copyPasteData = VseGraphView.GatherCopiedElementsData(x => x, new List <IGraphElementModel> { nodeModel }); return(new PasteSerializedDataAction(GraphModel, info, editorDataModel, copyPasteData.ToJson())); }, () => { Assert.That(GetNodeCount(), Is.EqualTo(2)); Assert.That(GraphModel.NodeModels.Count(n => n == null), Is.Zero); }); }
public static void ClearGraphElementsHighlight(this VseGraphView graphView) { IEnumerable <IHighlightable> elements = GetHighlightables(graphView, true); foreach (var element in elements) { element.Highlighted = false; } }
public Blackboard(Store store, VseGraphView graphView, bool windowed) { base.Store = store; styleSheets.Add(AssetDatabase.LoadAssetAtPath <StyleSheet>(UICreationHelper.templatePath + "Blackboard.uss")); AddToClassList("blackboard"); scrollable = true; title = k_ClassLibraryTitle; subTitle = ""; viewDataKey = string.Empty; addItemRequested = OnAddItemRequested; moveItemRequested = OnMoveItemRequested; // TODO 0.5: hack - we have two conflicting renaming systems // the blackboard one seems to win // for 0.4, just rewire it to dispatch the same action as ours editTextRequested = OnEditTextRequested; RegisterCallback <AttachToPanelEvent>(OnAttachToPanel); RegisterCallback <DetachFromPanelEvent>(OnDetachFromPanel); this.AddManipulator(new ContextualMenuManipulator(OnContextualMenuEvent)); graphView.OnSelectionChangedCallback += s => { IGraphModel currentGraphModel = Store.GetState().CurrentGraphModel; if (!(currentGraphModel as Object)) { return; } if (currentGraphModel == GraphView.UIController.LastGraphModel && (GraphView.selection.LastOrDefault() is BlackboardField || GraphView.selection.LastOrDefault() is IVisualScriptingField)) { ((VSGraphModel)currentGraphModel).LastChanges.RequiresRebuild = true; return; } RebuildSections(); }; var header = this.Query("header").First(); m_AddButton = header?.Query <Button>("addButton").First(); if (m_AddButton != null) { m_AddButton.style.visibility = Visibility.Hidden; } this.windowed = windowed; this.graphView = graphView; }
static void OnDropOutsideCallback(Store store, Vector2 pos, Edge edge) { VseGraphView graphView = edge.GetFirstAncestorOfType <VseGraphView>(); Vector2 worldPos = pos; pos = graphView.contentViewContainer.WorldToLocal(pos); List <IEdgeModel> edgesToDelete = GetDropEdgeModelsToDelete(edge); // when grabbing an existing edge's end, the edgeModel should be deleted if ((edge).GraphElementModel != null) { edgesToDelete.Add((IEdgeModel)edge.GraphElementModel); } IStackModel targetStackModel = null; int targetIndex = -1; IGroupNodeModel groupModel = null; StackNode stackNode = graphView.lastHoveredVisualElement as StackNode ?? graphView.lastHoveredVisualElement.GetFirstOfType <StackNode>(); if (stackNode != null) { targetStackModel = stackNode.stackModel; targetIndex = stackNode.GetInsertionIndex(worldPos); } else if (graphView.lastHoveredVisualElement is Group group) { groupModel = group.model; } IPortModel existingPortModel; // warning: when dragging the end of an existing edge, both ports are non null. if (edge.input != null && edge.output != null) { float distanceToOutput = Vector2.Distance(edge.edgeControl.from, pos); float distanceToInput = Vector2.Distance(edge.edgeControl.to, pos); // note: if the user was able to stack perfectly both ports, we'd be in trouble if (distanceToOutput < distanceToInput) { existingPortModel = (IPortModel)edge.input.userData; } else { existingPortModel = (IPortModel)edge.output.userData; } } else { Port existingPort = (Port)(edge.input ?? edge.output); existingPortModel = existingPort.userData as IPortModel; } CreateNodes(store, existingPortModel, pos, edgesToDelete, targetStackModel, targetIndex, groupModel); }
public TracingTimeline(VseGraphView vseGraphView, State vsWindowState, IMGUIContainer imguiContainer) { m_VseGraphView = vseGraphView; m_VSWindowState = vsWindowState; m_ImguiContainer = imguiContainer; m_TimeArea = new TimeArea(); m_Overlay = new AnimEditorOverlay(); m_State = new TimelineState(m_TimeArea); m_Overlay.state = m_State; }
static IEnumerable <IHighlightable> GetHighlightables(VseGraphView graphView, bool includeBlackboard = false) { IEnumerable <IHighlightable> elements = graphView.graphElements.ToList() .OfType <IHighlightable>() .Where(x => x is IHasGraphElementModel); Blackboard blackboard = graphView.UIController.Blackboard; return(includeBlackboard ? elements.Concat(blackboard.GraphVariables) : elements); }
public DebugDisplayElement(VseGraphView graphView) { m_GraphView = graphView; pickingMode = PickingMode.Ignore; m_Crosses = new List <DebugRectData>(); m_Boxes = new List <DebugRectData>(); AddCross(Rect.MinMaxRect(-10, -10, 10, 10), Color.green); }
public VseUIController(VseGraphView graphView, Store store) { m_GraphView = graphView; m_Store = store; m_IconsParent = new VisualElement { name = "iconsParent" }; m_IconsParent.style.overflow = Overflow.Visible; Blackboard = new Blackboard(m_Store, m_GraphView, windowed: true); m_LastGraphModel = null; }
public VseMenu(Store store, VseGraphView graphView) { m_Store = store; m_GraphView = graphView; name = "vseMenu"; styleSheets.Add(AssetDatabase.LoadAssetAtPath <StyleSheet>(PackageTransitionHelper.AssetPath + "VisualScripting/Editor/Menu/VseMenu.uss")); AssetDatabase.LoadAssetAtPath <VisualTreeAsset>(PackageTransitionHelper.AssetPath + "VisualScripting/Editor/Menu/VseMenu.uxml").CloneTree(this); CreateCommonMenu(); CreateErrorMenu(); CreateBreadcrumbMenu(); CreateTracingMenu(); CreateOptionsMenu(); }
public void DisplayAppropriateSearcher(Vector2 mousePosition, VseGraphView graphView) { VisualElement picked = graphView.panel.Pick(mousePosition); while (picked != null && !(picked is IVisualScriptingField)) { picked = picked.parent; } // optimization: stop at the first IVsBlackboardField, but still exclude BlackboardThisFields if (picked != null && picked is BlackboardVariableField field) { graphView.window.DisplayTokenDeclarationSearcher((VariableDeclarationModel)field.VariableDeclarationModel, mousePosition); } else { graphView.window.DisplayAddVariableSearcher(mousePosition); } }
public static void ClearGraphElementsHighlight(this VseGraphView graphView, Func <IGraphElementModel, bool> predicate) { IEnumerable <IHighlightable> elements = GetHighlightables(graphView, true); foreach (var element in elements) { var hasGraphElementModel = element as IHasGraphElementModel; if (hasGraphElementModel == null) { continue; } if (predicate(hasGraphElementModel.GraphElementModel)) { element.Highlighted = false; } } }
void ClearHighlights() { VseGraphView gv = (VseGraphView)m_GraphView; if (gv?.UIController.ModelsToNodeMapping != null) { foreach (GraphElement x in gv.UIController.ModelsToNodeMapping.Values) { x.RemoveFromClassList(k_TraceHighlight); x.RemoveFromClassList(k_TraceSecondaryHighlight); x.RemoveFromClassList(k_ExceptionHighlight); VseUIController.ClearErrorBadge(x); VseUIController.ClearValue(x); // TODO ugly gv.UIController.DisplayCompilationErrors(gv.store.GetState()); } } }
public VseUIController(VseGraphView graphView, Store store) { m_GraphView = graphView; m_Store = store; m_IconsParent = new VisualElement { name = "iconsParent" }; m_IconsParent.style.overflow = Overflow.Visible; Blackboard = new Blackboard(m_Store, m_GraphView); var blackboardPosition = m_Store.GetState().EditorDataModel.BlackboardPosition; if (Math.Abs(blackboardPosition.size.x) > float.Epsilon && Math.Abs(blackboardPosition.size.y) > float.Epsilon) { Blackboard.SetPosition(m_Store.GetState().EditorDataModel.BlackboardPosition); } else { ResetBlackboard(); } m_LastGraphModel = null; }
protected virtual void OnEnable() { if (m_PreviousGraphModels == null) { m_PreviousGraphModels = new List <GraphModel>(); } if (m_BlackboardExpandedRowStates == null) { m_BlackboardExpandedRowStates = new List <string>(); } if (m_ElementModelsToSelectUponCreation == null) { m_ElementModelsToSelectUponCreation = new List <string>(); } if (m_ElementModelsToExpandUponCreation == null) { m_ElementModelsToExpandUponCreation = new List <string>(); } rootVisualElement.RegisterCallback <ValidateCommandEvent>(OnValidateCommand); rootVisualElement.RegisterCallback <ExecuteCommandEvent>(OnExecuteCommand); rootVisualElement.RegisterCallback <MouseMoveEvent>(_ => m_IdleTimer?.Restart()); rootVisualElement.styleSheets.Add(AssetDatabase.LoadAssetAtPath <StyleSheet>(k_StyleSheetPath + "VSEditor.uss")); rootVisualElement.Clear(); rootVisualElement.style.overflow = Overflow.Hidden; rootVisualElement.pickingMode = PickingMode.Ignore; rootVisualElement.style.flexDirection = FlexDirection.Column; rootVisualElement.name = "vseRoot"; // Create the store. DataModel = CreateDataModel(); State initialState = CreateInitialState(); m_Store = new Store(initialState, Store.Options.TrackUndoRedo); VseUtility.SetupLogStickyCallback(); m_GraphContainer = new VisualElement { name = "graphContainer" }; m_GraphView = CreateGraphView(); m_Menu = CreateMenu(); m_BlankPage = CreateBlankPage(); IMGUIContainer imguiContainer = null; imguiContainer = new IMGUIContainer(() => { var timeRect = new Rect(0, 0, rootVisualElement.layout.width, imguiContainer.layout.height); m_TracingTimeline.OnGUI(timeRect); }); m_TracingTimeline = new TracingTimeline(m_Store.GetState(), imguiContainer); m_TracingTimeline.SyncVisible(); rootVisualElement.Add(m_Menu); rootVisualElement.Add(imguiContainer); rootVisualElement.Add(m_GraphContainer); m_CompilationPendingLabel = new Label("Compilation Pending") { name = "compilationPendingLabel" }; m_GraphContainer.Add(m_GraphView); m_ShortcutHandler = new ShortcutHandler( new Dictionary <Event, ShortcutDelegate> { { Event.KeyboardEvent("F2"), () => Application.platform != RuntimePlatform.OSXEditor ? RenameElement() : EventPropagation.Continue }, { Event.KeyboardEvent("F5"), () => { RefreshUI(UpdateFlags.All); return(EventPropagation.Continue); } }, { Event.KeyboardEvent("return"), () => Application.platform == RuntimePlatform.OSXEditor ? RenameElement() : EventPropagation.Continue }, { Event.KeyboardEvent("[enter]"), () => Application.platform == RuntimePlatform.OSXEditor ? RenameElement() : EventPropagation.Continue }, { Event.KeyboardEvent("backspace"), OnBackspaceKeyDown }, { Event.KeyboardEvent("space"), OnSpaceKeyDown }, { Event.KeyboardEvent("C"), () => { IGraphElementModel[] selectedModels = m_GraphView.selection .OfType <IHasGraphElementModel>() .Select(x => x.GraphElementModel) .ToArray(); // Convert variable -> constant if selection contains at least one item that satisfies conditions IVariableModel[] variableModels = selectedModels.OfType <VariableNodeModel>().Cast <IVariableModel>().ToArray(); if (variableModels.Any()) { m_Store.Dispatch(new ConvertVariableNodesToConstantNodesAction(variableModels)); return(EventPropagation.Stop); } IConstantNodeModel[] constantModels = selectedModels.OfType <IConstantNodeModel>().ToArray(); if (constantModels.Any()) { m_Store.Dispatch(new ConvertConstantNodesToVariableNodesAction(constantModels)); } return(EventPropagation.Stop); } }, { Event.KeyboardEvent("Q"), () => m_GraphView.AlignSelection(false) }, { Event.KeyboardEvent("#Q"), () => m_GraphView.AlignSelection(true) }, // DEBUG { Event.KeyboardEvent("1"), () => OnCreateLogNode(LogNodeModel.LogTypes.Message) }, { Event.KeyboardEvent("2"), () => OnCreateLogNode(LogNodeModel.LogTypes.Warning) }, { Event.KeyboardEvent("3"), () => OnCreateLogNode(LogNodeModel.LogTypes.Error) }, { Event.KeyboardEvent("`"), () => OnCreateStickyNote(new Rect(m_GraphView.ChangeCoordinatesTo(m_GraphView.contentViewContainer, m_GraphView.WorldToLocal(Event.current.mousePosition)), StickyNote.defaultSize)) }, }); rootVisualElement.parent.AddManipulator(m_ShortcutHandler); Selection.selectionChanged += OnGlobalSelectionChange; m_Store.StateChanged += StoreOnStateChanged; Undo.undoRedoPerformed += UndoRedoPerformed; rootVisualElement.RegisterCallback <AttachToPanelEvent>(OnEnterPanel); rootVisualElement.RegisterCallback <DetachFromPanelEvent>(OnLeavePanel); titleContent = new GUIContent("Visual Script"); // After a domain reload, all loaded objects will get reloaded and their OnEnable() called again // It looks like all loaded objects are put in a deserialization/OnEnable() queue // the previous graph's nodes/edges/... might be queued AFTER this window's OnEnable // so relying on objects to be loaded/initialized is not safe // hence, we need to defer the loading action rootVisualElement.schedule.Execute(() => { if (!String.IsNullOrEmpty(LastGraphFilePath)) { try { m_Store.Dispatch(new LoadGraphAssetAction(LastGraphFilePath, loadType: LoadGraphAssetAction.Type.KeepHistory)); } catch (Exception e) { Debug.LogError(e); } } else // will display the blank page. not needed otherwise as the LoadGraphAsset reducer will refresh { m_Store.Dispatch(new RefreshUIAction(UpdateFlags.All)); } }).ExecuteLater(0); m_LockTracker.lockStateChanged.AddListener(OnLockStateChanged); m_PluginRepository = new PluginRepository(m_Store, m_GraphView); EditorApplication.playModeStateChanged += OnEditorPlayModeStateChanged; EditorApplication.pauseStateChanged += OnEditorPauseStateChanged; if (DataModel is VSEditorDataModel vsDataModel) { vsDataModel.PluginRepository = m_PluginRepository; vsDataModel.OnCompilationRequest = OnCompilationRequest; } }
static State PasteSerializedData(State previousState, PasteSerializedDataAction action) { VseGraphView.OnUnserializeAndPaste(action.Graph, action.Info, action.EditorDataModel, action.Data); return(previousState); }
protected virtual void OnEnable() { if (m_PreviousGraphModels == null) { m_PreviousGraphModels = new List <OpenedGraph>(); } if (m_BlackboardExpandedRowStates == null) { m_BlackboardExpandedRowStates = new List <string>(); } if (m_ElementModelsToSelectUponCreation == null) { m_ElementModelsToSelectUponCreation = new List <string>(); } if (m_ElementModelsToExpandUponCreation == null) { m_ElementModelsToExpandUponCreation = new List <string>(); } rootVisualElement.RegisterCallback <ValidateCommandEvent>(OnValidateCommand); rootVisualElement.RegisterCallback <ExecuteCommandEvent>(OnExecuteCommand); rootVisualElement.RegisterCallback <MouseMoveEvent>(_ => _compilationTimer.Restart(m_Store.GetState().EditorDataModel)); rootVisualElement.styleSheets.Add(AssetDatabase.LoadAssetAtPath <StyleSheet>(k_StyleSheetPath + "VSEditor.uss")); rootVisualElement.Clear(); rootVisualElement.style.overflow = Overflow.Hidden; rootVisualElement.pickingMode = PickingMode.Ignore; rootVisualElement.style.flexDirection = FlexDirection.Column; rootVisualElement.name = "vseRoot"; // Create the store. DataModel = CreateDataModel(); State initialState = CreateInitialState(); m_Store = new Store(initialState, Store.Options.TrackUndoRedo); VseUtility.SetupLogStickyCallback(); m_GraphContainer = new VisualElement { name = "graphContainer" }; m_GraphView = CreateGraphView(); m_Menu = CreateMenu(); m_ErrorToolbar = CreateErrorToolbar(); m_BlankPage = CreateBlankPage(); SetupWindow(); m_CompilationPendingLabel = new Label("Compilation Pending") { name = "compilationPendingLabel" }; m_SidePanel = new VisualElement() { name = "sidePanel" }; m_SidePanelTitle = new Label(); m_SidePanel.Add(m_SidePanelTitle); m_SidePanelPropertyElement = new Unity.Properties.UI.PropertyElement { name = "sidePanelInspector" }; m_SidePanelPropertyElement.OnChanged += (element, path) => { if (m_ElementShownInSidePanel is IHasGraphElementModel hasGraphElementModel && hasGraphElementModel.GraphElementModel is IPropertyVisitorNodeTarget nodeTarget2) { nodeTarget2.Target = element.GetTarget <object>(); } (m_ElementShownInSidePanel as Node)?.NodeModel.DefineNode(); (m_ElementShownInSidePanel as Node)?.UpdateFromModel(); }; m_SidePanel.Add(m_SidePanelPropertyElement); ShowNodeInSidePanel(null, false); m_GraphContainer.Add(m_GraphView); m_GraphContainer.Add(m_SidePanel); Dictionary <Event, ShortcutDelegate> dictionaryShortcuts = GetShortcutDictionary(); m_ShortcutHandler = new ShortcutHandler(GetShortcutDictionary()); rootVisualElement.parent.AddManipulator(m_ShortcutHandler); m_Store.StateChanged += StoreOnStateChanged; Undo.undoRedoPerformed += UndoRedoPerformed; rootVisualElement.RegisterCallback <AttachToPanelEvent>(OnEnterPanel); rootVisualElement.RegisterCallback <DetachFromPanelEvent>(OnLeavePanel); // that will be true when the window is restored during the editor startup, so OnEnterPanel won't be called later if (rootVisualElement.panel != null) { OnEnterPanel(null); } titleContent = new GUIContent("Visual Script"); // After a domain reload, all loaded objects will get reloaded and their OnEnable() called again // It looks like all loaded objects are put in a deserialization/OnEnable() queue // the previous graph's nodes/edges/... might be queued AFTER this window's OnEnable // so relying on objects to be loaded/initialized is not safe // hence, we need to defer the loading action rootVisualElement.schedule.Execute(() => { if (!String.IsNullOrEmpty(LastGraphFilePath)) { try { m_Store.Dispatch(new LoadGraphAssetAction(LastGraphFilePath, boundObject: m_BoundObject, loadType: LoadGraphAssetAction.Type.KeepHistory)); } catch (Exception e) { Debug.LogError(e); } } else // will display the blank page. not needed otherwise as the LoadGraphAsset reducer will refresh { m_Store.Dispatch(new RefreshUIAction(UpdateFlags.All)); } }).ExecuteLater(0); m_LockTracker.lockStateChanged.AddListener(OnLockStateChanged); m_PluginRepository = new PluginRepository(m_Store, this); EditorApplication.playModeStateChanged += OnEditorPlayModeStateChanged; EditorApplication.pauseStateChanged += OnEditorPauseStateChanged; if (DataModel is VSEditorDataModel vsDataModel) { vsDataModel.PluginRepository = m_PluginRepository; vsDataModel.OnCompilationRequest = OnCompilationRequest; } }
public void AlignNodes(VseGraphView vseGraphView, bool follow, List <ISelectable> selection) { HashSet <INodeModel> topMostModels = new HashSet <INodeModel>(); topMostModels.Clear(); var selectedNodeModels = selection.OfType <Node>().Select(e => e.model); var nodeModelsFromSelectedEdges = selection.OfType <Edge>().SelectMany(e => e.model.GetPortModels().Select(p => p.NodeModel)); var affectedNodeModels = selectedNodeModels.Concat(nodeModelsFromSelectedEdges); foreach (INodeModel stackedNode in affectedNodeModels.Where(n => n.IsStacked)) { InitModelPositionFromUI(stackedNode); } bool anyEdge = false; foreach (Edge edge in selection.OfType <Edge>()) { anyEdge = true; LinkedNodesDependency dependency = CreateDependencyFromEdge(edge.model, out INodeModel parent); GraphElement element = vseGraphView.UIController.ModelsToNodeMapping[dependency.DependentNode]; AlignDependency(element, dependency, Vector2.zero, parent); topMostModels.Add(dependency.DependentNode); } if (anyEdge && !follow) { return; } if (!topMostModels.Any()) { foreach (GraphElement element in selection.OfType <GraphElement>()) { if (element is IHasGraphElementModel hasModel && hasModel.GraphElementModel is INodeModel nodeModel) { 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 Dictionary <GUID, IDependency> dependencies)) { continue; } foreach (KeyValuePair <GUID, IDependency> dependency in dependencies) { INodeModel dependentNode = dependency.Value.DependentNode; GraphElement element = vseGraphView.UIController.ModelsToNodeMapping[dependentNode]; Vector2 startPos = dependentNode.Position; AlignDependency(element, dependency.Value, Vector2.zero, model); Vector2 endPos = dependentNode.Position; Vector2 delta = endPos - startPos; OffsetNodeDependencies(dependentNode, delta); } } } else { // Align recursively m_ModelsToMove.AddRange(topMostModels); ProcessMovedNodes(Vector2.zero, AlignDependency); } m_ModelsToMove.Clear(); m_TempMovedModels.Clear(); }
public PositionDependenciesManager(VseGraphView vseGraphView, VSPreferences vsPreferences) { m_VseGraphView = vseGraphView; m_Preferences = vsPreferences; }