// Copyright (c) Pixel Crushers. All rights reserved.
using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;
namespace PixelCrushers.QuestMachine
{
///
/// Unity UI implementation of QuestAlertUI.
///
[AddComponentMenu("")] // Use wrapper.
public class UnityUIQuestAlertUI : UnityUIBaseUI, IQuestAlertUI //[TODO] 1. Show UI Content list; 2. Scroll multiple alerts as they come.
{
#region Serialized Fields
[SerializeField]
private RectTransform m_contentContainer;
[Header("UI Templates")]
[SerializeField]
private UnityUIContainerTemplate m_alertContainerTemplate;
[SerializeField]
private UnityUITextTemplate m_headingTemplate;
[SerializeField]
private UnityUITextTemplate[] m_subheadingTemplates;
[SerializeField]
private UnityUITextTemplate m_bodyTemplate;
[SerializeField]
private UnityUIIconListTemplate m_iconListTemplate;
[SerializeField]
private UnityUIButtonListTemplate m_buttonListTemplate;
[Tooltip("Use container template even for single-element content such as a single string.")]
[SerializeField]
private bool m_alwaysUseContainerTemplate = false;
[Header("Duration")]
[Tooltip("Minimum duration in seconds to show alerts.")]
[SerializeField]
private float m_minDisplayDuration = 5;
[Tooltip("Duration to show alerts in characters per second.")]
[SerializeField]
private int m_charsPerSecDuration = 50;
[Tooltip("When hiding after last content is done, leave last content visible during hide animation.")]
[SerializeField]
private bool m_leaveLastContentVisibleDuringHide = false;
[SerializeField]
private UnityEvent m_onShowAlert = new UnityEvent();
#endregion
#region Accessor Properties for Serialized Fields
public RectTransform contentContainer
{
get { return m_contentContainer; }
set { m_contentContainer = value; }
}
public UnityUIContainerTemplate alertContainerTemplate
{
get { return m_alertContainerTemplate; }
set { m_alertContainerTemplate = value; }
}
public UnityUITextTemplate headingTemplate
{
get { return m_headingTemplate; }
set { m_headingTemplate = value; }
}
public UnityUITextTemplate[] subheadingTemplates
{
get { return m_subheadingTemplates; }
set { m_subheadingTemplates = value; }
}
public UnityUITextTemplate bodyTemplate
{
get { return m_bodyTemplate; }
set { m_bodyTemplate = value; }
}
public UnityUIIconListTemplate iconListTemplate
{
get { return m_iconListTemplate; }
set { m_iconListTemplate = value; }
}
public UnityUIButtonListTemplate buttonListTemplate
{
get { return m_buttonListTemplate; }
set { m_buttonListTemplate = value; }
}
public bool alwaysUseContainerTemplate
{
get { return m_alwaysUseContainerTemplate; }
set { m_alwaysUseContainerTemplate = value; }
}
///
/// Minimum duration in seconds to show alerts.
///
public float minDisplayDuration
{
get { return m_minDisplayDuration; }
set { m_minDisplayDuration = value; }
}
///
/// Duration to show alerts in characters per second.
///
public int charsPerSecDuration
{
get { return m_charsPerSecDuration; }
set { m_charsPerSecDuration = value; }
}
///
/// When hiding after last content is done, leave last content visible during hide animation.
///
public bool leaveLastContentVisibleDuringHide
{
get { return m_leaveLastContentVisibleDuringHide; }
set { m_leaveLastContentVisibleDuringHide = value; }
}
public UnityEvent onShowAlert { get { return m_onShowAlert; } }
#endregion
#region Runtime Properties
protected UnityUIInstancedContentManager contentManager { get; set; }
protected override RectTransform currentContentContainer { get { return contentContainer; } }
protected override UnityUIInstancedContentManager currentContentManager { get { if (contentManager == null) contentManager = new UnityUIInstancedContentManager(); return contentManager; } }
protected override UnityUITextTemplate currentHeadingTemplate { get { return headingTemplate; } }
protected override UnityUITextTemplate[] currentSubheadingTemplates { get { return subheadingTemplates; } }
protected override UnityUITextTemplate currentBodyTemplate { get { return bodyTemplate; } }
protected override UnityUIIconListTemplate currentIconListTemplate { get { return iconListTemplate; } }
protected override UnityUIButtonListTemplate currentButtonListTemplate { get { return buttonListTemplate; } }
#endregion
protected override void Awake()
{
base.Awake();
contentManager = new UnityUIInstancedContentManager();
if (alertContainerTemplate != null) alertContainerTemplate.gameObject.SetActive(false);
if (contentContainer == null && Debug.isDebugBuild) Debug.LogError("Quest Machine: Content Container is unassigned.", this);
if (alertContainerTemplate == null && Debug.isDebugBuild) Debug.LogError("Quest Machine: Alert Container Template is unassigned.", this);
QuestMachine.defaultQuestAlertUI = this;
}
public override void Show()
{
currentContentManager.Clear();
base.Show();
}
///
/// Shows a quest alert.
///
/// Quest ID.
/// Complete quest alert content.
public virtual void ShowAlert(string questID, List contents)
{
if (contents == null || contents.Count == 0) return;
if (!isVisible) Show();
UnityUIContentTemplate alertInstance;
if (contents.Count == 1 && !alwaysUseContainerTemplate)
{
AddContent(contents[0]);
alertInstance = (contentManager.instancedContent.Count == 0) ? null
: contentManager.instancedContent[contentManager.instancedContent.Count - 1];
}
else
{
var container = Instantiate(alertContainerTemplate);
alertInstance = container;
contentManager.Add(container, currentContentContainer);
var realContentManager = contentManager; // Don't add sub-contents to real content manager.
contentManager = new UnityUIInstancedContentManager();
for (int i = 0; i < contents.Count; i++)
{
AddContent(contents[i]);
container.AddInstanceToContainer(contentManager.GetLastAdded());
}
contentManager = realContentManager;
}
if (alertInstance != null) StartCoroutine(TimedDespawn(alertInstance, GetDisplayDuration(contents)));
onShowAlert.Invoke();
}
protected override void AddContent(QuestContent content)
{
base.AddContent(content);
}
///
/// Shows a quest alert.
///
/// Alert to show.
public virtual void ShowAlert(string message)
{
if (string.IsNullOrEmpty(message)) return;
if (!isVisible) Show();
if (alwaysUseContainerTemplate)
{
var container = Instantiate(alertContainerTemplate);
var alertInstance = container;
contentManager.Add(container, currentContentContainer);
var realContentManager = contentManager; // Don't add sub-contents to real content manager.
contentManager = new UnityUIInstancedContentManager();
AddBodyContent(message);
container.AddInstanceToContainer(contentManager.GetLastAdded());
contentManager = realContentManager;
if (alertInstance != null) StartCoroutine(TimedDespawn(alertInstance, GetDisplayDuration(message)));
onShowAlert.Invoke();
}
else
{
// If useContainerTemplateForSimpleStrings is false, add body text directly to container
// to save the instantiation of an extra GameObject:
var alertInstance = Instantiate(bodyTemplate);
currentContentManager.Add(alertInstance, currentContentContainer);
alertInstance.Assign(message);
StartCoroutine(TimedDespawn(alertInstance, GetDisplayDuration(message)));
onShowAlert.Invoke();
}
}
///
/// Shows a quest alert.
///
/// Alert to show.
public void ShowAlert(StringField stringField)
{
ShowAlert(StringField.GetStringValue(stringField));
}
protected virtual IEnumerator TimedDespawn(UnityUIContentTemplate instance, float duration)
{
if (instance == null) yield break;
yield return new WaitForSeconds(duration);
if (leaveLastContentVisibleDuringHide && contentManager.instancedContent.Count <= 1)
{
Hide();
}
else
{
contentManager.Remove(instance);
if (contentManager.instancedContent.Count == 0) Hide();
}
}
protected float GetDisplayDuration(List contents)
{
float duration = minDisplayDuration;
if (contents != null)
{
for (int i = 0; i < contents.Count; i++)
{
duration = Mathf.Max(duration, GetDisplayDuration(contents[i]));
}
}
return duration;
}
protected float GetDisplayDuration(QuestContent content)
{
if (content is HeadingTextQuestContent)
{
return GetDisplayDuration((content as HeadingTextQuestContent).headingText);
}
else if (content is BodyTextQuestContent)
{
return GetDisplayDuration((content as BodyTextQuestContent).bodyText);
}
else if (content is IconQuestContent)
{
return GetDisplayDuration((content as IconQuestContent).caption);
}
else
{
return minDisplayDuration;
}
}
protected float GetDisplayDuration(StringField stringField)
{
return GetDisplayDuration(StringField.GetStringValue(stringField));
}
protected virtual float GetDisplayDuration(string text)
{
return Mathf.Max(minDisplayDuration, string.IsNullOrEmpty(text) ? 0 : (float)text.Length / charsPerSecDuration);
}
}
}