public static void CreateGraphAsset <TStencilType>(string graphAssetName = k_DefaultGraphAssetName, IGraphTemplate template = null) where TStencilType : Stencil { string uniqueFilePath = VseUtility.GetUniqueAssetPathNameInActiveFolder(graphAssetName); string modelName = Path.GetFileName(uniqueFilePath); var endAction = CreateInstance <DoCreateVisualScriptAsset>(); endAction.Template = template; endAction.StencilType = typeof(TStencilType); ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, endAction, modelName, GetIcon(), null); }
public void DisplayCompilationErrors(State state) { VseUtility.RemoveLogEntries(); if (ModelsToNodeMapping == null) { UpdateTopology(); } var lastCompilationResult = state.CompilationResultModel.GetLastResult(); if (lastCompilationResult?.errors == null) { return; } var graphAsset = (GraphAssetModel)m_Store.GetState().CurrentGraphModel?.AssetModel; 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); } } if (graphAsset) { 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()); } } }
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; } }
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, () => m_Store.Dispatch(new BuildAllEditorAction())); 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); menu.AddSeparator(""); MenuItem("Reload Graph", 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); m_Store.Dispatch(new LoadGraphAssetAction(path)); } }); 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("Clear Searcher Databases", false, () => { var provider = m_Store.GetState().CurrentGraphModel.Stencil.GetSearcherDatabaseProvider(); provider.ClearTypesItemsSearcherDatabases(); provider.ClearTypeMembersSearcherDatabases(); provider.ClearGraphElementsSearcherDatabases(); provider.ClearGraphVariablesSearcherDatabases(); }); 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; } }); } foreach (IPluginHandler pluginType in m_Store.GetState().EditorDataModel.PluginRepository.RegisteredPlugins) { pluginType.OptionsMenu(menu); } var compilationResult = m_Store.GetState()?.CompilationResultModel?.GetLastResult(); } menu.ShowAsContext(); }