using JetBrains.Annotations; using NEG.UI.Area; using NEG.UI.Popup; using NEG.UI.Window; using NEG.Utils; using NegUtils.NEG.UI; using System; using System.Collections.Generic; using UnityEngine; namespace NEG.UI { [PublicAPI] public abstract class UiManager : IDisposable { public static UiManager Instance { get; protected set; } /// /// Current area shown on screen. /// public IArea CurrentArea { get => currentArea; set { currentArea?.Close(); currentArea = value; currentArea?.Open(); } } /// /// Current window that is considered main (focused, lastly opened). Can be null. /// public IWindow CurrentMainWindow { get; protected set; } public PopupData CurrentPopup => currentShownPopup.data; private IArea currentArea; private (PopupData data, int priority) currentShownPopup; protected IDefaultPopup currentDefaultPopup; private PriorityQueue popupsToShow = new(); //TODO: localize private string localizedYes = "Yes", localizedNo = "No", localizedOk = "Ok"; protected UiManager(IArea startArea) { if (Instance != null) { Debug.LogError("Only one instance od UiManager is allowed"); return; } Instance = this; CurrentArea = startArea; } /// /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. It will be closed after pressing ok button. /// /// popup title /// popup content /// text to show on ok button, empty for localized "Ok" /// additional action on ok pressed /// priority of popup (lower number -> show first) /// force show current popup only if currently shown has lower priority /// data for created popup, can be used to invalidate popup (will not show) public PopupData ShowOkPopup(string title, string content, string okText = null, Action okPressed = null, int priority = 0, bool forceShow = false) { var data = new DefaultPopupData(currentDefaultPopup, title, content, new List<(string, Action)>() { (okText ?? localizedOk, okPressed) }); ShowPopup(data, priority, forceShow); return data; } /// /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. It will be closed after pressing yes or no button. /// /// popup title /// popup content /// text to show on yes button, empty for localized "Yes" /// text to show on no button, empty for localized "No" /// additional action on yes pressed /// additional action on no pressed /// priority of popup (lower number -> show first) /// force show current popup only if currently shown has lower priority /// data for created popup, can be used to invalidate popup (will not show) public PopupData ShowYesNoPopup(string title, string content, string yesText = null, string noText = null, Action yesPressed = null, Action noPressed = null, int priority = 0, bool forceShow = false) { var data = new DefaultPopupData(currentDefaultPopup, title, content, new List<(string, Action)>() { (yesText ?? localizedYes, yesPressed), (noText ?? localizedNo, noPressed) }); ShowPopup(data, priority, forceShow); return data; } /// /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. It will be closed after pressing any button. /// /// popup title /// popup content /// list of actions /// priority of popup (lower number -> show first) /// force show current popup only if currently shown has lower priority /// data for created popup, can be used to invalidate popup (will not show) public PopupData ShowPopup(string title, string content, List<(string, Action)> actions, int priority = 0, bool forceShow = false) { var data = new DefaultPopupData(currentDefaultPopup, title, content, actions); ShowPopup(data, priority, forceShow); return data; } /// /// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later. /// /// popup data object /// priority of popup (lower number -> show first) /// force show current popup only if currently shown has lower priority public void ShowPopup(PopupData data, int priority = 0, bool forceShow = false) { popupsToShow.Enqueue(data, priority); UpdatePopupsState(forceShow, priority, data); } public void UseBack() { IControllable.BackUsed backUsed = new(); CurrentMainWindow?.TryUseBack(ref backUsed); if(backUsed.Used) return; CurrentArea.TryUseBack(ref backUsed); } public void RefreshPopups() { if(currentShownPopup.data is { IsValid: true }) return; UpdatePopupsState(false); } public virtual void Dispose() => Instance = null; public void SetMainWindow(IWindow window) => CurrentMainWindow = window; public void OnWindowClosed(IWindow window) { if(CurrentMainWindow != window) return; //TODO: select new main window } protected void PopupClosed(PopupData data) { if (currentShownPopup.data != data) { //Debug.LogError("Popup was not shown"); return; } UpdatePopupsState(false); } protected void SetDefaultPopup(IDefaultPopup popup) => currentDefaultPopup = popup; private void UpdatePopupsState(bool forceShow, int priority = 0, PopupData data = null) { if (forceShow) { if(currentShownPopup.data != null && currentShownPopup.priority >= priority) return; popupsToShow.Enqueue(currentShownPopup.data, currentShownPopup.priority); ShowPopup(data, priority); return; } while (popupsToShow.TryDequeue(out var d, out int p)) { if(d == null) continue; if(!d.IsValid) continue; if(d == currentShownPopup.data) continue; ShowPopup(d, p); return; } if (currentShownPopup.data == null) return; currentShownPopup.data.PopupClosedEvent -= PopupClosed; currentShownPopup.data.Hide(); currentShownPopup.data = null; } private void ShowPopup(PopupData data, int priority) { if (currentShownPopup.data != null) { currentShownPopup.data.PopupClosedEvent -= PopupClosed; currentShownPopup.data.Hide(); } currentShownPopup = (data, priority); data.Show(); data.PopupClosedEvent += PopupClosed; } } }