public void OnCompilationDone(VSGraphModel vsGraphModel, CompilationOptions options, CompilationResult results)
        {
            if (!this)
            {
                // Should not happen, but it did, so...
                Debug.LogWarning("A destroyed VseWindow still has an OnCompilationDone callback registered.");
                return;
            }

            State state = m_Store.GetState();

            VseUtility.UpdateCodeViewer(show: false, sourceIndex: SourceCodePhases.Initial,
                                        compilationResult: results,
                                        selectionDelegate: lineMetadata =>
            {
                if (lineMetadata == null)
                {
                    return;
                }

                GUID nodeGuid = (GUID)lineMetadata;
                m_Store.Dispatch(new PanToNodeAction(nodeGuid));
            });

            //TODO: incremental re-register
            m_PluginRepository.RegisterPlugins(options);

            UpdateCompilationErrorsDisplay(state);

            if (results != null && results.errors.Count == 0)
            {
                // TODO : Add delegate to register to compilation Done
//                VSCompilationService.NotifyChange((ISourceProvider)vsGraphModel.assetModel);
            }
        }
Beispiel #2
0
        public TokenDeclaration(Store store, IVariableDeclarationModel model, GraphView graphView)
        {
            m_Pill = new Pill();
            Add(m_Pill);

            if (model is IObjectReference modelReference)
            {
                if (modelReference is IExposeTitleProperty titleProperty)
                {
#if UNITY_2019_3_OR_NEWER
                    m_TitleLabel = m_Pill.Q <Label>("title-label");
#else
                    m_TitleLabel = m_Pill.Q <Label>("title-label").ReplaceWithBoundLabel();
#endif
                    m_TitleLabel.bindingPath = titleProperty.TitlePropertyName;
                }
            }

            RegisterCallback <AttachToPanelEvent>(OnAttachToPanel);
            RegisterCallback <DetachFromPanelEvent>(OnDetachFromPanel);

            styleSheets.Add(AssetDatabase.LoadAssetAtPath <StyleSheet>(UICreationHelper.templatePath + "Token.uss"));

            Declaration = model;
            m_Store     = store;
            m_GraphView = graphView;

            m_Pill.icon = Declaration.IsExposed
                ? VisualScriptingIconUtility.LoadIconRequired("GraphView/Nodes/BlackboardFieldExposed.png")
                : null;

            m_Pill.text = Declaration.Title;

            if (model != null)
            {
                capabilities = VseUtility.ConvertCapabilities(model);
            }

            var     variableModel = model as VariableDeclarationModel;
            Stencil stencil       = store.GetState().CurrentGraphModel?.Stencil;
            if (variableModel != null && stencil && variableModel.DataType.IsValid)
            {
                string friendlyTypeName = variableModel.DataType.GetMetadata(stencil).FriendlyName;
                Assert.IsTrue(!string.IsNullOrEmpty(friendlyTypeName));
                tooltip = $"{variableModel.VariableString} declaration of type {friendlyTypeName}";
                if (!string.IsNullOrEmpty(variableModel.Tooltip))
                {
                    tooltip += "\n" + variableModel.Tooltip;
                }
            }

            SetClasses();

            this.EnableRename();

            if (model != null)
            {
                viewDataKey = model.GetId();
            }
        }
        public void DisplayCompilationErrors(State state)
        {
            VseUtility.RemoveLogEntries();
            if (ModelsToNodeMapping == null)
            {
                UpdateTopology();
            }

            var lastCompilationResult = state.CompilationResultModel.GetLastResult();

            if (lastCompilationResult?.errors == null)
            {
                return;
            }

            foreach (var error in lastCompilationResult.errors)
            {
                if (error.sourceNode != null && !error.sourceNode.Destroyed)
                {
                    var alignment = error.sourceNode is IStackModel
                        ? SpriteAlignment.TopCenter
                        : SpriteAlignment.RightCenter;

                    ModelsToNodeMapping.TryGetValue(error.sourceNode, out var graphElement);
                    if (graphElement != null)
                    {
                        AttachErrorBadge(graphElement, error.description, alignment, m_Store, error.quickFix);
                    }
                }

                var graphAsset     = (GraphAssetModel)m_Store.GetState().CurrentGraphModel?.AssetModel;
                var graphAssetPath = graphAsset ? AssetDatabase.GetAssetPath(graphAsset) : "<unknown>";
                VseUtility.LogSticky(error.isWarning ? LogType.Warning : LogType.Error, LogOption.None, $"{graphAssetPath}: {error.description}", $"{graphAssetPath}@{error.sourceNodeGuid}", graphAsset.GetInstanceID());
            }
        }
        public static void CreateGraphAsset <TStencilType>(string graphAssetName = k_DefaultGraphAssetName)
            where TStencilType : Stencil
        {
            string uniqueFilePath = VseUtility.GetUniqueAssetPathNameInActiveFolder(graphAssetName);
            string modelName      = Path.GetFileName(uniqueFilePath);

            var endAction = CreateInstance <DoCreateVisualScriptAsset>();

            endAction.StencilType = typeof(TStencilType);
            ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, endAction, modelName, GetIcon(), null);
        }
