using System;
using System.Collections.Generic;
namespace RosettaUI
{
///
/// 特定の型に標準のUI(UI.Field()で生成される)を指定できる
///
public static partial class UICustom
{
private static readonly Dictionary CreationFuncTable = new();
// exclude parent type
public static void RegisterElementCreationFunc(Func, Action, Element> creationFunc)
{
RegisterElementCreationFunc(typeof(T), new CreationFunc((label, binder) =>
{
var typedBinder = (IBinder)binder;
return creationFunc(label, typedBinder.Get, typedBinder.Set);
}
));
}
[Obsolete("Use other signature of RegisterElementCreationFunc().")]
public static void RegisterElementCreationFunc(Func, Element> creationFunc)
where T : class // GetObject() as T を呼ぶためにとりあえずwhere T : class
{
// binder から Element を生成するべきだが複雑な UI を作ろうとするとかなり大変なので
// binderのかわりにFuncから生成してもらう
//
// UI.Field(() => GetObj(), obj => SetObj(obj)); などのケースで
// binder.GetObject()で返ってきたobjを編集するだけではだめでSetObject()で通知する必要がある
RegisterElementCreationFunc(typeof(T), new CreationFunc((label, binder) =>
{
object obj = null;
return creationFunc(label, () => (obj = binder.GetObject()) as T)
.RegisterValueChangeCallback(() => binder.SetObject(obj));
}
));
}
// exclude parent type
public static void RegisterElementCreationFunc(Func, Element> creationFunc)
{
RegisterElementCreationFunc(typeof(T),
new CreationFunc((label, binder) => creationFunc(label, (IBinder)binder)));
}
// include parent type
public static void RegisterElementCreationFunc(Type type, Func creationFunc)
{
RegisterElementCreationFunc(type, new CreationFunc(creationFunc, true));
}
private static void RegisterElementCreationFunc(Type type, CreationFunc creationFunc)
{
CreationFuncTable[type] = creationFunc;
}
public static bool UnregisterElementCreationFunc(Type type)
{
return CreationFuncTable.Remove(type);
}
public static Func GetElementCreationFunc(Type type)
{
return GetElementCreationFuncData(type)?.func;
}
private static CreationFunc GetElementCreationFuncData(Type type, bool isTarget = true)
{
while (true)
{
if (type == null) return null;
if (CreationFuncTable.TryGetValue(type, out var creationFunc) && (isTarget || creationFunc.includeParentTypes))
{
return creationFunc;
}
type = type.BaseType;
isTarget = false;
}
}
#region Scope
public readonly ref struct ElementCreationFuncScope
{
// exclude parent type
public static ElementCreationFuncScope Create(Func, Action, Element> creationFunc)
{
var ret = new ElementCreationFuncScope(typeof(T));
RegisterElementCreationFunc(creationFunc);
return ret;
}
// exclude parent type
public static ElementCreationFuncScope Create(Func, Element> creationFunc)
{
var ret = new ElementCreationFuncScope(typeof(T));
RegisterElementCreationFunc(creationFunc);
return ret;
}
// include parent type
public static ElementCreationFuncScope Create(Type type, Func creationFunc)
{
var ret = new ElementCreationFuncScope(type);
RegisterElementCreationFunc(type, creationFunc);
return ret;
}
private readonly Type _type;
private readonly CreationFunc _creationFuncCache;
private ElementCreationFuncScope(Type type)
{
_type = type;
_creationFuncCache = GetElementCreationFuncData(type);
}
public void Dispose()
{
RegisterElementCreationFunc(_type, _creationFuncCache);
}
}
public readonly ref struct ElementCreationFuncScope
where T : class
{
private readonly CreationFunc _creationFuncCache;
[Obsolete("Use ElementCreationFuncScope.Create() instead.")]
public ElementCreationFuncScope(Func, Element> creationFunc)
{
_creationFuncCache = GetElementCreationFuncData(typeof(T));
RegisterElementCreationFunc(creationFunc);
}
public void Dispose()
{
RegisterElementCreationFunc(typeof(T), _creationFuncCache);
}
}
#endregion
private class CreationFunc
{
public readonly Func func;
public readonly bool includeParentTypes;
public CreationFunc(Func func, bool includeParentTypes = false) =>
(this.func, this.includeParentTypes) = (func, includeParentTypes);
}
}
}