using System.Collections.Generic; using UnityEngine; using TMPro; using UnityEngine.UI; public class LogicTrayUI : LogicElementHolder { [SerializeField] protected LogicElementUI Prefab; [SerializeField] protected int insertIndex = -1; [SerializeField] private Transform content; [SerializeField] private GameObject playButton; [SerializeField] private GameObject returnButton; [SerializeField] private Image border; [SerializeField] private int maxLength = 6; [SerializeField] public BlockReader reader; [SerializeField] private List readerQueue = new List(); #region Unity Functions public void Start() { readerQueue.Add(new QueueData(reader, border.color)); UpdateDisplay(); } protected override void OnEnable() { base.OnEnable(); if (reader != null) reader.OnUpdate += UpdateDisplay; } protected override void OnDisable() { base.OnDisable(); if (reader != null) reader.OnUpdate -= UpdateDisplay; } #endregion Unity Functions public void SetBlockReader(BlockReader newBlockReader) { if (reader != null) reader.OnUpdate -= UpdateDisplay; reader = newBlockReader; reader.OnUpdate += UpdateDisplay; UpdateDisplay(); } public void OnClick_Return() { if (readerQueue.Count <= 1) return; QueueData lastData = readerQueue[readerQueue.Count - 1]; readerQueue.RemoveAt(readerQueue.Count - 1); border.color = readerQueue[readerQueue.Count - 1].color; SetBlockReader(readerQueue[readerQueue.Count - 1].reader); UpdateDisplay(); } [ContextMenu("Update Display")] public void UpdateDisplay() { if (reader == null) return; //Destroy all children int destroyedCount = content.childCount; //we need to know how many were destroyed since unity doesn't actually destroy anything until the end of the frame foreach (Transform child in content) Destroy(child.gameObject); //Instatiate logicElement prefab foreach (LogicBlock element in reader.LogicChain) { LogicElementUI elementUI = Instantiate(Prefab.gameObject, content).GetComponent(); elementUI.Initialise(element, this,false); } //Add insertIndex object if needed if (insertIndex != -1) { GameObject elementObject = Instantiate(Prefab.gameObject, content); if (reader.Length < maxLength) { elementObject.GetComponentInChildren().text = "insert"; elementObject.GetComponentInChildren().color = new Color(0.5f, 0.5f, 0.5f, 0.25f); } else { elementObject.GetComponentInChildren().text = "X"; elementObject.GetComponentInChildren().color = new Color(1.0f, 0.25f, 0.25f, 0.5f); } //Set sibling index to where we want it in list + add destroyedCount since technically they are still here elementObject.transform.SetSiblingIndex(destroyedCount + insertIndex); } playButton.SetActive(readerQueue.Count <= 1); returnButton.SetActive(readerQueue.Count > 1); } #region LogicElementHolder Implementation /// /// When a LogicElement has started being dragged from this Tray /// /// Element which is being dragged public override void OnRemove(LogicElementUI element) { Vector2 offset = new Vector2(element.rectTransform.rect.width / 2, 0); int index = GetInsertIndex(element.rectTransform, offset); Debug.Log("Removing at " + index); if (index >= reader.LogicChain.Count) index = reader.LogicChain.Count - 1; reader.LogicChain.RemoveAt(index); } /// /// When a logicElement needs to be added back to this Tray /// /// Element to add public override void OnAdd(LogicElementUI element) { Vector2 offset = new Vector2(element.rectTransform.rect.width / 2, 0); int index = GetInsertIndex(element.rectTransform,offset); reader.Insert(index, element.logicElement); Destroy(element.gameObject); } /// /// When a logic Element is hovering over this holder /// /// Element which is hovering public override void OnHover(LogicElementUI element) { Vector2 offset = new Vector2(element.rectTransform.rect.width / 2, 0); insertIndex = GetInsertIndex(element.rectTransform, offset); UpdateDisplay(); } /// /// First frame a logic Element is hovering over this holder /// /// Element which is hovering public override void OnHoverStart(LogicElementUI element) { Debug.Log("OnHoverStart"); //Create insert prefab at End insertIndex = content.childCount; UpdateDisplay(); } /// /// first frame a logic Element is no longer hovering over this holder /// /// Element which is hovering public override void OnHoverEnd(LogicElementUI element) { //Remove insert prefab insertIndex = -1; UpdateDisplay(); } /// /// Called when an element in this holder is double clicked /// /// element which was double clicked public override void OnDoubleClick(LogicElementUI element) { EditableBlock block = element.logicElement as EditableBlock; if (block == null) return; readerQueue.Add(new QueueData(block.blockReader,block.Color)); border.color = block.Color; SetBlockReader(block.blockReader); } /// /// Called to check if this holder can hold the provided element; /// /// element to check if it can hold /// returns true if this can hold the element public override bool canHold(LogicBlock element) { return readerQueue[0].reader.Length < maxLength; } #endregion LogicElementHolder Implementation #region Helper Functions public int GetInsertIndex(RectTransform rt, Vector2 offset) { Rect rect = rt.rect; rect.center += offset; rect = rt.TransformRect(rect); DebugExtensions.DrawRect(rect, Color.green); foreach (Transform child in content) { RectTransform childRect = child as RectTransform; if (rect.Overlaps(childRect.GlobalRect())) return child.GetSiblingIndex(); } Debug.Log("Returning last"); return reader.LogicChain.Count; } public int GetInsertIndex(RectTransform rt) { return GetInsertIndex(rt, Vector2.zero); } #endregion Helper Functions [System.Serializable] public class QueueData { public Color color; public BlockReader reader; public QueueData(BlockReader reader, Color color) { this.color = color; this.reader = reader; } } }