AirControl  1.3.0
Open Source, Modular, and Extensible Flight Simulator For Deep Learning Research
ChartEditorHelper.cs
1 /************************************************/
2 /* */
3 /* Copyright (c) 2018 - 2021 monitor1394 */
4 /* https://github.com/monitor1394 */
5 /* */
6 /************************************************/
7 
8 using UnityEngine;
9 using UnityEditor;
10 using System.Collections.Generic;
11 
12 namespace XCharts
13 {
14  public class ChartEditorHelper
15  {
16 #if UNITY_2019_3_OR_NEWER
17  public const float INDENT_WIDTH = 15;
18  public const float BOOL_WIDTH = 15;
19  public const float ARROW_WIDTH = 20;
20  public const float BLOCK_WIDTH = 4;
21  public const float GAP_WIDTH = 2;
22 #else
23  public const float INDENT_WIDTH = 15;
24  public const float BOOL_WIDTH = 15;
25  public const float ARROW_WIDTH = 17.2f;
26  public const float BLOCK_WIDTH = 0;
27  public const float GAP_WIDTH = 0;
28 #endif
29 
30  public class Styles
31  {
32  public static readonly GUIStyle headerStyle = EditorStyles.boldLabel;
33  public static readonly GUIStyle foldoutStyle = new GUIStyle(EditorStyles.foldout)
34  {
35  font = headerStyle.font,
36  fontStyle = headerStyle.fontStyle,
37  };
38  public static readonly GUIContent iconAdd = new GUIContent("+", "Add");
39  public static readonly GUIContent iconRemove = new GUIContent("-", "Remove");
40  public static readonly GUIContent iconUp = new GUIContent("↑", "Up");
41  public static readonly GUIContent iconDown = new GUIContent("↓", "Down");
42  public static readonly GUIStyle invisibleButton = "InvisibleButton";
43  }
44 
45  public static void SecondField(Rect drawRect, SerializedProperty prop)
46  {
47  RectOffset offset = new RectOffset(-(int)EditorGUIUtility.labelWidth, 0, 0, 0);
48  drawRect = offset.Add(drawRect);
49  EditorGUI.PropertyField(drawRect, prop, GUIContent.none);
50  drawRect = offset.Remove(drawRect);
51  }
52 
53  public static void MakeTwoField(ref Rect drawRect, float rectWidth, SerializedProperty arrayProp,
54  string name)
55  {
56  while (arrayProp.arraySize < 2) arrayProp.arraySize++;
57  var prop1 = arrayProp.GetArrayElementAtIndex(0);
58  var prop2 = arrayProp.GetArrayElementAtIndex(1);
59  MakeTwoField(ref drawRect, rectWidth, prop1, prop2, name);
60  }
61 
62  public static void MakeDivideList(ref Rect drawRect, float rectWidth, SerializedProperty arrayProp,
63  string name, int showNum)
64  {
65  while (arrayProp.arraySize < showNum) arrayProp.arraySize++;
66  EditorGUI.LabelField(drawRect, name);
67 #if UNITY_2019_3_OR_NEWER
68  var gap = 2;
69 #else
70  var gap = 0;
71 #endif
72  var startX = drawRect.x + EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH + gap;
73  var dataWidTotal = (rectWidth - (startX + INDENT_WIDTH + 1));
74  EditorGUI.DrawRect(new Rect(startX, drawRect.y, dataWidTotal, drawRect.height), Color.grey);
75  var dataWid = dataWidTotal / showNum;
76  var xWid = dataWid - gap;
77  for (int i = 0; i < 1; i++)
78  {
79  drawRect.x = startX + i * xWid;
80  drawRect.width = dataWid + (EditorGUI.indentLevel - 2) * 40.5f;
81  EditorGUI.PropertyField(drawRect, arrayProp.GetArrayElementAtIndex(i), GUIContent.none);
82  }
83  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
84  }
85 
86  public static void MakeTwoField(ref Rect drawRect, float rectWidth, SerializedProperty prop1,
87  SerializedProperty prop2, string name)
88  {
89  EditorGUI.LabelField(drawRect, name);
90  var startX = drawRect.x + EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH + GAP_WIDTH;
91  var diff = 14 + EditorGUI.indentLevel * 14;
92  var offset = diff - INDENT_WIDTH;
93  var tempWidth = (rectWidth - startX + diff) / 2;
94  var centerXRect = new Rect(startX, drawRect.y, tempWidth, drawRect.height);
95  var centerYRect = new Rect(centerXRect.x + tempWidth - offset, drawRect.y, tempWidth, drawRect.height);
96  EditorGUI.PropertyField(centerXRect, prop1, GUIContent.none);
97  EditorGUI.PropertyField(centerYRect, prop2, GUIContent.none);
98  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
99  }
100 
101  public static void MakeVector2(ref Rect drawRect, float rectWidth, SerializedProperty prop, string name)
102  {
103  EditorGUI.LabelField(drawRect, name);
104  var startX = drawRect.x + EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH + GAP_WIDTH;
105  var diff = 14 + EditorGUI.indentLevel * 14;
106  var offset = diff - INDENT_WIDTH;
107  var tempWidth = (rectWidth - startX + diff) / 2;
108  var centerXRect = new Rect(startX, drawRect.y, tempWidth, drawRect.height);
109  var centerYRect = new Rect(centerXRect.x + tempWidth - offset, drawRect.y, tempWidth, drawRect.height);
110  var x = EditorGUI.FloatField(centerXRect, prop.vector3Value.x);
111  var y = EditorGUI.FloatField(centerYRect, prop.vector3Value.y);
112  prop.vector3Value = new Vector3(x, y);
113  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
114  }
115 
116  public static void MakeJsonData(ref Rect drawRect, ref bool showTextArea, ref string inputString,
117  SerializedProperty prop, float currentWidth, float diff = 0)
118  {
119  SerializedProperty stringDataProp = prop.FindPropertyRelative("m_JsonData");
120  SerializedProperty needParseProp = prop.FindPropertyRelative("m_DataFromJson");
121  float defalutX = drawRect.x;
122  drawRect.x = EditorGUIUtility.labelWidth + ARROW_WIDTH + diff;
123  drawRect.width = currentWidth - EditorGUIUtility.labelWidth - GAP_WIDTH - diff;
124  if (GUI.Button(drawRect, new GUIContent("Parse JsonData", "Parse data from input json")))
125  {
126  showTextArea = !showTextArea;
127  bool needParse = !showTextArea;
128  if (needParse)
129  {
130  stringDataProp.stringValue = inputString;
131  needParseProp.boolValue = true;
132  }
133  }
134  drawRect.x = defalutX;
135  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
136  if (showTextArea)
137  {
138  drawRect.width = currentWidth;
139  drawRect.height = EditorGUIUtility.singleLineHeight * 4;
140  inputString = EditorGUI.TextArea(drawRect, inputString);
141  drawRect.y += EditorGUIUtility.singleLineHeight * 4 + EditorGUIUtility.standardVerticalSpacing;
142  drawRect.height = EditorGUIUtility.singleLineHeight;
143  }
144  }
145 
146  public static bool MakeFoldout(ref Rect drawRect, ref bool moduleToggle, string content,
147  SerializedProperty prop = null, bool bold = false)
148  {
149  float defaultWidth = drawRect.width;
150  float defaultX = drawRect.x;
151  var style = bold ? Styles.foldoutStyle : EditorStyles.foldout;
152  drawRect.width = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH;
153  moduleToggle = EditorGUI.Foldout(drawRect, moduleToggle, content, true, style);
154  MakeBool(drawRect, prop);
155  drawRect.width = defaultWidth;
156  drawRect.x = defaultX;
157  return moduleToggle;
158  }
159 
160  public static bool MakeFoldout(ref Rect drawRect, Dictionary<string, float> heights,
161  Dictionary<string, bool> moduleToggle, string key, string content, SerializedProperty prop, bool bold = false)
162  {
163  float defaultWidth = drawRect.width;
164  float defaultX = drawRect.x;
165  var style = bold ? Styles.foldoutStyle : EditorStyles.foldout;
166  drawRect.width = EditorGUIUtility.labelWidth;
167  moduleToggle[key] = EditorGUI.Foldout(drawRect, moduleToggle[key], content, true, style);
168  if (prop != null)
169  {
170  if (prop.propertyType == SerializedPropertyType.Boolean)
171  {
172  MakeBool(drawRect, prop);
173  }
174  else
175  {
176  drawRect.x = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH + ARROW_WIDTH;
177  drawRect.width = defaultWidth - drawRect.x + ARROW_WIDTH - 2;
178  if (XChartsSettings.editorBlockEnable)
179  {
180  drawRect.x += BLOCK_WIDTH;
181  }
182 
183  EditorGUI.PropertyField(drawRect, prop, GUIContent.none);
184  }
185  }
186 
187  drawRect.width = defaultWidth;
188  drawRect.x = defaultX;
189  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
190  heights[key] += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
191  return moduleToggle[key];
192  }
193 
194  public static void MakeBool(Rect drawRect, SerializedProperty boolProp, int index = 0, string name = null)
195  {
196  float defaultWidth = drawRect.width;
197  float defaultX = drawRect.x;
198  float boolWidth = index * (BOOL_WIDTH + GAP_WIDTH);
199  drawRect.x = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH + ARROW_WIDTH + boolWidth;
200  if (XChartsSettings.editorBlockEnable)
201  {
202  drawRect.x += BLOCK_WIDTH;
203  }
204  drawRect.width = (EditorGUI.indentLevel + 1) * BOOL_WIDTH + index * 110;
205  if (boolProp != null)
206  {
207  EditorGUI.PropertyField(drawRect, boolProp, GUIContent.none);
208  if (!string.IsNullOrEmpty(name))
209  {
210  drawRect.x += BOOL_WIDTH;
211  drawRect.width = 200;
212  EditorGUI.LabelField(drawRect, name);
213  }
214  }
215  drawRect.width = defaultWidth;
216  drawRect.x = defaultX;
217  }
218 
219  public static bool MakeFoldout(ref Rect drawRect, ref float height, ref Dictionary<string, bool> moduleToggle,
220  SerializedProperty prop, string moduleName, string showPropName, bool bold = false)
221  {
222  var relativeProp = prop.FindPropertyRelative(showPropName);
223  var flag = MakeFoldout(ref drawRect, ref moduleToggle, prop, moduleName, relativeProp, bold);
224  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
225  height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
226  return flag;
227  }
228 
229  public static bool MakeFoldout(ref Rect drawRect, ref Dictionary<string, bool> moduleToggle, SerializedProperty prop,
230  string moduleName, SerializedProperty showProp = null, bool bold = false)
231  {
232  var key = prop.propertyPath;
233  if (!moduleToggle.ContainsKey(key))
234  {
235  moduleToggle.Add(key, false);
236  }
237  var toggle = moduleToggle[key];
238 
239  float defaultWidth = drawRect.width;
240  float defaultX = drawRect.x;
241 #if UNITY_2019_3_OR_NEWER
242  drawRect.width = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH;
243 #else
244  drawRect.width = EditorGUIUtility.labelWidth;
245 #endif
246  var displayName = string.IsNullOrEmpty(moduleName) ? prop.displayName : moduleName;
247  var foldoutStyle = bold ? Styles.foldoutStyle : EditorStyles.foldout;
248  toggle = EditorGUI.Foldout(drawRect, toggle, displayName, true, foldoutStyle);
249 
250  if (moduleToggle[key] != toggle)
251  {
252  moduleToggle[key] = toggle;
253  }
254  if (showProp != null)
255  {
256  drawRect.x = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * INDENT_WIDTH + ARROW_WIDTH;
257  if (showProp.propertyType == SerializedPropertyType.Boolean)
258  {
259  drawRect.width = (EditorGUI.indentLevel + 1) * BOOL_WIDTH;
260  }
261  else
262  {
263  drawRect.width = defaultWidth - drawRect.x + ARROW_WIDTH - GAP_WIDTH;
264  }
265  if (XChartsSettings.editorBlockEnable)
266  {
267  drawRect.x += BLOCK_WIDTH;
268  }
269  EditorGUI.PropertyField(drawRect, showProp, GUIContent.none);
270  }
271  drawRect.width = defaultWidth;
272  drawRect.x = defaultX;
273  return toggle;
274  }
275 
276  public static bool MakeListWithFoldout(ref Rect drawRect, SerializedProperty listProp, bool foldout,
277  bool showOrder = false, bool showSize = true)
278  {
279  var height = 0f;
280  return MakeListWithFoldout(ref drawRect, ref height, listProp, foldout, showOrder, showSize);
281  }
282 
283  public static bool MakeListWithFoldout(ref Rect drawRect, ref float height, SerializedProperty listProp,
284  bool foldout, bool showOrder = false, bool showSize = true)
285  {
286  var rawWidth = drawRect.width;
287  drawRect.width = EditorGUIUtility.labelWidth + 10;
288  bool flag = EditorGUI.Foldout(drawRect, foldout, listProp.displayName, true);
289  height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
290  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
291  drawRect.width = rawWidth;
292  if (flag)
293  {
294  MakeList(ref drawRect, ref height, listProp, showOrder, showSize);
295  }
296  return flag;
297  }
298 
299  public static void MakeList(ref Rect drawRect, SerializedProperty listProp, bool showOrder = false,
300  bool showSize = true)
301  {
302  var height = 0f;
303  MakeList(ref drawRect, ref height, listProp, showOrder, showSize);
304  }
305 
306  public static void MakeList(ref Rect drawRect, ref float height, SerializedProperty listProp,
307  bool showOrder = false, bool showSize = true)
308  {
309  EditorGUI.indentLevel++;
310  var listSize = listProp.arraySize;
311  var iconWidth = 14;
312  var iconGap = 3f;
313  if (showSize)
314  {
315  if (showOrder)
316  {
317  var temp = INDENT_WIDTH + GAP_WIDTH + iconGap;
318  var elementRect = new Rect(drawRect.x, drawRect.y, drawRect.width - iconWidth + 2, drawRect.height);
319  var iconRect = new Rect(drawRect.width - iconWidth + temp, drawRect.y, iconWidth, drawRect.height);
320  if (XChartsSettings.editorBlockEnable)
321  {
322  iconRect.x += BLOCK_WIDTH;
323  }
324  var oldColor = GUI.contentColor;
325  GUI.contentColor = Color.black;
326  if (GUI.Button(iconRect, Styles.iconAdd, Styles.invisibleButton))
327  {
328  if (listProp.displayName.Equals("Series"))
329  {
330  AddSerieEditor.chart = listProp.serializedObject.targetObject as BaseChart;
331  AddSerieEditor.ShowWindow();
332  }
333  else
334  {
335  listProp.arraySize++;
336  }
337  }
338  GUI.contentColor = oldColor;
339  listSize = listProp.arraySize;
340  listSize = EditorGUI.IntField(elementRect, "Size", listSize);
341  }
342  else
343  {
344  listSize = EditorGUI.IntField(drawRect, "Size", listSize);
345  }
346  if (listSize < 0) listSize = 0;
347  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
348  height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
349 
350  if (listSize != listProp.arraySize)
351  {
352  while (listSize > listProp.arraySize) listProp.arraySize++;
353  while (listSize < listProp.arraySize) listProp.arraySize--;
354  }
355  }
356  if (listSize > 30 && !XChartsSettings.editorShowAllListData)
357  {
358  SerializedProperty element;
359  int num = listSize > 10 ? 10 : listSize;
360  for (int i = 0; i < num; i++)
361  {
362  element = listProp.GetArrayElementAtIndex(i);
363  EditorGUI.PropertyField(drawRect, element, new GUIContent("Element " + i));
364  drawRect.y += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
365  height += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
366  }
367  if (num >= 10)
368  {
369  EditorGUI.LabelField(drawRect, "...");
370  drawRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
371  height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
372  element = listProp.GetArrayElementAtIndex(listSize - 1);
373  EditorGUI.PropertyField(drawRect, element, new GUIContent("Element " + (listSize - 1)));
374  drawRect.y += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
375  height += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
376  }
377  }
378  else
379  {
380  for (int i = 0; i < listProp.arraySize; i++)
381  {
382  SerializedProperty element = listProp.GetArrayElementAtIndex(i);
383  if (showOrder)
384  {
385  var temp = INDENT_WIDTH + GAP_WIDTH + iconGap;
386  var isSerie = "Serie".Equals(element.type);
387  var elementRect = isSerie
388  ? new Rect(drawRect.x, drawRect.y, drawRect.width + INDENT_WIDTH - 2 * iconGap, drawRect.height)
389  : new Rect(drawRect.x, drawRect.y, drawRect.width - 3 * iconWidth, drawRect.height);
390  EditorGUI.PropertyField(elementRect, element, new GUIContent("Element " + i));
391  var iconRect = new Rect(drawRect.width - 3 * iconWidth + temp, drawRect.y, iconWidth, drawRect.height);
392  if (XChartsSettings.editorBlockEnable)
393  {
394  iconRect.x += BLOCK_WIDTH;
395  }
396  var oldColor = GUI.contentColor;
397  GUI.contentColor = Color.black;
398  if (GUI.Button(iconRect, Styles.iconUp, Styles.invisibleButton))
399  {
400  if (i > 0) listProp.MoveArrayElement(i, i - 1);
401  }
402  iconRect = new Rect(drawRect.width - 2 * iconWidth + temp, drawRect.y, iconWidth, drawRect.height);
403  if (XChartsSettings.editorBlockEnable)
404  {
405  iconRect.x += BLOCK_WIDTH;
406  }
407  if (GUI.Button(iconRect, Styles.iconDown, Styles.invisibleButton))
408  {
409  if (i < listProp.arraySize - 1) listProp.MoveArrayElement(i, i + 1);
410  }
411  iconRect = new Rect(drawRect.width - iconWidth + temp, drawRect.y, iconWidth, drawRect.height);
412  if (XChartsSettings.editorBlockEnable)
413  {
414  iconRect.x += BLOCK_WIDTH;
415  }
416  if (GUI.Button(iconRect, Styles.iconRemove, Styles.invisibleButton))
417  {
418  if (i < listProp.arraySize && i >= 0) listProp.DeleteArrayElementAtIndex(i);
419  }
420  else
421  {
422  drawRect.y += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
423  height += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
424  }
425  GUI.contentColor = oldColor;
426  }
427  else
428  {
429  EditorGUI.PropertyField(drawRect, element, new GUIContent("Element " + i));
430  drawRect.y += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
431  height += EditorGUI.GetPropertyHeight(element) + EditorGUIUtility.standardVerticalSpacing;
432  }
433  }
434  }
435  EditorGUI.indentLevel--;
436  }
437 
438  public static bool PropertyField(ref Rect drawRect, Dictionary<string, float> heights, string key,
439  SerializedProperty prop)
440  {
441  if (prop == null) return false;
442  EditorGUI.PropertyField(drawRect, prop, true);
443  var hig = EditorGUI.GetPropertyHeight(prop);
444  drawRect.y += hig;
445  heights[key] += hig;
446  return true;
447  }
448 
449  public static bool PropertyFieldWithMinValue(ref Rect drawRect, Dictionary<string, float> heights, string key,
450  SerializedProperty prop, float minValue)
451  {
452  if (prop == null) return false;
453  EditorGUI.PropertyField(drawRect, prop, true);
454  if (prop.propertyType == SerializedPropertyType.Float && prop.floatValue < minValue)
455  prop.floatValue = minValue;
456  if (prop.propertyType == SerializedPropertyType.Integer && prop.intValue < minValue)
457  prop.intValue = (int)minValue;
458  var hig = EditorGUI.GetPropertyHeight(prop);
459  drawRect.y += hig;
460  heights[key] += hig;
461  return true;
462  }
463 
464  public static bool PropertyFieldWithMaxValue(ref Rect drawRect, Dictionary<string, float> heights, string key,
465  SerializedProperty prop, float maxValue)
466  {
467  if (prop == null) return false;
468  EditorGUI.PropertyField(drawRect, prop, true);
469  if (prop.propertyType == SerializedPropertyType.Float && prop.floatValue > maxValue)
470  prop.floatValue = maxValue;
471  if (prop.propertyType == SerializedPropertyType.Integer && prop.intValue > maxValue)
472  prop.intValue = (int)maxValue;
473  var hig = EditorGUI.GetPropertyHeight(prop);
474  drawRect.y += hig;
475  heights[key] += hig;
476  return true;
477  }
478 
479  public static bool PropertyField(ref Rect drawRect, Dictionary<string, float> heights, string key,
480  SerializedProperty parentProp, string relativeName)
481  {
482  return PropertyField(ref drawRect, heights, key, parentProp.FindPropertyRelative(relativeName));
483  }
484  public static bool PropertyFieldWithMinValue(ref Rect drawRect, Dictionary<string, float> heights, string key,
485  SerializedProperty parentProp, string relativeName, float minValue)
486  {
487  var relativeProp = parentProp.FindPropertyRelative(relativeName);
488  return PropertyFieldWithMinValue(ref drawRect, heights, key, relativeProp, minValue);
489  }
490  public static bool PropertyFieldWithMaxValue(ref Rect drawRect, Dictionary<string, float> heights, string key,
491  SerializedProperty parentProp, string relativeName, float maxValue)
492  {
493  var relativeProp = parentProp.FindPropertyRelative(relativeName);
494  return PropertyFieldWithMaxValue(ref drawRect, heights, key, relativeProp, maxValue);
495  }
496  }
497 }
XCharts.ChartEditorHelper
Definition: ChartEditorHelper.cs:14
XCharts.ChartEditorHelper.Styles
Definition: ChartEditorHelper.cs:30
XCharts
Definition: RewardChart.cs:14
XCharts.SerieSymbolType.Rect
@ Rect
正方形。可通过设置itemStyle的cornerRadius变成圆角矩形。