A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEditor; 5using UnityEngine; 6 7namespace Unity.VisualScripting 8{ 9 [Widget(typeof(FlowState))] 10 public sealed class FlowStateWidget : NesterStateWidget<FlowState>, IDragAndDropHandler 11 { 12 public FlowStateWidget(StateCanvas canvas, FlowState state) : base(canvas, state) 13 { 14 state.nest.beforeGraphChange += BeforeGraphChange; 15 state.nest.afterGraphChange += AfterGraphChange; 16 17 if (state.nest.graph != null) 18 { 19 state.nest.graph.elements.CollectionChanged += CacheEventLinesOnUnityThread; 20 } 21 } 22 23 public override void Dispose() 24 { 25 base.Dispose(); 26 27 state.nest.beforeGraphChange -= BeforeGraphChange; 28 state.nest.afterGraphChange -= AfterGraphChange; 29 } 30 31 private void BeforeGraphChange() 32 { 33 if (state.nest.graph != null) 34 { 35 state.nest.graph.elements.CollectionChanged -= CacheEventLinesOnUnityThread; 36 } 37 } 38 39 private void AfterGraphChange() 40 { 41 CacheEventLinesOnUnityThread(); 42 43 if (state.nest.graph != null) 44 { 45 state.nest.graph.elements.CollectionChanged += CacheEventLinesOnUnityThread; 46 } 47 } 48 49 #region Model 50 51 private List<EventLine> eventLines { get; } = new List<EventLine>(); 52 53 private void CacheEventLinesOnUnityThread() 54 { 55 UnityAPI.Async(CacheEventLines); 56 } 57 58 private void CacheEventLines() 59 { 60 eventLines.Clear(); 61 62 if (state.nest.graph != null) 63 { 64 eventLines.AddRange(state.nest.graph.units 65 .OfType<IEventUnit>() 66 .Select(e => e.GetType()) 67 .Distinct() 68 .Select(eventType => new EventLine(eventType)) 69 .OrderBy(eventLine => eventLine.content.text)); 70 } 71 72 Reposition(); 73 } 74 75 protected override void CacheItemFirstTime() 76 { 77 base.CacheItemFirstTime(); 78 79 CacheEventLines(); 80 } 81 82 #endregion 83 84 85 #region Positioning 86 87 public Dictionary<EventLine, Rect> eventLinesPositions { get; } = new Dictionary<EventLine, Rect>(); 88 89 public override void CachePosition() 90 { 91 base.CachePosition(); 92 93 eventLinesPositions.Clear(); 94 95 var y = contentInnerPosition.y; 96 97 foreach (var eventLine in eventLines) 98 { 99 var eventLinePosition = new Rect 100 ( 101 contentInnerPosition.x, 102 y, 103 contentInnerPosition.width, 104 eventLine.GetHeight(contentInnerPosition.width) 105 ); 106 107 eventLinesPositions.Add(eventLine, eventLinePosition); 108 109 y += eventLinePosition.height; 110 } 111 } 112 113 protected override float GetContentHeight(float width) 114 { 115 var eventLinesHeight = 0f; 116 117 foreach (var eventLine in eventLines) 118 { 119 eventLinesHeight += eventLine.GetHeight(width); 120 } 121 122 return eventLinesHeight; 123 } 124 125 #endregion 126 127 128 #region Drawing 129 130 protected override bool showContent => eventLines.Count > 0; 131 132 protected override void DrawContent() 133 { 134 foreach (var eventLine in eventLines) 135 { 136 eventLine.Draw(eventLinesPositions[eventLine]); 137 } 138 } 139 140 #endregion 141 142 143 #region Drag & Drop 144 145 public DragAndDropVisualMode dragAndDropVisualMode => DragAndDropVisualMode.Generic; 146 147 public bool AcceptsDragAndDrop() 148 { 149 return DragAndDropUtility.Is<ScriptGraphAsset>(); 150 } 151 152 public void PerformDragAndDrop() 153 { 154 UndoUtility.RecordEditedObject("Drag & Drop Macro"); 155 state.nest.source = GraphSource.Macro; 156 state.nest.macro = DragAndDropUtility.Get<ScriptGraphAsset>(); 157 state.nest.embed = null; 158 GUI.changed = true; 159 } 160 161 public void UpdateDragAndDrop() { } 162 163 public void DrawDragAndDropPreview() 164 { 165 GraphGUI.DrawDragAndDropPreviewLabel(new Vector2(edgePosition.x, outerPosition.yMax), "Replace with: " + DragAndDropUtility.Get<ScriptGraphAsset>().name, typeof(ScriptGraphAsset).Icon()); 166 } 167 168 public void ExitDragAndDrop() { } 169 170 #endregion 171 172 173 public new static class Styles 174 { 175 static Styles() 176 { 177 eventLine = new GUIStyle(EditorStyles.label); 178 eventLine.wordWrap = true; 179 eventLine.imagePosition = ImagePosition.TextOnly; // The icon is drawn manually 180 eventLine.padding = new RectOffset(0, 0, 3, 3); 181 } 182 183 public static readonly GUIStyle eventLine; 184 185 public static readonly float spaceAroundLineIcon = 5; 186 } 187 188 public class EventLine 189 { 190 public EventLine(Type eventType) 191 { 192 content = new GUIContent(BoltFlowNameUtility.UnitTitle(eventType, false, true), eventType.Icon()?[IconSize.Small]); 193 } 194 195 public GUIContent content { get; } 196 197 public float GetHeight(float width) 198 { 199 var labelWidth = width - Styles.spaceAroundLineIcon - IconSize.Small - Styles.spaceAroundLineIcon; 200 201 return Styles.eventLine.CalcHeight(content, labelWidth); 202 } 203 204 public void Draw(Rect position) 205 { 206 var iconPosition = new Rect 207 ( 208 position.x + Styles.spaceAroundLineIcon, 209 position.y + Styles.eventLine.padding.top - 1, 210 IconSize.Small, 211 IconSize.Small 212 ); 213 214 var labelPosition = new Rect 215 ( 216 iconPosition.xMax + Styles.spaceAroundLineIcon, 217 position.y, 218 position.width - Styles.spaceAroundLineIcon - iconPosition.width - Styles.spaceAroundLineIcon, 219 position.height 220 ); 221 222 if (content.image != null) 223 { 224 GUI.DrawTexture(iconPosition, content.image); 225 } 226 227 GUI.Label(labelPosition, content, Styles.eventLine); 228 } 229 } 230 } 231}