232 lines
6.5 KiB
C#
232 lines
6.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.VisualScripting
|
|
{
|
|
[Widget(typeof(FlowState))]
|
|
public sealed class FlowStateWidget : NesterStateWidget<FlowState>, IDragAndDropHandler
|
|
{
|
|
public FlowStateWidget(StateCanvas canvas, FlowState state) : base(canvas, state)
|
|
{
|
|
state.nest.beforeGraphChange += BeforeGraphChange;
|
|
state.nest.afterGraphChange += AfterGraphChange;
|
|
|
|
if (state.nest.graph != null)
|
|
{
|
|
state.nest.graph.elements.CollectionChanged += CacheEventLinesOnUnityThread;
|
|
}
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
base.Dispose();
|
|
|
|
state.nest.beforeGraphChange -= BeforeGraphChange;
|
|
state.nest.afterGraphChange -= AfterGraphChange;
|
|
}
|
|
|
|
private void BeforeGraphChange()
|
|
{
|
|
if (state.nest.graph != null)
|
|
{
|
|
state.nest.graph.elements.CollectionChanged -= CacheEventLinesOnUnityThread;
|
|
}
|
|
}
|
|
|
|
private void AfterGraphChange()
|
|
{
|
|
CacheEventLinesOnUnityThread();
|
|
|
|
if (state.nest.graph != null)
|
|
{
|
|
state.nest.graph.elements.CollectionChanged += CacheEventLinesOnUnityThread;
|
|
}
|
|
}
|
|
|
|
#region Model
|
|
|
|
private List<EventLine> eventLines { get; } = new List<EventLine>();
|
|
|
|
private void CacheEventLinesOnUnityThread()
|
|
{
|
|
UnityAPI.Async(CacheEventLines);
|
|
}
|
|
|
|
private void CacheEventLines()
|
|
{
|
|
eventLines.Clear();
|
|
|
|
if (state.nest.graph != null)
|
|
{
|
|
eventLines.AddRange(state.nest.graph.units
|
|
.OfType<IEventUnit>()
|
|
.Select(e => e.GetType())
|
|
.Distinct()
|
|
.Select(eventType => new EventLine(eventType))
|
|
.OrderBy(eventLine => eventLine.content.text));
|
|
}
|
|
|
|
Reposition();
|
|
}
|
|
|
|
protected override void CacheItemFirstTime()
|
|
{
|
|
base.CacheItemFirstTime();
|
|
|
|
CacheEventLines();
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Positioning
|
|
|
|
public Dictionary<EventLine, Rect> eventLinesPositions { get; } = new Dictionary<EventLine, Rect>();
|
|
|
|
public override void CachePosition()
|
|
{
|
|
base.CachePosition();
|
|
|
|
eventLinesPositions.Clear();
|
|
|
|
var y = contentInnerPosition.y;
|
|
|
|
foreach (var eventLine in eventLines)
|
|
{
|
|
var eventLinePosition = new Rect
|
|
(
|
|
contentInnerPosition.x,
|
|
y,
|
|
contentInnerPosition.width,
|
|
eventLine.GetHeight(contentInnerPosition.width)
|
|
);
|
|
|
|
eventLinesPositions.Add(eventLine, eventLinePosition);
|
|
|
|
y += eventLinePosition.height;
|
|
}
|
|
}
|
|
|
|
protected override float GetContentHeight(float width)
|
|
{
|
|
var eventLinesHeight = 0f;
|
|
|
|
foreach (var eventLine in eventLines)
|
|
{
|
|
eventLinesHeight += eventLine.GetHeight(width);
|
|
}
|
|
|
|
return eventLinesHeight;
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Drawing
|
|
|
|
protected override bool showContent => eventLines.Count > 0;
|
|
|
|
protected override void DrawContent()
|
|
{
|
|
foreach (var eventLine in eventLines)
|
|
{
|
|
eventLine.Draw(eventLinesPositions[eventLine]);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Drag & Drop
|
|
|
|
public DragAndDropVisualMode dragAndDropVisualMode => DragAndDropVisualMode.Generic;
|
|
|
|
public bool AcceptsDragAndDrop()
|
|
{
|
|
return DragAndDropUtility.Is<ScriptGraphAsset>();
|
|
}
|
|
|
|
public void PerformDragAndDrop()
|
|
{
|
|
UndoUtility.RecordEditedObject("Drag & Drop Macro");
|
|
state.nest.source = GraphSource.Macro;
|
|
state.nest.macro = DragAndDropUtility.Get<ScriptGraphAsset>();
|
|
state.nest.embed = null;
|
|
GUI.changed = true;
|
|
}
|
|
|
|
public void UpdateDragAndDrop() { }
|
|
|
|
public void DrawDragAndDropPreview()
|
|
{
|
|
GraphGUI.DrawDragAndDropPreviewLabel(new Vector2(edgePosition.x, outerPosition.yMax), "Replace with: " + DragAndDropUtility.Get<ScriptGraphAsset>().name, typeof(ScriptGraphAsset).Icon());
|
|
}
|
|
|
|
public void ExitDragAndDrop() { }
|
|
|
|
#endregion
|
|
|
|
|
|
public new static class Styles
|
|
{
|
|
static Styles()
|
|
{
|
|
eventLine = new GUIStyle(EditorStyles.label);
|
|
eventLine.wordWrap = true;
|
|
eventLine.imagePosition = ImagePosition.TextOnly; // The icon is drawn manually
|
|
eventLine.padding = new RectOffset(0, 0, 3, 3);
|
|
}
|
|
|
|
public static readonly GUIStyle eventLine;
|
|
|
|
public static readonly float spaceAroundLineIcon = 5;
|
|
}
|
|
|
|
public class EventLine
|
|
{
|
|
public EventLine(Type eventType)
|
|
{
|
|
content = new GUIContent(BoltFlowNameUtility.UnitTitle(eventType, false, true), eventType.Icon()?[IconSize.Small]);
|
|
}
|
|
|
|
public GUIContent content { get; }
|
|
|
|
public float GetHeight(float width)
|
|
{
|
|
var labelWidth = width - Styles.spaceAroundLineIcon - IconSize.Small - Styles.spaceAroundLineIcon;
|
|
|
|
return Styles.eventLine.CalcHeight(content, labelWidth);
|
|
}
|
|
|
|
public void Draw(Rect position)
|
|
{
|
|
var iconPosition = new Rect
|
|
(
|
|
position.x + Styles.spaceAroundLineIcon,
|
|
position.y + Styles.eventLine.padding.top - 1,
|
|
IconSize.Small,
|
|
IconSize.Small
|
|
);
|
|
|
|
var labelPosition = new Rect
|
|
(
|
|
iconPosition.xMax + Styles.spaceAroundLineIcon,
|
|
position.y,
|
|
position.width - Styles.spaceAroundLineIcon - iconPosition.width - Styles.spaceAroundLineIcon,
|
|
position.height
|
|
);
|
|
|
|
if (content.image != null)
|
|
{
|
|
GUI.DrawTexture(iconPosition, content.image);
|
|
}
|
|
|
|
GUI.Label(labelPosition, content, Styles.eventLine);
|
|
}
|
|
}
|
|
}
|
|
}
|