Beispiel #5
0
        public Edge(IEdgeModel edgeModel) : this()
        {
            m_EdgeModel = edgeModel;

            capabilities = VseUtility.ConvertCapabilities(m_EdgeModel);

            PortType portType = m_EdgeModel?.OutputPortModel?.PortType ?? PortType.Data;

            EnableInClassList("execution", portType == PortType.Execution || portType == PortType.Loop);
            EnableInClassList("event", portType == PortType.Event);
            viewDataKey = m_EdgeModel?.GetId();
        }
Beispiel #6
0
        public TokenDeclaration Clone()
        {
            var clone = new TokenDeclaration(m_Store, Declaration, m_GraphView)
            {
                viewDataKey = Guid.NewGuid().ToString()
            };

            if (Declaration is LoopVariableDeclarationModel loopVariableDeclarationModel)
            {
                VseUtility.AddTokenIcon(clone, loopVariableDeclarationModel.TitleComponentIcon);
            }
            return(clone);
        }
Beispiel #7
0
        public Placemat(PlacematModel model, Store store, GraphView graphView)
        {
            m_Model = model;
            m_Store = store;

            base.SetPosition(model.Position);
            base.Color     = model.Color;
            base.title     = model.Title;
            base.ZOrder    = model.ZOrder;
            base.Collapsed = model.Collapsed;

            capabilities = VseUtility.ConvertCapabilities(model);
        }
        void UpdateFromModel()
        {
            SetPosition(new Rect(stackModel.Position.x, stackModel.Position.y, 0, 0));

            capabilities = VseUtility.ConvertCapabilities(stackModel);

            UpdatePortsFromModels(stackModel.InputPorts, "input");
            UpdatePortsFromModels(stackModel.OutputPorts, "output");

            viewDataKey = stackModel.GetId();

            if (!stackModel.NodeModels.Any())
            {
                var contentContainerPlaceholder = this.MandatoryQ("stackNodeContentContainerPlaceholder");
                contentContainerPlaceholder.AddToClassList("empty");
            }
        }
        public static GraphElement CreateToken(this INodeBuilder builder, Store store, IVariableModel model)
        {
            var       isExposed = model.DeclarationModel?.IsExposed;
            Texture2D icon      = (isExposed != null && isExposed.Value)
                ? VisualScriptingIconUtility.LoadIconRequired("GraphView/Nodes/BlackboardFieldExposed.png")
                : null;

            GetTokenPorts(store, model, out var input, out var output, Orientation.Horizontal);

            var token = new Token(model, store, input, output, builder.GraphView, icon);

            if (model.DeclarationModel != null && model.DeclarationModel is LoopVariableDeclarationModel loopVariableDeclarationModel)
            {
                VseUtility.AddTokenIcon(token, loopVariableDeclarationModel.TitleComponentIcon);
            }
            return(token);
        }
Beispiel #10
0
        void OnViewInCodeViewerButton()
        {
            var compilationResult = m_Store.GetState()?.CompilationResultModel?.GetLastResult();

            if (compilationResult == null)
            {
                Debug.LogWarning("Compilation returned empty results");
                return;
            }

            VseUtility.UpdateCodeViewer(show: true, sourceIndex: m_GraphView.window.ToggleCodeViewPhase,
                                        compilationResult: compilationResult,
                                        selectionDelegate: lineMetadata =>
            {
                if (lineMetadata == null)
                {
                    return;
                }

                GUID nodeGuid = (GUID)lineMetadata;
                m_Store.Dispatch(new PanToNodeAction(nodeGuid));
            });
        }
