using JetBrains.Annotations; using NEG.UI.Area; using NEG.UI.Popup; using NEG.UI.Window; using NegUtils.NEG.UI; using System; using System.Collections.Generic; using System.Linq; 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 => mainWindows.LastOrDefault(); public PopupData CurrentPopup => currentShownPopup.data; private IArea currentArea; protected IDefaultPopup currentDefaultPopup; private (PopupData data, int priority) currentShownPopup; //TODO: localize private string localizedYes = "Yes", localizedNo = "No", localizedOk = "Ok"; private List mainWindows; private PriorityQueue popupsToShow = new(); private Dictionary registeredWindows = new(); protected UiManager(IArea startArea = default) { if (Instance != null) { Debug.LogError("Only one instance od UiManager is allowed"); return; } Instance = this; CurrentArea = startArea; mainWindows = new List(); } public virtual void Dispose() => Instance = null; /// /// 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 void SetMainWindow(IWindow window) => mainWindows.Add(window); public void MainWindowClosed(IWindow window) => mainWindows.Remove(window); public void OnWindowClosed(IWindow window) => MainWindowClosed(window); internal void RegisterWindow(IWindow window) => registeredWindows.Add(window.WindowId, window); internal void UnRegisterWindow(IWindow window) => registeredWindows.Remove(window.WindowId); //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; protected virtual 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; } } }