From d181f432fc35f23d1d3854d25ef2234784912303 Mon Sep 17 00:00:00 2001 From: Oli Date: Tue, 10 Jan 2023 21:11:23 +0000 Subject: [PATCH] Added GroupNode --- Editor/GroupNodeEditor.cs | 145 ++++++++++++++++++++++++++ Editor/GroupNodeEditor.cs.meta | 3 + Editor/NodeEditor.cs | 2 + Editor/NodeEditorAction.cs | 67 ++++++++++-- Editor/NodeEditorGUI.cs | 16 +-- Editor/Resources/xnode_group.png | Bin 0 -> 7653 bytes Editor/Resources/xnode_group.png.meta | 124 ++++++++++++++++++++++ Editor/Resources/xnode_node.png | Bin 20191 -> 7918 bytes Runtime/GroupNode.cs | 12 +++ Runtime/GroupNode.cs.meta | 3 + 10 files changed, 357 insertions(+), 15 deletions(-) create mode 100644 Editor/GroupNodeEditor.cs create mode 100644 Editor/GroupNodeEditor.cs.meta create mode 100644 Editor/Resources/xnode_group.png create mode 100644 Editor/Resources/xnode_group.png.meta create mode 100644 Runtime/GroupNode.cs create mode 100644 Runtime/GroupNode.cs.meta diff --git a/Editor/GroupNodeEditor.cs b/Editor/GroupNodeEditor.cs new file mode 100644 index 0000000..eeb5b4f --- /dev/null +++ b/Editor/GroupNodeEditor.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using XNode; +using System.Linq; +using UnityEditor; + +namespace XNodeEditor +{ + [CustomNodeEditor(typeof(XNode.GroupNode))] + public class GroupNodeEditor : NodeEditor + { + private static Vector4 padding = new Vector4(32, 48, 32, 32); + private bool _selected = false; + private UnityEngine.Object[] lastSelection; + + public override void OnHeaderGUI() + { + if (target is XNode.GroupNode node) + { + bool selectChildren = NodeEditorWindow.currentActivity is NodeEditorWindow.NodeActivity.HoldNode or NodeEditorWindow.NodeActivity.DragNode; + if (!_selected && Selection.activeObject == target && selectChildren) + { + _selected = true; + var selection = Selection.objects.ToList(); + lastSelection = selection.ToArray(); + GetChildren(node, ref selection); + //selection.AddRange(GetChildren(node)); + Selection.objects = selection.Distinct().ToArray(); + NodeEditorWindow.current.Repaint(); + } + else if (_selected && !selectChildren) + { + _selected = false; + Selection.objects = lastSelection; + } + } + base.OnHeaderGUI(); + } + + private void GetChildren(XNode.GroupNode group, ref List list) + { + foreach (var child in group.children) + { + if (list.Contains(child)) continue; + list.Add(child); + if (child is XNode.GroupNode _group) GetChildren(_group, ref list); + } + } + + public override void OnBodyGUI() + { + var e = Event.current; + var node = target as XNode.GroupNode; + + var nodes = node.graph.nodes; + if (e.type == EventType.Repaint) + { + if (nodes.FirstOrDefault() != node) + { + nodes.Remove(node); + int targetIndex = 0; + for (int i = 0; i < nodes.Count; i++) + { + if (nodes[i] is XNode.GroupNode _group) + { + if (_group.children.Contains(node)) + { + targetIndex = i + 1; + break; + } + } + else break; + } + nodes.Insert(targetIndex, node); + } + } + + if (node == null || node.children == null || node.children.Count == 0) return; + node.position = new Vector2( + node.children.Min(x => x.position.x) - padding.x, + node.children.Min(x => x.position.y) - padding.y + ); + GUILayout.Label(""); + } + + public override Color GetTint() + { + Type type = target.GetType(); + if (type.TryGetAttributeTint(out Color color)) return color; + + if (!(target is XNode.GroupNode node)) return NodeEditorPreferences.GetSettings().tintColor; + return node.color; + } + + public override int GetWidth() + { + int min = base.GetWidth(); + var node = target as XNode.GroupNode; + if (node == null || node.children == null || node.children.Count == 0) return min + (int)padding.x + (int)padding.z; + return Mathf.Max(min, + node.children.Max(x => + GetEditor(x, window).GetWidth() + (int)x.position.x) - (int)target.position.x) + + (int)padding.z; + } + + public override int GetMinHeight() + { + int min = base.GetMinHeight(); + var node = target as XNode.GroupNode; + if (node == null || node.children == null || node.children.Count == 0) return min + (int)padding.y + (int)padding.w; + return Mathf.Max(min, + node.children.Max(x => GetEditor(x, window).GetMinHeight() + (int) x.position.y - (int) target.position.y)) + + (int) padding.w; + } + + + private static int GetNodeWidth(Node node) + { + Type type = node.GetType(); + return (type.TryGetAttributeWidth(out int width) ? width : 208); + } + + private static int GetNodeHeight(Node node) + { + Type type = node.GetType(); + return (type.TryGetAttributeHeight(out int height) ? height : 100); + } + + + private static Texture2D nodeGroupBody { get { return _nodeGroupBody != null ? _nodeGroupBody : _nodeGroupBody = Resources.Load("xnode_group"); } } + private static Texture2D _nodeGroupBody; + public override GUIStyle GetBodyStyle() + { + var style = new GUIStyle(base.GetBodyStyle()) + { + normal = + { + background = nodeGroupBody + } + }; + return style; + } + } +} \ No newline at end of file diff --git a/Editor/GroupNodeEditor.cs.meta b/Editor/GroupNodeEditor.cs.meta new file mode 100644 index 0000000..1e3be7d --- /dev/null +++ b/Editor/GroupNodeEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 24f2e755a9b5423fb2792a1b075ca612 +timeCreated: 1673303313 \ No newline at end of file diff --git a/Editor/NodeEditor.cs b/Editor/NodeEditor.cs index ae3fdfa..e845aa2 100644 --- a/Editor/NodeEditor.cs +++ b/Editor/NodeEditor.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; +using XNode; + #if ODIN_INSPECTOR using Sirenix.OdinInspector.Editor; using Sirenix.Utilities; diff --git a/Editor/NodeEditorAction.cs b/Editor/NodeEditorAction.cs index e8a6494..9c7f1cc 100644 --- a/Editor/NodeEditorAction.cs +++ b/Editor/NodeEditorAction.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; +using XNode; using XNodeEditor.Internal; #if UNITY_2019_1_OR_NEWER && USE_ADVANCED_GENERIC_MENU using GenericMenu = XNodeEditor.AdvancedGenericMenu; @@ -148,7 +149,6 @@ namespace XNodeEditor { } } else if (e.button == 2) { panOffset += e.delta * zoom; - isPanning = true; } break; case EventType.MouseDown: @@ -204,7 +204,7 @@ namespace XNodeEditor { currentActivity = NodeActivity.HoldNode; } // If mousedown on grid background, deselect all - else if (!IsHoveringNode) { + else if (!IsHoveringNode || hoveredNode is XNode.GroupNode) { currentActivity = NodeActivity.HoldGrid; if (!e.control && !e.shift) { selectedReroutes.Clear(); @@ -212,6 +212,7 @@ namespace XNodeEditor { } } } + else if (e.button == 2) isPanning = true; break; case EventType.MouseUp: if (e.button == 0) { @@ -245,7 +246,7 @@ namespace XNodeEditor { IEnumerable nodes = Selection.objects.Where(x => x is XNode.Node).Select(x => x as XNode.Node); foreach (XNode.Node node in nodes) EditorUtility.SetDirty(node); if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); - } else if (!IsHoveringNode) { + } else if (!IsHoveringNode || hoveredNode is XNode.GroupNode) { // If click outside node, release field focus if (!isPanning) { EditorGUI.FocusTextInControl(null); @@ -260,10 +261,7 @@ namespace XNodeEditor { SelectNode(hoveredNode, false); // Double click to center node - if (isDoubleClick) { - Vector2 nodeDimension = nodeSizes.ContainsKey(hoveredNode) ? nodeSizes[hoveredNode] / 2 : Vector2.zero; - panOffset = -hoveredNode.position - nodeDimension; - } + if (isDoubleClick) RenameSelectedNode(); } // If click reroute, select it. @@ -276,7 +274,9 @@ namespace XNodeEditor { currentActivity = NodeActivity.Idle; } else if (e.button == 1) { if (!isPanning) { - if (IsDraggingPort) { + if (currentActivity == NodeActivity.DragNode && Selection.activeObject is Node) + ToggleSelectionGroup(); + else if (IsDraggingPort) { draggedOutputReroutes.Add(WindowToGridPosition(e.mousePosition)); } else if (currentActivity == NodeActivity.DragNode && Selection.activeObject == null && selectedReroutes.Count == 1) { selectedReroutes[0].InsertPoint(selectedReroutes[0].GetPoint()); @@ -292,7 +292,7 @@ namespace XNodeEditor { NodeEditor.GetEditor(hoveredNode, this).AddContextMenuItems(menu); menu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); e.Use(); // Fixes copy/paste context menu appearing in Unity 5.6.6f2 - doesn't occur in 2018.3.2f1 Probably needs to be used in other places. - } else if (!IsHoveringNode) { + } else if (!IsHoveringNode || hoveredNode is GroupNode) { autoConnectOutput = null; GenericMenu menu = new GenericMenu(); graphEditor.AddContextMenuItems(menu); @@ -301,6 +301,11 @@ namespace XNodeEditor { } isPanning = false; } + else if (e.button == 2) + { + isPanning = false; + Repaint(); + } // Reset DoubleClick isDoubleClick = false; break; @@ -349,6 +354,12 @@ namespace XNodeEditor { } Repaint(); break; + case EventType.Repaint: + if (currentActivity == NodeActivity.DragNode) + EditorGUIUtility.AddCursorRect(new Rect(0,0,10000,10000), MouseCursor.MoveArrow); + else if (isPanning) + EditorGUIUtility.AddCursorRect(new Rect(0,0,10000,10000), MouseCursor.Pan); + break; case EventType.Ignore: // If release mouse outside window if (e.rawType == EventType.MouseUp && currentActivity == NodeActivity.DragGrid) { @@ -417,6 +428,44 @@ namespace XNodeEditor { } } + public void ToggleSelectionGroup() + { + var nodes = Selection.objects.OfType().ToArray(); + var allGroups = graph.nodes.OfType().ToArray(); + var groups = allGroups.Where(group => !Selection.objects.Contains(group)).ToArray(); + bool anyGrouped = false; + foreach (var group in groups) + { + foreach (var node in nodes) + { + if (group.children.Contains(node)) + { + group.children.Remove(node); + anyGrouped = true; + } + } + } + + if (!anyGrouped) + { + nodes = nodes.Where(node => !allGroups.Any(group => group.children.Contains(node))).ToArray(); + foreach (var group in groups.Reverse()) + { + var editor = NodeEditor.GetEditor(group, this); + editor.target = group; + var rect = new Rect(group.position.x, group.position.y, editor.GetWidth(), editor.GetMinHeight()); + + if (rect.Contains(WindowToGridPosition(Event.current.mousePosition))) + { + group.children.AddRange(nodes); + break; + } + } + } + + Repaint(); + } + /// Draw this node on top of other nodes by placing it last in the graph.nodes list public void MoveNodeToTop(XNode.Node node) { int index; diff --git a/Editor/NodeEditorGUI.cs b/Editor/NodeEditorGUI.cs index e5b99bf..6872a4e 100644 --- a/Editor/NodeEditorGUI.cs +++ b/Editor/NodeEditorGUI.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; +using XNode; using XNodeEditor.Internal; #if UNITY_2019_1_OR_NEWER && USE_ADVANCED_GENERIC_MENU using GenericMenu = XNodeEditor.AdvancedGenericMenu; @@ -106,15 +107,17 @@ namespace XNodeEditor { /// Show right-click context menu for hovered reroute void ShowRerouteContextMenu(RerouteReference reroute) { - GenericMenu contextMenu = new GenericMenu(); - contextMenu.AddItem(new GUIContent("Remove"), false, () => reroute.RemovePoint()); - contextMenu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); + reroute.RemovePoint(); + //GenericMenu contextMenu = new GenericMenu(); + //contextMenu.AddItem(new GUIContent("Remove"), false, () => reroute.RemovePoint()); + //contextMenu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); } /// Show right-click context menu for hovered port void ShowPortContextMenu(XNode.NodePort hoveredPort) { - GenericMenu contextMenu = new GenericMenu(); + hoveredPort.ClearConnections(); + /*GenericMenu contextMenu = new GenericMenu(); foreach (var port in hoveredPort.GetConnections()) { var name = port.node.name; var index = hoveredPort.GetConnectionIndex(port); @@ -130,7 +133,7 @@ namespace XNodeEditor { else graphEditor.AddContextMenuItems(contextMenu, hoveredPort.ValueType, XNode.NodePort.IO.Input); } - contextMenu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero)); + contextMenu.DropDown(new Rect(Event.current.mousePosition, Vector2.zero));*/ if (NodeEditorPreferences.GetSettings().autoSave) AssetDatabase.SaveAssets(); } @@ -533,7 +536,8 @@ namespace XNodeEditor { //If dragging a selection box, add nodes inside to selection if (currentActivity == NodeActivity.DragGrid) { - if (windowRect.Overlaps(selectionBox)) preSelection.Add(node); + if (node is XNode.GroupNode ? selectionBox.Overlaps(new Rect(windowRect) {height = 32} ) + : windowRect.Overlaps(selectionBox)) preSelection.Add(node); } //Check if we are hovering any of this nodes ports diff --git a/Editor/Resources/xnode_group.png b/Editor/Resources/xnode_group.png new file mode 100644 index 0000000000000000000000000000000000000000..d1cfbd10d952f9ac0d78d40ec2074dc44a749dfe GIT binary patch literal 7653 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 literal 0 HcmV?d00001 diff --git a/Editor/Resources/xnode_group.png.meta b/Editor/Resources/xnode_group.png.meta new file mode 100644 index 0000000..2d0cc4e --- /dev/null +++ b/Editor/Resources/xnode_group.png.meta @@ -0,0 +1,124 @@ +fileFormatVersion: 2 +guid: 8eff5f1a77870ce4189eb84684342245 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 12 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Resources/xnode_node.png b/Editor/Resources/xnode_node.png index 6f0b42ebf871065541423b686e18ba31cf24fb5e..543c5b95aff12b8ff0e4becea516177b5bf3933a 100644 GIT binary patch delta 4379 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 children = new List(); + } +} \ No newline at end of file diff --git a/Runtime/GroupNode.cs.meta b/Runtime/GroupNode.cs.meta new file mode 100644 index 0000000..baf5eb6 --- /dev/null +++ b/Runtime/GroupNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 39b1316a0b0f4e389d24c32de475b0cd +timeCreated: 1673303110 \ No newline at end of file