diff --git a/Runtime/Helper/MacroEventTrigger.cs b/Runtime/Helper/MacroEventTrigger.cs
new file mode 100644
index 0000000..ca23109
--- /dev/null
+++ b/Runtime/Helper/MacroEventTrigger.cs
@@ -0,0 +1,165 @@
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Events;
+using UnityEngine.EventSystems;
+using XericLibrary.Runtime.MacroLibrary;
+
+namespace DigitalTwinTool
+{
+ public static class MacroEventTrigger
+ {
+ #region 基本事件
+
+ ///
+ /// 添加事件
+ ///
+ ///
+ ///
+ ///
+ public static void AddEntryEvent(this EventTrigger eventTrigger, EventTriggerType eventType,
+ UnityAction entryEvent)
+ {
+ var e = new EventTrigger.TriggerEvent();
+ e.AddListener(entryEvent);
+ var eventData = new EventTrigger.Entry()
+ {
+ eventID = eventType,
+ callback = e,
+ };
+ eventTrigger.triggers.Add(eventData);
+ }
+
+ ///
+ /// 移除类别下的所有事件
+ ///
+ ///
+ ///
+ public static void RemoveEntryEvent(this EventTrigger eventTrigger, EventTriggerType eventType)
+ {
+ foreach (var trigger in eventTrigger.triggers
+ .Where(a => a.eventID == eventType))
+ {
+ eventTrigger.triggers.Remove(trigger);
+ }
+ }
+
+ ///
+ /// 移除事件
+ ///
+ ///
+ ///
+ public static void RemoveEntryEvent(this EventTrigger eventTrigger, UnityAction entryEvent)
+ {
+ // 不知道,所以全部欧拉一遍
+ eventTrigger.triggers
+ .ForEachDo(a => a.callback.RemoveListener(entryEvent));
+ }
+
+ ///
+ /// 清除所有事件
+ ///
+ ///
+ public static void RemoveAllEntryEvent(this EventTrigger eventTrigger)
+ {
+ eventTrigger.triggers.Clear();
+ }
+
+ ///
+ /// 尝试返回光标事件下的碰撞结果
+ ///
+ ///
+ ///
+ public static bool TryGetPointerEventData(this BaseEventData data, out RaycastResult result)
+ {
+ if (data is PointerEventData pointer)
+ {
+ result = pointer.pointerCurrentRaycast;
+ return true;
+ }
+ result = default;
+ return false;
+ }
+
+ #endregion
+
+ #region 细节事件
+
+ public static EventTrigger.TriggerEvent OnPointerEnter(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.PointerEnter);
+
+ public static EventTrigger.TriggerEvent OnPointerExit(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.PointerExit);
+
+ public static EventTrigger.TriggerEvent OnPointerDown(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.PointerDown);
+
+ public static EventTrigger.TriggerEvent OnPointerUp(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.PointerUp);
+
+ public static EventTrigger.TriggerEvent OnPointerClick(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.PointerClick);
+
+ public static EventTrigger.TriggerEvent OnDrag(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Drag);
+
+ public static EventTrigger.TriggerEvent OnDrop(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Drop);
+
+ public static EventTrigger.TriggerEvent OnScroll(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Scroll);
+
+ public static EventTrigger.TriggerEvent OnUpdateSelected(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.UpdateSelected);
+
+ public static EventTrigger.TriggerEvent OnSelect(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Select);
+
+ public static EventTrigger.TriggerEvent OnDeselect(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Deselect);
+
+ public static EventTrigger.TriggerEvent OnMove(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Move);
+
+ public static EventTrigger.TriggerEvent OnInitializePotentialDrag(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.InitializePotentialDrag);
+
+ public static EventTrigger.TriggerEvent OnBeginDrag(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.BeginDrag);
+
+ public static EventTrigger.TriggerEvent OnEndDrag(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.EndDrag);
+
+ ///
+ /// 用户提交输入时触发(比如回车)
+ ///
+ ///
+ ///
+ public static EventTrigger.TriggerEvent OnSubmit(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Submit);
+
+ public static EventTrigger.TriggerEvent OnCancel(this EventTrigger eventTrigger)
+ => eventTrigger.GetEventTrigger(EventTriggerType.Cancel);
+
+ private static EventTrigger.TriggerEvent GetEventTrigger(this EventTrigger eventTrigger, EventTriggerType type)
+ {
+ EventTrigger.TriggerEvent e = null;
+ var entry = eventTrigger.triggers.FirstOrDefault(a => a.eventID == type);
+ if (entry == null)
+ {
+ e = new EventTrigger.TriggerEvent();
+ entry = new EventTrigger.Entry()
+ {
+ eventID = type,
+ callback = e,
+ };
+ eventTrigger.triggers.Add(entry);
+ }
+ else
+ e = entry.callback;
+
+ return e;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Helper/MacroEventTrigger.cs.meta b/Runtime/Helper/MacroEventTrigger.cs.meta
new file mode 100644
index 0000000..595e9e0
--- /dev/null
+++ b/Runtime/Helper/MacroEventTrigger.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5c736d2c11fc4e03947574b18003d66c
+timeCreated: 1729761085
\ No newline at end of file
diff --git a/Runtime/Helper/MacroLayout.cs b/Runtime/Helper/MacroLayout.cs
new file mode 100644
index 0000000..6456445
--- /dev/null
+++ b/Runtime/Helper/MacroLayout.cs
@@ -0,0 +1,37 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using UnityEngine.UI;
+using XericLibrary.Runtime.MacroLibrary;
+
+namespace DigitalTwinTool
+{
+ public static class MacroLayout
+ {
+ ///
+ /// 将布局组标记为脏,以触发重算。
+ ///
+ ///
+ public static void SetDirty(this LayoutGroup layoutGroup)
+ {
+ var type = typeof(LayoutGroup);
+ var method = type.GetMethod("SetDirty", BindingFlags.Instance | BindingFlags.NonPublic);
+ method?.Invoke(layoutGroup, null);
+ }
+
+ private static HashSet _rebuildSet = new HashSet();
+ public static void WaitParentLayoutRebuild(this MonoBehaviour script)
+ {
+ script.StartCoroutine(waitForRebuild());
+
+ return;
+ IEnumerator waitForRebuild()
+ {
+ yield return null;
+ LayoutRebuilder.MarkLayoutForRebuild(script.RectTransform());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/Helper/MacroLayout.cs.meta b/Runtime/Helper/MacroLayout.cs.meta
new file mode 100644
index 0000000..9cad9aa
--- /dev/null
+++ b/Runtime/Helper/MacroLayout.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 3f162d80c71a441780f9bc255eb5e169
+timeCreated: 1734339863
\ No newline at end of file