using UnityEditor; using UnityEditor.Experimental.UIElements; using UnityEngine; using UnityEngine.Experimental.UIElements; using UnityEngine.Experimental.UIElements.StyleEnums; using System.Linq; namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView { public class UdonGraphWindow : EditorWindow { private VisualElement _rootView; // Reference to actual Graph View [SerializeField]private UdonGraph _graphView; private UdonGraphProgramAsset _graphAsset; private UdonWelcomeView _welcomeView; private VisualElement _curtain; // Toolbar and Buttons private Toolbar _toolbar; private Label _graphAssetName; private ToolbarMenu _toolbarOptions; private UdonGraphStatus _graphStatus; private ToolbarButton _graphReload; private ToolbarButton _graphCompile; [MenuItem("VRChat SDK/Udon Graph")] private static void ShowWindow() { // Get or focus the window var window = GetWindow("Udon Graph", true, typeof(SceneView)); window.titleContent = new GUIContent("Udon Graph"); } private void LogPlayModeState(PlayModeStateChange state) { switch (state) { case PlayModeStateChange.EnteredEditMode: if (_rootView.Contains(_curtain)) { _curtain.RemoveFromHierarchy(); } break; case PlayModeStateChange.ExitingEditMode: break; case PlayModeStateChange.EnteredPlayMode: _rootView.Add(_curtain); break; case PlayModeStateChange.ExitingPlayMode: break; default: break; } } private void OnEnable() { EditorApplication.playModeStateChanged += LogPlayModeState; InitializeRootView(); _curtain = new VisualElement() { name = "curtain", }; _curtain.Add(new Label("Graph Locked in Play Mode")); _welcomeView = new UdonWelcomeView(); _welcomeView.StretchToParentSize(); _rootView.Add(_welcomeView); SetupToolbar(); Undo.undoRedoPerformed -= OnUndoRedo; //Remove old handler if present to prevent duplicates, doesn't cause errors if not present Undo.undoRedoPerformed += OnUndoRedo; if(_graphAsset != null) { UdonBehaviour udonBehaviour = null; string gPath = Settings.LastUdonBehaviourPath; string sPath = Settings.LastUdonBehaviourScenePath; if (!string.IsNullOrEmpty(gPath) && !string.IsNullOrEmpty(sPath)) { var targetScene = UnityEditor.SceneManagement.EditorSceneManager.GetSceneByPath(sPath); if (targetScene != null && targetScene.isLoaded && targetScene.IsValid()) { var targetObject = UnityEngine.GameObject.Find(gPath); if (targetObject != null) { udonBehaviour = targetObject.GetComponent(); } } } InitializeGraph(_graphAsset, udonBehaviour); } } private void InitializeRootView() { _rootView = this.GetRootVisualContainer(); _rootView.AddStyleSheetPath("UdonGraphStyle"); } public void InitializeGraph(UdonGraphProgramAsset graph, UdonBehaviour udonBehaviour = null) { this._graphAsset = graph; InitializeWindow(); _graphView = _rootView.Children().FirstOrDefault(e => e is UdonGraph) as UdonGraph; if (_graphView == null) { Debug.LogError("GraphView has not been added to the BaseGraph root view!"); return; } _graphView.Initialize(graph, udonBehaviour); _graphStatus.LoadAsset(graph); // Store GUID for this asset to settings for easy reload later if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(graph, out string guid, out long localId)){ Settings.LastGraphGuid = guid; } if (udonBehaviour != null) { Settings.LastUdonBehaviourPath = udonBehaviour.transform.GetHierarchyPath(); Settings.LastUdonBehaviourScenePath = udonBehaviour.gameObject.scene.path; } _graphAssetName.text = graph.name; ShowGraphTools(true); } private void InitializeWindow() { if (_graphView == null) { _graphView = new UdonGraph(this); // we could add the toolbar in here } RemoveIfContaining(_welcomeView); _rootView.Insert(0, _graphView); } private void ReloadWelcome() { RemoveIfContaining(_welcomeView); _rootView.Add(_welcomeView); ShowGraphTools(false); } // TODO: maybe move this to GraphView since it's so connected? private void SetupToolbar() { _toolbar = new Toolbar() { name = "UdonToolbar", }; _rootView.Add(_toolbar); _toolbar.Add(new ToolbarButton(() => { ReloadWelcome(); }) { text = "Welcome" }); _graphAssetName = new Label() { name = "assetName", }; _toolbar.Add(_graphAssetName); _toolbar.Add(new ToolbarFlexSpacer()); _toolbarOptions = new ToolbarMenu { text = "Settings" }; // Show Variables Window _toolbarOptions.menu.AppendAction("Show Variables", (m) => { _graphView.ToggleShowVariables(!_graphView.GetBlackboardVisible()); }, (s)=> { return BoolToStatus(_graphView.GetBlackboardVisible());}); // Show Minimap _toolbarOptions.menu.AppendAction("Show MiniMap", (m) => { _graphView.ToggleShowMiniMap(!_graphView.GetMinimapVisible()); }, (s) => { return BoolToStatus(_graphView.GetMinimapVisible()); }); _toolbarOptions.menu.AppendSeparator(); // Search On Noodle Drop _toolbarOptions.menu.AppendAction("Search on Noodle Drop", (m) => { Settings.SearchOnNoodleDrop = !Settings.SearchOnNoodleDrop; }, (s) => { return BoolToStatus(Settings.SearchOnNoodleDrop); }); // Search On Selected Node _toolbarOptions.menu.AppendAction("Search on Selected Node", (m) => { Settings.SearchOnSelectedNodeRegistry = !Settings.SearchOnSelectedNodeRegistry; }, (s) => { return BoolToStatus(Settings.SearchOnSelectedNodeRegistry); }); _toolbar.Add(_toolbarOptions); _graphCompile = new ToolbarButton(() => { if (_graphAsset != null && _graphAsset is AbstractUdonProgramSource udonProgramSource) { UdonEditorManager.Instance.QueueAndRefreshProgram(udonProgramSource); } }) { text = "Compile" }; _toolbar.Add(_graphCompile); _graphReload = new ToolbarButton(() => { _graphView.Reload(); }) { text = "Reload" }; _toolbar.Add(_graphReload); _graphStatus = new UdonGraphStatus(_rootView); _toolbar.Add(_graphStatus); ShowGraphTools(false); } private DropdownMenu.MenuAction.StatusFlags BoolToStatus(bool value) { return value ? DropdownMenu.MenuAction.StatusFlags.Checked : DropdownMenu.MenuAction.StatusFlags.Normal; } public void ShowGraphTools(bool value) { _graphAssetName.style.visibility = value ? Visibility.Visible : Visibility.Hidden; _toolbarOptions.style.visibility = value ? Visibility.Visible : Visibility.Hidden; _graphCompile.style.visibility = value ? Visibility.Visible : Visibility.Hidden; _graphReload.style.visibility = value ? Visibility.Visible : Visibility.Hidden; _graphStatus.style.visibility = value ? Visibility.Visible : Visibility.Hidden; } private void RemoveIfContaining(VisualElement element) { if (_rootView.Contains(element)) { _rootView.Remove(element); } } private void OnUndoRedo() { Repaint(); } public Graph.UdonGraphData GetGraphDataFromAsset(UdonGraphProgramAsset asset) { InitializeGraph(asset); return _graphView.graphData; } } }