Neg_Utils/NEG/UI/UiManager.cs
2024-02-12 21:26:24 +01:00

223 lines
8.6 KiB
C#

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
{
private IArea currentArea;
protected IDefaultPopup currentDefaultPopup;
private (PopupData data, int priority) currentShownPopup;
//TODO: localize
private string localizedYes = "Yes", localizedNo = "No", localizedOk = "Ok";
private List<IWindow> mainWindows;
private PriorityQueue<PopupData, int> popupsToShow = new();
protected UiManager(IArea startArea)
{
if (Instance != null)
{
Debug.LogError("Only one instance od UiManager is allowed");
return;
}
Instance = this;
CurrentArea = startArea;
mainWindows = new List<IWindow>();
}
public static UiManager Instance { get; protected set; }
/// <summary>
/// Current area shown on screen.
/// </summary>
public IArea CurrentArea
{
get => currentArea;
set
{
currentArea?.Close();
currentArea = value;
currentArea?.Open();
}
}
/// <summary>
/// Current window that is considered main (focused, lastly opened). Can be null.
/// </summary>
public IWindow CurrentMainWindow => mainWindows.LastOrDefault();
public PopupData CurrentPopup => currentShownPopup.data;
public virtual void Dispose() => Instance = null;
/// <summary>
/// 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.
/// </summary>
/// <param name="title">popup title</param>
/// <param name="content">popup content</param>
/// <param name="okText">text to show on ok button, empty for localized "Ok"</param>
/// <param name="okPressed">additional action on ok pressed</param>
/// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
/// <returns>data for created popup, can be used to invalidate popup (will not show)</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="title">popup title</param>
/// <param name="content">popup content</param>
/// <param name="yesText">text to show on yes button, empty for localized "Yes"</param>
/// <param name="noText">text to show on no button, empty for localized "No"</param>
/// <param name="yesPressed">additional action on yes pressed</param>
/// <param name="noPressed">additional action on no pressed</param>
/// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
/// <returns>data for created popup, can be used to invalidate popup (will not show)</returns>
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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="title">popup title</param>
/// <param name="content">popup content</param>
/// <param name="actions">list of actions</param>
/// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
/// <returns>data for created popup, can be used to invalidate popup (will not show)</returns>
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;
}
/// <summary>
/// Show popup if there is non other currently shown. Otherwise add current popup to ordered queue and show it later.
/// </summary>
/// <param name="data">popup data object</param>
/// <param name="priority">priority of popup (lower number -> show first)</param>
/// <param name="forceShow">force show current popup only if currently shown has lower priority</param>
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);
//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;
}
}
}