using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; namespace VMdemo.UI { public class SimulationTimelineView : MonoBehaviour { [SerializeField] private RectTransform logContainer; [SerializeField] private TMP_Text logItemPrefab; [SerializeField] private ScrollRect logScrollRect; [SerializeField] private int maxLogEntries = 200; private readonly Queue _logItems = new Queue(); public void Append(string message) { if (logContainer == null || logItemPrefab == null) { return; } var item = Instantiate(logItemPrefab, logContainer); item.gameObject.SetActive(true); item.text = message; item.ForceMeshUpdate(); var autoSize = item.GetComponent(); if (autoSize != null) { autoSize.RefreshLayout(); } else { // Fallback: adapt this text object's rect to preferred content size. var preferred = item.GetPreferredValues(item.text, logContainer.rect.width, 0f); var rect = item.rectTransform; rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, preferred.x); rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, preferred.y); } _logItems.Enqueue(item); while (_logItems.Count > Mathf.Max(1, maxLogEntries)) { var old = _logItems.Dequeue(); if (old != null) { Destroy(old.gameObject); } } LayoutRebuilder.ForceRebuildLayoutImmediate(logContainer); Canvas.ForceUpdateCanvases(); if (logScrollRect != null) { logScrollRect.verticalNormalizedPosition = 0f; } } public void Clear() { while (_logItems.Count > 0) { var item = _logItems.Dequeue(); if (item != null) { Destroy(item.gameObject); } } } } }