using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEngine; using Explorer.UI.Shared; using Explorer.CacheObject; namespace Explorer.UI { public class InteractiveValue { public const float MAX_LABEL_WIDTH = 400f; public const string EVALUATE_LABEL = "Evaluate"; public CacheObjectBase OwnerCacheObject; public object Value { get; set; } public Type ValueType; public string ButtonLabel => m_btnLabel ?? GetButtonLabel(); private string m_btnLabel; public MethodInfo ToStringMethod => m_toStringMethod ?? GetToStringMethod(); private MethodInfo m_toStringMethod; public virtual void Init() { UpdateValue(); } public virtual void UpdateValue() { GetButtonLabel(); } public float CalcWhitespace(Rect window) { if (!(this is IExpandHeight)) return 0f; float whitespace = (this as IExpandHeight).WhiteSpace; if (whitespace > 0) { ClampLabelWidth(window, ref whitespace); } return whitespace; } public static void ClampLabelWidth(Rect window, ref float labelWidth) { float min = window.width * 0.37f; if (min > MAX_LABEL_WIDTH) min = MAX_LABEL_WIDTH; labelWidth = Mathf.Clamp(labelWidth, min, MAX_LABEL_WIDTH); } public void Draw(Rect window, float labelWidth = 215f) { if (labelWidth > 0) { ClampLabelWidth(window, ref labelWidth); } var cacheMember = OwnerCacheObject as CacheMember; if (cacheMember != null && cacheMember.MemInfo != null) { GUILayout.Label(cacheMember.RichTextName, new GUILayoutOption[] { GUILayout.Width(labelWidth) }); } else { GUIUnstrip.Space(labelWidth); } var cacheMethod = OwnerCacheObject as CacheMethod; if (cacheMember != null && cacheMember.HasParameters) { GUIUnstrip.BeginVertical(new GUILayoutOption[] { GUILayout.ExpandHeight(true) } ); if (cacheMember.m_isEvaluating) { if (cacheMethod != null && cacheMethod.GenericArgs.Length > 0) { cacheMethod.DrawGenericArgsInput(); } if (cacheMember.m_arguments.Length > 0) { cacheMember.DrawArgsInput(); } GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) })) { if (cacheMethod != null) cacheMethod.Evaluate(); else cacheMember.UpdateValue(); } if (GUILayout.Button("Cancel", new GUILayoutOption[] { GUILayout.Width(70) })) { cacheMember.m_isEvaluating = false; } GUILayout.EndHorizontal(); } else { var lbl = $"Evaluate ("; int len = cacheMember.m_arguments.Length; if (cacheMethod != null) len += cacheMethod.GenericArgs.Length; lbl += len + " params)"; if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(150) })) { cacheMember.m_isEvaluating = true; } } GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.Space(labelWidth); } else if (cacheMethod != null) { if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) })) { cacheMethod.Evaluate(); } GUILayout.EndHorizontal(); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.Space(labelWidth); } string typeName = $"{ValueType.FullName}"; if (cacheMember != null && !string.IsNullOrEmpty(cacheMember.ReflectionException)) { GUILayout.Label("Reflection failed! (" + cacheMember.ReflectionException + ")", new GUILayoutOption[0]); } else if (cacheMember != null && (cacheMember.HasParameters || cacheMember is CacheMethod) && !cacheMember.m_evaluated) { GUILayout.Label($"Not yet evaluated ({typeName})", new GUILayoutOption[0]); } else if (Value == null && !(cacheMember is CacheMethod)) { GUILayout.Label($"null ({typeName})", new GUILayoutOption[0]); } else { float _width = window.width - labelWidth - 90; if (OwnerCacheObject is CacheMethod cm) { cm.DrawValue(window, _width); } else { DrawValue(window, _width); } } } public virtual void DrawValue(Rect window, float width) { GUI.skin.button.alignment = TextAnchor.MiddleLeft; if (GUILayout.Button(ButtonLabel, new GUILayoutOption[] { GUILayout.Width(width - 15) })) { if (OwnerCacheObject.IsStaticClassSearchResult) { WindowManager.InspectStaticReflection(Value as Type); } else { WindowManager.InspectObject(Value, out bool _); } } GUI.skin.button.alignment = TextAnchor.MiddleCenter; } private MethodInfo GetToStringMethod() { try { m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0]) ?? typeof(object).GetMethod("ToString", new Type[0]); // test invoke m_toStringMethod.Invoke(Value, null); } catch { m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]); } return m_toStringMethod; } private string GetButtonLabel() { if (Value == null) return null; string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString(); var classColor = ValueType.IsAbstract && ValueType.IsSealed ? Syntax.Class_Static : Syntax.Class_Instance; string typeLabel = $"{ValueType.FullName}"; if (Value is UnityEngine.Object) { label = label.Replace($"({ValueType.FullName})", $"({typeLabel})"); } else { if (!label.Contains(ValueType.FullName)) { label += $" ({typeLabel})"; } else { label = label.Replace(ValueType.FullName, typeLabel); } } return m_btnLabel = label; } } }