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 [Editor(typeof(IUnit))]
10 public class UnitEditor : GraphElementEditor<FlowGraphContext>
11 {
12 public UnitEditor(Metadata metadata) : base(metadata) { }
13
14 protected IUnit unit => (IUnit)element;
15
16 protected new UnitDescription description => (UnitDescription)base.description;
17
18 protected new UnitAnalysis analysis => (UnitAnalysis)base.analysis;
19
20 protected override float GetHeight(float width, GUIContent label)
21 {
22 var height = 0f;
23
24 height += GetHeaderHeight(width);
25
26 height += GetWrappedInspectorHeight(width);
27
28 if (exception != null)
29 {
30 height += GetExceptionHeight(width);
31 }
32
33 height += analysis.warnings.Sum(warning => warning.GetHeight(width));
34
35 if (unit.inputs.Any())
36 {
37 height += GetPortsHeight(width, new GUIContent("Inputs"), unit.inputs.Cast<IUnitPort>());
38 }
39
40 if (unit.outputs.Any())
41 {
42 height += GetPortsHeight(width, new GUIContent("Outputs"), unit.outputs.Cast<IUnitPort>());
43 }
44
45 return height;
46 }
47
48 protected override void OnGUI(Rect position, GUIContent label)
49 {
50 y = 0;
51
52 OnHeaderGUI(position);
53
54 EditorGUI.BeginChangeCheck();
55
56 OnWrappedInspectorGUI(position);
57
58 if (EditorGUI.EndChangeCheck())
59 {
60 unit.Define();
61 }
62
63 if (exception != null)
64 {
65 y--;
66 OnExceptionGUI(position.VerticalSection(ref y, GetExceptionHeight(position.width) + 1));
67 }
68
69 foreach (var warning in analysis.warnings)
70 {
71 y--;
72 warning.OnGUI(position.VerticalSection(ref y, warning.GetHeight(position.width) + 1));
73 }
74
75 if (unit.inputs.Any())
76 {
77 y--;
78 OnPortsGUI(position, new GUIContent("Inputs"), unit.inputs.Cast<IUnitPort>());
79 }
80
81 if (unit.outputs.Any())
82 {
83 y--;
84 OnPortsGUI(position, new GUIContent("Outputs"), unit.outputs.Cast<IUnitPort>());
85 }
86 }
87
88 private float GetPortsInnerWidth(float totalWidth)
89 {
90 return totalWidth - Styles.portsBackground.padding.left - Styles.portsBackground.padding.right;
91 }
92
93 private float GetPortsHeight(float totalWidth, GUIContent label, IEnumerable<IUnitPort> ports)
94 {
95 var innerWidth = GetPortsInnerWidth(totalWidth);
96
97 var height = 0f;
98
99 height += Styles.portsBackground.padding.top;
100 height += Styles.portsLabel.CalcHeight(label, innerWidth);
101
102 foreach (var port in ports)
103 {
104 height += Styles.spaceBetweenPorts;
105 height += GetPortHeight(innerWidth, port);
106 }
107
108 height += Styles.portsBackground.padding.bottom;
109
110 return height;
111 }
112
113 private void OnPortsGUI(Rect position, GUIContent label, IEnumerable<IUnitPort> ports)
114 {
115 var backgroundPosition = new Rect
116 (
117 position.x,
118 y,
119 position.width,
120 GetPortsHeight(position.width, label, ports)
121 );
122
123 if (e.type == EventType.Repaint)
124 {
125 Styles.portsBackground.Draw(backgroundPosition, false, false, false, false);
126 }
127
128 var innerWidth = GetPortsInnerWidth(position.width);
129
130 y += Styles.portsBackground.padding.top;
131 position.x += Styles.portsBackground.padding.left;
132
133 var labelPosition = new Rect
134 (
135 position.x,
136 y,
137 innerWidth,
138 Styles.portsLabel.CalcHeight(label, innerWidth)
139 );
140
141 GUI.Label(labelPosition, label, Styles.portsLabel);
142
143 y += labelPosition.height;
144
145 foreach (var port in ports)
146 {
147 y += Styles.spaceBetweenPorts;
148
149 var portPosition = new Rect
150 (
151 position.x,
152 y,
153 innerWidth,
154 GetPortHeight(innerWidth, port)
155 );
156
157 OnPortGUI(portPosition, port);
158
159 y += portPosition.height;
160 }
161
162 y += Styles.portsBackground.padding.bottom;
163 }
164
165 private GUIContent GetLabelContent(IUnitPort port)
166 {
167 string type;
168
169 if (port is IUnitControlPort)
170 {
171 type = "Flow";
172 }
173 else if (port is IUnitValuePort)
174 {
175 type = ((IUnitValuePort)port).type.DisplayName();
176 }
177 else if (port is IUnitInvalidPort)
178 {
179 type = "Invalid";
180 }
181 else
182 {
183 throw new NotSupportedException();
184 }
185
186 return new GUIContent(string.Format($"<b>{port.Description<UnitPortDescription>().label}</b> <color=#{ColorPalette.unityForegroundDim.ToHexString()}>: {LudiqGUIUtility.EscapeRichText(type)}</color>"));
187 }
188
189 private float GetPortHeight(float paddedWidth, IUnitPort port)
190 {
191 var portDescription = port.Description<UnitPortDescription>();
192
193 var labelWidth = paddedWidth - Styles.portIcon.fixedWidth - Styles.portIcon.margin.right;
194
195 var height = 0f;
196
197 height += Styles.portLabel.CalcHeight(GetLabelContent(port), labelWidth);
198
199 var summary = portDescription.summary;
200
201 if (!StringUtility.IsNullOrWhiteSpace(summary))
202 {
203 height += Styles.portDescription.CalcHeight(new GUIContent(summary), labelWidth);
204 }
205
206 return height;
207 }
208
209 private void OnPortGUI(Rect portPosition, IUnitPort port)
210 {
211 var portDescription = port.Description<UnitPortDescription>();
212
213 var labelWidth = portPosition.width - Styles.portIcon.fixedWidth - Styles.portIcon.margin.right;
214
215 var iconPosition = new Rect
216 (
217 portPosition.x,
218 portPosition.y,
219 Styles.portIcon.fixedWidth,
220 Styles.portIcon.fixedHeight
221 );
222
223 var icon = portDescription.icon?[IconSize.Small];
224
225 if (icon != null)
226 {
227 GUI.DrawTexture(iconPosition, icon);
228 }
229
230 var labelContent = GetLabelContent(port);
231
232 var labelPosition = new Rect
233 (
234 iconPosition.xMax + Styles.portIcon.margin.right,
235 portPosition.y,
236 labelWidth,
237 Styles.portLabel.CalcHeight(labelContent, labelWidth)
238 );
239
240 GUI.Label(labelPosition, labelContent, Styles.portLabel);
241
242 var summary = portDescription.summary;
243
244 if (!StringUtility.IsNullOrWhiteSpace(summary))
245 {
246 var descriptionContent = new GUIContent(summary);
247
248 var descriptionPosition = new Rect
249 (
250 labelPosition.x,
251 labelPosition.yMax,
252 labelWidth,
253 Styles.portDescription.CalcHeight(descriptionContent, labelWidth)
254 );
255
256 GUI.Label(descriptionPosition, descriptionContent, Styles.portDescription);
257 }
258 }
259
260 public new static class Styles
261 {
262 static Styles()
263 {
264 portsBackground = new GUIStyle("IN BigTitle");
265 portsBackground.padding = new RectOffset(10, 5, 7, 10);
266
267 portsLabel = new GUIStyle(EditorStyles.label);
268 portsLabel.fontSize = 13;
269 portsLabel.padding = new RectOffset(0, 0, 0, 3);
270
271 portLabel = new GUIStyle(EditorStyles.label);
272 portLabel.imagePosition = ImagePosition.TextOnly;
273 portLabel.wordWrap = true;
274 portLabel.richText = true;
275
276 portDescription = new GUIStyle(EditorStyles.label);
277 portDescription.imagePosition = ImagePosition.TextOnly;
278 portDescription.wordWrap = true;
279 portDescription.richText = true;
280 portDescription.fontSize = 10;
281 portDescription.normal.textColor = ColorPalette.unityForegroundDim;
282
283 portIcon = new GUIStyle();
284 portIcon.imagePosition = ImagePosition.ImageOnly;
285 portIcon.fixedWidth = portIcon.fixedHeight = IconSize.Small;
286 portIcon.margin.right = 5;
287
288 inspectorBackground = new GUIStyle();
289 inspectorBackground.padding = new RectOffset(10, 10, 10, 10);
290 }
291
292 public static readonly GUIStyle portsBackground;
293
294 public static readonly GUIStyle portsLabel;
295
296 public static readonly GUIStyle portLabel;
297
298 public static readonly GUIStyle portDescription;
299
300 public static readonly GUIStyle portIcon;
301
302 public static readonly float spaceBetweenPorts = 5;
303
304 public static readonly GUIStyle inspectorBackground;
305 }
306 }
307}