namespace SRDebugger.Internal { using System; using System.Collections.Generic; using System.Linq; using SRF; using UI.Controls; using UI.Controls.Data; using UnityEngine; using Object = UnityEngine.Object; public static class OptionControlFactory { private static IList _dataControlPrefabs; private static ActionControl _actionControlPrefab; private static readonly Dictionary TypeCache = new Dictionary(); public static bool CanCreateControl(OptionDefinition from) { PopulateDataControlPrefabs(); if (from.Property != null) { return TryGetDataControlPrefab(from) != null; } else { return _actionControlPrefab != null; } } /// /// Create a control from an OptionDefinition, optionally providing to remove /// the category name from the start of the control. /// /// /// /// public static OptionsControlBase CreateControl(OptionDefinition from, string categoryPrefix = null) { PopulateDataControlPrefabs(); if (from.Property != null) { return CreateDataControl(from, categoryPrefix); } if (from.Method != null) { return CreateActionControl(from, categoryPrefix); } throw new Exception("OptionDefinition did not contain property or method."); } private static void PopulateDataControlPrefabs() { if (_dataControlPrefabs == null) { _dataControlPrefabs = Resources.LoadAll(SRDebugPaths.DataControlsResourcesPath); } if (_actionControlPrefab == null) { _actionControlPrefab = Resources.LoadAll(SRDebugPaths.DataControlsResourcesPath).FirstOrDefault(); } if (_actionControlPrefab == null) { Debug.LogError("[SRDebugger.Options] Cannot find ActionControl prefab."); } } private static ActionControl CreateActionControl(OptionDefinition from, string categoryPrefix = null) { var control = SRInstantiate.Instantiate(_actionControlPrefab); if (control == null) { Debug.LogWarning("[SRDebugger.OptionsTab] Error creating action control from prefab"); return null; } control.SetMethod(from.Name, from.Method); control.Option = from; return control; } private static DataBoundControl CreateDataControl(OptionDefinition from, string categoryPrefix = null) { var prefab = TryGetDataControlPrefab(from); if (prefab == null) { Debug.LogWarning( "[SRDebugger.OptionsTab] Can't find data control for type {0}".Fmt(from.Property.PropertyType)); return null; } var instance = SRInstantiate.Instantiate(prefab); try { var n = from.Name; // Remove category name from the start of the property name if (!string.IsNullOrEmpty(categoryPrefix) && n.StartsWith(categoryPrefix)) { n = n.Substring(categoryPrefix.Length); } instance.Bind(n, from.Property); instance.Option = from; } catch (Exception e) { Debug.LogError("[SRDebugger.Options] Error binding to property {0}".Fmt(from.Name)); Debug.LogException(e); Object.Destroy(instance); instance = null; } return instance; } private static DataBoundControl TryGetDataControlPrefab(OptionDefinition from) { OptionType type = new OptionType(@from.Property.PropertyType, !@from.Property.CanWrite); DataBoundControl control; if (!TypeCache.TryGetValue(type, out control)) { control = _dataControlPrefabs.FirstOrDefault(p => p.CanBind(@from.Property.PropertyType, !@from.Property.CanWrite)); TypeCache.Add(type, control); } return control; } private struct OptionType { public readonly Type Type; public readonly bool IsReadyOnly; public OptionType(Type type, bool isReadyOnly) { Type = type; IsReadyOnly = isReadyOnly; } public bool Equals(OptionType other) { return Equals(Type, other.Type) && IsReadyOnly == other.IsReadyOnly; } public override bool Equals(object obj) { return obj is OptionType other && Equals(other); } public override int GetHashCode() { unchecked { return ((Type != null ? Type.GetHashCode() : 0) * 397) ^ IsReadyOnly.GetHashCode(); } } } } }