BITKit/Packages/Common~/Scripts/UX/Core/UXWindowManager.cs

219 lines
6.3 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.Events;
using Sirenix.OdinInspector;
using Cysharp.Threading.Tasks;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
namespace BITKit.UX
{
public interface IWindowElement
{
string GetName();
UXElement Navigation { get; }
UXElement Window { get; }
UXWindowManager SubWindowManager { get; }
Task Open(CancellationToken cancellationToken = default);
Task Close(CancellationToken cancellationToken = default);
}
[System.Serializable]
public class UXWindowElement : IWindowElement
{
[SerializeField]
protected string name;
[SerializeField]
protected UXElement navigation;
[SerializeField]
protected UXElement window;
[SerializeField]
protected UXWindowManager subWindowManager;
[SerializeField]
protected bool enabled;
public UXElement Navigation => navigation;
public UXElement Window => window;
public UXWindowManager SubWindowManager => subWindowManager;
public async Task Close(CancellationToken cancellationToken = default)
{
try
{
await UniTask.SwitchToMainThread(cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await UniTask.Yield();
try
{
navigation.GetVisualElement().SetEnabled(true);
}
catch (System.Exception)
{
Debug.LogWarning($"Navgation:{name} 已丢失");
throw;
}
try
{
window.Set(false);
}
catch (System.Exception)
{
Debug.LogWarning($"Window:{name} 已丢失");
throw;
}
enabled = false;
}
catch (System.Exception)
{
Debug.LogWarning(name);
throw;
}
}
public async Task Open(CancellationToken cancellationToken = default)
{
await UniTask.SwitchToMainThread(cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
navigation.GetVisualElement().SetEnabled(false);
window.Set(true);
enabled = true;
}
public string GetName() => name;
}
public class UXWindowManager : MonoBehaviour, INextble
{
public enum WindowState
{
None,
Flex,
Hidden
}
[Header(Constant.Header.Components)]
[SerializeReference, SubclassSelector] public List<IWindowElement> windows = new();
public UXWindowManager subWindowManager;
[Header(Constant.Header.Settings)]
public UXElement startElement;
[SerializeField] bool hidden;
[Header(Constant.Header.Events)]
public UnityEvent<string> OnEntry = new();
public UnityEvent<string> OnExit = new();
[Header(Constant.Header.InternalVariables)]
List<IWindowElement> activeWindows = new();
IWindowElement activeWindow;
public int index { get; private set; }
CancellationTokenSource cts;
public async void Select(UXElement element)
{
cts.Cancel();
cts = new();
foreach (var activeWindow in activeWindows)
{
await activeWindow.Close(cts.Token);
OnExit.Invoke(activeWindow.GetName());
}
activeWindows.Clear();
var window = windows
.Find(x => x.GetName() == element.name || x.Navigation == element || x.Window == element);
index = windows.IndexOf(window);
activeWindows.Add(window);
activeWindow = window;
// currentWindow = window;
try
{
await window.Open();
}
catch (System.Exception)
{
Debug.LogWarning(name);
if (window is null)
{
Debug.Log("Window is Null");
}
throw;
}
OnEntry.Invoke(window.GetName());
}
public bool Next()
{
if (activeWindow is not null && activeWindow.SubWindowManager)
{
if (activeWindow.SubWindowManager.Next())
{
return true;
}
}
if (windows.Count > index + 1)
{
var element = windows[index + 1].Navigation;
Select(element);
}
else
{
return false;
}
return true;
}
public bool Previous()
{
if (activeWindow is not null && activeWindow.SubWindowManager)
{
if (activeWindow.SubWindowManager.Previous())
{
return true;
}
}
if (index - 1 >= 0)
{
var element = windows[index - 1].Navigation;
Select(element);
return true;
}
return false;
}
public bool Hidden
{
get => hidden;
set
{
if (hidden)
{
Exit();
}
else
{
Recovery();
}
}
}
public void Exit()
{
hidden = true;
activeWindow?.Close();
}
public void Recovery()
{
hidden = false;
activeWindow?.Open();
}
void Awake()
{
cts = new();
var ct = gameObject.GetCancellationTokenOnDestroy();
ct.Register(cts.Cancel);
}
async void Start()
{
await UniTask.Yield();
foreach (var window in windows)
{
await window.Close(cts.Token);
}
Select(startElement);
}
}
}