2023-05-07 00:50:44 +08:00
using System ;
using System.Reflection ;
namespace DCFApixels.DragonECS
{
#if UNITY_EDITOR
namespace Editors
{
using UnityEditor ;
using UnityEngine ;
2023-05-27 09:14:36 +08:00
public abstract class EntityTemplateEditorBase : Editor
2023-05-07 00:50:44 +08:00
{
private static readonly Rect RemoveButtonRect = new Rect ( 0f , 0f , 15f , 15f ) ;
private static readonly Rect TooltipIconRect = new Rect ( 0f , 0f , 15f , 15f ) ;
private GUIStyle removeButtonStyle ;
private GenericMenu genericMenu ;
private bool _isInit = false ;
#region Init
private void Init ( )
{
if ( genericMenu = = null )
_isInit = false ;
if ( _isInit )
return ;
var tmpstylebase = EcsEditor . GetStyle ( new Color ( 0.9f , 0f , 0.22f ) , 0.5f ) ;
var tmpStyle = EcsEditor . GetStyle ( new Color ( 1f , 0.5f , 0.7f ) , 0.5f ) ;
removeButtonStyle = new GUIStyle ( EditorStyles . linkLabel ) ;
removeButtonStyle . alignment = TextAnchor . MiddleCenter ;
removeButtonStyle . normal = tmpstylebase . normal ;
removeButtonStyle . hover = tmpStyle . normal ;
removeButtonStyle . active = tmpStyle . normal ;
removeButtonStyle . focused = tmpStyle . normal ;
removeButtonStyle . padding = new RectOffset ( 0 , 0 , 0 , 0 ) ;
removeButtonStyle . margin = new RectOffset ( 0 , 0 , 0 , 0 ) ;
removeButtonStyle . border = new RectOffset ( 0 , 0 , 0 , 0 ) ;
genericMenu = new GenericMenu ( ) ;
var dummies = TemplateBrowsableTypeCache . Dummies ;
foreach ( var dummy in dummies )
{
string name , description ;
if ( dummy is ITemplateComponentName browsableName )
name = browsableName . Name ;
else
name = EcsEditor . GetName ( dummy . GetType ( ) ) ;
if ( dummy is TemplateComponentInitializerBase initializer )
description = initializer . Description ;
else
description = EcsEditor . GetDescription ( dummy . GetType ( ) ) ;
if ( ! string . IsNullOrEmpty ( description ) )
{
name = $"{name} {EcsUnityConsts.INFO_MARK}" ;
}
genericMenu . AddItem ( new GUIContent ( name , description ) , false , OnAddComponent , dummy ) ;
}
_isInit = true ;
}
#endregion
#region Add / Remove
private void OnAddComponent ( object obj )
{
Type componentType = obj . GetType ( ) ;
if ( this . target is ITemplateInternal target )
{
SerializedProperty componentsProp = serializedObject . FindProperty ( target . ComponentsPropertyName ) ;
for ( int i = 0 ; i < componentsProp . arraySize ; i + + )
{
if ( componentsProp . GetArrayElementAtIndex ( i ) . managedReferenceValue . GetType ( ) = = componentType )
return ;
}
componentsProp . InsertArrayElementAtIndex ( 0 ) ;
componentsProp . GetArrayElementAtIndex ( 0 ) . managedReferenceValue = ( ( ITemplateComponent ) obj ) . Clone ( ) ;
serializedObject . ApplyModifiedProperties ( ) ;
EditorUtility . SetDirty ( this . target ) ;
}
}
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
protected void Draw ( ITemplateInternal target )
{
Init ( ) ;
SerializedProperty componentsProp = serializedObject . FindProperty ( target . ComponentsPropertyName ) ;
if ( componentsProp = = null )
return ;
DrawTop ( target ) ;
for ( int i = 0 ; i < componentsProp . arraySize ; i + + )
{
DrawComponentData ( componentsProp . GetArrayElementAtIndex ( i ) , i ) ;
GUILayout . Space ( EditorGUIUtility . standardVerticalSpacing * 2 ) ;
}
2023-05-27 09:14:36 +08:00
DrawFooter ( target ) ;
2023-05-07 00:50:44 +08:00
}
private void DrawTop ( ITemplateInternal target )
{
if ( GUILayout . Button ( "Add Component" , GUILayout . Height ( 24f ) ) )
{
Init ( ) ;
genericMenu . ShowAsContext ( ) ;
}
}
2023-05-27 09:14:36 +08:00
private void DrawFooter ( ITemplateInternal target )
{
if ( GUILayout . Button ( "Clear" , GUILayout . Height ( 24f ) ) )
{
Init ( ) ;
serializedObject . FindProperty ( target . ComponentsPropertyName ) . ClearArray ( ) ;
serializedObject . ApplyModifiedProperties ( ) ;
}
}
2023-05-07 00:50:44 +08:00
private void DrawComponentData ( SerializedProperty componentRefProp , int index )
{
2023-05-27 09:14:36 +08:00
ITemplateComponent browsable = componentRefProp . managedReferenceValue as ITemplateComponent ;
if ( browsable = = null )
{
DrawDamagedComponent ( componentRefProp , index ) ;
return ;
}
2023-05-07 00:50:44 +08:00
ITemplateComponentName browsableName = browsable as ITemplateComponentName ;
if ( componentRefProp . managedReferenceValue = = null )
{
DrawDamagedComponent ( componentRefProp , index ) ;
return ;
}
2023-05-27 09:14:36 +08:00
Type initializerType ;
2023-05-07 00:50:44 +08:00
Type componentType ;
SerializedProperty componentProperty = componentRefProp ;
TemplateComponentInitializerBase customInitializer = componentProperty . managedReferenceValue as TemplateComponentInitializerBase ;
if ( customInitializer ! = null )
{
2023-05-27 09:14:36 +08:00
componentProperty = componentRefProp . FindPropertyRelative ( "component" ) ;
initializerType = customInitializer . Type ;
componentType = customInitializer . GetType ( ) . GetField ( "component" , BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ) . FieldType ;
2023-05-07 00:50:44 +08:00
}
else
{
2023-05-27 09:14:36 +08:00
initializerType = componentProperty . managedReferenceValue . GetType ( ) ;
componentType = initializerType ;
2023-05-07 00:50:44 +08:00
}
Type type = browsable . GetType ( ) ;
string name = browsableName = = null ? type . Name : GetLastPathComponent ( browsableName . Name ) ;
2023-05-27 09:14:36 +08:00
string description = customInitializer ! = null ? customInitializer . Description : initializerType . GetCustomAttribute < DebugDescriptionAttribute > ( ) ? . description ;
Color panelColor = customInitializer ! = null ? customInitializer . Color : initializerType . GetCustomAttribute < DebugColorAttribute > ( ) ? . GetUnityColor ( ) ? ? Color . black ;
2023-05-07 00:50:44 +08:00
GUILayout . BeginHorizontal ( ) ;
GUILayout . BeginVertical ( EcsEditor . GetStyle ( panelColor , 0.2f ) ) ;
EditorGUI . BeginChangeCheck ( ) ;
GUIContent label = new GUIContent ( name , $"{name} " ) ;
2023-05-27 09:14:36 +08:00
if ( componentType . GetFields ( BindingFlags . Instance | BindingFlags . Public | BindingFlags . NonPublic ) . Length < = 0 )
{
GUILayout . Label ( label ) ;
}
else
{
EditorGUILayout . PropertyField ( componentProperty , label , true ) ;
}
2023-05-07 00:50:44 +08:00
if ( EditorGUI . EndChangeCheck ( ) )
{
componentProperty . serializedObject . ApplyModifiedProperties ( ) ;
EditorUtility . SetDirty ( componentProperty . serializedObject . targetObject ) ;
}
Rect lastrect = GUILayoutUtility . GetLastRect ( ) ;
Rect removeButtonRect = RemoveButtonRect ;
removeButtonRect . center = new Vector2 ( lastrect . xMax + removeButtonRect . width , lastrect . yMin + removeButtonRect . height / 2f ) ;
GUILayout . EndVertical ( ) ;
GUILayout . Label ( "" , GUILayout . Width ( removeButtonRect . width ) ) ;
if ( GUI . Button ( removeButtonRect , "x" , removeButtonStyle ) )
OnRemoveComponentAt ( index ) ;
if ( ! string . IsNullOrEmpty ( description ) )
{
Rect tooltipIconRect = TooltipIconRect ;
tooltipIconRect . center = new Vector2 ( lastrect . xMax - removeButtonRect . width / 2f , lastrect . yMin + removeButtonRect . height / 2f ) ;
GUIContent descriptionLabel = new GUIContent ( EcsUnityConsts . INFO_MARK , description ) ;
GUI . Label ( tooltipIconRect , descriptionLabel , EditorStyles . boldLabel ) ;
}
GUILayout . EndHorizontal ( ) ;
}
private void DrawDamagedComponent ( SerializedProperty componentRefProp , int index )
{
GUILayout . BeginHorizontal ( ) ;
EditorGUILayout . HelpBox ( $"Damaged component. If the problem occurred after renaming a component or initializer. use MovedFromAttrubute" , MessageType . Warning ) ;
Rect lastrect = GUILayoutUtility . GetLastRect ( ) ;
Rect removeButtonRect = RemoveButtonRect ;
removeButtonRect . center = new Vector2 ( lastrect . xMax + removeButtonRect . width , lastrect . yMin + removeButtonRect . height / 2f ) ;
GUILayout . Label ( "" , GUILayout . Width ( removeButtonRect . width ) ) ;
if ( GUI . Button ( removeButtonRect , "x" , removeButtonStyle ) )
OnRemoveComponentAt ( index ) ;
GUILayout . EndHorizontal ( ) ;
}
public string GetLastPathComponent ( string input )
{
int lastSlashIndex = input . LastIndexOfAny ( new char [ ] { '/' , '\\' } ) ;
if ( lastSlashIndex = = - 1 )
return input ;
else
return input . Substring ( lastSlashIndex + 1 ) ;
}
}
[CustomEditor(typeof(EntityTemplatePreset), true)]
public class EntityTemplatePresetEditor : EntityTemplateEditorBase
{
public override void OnInspectorGUI ( )
{
Draw ( ( ITemplateInternal ) target ) ;
}
}
[CustomEditor(typeof(EntityTemplate), true)]
public class EntityTemplateEditor : EntityTemplateEditorBase
{
public override void OnInspectorGUI ( )
{
Draw ( ( ITemplateInternal ) target ) ;
}
}
}
#endif
}