mirror of
https://github.com/DCFApixels/DragonECS-Unity.git
synced 2025-09-17 17:34:34 +08:00
1067 lines
44 KiB
C#
1067 lines
44 KiB
C#
#if UNITY_EDITOR
|
|
using DCFApixels.DragonECS.Unity.Internal;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using UnityEditor;
|
|
using UnityEditor.IMGUI.Controls;
|
|
using UnityEngine;
|
|
using Color = UnityEngine.Color;
|
|
|
|
namespace DCFApixels.DragonECS.Unity.Editors
|
|
{
|
|
internal static partial class EcsGUI
|
|
{
|
|
#region Scores
|
|
private static int _changedCounter = 0;
|
|
private static bool _changed = false;
|
|
private static bool _delayedChanged = false;
|
|
|
|
public static int ChangedCounter
|
|
{
|
|
get { return _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
|
|
{
|
|
private readonly float _value;
|
|
public LabelWidthScope(float value)
|
|
{
|
|
_value = EditorGUIUtility.labelWidth;
|
|
EditorGUIUtility.labelWidth = value;
|
|
}
|
|
public void Dispose() { EditorGUIUtility.labelWidth = _value; }
|
|
}
|
|
public struct ColorScope : IDisposable
|
|
{
|
|
private readonly Color _value;
|
|
public ColorScope(float r, float g, float b, float a = 1f) : this(new Color(r, g, b, a)) { }
|
|
public ColorScope(Color value)
|
|
{
|
|
_value = GUI.color;
|
|
GUI.color = value;
|
|
}
|
|
public void Dispose() { GUI.color = _value; }
|
|
}
|
|
public struct ContentColorScope : IDisposable
|
|
{
|
|
private readonly Color _value;
|
|
public ContentColorScope(float r, float g, float b, float a = 1f) : this(new Color(r, g, b, a)) { }
|
|
public ContentColorScope(Color value)
|
|
{
|
|
_value = GUI.contentColor;
|
|
GUI.contentColor = value;
|
|
}
|
|
public void Dispose() { GUI.contentColor = _value; }
|
|
}
|
|
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;
|
|
}
|
|
public void Dispose() { GUI.backgroundColor = _value; }
|
|
}
|
|
public struct IndentLevelScope : IDisposable
|
|
{
|
|
private readonly int _value;
|
|
public IndentLevelScope(int value)
|
|
{
|
|
_value = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel = value;
|
|
}
|
|
public void Dispose() { EditorGUI.indentLevel = _value; }
|
|
}
|
|
public struct AlignmentScope : IDisposable
|
|
{
|
|
public readonly GUIStyle Target;
|
|
private readonly TextAnchor _value;
|
|
public AlignmentScope(GUIStyle target, TextAnchor value)
|
|
{
|
|
Target = target;
|
|
_value = Target.alignment;
|
|
Target.alignment = value;
|
|
}
|
|
public AlignmentScope(GUIStyle target)
|
|
{
|
|
Target = target;
|
|
_value = Target.alignment;
|
|
}
|
|
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; }
|
|
}
|
|
|
|
|
|
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 VerticalScope(Color backgroundColor, GUILayoutOption[] options)
|
|
{
|
|
using (SetColor(backgroundColor))
|
|
{
|
|
GUILayout.BeginVertical(UnityEditorUtility.GetWhiteStyle(), 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 HorizontalScope(Color backgroundColor, GUILayoutOption[] options)
|
|
{
|
|
using (SetColor(backgroundColor))
|
|
{
|
|
GUILayout.BeginHorizontal(UnityEditorUtility.GetWhiteStyle(), 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 ScrollViewScope BeginScrollView(ref Vector2 pos, params GUILayoutOption[] options) => new ScrollViewScope(ref pos, options);
|
|
public static ScrollViewScope BeginScrollView(ref Vector2 pos, GUIStyle style, params GUILayoutOption[] options) => new ScrollViewScope(ref pos, style, options);
|
|
public static HorizontalScope BeginHorizontal() => new HorizontalScope(Array.Empty<GUILayoutOption>());
|
|
public static HorizontalScope BeginHorizontal(params GUILayoutOption[] options) => new HorizontalScope(options);
|
|
public static HorizontalScope BeginHorizontal(GUIStyle style, params GUILayoutOption[] options) => new HorizontalScope(style, options);
|
|
public static HorizontalScope BeginHorizontal(Color backgroundColor, params GUILayoutOption[] options) => new HorizontalScope(backgroundColor, options);
|
|
public static VerticalScope BeginVertical() => new VerticalScope(Array.Empty<GUILayoutOption>());
|
|
public static VerticalScope BeginVertical(params GUILayoutOption[] options) => new VerticalScope(options);
|
|
public static VerticalScope BeginVertical(GUIStyle style, params GUILayoutOption[] options) => new VerticalScope(style, options);
|
|
public static VerticalScope BeginVertical(Color backgroundColor, params GUILayoutOption[] options) => new VerticalScope(backgroundColor, 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);
|
|
public static FontStyleScope SetFontStyle(GUIStyle target, FontStyle value) => new FontStyleScope(target, value);
|
|
public static FontStyleScope SetFontStyle(FontStyle value) => new FontStyleScope(GUI.skin.label, value);
|
|
public static FontStyleScope SetFontStyle(GUIStyle target) => new FontStyleScope(target);
|
|
public static FontSizeScope SetFontSize(GUIStyle target, int value) => new FontSizeScope(target, value);
|
|
public static FontSizeScope SetFontSize(int value) => new FontSizeScope(GUI.skin.label, value);
|
|
public static FontSizeScope SetFontSize(GUIStyle target) => new FontSizeScope(target);
|
|
public static AlignmentScope SetAlignment(GUIStyle target, TextAnchor value) => new AlignmentScope(target, value);
|
|
public static AlignmentScope SetAlignment(TextAnchor value) => new AlignmentScope(GUI.skin.label, value);
|
|
public static AlignmentScope SetAlignment(GUIStyle target) => new AlignmentScope(target);
|
|
public static IndentLevelScope SetIndentLevel(int level) => new IndentLevelScope(level);
|
|
public static IndentLevelScope UpIndentLevel() => new IndentLevelScope(EditorGUI.indentLevel + 1);
|
|
public static ContentColorScope SetContentColor(Color value) => new ContentColorScope(value);
|
|
public static ContentColorScope SetContentColor(Color value, float a) => new ContentColorScope(value.r, value.g, value.b, a);
|
|
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);
|
|
public static BackgroundColorScope SetBackgroundColor(Color value, float a) => new BackgroundColorScope(value.r, value.g, value.b, a);
|
|
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);
|
|
public static ColorScope SetColor(Color value, float a) => new ColorScope(value.a, value.g, value.b, a);
|
|
public static ColorScope SetColor(float r, float g, float b, float a = 1f) => new ColorScope(r, g, b, a);
|
|
public static ColorScope SetAlpha(float a) => new ColorScope(GUI.color * new Color(1, 1, 1, a));
|
|
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
|
|
|
|
private static readonly BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
|
|
|
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);
|
|
|
|
private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f);
|
|
|
|
public static float EntityBarHeight => EditorGUIUtility.singleLineHeight + 3f;
|
|
|
|
private static float indent => (float)EditorGUI.indentLevel * 15f;
|
|
private static float indentLevel => EditorGUI.indentLevel;
|
|
|
|
#region Properties
|
|
private static ComponentColorMode AutoColorMode
|
|
{
|
|
get { return UserSettingsPrefs.instance.ComponentColorMode; }
|
|
set { UserSettingsPrefs.instance.ComponentColorMode = value; }
|
|
}
|
|
private static bool IsShowHidden
|
|
{
|
|
get { return UserSettingsPrefs.instance.IsShowHidden; }
|
|
set { UserSettingsPrefs.instance.IsShowHidden = value; }
|
|
}
|
|
private static bool IsShowRuntimeComponents
|
|
{
|
|
get { return UserSettingsPrefs.instance.IsShowRuntimeComponents; }
|
|
set { UserSettingsPrefs.instance.IsShowRuntimeComponents = value; }
|
|
}
|
|
//private static bool IsFastModeRuntimeComponents
|
|
//{
|
|
// get { return UserSettingsPrefs.instance.IsFastModeRuntimeComponents; }
|
|
// set { UserSettingsPrefs.instance.IsFastModeRuntimeComponents = value; }
|
|
//}
|
|
private static float OneLineHeight
|
|
{
|
|
get => EditorGUIUtility.singleLineHeight;
|
|
}
|
|
private static float Spacing
|
|
{
|
|
get => EditorGUIUtility.standardVerticalSpacing;
|
|
}
|
|
#endregion
|
|
|
|
#region enums
|
|
public enum AddClearButton : byte
|
|
{
|
|
None = 0,
|
|
Add = 1,
|
|
Clear = 2,
|
|
}
|
|
[Flags]
|
|
public enum EntityStatus : byte
|
|
{
|
|
NotAlive = 0,
|
|
Alive = 1 << 0,
|
|
Undefined = 1 << 1,
|
|
}
|
|
#endregion
|
|
|
|
#region HitTest/ClickTest
|
|
internal static bool HitTest(Rect rect)
|
|
{
|
|
return HitTest(rect, Event.current.mousePosition);
|
|
}
|
|
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;
|
|
}
|
|
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;
|
|
}
|
|
#endregion
|
|
|
|
#region small elems
|
|
public static void DrawIcon(Rect position, Texture icon, float iconPadding, string description)
|
|
{
|
|
if (position.width != position.height)
|
|
{
|
|
Vector2 center = position.center;
|
|
float size = Mathf.Min(position.width, position.height);
|
|
position.height = size;
|
|
position.width = size;
|
|
position.center = center;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
public static (bool, bool) IconButtonGeneric(Rect position)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
public static bool IconButton(Rect position, Texture icon, float iconPadding, string description)
|
|
{
|
|
bool result = GUI.Button(position, UnityEditorUtility.GetLabel(string.Empty));
|
|
DrawIcon(position, icon, iconPadding, description);
|
|
return result;
|
|
}
|
|
public static void DescriptionIcon(Rect position, string description)
|
|
{
|
|
using (new ColorScope(new Color(1f, 1f, 1f, 0.8f)))
|
|
{
|
|
DrawIcon(position, Icons.Instance.HelpIcon, 0, description);
|
|
}
|
|
}
|
|
|
|
|
|
public static void ScriptAssetButton(Rect position, MonoScript script)
|
|
{
|
|
var current = Event.current;
|
|
var hover = IconHoverScan(position, current);
|
|
if (GUI.enabled)
|
|
{
|
|
using (SetColor(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)
|
|
{
|
|
EditorGUIUtility.PingObject(script);
|
|
}
|
|
else if (current.type == EventType.MouseDown && current.clickCount >= 2)
|
|
{
|
|
//UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(); //TODO
|
|
AssetDatabase.OpenAsset(script);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using (SetColor(0.85f, 0.85f, 0.85f, 0.7f))
|
|
{
|
|
DrawIcon(position, Icons.Instance.FileIcon, 2f, "One click - Ping File. Double click - Edit Script");
|
|
}
|
|
}
|
|
}
|
|
public static bool CloseButton(Rect position, string description = null)
|
|
{
|
|
using (new ColorScope(new Color(1f, 1f, 1f, 0.8f)))
|
|
{
|
|
var (hover, click) = IconButtonGeneric(position);
|
|
if (hover)
|
|
{
|
|
DrawIcon(position, Icons.Instance.CloseIconOn, -4f, description);
|
|
}
|
|
else
|
|
{
|
|
DrawIcon(position, Icons.Instance.CloseIcon, 0, description);
|
|
}
|
|
return click;
|
|
}
|
|
}
|
|
|
|
public static bool NewEntityButton(Rect position)
|
|
{
|
|
return IconButton(position, Icons.Instance.PassIcon, 2f, "Create entity");
|
|
}
|
|
public static bool ValidateButton(Rect position)
|
|
{
|
|
return IconButton(position, Icons.Instance.RepaireIcon, 2f, "Validate");
|
|
}
|
|
public static bool AutosetCascadeButton(Rect position)
|
|
{
|
|
return IconButton(position, Icons.Instance.AutosetCascadeIcon, 0f, "Autoset Cascade");
|
|
}
|
|
public static bool AutosetButton(Rect position)
|
|
{
|
|
return IconButton(position, Icons.Instance.AuotsetIcon, 1f, "Autoset");
|
|
}
|
|
public static bool UnlinkButton(Rect position)
|
|
{
|
|
return IconButton(position, Icons.Instance.UnlinkIcon, 1f, "Unlink Entity");
|
|
}
|
|
public static bool DelEntityButton(Rect position)
|
|
{
|
|
return IconButton(position, Icons.Instance.CloseIcon, 0f, "Delete Entity");
|
|
}
|
|
#endregion
|
|
|
|
#region entity bar
|
|
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))
|
|
{
|
|
var (entityInfoRect, statusRect) = RectUtility.VerticalSliceBottom(position, 3f);
|
|
|
|
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;
|
|
}
|
|
|
|
statusColor.a = 0.6f;
|
|
EditorGUI.DrawRect(statusRect, statusColor);
|
|
|
|
EntityBar_Internal(entityInfoRect, isPlaceholder, id, gen, world);
|
|
}
|
|
}
|
|
private static void EntityBar_Internal(Rect position, bool isPlaceHolder, int id = 0, short gen = 0, short world = 0)
|
|
{
|
|
using (SetLabelWidth(0f))
|
|
{
|
|
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();
|
|
|
|
if (isPlaceHolder)
|
|
{
|
|
using (new EditorGUI.DisabledScope(true))
|
|
{
|
|
GUI.Label(idRect, "Entity ID", style);
|
|
using (SetAlpha(0.85f))
|
|
{
|
|
GUI.Label(genRect, "Generation", style);
|
|
GUI.Label(worldRect, "World ID", style);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EditorGUI.IntField(idRect, id, style);
|
|
using (SetAlpha(0.85f))
|
|
{
|
|
EditorGUI.IntField(genRect, gen, style);
|
|
EditorGUI.IntField(worldRect, world, style);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#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;
|
|
}
|
|
public static bool DrawTypeMetaElementBlock(ref Rect position, SerializedProperty arrayProperty, int elementIndex, SerializedProperty elementRootProperty, ITypeMeta meta)
|
|
{
|
|
var result = DrawTypeMetaBlock_Internal(ref position, elementRootProperty, meta, elementIndex, arrayProperty.arraySize);
|
|
if (result.HasFlag(DrawTypeMetaBlockResult.CloseButtonClicked))
|
|
{
|
|
arrayProperty.DeleteArrayElementAtIndex(elementIndex);
|
|
}
|
|
return result != DrawTypeMetaBlockResult.None;
|
|
}
|
|
public static bool DrawTypeMetaBlock(ref Rect position, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1)
|
|
{
|
|
var result = DrawTypeMetaBlock_Internal(ref position, rootProperty, meta, index, total);
|
|
if (result.HasFlag(DrawTypeMetaBlockResult.CloseButtonClicked))
|
|
{
|
|
rootProperty.ResetValues();
|
|
}
|
|
return result.HasFlag(DrawTypeMetaBlockResult.Drop);
|
|
}
|
|
|
|
private enum DrawTypeMetaBlockResult
|
|
{
|
|
None = 0,
|
|
Drop = 1 << 0,
|
|
CloseButtonClicked = 1 << 1,
|
|
}
|
|
private static DrawTypeMetaBlockResult DrawTypeMetaBlock_Internal(ref Rect position, SerializedProperty rootProperty, ITypeMeta meta, int index = -1, int total = -1)
|
|
{
|
|
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;
|
|
|
|
int positionIndex;
|
|
if (index < 0)
|
|
{
|
|
positionIndex = int.MaxValue;
|
|
var counter = rootProperty.Copy();
|
|
int depth = -1;
|
|
while (counter.NextVisibleDepth(false, ref depth))
|
|
{
|
|
positionIndex--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
positionIndex = index;
|
|
}
|
|
|
|
alphaPanelColor = SelectPanelColor(meta, positionIndex, total).Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE).SetAlpha(EscEditorConsts.COMPONENT_DRAWER_ALPHA);
|
|
|
|
DrawTypeMetaBlockResult result = DrawTypeMetaBlockResult.None;
|
|
using (CheckChanged())
|
|
{
|
|
EditorGUI.DrawRect(position, alphaPanelColor);
|
|
|
|
Rect optionButton = position;
|
|
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;
|
|
optionButton.center += Vector2.up * DrawTypeMetaBlockPadding;
|
|
|
|
//Canceling isExpanded
|
|
bool oldIsExpanded = rootProperty.isExpanded;
|
|
if (ClickTest(optionButton))
|
|
{
|
|
rootProperty.isExpanded = oldIsExpanded;
|
|
result |= DrawTypeMetaBlockResult.Drop;
|
|
}
|
|
|
|
//Close button
|
|
optionButton.xMin = optionButton.xMax - HeadIconsRect.width;
|
|
if (CloseButton(optionButton))
|
|
{
|
|
result |= DrawTypeMetaBlockResult.CloseButtonClicked;
|
|
return result;
|
|
}
|
|
//Edit script button
|
|
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);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
#endregion
|
|
|
|
#region NextDepth/GetChildPropertiesCount
|
|
internal static bool NextVisibleDepth(this SerializedProperty property, bool child, ref int depth)
|
|
{
|
|
if (depth < 0)
|
|
{
|
|
depth = property.depth;
|
|
}
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
var propsCounter = property.Copy();
|
|
int lastDepth = propsCounter.depth;
|
|
bool next = propsCounter.Next(true) && lastDepth < propsCounter.depth;
|
|
int result = 0;
|
|
while (next)
|
|
{
|
|
result++;
|
|
next = propsCounter.Next(true);
|
|
}
|
|
return result;
|
|
}
|
|
#endregion
|
|
|
|
#region SelectPanelColor
|
|
public static Color SelectPanelColor(ITypeMeta meta, int index, int total)
|
|
{
|
|
var trueMeta = meta.Type.ToMeta();
|
|
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)
|
|
{
|
|
return color.ToUnityColor();
|
|
}
|
|
else
|
|
{
|
|
switch (AutoColorMode)
|
|
{
|
|
case ComponentColorMode.Auto:
|
|
return color.ToUnityColor().Desaturate(0.48f) / 1.18f; //.Desaturate(0.48f) / 1.18f;
|
|
case ComponentColorMode.Rainbow:
|
|
int localTotal = Mathf.Max(total, EscEditorConsts.AUTO_COLOR_RAINBOW_MIN_RANGE);
|
|
Color hsv = Color.HSVToRGB(1f / localTotal * (index % localTotal), 1, 1);
|
|
return hsv.Desaturate(0.48f) / 1.18f;
|
|
default:
|
|
return GetGenericPanelColor(index);
|
|
}
|
|
}
|
|
}
|
|
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
|
|
public static void ManuallySerializeButton(Rect position, UnityEngine.Object obj)
|
|
{
|
|
if (GUI.Button(position, UnityEditorUtility.GetLabel("Manually serialize")))
|
|
{
|
|
var so = new SerializedObject(obj);
|
|
EditorUtility.SetDirty(obj);
|
|
so.UpdateIfRequiredOrScript();
|
|
so.ApplyModifiedProperties();
|
|
AssetDatabase.SaveAssets();
|
|
AssetDatabase.Refresh();
|
|
}
|
|
}
|
|
public static bool AddComponentButton(Rect position, out Rect dropDownRect)
|
|
{
|
|
dropDownRect = RectUtility.AddPadding(position, 20f, 20f, 1f, 1f); ;
|
|
return GUI.Button(dropDownRect, "Add Component");
|
|
}
|
|
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)
|
|
{
|
|
position = RectUtility.AddPadding(position, 20f, 20f, 1f, 1f);
|
|
var (left, right) = RectUtility.HorizontalSliceLerp(position, 0.75f);
|
|
|
|
dropDownRect = left;
|
|
|
|
if (GUI.Button(left, addText))
|
|
{
|
|
return AddClearButton.Add;
|
|
}
|
|
if (GUI.Button(right, clearText))
|
|
{
|
|
return AddClearButton.Clear;
|
|
}
|
|
return AddClearButton.None;
|
|
}
|
|
|
|
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)
|
|
{
|
|
EditorGUI.LabelField(position, label);
|
|
if (isDisplayEmpty)
|
|
{
|
|
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
|
|
|
|
#region SerializeReference utils
|
|
|
|
private static Dictionary<PredicateTypesKey, ReferenceDropDown> _predicatTypesMenus = new Dictionary<PredicateTypesKey, ReferenceDropDown>();
|
|
[ThreadStatic]
|
|
private static SerializedProperty _currentProperty;
|
|
|
|
#region Init
|
|
private static ReferenceDropDown GetReferenceDropDown(Type[] predicatTypes, Type[] sortedWithOutTypes)
|
|
{
|
|
if (_predicatTypesMenus.TryGetValue((predicatTypes, sortedWithOutTypes), out ReferenceDropDown menu) == false)
|
|
{
|
|
menu = new ReferenceDropDown(predicatTypes, sortedWithOutTypes);
|
|
menu.OnSelected += SelectComponent;
|
|
_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;
|
|
public readonly Type[] withoutTypes;
|
|
public PredicateTypesKey(Type[] types, Type[] withoutTypes)
|
|
{
|
|
this.types = types;
|
|
this.withoutTypes = withoutTypes;
|
|
}
|
|
public bool Equals(PredicateTypesKey other)
|
|
{
|
|
if (types.Length != other.types.Length) { return false; }
|
|
if (withoutTypes.Length != other.withoutTypes.Length) { return false; }
|
|
for (int i = 0; i < types.Length; i++)
|
|
{
|
|
if (types[i] != other.types[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
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);
|
|
}
|
|
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;
|
|
public readonly Type[] WithOutTypes;
|
|
public ReferenceDropDown(Type[] predicateTypes, Type[] withOutTypes) : base(new AdvancedDropdownState())
|
|
{
|
|
PredicateTypes = predicateTypes;
|
|
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>();
|
|
|
|
foreach (var type in UnityEditorUtility._serializableTypes)
|
|
{
|
|
bool isAssignable = false;
|
|
foreach (Type predicateTypes in PredicateTypes)
|
|
{
|
|
if (predicateTypes.IsAssignableFrom(type))
|
|
{
|
|
isAssignable = true;
|
|
break;
|
|
}
|
|
}
|
|
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
|
|
|
|
public static void DrawSelectReferenceButton(Rect position, SerializedProperty property, Type[] sortedPredicateTypes, Type[] sortedWithOutTypes, bool isHideButtonIfNotNull)
|
|
{
|
|
object obj = property.hasMultipleDifferentValues ? null : property.managedReferenceValue;
|
|
|
|
string text = obj == null ? "Select..." : obj.GetMeta().Name;
|
|
if (!isHideButtonIfNotNull || obj == null)
|
|
{
|
|
if (GUI.Button(position, text, EditorStyles.layerMaskField))
|
|
{
|
|
DrawSelectReferenceMenu(position, property, sortedPredicateTypes, sortedWithOutTypes);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GUI.Label(position, text);
|
|
}
|
|
}
|
|
public static void DrawSelectReferenceMenu(Rect position, SerializedProperty property, Type[] sortedPredicateTypes, Type[] sortedWithOutTypes)
|
|
{
|
|
_currentProperty = property;
|
|
GetReferenceDropDown(sortedPredicateTypes, sortedWithOutTypes).Show(position);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
#endif |