DragonECS-Unity/src/Internal/Editor/EcsGUI.cs

1487 lines
64 KiB
C#
Raw Normal View History

2024-03-03 19:59:39 +08:00
#if UNITY_EDITOR
using DCFApixels.DragonECS.Unity.Internal;
using System;
using System.Collections.Generic;
2024-11-08 15:21:13 +08:00
//using System.Drawing;
2024-03-03 19:59:39 +08:00
using System.Reflection;
2024-11-08 15:21:13 +08:00
using Unity.Collections.LowLevel.Unsafe;
2024-03-03 19:59:39 +08:00
using UnityEditor;
using UnityEditor.IMGUI.Controls;
2024-03-03 19:59:39 +08:00
using UnityEngine;
2024-11-08 15:21:13 +08:00
using Color = UnityEngine.Color;
2024-05-16 19:59:57 +08:00
using UnityComponent = UnityEngine.Component;
2024-06-15 16:53:28 +08:00
using UnityObject = UnityEngine.Object;
2024-03-03 19:59:39 +08:00
namespace DCFApixels.DragonECS.Unity.Editors
{
2024-03-04 07:38:38 +08:00
internal static class EcsGUI
2024-03-03 19:59:39 +08:00
{
2024-05-13 19:20:07 +08:00
#region Scores
private static int _changedCounter = 0;
private static bool _changed = false;
private static bool _delayedChanged = false;
public static int ChangedCounter => _changedCounter;
public static bool Changed
{
get
{
_changed = _changed || GUI.changed;
GUI.changed = _changed;
return _changed;
}
set
{
_changed = Changed || value;
GUI.changed = _changed;
}
}
public static bool DelayedChanged
{
get
{
return _delayedChanged;
}
set
{
_delayedChanged = DelayedChanged || value;
Changed = _delayedChanged;
}
}
public readonly struct CheckChangedScope : IDisposable
{
private readonly bool _value;
public CheckChangedScope(bool value)
{
_value = value;
_changedCounter++;
_changed = false;
}
public static CheckChangedScope New() { return new CheckChangedScope(Changed); }
public void Dispose()
{
Changed = Changed || _value;
_changedCounter--;
//if(_changedCounter <= 0 && Event.current.type == EventType.Repaint)
if (_changedCounter <= 0)
{
_changedCounter = 0;
_changed = _delayedChanged;
_delayedChanged = false;
}
}
}
public readonly struct CheckChangedScopeWithAutoApply : IDisposable
{
private readonly CheckChangedScope _scope;
private readonly SerializedObject _serializedObject;
public CheckChangedScopeWithAutoApply(SerializedObject serializedObject)
{
_scope = CheckChangedScope.New();
_serializedObject = serializedObject;
}
public void Dispose()
{
if (Changed)
{
_serializedObject.ApplyModifiedProperties();
}
_scope.Dispose();
}
}
public struct ScrollViewScope : IDisposable
{
public ScrollViewScope(Rect position, ref Vector2 pos, Rect viewRect) { pos = GUI.BeginScrollView(position, pos, viewRect); }
public void Dispose() { GUI.EndScrollView(); }
}
public readonly struct LabelWidthScope : IDisposable
2024-05-13 19:20:07 +08:00
{
private readonly float _value;
public LabelWidthScope(float value)
2024-05-13 19:20:07 +08:00
{
_value = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = value;
}
2024-06-25 23:20:40 +08:00
public void Dispose() { EditorGUIUtility.labelWidth = _value; }
2024-05-13 19:20:07 +08:00
}
2024-03-09 09:42:04 +08:00
public struct ColorScope : IDisposable
{
2024-05-13 19:20:07 +08:00
private readonly Color _value;
2024-05-16 19:03:03 +08:00
public ColorScope(float r, float g, float b, float a = 1f) : this(new Color(r, g, b, a)) { }
2024-05-13 19:20:07 +08:00
public ColorScope(Color value)
2024-03-09 09:42:04 +08:00
{
2024-05-13 19:20:07 +08:00
_value = GUI.color;
GUI.color = value;
2024-03-09 09:42:04 +08:00
}
2024-06-25 23:20:40 +08:00
public void Dispose() { GUI.color = _value; }
2024-03-09 09:42:04 +08:00
}
2024-03-10 04:56:29 +08:00
public struct ContentColorScope : IDisposable
{
2024-05-13 19:20:07 +08:00
private readonly Color _value;
2024-05-15 00:36:56 +08:00
public ContentColorScope(float r, float g, float b, float a = 1f) : this(new Color(r, g, b, a)) { }
2024-05-13 19:20:07 +08:00
public ContentColorScope(Color value)
2024-03-10 04:56:29 +08:00
{
2024-05-13 19:20:07 +08:00
_value = GUI.contentColor;
GUI.contentColor = value;
2024-03-10 04:56:29 +08:00
}
2024-06-25 23:20:40 +08:00
public void Dispose() { GUI.contentColor = _value; }
2024-03-10 04:56:29 +08:00
}
2024-06-10 18:05:06 +08:00
public struct BackgroundColorScope : IDisposable
{
private readonly Color _value;
public BackgroundColorScope(float r, float g, float b, float a = 1f) : this(new Color(r, g, b, a)) { }
public BackgroundColorScope(Color value)
{
_value = GUI.backgroundColor;
GUI.backgroundColor = value;
}
2024-06-25 23:20:40 +08:00
public void Dispose() { GUI.backgroundColor = _value; }
2024-06-10 18:05:06 +08:00
}
2024-06-11 02:30:10 +08:00
public struct IndentLevelScope : IDisposable
2024-06-10 18:05:06 +08:00
{
private readonly int _value;
public IndentLevelScope(int value)
{
_value = EditorGUI.indentLevel;
EditorGUI.indentLevel = value;
}
2024-06-25 23:20:40 +08:00
public void Dispose() { EditorGUI.indentLevel = _value; }
2024-06-10 18:05:06 +08:00
}
2024-06-13 18:04:47 +08:00
public struct AlignmentScope : IDisposable
{
2024-06-25 23:20:40 +08:00
public readonly GUIStyle Target;
2024-06-13 18:04:47 +08:00
private readonly TextAnchor _value;
public AlignmentScope(GUIStyle target, TextAnchor value)
{
2024-06-25 23:20:40 +08:00
Target = target;
_value = Target.alignment;
Target.alignment = value;
2024-06-13 18:04:47 +08:00
}
2024-06-25 23:20:40 +08:00
public AlignmentScope(GUIStyle target)
2024-06-13 18:04:47 +08:00
{
2024-06-25 23:20:40 +08:00
Target = target;
_value = Target.alignment;
2024-06-13 18:04:47 +08:00
}
2024-06-25 23:20:40 +08:00
public void Dispose() { Target.alignment = _value; }
}
public struct FontSizeScope : IDisposable
{
public readonly GUIStyle Target;
private readonly int _value;
public FontSizeScope(GUIStyle target, int value)
{
Target = target;
_value = Target.fontSize;
Target.fontSize = value;
}
public FontSizeScope(GUIStyle target)
{
Target = target;
_value = Target.fontSize;
}
public void Dispose() { Target.fontSize = _value; }
}
public struct FontStyleScope : IDisposable
{
public readonly GUIStyle Target;
private readonly FontStyle _value;
public FontStyleScope(GUIStyle target, FontStyle value)
{
Target = target;
_value = Target.fontStyle;
Target.fontStyle = value;
}
public FontStyleScope(GUIStyle target)
{
Target = target;
_value = Target.fontStyle;
}
public void Dispose() { Target.fontStyle = _value; }
2024-06-13 18:04:47 +08:00
}
public static partial class Layout
{
public struct VerticalScope : IDisposable
{
public VerticalScope(GUILayoutOption[] options) { GUILayout.BeginVertical(options); }
public VerticalScope(GUIStyle style, GUILayoutOption[] options) { GUILayout.BeginVertical(style, options); }
public void Dispose() { GUILayout.EndVertical(); }
}
public struct HorizontalScope : IDisposable
{
public HorizontalScope(GUILayoutOption[] options) { GUILayout.BeginHorizontal(options); }
public HorizontalScope(GUIStyle style, GUILayoutOption[] options) { GUILayout.BeginHorizontal(style, options); }
public void Dispose() { GUILayout.EndHorizontal(); }
}
public struct ScrollViewScope : IDisposable
{
public ScrollViewScope(ref Vector2 pos, GUILayoutOption[] options) { pos = GUILayout.BeginScrollView(pos, options); }
public ScrollViewScope(ref Vector2 pos, GUIStyle style, GUILayoutOption[] options) { pos = GUILayout.BeginScrollView(pos, style, options); }
public void Dispose() { GUILayout.EndScrollView(); }
}
public static ScrollViewScope BeginScrollView(ref Vector2 pos) => new ScrollViewScope(ref pos, Array.Empty<GUILayoutOption>());
public static HorizontalScope BeginHorizontal() => new HorizontalScope(Array.Empty<GUILayoutOption>());
public static VerticalScope BeginVertical() => new VerticalScope(Array.Empty<GUILayoutOption>());
public static ScrollViewScope BeginScrollView(ref Vector2 pos, params GUILayoutOption[] options) => new ScrollViewScope(ref pos, options);
public static HorizontalScope BeginHorizontal(params GUILayoutOption[] options) => new HorizontalScope(options);
public static VerticalScope BeginVertical(params GUILayoutOption[] options) => new VerticalScope(options);
public static ScrollViewScope BeginScrollView(ref Vector2 pos, GUIStyle style, params GUILayoutOption[] options) => new ScrollViewScope(ref pos, style, options);
public static HorizontalScope BeginHorizontal(GUIStyle style, params GUILayoutOption[] options) => new HorizontalScope(style, options);
public static VerticalScope BeginVertical(GUIStyle style, params GUILayoutOption[] options) => new VerticalScope(style, options);
}
public static CheckChangedScope CheckChanged() => CheckChangedScope.New();
public static CheckChangedScopeWithAutoApply CheckChanged(SerializedObject serializedObject) => new CheckChangedScopeWithAutoApply(serializedObject);
public static ScrollViewScope BeginScrollView(Rect position, ref Vector2 pos, Rect viewRect) => new ScrollViewScope(position, ref pos, viewRect);
2024-06-25 23:20:40 +08:00
public static FontStyleScope SetFontStyle(GUIStyle target, FontStyle value) => new FontStyleScope(target, value);
public static FontStyleScope SetFontStyle(FontStyle value) => new FontStyleScope(GUI.skin.label, value);
2024-06-25 23:20:40 +08:00
public static FontStyleScope SetFontStyle(GUIStyle target) => new FontStyleScope(target);
public static FontSizeScope SetFontSize(GUIStyle target, int value) => new FontSizeScope(target, value);
2024-10-11 23:29:48 +08:00
public static FontSizeScope SetFontSize(int value) => new FontSizeScope(GUI.skin.label, value);
2024-06-25 23:20:40 +08:00
public static FontSizeScope SetFontSize(GUIStyle target) => new FontSizeScope(target);
2024-06-13 18:04:47 +08:00
public static AlignmentScope SetAlignment(GUIStyle target, TextAnchor value) => new AlignmentScope(target, value);
public static AlignmentScope SetAlignment(TextAnchor value) => new AlignmentScope(GUI.skin.label, value);
2024-06-25 23:20:40 +08:00
public static AlignmentScope SetAlignment(GUIStyle target) => new AlignmentScope(target);
2024-06-10 18:05:06 +08:00
public static IndentLevelScope SetIndentLevel(int level) => new IndentLevelScope(level);
2024-09-11 10:37:25 +08:00
public static IndentLevelScope UpIndentLevel() => new IndentLevelScope(EditorGUI.indentLevel + 1);
2024-06-10 18:05:06 +08:00
public static ContentColorScope SetContentColor(Color value) => new ContentColorScope(value);
2024-10-01 18:04:53 +08:00
public static ContentColorScope SetContentColor(Color value, float a) => new ContentColorScope(value.r, value.g, value.b, a);
2024-06-10 18:05:06 +08:00
public static ContentColorScope SetContentColor(float r, float g, float b, float a = 1f) => new ContentColorScope(r, g, b, a);
public static BackgroundColorScope SetBackgroundColor(Color value) => new BackgroundColorScope(value);
2024-10-01 18:04:53 +08:00
public static BackgroundColorScope SetBackgroundColor(Color value, float a) => new BackgroundColorScope(value.r, value.g, value.b, a);
2024-06-10 18:05:06 +08:00
public static BackgroundColorScope SetBackgroundColor(float r, float g, float b, float a = 1f) => new BackgroundColorScope(r, g, b, a);
public static ColorScope SetColor(Color value) => new ColorScope(value);
2024-10-01 18:04:53 +08:00
public static ColorScope SetColor(Color value, float a) => new ColorScope(value.a, value.g, value.b, a);
2024-06-10 18:05:06 +08:00
public static ColorScope SetColor(float r, float g, float b, float a = 1f) => new ColorScope(r, g, b, a);
2024-06-11 02:30:10 +08:00
public static ColorScope SetAlpha(float a) => new ColorScope(GUI.color * new Color(1, 1, 1, a));
2024-06-10 18:05:06 +08:00
public static EditorGUI.DisabledScope Enable => new EditorGUI.DisabledScope(false);
public static EditorGUI.DisabledScope Disable => new EditorGUI.DisabledScope(true);
public static EditorGUI.DisabledScope SetEnable(bool value) => new EditorGUI.DisabledScope(!value);
public static LabelWidthScope SetLabelWidth(float value) => new LabelWidthScope(value);
#endregion
2024-05-16 19:03:03 +08:00
2024-05-15 01:06:19 +08:00
private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
2024-03-10 04:56:29 +08:00
2024-03-04 07:38:38 +08:00
internal readonly static Color GrayColor = new Color32(100, 100, 100, 255);
internal readonly static Color GreenColor = new Color32(75, 255, 0, 255);
internal readonly static Color RedColor = new Color32(255, 0, 75, 255);
2024-03-03 19:59:39 +08:00
2024-06-15 16:53:28 +08:00
private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f);
2024-03-09 03:35:01 +08:00
2024-03-09 22:36:35 +08:00
public static float EntityBarHeight => EditorGUIUtility.singleLineHeight + 3f;
2024-11-01 17:17:52 +08:00
private static float indent => (float)EditorGUI.indentLevel * 15f;
2024-05-15 01:06:19 +08:00
#region Properties
private static ComponentColorMode AutoColorMode
{
2024-09-21 14:39:09 +08:00
get { return UserSettingsPrefs.instance.ComponentColorMode; }
set { UserSettingsPrefs.instance.ComponentColorMode = value; }
2024-05-15 01:06:19 +08:00
}
2024-03-09 03:35:01 +08:00
private static bool IsShowHidden
{
2024-09-21 14:39:09 +08:00
get { return UserSettingsPrefs.instance.IsShowHidden; }
set { UserSettingsPrefs.instance.IsShowHidden = value; }
2024-03-09 03:35:01 +08:00
}
private static bool IsShowRuntimeComponents
{
2024-09-21 14:39:09 +08:00
get { return UserSettingsPrefs.instance.IsShowRuntimeComponents; }
set { UserSettingsPrefs.instance.IsShowRuntimeComponents = value; }
2024-03-09 03:35:01 +08:00
}
private static float OneLineHeight
{
get => EditorGUIUtility.singleLineHeight;
}
private static float Spacing
{
get => EditorGUIUtility.standardVerticalSpacing;
}
2024-05-15 01:06:19 +08:00
#endregion
2024-03-09 03:35:01 +08:00
2024-05-15 01:06:19 +08:00
#region enums
2024-09-16 19:31:01 +08:00
public enum AddClearButton : byte
2024-03-09 03:35:01 +08:00
{
None = 0,
2024-09-16 19:31:01 +08:00
Add = 1,
Clear = 2,
2024-03-09 03:35:01 +08:00
}
2024-03-09 09:42:04 +08:00
[Flags]
2024-09-16 19:31:01 +08:00
public enum EntityStatus : byte
2024-03-09 09:42:04 +08:00
{
NotAlive = 0,
Alive = 1 << 0,
Undefined = 1 << 1,
}
2024-05-15 01:06:19 +08:00
#endregion
2024-03-09 03:35:01 +08:00
2024-09-16 19:31:01 +08:00
#region HitTest/ClickTest
2024-03-10 09:18:40 +08:00
internal static bool HitTest(Rect rect)
{
return HitTest(rect, Event.current.mousePosition);
}
2024-03-09 09:42:04 +08:00
internal static bool HitTest(Rect rect, Event evt)
{
return HitTest(rect, evt.mousePosition);
}
internal static bool HitTest(Rect rect, Vector2 point)
{
int offset = 0;
return HitTest(rect, point, offset);
}
internal static bool HitTest(Rect rect, Vector2 point, int offset)
{
return point.x >= rect.xMin - (float)offset && point.x < rect.xMax + (float)offset && point.y >= rect.yMin - (float)offset && point.y < rect.yMax + (float)offset;
}
2024-09-16 19:31:01 +08:00
internal static bool ClickTest(Rect rect)
{
Event evt = Event.current;
return ClickTest(rect, evt);
}
internal static bool ClickTest(Rect rect, Event evt)
{
return HitTest(rect, evt.mousePosition) && evt.type == EventType.MouseUp;
}
2024-05-15 01:06:19 +08:00
#endregion
2024-03-09 09:42:04 +08:00
2024-05-15 01:06:19 +08:00
#region small elems
2024-05-03 21:21:21 +08:00
public static void DrawIcon(Rect position, Texture icon, float iconPadding, string description)
{
2024-06-15 16:53:28 +08:00
if (position.width != position.height)
2024-06-13 18:04:47 +08:00
{
Vector2 center = position.center;
float size = Mathf.Min(position.width, position.height);
position.height = size;
position.width = size;
position.center = center;
}
2024-05-16 19:03:03 +08:00
using (SetColor(GUI.enabled ? GUI.color : GUI.color * new Color(1f, 1f, 1f, 0.4f)))
{
GUI.Label(position, UnityEditorUtility.GetLabel(string.Empty, description));
GUI.DrawTexture(RectUtility.AddPadding(position, iconPadding), icon);
}
2024-05-03 21:21:21 +08:00
}
2024-03-09 22:36:35 +08:00
public static (bool, bool) IconButtonGeneric(Rect position)
2024-03-09 09:42:04 +08:00
{
2024-06-15 16:53:28 +08:00
using (SetAlpha(0))
{
bool result = GUI.Button(position, string.Empty, EditorStyles.miniButtonMid);
var current = Event.current;
return (GUI.enabled && HitTest(position, current), result);
}
}
public static bool IconHoverScan(Rect position, Event current)
{
using (Disable) using (SetAlpha(0))
{
GUI.Button(position, string.Empty, EditorStyles.miniButtonMid);
return HitTest(position, current);
}
2024-03-09 09:42:04 +08:00
}
2024-03-09 22:36:35 +08:00
public static bool IconButton(Rect position, Texture icon, float iconPadding, string description)
2024-03-09 09:42:04 +08:00
{
2024-03-09 22:36:35 +08:00
bool result = GUI.Button(position, UnityEditorUtility.GetLabel(string.Empty));
2024-05-03 21:21:21 +08:00
DrawIcon(position, icon, iconPadding, description);
2024-03-09 22:36:35 +08:00
return result;
2024-03-09 09:42:04 +08:00
}
public static void DescriptionIcon(Rect position, string description)
{
using (new ColorScope(new Color(1f, 1f, 1f, 0.8f)))
{
2024-05-03 23:19:04 +08:00
DrawIcon(position, Icons.Instance.HelpIcon, 0, description);
2024-03-09 09:42:04 +08:00
}
}
2024-06-15 18:43:29 +08:00
2024-10-12 21:03:19 +08:00
2024-06-15 19:18:28 +08:00
public static void ScriptAssetButton(Rect position, MonoScript script)
2024-06-15 16:53:28 +08:00
{
var current = Event.current;
var hover = IconHoverScan(position, current);
using (new ColorScope(new Color(1f, 1f, 1f, hover ? 1f : 0.8f)))
{
DrawIcon(position, Icons.Instance.FileIcon, hover ? 1f : 2f, "One click - Ping File. Double click - Edit Script");
}
if (hover)
{
if (current.type == EventType.MouseUp)
{
2024-06-15 18:45:20 +08:00
EditorGUIUtility.PingObject(script);
2024-06-15 16:53:28 +08:00
}
else if (current.type == EventType.MouseDown && current.clickCount >= 2)
{
2024-06-15 18:45:20 +08:00
AssetDatabase.OpenAsset(script);
2024-06-15 16:53:28 +08:00
}
}
}
public static bool CloseButton(Rect position, string description = null)
2024-03-09 09:42:04 +08:00
{
using (new ColorScope(new Color(1f, 1f, 1f, 0.8f)))
{
2024-03-09 22:36:35 +08:00
var (hover, click) = IconButtonGeneric(position);
2024-03-09 09:42:04 +08:00
if (hover)
{
2024-06-15 16:53:28 +08:00
DrawIcon(position, Icons.Instance.CloseIconOn, -4f, description);
2024-03-09 09:42:04 +08:00
}
else
{
2024-06-15 16:53:28 +08:00
DrawIcon(position, Icons.Instance.CloseIcon, 0, description);
2024-03-09 09:42:04 +08:00
}
return click;
}
}
2024-10-19 00:05:07 +08:00
public static bool ValidateButton(Rect position)
{
return IconButton(position, Icons.Instance.RepaireIcon, 2f, "Validate");
}
2024-03-09 22:36:35 +08:00
public static bool AutosetCascadeButton(Rect position)
{
2024-05-03 23:19:04 +08:00
return IconButton(position, Icons.Instance.AutosetCascadeIcon, 0f, "Autoset Cascade");
2024-03-09 22:36:35 +08:00
}
public static bool AutosetButton(Rect position)
{
2024-05-03 23:19:04 +08:00
return IconButton(position, Icons.Instance.AuotsetIcon, 1f, "Autoset");
2024-03-09 22:36:35 +08:00
}
2024-03-09 09:42:04 +08:00
public static bool UnlinkButton(Rect position)
{
2024-05-03 23:19:04 +08:00
return IconButton(position, Icons.Instance.UnlinkIcon, 1f, "Unlink Entity");
2024-03-09 09:42:04 +08:00
}
public static bool DelEntityButton(Rect position)
{
2024-05-03 23:19:04 +08:00
return IconButton(position, Icons.Instance.CloseIcon, 0f, "Delete Entity");
2024-03-09 09:42:04 +08:00
}
2024-05-15 01:06:19 +08:00
#endregion
2024-03-09 09:42:04 +08:00
2024-05-15 01:06:19 +08:00
#region entity bar
2024-05-13 19:20:07 +08:00
public static void EntityBarForAlive(Rect position, EntityStatus status, int id, short gen, short world)
{
EntityBar(position, status != EntityStatus.Alive, status, id, gen, world);
}
public static void EntityBar(Rect position, int id, short gen, short world)
{
EntityBar_Internal(position, false, id, gen, world);
}
public static void EntityBar(Rect position)
{
EntityBar_Internal(position, true);
}
public static void EntityBar(Rect position, bool isPlaceholder, EntityStatus status, int id = 0, short gen = 0, short world = 0)
{
using (SetLabelWidth(0f))
2024-05-13 19:20:07 +08:00
{
var (entityInfoRect, statusRect) = RectUtility.VerticalSliceBottom(position, 3f);
2024-03-09 09:42:04 +08:00
2024-05-13 19:20:07 +08:00
Color statusColor;
switch (status)
{
case EntityStatus.NotAlive:
statusColor = EcsGUI.RedColor;
break;
case EntityStatus.Alive:
statusColor = EcsGUI.GreenColor;
break;
default:
statusColor = new Color32(200, 200, 200, 255);
break;
}
2024-03-09 09:42:04 +08:00
statusColor.a = 0.6f;
EditorGUI.DrawRect(statusRect, statusColor);
2024-05-13 19:20:07 +08:00
EntityBar_Internal(entityInfoRect, isPlaceholder, id, gen, world);
2024-03-09 09:42:04 +08:00
}
2024-05-13 19:20:07 +08:00
}
private static void EntityBar_Internal(Rect position, bool isPlaceHolder, int id = 0, short gen = 0, short world = 0)
{
using (SetLabelWidth(0f))
2024-03-09 09:42:04 +08:00
{
2024-05-13 19:20:07 +08:00
Color w = Color.gray;
w.a = 0.6f;
Color b = Color.black;
b.a = 0.55f;
EditorGUI.DrawRect(position, w);
var (idRect, genWorldRect) = RectUtility.HorizontalSliceLerp(position, 0.4f);
var (genRect, worldRect) = RectUtility.HorizontalSliceLerp(genWorldRect, 0.5f);
idRect = RectUtility.AddPadding(idRect, 2, 1, 0, 0);
genRect = RectUtility.AddPadding(genRect, 1, 1, 0, 0);
worldRect = RectUtility.AddPadding(worldRect, 1, 2, 0, 0);
EditorGUI.DrawRect(idRect, b);
EditorGUI.DrawRect(genRect, b);
EditorGUI.DrawRect(worldRect, b);
GUIStyle style = UnityEditorUtility.GetInputFieldCenterAnhor();
2024-03-09 09:42:04 +08:00
2024-05-13 19:20:07 +08:00
if (isPlaceHolder)
2024-03-09 09:42:04 +08:00
{
2024-05-13 19:20:07 +08:00
using (new EditorGUI.DisabledScope(true))
{
GUI.Label(idRect, "Entity ID", style);
GUI.Label(genRect, "Generation", style);
GUI.Label(worldRect, "World ID", style);
}
}
else
{
EditorGUI.IntField(idRect, id, style);
EditorGUI.IntField(genRect, gen, style);
EditorGUI.IntField(worldRect, world, style);
2024-03-09 09:42:04 +08:00
}
}
}
2024-05-15 01:06:19 +08:00
#endregion
2024-03-09 09:42:04 +08:00
#region DrawTypeMetaBlock
private static float DrawTypeMetaBlockPadding => EditorGUIUtility.standardVerticalSpacing;
private static float SingleLineWithPadding => EditorGUIUtility.singleLineHeight + DrawTypeMetaBlockPadding * 4f;
public static float GetTypeMetaBlockHeight(float contentHeight)
{
return DrawTypeMetaBlockPadding * 2 + contentHeight;
}
2024-10-02 14:01:18 +08:00
public static bool DrawTypeMetaElementBlock(ref Rect position, SerializedProperty arrayProperty, int elementIndex, SerializedProperty elementRootProperty, ITypeMeta meta)
2024-09-16 19:31:01 +08:00
{
2024-10-02 14:01:18 +08:00
var result = DrawTypeMetaBlock_Internal(ref position, elementRootProperty, meta, elementIndex, arrayProperty.arraySize);
2024-09-16 19:31:01 +08:00
if (result.HasFlag(DrawTypeMetaBlockResult.CloseButtonClicked))
{
arrayProperty.DeleteArrayElementAtIndex(elementIndex);
}
return result != DrawTypeMetaBlockResult.None;
}
2024-10-02 14:01:18 +08:00
public static bool DrawTypeMetaBlock(ref Rect position, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1)
{
2024-10-02 14:01:18 +08:00
var result = DrawTypeMetaBlock_Internal(ref position, rootProperty, meta, index, total);
2024-09-16 19:31:01 +08:00
if (result.HasFlag(DrawTypeMetaBlockResult.CloseButtonClicked))
{
2024-10-02 14:01:18 +08:00
rootProperty.ResetValues();
}
2024-09-16 19:31:01 +08:00
return result.HasFlag(DrawTypeMetaBlockResult.Drop);
}
2024-09-16 19:31:01 +08:00
private enum DrawTypeMetaBlockResult
{
None = 0,
Drop = 1 << 0,
CloseButtonClicked = 1 << 1,
}
2024-10-02 14:01:18 +08:00
private static DrawTypeMetaBlockResult DrawTypeMetaBlock_Internal(ref Rect position, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1)
2024-09-16 19:31:01 +08:00
{
Color alphaPanelColor;
if (meta == null)
{
alphaPanelColor = Color.black;
alphaPanelColor.a = EscEditorConsts.COMPONENT_DRAWER_ALPHA;
EditorGUI.DrawRect(position, alphaPanelColor);
position = position.AddPadding(DrawTypeMetaBlockPadding * 2f);
return DrawTypeMetaBlockResult.None;
}
string name = meta.Name;
string description = meta.Description.Text;
2024-10-02 14:01:18 +08:00
int positionIndex;
2024-09-27 22:04:00 +08:00
if (index < 0)
{
2024-10-02 14:01:18 +08:00
positionIndex = int.MaxValue;
var counter = rootProperty.Copy();
2024-09-27 22:04:00 +08:00
int depth = -1;
while (counter.NextVisibleDepth(false, ref depth))
{
2024-10-02 14:01:18 +08:00
positionIndex--;
2024-09-27 22:04:00 +08:00
}
}
else
{
2024-10-02 14:01:18 +08:00
positionIndex = index;
2024-09-27 22:04:00 +08:00
}
2024-10-02 14:01:18 +08:00
alphaPanelColor = SelectPanelColor(meta, positionIndex, total).Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE).SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA);
2024-09-16 19:31:01 +08:00
DrawTypeMetaBlockResult result = DrawTypeMetaBlockResult.None;
using (CheckChanged())
{
EditorGUI.DrawRect(position, alphaPanelColor);
Rect optionButton = position;
2024-09-16 19:31:01 +08:00
position = position.AddPadding(DrawTypeMetaBlockPadding * 2f);
optionButton.center -= new Vector2(0, optionButton.height);
optionButton.yMin = optionButton.yMax;
optionButton.yMax += HeadIconsRect.height;
optionButton.xMin = optionButton.xMax - 64;
2024-10-02 14:29:27 +08:00
optionButton.center += Vector2.up * DrawTypeMetaBlockPadding;
2024-09-16 19:31:01 +08:00
//Canceling isExpanded
2024-10-02 14:01:18 +08:00
bool oldIsExpanded = rootProperty.isExpanded;
2024-09-16 19:31:01 +08:00
if (ClickTest(optionButton))
{
2024-10-02 14:01:18 +08:00
rootProperty.isExpanded = oldIsExpanded;
2024-09-16 19:31:01 +08:00
result |= DrawTypeMetaBlockResult.Drop;
}
//Close button
optionButton.xMin = optionButton.xMax - HeadIconsRect.width;
if (CloseButton(optionButton))
{
2024-09-16 19:31:01 +08:00
result |= DrawTypeMetaBlockResult.CloseButtonClicked;
return result;
}
//Edit script button
2024-09-27 22:04:00 +08:00
if (ScriptsCache.TryGetScriptAsset(meta.FindRootTypeMeta(), out MonoScript script))
{
optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
ScriptAssetButton(optionButton, script);
}
//Description icon
if (string.IsNullOrEmpty(description) == false)
{
optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DescriptionIcon(optionButton, description);
}
}
2024-09-16 19:31:01 +08:00
return result;
}
#endregion
#region NextDepth/GetChildPropertiesCount
internal static bool NextVisibleDepth(this SerializedProperty property, bool child, ref int depth)
{
if (depth < 0)
{
depth = property.depth;
}
2024-10-02 14:01:18 +08:00
var next = property.NextVisible(child);
return next && property.depth >= depth;
}
internal static bool NextDepth(this SerializedProperty property, bool child, ref int depth)
{
if (depth < 0)
{
depth = property.depth;
}
return property.Next(child) && property.depth >= depth;
}
internal static int GetChildPropertiesCount(this SerializedProperty property, Type type, out bool isEmpty)
2024-05-16 19:03:03 +08:00
{
int result = GetChildPropertiesCount(property);
isEmpty = result <= 0 && type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Length <= 0;
return result;
}
internal static int GetChildPropertiesCount(this SerializedProperty property)
2024-05-16 19:03:03 +08:00
{
var propsCounter = property.Copy();
int lastDepth = propsCounter.depth;
bool next = propsCounter.Next(true) && lastDepth < propsCounter.depth;
2024-05-18 23:47:48 +08:00
int result = 0;
2024-05-16 19:03:03 +08:00
while (next)
{
result++;
2024-05-18 16:15:47 +08:00
next = propsCounter.Next(true);
2024-05-16 19:03:03 +08:00
}
return result;
}
#endregion
#region SelectPanelColor
2024-05-16 19:03:03 +08:00
public static Color SelectPanelColor(ITypeMeta meta, int index, int total)
{
2024-05-16 20:31:06 +08:00
var trueMeta = meta.Type.ToMeta();
2024-06-10 18:05:06 +08:00
bool isCustomColor = trueMeta.IsCustomColor || meta.Color != trueMeta.Color;
return SelectPanelColor(meta.Color, isCustomColor, index, total);
}
public static Color SelectPanelColor(MetaColor color, bool isCustomColor, int index, int total)
{
if (isCustomColor)
2024-05-16 19:03:03 +08:00
{
2024-06-10 18:05:06 +08:00
return color.ToUnityColor();
2024-05-16 19:03:03 +08:00
}
else
{
switch (AutoColorMode)
{
case ComponentColorMode.Auto:
2024-06-10 18:05:06 +08:00
return color.ToUnityColor().Desaturate(0.48f) / 1.18f; //.Desaturate(0.48f) / 1.18f;
2024-05-16 19:03:03 +08:00
case ComponentColorMode.Rainbow:
int localTotal = Mathf.Max(total, EscEditorConsts.AUTO_COLOR_RAINBOW_MIN_RANGE);
Color hsv = Color.HSVToRGB(1f / localTotal * (index % localTotal), 1, 1);
2024-05-16 20:31:06 +08:00
return hsv.Desaturate(0.48f) / 1.18f;
2024-05-16 19:03:03 +08:00
default:
2024-11-07 15:47:10 +08:00
return GetGenericPanelColor(index);
2024-05-16 19:03:03 +08:00
}
}
}
2024-11-07 15:47:10 +08:00
public static Color GetGenericPanelColor(int index)
{
return index % 2 == 0 ? new Color(0.40f, 0.40f, 0.40f) : new Color(0.54f, 0.54f, 0.54f);
}
#endregion
#region Other Elements
2024-09-12 01:35:37 +08:00
public static bool AddComponentButton(Rect position, out Rect dropDownRect)
2024-03-09 09:42:04 +08:00
{
2024-10-12 23:00:59 +08:00
dropDownRect = RectUtility.AddPadding(position, 20f, 20f, 1f, 1f); ;
2024-09-12 01:35:37 +08:00
return GUI.Button(dropDownRect, "Add Component");
2024-03-09 09:42:04 +08:00
}
2024-09-16 19:31:01 +08:00
public static AddClearButton AddClearComponentButtons(Rect position, out Rect dropDownRect)
{
return AddClearButtons(position, "Add Component", "Clear", out dropDownRect);
}
public static AddClearButton AddClearSystemButtons(Rect position, out Rect dropDownRect)
{
return AddClearButtons(position, "Add Record", "Clear", out dropDownRect);
}
public static AddClearButton AddClearButtons(Rect position, string addText, string clearText, out Rect dropDownRect)
2024-03-03 19:59:39 +08:00
{
2024-10-12 23:00:59 +08:00
position = RectUtility.AddPadding(position, 20f, 20f, 1f, 1f);
2024-03-09 03:35:01 +08:00
var (left, right) = RectUtility.HorizontalSliceLerp(position, 0.75f);
2024-09-12 01:35:37 +08:00
dropDownRect = left;
2024-09-16 19:31:01 +08:00
if (GUI.Button(left, addText))
2024-03-09 03:35:01 +08:00
{
2024-09-16 19:31:01 +08:00
return AddClearButton.Add;
2024-03-09 03:35:01 +08:00
}
2024-09-16 19:31:01 +08:00
if (GUI.Button(right, clearText))
2024-03-04 08:01:49 +08:00
{
2024-09-16 19:31:01 +08:00
return AddClearButton.Clear;
2024-03-04 08:01:49 +08:00
}
2024-09-16 19:31:01 +08:00
return AddClearButton.None;
2024-03-09 03:35:01 +08:00
}
2024-05-16 23:27:45 +08:00
public static void DrawEmptyComponentProperty(Rect position, SerializedProperty property, string name, bool isDisplayEmpty)
{
DrawEmptyComponentProperty(position, property, UnityEditorUtility.GetLabel(name), isDisplayEmpty);
}
public static void DrawEmptyComponentProperty(Rect position, SerializedProperty property, GUIContent label, bool isDisplayEmpty)
2024-03-09 03:35:01 +08:00
{
2024-05-16 23:27:45 +08:00
EditorGUI.LabelField(position, label);
if (isDisplayEmpty)
2024-05-16 19:59:57 +08:00
{
2024-05-16 23:27:45 +08:00
using (SetContentColor(1f, 1f, 1f, 0.4f))
{
GUI.Label(position.AddPadding(EditorGUIUtility.labelWidth, 0, 0, 0), "empty");
}
}
EditorGUI.BeginProperty(position, label, property);
EditorGUI.EndProperty();
}
#endregion
2024-05-16 19:59:57 +08:00
#region SerializeReference utils
private static Dictionary<PredicateTypesKey, ReferenceDropDown> _predicatTypesMenus = new Dictionary<PredicateTypesKey, ReferenceDropDown>();
[ThreadStatic]
private static SerializedProperty _currentProperty;
#region Init
2024-11-01 13:50:48 +08:00
private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes, Type[] sortedWithOutTypes)
{
2024-11-01 13:50:48 +08:00
if (_predicatTypesMenus.TryGetValue((predicatTypes, sortedWithOutTypes), out ReferenceDropDown menu) == false)
{
2024-11-01 13:50:48 +08:00
menu = new ReferenceDropDown(predicatTypes, sortedWithOutTypes);
menu.OnSelected += SelectComponent;
2024-11-01 13:50:48 +08:00
_predicatTypesMenus.Add((predicatTypes, sortedWithOutTypes), menu);
}
return menu;
}
private static void SelectComponent(ReferenceDropDown.Item item)
{
Type type = item.Type;
if (type == null)
{
_currentProperty.managedReferenceValue = null;
}
else
{
_currentProperty.managedReferenceValue = Activator.CreateInstance(type);
_currentProperty.isExpanded = true;
}
_currentProperty.serializedObject.ApplyModifiedProperties();
DelayedChanged = true;
}
#endregion
#region PredicateTypesKey
private readonly struct PredicateTypesKey : IEquatable<PredicateTypesKey>
{
public readonly Type[] types;
2024-11-01 13:50:48 +08:00
public readonly Type[] withoutTypes;
public PredicateTypesKey(Type[] types, Type[] withoutTypes)
{
this.types = types;
2024-11-01 13:50:48 +08:00
this.withoutTypes = withoutTypes;
}
public bool Equals(PredicateTypesKey other)
{
if (types.Length != other.types.Length) { return false; }
2024-11-01 13:50:48 +08:00
if (withoutTypes.Length != other.withoutTypes.Length) { return false; }
for (int i = 0; i < types.Length; i++)
{
if (types[i] != other.types[i])
{
return false;
}
}
2024-11-01 13:50:48 +08:00
for (int i = 0; i < withoutTypes.Length; i++)
{
if (withoutTypes[i] != other.withoutTypes[i])
{
return false;
}
}
return true;
}
public override bool Equals(object obj)
{
return obj is PredicateTypesKey key && Equals(key);
}
public override int GetHashCode()
{
return HashCode.Combine(types);
}
2024-11-01 13:50:48 +08:00
public static implicit operator PredicateTypesKey((Type[], Type[]) types) { return new PredicateTypesKey(types.Item1, types.Item2); }
}
#endregion
#region ReferenceDropDown
private class ReferenceDropDown : AdvancedDropdown
{
public readonly Type[] PredicateTypes;
2024-11-01 13:50:48 +08:00
public readonly Type[] WithOutTypes;
public ReferenceDropDown(Type[] predicateTypes, Type[] withOutTypes) : base(new AdvancedDropdownState())
{
PredicateTypes = predicateTypes;
2024-11-01 13:50:48 +08:00
WithOutTypes = withOutTypes;
minimumSize = new Vector2(minimumSize.x, EditorGUIUtility.singleLineHeight * 30);
}
protected override AdvancedDropdownItem BuildRoot()
{
int increment = 0;
var root = new Item(null, "Select Type", increment++);
root.AddChild(new Item(null, "<NULL>", increment++));
Dictionary<Key, Item> dict = new Dictionary<Key, Item>();
2024-09-16 19:31:01 +08:00
foreach (var type in UnityEditorUtility._serializableTypes)
{
bool isAssignable = false;
foreach (Type predicateTypes in PredicateTypes)
{
if (predicateTypes.IsAssignableFrom(type))
{
isAssignable = true;
break;
}
}
2024-11-01 13:50:48 +08:00
foreach (Type withoutType in WithOutTypes)
{
if (withoutType.IsAssignableFrom(type))
{
isAssignable = false;
break;
}
}
if (isAssignable)
{
ITypeMeta meta = type.ToMeta();
string description = meta.Description.Text;
MetaGroup group = meta.Group;
var splitedGroup = group.Splited;
Item parent = root;
if (splitedGroup.Count > 0)
{
int i = 1;
foreach (var subgroup in splitedGroup)
{
Key key = new Key(group, i);
if (dict.TryGetValue(key, out Item item) == false)
{
item = new Item(null, subgroup, increment++);
parent.AddChild(item);
dict.Add(key, item);
}
parent = item;
i++;
}
}
var leafItem = new Item(type, meta.Name, increment++);
parent.AddChild(leafItem);
}
}
return root;
}
protected override void ItemSelected(AdvancedDropdownItem item)
{
base.ItemSelected(item);
OnSelected((Item)item);
}
public event Action<Item> OnSelected = delegate { };
public class Item : AdvancedDropdownItem
{
public readonly Type Type;
public Item(Type type, string name, int id) : base(name)
{
Type = type;
this.id = id;
}
}
#region Key
private readonly struct Key : IEquatable<Key>
{
public readonly MetaGroup Group;
public readonly int Length;
public Key(MetaGroup group, int length)
{
Group = group;
Length = length;
}
public bool Equals(Key other)
{
if (Length != other.Length)
{
return false;
}
IEnumerator<string> splitedEnum = Group.Splited.GetEnumerator();
IEnumerator<string> splitedEnumOther = other.Group.Splited.GetEnumerator();
for (int i = 0; i < Length; i++)
{
splitedEnum.MoveNext();
splitedEnumOther.MoveNext();
if (splitedEnum.Current != splitedEnumOther.Current)
{
return false;
}
}
return true;
}
public override bool Equals(object obj)
{
return obj is Key key && Equals(key);
}
public override int GetHashCode()
{
unchecked
{
int state = Length;
state ^= state << 13;
state ^= state >> 17;
state ^= state << 5;
var x = Group.Splited.GetEnumerator();
x.MoveNext();
return x.Current.GetHashCode() ^ state;
};
}
}
#endregion
}
#endregion
2024-11-01 13:50:48 +08:00
public static void DrawSelectReferenceButton(Rect position, SerializedProperty property, Type[] sortedPredicateTypes, Type[] sortedWithOutTypes, bool isHideButtonIfNotNull)
{
object obj = property.hasMultipleDifferentValues ? null : property.managedReferenceValue;
2024-11-01 17:17:52 +08:00
2024-09-16 19:31:01 +08:00
string text = obj == null ? "Select..." : obj.GetMeta().Name;
if (!isHideButtonIfNotNull || obj == null)
{
2024-09-16 19:31:01 +08:00
if (GUI.Button(position, text, EditorStyles.layerMaskField))
{
2024-11-01 13:50:48 +08:00
DrawSelectReferenceMenu(position, property, sortedPredicateTypes, sortedWithOutTypes);
}
}
else
{
2024-09-16 19:31:01 +08:00
GUI.Label(position, text);
}
}
2024-11-01 13:50:48 +08:00
public static void DrawSelectReferenceMenu(Rect position, SerializedProperty property, Type[] sortedPredicateTypes, Type[] sortedWithOutTypes)
2024-09-16 19:31:01 +08:00
{
_currentProperty = property;
2024-11-01 13:50:48 +08:00
GetReferenceDropDown(sortedPredicateTypes, sortedWithOutTypes).Show(position);
2024-09-16 19:31:01 +08:00
}
#endregion
2024-06-13 18:04:47 +08:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static partial class Layout
2024-05-16 23:27:45 +08:00
{
2024-06-15 19:18:28 +08:00
public static void ScriptAssetButton(MonoScript script, params GUILayoutOption[] options)
{
EcsGUI.ScriptAssetButton(GUILayoutUtility.GetRect(UnityEditorUtility.GetLabelTemp(), EditorStyles.miniButton, options), script);
}
2024-10-12 14:37:21 +08:00
public static void CopyMetaIDButton(string metaID, params GUILayoutOption[] options)
{
Rect r = GUILayoutUtility.GetRect(UnityEditorUtility.GetLabelTemp(), EditorStyles.miniButton, options);
var current = Event.current;
var hover = IconHoverScan(r, current);
using (new ColorScope(new Color(1f, 1f, 1f, hover ? 1f : 0.8f)))
{
DrawIcon(r, Icons.Instance.MetaIDIcon, hover ? 1f : 2f, metaID);
if (hover && current.type == EventType.MouseUp)
{
GUIUtility.systemCopyBuffer = metaID;
}
}
}
2024-06-13 18:04:47 +08:00
public static bool IconButton(Texture icon, params GUILayoutOption[] options)
{
bool result = GUILayout.Button(UnityEditorUtility.GetLabel(string.Empty), options);
DrawIcon(GUILayoutUtility.GetLastRect(), icon, 0, null);
return result;
}
public static bool IconButton(Texture icon, float iconPadding = 0, string description = null)
{
bool result = GUILayout.Button(UnityEditorUtility.GetLabel(string.Empty));
DrawIcon(GUILayoutUtility.GetLastRect(), icon, iconPadding, description);
return result;
}
public static bool IconButton(Texture icon, float iconPadding = 0, string description = null, GUIStyle style = null, params GUILayoutOption[] options)
{
bool result;
2024-09-10 19:13:31 +08:00
if (style == null)
2024-06-13 18:04:47 +08:00
{
result = GUILayout.Button(UnityEditorUtility.GetLabel(string.Empty), options);
}
else
{
result = GUILayout.Button(UnityEditorUtility.GetLabel(string.Empty), style, options);
}
DrawIcon(GUILayoutUtility.GetLastRect(), icon, iconPadding, description);
return result;
}
2024-05-16 23:27:45 +08:00
public static void DrawEmptyComponentProperty(SerializedProperty property, string name, bool isDisplayEmpty)
{
EcsGUI.DrawEmptyComponentProperty(GUILayoutUtility.GetRect(UnityEditorUtility.GetLabel(name), EditorStyles.label), property, name, isDisplayEmpty);
}
public static void DrawEmptyComponentProperty(SerializedProperty property, GUIContent label, bool isDisplayEmpty)
{
EcsGUI.DrawEmptyComponentProperty(GUILayoutUtility.GetRect(label, EditorStyles.label), property, label, isDisplayEmpty);
2024-05-16 19:59:57 +08:00
}
2024-03-10 04:56:29 +08:00
public static void DrawWorldBaseInfo(EcsWorld world)
{
2024-11-01 12:44:45 +08:00
bool isNull = world == null || world.IsDestroyed || world.ID == 0;
2024-03-10 04:56:29 +08:00
int entitesCount = isNull ? 0 : world.Count;
int capacity = isNull ? 0 : world.Capacity;
2024-12-05 14:15:21 +08:00
long Version = isNull ? 0 : world.Version;
2024-03-10 04:56:29 +08:00
int leakedEntitesCount = isNull ? 0 : world.CountLeakedEntitesDebug();
EditorGUILayout.IntField("Entities", entitesCount, EditorStyles.boldLabel);
EditorGUILayout.IntField("Capacity", capacity, EditorStyles.boldLabel);
2024-12-05 14:15:21 +08:00
EditorGUILayout.LongField("Version", Version, EditorStyles.boldLabel);
2024-03-10 04:56:29 +08:00
Color color = leakedEntitesCount > 0 ? Color.yellow : GUI.contentColor;
using (new ContentColorScope(color))
{
EditorGUILayout.IntField("Leaked Entites", leakedEntitesCount, EditorStyles.boldLabel);
}
}
2024-12-05 14:15:21 +08:00
public static void DrawWorldComponents(EcsWorld world)
{
bool isNull = world == null || world.IsDestroyed || world.ID == 0;
if (isNull) { return; }
using (BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)))
{
IsShowRuntimeComponents = EditorGUILayout.BeginFoldoutHeaderGroup(IsShowRuntimeComponents, "RUNTIME COMPONENTS", EditorStyles.foldout);
EditorGUILayout.EndFoldoutHeaderGroup();
if (IsShowRuntimeComponents == false) { return; }
var worldID = world.ID;
var cmps = world.GetWorldComponents();
int index = -1;
int total = 9;
foreach (var cmp in cmps)
{
index++;
var meta = cmp.ComponentType.ToMeta();
if (meta.IsHidden == false || IsShowHidden)
{
Type componentType = cmp.ComponentType;
object data = cmp.GetRaw(worldID);
ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType);
float padding = EditorGUIUtility.standardVerticalSpacing;
Rect optionButton = GUILayoutUtility.GetLastRect();
optionButton.yMin = optionButton.yMax;
optionButton.yMax += HeadIconsRect.height;
optionButton.xMin = optionButton.xMax - 64;
optionButton.center += Vector2.up * padding * 2f;
//Canceling isExpanded
if (ClickTest(optionButton))
{
ref bool isExpanded = ref expandMatrix.Down();
isExpanded = !isExpanded;
}
Color panelColor = SelectPanelColor(meta, index, total);
GUILayout.BeginVertical(UnityEditorUtility.GetStyle(panelColor, EscEditorConsts.COMPONENT_DRAWER_ALPHA));
EditorGUI.BeginChangeCheck();
////Close button
//optionButton.xMin = optionButton.xMax - HeadIconsRect.width;
//if (CloseButton(optionButton))
//{
// cmp.Del(worldID);
// return;
//}
//Edit script button
if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script))
{
optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
EcsGUI.ScriptAssetButton(optionButton, script);
}
//Description icon
if (string.IsNullOrEmpty(meta.Description.Text) == false)
{
optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DescriptionIcon(optionButton, meta.Description.Text);
}
RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name);
if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData))
{
cmp.SetRaw(worldID, resultData);
}
GUILayout.EndVertical();
}
}
}
}
2024-05-15 01:06:19 +08:00
#region entity bar
2024-05-13 19:20:07 +08:00
public static void EntityBarForAlive(EntityStatus status, int id, short gen, short world)
{
float width = EditorGUIUtility.currentViewWidth;
float height = EntityBarHeight;
EcsGUI.EntityBarForAlive(GUILayoutUtility.GetRect(width, height), status, id, gen, world);
}
public static void EntityBar(EntityStatus status, bool isPlaceholder, int id, short gen, short world)
{
float width = EditorGUIUtility.currentViewWidth;
float height = EntityBarHeight;
EcsGUI.EntityBar(GUILayoutUtility.GetRect(width, height), isPlaceholder, status, id, gen, world);
}
public static void EntityBar(int id, short gen, short world)
2024-03-09 09:42:04 +08:00
{
float width = EditorGUIUtility.currentViewWidth;
2024-03-09 22:36:35 +08:00
float height = EntityBarHeight;
2024-05-13 19:20:07 +08:00
EcsGUI.EntityBar(GUILayoutUtility.GetRect(width, height), id, gen, world);
2024-03-09 09:42:04 +08:00
}
2024-05-13 19:20:07 +08:00
public static void EntityBar()
{
float width = EditorGUIUtility.currentViewWidth;
float height = EntityBarHeight;
EcsGUI.EntityBar(GUILayoutUtility.GetRect(width, height));
}
2024-05-15 01:06:19 +08:00
#endregion
2024-05-13 19:20:07 +08:00
2024-09-12 01:35:37 +08:00
public static bool AddComponentButtons(out Rect dropDownRect)
2024-03-09 09:42:04 +08:00
{
2024-10-12 23:00:59 +08:00
return EcsGUI.AddComponentButton(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 24f), out dropDownRect);
2024-03-09 09:42:04 +08:00
}
2024-09-16 19:31:01 +08:00
public static AddClearButton AddClearComponentButtons(out Rect dropDownRect)
2024-03-04 08:21:01 +08:00
{
2024-10-12 23:00:59 +08:00
return EcsGUI.AddClearComponentButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 24f), out dropDownRect);
2024-03-04 08:21:01 +08:00
}
2024-09-16 19:31:01 +08:00
public static AddClearButton AddClearSystemButtons(out Rect dropDownRect)
{
2024-10-12 23:00:59 +08:00
return EcsGUI.AddClearSystemButtons(GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, 24f), out dropDownRect);
2024-09-16 19:31:01 +08:00
}
2024-03-07 03:18:00 +08:00
public static void DrawRuntimeComponents(entlong entity, bool isWithFoldout = true)
2024-03-03 19:59:39 +08:00
{
2024-03-28 23:24:39 +08:00
if (entity.TryUnpackForUnityEditor(out int entityID, out _, out _, out EcsWorld world))
2024-03-03 19:59:39 +08:00
{
2024-03-07 03:18:00 +08:00
DrawRuntimeComponents(entityID, world, isWithFoldout);
2024-03-03 19:59:39 +08:00
}
}
2024-10-03 08:20:46 +08:00
[ThreadStatic]
private static List<IEcsPool> _componentPoolsBuffer;
2024-03-07 03:18:00 +08:00
public static void DrawRuntimeComponents(int entityID, EcsWorld world, bool isWithFoldout = true)
2024-03-03 19:59:39 +08:00
{
2024-11-08 15:21:13 +08:00
using (BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)))
2024-03-03 19:59:39 +08:00
{
2024-10-02 14:29:27 +08:00
if (isWithFoldout)
2024-03-09 03:35:01 +08:00
{
2024-10-02 14:29:27 +08:00
IsShowRuntimeComponents = EditorGUILayout.BeginFoldoutHeaderGroup(IsShowRuntimeComponents, "RUNTIME COMPONENTS", EditorStyles.foldout);
EditorGUILayout.EndFoldoutHeaderGroup();
2024-03-09 03:35:01 +08:00
}
2024-10-02 14:29:27 +08:00
if (isWithFoldout == false || IsShowRuntimeComponents)
{
if (AddComponentButtons(out Rect dropDownRect))
{
RuntimeComponentsUtility.GetAddComponentGenericMenu(world).Open(dropDownRect, entityID);
}
2024-03-09 03:35:01 +08:00
2024-10-02 14:29:27 +08:00
GUILayout.Box("", UnityEditorUtility.GetStyle(GUI.color, 0.16f), GUILayout.ExpandWidth(true));
IsShowHidden = EditorGUI.Toggle(GUILayoutUtility.GetLastRect(), "Show Hidden", IsShowHidden);
2024-03-09 03:35:01 +08:00
2024-10-03 08:20:46 +08:00
if (_componentPoolsBuffer == null)
{
_componentPoolsBuffer = new List<IEcsPool>(64);
}
world.GetComponentPoolsFor(entityID, _componentPoolsBuffer);
2024-10-02 14:29:27 +08:00
int i = 0;
2024-11-08 15:21:13 +08:00
//int iMax = _componentPoolsBuffer.Count;
2024-10-03 08:20:46 +08:00
foreach (var componentPool in _componentPoolsBuffer)
2024-03-04 08:21:01 +08:00
{
2024-11-08 15:21:13 +08:00
DrawRuntimeComponent(entityID, componentPool, 9, i++);
2024-03-04 08:21:01 +08:00
}
2024-03-03 19:59:39 +08:00
}
}
}
2024-10-03 08:20:46 +08:00
private static void DrawRuntimeComponent(int entityID, IEcsPool pool, int total, int index)
2024-03-03 19:59:39 +08:00
{
2024-03-04 08:01:49 +08:00
var meta = pool.ComponentType.ToMeta();
if (meta.IsHidden == false || IsShowHidden)
2024-03-03 19:59:39 +08:00
{
2024-11-08 15:21:13 +08:00
Type componentType = pool.ComponentType;
2024-03-04 08:01:49 +08:00
object data = pool.GetRaw(entityID);
2024-05-15 01:06:19 +08:00
2024-06-15 18:43:29 +08:00
ExpandMatrix expandMatrix = ExpandMatrix.Take(componentType);
2024-03-07 21:22:48 +08:00
float padding = EditorGUIUtility.standardVerticalSpacing;
2024-06-15 16:53:28 +08:00
Rect optionButton = GUILayoutUtility.GetLastRect();
optionButton.yMin = optionButton.yMax;
optionButton.yMax += HeadIconsRect.height;
2024-06-15 18:43:29 +08:00
optionButton.xMin = optionButton.xMax - 64;
2024-06-15 16:53:28 +08:00
optionButton.center += Vector2.up * padding * 2f;
2024-06-15 19:30:59 +08:00
//Canceling isExpanded
2024-09-16 19:31:01 +08:00
if (ClickTest(optionButton))
2024-03-07 21:22:48 +08:00
{
2024-06-15 18:43:29 +08:00
ref bool isExpanded = ref expandMatrix.Down();
isExpanded = !isExpanded;
2024-03-07 21:22:48 +08:00
}
2024-11-08 15:21:13 +08:00
Color panelColor = SelectPanelColor(meta, index, total);
GUILayout.BeginVertical(UnityEditorUtility.GetStyle(panelColor, EscEditorConsts.COMPONENT_DRAWER_ALPHA));
2024-06-15 18:43:29 +08:00
EditorGUI.BeginChangeCheck();
2024-06-15 16:53:28 +08:00
2024-06-15 18:43:29 +08:00
//Close button
optionButton.xMin = optionButton.xMax - HeadIconsRect.width;
if (CloseButton(optionButton))
{
pool.Del(entityID);
return;
}
//Edit script button
2024-09-27 22:04:00 +08:00
if (ScriptsCache.TryGetScriptAsset(meta, out MonoScript script))
2024-06-15 16:53:28 +08:00
{
optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
2024-06-15 19:18:28 +08:00
EcsGUI.ScriptAssetButton(optionButton, script);
2024-06-15 16:53:28 +08:00
}
2024-06-15 18:43:29 +08:00
//Description icon
2024-05-01 15:02:54 +08:00
if (string.IsNullOrEmpty(meta.Description.Text) == false)
2024-03-09 09:42:04 +08:00
{
2024-06-15 16:53:28 +08:00
optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
DescriptionIcon(optionButton, meta.Description.Text);
2024-03-09 09:42:04 +08:00
}
2024-11-08 15:21:13 +08:00
RuntimeComponentReflectionCache.FieldInfoData componentInfoData = new RuntimeComponentReflectionCache.FieldInfoData(null, componentType, meta.Name);
if (DrawRuntimeData(ref componentInfoData, UnityEditorUtility.GetLabel(meta.Name), expandMatrix, data, out object resultData))
2024-06-15 18:43:29 +08:00
{
pool.SetRaw(entityID, resultData);
}
2024-03-04 08:01:49 +08:00
GUILayout.EndVertical();
}
2024-03-03 19:59:39 +08:00
}
2024-11-08 15:21:13 +08:00
[InitializeOnLoadMethod]
private static void ResetRuntimeComponentReflectionCache()
{
_runtimeComponentReflectionCaches.Clear();
}
private class RuntimeComponentReflectionCache
{
public readonly Type Type;
public readonly bool IsUnityObjectType;
public readonly bool IsUnitySerializable;
public readonly bool IsUnmanaged;
public readonly FieldInfoData[] Fields;
public readonly RefEditorWrapper Wrapper;
2024-03-03 19:59:39 +08:00
2024-11-08 15:21:13 +08:00
public RuntimeComponentReflectionCache(Type type)
{
Type = type;
IsUnmanaged = UnsafeUtility.IsUnmanaged(type);
IsUnityObjectType = typeof(UnityObject).IsAssignableFrom(type);
IsUnitySerializable = IsUnityObjectType || (!type.IsGenericType && type.IsSerializable);
Wrapper = RefEditorWrapper.Take();
if (type == typeof(void)) { return; }
if (IsUnitySerializable == false)
{
var fs = type.GetFields(fieldFlags);
Fields = new FieldInfoData[fs.Length];
for (int i = 0; i < fs.Length; i++)
{
var f = fs[i];
Fields[i] = new FieldInfoData(f);
}
}
}
public readonly struct FieldInfoData
{
public readonly FieldInfo FieldInfo;
public readonly Type FieldType;
public readonly string UnityFormatName;
public readonly bool IsUnityObjectField;
public FieldInfoData(FieldInfo fieldInfo)
{
FieldInfo = fieldInfo;
FieldType = fieldInfo.FieldType;
IsUnityObjectField = typeof(UnityObject).IsAssignableFrom(fieldInfo.FieldType);
UnityFormatName = UnityEditorUtility.TransformFieldName(fieldInfo.Name);
}
public FieldInfoData(FieldInfo fieldInfo, Type fieldType, string unityFormatName)
{
FieldInfo = fieldInfo;
FieldType = fieldType;
UnityFormatName = unityFormatName;
IsUnityObjectField = typeof(UnityObject).IsAssignableFrom(fieldType);
}
}
}
private static Dictionary<Type, RuntimeComponentReflectionCache> _runtimeComponentReflectionCaches = new Dictionary<Type, RuntimeComponentReflectionCache>();
private static RuntimeComponentReflectionCache GetRuntimeComponentReflectionCache(Type type)
{
if (_runtimeComponentReflectionCaches.TryGetValue(type, out RuntimeComponentReflectionCache result) == false)
{
result = new RuntimeComponentReflectionCache(type);
_runtimeComponentReflectionCaches.Add(type, result);
}
return result;
}
private static bool DrawRuntimeData(ref RuntimeComponentReflectionCache.FieldInfoData fieldInfoData, GUIContent label, ExpandMatrix expandMatrix, object data, out object outData)
2024-03-09 09:42:04 +08:00
{
2024-03-09 03:35:01 +08:00
outData = data;
Type type = data == null ? typeof(void) : data.GetType();
2024-03-09 09:42:04 +08:00
2024-11-08 15:21:13 +08:00
RuntimeComponentReflectionCache cache = GetRuntimeComponentReflectionCache(type);
2024-03-09 03:35:01 +08:00
2024-11-08 15:21:13 +08:00
bool isUnityObjectField = fieldInfoData.IsUnityObjectField;
if (isUnityObjectField == false && data == null)
2024-03-09 03:35:01 +08:00
{
EditorGUILayout.TextField(label, "Null");
return false;
}
2024-11-08 15:21:13 +08:00
bool isUnityObjectType = cache.IsUnityObjectType;
2024-03-04 03:00:45 +08:00
ref bool isExpanded = ref expandMatrix.Down();
2024-03-04 07:38:38 +08:00
bool changed = false;
2024-03-03 22:46:26 +08:00
2024-11-08 15:21:13 +08:00
if (cache.IsUnitySerializable == false)
2024-03-03 19:59:39 +08:00
{
2024-03-05 00:46:47 +08:00
isExpanded = EditorGUILayout.BeginFoldoutHeaderGroup(isExpanded, label, EditorStyles.foldout);
EditorGUILayout.EndFoldoutHeaderGroup();
2024-03-04 03:00:45 +08:00
if (isExpanded)
2024-03-03 19:59:39 +08:00
{
2024-10-03 08:20:46 +08:00
using (UpIndentLevel())
2024-03-03 19:59:39 +08:00
{
2024-11-08 15:21:13 +08:00
for (int j = 0, jMax = cache.Fields.Length; j < jMax; j++)
2024-03-03 22:46:26 +08:00
{
2024-11-08 15:21:13 +08:00
var field = cache.Fields[j];
if (DrawRuntimeData(ref field, UnityEditorUtility.GetLabel(field.UnityFormatName), expandMatrix, field.FieldInfo.GetValue(data), out object fieldData))
2024-10-03 08:20:46 +08:00
{
2024-11-08 15:21:13 +08:00
field.FieldInfo.SetValue(data, fieldData);
2024-10-03 08:20:46 +08:00
outData = data;
changed = true;
}
2024-03-03 22:46:26 +08:00
}
2024-03-03 19:59:39 +08:00
}
}
}
else
{
2024-11-08 15:21:13 +08:00
Type fieldType = fieldInfoData.FieldType;
if (isUnityObjectType || isUnityObjectField)
2024-03-05 03:35:38 +08:00
{
EditorGUI.BeginChangeCheck();
2024-11-08 15:21:13 +08:00
var uobj = UnsafeUtility.As<object, UnityObject>(ref data);
2024-03-07 03:18:00 +08:00
2024-05-16 19:59:57 +08:00
bool isComponent = typeof(UnityComponent).IsAssignableFrom(fieldType);
2024-03-07 03:18:00 +08:00
if (isComponent)
{
2024-05-16 19:59:57 +08:00
uobj = EditorGUILayout.ObjectField(label, uobj, typeof(UnityObject), true);
2024-03-07 03:18:00 +08:00
}
else
{
uobj = EditorGUILayout.ObjectField(label, uobj, fieldType, true);
}
2024-10-03 08:20:46 +08:00
2024-03-05 03:35:38 +08:00
if (EditorGUI.EndChangeCheck())
{
2024-11-08 15:21:13 +08:00
if (isComponent && uobj is GameObject go)
{
uobj = go.GetComponent(fieldType);
}
2024-03-05 03:35:38 +08:00
outData = uobj;
changed = true;
}
}
else
{
EditorGUI.BeginChangeCheck();
2024-11-08 15:21:13 +08:00
//WrapperBase wrapper = RefEditorWrapper.Take(data);
RefEditorWrapper wrapper = cache.Wrapper;
wrapper.data = data;
wrapper.SO.Update();
2024-03-03 19:59:39 +08:00
2024-11-08 15:21:13 +08:00
wrapper.IsExpanded = isExpanded;
try
{
EditorGUILayout.PropertyField(wrapper.Property, label, true);
}
catch (ArgumentException)
{
if (Event.current.type != EventType.Repaint)
{
throw;
}
}
2024-03-04 03:00:45 +08:00
2024-03-05 03:35:38 +08:00
if (EditorGUI.EndChangeCheck())
{
2024-11-08 15:21:13 +08:00
isExpanded = wrapper.IsExpanded;
wrapper.SO.ApplyModifiedProperties();
outData = wrapper.Data;
2024-03-05 03:35:38 +08:00
changed = true;
}
2024-11-08 15:21:13 +08:00
//wrapper.Release();
2024-03-03 19:59:39 +08:00
}
}
2024-03-06 21:37:21 +08:00
2024-03-04 07:38:38 +08:00
expandMatrix.Up();
return changed;
2024-03-03 19:59:39 +08:00
}
}
}
}
#endif