Files
XericLibrary-Publish/ConfigUIElement/Scripts/Element/ConfigSelectableItem.cs

712 lines
21 KiB
C#
Raw Normal View History

2025-04-10 15:32:00 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;
using XericLibrary.Runtime.CustomEditor;
using XericLibrary.Runtime.MacroLibrary;
namespace LRC
{
/// <summary>
/// һ<><D2BB><EFBFBD><EFBFBD><EFBFBD>ڻ<EFBFBD><DABB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD>
/// <code>
/// <20>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E1B9A9>˫<EFBFBD><CBAB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ί<EFBFBD><CEAF><EFBFBD>޸ģ<DEB8><C4A3><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǡ<EFBFBD>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><CABC>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ȡ<EFBFBD>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״η<D7B4><CEB7><EFBFBD><EFBFBD>ı<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>м<EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0>ֵ<EFBFBD><D6B5>
/// </code>
/// </summary>
public abstract class ConfigSelectableItem : MonoBehaviour
{
#region <EFBFBD><EFBFBD>̬<EFBFBD>¼<EFBFBD>
private static event Action<bool, bool> ForceUpdateAllConfigEvent;
/// <summary>
/// ǿ<><C7BF><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD><EFBFBD>ij<EFBFBD>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ʱ<EFBFBD><CAB1><EFBFBD>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
/// </summary>
/// <param name="resetDirty"></param>
public static void ForceUpdateAll(bool resetDirty = false, bool forceSet = false)
{
ForceUpdateAllConfigEvent?.Invoke(resetDirty, forceSet);
}
private static event Action ForceSetAllSourceValueEvent;
/// <summary>
/// ǿ<><C7BF><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD><EFBFBD>ij<EFBFBD>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD><C3B5>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E7B0B4>Ӧ<EFBFBD>ð<EFBFBD>ťʱ<C5A5><CAB1>
/// </summary>
public static void ForceSetAllSourceValue()
{
ForceSetAllSourceValueEvent?.Invoke();
}
/// <summary>
/// <20><>ֵ<EFBFBD><EFBFBD>޸<EFBFBD>ʱ
/// </summary>
public static event Action<ConfigSelectableItem> OnAnyValueDirty;
/// <summary>
/// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD>յ<EFBFBD><D5B5>޸<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ĺ<EFBFBD><C4BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD>ǰ<EFBFBD><C7B0>ֵ
/// </summary>
public static event Action<ConfigSelectableItem, object> OnAnyValueChange;
#endregion
#region <EFBFBD><EFBFBD>̬<EFBFBD><EFBFBD>Ա
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD><D8A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڼ<EFBFBD><DABC><EFBFBD>״̬ʱ<CCAC><CAB1><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD>б<EFBFBD><D0B1><EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>
/// </summary>
private static readonly List<ConfigSelectableItem> ConfigItemList = new List<ConfigSelectableItem>();
/// <summary>
/// <20><>Ŀ<EFBFBD>б<EFBFBD><D0B1><EFBFBD>Ч<EFBFBD><D0A7>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public static int ConfigItemListCount => ConfigItemList.Count;
/// <summary>
/// <20><>ȡ
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public static ConfigSelectableItem GetConfigItemByIndex(int index) => ConfigItemList[index];
public static IEnumerable<ConfigSelectableItem> ConfigItemLists => ConfigItemList;
private static bool autoUpdateValueAll;
/// <summary>
/// <20>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
/// </summary>
public static bool AutoUpdateValueAll
{
get => autoUpdateValueAll;
set
{
foreach (var item in ConfigItemList)
item.autoUpdateValue = value;
autoUpdateValueAll = value;
}
}
#endregion
#region ״̬
/// <summary>
/// <20><>ֵ<EFBFBD><EFBFBD>޸<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0A3AC><EFBFBD><EFBFBD><EFBFBD>ں<EFBFBD><DABA><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD><EFBFBD>п<EFBFBD><D0BF>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD>ı
/// <code>
/// <20><><EFBFBD><EFBFBD><E9A3BA><EFBFBD>ǿ<EFBFBD>ѡ<EFBFBD><D1A1>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><CCB7><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>޸<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>ұ<EFBFBD>OnValueChange<67><65><EFBFBD><EFBFBD><E7A3AC><EFBFBD>ڸ<EFBFBD>λ֮ǰֻ<C7B0><D6BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD>Ρ<EFBFBD>
/// </code>
/// </summary>
public event Action<ConfigSelectableItem> OnValueDirty;
/// <summary>
/// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD>յ<EFBFBD><D5B5>޸<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>ĺ<EFBFBD><C4BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD>ǰ<EFBFBD><C7B0>ֵ
/// <code>
/// <20><><EFBFBD><EFBFBD><E9A3BA><EFBFBD>ǿ<EFBFBD>ѡ<EFBFBD><D1A1>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̷<EFBFBD><CCB7><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>޸<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>ˢ<EFBFBD>µĻ<C2B5><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еȴ<D0B5>
/// </code>
/// </summary>
public event Action<ConfigSelectableItem, object> OnValueChange;
/// <summary>
/// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD>޸<EFBFBD>ʱ
/// </summary>
public event Action<ConfigSelectableItem, object> OnEndEdit;
/// <summary>
/// <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ֵ
/// <code>
/// <20><><EFBFBD><EFBFBD><E9A3BA><EFBFBD>DZ<EFBFBD>Ҫ<EFBFBD><D2AA>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˢ<EFBFBD><CBA2><EFBFBD>¼<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD>ⲿ<EFBFBD><E2B2BF>ֵ<EFBFBD><EFBFBD><E8B6A8><EFBFBD>ˡ<EFBFBD>
/// </code>
/// </summary>
public event Func<ConfigSelectableItem, object> GetSourceValue;
/// <summary>
/// <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
/// <code>
/// <20><><EFBFBD><EFBFBD><E9A3BA><EFBFBD>DZ<EFBFBD>Ҫ<EFBFBD><D2AA>
/// <20><><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ForceSetAllSourceValue<75><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>á<EFBFBD>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ǽ<EFBFBD><C7BD>˴<EFBFBD><CBB4>Ľ<EFBFBD><C4BD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD>
/// <20><><EFBFBD><EFBFBD><E6A3BA>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ForceSetAllSourceValue<75><65>SetSourceValueRequest<73>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD><EFBFBD>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>Լ<EFBFBD><D4BC>ڴ<EFBFBD><DAB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </code>
/// </summary>
public event Action<ConfigSelectableItem, object> SetSourceValue;
/// <summary>
/// <20><>ǰ<EFBFBD><C7B0><EFBFBD>Ե<EFBFBD><D4B5>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ
/// <code>
/// <20><><EFBFBD><EFBFBD><E9A3BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD>д<EFBFBD><D0B4><EFBFBD>Toggleʱ(<28><>ӦautoUpdateValueToggle<6C><65>Ŀ)
/// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4>ⲿ<EFBFBD><E2B2BF>ֵ<EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ѡֵ<D1A1><EFBFBD><E8B6A8><EFBFBD><EFBFBD>
/// </code>
/// </summary>
public event Func<ConfigSelectableItem, bool> GetSourceValueAutoUpdate;
/// <summary>
/// <20><>ǰ<EFBFBD><C7B0><EFBFBD>Ե<EFBFBD><D4B5>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// <code>
/// <20><><EFBFBD><EFBFBD><E9A3BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD>д<EFBFBD><D0B4><EFBFBD>Toggleʱ(<28><>ӦautoUpdateValueToggle<6C><65>Ŀ)
/// <20>˴<EFBFBD><CBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD><C3B5>ⲿ<EFBFBD><E2B2BF><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ѡֵ<D1A1><EFBFBD><E8B6A8><EFBFBD><EFBFBD>
/// </code>
/// </summary>
public event Action<bool> SetSourceValueAutoUpdate;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ(<28><>ֵӦ<D6B5>õ<EFBFBD><C3B5>Ĵ<EFBFBD><C4B4><EFBFBD>)
/// </summary>
public void SetSourceValueRequest()
{
SetSourceValue?.Invoke(this, Value);
}
#endregion
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD>
/// <summary>
/// <20><>Ŀ<EFBFBD><C4BF>Ӧ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>tag
/// </summary>
[Rename("ӳ<><D3B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")]
public string configTag;
/// <summary>
/// <20><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ч<EFBFBD><D0A7>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
[SerializeField]
[Rename("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")]
private bool allowInput = true;
/// <summary>
/// <20>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
/// </summary>
[SerializeField]
[Rename("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>")]
private bool autoUpdateValue = true;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>£<EFBFBD><C2A3><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>״̬ѡ<CCAC><D1A1><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>
/// </summary>
[SerializeField]
[Rename("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>")]
private bool allowBlockUpdate = true;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>£<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ɳ<EFBFBD><C9B3><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>ݽ<EFBFBD><DDBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
[SerializeField]
[Rename("<22><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>")]
private bool forceBlockUpdate = false;
/// <summary>
/// <20><>ʽ<EFBFBD><CABD><EFBFBD>ı<EFBFBD>
/// </summary>
public string numberFormat = "0.##";
/// <summary>
/// <20><>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public TextMeshProUGUI titleLabel;
#if UNITY_EDITOR
[SerializeField]
#endif
private string titleTextContext;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public TextMeshProUGUI helpLabel;
#if UNITY_EDITOR
[SerializeField]
#endif
private string helpTextContext;
/// <summary>
/// <20><>λ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public TextMeshProUGUI unitLabel;
#if UNITY_EDITOR
[SerializeField]
#endif
private string unitTextContext;
/// <summary>
/// <20><>Ŀǰ<C4BF><C7B0>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>autoUpdateValue<75><65>Ӧ
/// </summary>
[Rename("<22>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>״̬ѡ<CCAC><D1A1>")]
public Toggle autoUpdateValueToggle;
/// <summary>
/// <20><>תѡ<D7AA><D1A1>״̬
/// </summary>
[Rename("<22><>ת<EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>°<EFBFBD>ť״̬")]
public bool autoUpdateValueToggleReversalState;
[Rename("<22><>ת<EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>״̬")]
public bool autoUpdateValueReversalState;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD>λ<EFBFBD><CEBB>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ա<EFBFBD><D4B1><EFBFBD><EFBFBD>¿<EFBFBD><C2BF><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>״̬
/// </summary>
[Rename("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD>λ")]
public bool dirtyAutoReset = false;
// ==== <20><><EFBFBD><EFBFBD> ==== //
/// <summary>
/// <20><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч
/// </summary>
public virtual bool AllowInput
{
get => allowInput;
set => allowInput = value;
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD>Ѿ<EFBFBD><D1BE><EFBFBD>ʼ<EFBFBD><CABC>
/// </summary>
[HideInInspector]
public bool IsValueInitNull { get; private set; } = true;
// [Obsolete("<22><>ʹ<EFBFBD>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD>")]
private bool _isDirty;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Ա<EFBFBD><D4B1>ǣ<EFBFBD><C7A3>״<EFBFBD><D7B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>й㲥
/// </summary>
private bool IsDirty
{
get => _isDirty;
set
{
if (_isDirty)
{
if (!value)
_isDirty = false;
return;
}
if (!value) return;
_isDirty = true;
OnAnyValueDirty?.Invoke(this);
OnValueDirty?.Invoke(this);
}
}
/// <summary>
/// <20><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC>ѡ<EFBFBD><D1A1>
/// <code>
/// Ϊ<><CEAA><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD><E3A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<D7B4>Ǻ<EFBFBD><C7BA>ⲿ<EFBFBD>ݴ<EFBFBD>ֵһ<D6B5>£<EFBFBD>
/// <20>˷<EFBFBD><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>״̬<D7B4>ı<EFBFBD>׼<EFBFBD><D7BC><EFBFBD>ʡ<EFBFBD>
///
/// <20><><EFBFBD>ʽ<EFBFBD><CABD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򲻽<EFBFBD><F2B2BBBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>
/// <20><><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>ʹ<EFBFBD>ô˷<C3B4><CBB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB>ڲ<EFBFBD><DAB2><EFBFBD><EFBFBD>ʣ<EFBFBD><CAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ⲿͨѶӦ<D1B6><D3A6>ʹ<EFBFBD><CAB9><EFBFBD>ֶΡ<D6B6>
///
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2>ж<EFBFBD>״̬תΪ<D7AA><CEAA><EFBFBD><EFBFBD>״̬<D7B4><CCAC>
/// Ӧ<><D3A6><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>autoUpdateValueReversalStateתΪ<D7AA>ݴ<EFBFBD>ֵ<EFBFBD><D6B5>
/// Ȼ<><C8BB><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>autoUpdateValueToggleReversalStateתΪ<D7AA><CEAA><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>
/// </code>
/// </summary>
public bool AutoUpdateValue
{
get => autoUpdateValueReversalState ^ autoUpdateValue;
set
{
autoUpdateValue = value;
if (autoUpdateValueToggle != null)
autoUpdateValueToggle.isOn = autoUpdateValueToggleReversalState ^ value;
}
}
/// <summary>
/// <20><EFBFBD><E8B6A8><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public bool ForceBlockUpdate
{
get => forceBlockUpdate;
set => forceBlockUpdate = value;
}
/// <summary>
/// <20><>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD>
/// </summary>
public string TitleName
{
get => titleLabel.text;
set => titleLabel.text = value;
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD><C4AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>Dz<EFBFBD><C7B2><EFBFBD>ʾ<EFBFBD><CABE>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>ر<EFBFBD><D8B1><EFBFBD>ʾ
/// </summary>
public string HelpName
{
get
{
if (helpLabel != null) return helpLabel.text;
return null;
}
set
{
if (helpLabel != null)
{
if (value != null)
{
helpLabel.text = value;
helpLabel.gameObject.SetActive(true);
}
else
helpLabel.gameObject.SetActive(false);
}
}
}
public string UnitName
{
get => unitLabel.text;
set => unitLabel.text = value;
}
[SerializeField]
// [Obsolete("<22><>ʹ<EFBFBD>÷<EFBFBD><C3B7><EFBFBD><EFBFBD><EFBFBD>")]
private object _value;
/// <summary>
/// <20><>Ŀֵ
/// </summary>
public object Value
{
get => _value;
protected set
{
if (IsValueInitNull && value != null)
IsValueInitNull = false;
_value = value;
}
}
// ==== <20>ݴ<EFBFBD> ==== //
public FieldInfo FieldInfo;
public Type FieldType;
#endregion
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
protected virtual void OnValidate()
{
if (titleLabel != null)
TitleName = titleTextContext;
if (helpLabel != null)
HelpName = helpTextContext;
if (unitLabel != null)
UnitName = unitTextContext;
}
protected virtual void Awake()
{
foreach (var child in transform.GetChildren())
{
var component = child.GetComponent<UIBehaviour>();
if (component != null)
Initialization_ChildConstruction(component);
}
Initialization_EventBinding();
}
protected virtual void OnEnable()
{
ConfigItemList.Add(this);
ForceUpdateAllConfigEvent += ForceUpdate;
ForceSetAllSourceValueEvent += SetSourceValueRequest;
if (dirtyAutoReset)
IsDirty = false;
}
protected virtual void OnDisable()
{
ConfigItemList.Remove(this);
ForceUpdateAllConfigEvent -= ForceUpdate;
ForceSetAllSourceValueEvent -= SetSourceValueRequest;
}
protected virtual void Start()
{
ForceUpdate(true);
}
private void Update()
{
if (IsValueInitNull || (AutoUpdateValue && !(allowBlockUpdate && forceBlockUpdate)))
{
ForceUpdate();
}
}
private void OnDestroy()
{
ForceUpdateAllConfigEvent -= ForceUpdate;
}
#endregion
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><EFBFBD>
protected static double CastDigitalNumber(object newValue)
{
if (double.TryParse(newValue.ToString(), out var value))
{
return value;
}
return -1;
}
/// <summary>
/// ת<><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD>ֵǯ<D6B5><C7AF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
/// <param name="newValue"></param>
/// <param name="minValue"></param>
/// <param name="maxValue"></param>
/// <param name="digits"></param>
/// <returns></returns>
protected static double CastDigitalNumber(object newValue, double minValue, double maxValue, int digits)
{
// var resultValue = newValue switch
// {
// bool boolValue => boolValue ? 1 : 0,
// short intValue => intValue,
// int intValue => intValue,
// long intValue => intValue,
// float floatValue => Math.Round(floatValue, digits),
// double doubleValue => Math.Round(doubleValue, digits),
// _ => 0
// };
#if UNITY_EDITOR
if (newValue == null)
{
Debug.LogError($"<22><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:Ŀ<><C4BF><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD>ڷ<EFBFBD><DAB7><EFBFBD><EFBFBD><EFBFBD>ֵʱ<D6B5><CAB1>ǰ<EFBFBD>˳<EFBFBD>");
return -1;
}
#endif
if (double.TryParse(newValue.ToString(), out var value))
{
var resultValue = Math.Round(value, digits);
return Math.Clamp(resultValue, minValue, maxValue);
}
Debug.LogError($"<22><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:{newValue}<7D><><EFBFBD>ܲ<EFBFBD><DCB2><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD>ֵ");
return -1;
}
protected static int CastIntNumber(object newValue)
{
var resultValue = Convert.ToInt32(newValue);
return resultValue;
}
protected static Vector2 CastVector2(object newValue)
{
return newValue switch
{
Vector2 vec2Value => vec2Value,
System.Numerics.Vector2 sysVec2Value => new Vector2(sysVec2Value.X, sysVec2Value.Y),
_ => Vector2.zero
};
}
protected static Vector3 CastVector3(object newValue)
{
return newValue switch
{
Vector3 vec3Value => vec3Value,
System.Numerics.Vector3 sysVec3Value => new Vector3(sysVec3Value.X, sysVec3Value.Y, sysVec3Value.Z),
_ => Vector3.zero
};
}
#endregion
#region <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// <summary>
/// <20><>ѡ<EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>
/// </summary>
/// <param name="autoUpdateValue"><3E><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD></param>
protected void Initialization(bool autoUpdateValue = true)
{
AutoUpdateValue = autoUpdateValue;
}
private bool _doOnce = false;
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԣ<EFBFBD><D4A3>ڳ<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>ͨ<EFBFBD><CDA8>ʶ<EFBFBD><CAB6><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
protected virtual void Initialization_ChildConstruction(UIBehaviour component)
{
// <20><><EFBFBD>ٽڵ<D9BD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
var name = component.gameObject.name;
// <20><>ʼ<EFBFBD><CABC><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>¶Թ<C2B6>
if (name == "toggle" && component is Toggle toggle)
{
if (autoUpdateValueToggle == null)
autoUpdateValueToggle = toggle;
return;
}
if (name is not ("title" or "name")) return;
if (_doOnce)
{
Debug.LogError("<22><><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD>飺" + name);
return;
}
if (component is TextMeshProUGUI textMeshProUGUI)
{
_doOnce = true;
if (titleLabel != null)
titleLabel = textMeshProUGUI;
}
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>̬<EFBFBD>󶨵İ<F3B6A8B5><C4B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
protected virtual void Initialization_EventBinding()
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Σ<EFBFBD><CEA3>¼<EFBFBD><C2BC><EFBFBD>Ҫ<EFBFBD><D2AA>ע<EFBFBD><D7A2>
if (autoUpdateValueToggle != null)
{
autoUpdateValueToggle.onValueChanged.AddListener(a =>
{
autoUpdateValue = autoUpdateValueToggleReversalState ^ a;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD>ֶ<EFBFBD>
SetSourceValueAutoUpdate?.Invoke(autoUpdateValue);
// <20><><EFBFBD>ܲ<EFBFBD><DCB2><EFBFBD><EFBFBD><EFBFBD>
// OnValueDirty?.Invoke(this);
});
}
}
#endregion
#region <EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><EFBFBD><EFBFBD>
/// <summary>
/// <20><><EFBFBD>º<EFBFBD><C2BA><EFBFBD>
/// <code>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD>̵<EFBFBD><CCB5><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ǿ<EFBFBD><C7BF>ˢ<EFBFBD><CBA2><EFBFBD><EFBFBD><EFBFBD>еĹ<D0B5><C4B9>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>򲻻<EFBFBD><F2B2BBBB><EFBFBD><EFBFBD>κ<EFBFBD><CEBA><EFBFBD>Ϊ<EFBFBD><CEAA>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD>ӱ<EFBFBD><D3B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>и<EFBFBD><D0B8>£<EFBFBD><C2A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̲<EFBFBD><CCB2><EFBFBD>ֵ<EFBFBD><D6B5>ȡ<EFBFBD>ص<EFBFBD><D8B5><EFBFBD>
/// </code>
/// </summary>
public virtual void ForceUpdate(bool resetDirty = false, bool forceSet = false)
{
if (resetDirty)
IsDirty = false;
var value = GetSourceValue?.Invoke(this);
if (value == null)
return ;
RefreshValueWithoutEvent(value, forceSet);
RefreshAutoUpdateValue();
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD>ɽ<EFBFBD><C9BD><EFBFBD><E6B7A2><EFBFBD><EFBFBD><EFBFBD>Բ<EFBFBD><D4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
/// </summary>
/// <param name="newValue"></param>
protected virtual void SetValue(object newValue)
{
if (Value == newValue)
return;
var lastValue = Value;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EBA3AC><EFBFBD><EFBFBD>λΪ<CEBB><CEAA><EFBFBD>ڵ<EFBFBD>ֵ
if (!allowInput)
RefreshValueWithoutEvent(Value);
else
{
Value = newValue;
IsDirty = true;
OnAnyValueChange?.Invoke(this, lastValue);
OnValueChange?.Invoke(this, lastValue);
}
}
/// <summary>
/// <20><><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD>ý<EFBFBD><C3BD>н<EFBFBD><D0BD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD>¡<EFBFBD>
/// </summary>
/// <param name="newValue"></param>
/// <param name="forceSet"></param>
public virtual void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
{
if (!AutoUpdateValue && !forceSet)
return;
if (newValue == null)
return;
if (Value != null && (Value.ToString() == newValue.ToString()))
return;
Value = newValue;
RefreshFormatValue(newValue);
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>״̬
/// </summary>
protected void RefreshAutoUpdateValue()
{
var isSourceValueAutoUpdate = GetSourceValueAutoUpdate?.Invoke(this);
if (isSourceValueAutoUpdate != null)
AutoUpdateValue = isSourceValueAutoUpdate.Value;
}
/// <summary>
/// ˢ<>¸<EFBFBD>ʽ<EFBFBD><CABD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>ڴ<EFBFBD><DAB4><EFBFBD>ˢ<EFBFBD><CBA2>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
protected virtual void RefreshFormatValue(object newValue)
{
}
protected void WhenStartEdit()
{
// Debug.Log("<22><>ʼ<EFBFBD>༭");
ForceBlockUpdate = true;
}
/// <summary>
/// <20><>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϣ<EFBFBD><CFA3>򽹵<EFBFBD><F2BDB9B5>Ƴ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD>á<EFBFBD>
/// </summary>
protected void WhenEndEdit()
{
// Debug.Log("<22><><EFBFBD><EFBFBD><EFBFBD>༭");
ForceBlockUpdate = false;
OnEndEdit?.Invoke(this, Value);
}
#endregion
#region <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD>¸<EFBFBD>ѡ<EFBFBD>򣬲<EFBFBD><F2A3ACB2><EFBFBD><E8B6A8>ǰ<EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
/// <param name="autoUpdateValue"></param>
public void DestroyAutoUpdateValue(bool autoUpdateValue)
{
Destroy(autoUpdateValueToggle.gameObject);
this.autoUpdateValue = autoUpdateValueReversalState ^ autoUpdateValue;
}
#endregion
}
}