protected void OnGUI() { if (_system == null) { return; } // Not sure why the magic numbers on size are needed to make the scrollbars appear in the correct place.... _scrollPosition = GUI.BeginScrollView(new Rect(0, 0, Screen.width - 4, Screen.height - 21), _scrollPosition, new Rect(0, 0, 5000, 5000), true, true); Event evt = Event.current; if (evt.type == EventType.MouseDrag) { Repaint(); } _connections.Clear(); foreach (MonoBehaviour component in _system.gameObject.GetComponents <MonoBehaviour>()) { Type componentType = component.GetType(); GraphNodeAttribute[] nodeAttributes = componentType.GetCustomAttributes(typeof(GraphNodeAttribute), false) as GraphNodeAttribute[]; if (nodeAttributes != null) { bool hasSystem = false; foreach (GraphNodeAttribute attribute in nodeAttributes) { if (attribute.System == _systemName) { hasSystem = true; break; } } if (!hasSystem) { continue; } GraphNodeData nodeData = _graphData.GetNodeData(component); _areaRect = new Rect(nodeData.Position.x, nodeData.Position.y, nodeData.Width, 1000); GUILayout.BeginArea(_areaRect); GUILayout.Box(ObjectNames.NicifyVariableName(componentType.Name), GUILayout.ExpandWidth(true)); if (evt.type == EventType.ContextClick && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) { GenericMenu menu = new GenericMenu(); menu.AddItem(new GUIContent("Delete"), false, (object data) => { DestroyImmediate(data as MonoBehaviour, false); }, component); menu.ShowAsContext(); evt.Use(); } if (evt.type == EventType.MouseDown && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition) && _dragItem == null) { _dragItem = component; } if (evt.type == EventType.MouseDrag && _dragItem == component) { nodeData.Position += Event.current.delta; Event.current.Use(); } GUILayout.Box("", GUILayout.ExpandWidth(true)); if (evt.type == EventType.MouseUp && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition) && _dragConnectionComponent != null) { if (EditorHelpers.IsSubclassOfRawGeneric(_dragConnectionField.FieldType, component.GetType())) { _dragConnectionField.SetValue(_dragConnectionComponent, component); } } string description = component.ToString(); // ) is the last character on the default ToString... there's probably a better way of doing this, without requiring a custom method on every node if (!string.IsNullOrEmpty(description) && description[description.Length - 1] != ')') { GUI.skin.label.wordWrap = true; GUILayout.Label(description, GUILayout.ExpandWidth(true)); } List <FieldInfo> componentFields = new List <FieldInfo>(); EditorHelpers.FindFields(componentFields, componentType); foreach (FieldInfo field in componentFields) { GraphConnectionAttribute[] connectionAttributes = field.GetCustomAttributes(typeof(GraphConnectionAttribute), false) as GraphConnectionAttribute[]; if (connectionAttributes != null && connectionAttributes.Length > 0) { GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true)); if (connectionAttributes[0].Direction == GraphConnectionAttribute.DirectionType.In) { DoConnectionBox(component, field); } else { GUILayout.Space(24); } GUILayout.FlexibleSpace(); GUILayout.Label(ObjectNames.NicifyVariableName(field.Name), GUILayout.ExpandWidth(true)); GUILayout.FlexibleSpace(); if (connectionAttributes[0].Direction == GraphConnectionAttribute.DirectionType.Out) { DoConnectionBox(component, field); } else { GUILayout.Space(24); } GUILayout.EndHorizontal(); } } nodeData.ShowInspector = EditorGUILayout.Foldout(nodeData.ShowInspector, "Inspector"); if (nodeData.ShowInspector) { var editor = Editor.CreateEditor(component); editor.OnInspectorGUI(); } GUILayout.EndArea(); } } foreach (var connection in _connections) { GraphNodeData graphData = _graphData.GetNodeData(connection.Value); if (graphData != null) { if (connection.Key.x > graphData.Position.x) { DrawLine(connection.Key, graphData.Position + new Vector2(graphData.Width, 32)); } else { DrawLine(connection.Key, graphData.Position + new Vector2(0, 32)); } } } if (_dragConnectionComponent != null) { DrawLine(_dragConnectionPosition, Event.current.mousePosition); } if (evt.type == EventType.MouseUp) { _dragItem = null; _dragConnectionComponent = null; _dragConnectionField = null; Repaint(); } if (evt.type == EventType.ContextClick) { _mousePosition = evt.mousePosition; GenericMenu menu = new GenericMenu(); menu.AddSeparator("Add New Item"); Assembly assembly = typeof(Realtime).Assembly; foreach (Type type in assembly.GetTypes()) { object[] attributes = type.GetCustomAttributes(false); foreach (Attribute attribute in attributes) { GraphNodeAttribute graphNode = attribute as GraphNodeAttribute; if (graphNode != null && graphNode.System == _systemName) { menu.AddItem(new GUIContent(graphNode.Type + "/" + graphNode.Name), false, OnMenuItemClicked, type); break; } } } menu.ShowAsContext(); evt.Use(); } GUI.EndScrollView(); _graphData.Clean(); EditorUtility.SetDirty(_system.gameObject); }