Car/Assets/StompyRobot/SRDebugger/Scripts/Internal/OptionControlFactory.cs

175 lines
5.5 KiB
C#
Raw Permalink Normal View History

2025-01-02 11:32:58 +08:00
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<DataBoundControl> _dataControlPrefabs;
private static ActionControl _actionControlPrefab;
private static readonly Dictionary<OptionType, DataBoundControl> TypeCache = new Dictionary<OptionType, DataBoundControl>();
public static bool CanCreateControl(OptionDefinition from)
{
PopulateDataControlPrefabs();
if (from.Property != null)
{
return TryGetDataControlPrefab(from) != null;
}
else
{
return _actionControlPrefab != null;
}
}
/// <summary>
/// Create a control from an <c>OptionDefinition</c>, optionally providing <paramref name="categoryPrefix" /> to remove
/// the category name from the start of the control.
/// </summary>
/// <param name="from"></param>
/// <param name="categoryPrefix"></param>
/// <returns></returns>
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<DataBoundControl>(SRDebugPaths.DataControlsResourcesPath);
}
if (_actionControlPrefab == null)
{
_actionControlPrefab =
Resources.LoadAll<ActionControl>(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();
}
}
}
}
}