public void OnGUI() { DrawGUIToolBar(); using (new EditorGUILayout.HorizontalScope()) { DrawGUINodeGraph(); if(showErrors) { DrawGUINodeErrors(); } } /* Event Handling: - Supporting dragging script into window to create node. - Context Menu - NodeGUI connection. - Command(Delete, Copy, etc...) */ switch (Event.current.type) { // detect dragging script then change interface to "(+)" icon. case EventType.DragUpdated: { var refs = DragAndDrop.objectReferences; foreach (var refe in refs) { if (refe.GetType() == typeof(UnityEditor.MonoScript)) { Type scriptTypeInfo = ((MonoScript)refe).GetClass(); Type inheritedTypeInfo = GetDragAndDropAcceptableScriptType(scriptTypeInfo); if (inheritedTypeInfo != null) { // at least one asset is script. change interface. DragAndDrop.visualMode = DragAndDropVisualMode.Copy; break; } } } break; } // script drop on editor. case EventType.DragPerform: { var pathAndRefs = new Dictionary<string, object>(); for (var i = 0; i < DragAndDrop.paths.Length; i++) { var path = DragAndDrop.paths[i]; var refe = DragAndDrop.objectReferences[i]; pathAndRefs[path] = refe; } var shouldSave = false; foreach (var item in pathAndRefs) { var refe = (MonoScript)item.Value; if (refe.GetType() == typeof(UnityEditor.MonoScript)) { Type scriptTypeInfo = refe.GetClass(); Type inheritedTypeInfo = GetDragAndDropAcceptableScriptType(scriptTypeInfo); if (inheritedTypeInfo != null) { var dropPos = Event.current.mousePosition; var scriptName = refe.name; var scriptClassName = scriptName; AddNodeFromCode(scriptName, scriptClassName, inheritedTypeInfo, dropPos.x, dropPos.y); shouldSave = true; } } } if (shouldSave) { SaveGraphWithReload(); } break; } // show context menu case EventType.ContextClick: { var rightClickPos = Event.current.mousePosition; var menu = new GenericMenu(); foreach (var menuItemStr in AssetBundleGraphSettings.GUI_Menu_Item_TargetGUINodeDict.Keys) { var kind = AssetBundleGraphSettings.GUI_Menu_Item_TargetGUINodeDict[menuItemStr]; menu.AddItem( new GUIContent(menuItemStr), false, () => { AddNodeFromGUI(kind, rightClickPos.x, rightClickPos.y); SaveGraphWithReload(); Repaint(); } ); } menu.ShowAsContext(); break; } /* Handling mouseUp at empty space. */ case EventType.MouseUp: { modifyMode = ModifyMode.NONE; HandleUtility.Repaint(); if (activeObject.idPosDict.ReadonlyDict().Any()) { Undo.RecordObject(this, "Unselect"); foreach (var activeObjectId in activeObject.idPosDict.ReadonlyDict().Keys) { // unselect all. foreach (var node in nodes) { if (activeObjectId == node.Id) { node.SetInactive(); } } foreach (var connection in connections) { if (activeObjectId == connection.Id) { connection.SetInactive(); } } } activeObject = RenewActiveObject(new List<string>()); } // clear inspector if( Selection.activeObject is NodeGUIInspectorHelper || Selection.activeObject is ConnectionGUIInspectorHelper) { Selection.activeObject = null; } break; } /* scale up or down by command & + or command & -. */ case EventType.KeyDown: { if (Event.current.command) { if (Event.current.shift && Event.current.keyCode == KeyCode.Semicolon) { NodeGUI.scaleFactor = NodeGUI.scaleFactor + 0.1f; if (NodeGUI.scaleFactor < NodeGUI.SCALE_MIN) NodeGUI.scaleFactor = NodeGUI.SCALE_MIN; if (NodeGUI.SCALE_MAX < NodeGUI.scaleFactor) NodeGUI.scaleFactor = NodeGUI.SCALE_MAX; Event.current.Use(); break; } if (Event.current.keyCode == KeyCode.Minus) { NodeGUI.scaleFactor = NodeGUI.scaleFactor - 0.1f; if (NodeGUI.scaleFactor < NodeGUI.SCALE_MIN) NodeGUI.scaleFactor = NodeGUI.SCALE_MIN; if (NodeGUI.SCALE_MAX < NodeGUI.scaleFactor) NodeGUI.scaleFactor = NodeGUI.SCALE_MAX; Event.current.Use(); break; } } break; } case EventType.ValidateCommand: { switch (Event.current.commandName) { // Delete active node or connection. case "Delete": { if (activeObject.idPosDict.ReadonlyDict().Any()) { Event.current.Use(); } break; } case "Copy": { if (activeObject.idPosDict.ReadonlyDict().Any()) { Event.current.Use(); } break; } case "Cut": { if (activeObject.idPosDict.ReadonlyDict().Any()) { Event.current.Use(); } break; } case "Paste": { if(copyField.datas == null) { break; } if (copyField.datas.Any()) { Event.current.Use(); } break; } case "SelectAll": { Event.current.Use(); break; } } break; } case EventType.ExecuteCommand: { switch (Event.current.commandName) { // Delete active node or connection. case "Delete": { if (!activeObject.idPosDict.ReadonlyDict().Any()) break; Undo.RecordObject(this, "Delete Selection"); foreach (var targetId in activeObject.idPosDict.ReadonlyDict().Keys) { DeleteNode(targetId); DeleteConnectionById(targetId); } SaveGraphWithReload(); activeObject = RenewActiveObject(new List<string>()); UpdateActivationOfObjects(activeObject); Event.current.Use(); break; } case "Copy": { if (!activeObject.idPosDict.ReadonlyDict().Any()) { break; } Undo.RecordObject(this, "Copy Selection"); var targetNodeIds = activeObject.idPosDict.ReadonlyDict().Keys.ToList(); var targetNodeJsonRepresentations = JsonRepresentations(targetNodeIds); copyField = new CopyField(targetNodeJsonRepresentations, CopyType.COPYTYPE_COPY); Event.current.Use(); break; } case "Cut": { if (!activeObject.idPosDict.ReadonlyDict().Any()) { break; } Undo.RecordObject(this, "Cut Selection"); var targetNodeIds = activeObject.idPosDict.ReadonlyDict().Keys.ToList(); var targetNodeJsonRepresentations = JsonRepresentations(targetNodeIds); copyField = new CopyField(targetNodeJsonRepresentations, CopyType.COPYTYPE_CUT); foreach (var targetId in activeObject.idPosDict.ReadonlyDict().Keys) { DeleteNode(targetId); DeleteConnectionById(targetId); } SaveGraphWithReload(); InitializeGraph(); activeObject = RenewActiveObject(new List<string>()); UpdateActivationOfObjects(activeObject); Event.current.Use(); break; } case "Paste": { if(copyField.datas == null) { break; } var nodeNames = nodes.Select(node => node.Name).ToList(); var duplicatingData = new List<NodeGUI>(); if (copyField.datas.Any()) { var pasteType = copyField.type; foreach (var copyFieldData in copyField.datas) { var nodeJsonDict = AssetBundleGraph.Json.Deserialize(copyFieldData) as Dictionary<string, object>; var pastingNode = new NodeGUI(new NodeData(nodeJsonDict)); var pastingNodeName = pastingNode.Name; var nameOverlapping = nodeNames.Where(name => name == pastingNodeName).ToList(); switch (pasteType) { case CopyType.COPYTYPE_COPY: { if (2 <= nameOverlapping.Count) { continue; } break; } case CopyType.COPYTYPE_CUT: { if (1 <= nameOverlapping.Count) { continue; } break; } } duplicatingData.Add(pastingNode); } } // consume copyField copyField.datas = null; if (!duplicatingData.Any()) { break; } Undo.RecordObject(this, "Paste"); foreach (var newNode in duplicatingData) { DuplicateNode(newNode); } SaveGraphWithReload(); InitializeGraph(); Event.current.Use(); break; } case "SelectAll": { Undo.RecordObject(this, "Select All Objects"); var nodeIds = nodes.Select(node => node.Id).ToList(); activeObject = RenewActiveObject(nodeIds); // select all. foreach (var node in nodes) { node.SetActive(); } foreach (var connection in connections) { connection.SetActive(); } Event.current.Use(); break; } default: { break; } } break; } } }
public void OnGUI() { using (new EditorGUILayout.HorizontalScope(GUI.skin.box)) { if (GUILayout.Button(reloadButtonTexture, GUILayout.Height(18))) { Setup(); } if (GUILayout.Button("Build (active build target is " + EditorUserBuildSettings.activeBuildTarget + ")", GUILayout.Height(18))) { Run(); } } /* scroll view. */ // var scaledScrollPos = Node.ScaleEffect(scrollPos); scrollPos = EditorGUILayout.BeginScrollView(scrollPos); // scrollPos = scrollPos + (movedScrollPos - scaledScrollPos); { // draw node window x N. { BeginWindows(); nodes.ForEach(node => node.DrawNode()); EndWindows(); } // draw connection input point marks. foreach (var node in nodes) { node.DrawConnectionInputPointMark(currentEventSource, modifyMode == ModifyMode.CONNECT_STARTED); } // draw connections. foreach (var con in connections) { if (connectionThroughputs.ContainsKey(con.connectionId)) { var throughputListDict = connectionThroughputs[con.connectionId]; con.DrawConnection(nodes, throughputListDict); } else { con.DrawConnection(nodes, new Dictionary<string, List<ThroughputAsset>>()); } } // draw connection output point marks. foreach (var node in nodes) { node.DrawConnectionOutputPointMark(currentEventSource, modifyMode == ModifyMode.CONNECT_STARTED, Event.current); } /* draw connecting line if modifing connection. */ switch (modifyMode) { case ModifyMode.CONNECT_STARTED: { // from start node to mouse. DrawStraightLineFromCurrentEventSourcePointTo(Event.current.mousePosition, currentEventSource); break; } case ModifyMode.CONNECT_ENDED: { // do nothing break; } case ModifyMode.SELECTION_STARTED: { GUI.DrawTexture(new Rect(selection.x, selection.y, Event.current.mousePosition.x - selection.x, Event.current.mousePosition.y - selection.y), selectionTex); break; } } /* mouse drag event handling. */ switch (Event.current.type) { // draw line while dragging. case EventType.MouseDrag: { switch (modifyMode) { case ModifyMode.CONNECT_ENDED: { switch (Event.current.button) { case 0:{// left click if (Event.current.command) { scalePoint = new ScalePoint(Event.current.mousePosition, Node.scaleFactor, 0); modifyMode = ModifyMode.SCALING_STARTED; break; } selection = new AssetBundleGraphSelection(Event.current.mousePosition); modifyMode = ModifyMode.SELECTION_STARTED; break; } case 2:{// middle click. scalePoint = new ScalePoint(Event.current.mousePosition, Node.scaleFactor, 0); modifyMode = ModifyMode.SCALING_STARTED; break; } } break; } case ModifyMode.SELECTION_STARTED: { // do nothing. break; } case ModifyMode.SCALING_STARTED: { var baseDistance = (int)Vector2.Distance(Event.current.mousePosition, new Vector2(scalePoint.x, scalePoint.y)); var distance = baseDistance / Node.SCALE_WIDTH; var direction = (0 < Event.current.mousePosition.y - scalePoint.y); if (!direction) distance = -distance; // var before = Node.scaleFactor; Node.scaleFactor = scalePoint.startScale + (distance * Node.SCALE_RATIO); if (Node.scaleFactor < Node.SCALE_MIN) Node.scaleFactor = Node.SCALE_MIN; if (Node.SCALE_MAX < Node.scaleFactor) Node.scaleFactor = Node.SCALE_MAX; break; } } HandleUtility.Repaint(); Event.current.Use(); break; } } /* mouse up event handling. use rawType for detect for detectiong mouse-up which raises outside of window. */ switch (Event.current.rawType) { case EventType.MouseUp: { switch (modifyMode) { /* select contained nodes & connections. */ case ModifyMode.SELECTION_STARTED: { var x = 0f; var y = 0f; var width = 0f; var height = 0f; if (Event.current.mousePosition.x < selection.x) { x = Event.current.mousePosition.x; width = selection.x - Event.current.mousePosition.x; } if (selection.x < Event.current.mousePosition.x) { x = selection.x; width = Event.current.mousePosition.x - selection.x; } if (Event.current.mousePosition.y < selection.y) { y = Event.current.mousePosition.y; height = selection.y - Event.current.mousePosition.y; } if (selection.y < Event.current.mousePosition.y) { y = selection.y; height = Event.current.mousePosition.y - selection.y; } var activeObjectIds = new List<string>(); var selectedRect = new Rect(x, y, width, height); foreach (var node in nodes) { var nodeRect = new Rect(node.GetRect()); nodeRect.x = nodeRect.x * Node.scaleFactor; nodeRect.y = nodeRect.y * Node.scaleFactor; nodeRect.width = nodeRect.width * Node.scaleFactor; nodeRect.height = nodeRect.height * Node.scaleFactor; // get containd nodes, if (nodeRect.Overlaps(selectedRect)) { activeObjectIds.Add(node.nodeId); } } foreach (var connection in connections) { // get contained connection badge. if (connection.GetRect().Overlaps(selectedRect)) { activeObjectIds.Add(connection.connectionId); } } if (Event.current.shift) { // add current active object ids to new list. foreach (var alreadySelectedObjectId in activeObject.idPosDict.ReadonlyDict().Keys) { if (!activeObjectIds.Contains(alreadySelectedObjectId)) activeObjectIds.Add(alreadySelectedObjectId); } } else { // do nothing, means cancel selections if nodes are not contained by selection. } Undo.RecordObject(this, "Select Objects"); activeObject = RenewActiveObject(activeObjectIds); UpdateActivationOfObjects(activeObject); selection = new AssetBundleGraphSelection(Vector2.zero); modifyMode = ModifyMode.CONNECT_ENDED; HandleUtility.Repaint(); Event.current.Use(); break; } case ModifyMode.SCALING_STARTED: { modifyMode = ModifyMode.CONNECT_ENDED; break; } } break; } } // set rect for scroll. if (nodes.Any()) { GUILayoutUtility.GetRect(new GUIContent(string.Empty), GUIStyle.none, GUILayout.Width(spacerRectRightBottom.x), GUILayout.Height(spacerRectRightBottom.y)); } } EditorGUILayout.EndScrollView(); /* detect dragging some script into window. right click. connection end mouse up. command(Delete, Copy, and more) */ switch (Event.current.type) { // detect dragging script then change interface to "(+)" icon. case EventType.DragUpdated: { var refs = DragAndDrop.objectReferences; foreach (var refe in refs) { if (refe.GetType() == typeof(UnityEditor.MonoScript)) { var type = ((MonoScript)refe).GetClass(); var inherited = IsAcceptableScriptType(type); if (inherited != null) { // at least one asset is script. change interface. DragAndDrop.visualMode = DragAndDropVisualMode.Copy; break; } } } break; } // script drop on editor. case EventType.DragPerform: { var pathAndRefs = new Dictionary<string, object>(); for (var i = 0; i < DragAndDrop.paths.Length; i++) { var path = DragAndDrop.paths[i]; var refe = DragAndDrop.objectReferences[i]; pathAndRefs[path] = refe; } var shouldSave = false; foreach (var item in pathAndRefs) { var path = item.Key; var refe = (MonoScript)item.Value; if (refe.GetType() == typeof(UnityEditor.MonoScript)) { var type = refe.GetClass(); var inherited = IsAcceptableScriptType(type); if (inherited != null) { var dropPos = Event.current.mousePosition; var scriptName = refe.name; var scriptType = scriptName;// name = type. var scriptPath = path; AddNodeFromCode(scriptName, scriptType, scriptPath, inherited, Guid.NewGuid().ToString(), dropPos.x, dropPos.y); shouldSave = true; } } } if (shouldSave) SaveGraphWithReload(); break; } // show context menu case EventType.ContextClick: { var rightClickPos = Event.current.mousePosition; var menu = new GenericMenu(); foreach (var menuItemStr in AssetBundleGraphSettings.GUI_Menu_Item_TargetGUINodeDict.Keys) { var targetGUINodeNameStr = AssetBundleGraphSettings.GUI_Menu_Item_TargetGUINodeDict[menuItemStr]; menu.AddItem( new GUIContent(menuItemStr), false, () => { AddNodeFromGUI(string.Empty, targetGUINodeNameStr, Guid.NewGuid().ToString(), rightClickPos.x, rightClickPos.y); SaveGraphWithReload(); Repaint(); } ); } menu.ShowAsContext(); break; } /* handling mouse up -> drag released -> release modifyMode. */ case EventType.MouseUp: { modifyMode = ModifyMode.CONNECT_ENDED; HandleUtility.Repaint(); if (activeObject.idPosDict.ReadonlyDict().Any()) { Undo.RecordObject(this, "Unselect"); foreach (var activeObjectId in activeObject.idPosDict.ReadonlyDict().Keys) { // unselect all. foreach (var node in nodes) { if (activeObjectId == node.nodeId) node.SetInactive(); } foreach (var connection in connections) { if (activeObjectId == connection.connectionId) connection.SetInactive(); } } activeObject = RenewActiveObject(new List<string>()); } break; } /* scale up or down by command & + or command & -. */ case EventType.KeyDown: { if (Event.current.command) { if (Event.current.shift && Event.current.keyCode == KeyCode.Semicolon) { Node.scaleFactor = Node.scaleFactor + 0.1f; if (Node.scaleFactor < Node.SCALE_MIN) Node.scaleFactor = Node.SCALE_MIN; if (Node.SCALE_MAX < Node.scaleFactor) Node.scaleFactor = Node.SCALE_MAX; Event.current.Use(); break; } if (Event.current.keyCode == KeyCode.Minus) { Node.scaleFactor = Node.scaleFactor - 0.1f; if (Node.scaleFactor < Node.SCALE_MIN) Node.scaleFactor = Node.SCALE_MIN; if (Node.SCALE_MAX < Node.scaleFactor) Node.scaleFactor = Node.SCALE_MAX; Event.current.Use(); break; } } break; } case EventType.ValidateCommand: { switch (Event.current.commandName) { // Delete active node or connection. case "Delete": { if (!activeObject.idPosDict.ReadonlyDict().Any()) break; Undo.RecordObject(this, "Delete Selection"); foreach (var targetId in activeObject.idPosDict.ReadonlyDict().Keys) { DeleteNode(targetId); DeleteConnectionById(targetId); } SaveGraphWithReload(); InitializeGraph(); activeObject = RenewActiveObject(new List<string>()); UpdateActivationOfObjects(activeObject); Event.current.Use(); break; } case "Copy": { if (!activeObject.idPosDict.ReadonlyDict().Any()) { break; } Undo.RecordObject(this, "Copy Selection"); var targetNodeIds = activeObject.idPosDict.ReadonlyDict().Keys.ToList(); var targetNodeJsonRepresentations = JsonRepresentations(targetNodeIds); copyField = new CopyField(targetNodeJsonRepresentations, CopyType.COPYTYPE_COPY); Event.current.Use(); break; } case "Cut": { if (!activeObject.idPosDict.ReadonlyDict().Any()) { break; } Undo.RecordObject(this, "Cut Selection"); var targetNodeIds = activeObject.idPosDict.ReadonlyDict().Keys.ToList(); var targetNodeJsonRepresentations = JsonRepresentations(targetNodeIds); copyField = new CopyField(targetNodeJsonRepresentations, CopyType.COPYTYPE_CUT); foreach (var targetId in activeObject.idPosDict.ReadonlyDict().Keys) { DeleteNode(targetId); DeleteConnectionById(targetId); } SaveGraphWithReload(); InitializeGraph(); activeObject = RenewActiveObject(new List<string>()); UpdateActivationOfObjects(activeObject); Event.current.Use(); break; } case "Paste": { var nodeNames = nodes.Select(node => node.name).ToList(); var duplicatingData = new List<Node>(); if (copyField.datas.Any()) { var pasteType = copyField.type; foreach (var copyFieldData in copyField.datas) { var nodeJsonDict = Json.Deserialize(copyFieldData) as Dictionary<string, object>; var pastingNode = NodeFromJsonDict(nodes.Count, nodeJsonDict); var pastingNodeName = pastingNode.name; var nameOverlapping = nodeNames.Where(name => name == pastingNodeName).ToList(); switch (pasteType) { case CopyType.COPYTYPE_COPY: { if (2 <= nameOverlapping.Count) continue; break; } case CopyType.COPYTYPE_CUT: { if (1 <= nameOverlapping.Count) continue; break; } } duplicatingData.Add(pastingNode); } } if (!duplicatingData.Any()) break; Undo.RecordObject(this, "Paste"); foreach (var newNode in duplicatingData) { DuplicateNode(newNode); } SaveGraphWithReload(); InitializeGraph(); Event.current.Use(); break; } case "SelectAll": { Undo.RecordObject(this, "Select All Objects"); var nodeIds = nodes.Select(node => node.nodeId).ToList(); activeObject = RenewActiveObject(nodeIds); // select all. foreach (var node in nodes) { node.SetActive(); } foreach (var connection in connections) { connection.SetActive(); } Event.current.Use(); break; } default: { break; } } break; } } }