DragonECS-Unity/src/Templates/EntityTemplate/Editor/EntityTemplateEditor.cs

376 lines
15 KiB
C#
Raw Normal View History

2024-03-07 03:18:00 +08:00
#if UNITY_EDITOR
using DCFApixels.DragonECS.Unity.Internal;
2024-03-03 03:51:49 +08:00
using System;
using System.Reflection;
2024-03-07 03:18:00 +08:00
using UnityEditor;
2024-09-27 22:04:00 +08:00
using UnityEditorInternal;
2024-03-07 03:18:00 +08:00
using UnityEngine;
2024-03-03 03:51:49 +08:00
namespace DCFApixels.DragonECS.Unity.Editors
{
internal abstract class EntityTemplateEditorBase<T> : ExtendedEditor<ITemplateInternal>
2024-03-03 03:51:49 +08:00
{
2024-05-16 19:03:03 +08:00
private static readonly Rect HeadIconsRect = new Rect(0f, 0f, 19f, 19f);
2024-03-03 03:51:49 +08:00
2024-09-12 01:35:37 +08:00
private ComponentDropDown _componentDropDown;
2024-03-03 03:51:49 +08:00
2024-09-27 22:04:00 +08:00
private SerializedProperty _componentsProp;
private ReorderableList _reorderableComponentsList;
2024-05-15 00:36:56 +08:00
2024-03-03 03:51:49 +08:00
#region Init
2024-09-29 15:59:14 +08:00
protected override bool IsInit { get { return _componentDropDown != null; } }
protected override void OnInit()
2024-03-03 03:51:49 +08:00
{
2024-09-12 01:35:37 +08:00
_componentDropDown = new ComponentDropDown();
2024-09-27 22:04:00 +08:00
_componentsProp = serializedObject.FindProperty(Target.ComponentsPropertyName);
_reorderableComponentsList = new ReorderableList(serializedObject, _componentsProp, true, false, false, false);
_reorderableComponentsList.onAddCallback += OnReorderableComponentsListAdd;
_reorderableComponentsList.onRemoveCallback += OnReorderableListRemove;
_reorderableComponentsList.drawElementCallback += OnReorderableListDrawEmptyElement;
_reorderableComponentsList.drawElementBackgroundCallback += OnReorderableComponentsListDrawElement;
_reorderableComponentsList.drawNoneElementCallback += OnReorderableComponentsListDrawNoneElement;
_reorderableComponentsList.elementHeightCallback += OnReorderableComponentsListElementHeight;
_reorderableComponentsList.onReorderCallback += OnReorderableListReorder;
_reorderableComponentsList.showDefaultBackground = false;
_reorderableComponentsList.footerHeight = 0f;
_reorderableComponentsList.headerHeight = 0f;
_reorderableComponentsList.elementHeight = 0f;
}
#region ReorderableComponentsList
private void OnReorderableComponentsListDrawNoneElement(Rect rect) { }
private void OnReorderableListDrawEmptyElement(Rect rect, int index, bool isActive, bool isFocused) { }
private void OnReorderableListReorder(ReorderableList list)
{
EcsGUI.Changed = true;
}
private SerializedProperty GetTargetProperty(SerializedProperty prop)
{
IComponentTemplate template = prop.managedReferenceValue as IComponentTemplate;
if (template == null || prop.managedReferenceValue == null)
{
//DrawDamagedComponent_Replaced(componentRefProp, index);
return prop;
}
SerializedProperty componentProperty = prop;
try
{
if (componentProperty.managedReferenceValue is ComponentTemplateBase customTemplate)
{
componentProperty = prop.FindPropertyRelative("component");
}
if (componentProperty == null)
{
throw new NullReferenceException();
}
}
catch (Exception e)
{
Debug.LogException(e, serializedObject.targetObject);
//DrawDamagedComponent(index, "Damaged component template.");
return prop;
}
return componentProperty;
}
private float OnReorderableComponentsListElementHeight(int index)
{
var componentProperty = GetTargetProperty(_componentsProp.GetArrayElementAtIndex(index));
float result = EditorGUI.GetPropertyHeight(componentProperty);
return EcsGUI.GetTypeMetaBlockHeight(result) + Spacing * 2f;
}
private void OnReorderableComponentsListDrawElement(Rect rect, int index, bool isActive, bool isFocused)
{
if (index < 0 || Event.current.type == EventType.Used) { return; }
rect = rect.AddPadding(OneLineHeight + Spacing, Spacing * 2f, Spacing, Spacing);
using (EcsGUI.CheckChanged())
{
SerializedProperty prop = _componentsProp.GetArrayElementAtIndex(index);
IComponentTemplate template = prop.managedReferenceValue as IComponentTemplate;
if (template == null || prop.managedReferenceValue == null)
{
DrawDamagedComponent_Replaced(prop, index);
return;
}
var componentProp = GetTargetProperty(prop);
ITypeMeta meta = template is ITypeMeta metaOverride ? metaOverride : template.Type.ToMeta();
if (EcsGUI.DrawTypeMetaElementBlock(ref rect, _componentsProp, index, componentProp, meta))
{
return;
}
GUIContent label = UnityEditorUtility.GetLabel(meta.Name);
if (componentProp.propertyType == SerializedPropertyType.Generic)
{
EditorGUI.PropertyField(rect, componentProp, label, true);
}
else
{
EditorGUI.PropertyField(rect.AddPadding(0, 20f, 0, 0), componentProp, label, true);
}
}
}
private void OnReorderableComponentsListAdd(ReorderableList list)
{
list.serializedProperty.arraySize += 1;
list.serializedProperty.GetArrayElementAtIndex(list.serializedProperty.arraySize - 1).ResetValues();
EcsGUI.Changed = true;
}
private void OnReorderableListRemove(ReorderableList list)
{
if (list.selectedIndices.Count <= 0)
{
if (list.serializedProperty.arraySize > 0)
{
list.serializedProperty.DeleteArrayElementAtIndex(list.serializedProperty.arraySize - 1);
}
return;
}
for (int i = list.selectedIndices.Count - 1; i >= 0; i--)
{
list.serializedProperty.DeleteArrayElementAtIndex(list.selectedIndices[i]);
}
EcsGUI.Changed = true;
2024-03-03 03:51:49 +08:00
}
#endregion
2024-09-27 22:04:00 +08:00
#endregion
2024-03-03 03:51:49 +08:00
#region Add/Remove
private void OnRemoveComponentAt(int index)
{
if (this.target is ITemplateInternal target)
{
SerializedProperty componentsProp = serializedObject.FindProperty(target.ComponentsPropertyName);
componentsProp.DeleteArrayElementAtIndex(index);
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(this.target);
}
}
#endregion
2024-09-27 22:04:00 +08:00
protected override void DrawCustom()
2024-03-03 03:51:49 +08:00
{
Init();
2024-09-27 22:04:00 +08:00
if (_componentsProp == null)
2024-03-05 00:46:47 +08:00
{
2024-03-03 03:51:49 +08:00
return;
2024-03-05 00:46:47 +08:00
}
2024-03-03 03:51:49 +08:00
2024-10-01 18:04:53 +08:00
if (IsMultipleTargets == false && SerializationUtility.HasManagedReferencesWithMissingTypes(target))
{
using (EcsGUI.Layout.BeginHorizontal(EditorStyles.helpBox))
{
GUILayout.Label(UnityEditorUtility.GetLabel(Icons.Instance.WarningIcon), GUILayout.ExpandWidth(false));
using (EcsGUI.Layout.BeginVertical())
{
GUILayout.Label("This object contains SerializeReference types which are missing.", EditorStyles.miniLabel);
if (GUILayout.Button("Repaire References Tool", EditorStyles.miniButton, GUILayout.MaxWidth(200f)))
{
RefRepairerWindow.Open();
}
}
}
}
2024-09-16 19:31:01 +08:00
using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetStyle(Color.black, 0.2f)))
2024-03-03 03:51:49 +08:00
{
2024-09-27 22:04:00 +08:00
DrawTop(Target, _componentsProp);
_reorderableComponentsList.DoLayoutList();
2024-10-01 18:04:53 +08:00
2024-03-03 03:51:49 +08:00
}
}
2024-09-16 19:31:01 +08:00
private void DrawTop(ITemplateInternal target, SerializedProperty componentsProp)
2024-03-03 03:51:49 +08:00
{
2024-09-12 01:35:37 +08:00
switch (EcsGUI.Layout.AddClearComponentButtons(out Rect rect))
2024-03-03 03:51:49 +08:00
{
2024-09-16 19:31:01 +08:00
case EcsGUI.AddClearButton.Add:
2024-03-09 03:35:01 +08:00
Init();
2024-09-16 19:31:01 +08:00
_componentDropDown.OpenForArray(rect, componentsProp, true);
2024-03-09 03:35:01 +08:00
break;
2024-09-16 19:31:01 +08:00
case EcsGUI.AddClearButton.Clear:
2024-03-09 03:35:01 +08:00
Init();
2024-09-27 22:04:00 +08:00
componentsProp.ClearArray();
2024-03-09 03:35:01 +08:00
serializedObject.ApplyModifiedProperties();
break;
2024-03-03 03:51:49 +08:00
}
}
2024-03-09 03:35:01 +08:00
2024-05-15 00:36:56 +08:00
private void DrawComponentData(SerializedProperty componentRefProp, int total, int index)
2024-03-03 03:51:49 +08:00
{
IComponentTemplate template = componentRefProp.managedReferenceValue as IComponentTemplate;
2024-03-09 03:35:01 +08:00
if (template == null || componentRefProp.managedReferenceValue == null)
2024-03-03 03:51:49 +08:00
{
2024-05-15 00:36:56 +08:00
DrawDamagedComponent_Replaced(componentRefProp, index);
2024-03-03 03:51:49 +08:00
return;
}
Type componentType;
SerializedProperty componentProperty = componentRefProp;
2024-05-15 00:36:56 +08:00
try
2024-03-03 03:51:49 +08:00
{
2024-05-15 00:36:56 +08:00
ComponentTemplateBase customTemplate = componentProperty.managedReferenceValue as ComponentTemplateBase;
if (customTemplate != null)
{
componentProperty = componentRefProp.FindPropertyRelative("component");
componentType = customTemplate.GetType().GetField("component", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FieldType;
}
else
{
componentType = componentProperty.managedReferenceValue.GetType();
}
if (componentType == null || componentProperty == null)
{
throw new NullReferenceException();
}
2024-03-03 03:51:49 +08:00
}
2024-05-15 00:36:56 +08:00
catch (Exception e)
2024-03-03 03:51:49 +08:00
{
2024-05-15 00:36:56 +08:00
Debug.LogException(e, serializedObject.targetObject);
DrawDamagedComponent(index, "Damaged component template.");
return;
2024-03-03 03:51:49 +08:00
}
2024-03-07 03:18:00 +08:00
2024-05-15 00:36:56 +08:00
//сюда попадают уже валидные компоненты
2024-03-06 23:29:54 +08:00
ITypeMeta meta = template is ITypeMeta metaOverride ? metaOverride : template.Type.ToMeta();
string name = meta.Name;
2024-05-01 15:02:54 +08:00
string description = meta.Description.Text;
2024-03-03 03:51:49 +08:00
2024-05-16 19:03:03 +08:00
int propCount = EcsGUI.GetChildPropertiesCount(componentProperty, componentType, out bool isEmpty);
2024-03-05 00:46:47 +08:00
float padding = EditorGUIUtility.standardVerticalSpacing;
2024-05-15 00:36:56 +08:00
2024-05-16 19:03:03 +08:00
Color panelColor = EcsGUI.SelectPanelColor(meta, index, total).Desaturate(EscEditorConsts.COMPONENT_DRAWER_DESATURATE);
2024-05-15 00:36:56 +08:00
2024-03-05 00:46:47 +08:00
Color alphaPanelColor = panelColor;
alphaPanelColor.a = EscEditorConsts.COMPONENT_DRAWER_ALPHA;
2024-06-15 16:53:28 +08:00
Rect optionButton = GUILayoutUtility.GetLastRect();
2024-06-15 18:43:29 +08:00
optionButton.yMin = optionButton.yMax;
optionButton.yMax += HeadIconsRect.height;
optionButton.xMin = optionButton.xMax - 64;
optionButton.center += Vector2.up * padding * 2f;
2024-09-16 19:31:01 +08:00
bool cancelExpanded = EcsGUI.ClickTest(optionButton);
2024-03-07 21:22:48 +08:00
2024-09-16 19:31:01 +08:00
#region Draw Component Block
using (EcsGUI.CheckChanged()) using (EcsGUI.Layout.BeginVertical(UnityEditorUtility.GetStyle(alphaPanelColor)))
2024-06-15 18:43:29 +08:00
{
//Close button
optionButton.xMin = optionButton.xMax - HeadIconsRect.width;
if (EcsGUI.CloseButton(optionButton))
2024-05-05 00:59:26 +08:00
{
OnRemoveComponentAt(index);
return;
}
//Canceling isExpanded
if (cancelExpanded)
{
componentProperty.isExpanded = !componentProperty.isExpanded;
}
//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));
EcsGUI.ScriptAssetButton(optionButton, script);
}
//Description icon
if (string.IsNullOrEmpty(description) == false)
{
optionButton = HeadIconsRect.MoveTo(optionButton.center - (Vector2.right * optionButton.width));
EcsGUI.DescriptionIcon(optionButton, description);
}
if (propCount <= 0)
{
EcsGUI.Layout.DrawEmptyComponentProperty(componentRefProp, name, isEmpty);
2024-05-05 00:59:26 +08:00
}
else
{
GUIContent label = UnityEditorUtility.GetLabel(name);
if (componentProperty.propertyType == SerializedPropertyType.Generic)
{
EditorGUILayout.PropertyField(componentProperty, label, true);
}
else
{
Rect r = RectUtility.AddPadding(GUILayoutUtility.GetRect(label, EditorStyles.objectField), 0, 20f, 0, 0);
EditorGUI.PropertyField(r, componentProperty, label, true);
}
2024-05-05 00:59:26 +08:00
}
2024-03-09 09:42:04 +08:00
if (EcsGUI.Changed)
{
componentProperty.serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(componentProperty.serializedObject.targetObject);
}
2024-03-05 00:46:47 +08:00
}
2024-09-16 19:31:01 +08:00
#endregion
2024-03-03 03:51:49 +08:00
}
2024-05-15 00:36:56 +08:00
private void DrawDamagedComponent_Replaced(SerializedProperty componentRefProp, int index)
2024-03-03 03:51:49 +08:00
{
2024-05-15 00:36:56 +08:00
DrawDamagedComponent(index, $"Damaged component template. If the problem occurred after renaming a component or initializer. use MovedFromAttrubute");
}
private void DrawDamagedComponent(int index, string message)
{
Rect removeButtonRect = GUILayoutUtility.GetLastRect();
2024-03-03 03:51:49 +08:00
GUILayout.BeginHorizontal();
2024-05-15 00:36:56 +08:00
float padding = EditorGUIUtility.standardVerticalSpacing;
removeButtonRect.yMin = removeButtonRect.yMax;
2024-05-16 19:03:03 +08:00
removeButtonRect.yMax += HeadIconsRect.height;
removeButtonRect.xMin = removeButtonRect.xMax - HeadIconsRect.width;
2024-05-15 00:36:56 +08:00
removeButtonRect.center += Vector2.up * padding * 2f;
bool isRemoveComponent = EcsGUI.CloseButton(removeButtonRect);
2024-03-03 03:51:49 +08:00
2024-05-15 00:36:56 +08:00
EditorGUILayout.HelpBox(message, MessageType.Warning);
2024-03-03 03:51:49 +08:00
2024-05-15 00:36:56 +08:00
if (isRemoveComponent)
2024-03-06 21:37:21 +08:00
{
2024-03-03 03:51:49 +08:00
OnRemoveComponentAt(index);
2024-03-06 21:37:21 +08:00
}
2024-03-03 03:51:49 +08:00
GUILayout.EndHorizontal();
}
}
[CustomEditor(typeof(ScriptableEntityTemplate), true)]
internal class EntityTemplatePresetEditor : EntityTemplateEditorBase<ScriptableEntityTemplate>
2024-03-03 03:51:49 +08:00
{
2024-09-27 22:04:00 +08:00
//protected override void DrawCustom()
//{
// Draw(Target);
//}
2024-03-03 03:51:49 +08:00
}
[CustomEditor(typeof(MonoEntityTemplate), true)]
internal class EntityTemplateEditor : EntityTemplateEditorBase<MonoEntityTemplate>
2024-03-03 03:51:49 +08:00
{
2024-09-27 22:04:00 +08:00
//protected override void DrawCustom()
//{
// Draw(Target);
//}
2024-03-03 03:51:49 +08:00
}
}
#endif