Neg_Utils/NEG/UI/UiManager.cs

186 lines
7.5 KiB
C#

using JetBrains.Annotations;
using NEG.UI.Area;
using NEG.UI.Popup;
using NEG.UI.Window;
using NEG.Utils;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace NEG.UI
{
[PublicAPI]
public abstract class UiManager
{
public static UiManager Instance { get; private set; }
/// <summary>
/// Current area shown on screen.
/// </summary>
public IArea CurrentArea
{
get => currentArea;
set
{
currentArea?.SetEnabled(false);
currentArea = value;
currentArea?.SetEnabled(true);
}
}
/// <summary>
/// Current window that is considered main (focused, lastly opened). Can be null.
/// </summary>
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<PopupData, int> 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;
}
/// <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 RefreshPopups()
{
if(currentShownPopup.data is { IsValid: true })
return;
UpdatePopupsState(false);
}
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.priority <= priority)
return;
popupsToShow.Enqueue(currentShownPopup.data, currentShownPopup.priority);
ShowPopup(data, priority);
return;
}
while (popupsToShow.TryDequeue(out var d, out int p))
{
if(!d.IsValid)
continue;
ShowPopup(d, p);
return;
}
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;
}
}
}