using Uigenx.Binding; using UnityEngine; using UnityEngine.UIElements; namespace Uigenx { /// /// Drives one generated screen on one . Use it for a screen that is /// simply present in a scene; use when screens are pushed and /// popped at runtime. /// [AddComponentMenu("UI Creator/Document")] [RequireComponent(typeof(UIDocument))] [DisallowMultipleComponent] public sealed class UgxDocument : MonoBehaviour { [Tooltip("Screen key as exported by UI Creator, for example `Hud`.")] [SerializeField] string screenKey; [Tooltip("Object implementing IUgxDataSource. Optional; the screen binds to nothing without it.")] [SerializeField] UnityEngine.Object dataSourceObject; [SerializeField] bool autoShow = true; [SerializeField] UgxScreenRegistry registryOverride; UIDocument _document; UgxScreen _screen; VisualElement _container; bool _ownsContainer; // A plain C# source cannot live in the serialized field, so it is held here and wins. IUgxDataSource _runtimeDataSource; public UgxScreen Screen => _screen; public string ScreenKey { get => screenKey; set { if (screenKey == value) return; screenKey = value; if (isActiveAndEnabled) Reopen(); } } public IUgxDataSource DataSource { get => _runtimeDataSource ?? dataSourceObject as IUgxDataSource; set { _runtimeDataSource = value; dataSourceObject = value as UnityEngine.Object; if (isActiveAndEnabled) Reopen(); } } void OnEnable() => Open(); void OnDisable() => Close(); public void Reopen() { Close(); Open(); } void Open() { if (string.IsNullOrEmpty(screenKey)) return; _document = GetComponent(); var registry = registryOverride != null ? registryOverride : UgxScreenRegistry.Active; if (registry == null) { Debug.LogError("[ugx] no screen registry is available for '" + screenKey + "'", this); return; } if (!registry.TryGet(screenKey, out var entry)) { Debug.LogError("[ugx] screen '" + screenKey + "' is not in the registry. Re-export it from " + "UI Creator.", this); return; } _screen = UgxScreens.Create(screenKey); if (_screen == null) { Debug.LogError("[ugx] no generated factory can create screen '" + screenKey + "'. Check that UgxScreenFactory.g.cs compiled.", this); return; } _container = ResolveContainer(entry); if (_container == null) return; ApplyStyles(entry, _container); _screen.Attach(_container, DataSource); if (autoShow) _screen.Show(); else _container.style.display = DisplayStyle.None; } void Close() { _screen?.Detach(); _screen = null; if (_ownsContainer) _container?.RemoveFromHierarchy(); _container = null; _ownsContainer = false; } VisualElement ResolveContainer(UgxScreenEntry entry) { if (entry.Uxml == null) { Debug.LogError("[ugx] screen '" + screenKey + "' has no VisualTreeAsset in the registry", this); return null; } // Assigning the asset makes UIDocument rebuild its tree straight away, so the clone is // available on the next line. _document.visualTreeAsset = entry.Uxml; var root = _document.rootVisualElement; if (root == null) return null; if (root.childCount > 0) { _ownsContainer = false; return root[0]; } var container = entry.Uxml.Instantiate(); container.style.flexGrow = 1f; root.Add(container); _ownsContainer = true; return container; } static void ApplyStyles(UgxScreenEntry entry, VisualElement container) { var styles = entry.Styles; if (styles == null) return; foreach (var sheet in styles) if (sheet != null && !container.styleSheets.Contains(sheet)) container.styleSheets.Add(sheet); } } }