Beispiel #11
0
        public void DisplayCompilationErrors(State state)
        {
            VseUtility.RemoveLogEntries();
            if (ModelsToNodeMapping == null)
            {
                UpdateTopology();
            }

            var lastCompilationResult = state.CompilationResultModel.GetLastResult();

            if (lastCompilationResult?.errors == null)
            {
                return;
            }

            foreach (var error in lastCompilationResult.errors)
            {
                if (!(error.sourceNode.Model is INodeModel model))
                {
                    continue;
                }

                var alignment = model is IStackModel
                    ? SpriteAlignment.TopCenter
                    : SpriteAlignment.RightCenter;

                ModelsToNodeMapping.TryGetValue(model, out var graphElement);
                if (graphElement != null)
                {
                    AttachErrorBadge(graphElement, error.description, alignment, m_Store, error.quickFix);
                }

                var graphAssetPath = AssetDatabase.GetAssetPath((GraphAssetModel)m_Store.GetState().CurrentGraphModel.AssetModel);
                VseUtility.LogSticky(LogType.Error, LogOption.None, $"{graphAssetPath}: {error.description}", graphAssetPath, error.sourceNodeId);
            }
        }
        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;
            }
        }
Beispiel #13
0
        void OnOptionsButton()
        {
            GenericMenu   menu         = new GenericMenu();
            VSGraphModel  vsGraphModel = (VSGraphModel)m_Store.GetState().CurrentGraphModel;
            VSPreferences pref         = m_Store.GetState().Preferences;

            void MenuItem(string title, bool value, GenericMenu.MenuFunction onToggle)
            => menu.AddItem(VseUtility.CreatTextContent(title), value, onToggle);

            void MenuToggle(string title, BoolPref k, Action callback = null)
            => MenuItem(title, pref.GetBool(k), () =>
            {
                pref.ToggleBool(k);
                callback?.Invoke();
            });

            void MenuMapToggle(string title, Func <bool> match, GenericMenu.MenuFunction onToggle)
            => MenuItem(title, match(), onToggle);

            void MenuItemDisable(string title, bool value, GenericMenu.MenuFunction onToggle, Func <bool> shouldDisable)
            {
                if (shouldDisable())
                {
                    menu.AddDisabledItem(VseUtility.CreatTextContent(title));
                }
                else
                {
                    menu.AddItem(VseUtility.CreatTextContent(title), value, onToggle);
                }
            }

            MenuItem("Build All", false, AssetDatabase.SaveAssets);
            MenuItemDisable("Compile", false, () =>
            {
                m_Store.GetState().EditorDataModel.RequestCompilation(RequestCompilationOptions.SaveGraph);
            }, () => (vsGraphModel == null || !vsGraphModel.Stencil.CreateTranslator().SupportsCompilation()));
            MenuItem("Auto-itemize/Variables", pref.CurrentItemizeOptions.HasFlag(ItemizeOptions.Variables), () =>
                     pref.ToggleItemizeOption(ItemizeOptions.Variables));
            MenuItem("Auto-itemize/System Constants", pref.CurrentItemizeOptions.HasFlag(ItemizeOptions.SystemConstants), () =>
                     pref.ToggleItemizeOption(ItemizeOptions.SystemConstants));
            MenuItem("Auto-itemize/Constants", pref.CurrentItemizeOptions.HasFlag(ItemizeOptions.Constants), () =>
                     pref.ToggleItemizeOption(ItemizeOptions.Constants));
            MenuToggle("Show unused nodes", BoolPref.ShowUnusedNodes, () => m_Store.Dispatch(new RefreshUIAction(UpdateFlags.All)));
            if (Unsupported.IsDeveloperMode())
            {
                MenuItem("Log compile time stats", LogCompileTimeStats, () => LogCompileTimeStats = !LogCompileTimeStats);

                MenuItem("Rebuild UI", false, () =>
                {
                    m_Store.Dispatch(new RefreshUIAction(UpdateFlags.All));
                });
                MenuItem("Rebuild Blackboard", false, () =>
                {
                    m_GraphView.UIController.Blackboard?.Rebuild(Blackboard.RebuildMode.BlackboardOnly);
                });
                menu.AddSeparator("");
                MenuItem("Reload and Rebuild UI", false, () =>
                {
                    if (m_Store.GetState()?.CurrentGraphModel != null)
                    {
                        var path = m_Store.GetState().CurrentGraphModel.GetAssetPath();
                        Selection.activeObject = null;
                        Resources.UnloadAsset((Object)m_Store.GetState().CurrentGraphModel.AssetModel);
                        Resources.UnloadAsset((Object)m_Store.GetState().CurrentGraphModel);
                        m_Store.Dispatch(new LoadGraphAssetAction(path));
                    }
                });

                MenuItem("Layout", false, () =>
                {
                    m_GraphView.FrameAll();
                    m_Store.Dispatch(new RefreshUIAction(UpdateFlags.All));
                });

                menu.AddSeparator("");
                MenuItem("Clear Searcher Databases", false, () =>
                {
                    var provider = m_Store.GetState().CurrentGraphModel.Stencil.GetSearcherDatabaseProvider();
                    provider.ClearTypesItemsSearcherDatabases();
                    provider.ClearTypeMembersSearcherDatabases();
                    provider.ClearGraphElementsSearcherDatabases();
                    provider.ClearGraphVariablesSearcherDatabases();
                    provider.ClearReferenceItemsSearcherDatabases();
                });
                MenuItem("Integrity Check", false, () => vsGraphModel.CheckIntegrity(GraphModel.Verbosity.Verbose));
                MenuItem("Graph cleanup", false, () =>
                {
                    vsGraphModel.QuickCleanup();
                    vsGraphModel.CheckIntegrity(GraphModel.Verbosity.Verbose);
                });
                MenuItem("Fix and reimport all textures", false, OnFixAndReimportTextures);

                MenuToggle("Auto compilation when idle", BoolPref.AutoRecompile);
                MenuToggle("Auto align new dragged edges", BoolPref.AutoAlignDraggedEdges);
                if (Unsupported.IsDeveloperMode())
                {
                    MenuToggle("Bound object logging", BoolPref.BoundObjectLogging);
                    MenuToggle("Dependencies logging", BoolPref.DependenciesLogging);
                    MenuToggle("UI Performance/Always fully rebuild UI on change", BoolPref.FullUIRebuildOnChange);
                    MenuToggle("UI Performance/Warn when UI gets fully rebuilt", BoolPref.WarnOnUIFullRebuild);
                    MenuToggle("UI Performance/Log UI build time", BoolPref.LogUIBuildTime);
                    if (DebugDisplayElement.Allowed)
                    {
                        MenuItem("Show Debug", m_GraphView.ShowDebug, () => m_GraphView.ShowDebug = !m_GraphView.ShowDebug);
                    }
                    MenuToggle("Diagnostics/Log Recursive Action Dispatch", BoolPref.ErrorOnRecursiveDispatch);
                    MenuToggle("Diagnostics/Log Multiple Actions Dispatch", BoolPref.ErrorOnMultipleDispatchesPerFrame);
                    MenuToggle("Diagnostics/Log All Dispatched Actions", BoolPref.LogAllDispatchedActions);
                    MenuItem("Spawn all node types in graph", false, () =>
                    {
                        VSGraphModel graph   = (VSGraphModel)m_Store.GetState().CurrentGraphModel;
                        Stencil stencil      = graph.Stencil;
                        Vector2 nextPosition = Vector2.zero;
                        Vector2 spaceBetween = new Vector2(300, 0);
                        foreach (var node in stencil.SpawnAllNodes(graph))
                        {
                            node.Position += nextPosition;
                            nextPosition  += spaceBetween;
                        }
                    });
                }

                var compilationResult = m_Store.GetState()?.CompilationResultModel?.GetLastResult();
                if (compilationResult != null)
                {
                    foreach (var pluginType in compilationResult.pluginSourceCode.Keys)
                    {
                        MenuMapToggle(title: "CodeViewer/Plugin/" + pluginType.Name, match: () => pref.PluginTypePref == pluginType, onToggle: () =>
                        {
                            VseUtility.UpdateCodeViewer(show: true, pluginIndex: pluginType,
                                                        compilationResult: compilationResult,
                                                        selectionDelegate: lineMetadata =>
                            {
                                if (lineMetadata == null)
                                {
                                    return;
                                }

                                GUID nodeGuid = (GUID)lineMetadata;
                                m_Store.Dispatch(new PanToNodeAction(nodeGuid));
                            });
                            pref.PluginTypePref = pluginType;
                        });
                    }
                }
            }

            menu.ShowAsContext();
        }
Beispiel #14
0
        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>(_ => 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();

            SetupWindow();

            m_CompilationPendingLabel = new Label("Compilation Pending")
            {
                name = "compilationPendingLabel"
            };

            m_SidePanel = new VisualElement()
            {
                name = "sidePanel"
            };
            m_ImguiContainer = new IMGUIContainer(DrawSidePanel)
            {
                name = "sidePanelInspector"
            };
            m_SidePanel.Add(m_ImguiContainer);

            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, m_GraphView);

            EditorApplication.playModeStateChanged += OnEditorPlayModeStateChanged;
            EditorApplication.pauseStateChanged    += OnEditorPauseStateChanged;

            if (DataModel is VSEditorDataModel vsDataModel)
            {
                vsDataModel.PluginRepository     = m_PluginRepository;
                vsDataModel.OnCompilationRequest = OnCompilationRequest;
            }
        }