Thomas ICHÉ
6 年前
当前提交
8c666b84
共有 131 个文件被更改,包括 3307 次插入 和 1 次删除
-
4Editor/GameplayIngredients-Editor.asmdef
-
63Editor/HiearchyItems.cs
-
11Editor/HiearchyItems.cs.meta
-
8NodeGraphProcessor.meta
-
8NodeGraphProcessor/Editor.meta
-
81NodeGraphProcessor/Editor/BaseGraphWindow.cs
-
11NodeGraphProcessor/Editor/BaseGraphWindow.cs.meta
-
8NodeGraphProcessor/Editor/Callbacks.meta
-
93NodeGraphProcessor/Editor/Callbacks/NodeScriptCreation.cs
-
11NodeGraphProcessor/Editor/Callbacks/NodeScriptCreation.cs.meta
-
22NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt
-
7NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt.meta
-
21NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt
-
7NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt.meta
-
26NodeGraphProcessor/Editor/Callbacks/OnBaseGraphDeleted.cs
-
11NodeGraphProcessor/Editor/Callbacks/OnBaseGraphDeleted.cs.meta
-
19NodeGraphProcessor/Editor/EditorAttributes.cs
-
11NodeGraphProcessor/Editor/EditorAttributes.cs.meta
-
8NodeGraphProcessor/Editor/Logic.meta
-
60NodeGraphProcessor/Editor/Logic/EdgeConnectorListener.cs
-
11NodeGraphProcessor/Editor/Logic/EdgeConnectorListener.cs.meta
-
8NodeGraphProcessor/Editor/Manipulators.meta
-
125NodeGraphProcessor/Editor/Manipulators/BorderResizer.cs
-
11NodeGraphProcessor/Editor/Manipulators/BorderResizer.cs.meta
-
75NodeGraphProcessor/Editor/Manipulators/ConfinedDragger.cs
-
11NodeGraphProcessor/Editor/Manipulators/ConfinedDragger.cs.meta
-
8NodeGraphProcessor/Editor/PortBehaviors.meta
-
19NodeGraphProcessor/Editor/PortBehaviors/DefaultPortBehavior.cs
-
11NodeGraphProcessor/Editor/PortBehaviors/DefaultPortBehavior.cs.meta
-
98NodeGraphProcessor/Editor/PortBehaviors/MultiPortBehavior.cs
-
11NodeGraphProcessor/Editor/PortBehaviors/MultiPortBehavior.cs.meta
-
41NodeGraphProcessor/Editor/PortBehaviors/PortBehaviorFactory.cs
-
11NodeGraphProcessor/Editor/PortBehaviors/PortBehaviorFactory.cs.meta
-
8NodeGraphProcessor/Editor/Resources.meta
-
8NodeGraphProcessor/Editor/Resources/GraphProcessorStyles.meta
-
4NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseGraphView.uss
-
10NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseGraphView.uss.meta
-
7NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseNodeView.uss
-
10NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/BaseNodeView.uss.meta
-
4NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/CommentBlockView.uss
-
10NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/CommentBlockView.uss.meta
-
3NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/EdgeView.uss
-
10NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/EdgeView.uss.meta
-
50NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PinnedElementView.uss
-
10NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PinnedElementView.uss.meta
-
50NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PortView.uss
-
10NodeGraphProcessor/Editor/Resources/GraphProcessorStyles/PortView.uss.meta
-
8NodeGraphProcessor/Editor/Utils.meta
-
14NodeGraphProcessor/Editor/Utils/CopyPasteHelper.cs
-
11NodeGraphProcessor/Editor/Utils/CopyPasteHelper.cs.meta
-
114NodeGraphProcessor/Editor/Utils/FieldFactory.cs
-
11NodeGraphProcessor/Editor/Utils/FieldFactory.cs.meta
-
102NodeGraphProcessor/Editor/Utils/NodeProvider.cs
-
11NodeGraphProcessor/Editor/Utils/NodeProvider.cs.meta
-
8NodeGraphProcessor/Editor/Views.meta
-
585NodeGraphProcessor/Editor/Views/BaseGraphView.cs
-
11NodeGraphProcessor/Editor/Views/BaseGraphView.cs.meta
-
245NodeGraphProcessor/Editor/Views/BaseNodeView.cs
-
11NodeGraphProcessor/Editor/Views/BaseNodeView.cs.meta
-
98NodeGraphProcessor/Editor/Views/CommentBlockView.cs
-
11NodeGraphProcessor/Editor/Views/CommentBlockView.cs.meta
-
17NodeGraphProcessor/Editor/Views/EdgeView.cs
-
11NodeGraphProcessor/Editor/Views/EdgeView.cs.meta
-
22NodeGraphProcessor/Editor/Views/MiniMapView.cs
-
11NodeGraphProcessor/Editor/Views/MiniMapView.cs.meta
-
58NodeGraphProcessor/Editor/Views/PinnedElementView.cs
-
11NodeGraphProcessor/Editor/Views/PinnedElementView.cs.meta
-
99NodeGraphProcessor/Editor/Views/PortView.cs
-
11NodeGraphProcessor/Editor/Views/PortView.cs.meta
-
36NodeGraphProcessor/Editor/Views/ProcessorView.cs
-
11NodeGraphProcessor/Editor/Views/ProcessorView.cs.meta
-
101NodeGraphProcessor/Editor/Views/ToolbarView.cs
-
11NodeGraphProcessor/Editor/Views/ToolbarView.cs.meta
-
16NodeGraphProcessor/Editor/com.alelievr.NodeGraphProcessor-Editor.asmdef
-
7NodeGraphProcessor/Editor/com.alelievr.NodeGraphProcessor-Editor.asmdef.meta
-
21NodeGraphProcessor/LICENSE
-
7NodeGraphProcessor/LICENSE.meta
-
8NodeGraphProcessor/Runtime.meta
-
8NodeGraphProcessor/Runtime/Elements.meta
-
216NodeGraphProcessor/Runtime/Elements/BaseNode.cs
-
11NodeGraphProcessor/Runtime/Elements/BaseNode.cs.meta
-
29NodeGraphProcessor/Runtime/Elements/CommentBlock.cs
-
11NodeGraphProcessor/Runtime/Elements/CommentBlock.cs.meta
-
161NodeGraphProcessor/Runtime/Elements/NodePort.cs
-
11NodeGraphProcessor/Runtime/Elements/NodePort.cs.meta
-
20NodeGraphProcessor/Runtime/Elements/PinnedElement.cs
-
11NodeGraphProcessor/Runtime/Elements/PinnedElement.cs.meta
-
8NodeGraphProcessor/Runtime/Graph.meta
|
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
|
|||
namespace GameplayIngredients |
|||
{ |
|||
static class HiearchyItems |
|||
{ |
|||
#region TRIGGERS
|
|||
|
|||
[MenuItem("GameObject/GameplayIngredients/Hooks/Trigger (Box)", false, 10)] |
|||
static void CreateTriggerBox() |
|||
{ |
|||
var go = new GameObject(); |
|||
var col = go.AddComponent<BoxCollider>(); |
|||
col.isTrigger = true; |
|||
var hook = go.AddComponent<Hooks.OnTriggerHook>(); |
|||
go.name = "Box Trigger"; |
|||
|
|||
if (Selection.activeGameObject != null) |
|||
go.transform.parent = Selection.activeGameObject.transform; |
|||
} |
|||
|
|||
[MenuItem("GameObject/GameplayIngredients/Hooks/Trigger (Sphere)", false, 10)] |
|||
static void CreateTriggerSphere() |
|||
{ |
|||
var go = new GameObject(); |
|||
var col = go.AddComponent<SphereCollider>(); |
|||
col.isTrigger = true; |
|||
var hook = go.AddComponent<Hooks.OnTriggerHook>(); |
|||
go.name = "Sphere Trigger"; |
|||
|
|||
if (Selection.activeGameObject != null) |
|||
go.transform.parent = Selection.activeGameObject.transform; |
|||
} |
|||
|
|||
[MenuItem("GameObject/GameplayIngredients/Hooks/Trigger (Capsule)", false, 10)] |
|||
static void CreateTriggerCapsule() |
|||
{ |
|||
var go = new GameObject(); |
|||
var col = go.AddComponent<CapsuleCollider>(); |
|||
col.isTrigger = true; |
|||
var hook = go.AddComponent<Hooks.OnTriggerHook>(); |
|||
go.name = "Capsule Trigger"; |
|||
|
|||
if (Selection.activeGameObject != null) |
|||
go.transform.parent = Selection.activeGameObject.transform; |
|||
} |
|||
|
|||
[MenuItem("GameObject/GameplayIngredients/Hooks/On Awake", false, 10)] |
|||
static void CreateOnAwake() |
|||
{ |
|||
var go = new GameObject(); |
|||
var hook = go.AddComponent<Hooks.OnAwakeHook>(); |
|||
go.name = "OnAwake Hook"; |
|||
|
|||
if (Selection.activeGameObject != null) |
|||
go.transform.parent = Selection.activeGameObject.transform; |
|||
} |
|||
#endregion
|
|||
|
|||
} |
|||
} |
|||
|
|
|||
fileFormatVersion: 2 |
|||
guid: 28d66973767a30643a54411070050920 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: a7f14529a2d38974cb3d53b8d5014fb0 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 232f899daeba5461ebf015a1f96643b3 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using UnityEngine.Assertions; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[System.Serializable] |
|||
public abstract class BaseGraphWindow : EditorWindow |
|||
{ |
|||
protected VisualElement rootView; |
|||
protected BaseGraphView graphView; |
|||
|
|||
[SerializeField] |
|||
protected BaseGraph graph; |
|||
|
|||
public bool isGraphLoaded |
|||
{ |
|||
get { return graphView != null && graphView.graph != null; } |
|||
} |
|||
|
|||
protected void OnEnable() |
|||
{ |
|||
InitializeRootView(); |
|||
|
|||
if (graph != null) |
|||
InitializeGraph(graph); |
|||
} |
|||
|
|||
protected void OnDisable() |
|||
{ |
|||
if (graph != null) |
|||
graphView.SaveGraphToDisk(); |
|||
} |
|||
|
|||
void InitializeRootView() |
|||
{ |
|||
rootView = this.GetRootVisualContainer(); |
|||
|
|||
rootView.name = "graphRootView"; |
|||
|
|||
rootView.AddStyleSheetPath("GraphProcessorStyles/BaseGraphView"); |
|||
} |
|||
|
|||
public void InitializeGraph(BaseGraph graph) |
|||
{ |
|||
this.graph = graph; |
|||
|
|||
if (graphView != null) |
|||
rootView.Remove(graphView); |
|||
|
|||
//Initialize will provide the BaseGraphView
|
|||
Initialize(graph); |
|||
|
|||
graphView = rootView.Children().FirstOrDefault(e => e is BaseGraphView) as BaseGraphView; |
|||
|
|||
if (graphView == null) |
|||
{ |
|||
Debug.LogError("GraphView has not been added to the BaseGraph root view !"); |
|||
return ; |
|||
} |
|||
|
|||
graphView.Initialize(graph); |
|||
} |
|||
|
|||
public virtual void OnGraphDeleted() |
|||
{ |
|||
if (graph != null) |
|||
rootView.Remove(graphView); |
|||
|
|||
graphView = null; |
|||
} |
|||
|
|||
protected abstract void Initialize(BaseGraph graph); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2b4b18f42b137457bbc04f077fe5fd56 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 63fdfc474ed0f4db7aa1432eaf667691 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using System.IO; |
|||
using System.Reflection; |
|||
using UnityEditor.ProjectWindowCallback; |
|||
|
|||
namespace ProceduralWorlds.Editor |
|||
{ |
|||
public static class NodeScriptMenuItem |
|||
{ |
|||
static readonly string nodeBaseName = "Node.cs"; |
|||
static readonly string nodeViewBaseName = "NodeView.cs"; |
|||
static readonly string nodeTemplatePath = "Assets/NodeGraphProcessor/Editor/Callbacks/NodeTemplate.cs.txt"; |
|||
static readonly string nodeViewTemplatePath = "Assets/NodeGraphProcessor/Editor/Callbacks/NodeViewTemplate.cs.txt"; |
|||
|
|||
static string GetCurrentPath() |
|||
{ |
|||
var path = ""; |
|||
var obj = Selection.activeObject; |
|||
|
|||
if (obj == null) |
|||
return null; |
|||
else |
|||
path = AssetDatabase.GetAssetPath(obj.GetInstanceID()); |
|||
|
|||
if (path.Length > 0) |
|||
{ |
|||
if (Directory.Exists(path)) |
|||
return path; |
|||
else |
|||
return new FileInfo(path).Directory.FullName; |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
[MenuItem("Assets/Create/Node C# Script", false, 20)] |
|||
private static void CreateNodeCSharpScritpt() |
|||
{ |
|||
string path = GetCurrentPath() + "/" + nodeBaseName; |
|||
path = AssetDatabase.GenerateUniqueAssetPath(path); |
|||
|
|||
ProjectWindowUtil.StartNameEditingIfProjectWindowExists( |
|||
0, |
|||
ScriptableObject.CreateInstance< DoCreateNodeScript >(), |
|||
path, |
|||
EditorGUIUtility.FindTexture("cs Script Icon"), |
|||
Path.GetFullPath(nodeTemplatePath) |
|||
); |
|||
|
|||
AssetDatabase.Refresh(); |
|||
} |
|||
|
|||
[MenuItem("Assets/Create/Node View C# Script", false, 21)] |
|||
private static void CreateNodeViewCSharpScritpt() |
|||
{ |
|||
string path = GetCurrentPath() + "/" + nodeViewBaseName; |
|||
path = AssetDatabase.GenerateUniqueAssetPath(path); |
|||
|
|||
ProjectWindowUtil.StartNameEditingIfProjectWindowExists( |
|||
0, |
|||
ScriptableObject.CreateInstance< DoCreateNodeScript >(), |
|||
path, |
|||
EditorGUIUtility.FindTexture("cs Script Icon"), |
|||
Path.GetFullPath(nodeViewTemplatePath) |
|||
); |
|||
|
|||
AssetDatabase.Refresh(); |
|||
} |
|||
|
|||
class DoCreateNodeScript : EndNameEditAction |
|||
{ |
|||
static MethodInfo createScriptAsset = typeof(ProjectWindowUtil).GetMethod("CreateScriptAssetFromTemplate", BindingFlags.Static | BindingFlags.NonPublic); |
|||
|
|||
public override void Action(int instanceId, string pathName, string resourceFile) |
|||
{ |
|||
if (!File.Exists(resourceFile)) |
|||
{ |
|||
Debug.LogError("Can't find template: " + resourceFile); |
|||
return ; |
|||
} |
|||
|
|||
createScriptAsset.Invoke(null, new object[]{ pathName, resourceFile }); |
|||
|
|||
var asset = AssetDatabase.LoadAssetAtPath(pathName, typeof(MonoScript)); |
|||
ProjectWindowUtil.ShowCreatedAsset(asset); |
|||
|
|||
AssetDatabase.Refresh(); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a2c7e2490c5456c4ca6d567178222b16 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using GraphProcessor; |
|||
using System.Linq; |
|||
|
|||
[System.Serializable, NodeMenuItem("Custom/#NAME#")] |
|||
public class #SCRIPTNAME# : BaseNode |
|||
{ |
|||
[Input(name = "In")] |
|||
public float input; |
|||
|
|||
[Output(name = "Out")] |
|||
public float output; |
|||
|
|||
public override string name => "#NAME#"; |
|||
|
|||
protected override void Process() |
|||
{ |
|||
output = input * 42; |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a9cbafe2f8c9a0042ad9fcc60c538f05 |
|||
TextScriptImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using GraphProcessor; |
|||
|
|||
[NodeCustomEditor(typeof(NODE_TYPE))] |
|||
public class #SCRIPTNAME# : BaseNodeView |
|||
{ |
|||
public override void Enable() |
|||
{ |
|||
var node = nodeTarget as NODE_TYPE; |
|||
|
|||
// Create your fields using node's variables and add them to the controlsContainer |
|||
|
|||
controlsContainer.Add(new Label("Hello World !")); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 1cff9adb4a6bd6b4aac3a5472648a524 |
|||
TextScriptImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using UnityEditor.Callbacks; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[ExecuteInEditMode] |
|||
public class DeleteCallback : UnityEditor.AssetModificationProcessor |
|||
{ |
|||
static AssetDeleteResult OnWillDeleteAsset(string path, RemoveAssetOptions options) |
|||
{ |
|||
var graph = AssetDatabase.LoadAssetAtPath(path, typeof(BaseGraph)); |
|||
|
|||
if (graph != null) |
|||
{ |
|||
foreach (var graphWindow in Resources.FindObjectsOfTypeAll< BaseGraphWindow >()) |
|||
graphWindow.OnGraphDeleted(); |
|||
} |
|||
|
|||
return AssetDeleteResult.DidNotDelete; |
|||
} |
|||
} |
|||
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 59cb170ad7b9d4c7394a1a7bfd6b11a1 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using System; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[AttributeUsage(AttributeTargets.Class)] |
|||
public class NodeCustomEditor : Attribute |
|||
{ |
|||
public Type nodeType; |
|||
|
|||
public NodeCustomEditor(Type nodeType) |
|||
{ |
|||
this.nodeType = nodeType; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5c50a793169754f699b4987ff8e0733f |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: ae3080c0c3f0d42f38d4300d12b41091 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public sealed class EdgeConnectorListener : IEdgeConnectorListener |
|||
{ |
|||
readonly BaseGraphView graphView; |
|||
|
|||
Dictionary< Edge, PortView > edgeInputPorts = new Dictionary< Edge, PortView >(); |
|||
Dictionary< Edge, PortView > edgeOutputPorts = new Dictionary< Edge, PortView >(); |
|||
|
|||
public EdgeConnectorListener(BaseGraphView graphView) |
|||
{ |
|||
this.graphView = graphView; |
|||
} |
|||
|
|||
public void OnDropOutsidePort(Edge edge, Vector2 position) |
|||
{ |
|||
this.graphView.RegisterCompleteObjectUndo("Disconnect edge"); |
|||
|
|||
//If the edge was already existing, remove it
|
|||
if (!edge.isGhostEdge) |
|||
graphView.Disconnect(edge as EdgeView); |
|||
|
|||
//TODO: open new nodes selector and connect the created node if there is one
|
|||
} |
|||
|
|||
public void OnDrop(GraphView graphView, Edge edge) |
|||
{ |
|||
var edgeView = edge as EdgeView; |
|||
bool wasOnTheSamePort = false; |
|||
|
|||
if (edgeView?.input == null || edgeView?.output == null) |
|||
return ; |
|||
|
|||
//If the edge was moved to another port
|
|||
if (edgeView.isConnected) |
|||
{ |
|||
if (edgeInputPorts.ContainsKey(edge) && edgeOutputPorts.ContainsKey(edge)) |
|||
if (edgeInputPorts[edge] == edge.input && edgeOutputPorts[edge] == edge.output) |
|||
wasOnTheSamePort = true; |
|||
|
|||
if (!wasOnTheSamePort) |
|||
this.graphView.Disconnect(edgeView); |
|||
} |
|||
|
|||
if (edgeView.input.node == null || edgeView.output.node == null) |
|||
return; |
|||
|
|||
edgeInputPorts[edge] = edge.input as PortView; |
|||
edgeOutputPorts[edge] = edge.output as PortView; |
|||
this.graphView.RegisterCompleteObjectUndo("Connected " + edgeView.input.node.name + " and " + edgeView.output.node.name); |
|||
this.graphView.Connect(edge as EdgeView, autoDisconnectInputs: !wasOnTheSamePort); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 594eed6e129424e83abd868b8d10d7a7 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: c6072e601ba164a9baaee07146ebd0a2 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class BorderResizer : MouseManipulator |
|||
{ |
|||
bool active; |
|||
Vector2 startMousePosition; |
|||
Vector2 startComponentSize; |
|||
Vector2 startComponentPosition; |
|||
|
|||
readonly int dragBorderSize = 15; |
|||
Vector2 dragDirection; |
|||
|
|||
readonly string cursorBorderStyleSheet = "GraphProcessorStyles/BorderResizer"; |
|||
|
|||
GraphElement elem; |
|||
|
|||
public BorderResizer() |
|||
{ |
|||
activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse }); |
|||
} |
|||
|
|||
protected override void RegisterCallbacksOnTarget() |
|||
{ |
|||
elem = target as GraphElement; |
|||
|
|||
if (elem == null) |
|||
throw new System.InvalidOperationException("BorderReiszer can only be added to a GraphElement"); |
|||
|
|||
target.RegisterCallback< MouseDownEvent >(OnMouseDown); |
|||
target.RegisterCallback< MouseMoveEvent >(OnMouseMove); |
|||
target.RegisterCallback< MouseUpEvent >(OnMouseUp); |
|||
|
|||
if (!target.HasStyleSheetPath(cursorBorderStyleSheet)) |
|||
target.AddStyleSheetPath(cursorBorderStyleSheet); |
|||
} |
|||
|
|||
protected override void UnregisterCallbacksFromTarget() |
|||
{ |
|||
target.UnregisterCallback< MouseDownEvent >(OnMouseDown); |
|||
target.UnregisterCallback< MouseMoveEvent >(OnMouseMove); |
|||
target.UnregisterCallback< MouseUpEvent >(OnMouseUp); |
|||
} |
|||
|
|||
void OnMouseDown(MouseDownEvent e) |
|||
{ |
|||
if (active) |
|||
{ |
|||
e.StopPropagation(); |
|||
return ; |
|||
} |
|||
|
|||
if (MouseCaptureController.IsMouseCaptured()) |
|||
return ; |
|||
|
|||
if (!IsMouseOverBorders(e.localMousePosition)) |
|||
return; |
|||
|
|||
if (CanStartManipulation(e)) |
|||
{ |
|||
active = true; |
|||
target.CaptureMouse(); |
|||
e.StopPropagation(); |
|||
|
|||
startComponentSize = new Vector2(elem.style.width, elem.style.height); |
|||
startMousePosition = e.localMousePosition; |
|||
startComponentPosition = elem.transform.position; |
|||
} |
|||
else |
|||
Debug.Log("can't start manipulation !"); |
|||
} |
|||
|
|||
void OnMouseMove(MouseMoveEvent e) |
|||
{ |
|||
if (!active) |
|||
return ; |
|||
|
|||
Vector2 delta = e.localMousePosition - startMousePosition + (Vector2)elem.transform.position - startComponentPosition; |
|||
|
|||
elem.style.width = startComponentSize.x + delta.x * dragDirection.x; |
|||
elem.style.height = startComponentSize.y + delta.y * dragDirection.y; |
|||
|
|||
elem.transform.position -= (Vector3)(e.mouseDelta * Vector2.Min(Vector2.zero, dragDirection)); |
|||
} |
|||
|
|||
void OnMouseUp(MouseUpEvent e) |
|||
{ |
|||
if (!active) |
|||
return ; |
|||
|
|||
if (CanStopManipulation(e)) |
|||
{ |
|||
target.ReleaseMouse(); |
|||
e.StopPropagation(); |
|||
|
|||
GraphView graphView = elem.GetFirstAncestorOfType<GraphView>(); |
|||
if (graphView != null && graphView.elementResized != null) |
|||
graphView.elementResized(elem); |
|||
} |
|||
|
|||
active = false; |
|||
} |
|||
|
|||
bool IsMouseOverBorders(Vector2 mousePosition) |
|||
{ |
|||
Rect borders = new Rect(Vector2.zero, target.localBound.size); |
|||
|
|||
dragDirection = Vector2.zero; |
|||
|
|||
if (mousePosition.x - borders.xMin < dragBorderSize) |
|||
dragDirection.x = -1; |
|||
if (borders.xMax - mousePosition.x < dragBorderSize) |
|||
dragDirection.x = 1; |
|||
if (mousePosition.y - borders.yMin < dragBorderSize) |
|||
dragDirection.y = -1; |
|||
if (borders.yMax - mousePosition.y < dragBorderSize) |
|||
dragDirection.y = 1; |
|||
|
|||
return dragDirection != Vector2.zero; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2184598ff73294c1b9dd5255d8545679 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEngine.Experimental.UIElements.StyleSheets; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class ConfinedDragger : MouseManipulator |
|||
{ |
|||
bool active; |
|||
Vector3 offset; |
|||
|
|||
VisualElement container; |
|||
VisualElement handle; |
|||
|
|||
public Action onDragEnd; |
|||
|
|||
public ConfinedDragger(VisualElement container) |
|||
{ |
|||
this.container = container; |
|||
active = false; |
|||
} |
|||
|
|||
protected override void RegisterCallbacksOnTarget() |
|||
{ |
|||
handle = target; |
|||
|
|||
handle.RegisterCallback(new EventCallback<MouseDownEvent>(OnMouseDown), TrickleDown.NoTrickleDown); |
|||
handle.RegisterCallback(new EventCallback<MouseMoveEvent>(OnMouseMove), TrickleDown.NoTrickleDown); |
|||
handle.RegisterCallback(new EventCallback<MouseUpEvent>(OnMouseUp), TrickleDown.NoTrickleDown); |
|||
} |
|||
|
|||
protected override void UnregisterCallbacksFromTarget() |
|||
{ |
|||
handle.UnregisterCallback(new EventCallback<MouseDownEvent>(OnMouseDown), TrickleDown.NoTrickleDown); |
|||
handle.UnregisterCallback(new EventCallback<MouseMoveEvent>(OnMouseMove), TrickleDown.NoTrickleDown); |
|||
handle.UnregisterCallback(new EventCallback<MouseUpEvent>(OnMouseUp), TrickleDown.NoTrickleDown); |
|||
} |
|||
|
|||
void OnMouseDown(MouseDownEvent evt) |
|||
{ |
|||
active = true; |
|||
|
|||
offset = evt.mousePosition - (Vector2)target.transform.position; |
|||
|
|||
handle.CaptureMouse(); |
|||
evt.StopImmediatePropagation(); |
|||
} |
|||
|
|||
void OnMouseMove(MouseMoveEvent evt) |
|||
{ |
|||
if (active) |
|||
{ |
|||
Vector3 position = (Vector3)evt.mousePosition - offset; |
|||
position.x = Mathf.Clamp(position.x, -target.layout.position.x, container.layout.width - target.layout.position.x - target.localBound.size.x); |
|||
position.y = Mathf.Clamp(position.y, -target.layout.position.y, container.layout.height - target.layout.position.y - target.localBound.size.y); |
|||
|
|||
target.transform.position = position; |
|||
} |
|||
} |
|||
|
|||
void OnMouseUp(MouseUpEvent evt) |
|||
{ |
|||
active = false; |
|||
|
|||
if (handle.HasMouseCapture()) |
|||
handle.ReleaseMouse(); |
|||
evt.StopImmediatePropagation(); |
|||
|
|||
if (onDragEnd != null) |
|||
onDragEnd(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 8984ae8e754a344d7a6361c06cd1b9b1 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: cffd7e4ce183a9f48927dc1c49f90616 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine.Experimental.UIElements.StyleEnums; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEngine; |
|||
using System.Reflection; |
|||
using System.Linq; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class DefaultPortBehavior |
|||
{ |
|||
public DefaultPortBehavior(BaseNodeView nodeView, FieldInfo fieldInfo, Direction direction, EdgeConnectorListener listener, bool isMultiple, string name) |
|||
{ |
|||
nodeView.AddPort(fieldInfo, direction, listener, isMultiple, name); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0c02c9f760c77ef44a7696e41c76d3a9 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine.Experimental.UIElements.StyleEnums; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEngine; |
|||
using System.Reflection; |
|||
using System.Linq; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[CustomPortBehavior(typeof(MultiPorts))] |
|||
public class MultiPortBehavior |
|||
{ |
|||
MultiPorts multiPorts; |
|||
BaseNodeView node; |
|||
Dictionary< Edge, PortView > portViews = new Dictionary< Edge, PortView >(); |
|||
|
|||
FieldInfo fieldInfo; |
|||
Direction direction; |
|||
EdgeConnectorListener listener; |
|||
bool isMultiple; |
|||
string name; |
|||
|
|||
public MultiPortBehavior(BaseNodeView nodeView, FieldInfo fieldInfo, Direction direction, EdgeConnectorListener listener, bool isMultiple, string name) |
|||
{ |
|||
this.multiPorts = fieldInfo.GetValue(nodeView.nodeTarget) as MultiPorts; |
|||
this.node = nodeView; |
|||
this.fieldInfo = fieldInfo; |
|||
this.direction = direction; |
|||
this.listener = listener; |
|||
this.isMultiple = isMultiple; |
|||
this.name = name; |
|||
|
|||
// Initialize the MultiPort field if null
|
|||
if (multiPorts == null) |
|||
{ |
|||
multiPorts = new MultiPorts(); |
|||
fieldInfo.SetValue(nodeView.nodeTarget, multiPorts); |
|||
} |
|||
|
|||
// Instantiate all ports needed to create the serialized connections
|
|||
// Minus one because we count our current instance
|
|||
for (int i = 0; i < multiPorts.portCount; i++) |
|||
AddPort(); |
|||
} |
|||
|
|||
void AddPort() |
|||
{ |
|||
PortView pv = node.AddPort(fieldInfo, direction, listener, isMultiple, name); |
|||
|
|||
// We force the AddPort in the BaseNode class because the port list is not updated except at the construction of the class
|
|||
node.nodeTarget.AddPort(direction == Direction.Input, pv.fieldName); |
|||
|
|||
pv.OnConnected += OnPortConnected; |
|||
pv.OnDisconnected += OnPortDisconnected; |
|||
} |
|||
|
|||
public void OnPortConnected(PortView pv, Edge edge) |
|||
{ |
|||
// Fix port datas
|
|||
if (pv.direction == Direction.Input) |
|||
edge.input = pv; |
|||
else |
|||
edge.output = pv; |
|||
|
|||
// If the edge is already connected, ignore it
|
|||
if (portViews.ContainsKey(edge)) |
|||
return ; |
|||
|
|||
portViews[edge] = pv; |
|||
|
|||
if (pv.GetEdges().Count == 0) |
|||
{ |
|||
multiPorts.AddUniqueId(multiPorts.GetUniqueId()); |
|||
AddPort(); |
|||
} |
|||
} |
|||
|
|||
public void OnPortDisconnected(PortView pv, Edge edge) |
|||
{ |
|||
if (pv.GetEdges().Count == 0) |
|||
{ |
|||
if ((edge as EdgeView).isConnected && portViews.ContainsKey(edge)) |
|||
{ |
|||
var portToRemove = portViews[edge]; |
|||
|
|||
node.RemovePort(portToRemove); |
|||
|
|||
node.nodeTarget.RemovePort(direction == Direction.Input, portToRemove.fieldName); |
|||
|
|||
portViews.Remove(edge); |
|||
multiPorts.RemoveUniqueId(0); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 9a47c447ebb4fe54c8922feadb2782f5 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using System; |
|||
using System.Reflection; |
|||
using System.Linq; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public static class PortBehaviorFactory |
|||
{ |
|||
static Dictionary<Type, Type> portBehaviors = new Dictionary<Type, Type>(); |
|||
|
|||
static PortBehaviorFactory() |
|||
{ |
|||
foreach (var type in AppDomain.CurrentDomain.GetAllTypes()) |
|||
{ |
|||
var customPortBehaviorAttr = type.GetCustomAttribute< CustomPortBehaviorAttribute >(); |
|||
|
|||
if (customPortBehaviorAttr == null) |
|||
continue ; |
|||
|
|||
portBehaviors[customPortBehaviorAttr.targetType] = type; |
|||
} |
|||
} |
|||
|
|||
public static void CreatePortBehavior(BaseNodeView nodeView, FieldInfo field, Direction direction, EdgeConnectorListener listener, bool isMultiple, string name) |
|||
{ |
|||
Type behaviorType; |
|||
|
|||
portBehaviors.TryGetValue(field.FieldType, out behaviorType); |
|||
|
|||
if (behaviorType == null) |
|||
behaviorType = typeof(DefaultPortBehavior); |
|||
|
|||
Activator.CreateInstance(behaviorType, nodeView, field, direction, listener, isMultiple, name); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 379e2785adbd6ab43adf7682b6d77b69 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: a15334d6fa12046e5afcb22ac791a43d |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 6562f61ebe4c045d29fe4b1a3457379a |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#graphRootView |
|||
{ |
|||
background-color: #101010; |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2769cf0fb82ce4c2691edb49469f5f17 |
|||
ScriptedImporter: |
|||
fileIDToRecycleName: |
|||
11400000: stylesheet |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} |
|
|||
#node { |
|||
background-color: rgba(0, 63, 63, 0.8); |
|||
} |
|||
|
|||
#controls { |
|||
background-color: rgba(63, 63, 63, 0.8); |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 7aed4ab0823d4432996ae4614575bc7c |
|||
ScriptedImporter: |
|||
fileIDToRecycleName: |
|||
11400000: stylesheet |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} |
|
|||
#headerColorPicker { |
|||
width: 50; |
|||
align: right; |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 778f73de1e04f4acd871308e30971a42 |
|||
ScriptedImporter: |
|||
fileIDToRecycleName: |
|||
11400000: stylesheet |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} |
|
|||
EdgeView.Single { |
|||
color: #800080 |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 28f83445e912a4e25aa30a4f0cd22636 |
|||
ScriptedImporter: |
|||
fileIDToRecycleName: |
|||
11400000: stylesheet |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} |
|
|||
#PinnedElementView { |
|||
flex-direction: column; |
|||
position-type: absolute; |
|||
position-right: 10; |
|||
position-bottom: 10; |
|||
background-color: rgb(79, 79, 79); |
|||
justify-content: flex-start; |
|||
border-radius: 6; |
|||
border-top-width: 1; |
|||
border-bottom-width: 1; |
|||
border-left-width: 1; |
|||
border-right-width: 1; |
|||
border-color: rgb(25,25,25); |
|||
} |
|||
|
|||
#PinnedElementView > #header { |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
background-color: rgb(64, 64, 64); |
|||
padding-top: 8; |
|||
padding-bottom: 8; |
|||
padding-left: 8; |
|||
padding-right: 8; |
|||
border-top-left-radius: 6; |
|||
border-top-right-radius: 6; |
|||
} |
|||
|
|||
#PinnedElementView > #header > #title { |
|||
font-size: 12; |
|||
text-color: rgb(180, 180, 180); |
|||
padding-top: 1; |
|||
padding-bottom: 2; |
|||
padding-left: 2; |
|||
padding-right: 2; |
|||
} |
|||
|
|||
#PinnedElementView > #content { |
|||
flex-grow: 1; |
|||
border-width: 10; |
|||
flex-direction: row; |
|||
border-color: rgb(0,10,190); |
|||
} |
|||
|
|||
#PinnedElementView.collapsed{ |
|||
background-color: rgb(206, 53, 185); |
|||
} |
|||
|
|||
#PinnedElementView.expanded{ |
|||
background-color: rgb(206, 53, 185); |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2fdbf4d830a3942a18aafb8fd7a5fa53 |
|||
ScriptedImporter: |
|||
fileIDToRecycleName: |
|||
11400000: stylesheet |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} |
|
|||
PortView { |
|||
height: 24; |
|||
align-items: center; |
|||
padding-left: 4; |
|||
padding-right: 4; |
|||
port-color: rgb(200, 200, 00); |
|||
disabled-port-color: rgb(0, 70, 70); |
|||
} |
|||
|
|||
PortView.input { |
|||
flex-direction: row; |
|||
} |
|||
|
|||
PortView.output { |
|||
flex-direction: row-reverse; |
|||
} |
|||
|
|||
PortView > #connector { |
|||
border-color: rgb(255, 255, 0); |
|||
background-color: #212121; |
|||
width: 8; |
|||
height: 8; |
|||
border-radius: 8; |
|||
align-items: center; |
|||
justify-content: center; |
|||
|
|||
margin-left: 4; |
|||
margin-right: 4; |
|||
border-left-width:1; |
|||
border-top-width:1; |
|||
border-right-width:1; |
|||
border-bottom-width:1; |
|||
} |
|||
|
|||
PortView > #connector:hover { |
|||
border-color: #f0f0f0 |
|||
} |
|||
|
|||
PortView > #connector > #cap |
|||
{ |
|||
background-color: #212121; |
|||
width: 4; |
|||
height: 4; |
|||
border-radius: 4; |
|||
} |
|||
|
|||
PortView > #connector > #cap:hover |
|||
{ |
|||
background-color: #f0f0f0; |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 7f9f1707b6119456581ab1a100d96aaa |
|||
ScriptedImporter: |
|||
fileIDToRecycleName: |
|||
11400000: stylesheet |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} |
|
|||
fileFormatVersion: 2 |
|||
guid: 5e5f8827aa14940f59f6f29179b03d0c |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[System.Serializable] |
|||
public class CopyPasteHelper |
|||
{ |
|||
public List< JsonElement > copiedNodes = new List< JsonElement >(); |
|||
|
|||
public List< JsonElement > copiedCommentBlocks = new List< JsonElement >(); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ad4ab8e74dd9540cab3bc65ba3b8b58c |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using System; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public static class FieldFactory |
|||
{ |
|||
static readonly Dictionary< Type, Type > fieldDrawers = new Dictionary< Type, Type >(); |
|||
|
|||
static readonly MethodInfo createFieldMethod = typeof(FieldFactory).GetMethod("CreateFieldSpecific", BindingFlags.Static | BindingFlags.Public); |
|||
|
|||
static FieldFactory() |
|||
{ |
|||
foreach (var type in AppDomain.CurrentDomain.GetAllTypes()) |
|||
{ |
|||
var drawerAttribute = type.GetCustomAttributes(typeof(FieldDrawerAttribute), false).FirstOrDefault() as FieldDrawerAttribute; |
|||
|
|||
if (drawerAttribute == null) |
|||
continue ; |
|||
|
|||
AddDrawer(drawerAttribute.fieldType, type); |
|||
} |
|||
|
|||
// щ(ºДºщ) ...
|
|||
AddDrawer(typeof(int), typeof(IntegerField)); |
|||
AddDrawer(typeof(long), typeof(LongField)); |
|||
AddDrawer(typeof(float), typeof(FloatField)); |
|||
AddDrawer(typeof(double), typeof(DoubleField)); |
|||
AddDrawer(typeof(string), typeof(TextField)); |
|||
AddDrawer(typeof(Bounds), typeof(BoundsField)); |
|||
AddDrawer(typeof(Color), typeof(ColorField)); |
|||
AddDrawer(typeof(Vector2), typeof(Vector2Field)); |
|||
AddDrawer(typeof(Vector3), typeof(Vector3Field)); |
|||
AddDrawer(typeof(Vector4), typeof(Vector4Field)); |
|||
AddDrawer(typeof(AnimationCurve), typeof(CurveField)); |
|||
AddDrawer(typeof(Enum), typeof(EnumField)); |
|||
AddDrawer(typeof(Gradient), typeof(GradientField)); |
|||
AddDrawer(typeof(UnityEngine.Object), typeof(ObjectField)); |
|||
AddDrawer(typeof(Rect), typeof(RectField)); |
|||
} |
|||
|
|||
static void AddDrawer(Type fieldType, Type drawerType) |
|||
{ |
|||
var iNotifyType = typeof(INotifyValueChanged<>).MakeGenericType(fieldType); |
|||
|
|||
if (!iNotifyType.IsAssignableFrom(drawerType)) |
|||
{ |
|||
Debug.LogWarning("The custom field drawer " + drawerType + " does not implements INotifyValueChanged< " + fieldType + " >"); |
|||
return ; |
|||
} |
|||
|
|||
fieldDrawers[fieldType] = drawerType; |
|||
} |
|||
|
|||
public static INotifyValueChanged< T > CreateField< T >() |
|||
{ |
|||
return CreateField(typeof(T)) as INotifyValueChanged< T >; |
|||
} |
|||
|
|||
public static VisualElement CreateField(Type t) |
|||
{ |
|||
Type drawerType; |
|||
|
|||
fieldDrawers.TryGetValue(t, out drawerType); |
|||
|
|||
if (drawerType == null) |
|||
drawerType = fieldDrawers.FirstOrDefault(kp => kp.Key.IsReallyAssignableFrom(t)).Value; |
|||
|
|||
if (drawerType == null) |
|||
{ |
|||
Debug.LogWarning("Can't find field drawer for type: " + t); |
|||
return null; |
|||
} |
|||
|
|||
var field = Activator.CreateInstance(drawerType); |
|||
|
|||
// For mutiline
|
|||
if (field is TextField) |
|||
{ |
|||
(field as TextField).multiline = true; |
|||
} |
|||
|
|||
return field as VisualElement; |
|||
} |
|||
|
|||
public static INotifyValueChanged< T > CreateFieldSpecific< T >(FieldInfo field, T value, Action< object > onValueChanged) |
|||
{ |
|||
var fieldDrawer = CreateField< T >(); |
|||
|
|||
if (fieldDrawer == null) |
|||
return null; |
|||
|
|||
fieldDrawer.value = value; |
|||
fieldDrawer.OnValueChanged((e) => { |
|||
onValueChanged(e.newValue); |
|||
}); |
|||
|
|||
return fieldDrawer as INotifyValueChanged< T >; |
|||
} |
|||
|
|||
public static VisualElement CreateField(FieldInfo field, object value, Action< object > onValueChanged) |
|||
{ |
|||
var createFieldSpecificMethod = createFieldMethod.MakeGenericMethod(field.FieldType); |
|||
|
|||
return createFieldSpecificMethod.Invoke(null, new object[]{field, value, onValueChanged}) as VisualElement; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 8e070bfe6917e4be9bff3e56c4cda092 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using System; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using System.Linq; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public static class NodeProvider |
|||
{ |
|||
static Dictionary< Type, Type > nodeViewPerType = new Dictionary< Type, Type >(); |
|||
static Dictionary< string, Type > nodePerMenuTitle = new Dictionary< string, Type >(); |
|||
static Dictionary< Type, string > nodeViewScripts = new Dictionary< Type, string >(); |
|||
static Dictionary< Type, string > nodeScripts = new Dictionary< Type, string >(); |
|||
|
|||
static NodeProvider() |
|||
{ |
|||
foreach (var type in AppDomain.CurrentDomain.GetAllTypes()) |
|||
{ |
|||
if (type.IsClass && !type.IsAbstract) |
|||
{ |
|||
if (type.IsSubclassOf(typeof(BaseNode))) |
|||
AddNodeType(type); |
|||
if (type.IsSubclassOf(typeof(BaseNodeView))) |
|||
AddNodeViewType(type); |
|||
} |
|||
} |
|||
} |
|||
|
|||
static void AddNodeType(Type type) |
|||
{ |
|||
var attrs = type.GetCustomAttributes(typeof(NodeMenuItemAttribute), false) as NodeMenuItemAttribute[]; |
|||
|
|||
if (attrs != null && attrs.Length > 0) |
|||
nodePerMenuTitle[attrs.First().menuTitle] = type; |
|||
|
|||
var nodeScriptAsset = FindScriptFromClassName(type.Name); |
|||
if (nodeScriptAsset != null) |
|||
nodeScripts[type] = nodeScriptAsset; |
|||
} |
|||
|
|||
static void AddNodeViewType(Type type) |
|||
{ |
|||
var attrs = type.GetCustomAttributes(typeof(NodeCustomEditor), false) as NodeCustomEditor[]; |
|||
|
|||
if (attrs != null && attrs.Length > 0) |
|||
{ |
|||
Type nodeType = attrs.First().nodeType; |
|||
nodeViewPerType[nodeType] = type; |
|||
|
|||
var nodeViewScriptAsset = FindScriptFromClassName(type.Name); |
|||
|
|||
if (nodeViewScriptAsset != null) |
|||
nodeViewScripts[type] = nodeViewScriptAsset; |
|||
} |
|||
} |
|||
|
|||
static string FindScriptFromClassName(string className) |
|||
{ |
|||
var scriptGUIDs = AssetDatabase.FindAssets(className); |
|||
|
|||
if (scriptGUIDs.Length == 0) |
|||
return null; |
|||
|
|||
return AssetDatabase.GUIDToAssetPath(scriptGUIDs[0]); |
|||
} |
|||
|
|||
public static Type GetNodeViewTypeFromType(Type nodeType) |
|||
{ |
|||
Type view; |
|||
|
|||
nodeViewPerType.TryGetValue(nodeType, out view); |
|||
|
|||
return view; |
|||
} |
|||
|
|||
public static Dictionary< string, Type > GetNodeMenuEntries() |
|||
{ |
|||
return nodePerMenuTitle; |
|||
} |
|||
|
|||
public static string GetNodeViewScript(Type type) |
|||
{ |
|||
string scriptPath; |
|||
|
|||
nodeViewScripts.TryGetValue(type, out scriptPath); |
|||
|
|||
return scriptPath; |
|||
} |
|||
|
|||
public static string GetNodeScript(Type type) |
|||
{ |
|||
string scriptPath; |
|||
|
|||
nodeScripts.TryGetValue(type, out scriptPath); |
|||
|
|||
return scriptPath; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0f90580539cbf48d58ba35c626500169 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 600ac8da8b308477fa0dfcd14d40ce53 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using System.Linq; |
|||
using System; |
|||
|
|||
using StatusFlags = UnityEngine.Experimental.UIElements.DropdownMenu.MenuAction.StatusFlags; |
|||
|
|||
using Object = UnityEngine.Object; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class BaseGraphView : GraphView |
|||
{ |
|||
public BaseGraph graph; |
|||
|
|||
public EdgeConnectorListener connectorListener; |
|||
|
|||
public List< BaseNodeView > nodeViews = new List< BaseNodeView >(); |
|||
public Dictionary< BaseNode, BaseNodeView > nodeViewsPerNode = new Dictionary< BaseNode, BaseNodeView >(); |
|||
public List< EdgeView > edgeViews = new List< EdgeView >(); |
|||
public List< CommentBlockView > commentBlockViews = new List< CommentBlockView >(); |
|||
|
|||
Dictionary< Type, PinnedElementView > pinnedElements = new Dictionary< Type, PinnedElementView >(); |
|||
|
|||
public delegate void ComputeOrderUpdatedDelegate(); |
|||
|
|||
public event Action initialized; |
|||
public event ComputeOrderUpdatedDelegate computeOrderUpdated; |
|||
|
|||
public BaseGraphView() |
|||
{ |
|||
serializeGraphElements = SerializeGraphElementsCallback; |
|||
canPasteSerializedData = CanPasteSerializedDataCallback; |
|||
unserializeAndPaste = UnserializeAndPasteCallback; |
|||
graphViewChanged = GraphViewChangedCallback; |
|||
viewTransformChanged = ViewTransformChangedCallback; |
|||
elementResized = ElementResizedCallback; |
|||
|
|||
InitializeManipulators(); |
|||
|
|||
RegisterCallback< KeyDownEvent >(KeyDownCallback); |
|||
|
|||
SetupZoom(0.05f, 2f); |
|||
|
|||
Undo.undoRedoPerformed += ReloadView; |
|||
|
|||
this.StretchToParentSize(); |
|||
} |
|||
|
|||
#region Callbacks
|
|||
|
|||
protected override bool canCopySelection |
|||
{ |
|||
get { return selection.Any(e => e is BaseNodeView || e is CommentBlockView); } |
|||
} |
|||
|
|||
protected override bool canCutSelection |
|||
{ |
|||
get { return selection.Any(e => e is BaseNodeView || e is CommentBlockView); } |
|||
} |
|||
|
|||
string SerializeGraphElementsCallback(IEnumerable<GraphElement> elements) |
|||
{ |
|||
var data = new CopyPasteHelper(); |
|||
|
|||
foreach (var nodeView in elements.Where(e => e is BaseNodeView)) |
|||
{ |
|||
var node = ((nodeView) as BaseNodeView).nodeTarget; |
|||
data.copiedNodes.Add(JsonSerializer.Serialize< BaseNode >(node)); |
|||
} |
|||
|
|||
foreach (var commentBlockView in elements.Where(e => e is CommentBlockView)) |
|||
{ |
|||
var commentBlock = (commentBlockView as CommentBlockView).commentBlock; |
|||
data.copiedCommentBlocks.Add(JsonSerializer.Serialize< CommentBlock >(commentBlock)); |
|||
} |
|||
|
|||
ClearSelection(); |
|||
|
|||
return JsonUtility.ToJson(data, true); |
|||
} |
|||
|
|||
bool CanPasteSerializedDataCallback(string serializedData) |
|||
{ |
|||
try { |
|||
return JsonUtility.FromJson(serializedData, typeof(CopyPasteHelper)) != null; |
|||
} catch { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
void UnserializeAndPasteCallback(string operationName, string serializedData) |
|||
{ |
|||
var data = JsonUtility.FromJson< CopyPasteHelper >(serializedData); |
|||
|
|||
RegisterCompleteObjectUndo(operationName); |
|||
|
|||
foreach (var serializedNode in data.copiedNodes) |
|||
{ |
|||
var node = JsonSerializer.DeserializeNode(serializedNode); |
|||
|
|||
//Call OnNodeCreated on the new fresh copied node
|
|||
node.OnNodeCreated(); |
|||
//And move a bit the new node
|
|||
node.position.position += new Vector2(20, 20); |
|||
|
|||
AddNode(node); |
|||
|
|||
//Select the new node
|
|||
AddToSelection(nodeViewsPerNode[node]); |
|||
} |
|||
|
|||
foreach (var serializedCommentBlock in data.copiedCommentBlocks) |
|||
{ |
|||
var commentBlock = JsonSerializer.Deserialize<CommentBlock>(serializedCommentBlock); |
|||
|
|||
//Same than for node
|
|||
commentBlock.OnCreated(); |
|||
commentBlock.position.position += new Vector2(20, 20); |
|||
|
|||
AddCommentBlock(commentBlock); |
|||
} |
|||
} |
|||
|
|||
GraphViewChange GraphViewChangedCallback(GraphViewChange changes) |
|||
{ |
|||
if (changes.elementsToRemove != null) |
|||
{ |
|||
RegisterCompleteObjectUndo("Remove Graph Elements"); |
|||
|
|||
//Handle ourselves the edge and node remove
|
|||
changes.elementsToRemove.RemoveAll(e => { |
|||
var edge = e as EdgeView; |
|||
var node = e as BaseNodeView; |
|||
var commentBlock = e as CommentBlockView; |
|||
|
|||
if (edge != null) |
|||
{ |
|||
Disconnect(edge); |
|||
return true; |
|||
} |
|||
else if (node != null) |
|||
{ |
|||
graph.RemoveNode(node.nodeTarget); |
|||
RemoveElement(node); |
|||
return true; |
|||
} |
|||
else if (commentBlock != null) |
|||
{ |
|||
graph.RemoveCommentBlock(commentBlock.commentBlock); |
|||
RemoveElement(commentBlock); |
|||
return true; |
|||
} |
|||
return false; |
|||
}); |
|||
} |
|||
|
|||
return changes; |
|||
} |
|||
|
|||
void ViewTransformChangedCallback(GraphView view) |
|||
{ |
|||
graph.position = viewTransform.position; |
|||
graph.scale = viewTransform.scale; |
|||
} |
|||
|
|||
void ElementResizedCallback(VisualElement elem) |
|||
{ |
|||
var commentBlockView = elem as CommentBlockView; |
|||
|
|||
if (commentBlockView != null) |
|||
commentBlockView.commentBlock.size = commentBlockView.GetPosition().size; |
|||
} |
|||
|
|||
public override void OnPersistentDataReady() |
|||
{ |
|||
//We set the position and scale saved in the graph asset file
|
|||
Vector3 pos = graph.position; |
|||
Vector3 scale = graph.scale; |
|||
|
|||
base.OnPersistentDataReady(); |
|||
|
|||
UpdateViewTransform(pos, scale); |
|||
} |
|||
|
|||
public override List< Port > GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) |
|||
{ |
|||
var compatiblePorts = new List< Port >(); |
|||
|
|||
compatiblePorts.AddRange(ports.ToList().Where(p => { |
|||
var portView = p as PortView; |
|||
|
|||
if (p.direction == startPort.direction) |
|||
return false; |
|||
|
|||
//Check if there is custom adapters for this assignation
|
|||
if (CustomPortIO.IsAssignable(startPort.portType, p.portType)) |
|||
return true; |
|||
|
|||
//Check for type assignability
|
|||
if (!p.portType.IsReallyAssignableFrom(startPort.portType)) |
|||
return false; |
|||
|
|||
//Check if the edge already exists
|
|||
if (portView.GetEdges().Any(e => e.input == startPort || e.output == startPort)) |
|||
return false; |
|||
|
|||
return true; |
|||
})); |
|||
|
|||
return compatiblePorts; |
|||
} |
|||
|
|||
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) |
|||
{ |
|||
BuildCreateContextualMenu(evt); |
|||
BuildViewContextualMenu(evt); |
|||
base.BuildContextualMenu(evt); |
|||
BuildSelectAssetContextualMenu(evt); |
|||
BuildSaveAssetContextualMenu(evt); |
|||
} |
|||
|
|||
protected void BuildCreateContextualMenu(ContextualMenuPopulateEvent evt) |
|||
{ |
|||
Vector2 position = evt.mousePosition - (Vector2)viewTransform.position; |
|||
evt.menu.AppendAction("Create/Comment Block", (e) => AddCommentBlock(new CommentBlock("New Comment Block", position)), DropdownMenu.MenuAction.AlwaysEnabled); |
|||
} |
|||
|
|||
protected void BuildViewContextualMenu(ContextualMenuPopulateEvent evt) |
|||
{ |
|||
evt.menu.AppendAction("View/Processor", (e) => ToggleView< ProcessorView >(), (e) => GetPinnedElementStatus< ProcessorView >()); |
|||
} |
|||
|
|||
protected void BuildSelectAssetContextualMenu(ContextualMenuPopulateEvent evt) |
|||
{ |
|||
evt.menu.AppendAction("Select Asset", (e) => EditorGUIUtility.PingObject(graph), DropdownMenu.MenuAction.AlwaysEnabled); |
|||
} |
|||
|
|||
protected void BuildSaveAssetContextualMenu(ContextualMenuPopulateEvent evt) |
|||
{ |
|||
evt.menu.AppendAction("Save Asset", (e) => { |
|||
EditorUtility.SetDirty(graph); |
|||
AssetDatabase.SaveAssets(); |
|||
}, DropdownMenu.MenuAction.AlwaysEnabled); |
|||
} |
|||
|
|||
void KeyDownCallback(KeyDownEvent e) |
|||
{ |
|||
if (e.keyCode == KeyCode.S) |
|||
{ |
|||
SaveGraphToDisk(); |
|||
e.StopPropagation(); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Initialization
|
|||
|
|||
void ReloadView() |
|||
{ |
|||
// Remove everything
|
|||
RemoveNodeViews(); |
|||
RemoveEdges(); |
|||
RemoveCommentBlocks(); |
|||
|
|||
// And re-add with new up to date datas
|
|||
InitializeNodeViews(); |
|||
InitializeEdgeViews(); |
|||
InitializeCommentBlocks(); |
|||
|
|||
Reload(); |
|||
|
|||
UpdateComputeOrder(); |
|||
} |
|||
|
|||
public void Initialize(BaseGraph graph) |
|||
{ |
|||
if (this.graph != null) |
|||
SaveGraphToDisk(); |
|||
|
|||
this.graph = graph; |
|||
|
|||
connectorListener = new EdgeConnectorListener(this); |
|||
|
|||
InitializeNodeViews(); |
|||
InitializeEdgeViews(); |
|||
InitializeViews(); |
|||
InitializeCommentBlocks(); |
|||
|
|||
UpdateComputeOrder(); |
|||
|
|||
if (initialized != null) |
|||
initialized(); |
|||
} |
|||
|
|||
void InitializeNodeViews() |
|||
{ |
|||
graph.nodes.RemoveAll(n => n == null); |
|||
|
|||
foreach (var node in graph.nodes) |
|||
AddNodeView(node); |
|||
} |
|||
|
|||
void InitializeEdgeViews() |
|||
{ |
|||
foreach (var serializedEdge in graph.edges) |
|||
{ |
|||
var inputNodeView = nodeViewsPerNode[serializedEdge.inputNode]; |
|||
var outputNodeView = nodeViewsPerNode[serializedEdge.outputNode]; |
|||
var edgeView = new EdgeView() { |
|||
userData = serializedEdge, |
|||
input = inputNodeView.GetPortFromFieldName(serializedEdge.inputFieldName), |
|||
output = outputNodeView.GetPortFromFieldName(serializedEdge.outputFieldName) |
|||
}; |
|||
|
|||
Connect(edgeView, false); |
|||
} |
|||
} |
|||
|
|||
void InitializeViews() |
|||
{ |
|||
foreach (var viewType in graph.pinnedWindows) |
|||
OpenPinned(viewType.editorType.type); |
|||
} |
|||
|
|||
void InitializeCommentBlocks() |
|||
{ |
|||
foreach (var commentBlock in graph.commentBlocks) |
|||
AddCommentBlockView(commentBlock); |
|||
} |
|||
|
|||
protected virtual void InitializeManipulators() |
|||
{ |
|||
this.AddManipulator(new ContentDragger()); |
|||
this.AddManipulator(new SelectionDragger()); |
|||
this.AddManipulator(new RectangleSelector()); |
|||
this.AddManipulator(new ClickSelector()); |
|||
} |
|||
|
|||
protected virtual void Reload() {} |
|||
|
|||
#endregion
|
|||
|
|||
#region Graph content modification
|
|||
|
|||
protected bool AddNode(BaseNode node) |
|||
{ |
|||
AddNodeView(node); |
|||
|
|||
graph.AddNode(node); |
|||
|
|||
UpdateComputeOrder(); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
protected bool AddNodeView(BaseNode node) |
|||
{ |
|||
var viewType = NodeProvider.GetNodeViewTypeFromType(node.GetType()); |
|||
|
|||
if (viewType == null) |
|||
viewType = typeof(BaseNodeView); |
|||
|
|||
var baseNodeView = Activator.CreateInstance(viewType) as BaseNodeView; |
|||
baseNodeView.Initialize(this, node); |
|||
AddElement(baseNodeView); |
|||
|
|||
nodeViews.Add(baseNodeView); |
|||
nodeViewsPerNode[node] = baseNodeView; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void RemoveNodeViews() |
|||
{ |
|||
foreach (var nodeView in nodeViews) |
|||
RemoveElement(nodeView); |
|||
nodeViews.Clear(); |
|||
nodeViewsPerNode.Clear(); |
|||
} |
|||
|
|||
public void AddCommentBlock(CommentBlock block) |
|||
{ |
|||
graph.AddCommentBlock(block); |
|||
block.OnCreated(); |
|||
AddCommentBlockView(block); |
|||
} |
|||
|
|||
public void AddCommentBlockView(CommentBlock block) |
|||
{ |
|||
var c = new CommentBlockView(); |
|||
|
|||
c.Initialize(this, block); |
|||
|
|||
AddElement(c); |
|||
|
|||
commentBlockViews.Add(c); |
|||
} |
|||
|
|||
public void RemoveCommentBlocks() |
|||
{ |
|||
foreach (var commentBlockView in commentBlockViews) |
|||
RemoveElement(commentBlockView); |
|||
commentBlockViews.Clear(); |
|||
} |
|||
|
|||
public void Connect(EdgeView e, bool serializeToGraph = true, bool autoDisconnectInputs = true) |
|||
{ |
|||
if (e.input == null || e.output == null) |
|||
return ; |
|||
|
|||
//If the input port does not support multi-connection, we remove them
|
|||
if (autoDisconnectInputs && !(e.input as PortView).isMultiple) |
|||
foreach (var edge in edgeViews.Where(ev => ev.input == e.input)) |
|||
{ |
|||
// TODO: do not disconnect them if the connected port is the same than the old connected
|
|||
Disconnect(edge, serializeToGraph); |
|||
} |
|||
|
|||
AddElement(e); |
|||
|
|||
e.input.Connect(e); |
|||
e.output.Connect(e); |
|||
|
|||
var inputNodeView = e.input.node as BaseNodeView; |
|||
var outputNodeView = e.output.node as BaseNodeView; |
|||
|
|||
if (inputNodeView == null || outputNodeView == null) |
|||
{ |
|||
Debug.LogError("Connect aborted !"); |
|||
return ; |
|||
} |
|||
|
|||
edgeViews.Add(e); |
|||
|
|||
if (serializeToGraph) |
|||
{ |
|||
e.userData = graph.Connect( |
|||
inputNodeView.nodeTarget, (e.input as PortView).fieldName, |
|||
outputNodeView.nodeTarget, (e.output as PortView).fieldName |
|||
); |
|||
} |
|||
|
|||
inputNodeView.RefreshPorts(); |
|||
outputNodeView.RefreshPorts(); |
|||
|
|||
inputNodeView.nodeTarget.OnEdgeConnected(e.userData as SerializableEdge); |
|||
outputNodeView.nodeTarget.OnEdgeConnected(e.userData as SerializableEdge); |
|||
|
|||
e.isConnected = true; |
|||
|
|||
if (serializeToGraph) |
|||
UpdateComputeOrder(); |
|||
} |
|||
|
|||
public void Disconnect(EdgeView e, bool serializeToGraph = true) |
|||
{ |
|||
var serializableEdge = e.userData as SerializableEdge; |
|||
|
|||
RemoveElement(e); |
|||
|
|||
if (e?.input?.node != null) |
|||
{ |
|||
var inputNodeView = e.input.node as BaseNodeView; |
|||
e.input.Disconnect(e); |
|||
inputNodeView.nodeTarget.OnEdgeDisonnected(e.serializedEdge); |
|||
inputNodeView.RefreshPorts(); |
|||
} |
|||
if (e?.output?.node != null) |
|||
{ |
|||
var outputNodeView = e.output.node as BaseNodeView; |
|||
e.output.Disconnect(e); |
|||
outputNodeView.nodeTarget.OnEdgeDisonnected(e.serializedEdge); |
|||
outputNodeView.RefreshPorts(); |
|||
} |
|||
|
|||
// Remove the serialized edge if there was one
|
|||
if (serializableEdge != null) |
|||
{ |
|||
if (serializeToGraph) |
|||
graph.Disconnect(serializableEdge.GUID); |
|||
UpdateComputeOrder(); |
|||
} |
|||
} |
|||
|
|||
public void RemoveEdges() |
|||
{ |
|||
foreach (var edge in edgeViews) |
|||
RemoveElement(edge); |
|||
edgeViews.Clear(); |
|||
} |
|||
|
|||
public void UpdateComputeOrder() |
|||
{ |
|||
graph.UpdateComputeOrder(); |
|||
|
|||
computeOrderUpdated?.Invoke(); |
|||
} |
|||
|
|||
public void RegisterCompleteObjectUndo(string name) |
|||
{ |
|||
Undo.RegisterCompleteObjectUndo(graph, name); |
|||
} |
|||
|
|||
public void SaveGraphToDisk() |
|||
{ |
|||
EditorUtility.SetDirty(graph); |
|||
} |
|||
|
|||
public void ToggleView< T >() where T : PinnedElementView |
|||
{ |
|||
ToggleView(typeof(T)); |
|||
} |
|||
|
|||
public void ToggleView(Type type) |
|||
{ |
|||
PinnedElementView view; |
|||
pinnedElements.TryGetValue(type, out view); |
|||
|
|||
if (view == null) |
|||
OpenPinned(type); |
|||
else |
|||
ClosePinned(type, view); |
|||
} |
|||
|
|||
public void OpenPinned(Type type) |
|||
{ |
|||
PinnedElementView view; |
|||
|
|||
if (type == null) |
|||
return ; |
|||
|
|||
PinnedElement elem = graph.OpenPinned(type); |
|||
|
|||
view = Activator.CreateInstance(type) as PinnedElementView; |
|||
pinnedElements[type] = view; |
|||
|
|||
view.InitializeGraphView(elem, this); |
|||
|
|||
ConfinedDragger masterPreviewViewDraggable = new ConfinedDragger(this); |
|||
masterPreviewViewDraggable.onDragEnd = () => elem.position = view.transform.position; |
|||
view.AddManipulator(masterPreviewViewDraggable); |
|||
Add(view); |
|||
} |
|||
|
|||
public void ClosePinned(Type type, PinnedElementView elem) |
|||
{ |
|||
pinnedElements.Remove(type); |
|||
Remove(elem); |
|||
graph.ClosePinned(type); |
|||
} |
|||
|
|||
public StatusFlags GetPinnedElementStatus< T >() where T : PinnedElementView |
|||
{ |
|||
return GetPinnedElementStatus(typeof(T)); |
|||
} |
|||
|
|||
public StatusFlags GetPinnedElementStatus(Type type) |
|||
{ |
|||
var pinned = graph.pinnedWindows.Find(p => p.editorType.type == type); |
|||
|
|||
if (pinned != null && pinned.opened) |
|||
return StatusFlags.Normal; |
|||
else |
|||
return StatusFlags.Hidden; |
|||
} |
|||
|
|||
public void ResetPositionAndZoom() |
|||
{ |
|||
graph.position = Vector3.zero; |
|||
graph.scale = Vector3.one; |
|||
|
|||
UpdateViewTransform(graph.position, graph.scale); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 82433700726b148b2af8af687c24fa3a |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEditor; |
|||
using System.Reflection; |
|||
using System; |
|||
using System.Linq; |
|||
using UnityEditorInternal; |
|||
|
|||
using StatusFlags = UnityEngine.Experimental.UIElements.DropdownMenu.MenuAction.StatusFlags; |
|||
using NodeView = UnityEditor.Experimental.UIElements.GraphView.Node; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[NodeCustomEditor(typeof(BaseNode))] |
|||
public class BaseNodeView : NodeView |
|||
{ |
|||
public BaseNode nodeTarget; |
|||
|
|||
public List< Port > inputPorts = new List< Port >(); |
|||
public List< Port > outputPorts = new List< Port >(); |
|||
|
|||
public BaseGraphView owner { private set; get; } |
|||
|
|||
protected Dictionary< string, Port > portsPerFieldName = new Dictionary< string, Port >(); |
|||
|
|||
protected VisualElement controlsContainer; |
|||
protected VisualElement debugContainer; |
|||
|
|||
Label computeOrderLabel = new Label(); |
|||
|
|||
#region Initialization
|
|||
|
|||
public void Initialize(BaseGraphView owner, BaseNode node) |
|||
{ |
|||
nodeTarget = node; |
|||
this.owner = owner; |
|||
|
|||
owner.computeOrderUpdated += ComputeOrderUpdatedCallback; |
|||
|
|||
AddStyleSheetPath("GraphProcessorStyles/BaseNodeView"); |
|||
|
|||
InitializePorts(); |
|||
InitializeView(); |
|||
InitializeDebug(); |
|||
|
|||
Enable(); |
|||
|
|||
this.RefreshPorts(); |
|||
} |
|||
|
|||
void InitializePorts() |
|||
{ |
|||
foreach (var fieldInfo in nodeTarget.nodeFields) |
|||
{ |
|||
// This will automatically create our visual ports
|
|||
PortBehaviorFactory.CreatePortBehavior( |
|||
this, |
|||
fieldInfo.Value.info, |
|||
fieldInfo.Value.input ? Direction.Input : Direction.Output, |
|||
owner.connectorListener, |
|||
fieldInfo.Value.isMultiple, |
|||
fieldInfo.Value.name |
|||
); |
|||
} |
|||
} |
|||
|
|||
void InitializeView() |
|||
{ |
|||
controlsContainer = new VisualElement{ name = "controls" }; |
|||
mainContainer.Add(controlsContainer); |
|||
|
|||
debugContainer = new VisualElement{ name = "debug" }; |
|||
mainContainer.Add(debugContainer); |
|||
|
|||
title = (string.IsNullOrEmpty(nodeTarget.name)) ? nodeTarget.GetType().Name : nodeTarget.name; |
|||
|
|||
SetPosition(nodeTarget.position); |
|||
} |
|||
|
|||
void InitializeDebug() |
|||
{ |
|||
ComputeOrderUpdatedCallback(); |
|||
debugContainer.Add(computeOrderLabel); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region API
|
|||
|
|||
public Port GetPortFromFieldName(string fieldName) |
|||
{ |
|||
Port ret; |
|||
|
|||
portsPerFieldName.TryGetValue(fieldName, out ret); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
public PortView AddPort(FieldInfo fieldInfo, Direction direction, EdgeConnectorListener listener, bool isMultiple = false, string name = null) |
|||
{ |
|||
// TODO: hardcoded value
|
|||
PortView p = new PortView(Orientation.Horizontal, direction, fieldInfo, listener); |
|||
|
|||
if (p.direction == Direction.Input) |
|||
{ |
|||
inputPorts.Add(p); |
|||
inputContainer.Add(p); |
|||
} |
|||
else |
|||
{ |
|||
outputPorts.Add(p); |
|||
outputContainer.Add(p); |
|||
} |
|||
|
|||
p.Initialize(this, isMultiple, name); |
|||
|
|||
portsPerFieldName[p.fieldName] = p; |
|||
|
|||
return p; |
|||
} |
|||
|
|||
public void RemovePort(PortView p) |
|||
{ |
|||
if (p.direction == Direction.Input) |
|||
{ |
|||
inputPorts.Remove(p); |
|||
inputContainer.Remove(p); |
|||
|
|||
} |
|||
else |
|||
{ |
|||
outputPorts.Remove(p); |
|||
outputContainer.Remove(p); |
|||
} |
|||
|
|||
portsPerFieldName.Remove(p.fieldName); |
|||
} |
|||
|
|||
public void OpenNodeViewScript() |
|||
{ |
|||
var scriptPath = NodeProvider.GetNodeViewScript(GetType()); |
|||
|
|||
if (scriptPath != null) |
|||
InternalEditorUtility.OpenFileAtLineExternal(scriptPath, 0); |
|||
} |
|||
|
|||
public void OpenNodeScript() |
|||
{ |
|||
var scriptPath = NodeProvider.GetNodeScript(nodeTarget.GetType()); |
|||
|
|||
if (scriptPath != null) |
|||
InternalEditorUtility.OpenFileAtLineExternal(scriptPath, 0); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Callbacks & Overrides
|
|||
|
|||
void ComputeOrderUpdatedCallback() |
|||
{ |
|||
//Update debug compute order
|
|||
computeOrderLabel.text = "Compute order: " + nodeTarget.computeOrder; |
|||
} |
|||
|
|||
public virtual void Enable() |
|||
{ |
|||
DrawDefaultInspector(); |
|||
} |
|||
|
|||
public virtual void DrawDefaultInspector() |
|||
{ |
|||
var fields = nodeTarget.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); |
|||
|
|||
foreach (var field in fields) |
|||
{ |
|||
//skip if the field is not serializable
|
|||
if (!field.IsPublic && field.GetCustomAttribute(typeof(SerializeField)) == null) |
|||
continue ; |
|||
|
|||
//skip if the field is an input/output and not marked as SerializedField
|
|||
if (field.GetCustomAttribute(typeof(SerializeField)) == null && (field.GetCustomAttribute(typeof(InputAttribute)) != null || field.GetCustomAttribute(typeof(OutputAttribute)) != null)) |
|||
continue ; |
|||
|
|||
//skip if marked with NonSerialized or HideInInspector
|
|||
if (field.GetCustomAttribute(typeof(System.NonSerializedAttribute)) != null || field.GetCustomAttribute(typeof(HideInInspector)) != null) |
|||
continue ; |
|||
|
|||
var controlLabel = new Label(field.Name); |
|||
controlsContainer.Add(controlLabel); |
|||
|
|||
var element = FieldFactory.CreateField(field, field.GetValue(nodeTarget), (newValue) => { |
|||
field.SetValue(nodeTarget, newValue); |
|||
owner.RegisterCompleteObjectUndo("Updated " + newValue); |
|||
}); |
|||
|
|||
if (element != null) |
|||
controlsContainer.Add(element); |
|||
} |
|||
} |
|||
|
|||
public virtual void OnPortConnected(PortView port) {} |
|||
public virtual void OnPortDisconnected(PortView port) {} |
|||
|
|||
public override void SetPosition(Rect newPos) |
|||
{ |
|||
base.SetPosition(newPos); |
|||
|
|||
nodeTarget.position = newPos; |
|||
} |
|||
|
|||
public override bool expanded |
|||
{ |
|||
get { return base.expanded; } |
|||
set |
|||
{ |
|||
base.expanded = value; |
|||
nodeTarget.expanded = value; |
|||
} |
|||
} |
|||
|
|||
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) |
|||
{ |
|||
evt.menu.AppendAction("Open Node Script", (e) => OpenNodeScript(), OpenNodeScriptStatus); |
|||
evt.menu.AppendAction("Open Node View Script", (e) => OpenNodeViewScript(), OpenNodeViewScriptStatus); |
|||
} |
|||
|
|||
StatusFlags OpenNodeScriptStatus(DropdownMenu.MenuAction action) |
|||
{ |
|||
if (NodeProvider.GetNodeScript(nodeTarget.GetType()) != null) |
|||
return StatusFlags.Normal; |
|||
return StatusFlags.Disabled; |
|||
} |
|||
|
|||
StatusFlags OpenNodeViewScriptStatus(DropdownMenu.MenuAction action) |
|||
{ |
|||
if (NodeProvider.GetNodeViewScript(GetType()) != null) |
|||
return StatusFlags.Normal; |
|||
return StatusFlags.Disabled; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 82efb95f0451b4cc88cc103f2a013dd5 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class CommentBlockView : Group |
|||
{ |
|||
public BaseGraphView owner; |
|||
public CommentBlock commentBlock; |
|||
|
|||
Label titleLabel; |
|||
ColorField colorField; |
|||
|
|||
public CommentBlockView() |
|||
{ |
|||
AddStyleSheetPath("GraphProcessorStyles/CommentBlockView"); |
|||
} |
|||
|
|||
public void Initialize(BaseGraphView graphView, CommentBlock block) |
|||
{ |
|||
commentBlock = block; |
|||
owner = graphView; |
|||
|
|||
title = block.title; |
|||
SetSize(block.size); |
|||
SetPosition(block.position); |
|||
|
|||
headerContainer.Q<TextField>().RegisterCallback<ChangeEvent<string>>(TitleChangedCallback); |
|||
titleLabel = headerContainer.Q<Label>(); |
|||
|
|||
colorField = new ColorField{ value = commentBlock.color, name = "headerColorPicker" }; |
|||
colorField.OnValueChanged(e => |
|||
{ |
|||
UpdateCommentBlockColor(e.newValue); |
|||
}); |
|||
UpdateCommentBlockColor(commentBlock.color); |
|||
|
|||
headerContainer.Add(colorField); |
|||
|
|||
InitializeInnerNodes(); |
|||
} |
|||
|
|||
void InitializeInnerNodes() |
|||
{ |
|||
foreach (var nodeGUID in commentBlock.innerNodeGUIDs) |
|||
{ |
|||
if (!owner.graph.nodesPerGUID.ContainsKey(nodeGUID)) |
|||
{ |
|||
Debug.LogWarning("Node GUID not found: " + nodeGUID); |
|||
|
|||
continue ; |
|||
} |
|||
var node = owner.graph.nodesPerGUID[nodeGUID]; |
|||
var nodeView = owner.nodeViewsPerNode[node]; |
|||
|
|||
AddElement(nodeView); |
|||
} |
|||
} |
|||
|
|||
protected override void OnElementsAdded(IEnumerable<GraphElement> elements) |
|||
{ |
|||
foreach (var element in elements) |
|||
{ |
|||
var node = element as BaseNodeView; |
|||
|
|||
if (node == null) |
|||
throw new System.ArgumentException("Adding another thing than node is not currently supported"); |
|||
|
|||
if (!commentBlock.innerNodeGUIDs.Contains(node.nodeTarget.GUID)) |
|||
commentBlock.innerNodeGUIDs.Add(node.nodeTarget.GUID); |
|||
} |
|||
base.OnElementsAdded(elements); |
|||
} |
|||
|
|||
public void UpdateCommentBlockColor(Color newColor) |
|||
{ |
|||
commentBlock.color = newColor; |
|||
style.backgroundColor = newColor; |
|||
titleLabel.style.color = new Color(1 - newColor.r, 1 - newColor.g, 1 - newColor.b, 1); |
|||
} |
|||
|
|||
void TitleChangedCallback(ChangeEvent< string > e) |
|||
{ |
|||
commentBlock.title = e.newValue; |
|||
} |
|||
|
|||
public override void SetPosition(Rect newPos) |
|||
{ |
|||
base.SetPosition(newPos); |
|||
|
|||
commentBlock.position = newPos; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e577ba4ccbfd74da5a0ea1c19bc93bd2 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class EdgeView : Edge |
|||
{ |
|||
public bool isConnected = false; |
|||
|
|||
public SerializableEdge serializedEdge { get { return userData as SerializableEdge; } } |
|||
|
|||
public EdgeView() |
|||
{ |
|||
AddStyleSheetPath("GraphProcessorStyles/EdgeView"); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: e38753fb1fe624181b84aa5b468ebc01 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class MiniMapView : MiniMap |
|||
{ |
|||
BaseGraphView graphView; |
|||
Vector2 size; |
|||
|
|||
public MiniMapView(BaseGraphView baseGraphView) |
|||
{ |
|||
this.graphView = baseGraphView; |
|||
SetPosition(new Rect(0, 0, 100, 100)); |
|||
size = new Vector2(100, 100); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 76246e393040b425e8d74ff93388a1d5 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEngine.Experimental.UIElements.StyleEnums; |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public abstract class PinnedElementView : VisualElement |
|||
{ |
|||
protected VisualElement header; |
|||
protected PinnedElement pinnedElement; |
|||
|
|||
private Label titleLabel; |
|||
|
|||
public string title |
|||
{ |
|||
get => titleLabel.text; |
|||
set => titleLabel.text = value; |
|||
} |
|||
|
|||
public PinnedElementView() |
|||
{ |
|||
AddStyleSheetPath("GraphProcessorStyles/PinnedElementView"); |
|||
|
|||
name = "PinnedElementView"; |
|||
|
|||
clippingOptions = ClippingOptions.ClipAndCacheContents; |
|||
header = new VisualElement { name = "header" }; |
|||
{ |
|||
titleLabel = new Label { name = "title", text = "Title" }; |
|||
header.Add(titleLabel); |
|||
} |
|||
Add(header); |
|||
} |
|||
|
|||
public override void OnPersistentDataReady() |
|||
{ |
|||
transform.position = pinnedElement.position; |
|||
} |
|||
|
|||
public void InitializeGraphView(PinnedElement pinnedElement, BaseGraphView graphView) |
|||
{ |
|||
this.pinnedElement = pinnedElement; |
|||
transform.position = pinnedElement.position; |
|||
Initialize(graphView); |
|||
} |
|||
|
|||
protected abstract void Initialize(BaseGraphView graphView); |
|||
|
|||
~PinnedElementView() |
|||
{ |
|||
Destroy(); |
|||
} |
|||
|
|||
protected virtual void Destroy() {} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ed45305e038bd465d8f37499a7d22489 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using System; |
|||
using System.Reflection; |
|||
using UnityEngine.Experimental.UIElements.StyleEnums; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class PortView : Port |
|||
{ |
|||
public bool isMultiple; |
|||
public string fieldName { get; protected set; } |
|||
public new Type portType; |
|||
public BaseNodeView owner { get; private set; } |
|||
|
|||
public event Action< PortView, Edge > OnConnected; |
|||
public event Action< PortView, Edge > OnDisconnected; |
|||
|
|||
protected FieldInfo fieldInfo; |
|||
protected EdgeConnectorListener listener; |
|||
|
|||
string userPortStyleFile = "PortViewTypes"; |
|||
|
|||
List< EdgeView > edges = new List< EdgeView >(); |
|||
|
|||
public PortView(Orientation portOrientation, Direction direction, FieldInfo fieldInfo, EdgeConnectorListener edgeConnectorListener) |
|||
: base(portOrientation, direction, Capacity.Multi, fieldInfo.FieldType) |
|||
{ |
|||
AddStyleSheetPath("GraphProcessorStyles/PortView"); |
|||
|
|||
if (Resources.Load< UnityEngine.Object >(userPortStyleFile) != null) |
|||
AddStyleSheetPath(userPortStyleFile); |
|||
|
|||
this.m_EdgeConnector = new EdgeConnector< EdgeView >(edgeConnectorListener); |
|||
this.AddManipulator(m_EdgeConnector); |
|||
|
|||
fieldName = fieldInfo.Name; |
|||
portType = fieldInfo.FieldType; |
|||
|
|||
this.fieldInfo = fieldInfo; |
|||
this.listener = edgeConnectorListener; |
|||
} |
|||
|
|||
public virtual void Initialize(BaseNodeView nodeView, bool isMultiple, string name) |
|||
{ |
|||
this.isMultiple = isMultiple; |
|||
this.owner = nodeView; |
|||
|
|||
// Correct port type if port accept multiple values (and so is a container)
|
|||
if (isMultiple) |
|||
portType = portType.GetGenericArguments()[0]; |
|||
|
|||
if (name != null) |
|||
portName = name; |
|||
visualClass = "Port_" + portType.Name; |
|||
} |
|||
|
|||
public override void Connect(Edge edge) |
|||
{ |
|||
OnConnected?.Invoke(this, edge); |
|||
|
|||
base.Connect(edge); |
|||
|
|||
var inputNode = (edge.input as PortView).owner; |
|||
var outputNode = (edge.output as PortView).owner; |
|||
|
|||
inputNode.OnPortConnected(edge.input as PortView); |
|||
outputNode.OnPortConnected(edge.output as PortView); |
|||
|
|||
edges.Add(edge as EdgeView); |
|||
} |
|||
|
|||
public override void Disconnect(Edge edge) |
|||
{ |
|||
OnDisconnected?.Invoke(this, edge); |
|||
|
|||
base.Disconnect(edge); |
|||
|
|||
if (!(edge as EdgeView).isConnected) |
|||
return ; |
|||
|
|||
var inputNode = (edge.input as PortView).owner; |
|||
var outputNode = (edge.output as PortView).owner; |
|||
|
|||
inputNode.OnPortDisconnected(edge.input as PortView); |
|||
outputNode.OnPortDisconnected(edge.output as PortView); |
|||
|
|||
edges.Remove(edge as EdgeView); |
|||
} |
|||
|
|||
public List< EdgeView > GetEdges() |
|||
{ |
|||
return edges; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 69c0ad40b9eda46c89c464f0b6d81a38 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using UnityEngine.Experimental.UIElements.StyleEnums; |
|||
using UnityEngine.Experimental.UIElements; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class ProcessorView : PinnedElementView |
|||
{ |
|||
BaseGraphProcessor processor; |
|||
|
|||
public ProcessorView() |
|||
{ |
|||
title = "Process panel"; |
|||
} |
|||
|
|||
protected override void Initialize(BaseGraphView graphView) |
|||
{ |
|||
processor = new ProcessGraphProcessor(graphView.graph); |
|||
|
|||
graphView.computeOrderUpdated += processor.UpdateComputeOrder; |
|||
|
|||
Button b = new Button(OnPlay) { name = "ActionButton", text = "Play !" }; |
|||
|
|||
Add(b); |
|||
} |
|||
|
|||
void OnPlay() |
|||
{ |
|||
processor.Run(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: ba435dc6c3986437ebc9baec443d80b9 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using UnityEditor.Experimental.UIElements.GraphView; |
|||
using UnityEditor.Experimental.UIElements; |
|||
using UnityEngine.Experimental.UIElements.StyleEnums; |
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEditor; |
|||
using System; |
|||
|
|||
using StatusFlags = UnityEngine.Experimental.UIElements.DropdownMenu.MenuAction.StatusFlags; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class ToolbarView : VisualElement |
|||
{ |
|||
class ToolbarButtonData |
|||
{ |
|||
public string name; |
|||
public bool toggle; |
|||
public bool value; |
|||
public Action buttonCallback; |
|||
public Action< bool > toggleCallback; |
|||
} |
|||
|
|||
List< ToolbarButtonData > leftButtonDatas = new List< ToolbarButtonData >(); |
|||
List< ToolbarButtonData > rightButtonDatas = new List< ToolbarButtonData >(); |
|||
protected BaseGraphView graphView; |
|||
|
|||
public ToolbarView(BaseGraphView graphView) |
|||
{ |
|||
name = "ToolbarView"; |
|||
this.graphView = graphView; |
|||
|
|||
graphView.initialized += AddButtons; |
|||
|
|||
Add(new IMGUIContainer(DrawImGUIToolbar)); |
|||
} |
|||
|
|||
protected void AddButton(string name, Action callback, bool left = true) |
|||
{ |
|||
((left) ? leftButtonDatas : rightButtonDatas).Add(new ToolbarButtonData{ |
|||
name = name, |
|||
toggle = false, |
|||
buttonCallback = callback |
|||
}); |
|||
} |
|||
|
|||
protected void AddToggle(string name, bool defaultValue, Action< bool > callback, bool left = true) |
|||
{ |
|||
((left) ? leftButtonDatas : rightButtonDatas).Add(new ToolbarButtonData{ |
|||
name = name, |
|||
toggle = true, |
|||
value = defaultValue, |
|||
toggleCallback = callback |
|||
}); |
|||
} |
|||
|
|||
protected virtual void AddButtons() |
|||
{ |
|||
AddButton("Center", graphView.ResetPositionAndZoom); |
|||
|
|||
bool processorVisible = graphView.GetPinnedElementStatus< ProcessorView >() != StatusFlags.Hidden; |
|||
AddToggle("Show Processor", processorVisible, (v) => graphView.ToggleView< ProcessorView>()); |
|||
|
|||
AddButton("Show In Project", () => EditorGUIUtility.PingObject(graphView.graph), false); |
|||
} |
|||
|
|||
void DrawImGUIButtonList(List< ToolbarButtonData > buttons) |
|||
{ |
|||
foreach (var button in buttons) |
|||
{ |
|||
if (button.toggle) |
|||
{ |
|||
EditorGUI.BeginChangeCheck(); |
|||
button.value = GUILayout.Toggle(button.value, button.name, EditorStyles.toolbarButton); |
|||
if (EditorGUI.EndChangeCheck() && button.toggleCallback != null) |
|||
button.toggleCallback(button.value); |
|||
} |
|||
else |
|||
{ |
|||
if (GUILayout.Button(button.name, EditorStyles.toolbarButton) && button.buttonCallback != null) |
|||
button.buttonCallback(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
void DrawImGUIToolbar() |
|||
{ |
|||
GUILayout.BeginHorizontal(EditorStyles.toolbar); |
|||
|
|||
DrawImGUIButtonList(leftButtonDatas); |
|||
|
|||
GUILayout.FlexibleSpace(); |
|||
|
|||
DrawImGUIButtonList(rightButtonDatas); |
|||
|
|||
GUILayout.EndHorizontal(); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3844ba2924c064729bd5589ba9d3ad59 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
{ |
|||
"name": "com.alelievr.NodeGraphProcessor-Editor", |
|||
"references": [ |
|||
"com.alelievr.NodeGraphProcessor" |
|||
], |
|||
"optionalUnityReferences": [], |
|||
"includePlatforms": [], |
|||
"excludePlatforms": [ |
|||
"Editor" |
|||
], |
|||
"allowUnsafeCode": false, |
|||
"overrideReferences": false, |
|||
"precompiledReferences": [], |
|||
"autoReferenced": true, |
|||
"defineConstraints": [] |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 036ec4299675a444c8cda9774db433f1 |
|||
AssemblyDefinitionImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
MIT License |
|||
|
|||
Copyright (c) 2018 Antoine Lelievre |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
|
|||
fileFormatVersion: 2 |
|||
guid: f80bc1a9962357243a163132b9b2ca5e |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: de9dcb1d4913a5646b09e2b73101162f |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: d87d8f985f7499f40b41e67ff7212077 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using System; |
|||
using System.Reflection; |
|||
using Unity.Jobs; |
|||
using System.Linq; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[Serializable] |
|||
public abstract class BaseNode |
|||
{ |
|||
public virtual string name => GetType().Name; |
|||
|
|||
//id
|
|||
public string GUID; |
|||
|
|||
public int computeOrder = -1; |
|||
public bool canProcess = true; |
|||
|
|||
[NonSerialized] |
|||
public readonly NodeInputPortContainer inputPorts; |
|||
[NonSerialized] |
|||
public readonly NodeOutputPortContainer outputPorts; |
|||
|
|||
//Node view datas
|
|||
public Rect position; |
|||
public bool expanded; |
|||
|
|||
public delegate void ProcessDelegate(); |
|||
|
|||
public event ProcessDelegate onProcessed; |
|||
|
|||
[NonSerialized] |
|||
public Dictionary< string, NodeFieldInformation > nodeFields = new Dictionary< string, NodeFieldInformation >(); |
|||
|
|||
public class NodeFieldInformation |
|||
{ |
|||
public string name; |
|||
public string fieldName; |
|||
public FieldInfo info; |
|||
public bool input; |
|||
public bool isMultiple; |
|||
|
|||
public NodeFieldInformation(FieldInfo info, string name, bool input, bool isMultiple) |
|||
{ |
|||
this.input = input; |
|||
this.isMultiple = isMultiple; |
|||
this.info = info; |
|||
this.name = name; |
|||
this.fieldName = info.Name; |
|||
} |
|||
} |
|||
|
|||
public static BaseNode CreateFromType(Type nodeType, Vector2 position) |
|||
{ |
|||
if (!nodeType.IsSubclassOf(typeof(BaseNode))) |
|||
return null; |
|||
|
|||
var node = Activator.CreateInstance(nodeType) as BaseNode; |
|||
|
|||
node.position = new Rect(position, new Vector2(100, 100)); |
|||
|
|||
node.OnNodeCreated(); |
|||
|
|||
return node; |
|||
} |
|||
|
|||
#region Initialization
|
|||
|
|||
protected BaseNode() |
|||
{ |
|||
InitializeInOutDatas(); |
|||
|
|||
Enable(); |
|||
|
|||
inputPorts = new NodeInputPortContainer(this); |
|||
outputPorts = new NodeOutputPortContainer(this); |
|||
|
|||
foreach (var nodeFieldKP in nodeFields) |
|||
{ |
|||
AddPort(nodeFieldKP.Value.input, nodeFieldKP.Value.fieldName); |
|||
} |
|||
} |
|||
|
|||
~BaseNode() |
|||
{ |
|||
Disable(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Called only when the node is created, not when instantiated
|
|||
/// </summary>
|
|||
public virtual void OnNodeCreated() |
|||
{ |
|||
GUID = Guid.NewGuid().ToString(); |
|||
} |
|||
|
|||
void InitializeInOutDatas() |
|||
{ |
|||
var fields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); |
|||
|
|||
foreach (var field in fields) |
|||
{ |
|||
var inputAttribute = field.GetCustomAttribute< InputAttribute >(); |
|||
var outputAttribute = field.GetCustomAttribute< OutputAttribute >(); |
|||
bool isMultiple = false; |
|||
bool input = false; |
|||
string name = field.Name; |
|||
|
|||
if (inputAttribute == null && outputAttribute == null) |
|||
continue ; |
|||
|
|||
//check if field is a collection type
|
|||
isMultiple = (inputAttribute != null) ? inputAttribute.allowMultiple : false; |
|||
input = inputAttribute != null; |
|||
|
|||
if (!String.IsNullOrEmpty(inputAttribute?.name)) |
|||
name = inputAttribute.name; |
|||
if (!String.IsNullOrEmpty(outputAttribute?.name)) |
|||
name = outputAttribute.name; |
|||
|
|||
nodeFields[field.Name] = new NodeFieldInformation(field, name, input, isMultiple); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region Events and Processing
|
|||
|
|||
public void OnEdgeConnected(SerializableEdge edge) |
|||
{ |
|||
bool input = edge.inputNode == this; |
|||
NodePortContainer portCollection = (input) ? (NodePortContainer)inputPorts : outputPorts; |
|||
|
|||
portCollection.Add(edge); |
|||
} |
|||
|
|||
public void OnEdgeDisonnected(SerializableEdge edge) |
|||
{ |
|||
if (edge == null) |
|||
return ; |
|||
|
|||
bool input = edge.inputNode == this; |
|||
NodePortContainer portCollection = (input) ? (NodePortContainer)inputPorts : outputPorts; |
|||
|
|||
portCollection.Remove(edge); |
|||
} |
|||
|
|||
public void OnProcess() |
|||
{ |
|||
inputPorts.PullDatas(); |
|||
|
|||
Process(); |
|||
|
|||
onProcessed?.Invoke(); |
|||
|
|||
outputPorts.PushDatas(); |
|||
} |
|||
|
|||
protected virtual void Enable() {} |
|||
protected virtual void Disable() {} |
|||
|
|||
protected virtual void Process() {} |
|||
|
|||
#endregion
|
|||
|
|||
#region API and utils
|
|||
|
|||
public void AddPort(bool input, string fieldName) |
|||
{ |
|||
if (input) |
|||
inputPorts.Add(new NodePort(this, fieldName)); |
|||
else |
|||
outputPorts.Add(new NodePort(this, fieldName)); |
|||
} |
|||
|
|||
public void RemovePort(bool input, NodePort port) |
|||
{ |
|||
if (input) |
|||
inputPorts.Remove(port); |
|||
else |
|||
outputPorts.Remove(port); |
|||
} |
|||
|
|||
public void RemovePort(bool input, string fieldName) |
|||
{ |
|||
if (input) |
|||
inputPorts.RemoveAll(p => p.fieldName == fieldName); |
|||
else |
|||
outputPorts.RemoveAll(p => p.fieldName == fieldName); |
|||
} |
|||
|
|||
public IEnumerable< BaseNode > GetInputNodes() |
|||
{ |
|||
foreach (var port in inputPorts) |
|||
foreach (var edge in port.GetEdges()) |
|||
yield return edge.outputNode; |
|||
} |
|||
|
|||
public IEnumerable< BaseNode > GetOutputNodes() |
|||
{ |
|||
foreach (var port in outputPorts) |
|||
foreach (var edge in port.GetEdges()) |
|||
yield return edge.inputNode; |
|||
} |
|||
|
|||
public NodePort GetPort(string fieldName) |
|||
{ |
|||
return inputPorts.Concat(outputPorts).FirstOrDefault(p => p.fieldName == fieldName); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: d3989238b25842a4da391d2c531fac81 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[System.Serializable] |
|||
public class CommentBlock |
|||
{ |
|||
public string title; |
|||
public Color color; |
|||
public Rect position; |
|||
public Vector2 size; |
|||
|
|||
public List< string > innerNodeGUIDs = new List< string >(); |
|||
|
|||
public CommentBlock(string title, Vector2 position) |
|||
{ |
|||
this.title = title; |
|||
this.position.position = position; |
|||
} |
|||
|
|||
public virtual void OnCreated() |
|||
{ |
|||
size = new Vector2(300, 100); |
|||
position.size = size; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 97be34581635f0c429c2b7a84773be03 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Linq; |
|||
using System.Collections.Generic; |
|||
using UnityEngine; |
|||
using System.Reflection; |
|||
using System.Linq.Expressions; |
|||
using System; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
public class NodePort |
|||
{ |
|||
|
|||
public string fieldName; |
|||
public BaseNode owner; |
|||
List< SerializableEdge > edges = new List< SerializableEdge >(); |
|||
Dictionary< SerializableEdge, PushDataDelegate > pushDataDelegates = new Dictionary< SerializableEdge, PushDataDelegate >(); |
|||
List< SerializableEdge > edgeWithRemoteCustomIO = new List< SerializableEdge >(); |
|||
|
|||
CustomPortIODelegate customPortIOMethod; |
|||
FieldInfo ourValueField; |
|||
|
|||
public delegate void PushDataDelegate(); |
|||
|
|||
public NodePort(BaseNode owner, string fieldName) |
|||
{ |
|||
this.fieldName = fieldName; |
|||
this.owner = owner; |
|||
|
|||
ourValueField = owner.GetType().GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); |
|||
|
|||
customPortIOMethod = CustomPortIO.GetCustomPortMethod(owner.GetType(), fieldName); |
|||
} |
|||
|
|||
public void Add(SerializableEdge edge) |
|||
{ |
|||
if (!edges.Contains(edge)) |
|||
edges.Add(edge); |
|||
|
|||
if (edge.inputNode == owner) |
|||
{ |
|||
if (edge.outputPort.customPortIOMethod != null) |
|||
edgeWithRemoteCustomIO.Add(edge); |
|||
} |
|||
else |
|||
{ |
|||
if (edge.inputPort.customPortIOMethod != null) |
|||
edgeWithRemoteCustomIO.Add(edge); |
|||
} |
|||
|
|||
//if we have a custom io implementation, we don't need
|
|||
if (edge.inputPort.customPortIOMethod != null || edge.outputPort.customPortIOMethod != null) |
|||
return ; |
|||
|
|||
PushDataDelegate edgeDelegate = CreatePushDataDelegateForEdge(edge); |
|||
|
|||
if (edgeDelegate != null) |
|||
pushDataDelegates[edge] = edgeDelegate; |
|||
} |
|||
|
|||
PushDataDelegate CreatePushDataDelegateForEdge(SerializableEdge edge) |
|||
{ |
|||
try |
|||
{ |
|||
//Creation of the delegate to move the data from the input node to the output node:
|
|||
FieldInfo inputField = edge.inputNode.GetType().GetField(edge.trueInputFieldName, BindingFlags.Public | BindingFlags.Instance); |
|||
FieldInfo outputField = edge.outputNode.GetType().GetField(edge.trueOutputFieldName, BindingFlags.Public | BindingFlags.Instance); |
|||
|
|||
MemberExpression inputParamField = Expression.Field(Expression.Constant(edge.inputNode), inputField); |
|||
MemberExpression outputParamField = Expression.Field(Expression.Constant(edge.outputNode), outputField); |
|||
|
|||
BinaryExpression assign = Expression.Assign(inputParamField, Expression.Convert(outputParamField, inputField.FieldType)); |
|||
return Expression.Lambda< PushDataDelegate >(assign).Compile(); |
|||
} catch (Exception e) { |
|||
Debug.LogError(e); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public void Remove(SerializableEdge edge) |
|||
{ |
|||
pushDataDelegates.Remove(edge); |
|||
edges.Remove(edge); |
|||
} |
|||
|
|||
public List< SerializableEdge > GetEdges() |
|||
{ |
|||
return edges; |
|||
} |
|||
|
|||
//This method can only be called on output ports
|
|||
public void PushData() |
|||
{ |
|||
if (customPortIOMethod != null) |
|||
{ |
|||
customPortIOMethod(owner, edges); |
|||
return ; |
|||
} |
|||
|
|||
foreach (var pushDataDelegate in pushDataDelegates) |
|||
pushDataDelegate.Value(); |
|||
|
|||
if (edgeWithRemoteCustomIO.Count == 0) |
|||
return ; |
|||
|
|||
//if there are custom IO implementation on the other ports, they'll need our value in the passThrough buffer
|
|||
object ourValue = ourValueField.GetValue(owner); |
|||
foreach (var edge in edgeWithRemoteCustomIO) |
|||
edge.passThroughBuffer = ourValue; |
|||
} |
|||
|
|||
public void PullData() |
|||
{ |
|||
if (customPortIOMethod != null) |
|||
{ |
|||
customPortIOMethod(owner, edges); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public abstract class NodePortContainer : List< NodePort > |
|||
{ |
|||
protected BaseNode node; |
|||
|
|||
public NodePortContainer(BaseNode node) |
|||
{ |
|||
this.node = node; |
|||
} |
|||
|
|||
public void Remove(SerializableEdge edge) |
|||
{ |
|||
ForEach(p => p.Remove(edge)); |
|||
} |
|||
|
|||
public void Add(SerializableEdge edge) |
|||
{ |
|||
string portFieldName = (edge.inputNode == node) ? edge.inputFieldName : edge.outputFieldName; |
|||
var port = this.FirstOrDefault(p => p.fieldName == portFieldName); |
|||
port.Add(edge); |
|||
} |
|||
} |
|||
|
|||
public class NodeInputPortContainer : NodePortContainer |
|||
{ |
|||
public NodeInputPortContainer(BaseNode node) : base(node) {} |
|||
|
|||
public void PullDatas() |
|||
{ |
|||
ForEach(p => p.PullData()); |
|||
} |
|||
} |
|||
|
|||
public class NodeOutputPortContainer : NodePortContainer |
|||
{ |
|||
public NodeOutputPortContainer(BaseNode node) : base(node) {} |
|||
|
|||
public void PushDatas() |
|||
{ |
|||
ForEach(p => p.PushData()); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 3f706f6f8536b264cb9beb4781f59eda |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using UnityEngine.Experimental.UIElements; |
|||
using UnityEngine.Experimental.UIElements.StyleEnums; |
|||
using UnityEngine; |
|||
using System; |
|||
|
|||
namespace GraphProcessor |
|||
{ |
|||
[System.Serializable] |
|||
public class PinnedElement |
|||
{ |
|||
public Vector2 position = Vector2.zero; |
|||
public bool opened = true; |
|||
public SerializableType editorType; |
|||
|
|||
public PinnedElement(Type editorType) |
|||
{ |
|||
this.editorType = new SerializableType(editorType); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 0429aeae57996a844a00657c8913e21d |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: db326f54ce37a86488063e8a81d25fb2 |
|||
folderAsset: yes |
|||
DefaultImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
部分文件因为文件数量过多而无法显示
撰写
预览
正在加载...
取消
保存
Reference in new issue