private void ReloadTabbar() { if (tabbarContainer != null) { tabbarContainer.RemoveFromHierarchy(); } tabbarContainer = new VisualElement() { name = "tabbar-container" }; tabbarContainer.style.left = _tabPosition; tabbarContainer.AddStyleSheet("uNodeStyles/Tabbar"); tabbarContainer.AddStyleSheet(UIElementUtility.Theme.tabbarStyle); var tabbar = new VisualElement() { name = "tabbar" }; { #region Main/Selection Tab if (window.mainGraph != null && window.mainGraph == window.selectedGraph && !window.mainGraph.selectedData.isValidGraph) { window.mainGraph.owner = null; window.mainGraph.graph = null; window.mainGraph.selectedData = new GraphEditorData(); } var tabMainElement = new ClickableElement("\"Main\"") { name = "tab-element", onClick = () => { window.ChangeEditorTarget(null); }, }; tabMainElement.AddManipulator(new ContextualMenuManipulator((evt) => { evt.menu.AppendAction("Close All But This", (act) => { window.graphs.Clear(); window.ChangeEditorTarget(null); ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); evt.menu.AppendSeparator(""); evt.menu.AppendAction("Find Object", (act) => { EditorGUIUtility.PingObject(window.mainGraph.owner); ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); evt.menu.AppendAction("Select Object", (act) => { EditorGUIUtility.PingObject(window.mainGraph.owner); Selection.activeObject = window.mainGraph.owner; ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); })); if (window.selectedGraph == window.mainGraph) { tabMainElement.AddToClassList("tab-selected"); } tabbar.Add(tabMainElement); #endregion for (int i = 0; i < window.graphs.Count; i++) { var graph = window.graphs[i]; try { if (graph == null || graph.owner == null || !graph.selectedData.isValidGraph) { window.graphs.RemoveAt(i); i--; continue; } } catch { window.graphs.RemoveAt(i); i--; continue; } var tabElement = new ClickableElement(graph.displayName) { name = "tab-element", onClick = () => { window.ChangeEditorTarget(graph); }, }; tabElement.AddManipulator(new ContextualMenuManipulator((evt) => { evt.menu.AppendAction("Close", (act) => { var oldData = window.selectedGraph; window.graphs.Remove(graph); window.ChangeEditorTarget(oldData); ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); evt.menu.AppendAction("Close All", (act) => { window.graphs.Clear(); window.ChangeEditorTarget(null); ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); evt.menu.AppendAction("Close Others", (act) => { var current = window.selectedGraph; window.graphs.Clear(); window.graphs.Add(current); window.ChangeEditorTarget(current); ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); evt.menu.AppendSeparator(""); evt.menu.AppendAction("Find Object", (act) => { EditorGUIUtility.PingObject(graph.owner); ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); evt.menu.AppendAction("Select Object", (act) => { EditorGUIUtility.PingObject(graph.owner); Selection.activeObject = graph.owner; ReloadTabbar(); }, DropdownMenuAction.AlwaysEnabled); })); if (window.selectedGraph == graph) { tabElement.AddToClassList("tab-selected"); } tabbar.Add(tabElement); } #region Plus Tab { var plusElement = new ClickableElement("+") { name = "tab-element", }; { plusElement.menu = new DropdownMenu(); plusElement.menu.AppendAction("Open...", (act) => { window.OpenNewGraphTab(); ReloadTabbar(); }); #region Recent Files List <UnityEngine.Object> lastOpenedObjects = uNodeEditor.FindLastOpenedGraphs(); for (int i = 0; i < lastOpenedObjects.Count; i++) { var obj = lastOpenedObjects[i]; if (obj is uNodeRoot) { uNodeRoot root = obj as uNodeRoot; plusElement.menu.AppendAction("Open Recent/" + root.gameObject.name, (act) => { uNodeEditor.ChangeTarget(root, true); }); } else if (obj is uNodeData) { uNodeData data = obj as uNodeData; plusElement.menu.AppendAction("Open Recent/" + data.gameObject.name, (act) => { uNodeEditor.ChangeTarget(data, true); }); } } if (lastOpenedObjects.Count > 0) { plusElement.menu.AppendSeparator("Open Recent/"); plusElement.menu.AppendAction("Open Recent/Clear Recent", (act) => { uNodeEditor.ClearLastOpenedGraphs(); }); } #endregion var graphSystem = GraphUtility.FindGraphSystemAttributes(); int lastOrder = int.MinValue; for (int i = 0; i < graphSystem.Count; i++) { var g = graphSystem[i]; if (i == 0 || Mathf.Abs(g.order - lastOrder) >= 10) { plusElement.menu.AppendSeparator(""); } lastOrder = g.order; plusElement.menu.AppendAction(g.menu, (act) => { string path = EditorUtility.SaveFilePanelInProject("Create " + g.menu, "", "prefab", ""); if (!string.IsNullOrEmpty(path)) { GameObject go = new GameObject(); go.name = path.Split('/').Last().Split('.')[0]; go.AddComponent(g.type); GameObject prefab = PrefabUtility.SaveAsPrefabAsset(go, path); UnityEngine.Object.DestroyImmediate(go); AssetDatabase.SaveAssets(); EditorUtility.FocusProjectWindow(); uNodeEditor.ChangeTarget(prefab.GetComponent(g.type) as uNodeRoot); } }); } } tabbar.Add(plusElement); } #endregion } var pathbar = new VisualElement() { name = "pathbar" }; if (editorData.graph != null) { var graph = new ClickableElement(editorData.graph.DisplayName) { name = "path-element" }; graph.AddToClassList("path-graph"); { graph.menu = new DropdownMenu(); uNodeRoot[] graphs = editorData.graphs; if (graphs == null) { return; } for (int i = 0; i < graphs.Length; i++) { var g = graphs[i]; if (g == null) { continue; } graph.menu.AppendAction(g.DisplayName, (act) => { if (g == editorData.graph) { window.ChangeEditorSelection(g); } else { uNodeEditor.ChangeTarget(g); } }, (act) => { if (g == editorData.graph) { return(DropdownMenuAction.Status.Checked); } return(DropdownMenuAction.Status.Normal); }); } } Type graphIcon = typeof(TypeIcons.GraphIcon); if (editorData.graph is IClass) { IClass classSystem = editorData.graph as IClass; graphIcon = classSystem.IsStruct ? typeof(TypeIcons.StructureIcon) : typeof(TypeIcons.ClassIcon); } graph.ShowIcon(uNodeEditorUtility.GetTypeIcon(graphIcon)); graph.EnableBreadcrumb(true); pathbar.Add(graph); var root = window.selectedGraph.selectedData.selectedRoot; var function = new ClickableElement(root != null ? root.Name : editorData.graph is IStateGraph state && state.canCreateGraph ? "[State Graph]" : editorData.graph is IMacroGraph ? "[MACRO]" : "[NO ROOT]") { name = "path-element" }; function.AddToClassList("path-function"); { function.menu = new DropdownMenu(); if (editorData.graph is IStateGraph stateGraph && stateGraph.canCreateGraph) { function.menu.AppendAction("[State Graph]", (act) => { if (editorData.selectedRoot != null || editorData.selectedGroup != null) { editorData.selected = null; editorData.selectedRoot = null; Refresh(); UpdatePosition(); } window.ChangeEditorSelection(null); }, (act) => { if (editorData.selectedRoot == null) { return(DropdownMenuAction.Status.Checked); } return(DropdownMenuAction.Status.Normal); }); } List <RootObject> roots = new List <RootObject>(); roots.AddRange(editorData.graph.Functions); roots.Sort((x, y) => string.Compare(x.Name, y.Name)); for (int i = 0; i < roots.Count; i++) { var r = roots[i]; if (r == null) { continue; } function.menu.AppendAction(r.Name, (act) => { if (editorData.currentCanvas == r) { window.ChangeEditorSelection(r); } else { editorData.selectedRoot = r; SelectionChanged(); Refresh(); UpdatePosition(); } }, (act) => { if (r == editorData.selectedRoot) { return(DropdownMenuAction.Status.Checked); } return(DropdownMenuAction.Status.Normal); }); } } function.ShowIcon(uNodeEditorUtility.GetTypeIcon(root == null ? typeof(TypeIcons.StateIcon) : typeof(TypeIcons.MethodIcon))); pathbar.Add(function); if (editorData.graph != null && editorData.selectedGroup && editorData.selectedGroup.owner == editorData.graph) { function.EnableBreadcrumb(true); List <Node> GN = new List <Node>(); GN.Add(editorData.selectedGroup); NodeEditorUtility.FindParentNode(editorData.selectedGroup.transform, ref GN, editorData.graph); for (int i = GN.Count - 1; i >= 0; i--) { var nestedGraph = GN[i]; var element = new ClickableElement(nestedGraph.GetNodeName()) { name = "path-element", onClick = () => { window.ChangeEditorSelection(nestedGraph); if (editorData.selectedGroup != nestedGraph) { editorData.selectedGroup = nestedGraph; Refresh(); UpdatePosition(); } } }; element.AddToClassList("path-nested"); element.ShowIcon(uNodeEditorUtility.GetTypeIcon(nestedGraph.GetNodeIcon())); pathbar.Add(element); if (i != 0) { element.EnableBreadcrumb(true); } } } } else { var graph = new ClickableElement("[NO GRAPH]") { name = "path-element" }; pathbar.Add(graph); } tabbarContainer.Add(tabbar); tabbarContainer.Add(pathbar); window.rootVisualElement.Add(tabbarContainer); tabbarContainer.SendToBack(); }