using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using XericLibrary.Runtime.MacroLibrary;
using XericLibrary.Runtime.Type;
namespace Deconstruction.UI.TmpText
{
///
/// TMP超链接点击管理组件
///
public class TMPHyperlinkManager : MonoBehaviour
{
///
/// 画布组件
///
#if ODIN_INSPECTOR
[LabelText("画布*")]
#endif
[Tooltip("组件可为空,将自动向上查找")]
[SerializeField]
public Canvas canvas;
#if ODIN_INSPECTOR
[LabelText("点击超链接时回调")]
#endif
[SerializeField]
public UnityEvent onClickLink;
///
/// 当前摄像机
///
private Camera _camera;
///
/// 存储链接ID与对应回调函数的映射
///
private Dictionary _linkCallbacks = new Dictionary();
protected void Awake()
{
if (canvas == null)
transform.GetParents().Startup(transform).GetComponent(out canvas);
if (canvas == null)
{
Debug.LogError("TMP文本对象必须在Canvas下才能使用超链接功能");
return;
}
if (canvas.renderMode == RenderMode.ScreenSpaceOverlay)
_camera = null;
else
_camera = canvas.worldCamera;
}
///
/// 注册链接回调函数
///
public void RegisterLinkCallback(string linkID, Action callback)
{
if (_linkCallbacks.ContainsKey(linkID))
{
Debug.LogWarning($"链接ID '{linkID}' 已存在,将覆盖之前的回调函数");
_linkCallbacks[linkID] = callback;
}
else
{
_linkCallbacks.Add(linkID, callback);
}
}
///
/// 注销链接回调函数
///
public void UnregisterLinkCallback(string linkID)
{
if (_linkCallbacks.ContainsKey(linkID))
{
_linkCallbacks.Remove(linkID);
}
}
///
/// 处理链接点击事件
///
public void HandleLinkClick(string linkID)
{
if (_linkCallbacks.TryGetValue(linkID, out Action callback))
{
callback?.Invoke();
Debug.Log($"执行链接 '{linkID}' 的回调函数");
}
else
{
Debug.LogWarning($"未找到链接ID '{linkID}' 的回调函数");
}
}
///
/// 检查坐标下的超链接索引
///
///
///
///
internal int CheckLinkIndex(TMP_Text text, Vector3 position)
{
return TMP_TextUtilities.FindIntersectingLink(text, position, _camera);
}
///
/// 检查坐标下的超链接id信息
///
///
///
///
///
internal bool CheckLinkInfo(TMP_Text text, Vector3 position, out TMP_LinkInfo linkInfo)
{
var index = CheckLinkIndex(text, position);
if (index != -1)
{
linkInfo = text.textInfo.linkInfo[index];
return true;
}
linkInfo = default;
return false;
}
///
/// 检查坐标下的超链接id
///
///
///
///
///
internal bool CheckLinkID(TMP_Text text, Vector3 position, out string linkID)
{
if (CheckLinkInfo(text, position, out var info))
{
linkID = info.GetLinkID();
return true;
}
linkID = string.Empty;
return false;
}
///
/// 当任意tmp对象超链接点击时调用,从这里发送事件
///
///
internal void OnAnyLinkClick(string linkID)
{
onClickLink?.Invoke(linkID);
Debug.Log($"click link{linkID}");
// 这里不需要处理报错,应当由发送消息的成员处理
}
// todo 主动查找所有的tmp组件,或是等组件唤醒后区管理它们,用来获得所有的带有标记的超链接组件
///
/// 主动查找所有具有link属性的tmp组件
///
/// 自动查找
///
public void FindAllID(bool requirementComponent = true, bool forceRefesh = false)
{
transform.GetChildrenBFS().GetComponentsOTON();
}
private List _tempGetChildrenHyperlink = null;
///
/// 获取所有链接子项
///
/// 强制刷新,如果刷新过一次,之后不论设定如何都将直接从缓存中返回对象,置位将跳过这个缓存
/// 包括重复标记(也就是是否包含另一个超链接管理器作用域下的超链接对象)
public List GetChildrenHyperlink(bool forceRefesh = false,
bool includeRepeatedMarking = false)
{
if (!forceRefesh && _tempGetChildrenHyperlink != null && _tempGetChildrenHyperlink.Count > 0)
return _tempGetChildrenHyperlink;
_tempGetChildrenHyperlink = transform.GetChildrenBFS()
.GetComponentsOTON().ToList();
return _tempGetChildrenHyperlink;
}
private List _tempGetChildrenTmpText2Hyperlink = null;
///
/// 获取所有tmp_text,然后根据规则返回链接
///
/// 强制刷新,如果刷新过一次,之后不论设定如何都将直接从缓存中返回对象,置位将跳过这个缓存
/// 强制给带有link标记的对象加上超链接组件
/// 包括重复标记(也就是是否包含另一个超链接管理器作用域下的超链接对象)
///
public List GetChildrenTmpText2Hyperlink(
bool forceRefesh = false,
bool requirementHyperlink = true,
bool includeRepeatedMarking = false)
{
if (!forceRefesh && _tempGetChildrenTmpText2Hyperlink != null && _tempGetChildrenTmpText2Hyperlink.Count > 0)
return _tempGetChildrenTmpText2Hyperlink;
var children = includeRepeatedMarking
? transform.GetChildrenBFS()
: transform.GetChildrenBFS();
var result = new List();
var hyperlinkType = typeof(TMPHyperlinkReceiver);
var tmpTextType = typeof(TMP_Text);
// 预先分配足够的容量,减少扩容
result.Capacity = Mathf.Min(children.Count(), 10);
foreach (var child in children)
{
// 尝试从缓存获取组件
var hyperlink = child.GetComponent(hyperlinkType) as TMPHyperlinkReceiver;
if (hyperlink != null)
{
result.Add(hyperlink);
continue;
}
if (!requirementHyperlink)
continue;
// 尝试获取TMP_Text组件
var tmp = child.GetComponent(tmpTextType) as TMP_Text;
if (tmp != null && tmp.text.MatchRichTextID())
{
result.Add(child.gameObject.AddComponent());
}
}
return result;
}
}
}