您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

285 行
8.9 KiB

using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Experimental.Graph
{
public delegate void EdgeRenderMethod(Canvas2D parent, IConnect source, IConnect target, Vector3 from, Vector3 to);
internal class EdgeConnector<T> : IManipulate where T : IConnect
{
private static readonly Color s_EdgeColor = new Color(1.0f, 1.0f, 1.0f, 0.8f);
private static readonly Color s_ActiveEdgeColor = new Color(0.2f, 0.4f, 1.0f, 0.8f);
private Vector2 m_Start = Vector2.zero;
private Vector2 m_End = Vector2.zero;
private Color m_Color = s_EdgeColor;
private IConnect m_SnappedTarget;
private IConnect m_SnappedSource;
private EdgeRenderMethod m_DrawMethod = null;
private List<IConnect> m_CompatibleAnchors = new List<IConnect>();
public EdgeConnector(EdgeRenderMethod customDrawMethod)
{
m_DrawMethod = customDrawMethod;
}
public EdgeConnector()
{
m_DrawMethod = null;
}
public bool GetCaps(ManipulatorCapability cap)
{
return false;
}
public void AttachTo(CanvasElement element)
{
element.MouseUp += EndDrag;
element.MouseDown += StartDrag;
element.MouseDrag += MouseDrag;
}
private bool StartDrag(CanvasElement element, Event e, Canvas2D canvas)
{
if (e.type == EventType.Used)
{
return false;
}
if (e.button != 0)
{
return false;
}
element.OnWidget += DrawEdge;
if (element.collapsed)
return false;
canvas.StartCapture(this, element);
m_Start = m_End = element.canvasBoundingRect.center;
e.Use();
IConnect cnx = element as IConnect;
if (cnx != null)
{
cnx.Highlight(true);
}
EndSnap();
// find compatible anchors
m_CompatibleAnchors.Clear();
Rect screenRect = new Rect
{
min = canvas.MouseToCanvas(new Vector2(0.0f, 0.0f)),
max = canvas.MouseToCanvas(new Vector2(Screen.width, Screen.height))
};
CanvasElement[] visibleAnchors = canvas.Pick<T>(screenRect);
NodeAdapter nodeAdapter = new NodeAdapter();
foreach (CanvasElement anchor in visibleAnchors)
{
IConnect toCnx = anchor as IConnect;
if (toCnx == null)
continue;
if (cnx.GetOrientation() != toCnx.GetOrientation())
continue;
bool isBidirectional = ((cnx.GetDirection() == Direction.Bidirectional) ||
(toCnx.GetDirection() == Direction.Bidirectional));
if (cnx.GetDirection() != toCnx.GetDirection() || isBidirectional)
{
if (nodeAdapter.GetAdapter(cnx.Source(), toCnx.Source()) != null)
{
m_CompatibleAnchors.Add(toCnx);
}
}
}
canvas.OnOverlay += HighlightCompatibleAnchors;
return true;
}
private bool EndDrag(CanvasElement element, Event e, Canvas2D canvas)
{
if (e.type == EventType.Used)
return false;
if (!canvas.IsCaptured(this))
{
return false;
}
element.OnWidget -= DrawEdge;
canvas.EndCapture();
IConnect cnx = element as IConnect;
if (cnx != null)
{
cnx.Highlight(false);
}
if (m_SnappedSource == null && m_SnappedTarget == null)
{
cnx.OnConnect(null);
}
else if (m_SnappedSource != null && m_SnappedTarget != null)
{
NodeAdapter nodeAdapter = new NodeAdapter();
if (nodeAdapter.CanAdapt(m_SnappedSource.Source(), m_SnappedTarget.Source()))
{
nodeAdapter.Connect(m_SnappedSource.Source(), m_SnappedTarget.Source());
cnx.OnConnect(m_SnappedTarget);
}
}
EndSnap();
e.Use();
canvas.OnOverlay -= HighlightCompatibleAnchors;
return true;
}
private bool MouseDrag(CanvasElement element, Event e, Canvas2D canvas)
{
if (e.type == EventType.Used)
{
return false;
}
if (!canvas.IsCaptured(this))
{
return false;
}
m_End = canvas.MouseToCanvas(e.mousePosition);
e.Use();
m_Color = s_EdgeColor;
IConnect thisCnx = element as IConnect;
// find target anchor under us
CanvasElement elementUnderMouse = canvas.PickSingle<T>(e.mousePosition);
if (elementUnderMouse != null)
{
IConnect cnx = elementUnderMouse as IConnect;
if (cnx == null)
{
Debug.LogError("PickSingle returned an incompatible element: does not support IConnect interface");
return true;
}
if (m_CompatibleAnchors.Exists(ic => ic == cnx))
{
StartSnap(thisCnx, cnx);
m_Color = s_ActiveEdgeColor;
}
}
else
{
EndSnap();
}
return true;
}
private void StartSnap(IConnect from, IConnect to)
{
EndSnap();
m_SnappedTarget = to;
m_SnappedSource = from;
m_SnappedTarget.Highlight(true);
}
private void EndSnap()
{
if (m_SnappedTarget != null)
{
m_SnappedTarget.Highlight(false);
m_SnappedTarget = null;
}
}
private bool DrawEdge(CanvasElement element, Event e, Canvas2D canvas)
{
if (!canvas.IsCaptured(this))
{
return false;
}
if (m_DrawMethod != null)
{
m_DrawMethod(canvas, m_SnappedSource, m_SnappedTarget, m_Start, m_End);
return true;
}
IConnect thisCnx = element as IConnect;
Vector3[] points, tangents;
IConnect cnx = element as IConnect;
GetTangents(thisCnx.GetDirection(), cnx.GetOrientation(), m_Start, m_End, out points, out tangents);
Handles.DrawBezier(points[0], points[1], tangents[0], tangents[1], m_Color, null, 5f);
// little widget on the middle of the edge
Vector3[] allPoints = Handles.MakeBezierPoints(points[0], points[1], tangents[0], tangents[1], 20);
Color oldColor = Handles.color;
Handles.color = m_Color;
Handles.DrawSolidDisc(allPoints[10], new Vector3(0.0f, 0.0f, -1.0f), 6f);
Handles.color = oldColor;
return true;
}
private bool HighlightCompatibleAnchors(CanvasElement element, Event e, Canvas2D canvas)
{
foreach (IConnect visible in m_CompatibleAnchors)
{
visible.RenderOverlay(canvas);
}
return false;
}
public static void GetTangents(Direction direction, Orientation orientation, Vector2 start, Vector2 end, out Vector3[] points, out Vector3[] tangents)
{
if (direction == Direction.Output)
{
Vector2 t = end;
end = start;
start = t;
}
bool invert = false;
if (end.x < start.x)
{
Vector3 t = start;
start = end;
end = t;
invert = true;
}
points = new Vector3[] {start, end};
tangents = new Vector3[2];
const float minTangent = 30;
float weight = .5f;
float weight2 = 1 - weight;
float y = 0;
float cleverness = Mathf.Clamp01(((start - end).magnitude - 10) / 50);
if (orientation == Orientation.Horizontal)
{
tangents[0] = start + new Vector2((end.x - start.x) * weight + minTangent, y) * cleverness;
tangents[1] = end + new Vector2((end.x - start.x) * -weight2 - minTangent, -y) * cleverness;
} else
{
float inverse = (invert) ? 1.0f : -1.0f;
tangents[0] = start + new Vector2(y, inverse* ((end.x - start.x) * weight + minTangent)) * cleverness;
tangents[1] = end + new Vector2(-y, inverse * ((end.x - start.x) * -weight2 - minTangent)) * cleverness;
}
}
};
}