using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace Unity.VisualScripting { public abstract class UnitConnectionWidget : GraphElementWidget, IUnitConnectionWidget where TConnection : class, IUnitConnection { protected UnitConnectionWidget(FlowCanvas canvas, TConnection connection) : base(canvas, connection) { } #region Model protected TConnection connection => element; protected IUnitConnectionDebugData ConnectionDebugData => GetDebugData(); #endregion #region Lifecycle public override void BeforeFrame() { base.BeforeFrame(); if (showDroplets) { GraphGUI.UpdateDroplets(canvas, droplets, ConnectionDebugData.lastInvokeFrame, ref lastInvokeTime, ref dropTime); } } #endregion #region Positioning public override IEnumerable positionDependencies { get { yield return canvas.Widget(connection.source); yield return canvas.Widget(connection.destination); } } protected override bool snapToGrid => false; public Rect sourceHandlePosition { get; private set; } public Rect destinationHandlePosition { get; private set; } public Vector2 sourceHandleEdgeCenter { get; private set; } public Vector2 destinationHandleEdgeCenter { get; private set; } public Vector2 middlePosition; private Rect _position; private Rect _clippingPosition; public override Rect position { get { return _position; } set { } } public override Rect clippingPosition => _clippingPosition; public override void CachePosition() { base.CachePosition(); sourceHandlePosition = canvas.Widget(connection.source).handlePosition; destinationHandlePosition = canvas.Widget(connection.destination).handlePosition; sourceHandleEdgeCenter = sourceHandlePosition.GetEdgeCenter(Edge.Right); destinationHandleEdgeCenter = destinationHandlePosition.GetEdgeCenter(Edge.Left); middlePosition = (sourceHandlePosition.center + destinationHandlePosition.center) / 2; _position = new Rect ( middlePosition.x, middlePosition.y, 0, 0 ); _clippingPosition = _position.Encompass(sourceHandleEdgeCenter).Encompass(destinationHandleEdgeCenter); } #endregion #region Drawing protected virtual bool colorIfActive => true; public abstract Color color { get; } protected override bool dim { get { var dim = BoltCore.Configuration.dimInactiveNodes && !connection.destination.unit.Analysis(context).isEntered; if (BoltCore.Configuration.dimIncompatibleNodes && canvas.isCreatingConnection) { dim = true; } return dim; } } public override void DrawBackground() { base.DrawBackground(); BeginDim(); DrawConnection(); if (showDroplets) { DrawDroplets(); } EndDim(); } protected virtual void DrawConnection() { var color = this.color; var sourceWidget = canvas.Widget(connection.source); var destinationWidget = canvas.Widget(connection.destination); var highlight = !canvas.isCreatingConnection && (sourceWidget.isMouseOver || destinationWidget.isMouseOver); var willDisconnect = sourceWidget.willDisconnect || destinationWidget.willDisconnect; if (willDisconnect) { color = UnitConnectionStyles.disconnectColor; } else if (highlight) { color = UnitConnectionStyles.highlightColor; } else if (colorIfActive) { if (EditorApplication.isPaused) { if (EditorTimeBinding.frame == ConnectionDebugData.lastInvokeFrame) { color = UnitConnectionStyles.activeColor; } } else { color = Color.Lerp(UnitConnectionStyles.activeColor, color, (EditorTimeBinding.time - ConnectionDebugData.lastInvokeTime) / UnitWidget.Styles.invokeFadeDuration); } } var thickness = 3; GraphGUI.DrawConnection(color, sourceHandleEdgeCenter, destinationHandleEdgeCenter, Edge.Right, Edge.Left, null, Vector2.zero, UnitConnectionStyles.relativeBend, UnitConnectionStyles.minBend, thickness); } #endregion #region Selecting public override bool canSelect => false; #endregion #region Dragging public override bool canDrag => false; #endregion #region Deleting public override bool canDelete => true; #endregion #region Droplets private readonly List droplets = new List(); private float dropTime; private float lastInvokeTime; private const float handleAlignmentMargin = 0.1f; protected virtual bool showDroplets => true; protected abstract Vector2 GetDropletSize(); protected abstract void DrawDroplet(Rect position); protected virtual void DrawDroplets() { foreach (var droplet in droplets) { Vector2 position; if (droplet < handleAlignmentMargin) { var t = droplet / handleAlignmentMargin; position = Vector2.Lerp(sourceHandlePosition.center, sourceHandleEdgeCenter, t); } else if (droplet > 1 - handleAlignmentMargin) { var t = (droplet - (1 - handleAlignmentMargin)) / handleAlignmentMargin; position = Vector2.Lerp(destinationHandleEdgeCenter, destinationHandlePosition.center, t); } else { var t = (droplet - handleAlignmentMargin) / (1 - 2 * handleAlignmentMargin); position = GraphGUI.GetPointOnConnection(t, sourceHandleEdgeCenter, destinationHandleEdgeCenter, Edge.Right, Edge.Left, UnitConnectionStyles.relativeBend, UnitConnectionStyles.minBend); } var size = GetDropletSize(); using (LudiqGUI.color.Override(GUI.color * color)) { DrawDroplet(new Rect(position.x - size.x / 2, position.y - size.y / 2, size.x, size.y)); } } } #endregion } }