UnityGame/Library/PackageCache/com.unity.visualscripting/Editor/VisualScripting.State/States/FlowStateWidget.cs
2024-10-27 10:53:47 +03:00

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);
}
}
}
}