using System; using System.Buffers; using System.Collections.Generic; using System.Threading; using AlicizaX; using Cysharp.Threading.Tasks; using UnityEngine; namespace AlicizaX.UI.Runtime { public abstract partial class UIBase { private readonly Dictionary _children = new(); private readonly List _updateableChildren = new(); private void UpdateChildren() { for (int i = 0; i < _updateableChildren.Count; i++) { var meta = _updateableChildren[i]; if (meta.View.State == UIState.Opened) { meta.View.InternalUpdate(); } } } private async UniTask DestroyAllChildren() { var temp = ArrayPool.Shared.Rent(_children.Count); try { int i = 0; foreach (var kvp in _children) { temp[i++] = kvp.Value; } for (int j = 0; j < i; j++) { UIMetadata metadata = temp[j]; if (metadata.View.Visible) { metadata.CancelAsyncOperations(); metadata.EnsureCancellationToken(); await metadata.View.InternalClose(metadata.CancellationToken); } await metadata.DisposeAsync(); UIMetadataFactory.ReturnToPool(metadata); temp[j] = null; } } finally { ArrayPool.Shared.Return(temp, true); } _children.Clear(); _updateableChildren.Clear(); } private void ChildVisible(bool value) { foreach (KeyValuePair kvp in _children) { UIBase view = kvp.Value.View; if (view.State == UIState.Opened) { view.Visible = value; } } } internal async UniTask CreateWidgetUIAsync(UIMetadata metadata, Transform parent, bool visible) { metadata.CreateUI(); await UIHolderFactory.CreateUIResourceAsync(metadata, parent, this); await ProcessWidget(metadata, visible, metadata.CancellationToken); return (UIBase)metadata.View; } internal UIBase CreateWidgetUISync(UIMetadata metadata, Transform parent, bool visible) { metadata.CreateUI(); UIHolderFactory.CreateUIResourceSync(metadata, parent, this); ProcessWidget(metadata, visible).Forget(); return (UIBase)metadata.View; } #region CreateWidget #region Async protected async UniTask CreateWidgetAsync(string typeName, Transform parent, bool visible = true) { UIMetaRegistry.TryGet(typeName, out var metaRegistry); UIMetadata metadata = UIMetadataFactory.GetWidgetMetadata(metaRegistry.RuntimeTypeHandle); return await CreateWidgetUIAsync(metadata, parent, visible); } protected async UniTask CreateWidgetAsync(Transform parent, bool visible = true) where T : UIBase { UIMetadata metadata = UIMetadataFactory.GetWidgetMetadata(); return (T)await CreateWidgetUIAsync(metadata, parent, visible); } protected async UniTask CreateWidgetAsync(UIHolderObjectBase holder) where T : UIBase { UIMetadata metadata = UIMetadataFactory.GetWidgetMetadata(); metadata.CreateUI(); UIBase widget = (UIBase)metadata.View; widget.BindUIHolder(holder, this); await ProcessWidget(metadata, true, metadata.CancellationToken); return (T)widget; } #endregion #region Sync protected UIBase CreateWidgetSync(string typeName, Transform parent, bool visible = true) { UIMetaRegistry.TryGet(typeName, out var metaRegistry); UIMetadata metadata = UIMetadataFactory.GetWidgetMetadata(metaRegistry.RuntimeTypeHandle); return CreateWidgetUISync(metadata, parent, visible); } protected T CreateWidgetSync(Transform parent, bool visible = true) where T : UIBase { UIMetadata metadata = UIMetadataFactory.GetWidgetMetadata(); return (T)CreateWidgetUISync(metadata, parent, visible); } protected T CreateWidgetSync(UIHolderObjectBase holder) where T : UIBase { UIMetadata metadata = UIMetadataFactory.GetWidgetMetadata(); metadata.CreateUI(); UIBase widget = (UIBase)metadata.View; widget.BindUIHolder(holder, this); ProcessWidget(metadata, true).Forget(); return (T)widget; } #endregion #endregion private async UniTask ProcessWidget(UIMetadata meta, bool visible, CancellationToken cancellationToken = default) { if (!AddWidget(meta)) { await meta.DisposeAsync(); UIMetadataFactory.ReturnToPool(meta); return; } await meta.View.InternalInitlized(cancellationToken); meta.View.Visible = visible; if (meta.View.Visible) { await meta.View.InternalOpen(cancellationToken); } } private bool AddWidget(UIMetadata meta) { if (!_children.TryAdd(meta.View, meta)) { Log.Warning("Already has widget:{0}", meta.View); return false; } if (meta.MetaInfo.NeedUpdate) { _updateableChildren.Add(meta); } return true; } public async UniTask RemoveWidget(UIBase widget) { if (_children.Remove(widget, out var meta)) { meta.CancelAsyncOperations(); meta.EnsureCancellationToken(); await widget.InternalClose(meta.CancellationToken); if (meta.MetaInfo.NeedUpdate) { RemoveUpdateableChild(meta); } await meta.DisposeAsync(); UIMetadataFactory.ReturnToPool(meta); } } private void RemoveUpdateableChild(UIMetadata meta) { for (int i = 0; i < _updateableChildren.Count; i++) { if (_updateableChildren[i] != meta) { continue; } int lastIndex = _updateableChildren.Count - 1; _updateableChildren[i] = _updateableChildren[lastIndex]; _updateableChildren.RemoveAt(lastIndex); return; } } } }