using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEngine; using static Convention.WindowsUI.Variant.PropertiesWindow; namespace Convention.WindowsUI.Variant { /// /// enum&1==1��Ϊ��̬�������� /// public enum InspectorDrawType { // Auto Auto = -1, // String Text = 0, // Bool Toggle = 1 << 1, // Sripte Image = 1 << 2, // Transform Transform = 1 << 3, // Container List = 1 << 4 + 1, Dictionary = 1 << 5 + 1, Array = 1 << 6 + 1, // Object Reference = 1 << 7, Structure = 1 << 8, // Method Button = 1 << 9, // Enum Enum = 1 << 10 } [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public class InspectorDrawAttribute : Attribute { public readonly InspectorDrawType drawType; public readonly bool isUpdateAble = true; public readonly bool isChangeAble = true; public readonly string name = null; // Get Real Inspector Name: Field public readonly string nameGenerater = null; // Get Real Enum Names: Method public readonly string enumGenerater = null; public InspectorDrawAttribute() { this.drawType = InspectorDrawType.Auto; } public InspectorDrawAttribute(InspectorDrawType drawType = InspectorDrawType.Auto, bool isUpdateAble = true, bool isChangeAble = true, string name = null, string nameGenerater = null, string enumGenerater = null) { this.drawType = drawType; this.isUpdateAble = isUpdateAble; this.isChangeAble = isChangeAble; this.name = name; this.nameGenerater = nameGenerater; this.enumGenerater = enumGenerater; } } public interface IInspectorUpdater { void OnInspectorUpdate(); } public abstract class InspectorDrawer : WindowUIModule { [Resources, SerializeField] private InspectorItem m_targetItem; public InspectorItem targetItem { get => m_targetItem; private set => m_targetItem = value; } public virtual void OnInspectorItemInit(InspectorItem item) { targetItem = item; } } public class InspectorItem : PropertyListItem,ITitle { [Resources, OnlyNotNullMode, SerializeField] private Text Title; [Resources, OnlyNotNullMode, SerializeField, Header("Inspector Components")] private InspectorDrawer m_TransformModule; [Resources, OnlyNotNullMode, SerializeField] private InspectorDrawer m_TextModule, m_ToggleModule, m_ImageModule, m_ReferenceModule, m_ButtonModule, m_StructureModule, m_DictionaryItemModule, m_EnumItemModule; private Dictionary m_AllUIModules = new(); private List m_DynamicSubEntries = new(); [Content, OnlyPlayMode] public object target; public MemberInfo targetMemberInfo { get; private set; } public ValueWrapper targetValueWrapper { get; private set; } public Action targetFunctionCall { get; private set; } [Setting, SerializeField] private InspectorDrawType targetDrawType; [Setting, SerializeField] private bool targetAbleChangeMode = true; [Setting, SerializeField] private bool targetUpdateMode = true; [Setting, SerializeField] public InspectorDrawAttribute targetDrawer { get; private set; } public InspectorDrawer CurrentModule => m_AllUIModules[targetDrawType]; public InspectorDrawType DrawType { get => targetDrawType; set => targetDrawType = value; } private void EnableDrawType() { if ((1 & (int)targetDrawType) == 0) m_AllUIModules[targetDrawType].gameObject.SetActive(true); else if (targetDrawType == InspectorDrawType.List) { Type listType = (targetMemberInfo != null) ? ConventionUtility.SeekValue(target, targetMemberInfo).GetType().GetGenericArguments()[0] : targetValueWrapper.GetValue().GetType().GetGenericArguments()[0]; m_DynamicSubEntries = CreateSubPropertyItem(2); m_DynamicSubEntries[0].ref_value.GetComponent().SetTarget(null, () => { (GetValue() as IList).Add(ConventionUtility.GetDefault(listType)); }); m_DynamicSubEntries[1].ref_value.GetComponent().SetTarget(null, () => { var list = (IList)GetValue(); int length = list.Count; if (length != 0) (GetValue() as IList).RemoveAt(length - 1); }); CreateSequenceItems(2); } else if (targetDrawType == InspectorDrawType.Dictionary) { } else if (targetDrawType == InspectorDrawType.Array) { m_DynamicSubEntries = new(); CreateSequenceItems(); } else throw new InvalidOperationException($"Unknown {nameof(InspectorDrawType)}: {targetDrawType}"); void CreateSequenceItems(int offset = 0) { var array = (IList)GetValue(); Type arrayType = (targetMemberInfo != null) ? ConventionUtility.SeekValue(target, targetMemberInfo).GetType().GetGenericArguments()[0] : targetValueWrapper.GetValue().GetType().GetGenericArguments()[0]; int length = array.Count;// (int)ConventionUtility.SeekValue(array, nameof(Array.Length), BindingFlags.Default); m_DynamicSubEntries.AddRange(CreateSubPropertyItem(length)); int index = 0; foreach (var item in array) { m_DynamicSubEntries[index + offset].ref_value.GetComponent().title = index.ToString(); m_DynamicSubEntries[index + offset].ref_value.GetComponent().SetTarget(null, new ValueWrapper( () => array[index], (x) => array[index] = x, arrayType )); index++; } } } private void DisableDrawType() { if ((1 & (int)targetDrawType) == 0) m_AllUIModules[targetDrawType].gameObject.SetActive(false); else { foreach (var item in m_DynamicSubEntries) { item.Release(); } m_DynamicSubEntries.Clear(); } } public bool AbleChangeType { get => targetAbleChangeMode; set => targetAbleChangeMode = value; } public bool UpdateType { get => targetUpdateMode; set => targetUpdateMode = value; } public static string BroadcastName => $"On{nameof(InspectorItem)}Init"; private void InitModules() { m_AllUIModules[InspectorDrawType.Text] = m_TextModule; m_AllUIModules[InspectorDrawType.Toggle] = m_ToggleModule; m_AllUIModules[InspectorDrawType.Image] = m_ImageModule; m_AllUIModules[InspectorDrawType.Transform] = m_TransformModule; m_AllUIModules[InspectorDrawType.Reference] = m_ReferenceModule; m_AllUIModules[InspectorDrawType.Structure] = m_StructureModule; m_AllUIModules[InspectorDrawType.Button] = m_ButtonModule; m_AllUIModules[InspectorDrawType.Enum] = m_EnumItemModule; MakeInspectorItemInit(); } private void MakeInspectorItemInit() { foreach (var module in m_AllUIModules) { module.Value.OnInspectorItemInit(this); } } public void SetTarget([In] object target, MemberInfo member) { this.target = target; this.targetMemberInfo = member; this.targetValueWrapper = null; this.targetFunctionCall = null; InitModules(); RebulidImmediate(); } public void SetTarget([In] object target,ValueWrapper wrapper) { this.target = target; this.targetMemberInfo = null; this.targetValueWrapper = wrapper; this.targetFunctionCall = null; InitModules(); RebulidImmediate(); } public void SetTarget([In] object target,Action action) { this.target = target; this.targetMemberInfo = null; this.targetValueWrapper = null; this.targetFunctionCall = action; InitModules(); RebulidImmediate(); } public void SetValue([In] object value) { if (targetMemberInfo != null) ConventionUtility.PushValue(target, value, targetMemberInfo); else if (targetValueWrapper != null) targetValueWrapper.SetValue(value); else throw new InvalidOperationException(); } public object GetValue() { if (targetMemberInfo != null) return ConventionUtility.SeekValue(target, targetMemberInfo); else if (targetValueWrapper != null) return targetValueWrapper.GetValue(); else throw new InvalidOperationException(); } public Type GetValueType() { if (targetMemberInfo != null) return ConventionUtility.GetMemberValueType(targetMemberInfo); else if (targetValueWrapper != null) return targetValueWrapper.type; else throw new InvalidOperationException(); } public void InvokeAction() { if (targetFunctionCall != null) targetFunctionCall.Invoke(); else ConventionUtility.InvokeMember(targetMemberInfo, target); } [Content, OnlyPlayMode] public void RebulidImmediate() { if (targetMemberInfo != null) { RebuildWithMemberInfo(); } else if (targetValueWrapper != null) { RebuildWithWrapper(); } else if (targetFunctionCall != null) { RebuildWithFunctionCall(); } void RebuildWithMemberInfo() { InspectorDrawAttribute drawAttr = null; ArgPackageAttribute argAttr = null; Type type = null; // Reset AbleChangeType this.targetDrawer = drawAttr = targetMemberInfo.GetCustomAttribute(true); argAttr = targetMemberInfo.GetCustomAttribute(true); type = ConventionUtility.GetMemberValueType(targetMemberInfo); AbleChangeType = targetMemberInfo.GetCustomAttributes(typeof(IgnoreAttribute), true).Length == 0; // Reset DrawType DisableDrawType(); if (drawAttr != null) { AbleChangeType &= drawAttr.isChangeAble; UpdateType = drawAttr.isUpdateAble; if (drawAttr.nameGenerater != null) { title = (string)ConventionUtility.SeekValue(target, drawAttr.nameGenerater, typeof(string), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.GetField); } else { title = drawAttr.name; } } if (drawAttr != null && drawAttr.drawType != InspectorDrawType.Auto) { DrawType = drawAttr.drawType; } else if (type != null) { if (ConventionUtility.IsEnum(type)) DrawType = InspectorDrawType.Enum; if (ConventionUtility.IsBool(type)) DrawType = InspectorDrawType.Toggle; else if (ConventionUtility.IsString(type) || ConventionUtility.IsNumber(type)) DrawType = InspectorDrawType.Text; else if (ConventionUtility.IsArray(type)) DrawType = InspectorDrawType.Array; else if (ConventionUtility.IsImage(type)) DrawType = InspectorDrawType.Image; else if (type.GetInterface(nameof(IEnumerable)) != null && type.GetGenericArguments().Length == 1) DrawType = InspectorDrawType.List; else if (type.GetInterface(nameof(IEnumerable)) != null && type.GetGenericArguments().Length == 2) DrawType = InspectorDrawType.Dictionary; else if (type == typeof(Transform)) DrawType = InspectorDrawType.Transform; else if (type.IsClass) DrawType = InspectorDrawType.Reference; else DrawType = InspectorDrawType.Structure; } else if (targetMemberInfo is MethodInfo method) { DrawType = InspectorDrawType.Button; } else { throw new NotImplementedException("Reach this location by unknown Impl"); } EnableDrawType(); RectTransformExtension.AdjustSizeToContainsChilds(transform as RectTransform); RectTransformExtension.AdjustSizeToContainsChilds(this.Entry.rootWindow.TargetWindowContent); } void RebuildWithWrapper() { Type type = targetValueWrapper.type; AbleChangeType = targetValueWrapper.IsChangeAble; // Reset DrawType if (ConventionUtility.IsBool(type)) DrawType = InspectorDrawType.Toggle; else if (ConventionUtility.IsString(type) || ConventionUtility.IsNumber(type)) DrawType = InspectorDrawType.Text; else if (ConventionUtility.IsArray(type)) DrawType = InspectorDrawType.Array; else if (type.GetInterface(nameof(IEnumerable)) != null && type.GetGenericArguments().Length == 1) DrawType = InspectorDrawType.List; else if (type.GetInterface(nameof(IEnumerable)) != null && type.GetGenericArguments().Length == 2) DrawType = InspectorDrawType.Dictionary; else if (type == typeof(Transform)) DrawType = InspectorDrawType.Transform; else if (type.IsSubclassOf(typeof(Texture))) DrawType = InspectorDrawType.Image; else if (type.IsClass) DrawType = InspectorDrawType.Reference; else DrawType = InspectorDrawType.Structure; RectTransformExtension.AdjustSizeToContainsChilds(transform as RectTransform); RectTransformExtension.AdjustSizeToContainsChilds(this.Entry.rootWindow.TargetWindowContent); } void RebuildWithFunctionCall() { DrawType = InspectorDrawType.Button; } } protected override void FoldChilds() { base.FoldChilds(); CurrentModule.gameObject.SetActive(false); } protected override void UnfoldChilds() { base.UnfoldChilds(); CurrentModule.gameObject.SetActive(true); } } /// /// /// /// public interface IOnlyFocusThisOnInspector { } }