//The title name or icon of the node static void ShowHeader(Node node) { //text if ( !node.showIcon || node.iconAlignment != Alignment2x2.Default ) { if ( node.name != null ) { string hex; var isProSkin = EditorGUIUtility.isProSkin; if ( node.nodeColor != default(Color) ) { hex = node.nodeColor.grayscale > 0.6f ? DEFAULT_HEX_COLOR_DARK : DEFAULT_HEX_COLOR_LIGHT; } else { hex = isProSkin ? node.hexColor : DEFAULT_HEX_COLOR_DARK; } if ( node.nodeColor != default(Color) ) { GUI.color = node.nodeColor; var headerHeight = node.rect.height <= 35 ? 35 : 27; GUI.Box(new Rect(0, 0, node.rect.width, headerHeight), string.Empty, StyleSheet.windowHeader); GUI.color = Color.white; } var finalTitle = node is IGraphAssignable ? string.Format("{{ {0} }}", node.name) : node.name; var text = string.Format("<b><size=12><color=#{0}>{1}</color></size></b>", hex, finalTitle); var image = node.showIcon && node.iconAlignment == Alignment2x2.Left ? node.icon : null; var content = new GUIContent(text, image); GUILayout.Label(content, StyleSheet.windowTitle, GUILayout.MaxHeight(23)); } } //icon if ( node.showIcon && ( node.iconAlignment == Alignment2x2.Default || node.iconAlignment == Alignment2x2.Bottom ) ) { GUI.color = node.nodeColor.a > 0.2f ? node.nodeColor : Color.white; if ( !EditorGUIUtility.isProSkin ) { var assignable = node as ITaskAssignable; IconAttribute att = null; if ( assignable != null && assignable.task != null ) { att = assignable.task.GetType().RTGetAttribute<IconAttribute>(true); } if ( att == null ) { att = node.GetType().RTGetAttribute<IconAttribute>(true); } if ( att != null ) { if ( att.fixedColor == false ) { GUI.color = Color.black.WithAlpha(0.7f); } } } GUI.backgroundColor = Color.clear; GUILayout.Box(node.icon, StyleSheet.box, GUILayout.MaxHeight(32)); GUI.backgroundColor = Color.white; GUI.color = Color.white; } }
//Handles events, Mouse downs, ups etc. static void HandleEvents(Node node, Event e) { //Node click if ( e.type == EventType.MouseDown && GraphEditorUtility.allowClick && e.button != 2 ) { Undo.RegisterCompleteObjectUndo(node.graph, "Move Node"); if ( !e.control ) { GraphEditorUtility.activeElement = node; } if ( e.control ) { if ( node.isSelected ) { GraphEditorUtility.activeElements.Remove(node); } else { GraphEditorUtility.activeElements.Add(node); } } if ( e.button == 0 ) { node.nodeIsPressed = true; } //Double click if ( e.button == 0 && e.clickCount == 2 ) { if ( node is IGraphAssignable && ( node as IGraphAssignable ).nestedGraph != null ) { node.graph.currentChildGraph = ( node as IGraphAssignable ).nestedGraph; node.nodeIsPressed = false; } else if ( node is ITaskAssignable && ( node as ITaskAssignable ).task != null ) { EditorUtils.OpenScriptOfType(( node as ITaskAssignable ).task.GetType()); } else { EditorUtils.OpenScriptOfType(node.GetType()); } e.Use(); } node.OnNodePicked(); } //Mouse up if ( e.type == EventType.MouseUp ) { if ( node.nodeIsPressed ) { node.TrySortConnectionsByPositionX(); } node.nodeIsPressed = false; node.OnNodeReleased(); } }
//If the node implements ITaskAssignable this is shown for the user to assign a task static void TaskAssignableGUI(Node node) { if ( node is ITaskAssignable ) { var assignable = ( node as ITaskAssignable ); System.Type taskType = null; var interfaces = node.GetType().GetInterfaces(); for ( var i = 0; i < interfaces.Length; i++ ) { var iType = interfaces[i]; if ( iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(ITaskAssignable<>) ) { taskType = iType.GetGenericArguments()[0]; break; } } if ( taskType != null ) { TaskEditor.TaskFieldMulti(assignable.task, node.graph, taskType, (t) => { node._icon = null; assignable.task = t; }); } } }
///Disconnects and then removes a node from this graph public void RemoveNode(Node node, bool recordUndo = true) { if (node.GetType().RTGetAttribute <ParadoxNotion.Design.ProtectedAttribute>(true) != null) { return; } if (!allNodes.Contains(node)) { Debug.LogWarning("Node is not part of this graph"); return; } #if UNITY_EDITOR if (!Application.isPlaying) { //auto reconnect parent & child of deleted node. Just a workflow convenience if (autoSort && node.inConnections.Count == 1 && node.outConnections.Count == 1) { var relinkNode = node.outConnections[0].targetNode; if (relinkNode != node.inConnections[0].sourceNode) { RemoveConnection(node.outConnections[0]); node.inConnections[0].SetTarget(relinkNode); } } } //TODO: Fix this in the property accessors? currentSelection = null; #endif //callback node.OnDestroy(); //disconnect parents foreach (var inConnection in node.inConnections.ToArray()) { RemoveConnection(inConnection); } //disconnect children foreach (var outConnection in node.outConnections.ToArray()) { RemoveConnection(outConnection); } if (recordUndo) { RecordUndo("Delete Node"); } allNodes.Remove(node); if (node == primeNode) { primeNode = GetNodeWithID(2); } UpdateNodeIDs(false); }
///Disconnects and then removes a node from this graph public void RemoveNode(Node node, bool recordUndo = true, bool force = false) { if (!force && node.GetType().RTIsDefined <ParadoxNotion.Design.ProtectedSingletonAttribute>(true)) { if (allNodes.Where(n => n.GetType() == node.GetType()).ToArray().Length == 1) { return; } } if (!allNodes.Contains(node)) { Logger.LogWarning("Node is not part of this graph.", "NodeCanvas", this); return; } #if UNITY_EDITOR if (!Application.isPlaying) { //auto reconnect parent & child of deleted node. Just a workflow convenience if (autoSort && node.inConnections.Count == 1 && node.outConnections.Count == 1) { var relinkNode = node.outConnections[0].targetNode; if (relinkNode != node.inConnections[0].sourceNode) { RemoveConnection(node.outConnections[0]); node.inConnections[0].SetTarget(relinkNode); } } } NodeCanvas.Editor.GraphEditorUtility.activeElement = null; #endif //callback node.OnDestroy(); //disconnect parents foreach (var inConnection in node.inConnections.ToArray()) { RemoveConnection(inConnection); } //disconnect children foreach (var outConnection in node.outConnections.ToArray()) { RemoveConnection(outConnection); } if (recordUndo) { RecordUndo("Delete Node"); } allNodes.Remove(node); if (node == primeNode) { primeNode = GetNodeWithID(primeNode.ID); } UpdateNodeIDs(false); }
//Returns single node context menu static GenericMenu GetNodeMenu_Single(Node node) { var menu = new GenericMenu(); if ( node.graph.primeNode != node && node.allowAsPrime ) { menu.AddItem(new GUIContent("Set Start"), false, () => { node.graph.primeNode = node; }); } if ( node is IGraphAssignable ) { menu.AddItem(new GUIContent("Edit Nested (Double Click)"), false, () => { node.graph.currentChildGraph = ( node as IGraphAssignable ).nestedGraph; }); } menu.AddItem(new GUIContent("Duplicate (CTRL+D)"), false, () => { GraphEditorUtility.activeElement = node.Duplicate(node.graph); }); menu.AddItem(new GUIContent("Copy Node"), false, () => { CopyBuffer.Set<Node[]>(new Node[] { node }); }); if ( node.inConnections.Count > 0 ) { menu.AddItem(new GUIContent(node.isActive ? "Disable" : "Enable"), false, () => { node.SetActive(!node.isActive); }); } if ( node.graph.isTree && node.outConnections.Count > 0 ) { menu.AddItem(new GUIContent(node.collapsed ? "Expand Children" : "Collapse Children"), false, () => { node.collapsed = !node.collapsed; }); } if ( node is ITaskAssignable ) { var assignable = node as ITaskAssignable; if ( assignable.task != null ) { menu.AddItem(new GUIContent("Copy Assigned Task"), false, () => { CopyBuffer.Set<Task>(assignable.task); }); } else { menu.AddDisabledItem(new GUIContent("Copy Assigned Task")); } if ( CopyBuffer.Has<Task>() ) { menu.AddItem(new GUIContent("Paste Assigned Task"), false, () => { if ( assignable.task == CopyBuffer.Peek<Task>() ) { return; } if ( assignable.task != null ) { if ( !EditorUtility.DisplayDialog("Paste Task", string.Format("Node already has a Task assigned '{0}'. Replace assigned task with pasted task '{1}'?", assignable.task.name, CopyBuffer.Peek<Task>().name), "YES", "NO") ) { return; } } try { assignable.task = CopyBuffer.Get<Task>().Duplicate(node.graph); } catch { ParadoxNotion.Services.Logger.LogWarning("Can't paste Task here. Incombatible Types", "Editor", node); } }); } else { menu.AddDisabledItem(new GUIContent("Paste Assigned Task")); } } //extra items with override menu = node.OnContextMenu(menu); if ( menu != null ) { //extra items with attribute foreach ( var _m in node.GetType().RTGetMethods() ) { var m = _m; var att = m.RTGetAttribute<ContextMenu>(true); if ( att != null ) { menu.AddItem(new GUIContent(att.menuItem), false, () => { m.Invoke(node, null); }); } } menu.AddSeparator("/"); menu.AddItem(new GUIContent("Delete (DEL)"), false, () => { node.graph.RemoveNode(node); }); } return menu; }
//The title name or icon of the node static void ShowHeader(Node node) { var colorizeHeader = NCPrefs.nodeHeaderStyle == NCPrefs.NodeHeaderStyle.ColorizeHeader; //alternative idea where header gets a colored background instead of coloring the text if (!node.showIcon || node.iconAlignment != Alignment2x2.Default) { if (node.name != null) { var finalTitle = node is IGraphAssignable?string.Format("{{ {0} }}", node.name) : node.name; var image = node.showIcon && node.iconAlignment == Alignment2x2.Left? node.icon : null; string hex; var isProSkin = EditorGUIUtility.isProSkin; if (colorizeHeader && node.nodeColor != default(Color)) { hex = node.nodeColor.grayscale > 0.6f? DEFAULT_HEX_COLOR_DARK : DEFAULT_HEX_COLOR_LIGHT; } else { hex = isProSkin? node.hexColor : DEFAULT_HEX_COLOR_DARK; } if (colorizeHeader && node.nodeColor != default(Color)) { GUI.color = node.nodeColor; var headerHeight = node.rect.height <= 35? 35 : 27; GUI.Box(new Rect(0, 0, node.rect.width, headerHeight), string.Empty, CanvasStyles.windowHeader); GUI.color = Color.white; } var text = string.Format("<b><size=12><color=#{0}>{1}{2}</color></size></b>", hex, (image != null? " " : ""), finalTitle); var content = new GUIContent(text, image, node.description); GUILayout.Label(content, CanvasStyles.nodeTitle, GUILayout.MaxHeight(23)); } } if (node.showIcon && (node.iconAlignment == Alignment2x2.Default || node.iconAlignment == Alignment2x2.Bottom)) //prefs in icon mode AND has icon { GUI.color = node.nodeColor.a > 0.2f? node.nodeColor : Color.white; if (!EditorGUIUtility.isProSkin) { var assignable = node as ITaskAssignable; IconAttribute att = null; if (assignable != null && assignable.task != null) { att = assignable.task.GetType().RTGetAttribute <IconAttribute>(true); } if (att == null) { att = node.GetType().RTGetAttribute <IconAttribute>(true); } if (att != null) { if (att.fixedColor == false) { GUI.color = new Color(0f, 0f, 0f, 0.7f); } } } GUI.backgroundColor = Color.clear; GUILayout.Box(node.icon, CanvasStyles.box, GUILayout.MaxHeight(32)); GUI.backgroundColor = Color.white; GUI.color = Color.white; } //horizontal line node color indicator if (!colorizeHeader && node.name != null && node.nodeColor.a > 0.2f && (!node.showIcon || !node.hasColorAttribute)) { var lastRect = GUILayoutUtility.GetLastRect(); var hMargin = EditorGUIUtility.isProSkin? 4 : 1; GUILayout.Space(2); GUI.color = node.nodeColor; GUI.DrawTexture(new Rect(hMargin, lastRect.yMax, node.rect.width - (hMargin * 2), 3), EditorGUIUtility.whiteTexture); GUI.color = Color.white; } }