using System; using System.Collections.Generic; using System.Linq; using UnityEngine.Rendering; namespace UnityEngine.Rendering.UI { /// /// Debug UI Prefab bundle. /// [Serializable] public class DebugUIPrefabBundle { /// type of the widget. public string type; /// Prefab for the widget. public RectTransform prefab; } /// /// DebugUIHandler for canvas widget. /// public class DebugUIHandlerCanvas : MonoBehaviour { int m_DebugTreeState; Dictionary m_PrefabsMap; /// Panel prefab. public Transform panelPrefab; /// List of prefabs. public List prefabs; List m_UIPanels; int m_SelectedPanel; DebugUIHandlerWidget m_SelectedWidget; string m_CurrentQueryPath; void OnEnable() { if (prefabs == null) prefabs = new List(); if (m_PrefabsMap == null) m_PrefabsMap = new Dictionary(); if (m_UIPanels == null) m_UIPanels = new List(); DebugManager.instance.RegisterRootCanvas(this); } void Update() { int state = DebugManager.instance.GetState(); if (m_DebugTreeState != state) { ResetAllHierarchy(); } HandleInput(); // Update scroll position in the panel if (m_UIPanels != null && m_SelectedPanel < m_UIPanels.Count && m_UIPanels[m_SelectedPanel] != null) m_UIPanels[m_SelectedPanel].UpdateScroll(); } internal void RequestHierarchyReset() { m_DebugTreeState = -1; } void ResetAllHierarchy() { foreach (Transform t in transform) CoreUtils.Destroy(t.gameObject); Rebuild(); } void Rebuild() { // Check prefab associations m_PrefabsMap.Clear(); foreach (var bundle in prefabs) { var type = Type.GetType(bundle.type); if (type != null && bundle.prefab != null) m_PrefabsMap.Add(type, bundle.prefab); } m_UIPanels.Clear(); m_DebugTreeState = DebugManager.instance.GetState(); var panels = DebugManager.instance.panels; #if UNITY_ANDROID || UNITY_IPHONE // Mobile device safe area Rect parentRect = GetComponentInParent().rect; float parentWidth = Math.Min(parentRect.width, parentRect.height); float scaleRatio = parentWidth / Math.Min(Screen.height, Screen.width); Rect safeAreaRect = Screen.safeArea; Vector2 margin = new Vector2(5, 5); var safeAreaOffsetLeft = safeAreaRect.xMin * scaleRatio; var safeAreaOffsetTop = -safeAreaRect.yMin * scaleRatio; Vector2 safeAreaOffset = new Vector2(safeAreaOffsetLeft, safeAreaOffsetTop) + margin; #endif DebugUIHandlerWidget selectedWidget = null; foreach (var panel in panels) { if (panel.isEditorOnly || panel.children.Count(x => !x.isEditorOnly && !x.isHidden) == 0) continue; var go = Instantiate(panelPrefab, transform, false).gameObject; go.name = panel.displayName; #if UNITY_ANDROID || UNITY_IPHONE RectTransform rectTransform = go.GetComponent(); rectTransform.anchoredPosition = safeAreaOffset; rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, safeAreaRect.height * scaleRatio + 2 * safeAreaOffsetTop); #endif var uiPanel = go.GetComponent(); uiPanel.SetPanel(panel); uiPanel.Canvas = this; m_UIPanels.Add(uiPanel); var container = go.GetComponent(); DebugUIHandlerWidget selected = null; Traverse(panel, container.contentHolder, null, ref selected); if (selected != null && selected.GetWidget().queryPath.Contains(panel.queryPath)) { selectedWidget = selected; } } ActivatePanel(m_SelectedPanel, selectedWidget); } void Traverse(DebugUI.IContainer container, Transform parentTransform, DebugUIHandlerWidget parentUIHandler, ref DebugUIHandlerWidget selectedHandler) { DebugUIHandlerWidget previousUIHandler = null; for (int i = 0; i < container.children.Count; i++) { var child = container.children[i]; if (child.isEditorOnly || child.isHidden) continue; Transform prefab; if (!m_PrefabsMap.TryGetValue(child.GetType(), out prefab)) { Debug.LogWarning("DebugUI widget doesn't have a prefab: " + child.GetType()); continue; } var go = Instantiate(prefab, parentTransform, false).gameObject; go.name = child.displayName; var uiHandler = go.GetComponent(); if (uiHandler == null) { Debug.LogWarning("DebugUI prefab is missing a DebugUIHandler for: " + child.GetType()); continue; } if (!string.IsNullOrEmpty(m_CurrentQueryPath) && child.queryPath.Equals(m_CurrentQueryPath)) { selectedHandler = uiHandler; } if (previousUIHandler != null) previousUIHandler.nextUIHandler = uiHandler; uiHandler.previousUIHandler = previousUIHandler; previousUIHandler = uiHandler; uiHandler.parentUIHandler = parentUIHandler; uiHandler.SetWidget(child); var childContainer = go.GetComponent(); if (childContainer != null && child is DebugUI.IContainer childAsContainer) Traverse(childAsContainer, childContainer.contentHolder, uiHandler, ref selectedHandler); } } DebugUIHandlerWidget GetWidgetFromPath(string queryPath) { if (string.IsNullOrEmpty(queryPath)) return null; var panel = m_UIPanels[m_SelectedPanel]; return panel .GetComponentsInChildren() .FirstOrDefault(w => w.GetWidget().queryPath == queryPath); } void ActivatePanel(int index, DebugUIHandlerWidget selectedWidget = null) { if (m_UIPanels.Count == 0) return; if (index >= m_UIPanels.Count) index = m_UIPanels.Count - 1; m_UIPanels.ForEach(p => p.gameObject.SetActive(false)); m_UIPanels[index].gameObject.SetActive(true); m_SelectedPanel = index; if (selectedWidget == null) selectedWidget = m_UIPanels[index].GetFirstItem(); ChangeSelection(selectedWidget, true); } internal void ChangeSelection(DebugUIHandlerWidget widget, bool fromNext) { if (widget == null) return; if (m_SelectedWidget != null) m_SelectedWidget.OnDeselection(); var prev = m_SelectedWidget; m_SelectedWidget = widget; SetScrollTarget(widget); if (!m_SelectedWidget.OnSelection(fromNext, prev)) { if (fromNext) SelectNextItem(); else SelectPreviousItem(); } else { if (m_SelectedWidget == null || m_SelectedWidget.GetWidget() == null) m_CurrentQueryPath = string.Empty; else m_CurrentQueryPath = m_SelectedWidget.GetWidget().queryPath; } } internal void SelectPreviousItem() { if (m_SelectedWidget == null) return; var newSelection = m_SelectedWidget.Previous(); if (newSelection != null) ChangeSelection(newSelection, false); } internal void SelectNextPanel() { int index = m_SelectedPanel + 1; if (index >= m_UIPanels.Count) index = 0; index = Mathf.Clamp(index, 0, m_UIPanels.Count - 1); ActivatePanel(index); } internal void SelectPreviousPanel() { int index = m_SelectedPanel - 1; if (index < 0) index = m_UIPanels.Count - 1; index = Mathf.Clamp(index, 0, m_UIPanels.Count - 1); ActivatePanel(index); } internal void SelectNextItem() { if (m_SelectedWidget == null) return; var newSelection = m_SelectedWidget.Next(); if (newSelection != null) ChangeSelection(newSelection, true); } void ChangeSelectionValue(float multiplier) { if (m_SelectedWidget == null) return; bool fast = DebugManager.instance.GetAction(DebugAction.Multiplier) != 0f; if (multiplier < 0f) m_SelectedWidget.OnDecrement(fast); else m_SelectedWidget.OnIncrement(fast); } void ActivateSelection() { if (m_SelectedWidget == null) return; m_SelectedWidget.OnAction(); } void HandleInput() { if (DebugManager.instance.GetAction(DebugAction.PreviousDebugPanel) != 0f) { SelectPreviousPanel(); } if (DebugManager.instance.GetAction(DebugAction.NextDebugPanel) != 0f) { SelectNextPanel(); } if (DebugManager.instance.GetAction(DebugAction.Action) != 0f) ActivateSelection(); if (DebugManager.instance.GetAction(DebugAction.MakePersistent) != 0f && m_SelectedWidget != null) DebugManager.instance.TogglePersistent(m_SelectedWidget.GetWidget()); float moveHorizontal = DebugManager.instance.GetAction(DebugAction.MoveHorizontal); if (moveHorizontal != 0f) ChangeSelectionValue(moveHorizontal); float moveVertical = DebugManager.instance.GetAction(DebugAction.MoveVertical); if (moveVertical != 0f) { if (moveVertical < 0f) SelectNextItem(); else SelectPreviousItem(); } } internal void SetScrollTarget(DebugUIHandlerWidget widget) { if (m_UIPanels != null && m_SelectedPanel < m_UIPanels.Count && m_UIPanels[m_SelectedPanel] != null) m_UIPanels[m_SelectedPanel].SetScrollTarget(widget); } } }