using UnityEngine;
using System;
using System.Collections.Generic;
namespace PixelCrushers.DialogueSystem.UnityGUI
{
///
/// This is a Unity GUI implementation of QuestLogWindow. Don't confuse it with the
/// deprecated UnityQuestLogWindow, which was the old quest log window implementation.
///
[AddComponentMenu("")] // Deprecated
public class UnityGUIQuestLogWindow : QuestLogWindow
{
///
/// The GUI root.
///
public GUIRoot guiRoot;
///
/// The scroll view where quest titles and descriptions will be shown.
///
public GUIScrollView scrollView;
///
/// The button to show active quests. When clicked, it should send the message
/// "OnShowActiveQuests" to the UnityQuestLogWindow.
///
public GUIButton activeButton;
///
/// The button to show completed quests. When clicked, it should send the message
/// "OnShowCompletedQuests" to the UnityQuestLogWindow.
///
public GUIButton completedButton;
[Serializable]
public class AbandonControls
{
public GUIControl panel;
public GUILabel questTitleLabel;
public GUIButton ok;
public GUIButton cancel;
}
public AbandonControls abandonQuestPopup = new AbandonControls();
///
/// The name of the GUI style to use for quest group titles. If blank, defaults to questHeadingGuiStyleName.
///
public string groupHeadingGuiStyleName;
///
/// The name of the GUI style to use for quest titles. If blank, defaults to label.
///
public string questHeadingGuiStyleName;
///
/// The name of the GUI style to use for quest titles when the quest is open.
/// For example, if the normal (closed) quest heading uses a down arrow graphic,
/// this style could use an up arrow graphic.
///
public string questHeadingOpenGuiStyleName;
///
/// The name of the GUI style to use for quest descriptions. If blank, defaults to label.
///
public string questBodyGuiStyleName;
///
/// The name of the GUI style to use for active quest entries. If blank, defaults to label.
///
public string questEntryActiveGuiStyleName;
///
/// The name of the GUI style to use when displaying successfully-completed entries.
/// If blank, it defaults to label.
///
public string questEntrySuccessGuiStyleName;
///
/// The name of the GUI style to use when displaying failed entries.
/// If blank, it defaults to label.
///
public string questEntryFailureGuiStyleName;
///
/// The name of the GUI style to use for Track and Abandon buttons.
///
public string questEntryButtonStyleName;
///
/// The name of the GUI style to use for the "No Active Quests" and "No Completed Quests"
/// messages. If blank, defaults to label.
///
public string noQuestsGuiStyleName;
public int padding = 2;
private GUIStyle groupHeadingStyle = null;
private GUIStyle questHeadingStyle = null;
private GUIStyle questHeadingOpenStyle = null;
private GUIStyle questBodyStyle = null;
private GUIStyle questEntryActiveStyle = null;
private GUIStyle questEntrySuccessStyle = null;
private GUIStyle questEntryFailureStyle = null;
private GUIStyle questButtonStyle = null;
private Action confirmAbandonQuestHandler = null;
private List collapsedGroups = new List();
///
/// Attempts to find the GUI root and scroll view if they weren't set.
/// Sets up the scroll view.
///
public override void Awake()
{
base.Awake();
if (guiRoot == null) guiRoot = GetComponentInChildren();
if (scrollView == null) scrollView = GetComponentInChildren();
if (scrollView != null)
{
scrollView.MeasureContentHandler += OnMeasureContent;
scrollView.DrawContentHandler += OnDrawContent;
}
if (string.IsNullOrEmpty(groupHeadingGuiStyleName)) groupHeadingGuiStyleName = questHeadingGuiStyleName;
}
///
/// Start this instance by hiding the GUI root. We only need to activate it when the window
/// is open.
///
protected override void Start()
{
base.Start();
if (guiRoot != null) guiRoot.gameObject.SetActive(false);
}
public override void OpenWindow(Action openedWindowHandler)
{
if (guiRoot != null)
{
guiRoot.gameObject.SetActive(true);
if ((abandonQuestPopup != null) && (abandonQuestPopup.panel != null))
{
abandonQuestPopup.panel.gameObject.SetActive(false);
}
guiRoot.ManualRefresh();
}
openedWindowHandler();
}
public override void CloseWindow(Action closedWindowHandler)
{
if (guiRoot != null) guiRoot.gameObject.SetActive(false);
closedWindowHandler();
}
public override void ConfirmAbandonQuest(string title, Action confirmAbandonQuestHandler)
{
this.confirmAbandonQuestHandler = confirmAbandonQuestHandler;
OpenAbandonQuestPopup(title);
}
private void OpenAbandonQuestPopup(string title)
{
if (abandonQuestPopup.panel == null)
{
if (confirmAbandonQuestHandler != null) confirmAbandonQuestHandler();
}
else
{
if (abandonQuestPopup.questTitleLabel != null) abandonQuestPopup.questTitleLabel.text = title;
abandonQuestPopup.panel.gameObject.SetActive(true);
}
}
private void CloseAbandonQuestPopup()
{
if (abandonQuestPopup.panel != null) abandonQuestPopup.panel.gameObject.SetActive(false);
}
public void ClickConfirmAbandonQuest(object data)
{
CloseAbandonQuestPopup();
if (confirmAbandonQuestHandler != null) confirmAbandonQuestHandler();
}
public void ClickCancelAbandonQuest(object data)
{
CloseAbandonQuestPopup();
}
///
/// The event handler that measures the size of the content that will go into the scroll
/// view.
///
public void OnMeasureContent()
{
MeasureQuestContent();
}
///
/// The event handler that draws the content of the scroll view.
///
public void OnDrawContent()
{
DrawQuests();
}
private void MeasureQuestContent()
{
float contentHeight = padding;
string currentGroup = null;
var isCurrentGroupCollapsed = false;
foreach (var questInfo in quests)
{
// Group:
if (!string.Equals(questInfo.Group, currentGroup))
{
currentGroup = questInfo.Group;
if (!string.IsNullOrEmpty(currentGroup))
{
contentHeight += GroupHeadingHeight(currentGroup);
isCurrentGroupCollapsed = collapsedGroups.Contains(currentGroup);
}
}
// Quest:
if (!isCurrentGroupCollapsed)
{
contentHeight += QuestHeadingHeight(questInfo);
if (IsSelectedQuest(questInfo))
{
contentHeight += QuestDescriptionHeight(questInfo);
contentHeight += QuestEntriesHeight(questInfo);
contentHeight += QuestButtonsHeight(questInfo);
}
}
}
contentHeight += padding;
if (scrollView != null) scrollView.contentHeight = contentHeight;
}
public override void OnQuestListUpdated()
{
if (activeButton != null) activeButton.clickable = !isShowingActiveQuests;
if (completedButton != null) completedButton.clickable = isShowingActiveQuests;
}
private GUIStyle UseGUIStyle(GUIStyle guiStyle, string guiStyleName, GUIStyle defaultStyle)
{
return (guiStyle != null) ? guiStyle : UnityGUITools.GetGUIStyle(guiStyleName, defaultStyle);
}
private GUIStyle GetGroupHeadingStyle()
{
return UseGUIStyle(groupHeadingStyle, groupHeadingGuiStyleName, GUI.skin.button);
}
private GUIStyle GetQuestHeadingStyle(bool isSelectedQuest)
{
if (isSelectedQuest && !string.IsNullOrEmpty(questHeadingOpenGuiStyleName))
{
questHeadingOpenStyle = UseGUIStyle(questHeadingOpenStyle, questHeadingOpenGuiStyleName, GUI.skin.button);
return questHeadingOpenStyle;
}
else
{
questHeadingStyle = UseGUIStyle(questHeadingStyle, questHeadingGuiStyleName, GUI.skin.button);
return questHeadingStyle;
}
}
private GUIStyle GetQuestEntryStyle(QuestState entryState)
{
questEntryActiveStyle = UseGUIStyle(questEntryActiveStyle, questEntryActiveGuiStyleName, GUI.skin.label);
questEntrySuccessStyle = UseGUIStyle(questEntrySuccessStyle, questEntrySuccessGuiStyleName, GUI.skin.label);
questEntryFailureStyle = UseGUIStyle(questEntryFailureStyle, questEntryFailureGuiStyleName, GUI.skin.label);
switch (entryState)
{
case QuestState.Success: return questEntrySuccessStyle;
case QuestState.Failure: return questEntryFailureStyle;
default: return questEntryActiveStyle;
}
}
private float GroupHeadingHeight(string group)
{
return GetGroupHeadingStyle().CalcHeight(new GUIContent(group), scrollView.contentWidth - (2 * padding));
}
///
/// Computes the height of a quest heading, which is the height of the text or the height
/// of the active button, whichever is greater. This way headings will look similar to
/// the active/completed buttons (and will be tall enough if the skin has large buttons).
///
///
/// The heading height.
///
///
/// Heading.
///
private float QuestHeadingHeight(QuestInfo questInfo)
{
return Mathf.Max(activeButton.rect.height, GetQuestHeadingStyle(IsSelectedQuest(questInfo)).CalcHeight(new GUIContent(questInfo.Heading.text), scrollView.contentWidth - (2 * padding)));
}
private float QuestDescriptionHeight(QuestInfo questInfo)
{
questBodyStyle = UseGUIStyle(questBodyStyle, questBodyGuiStyleName, GUI.skin.label);
if (questHeadingSource == QuestHeadingSource.Name)
{
return questBodyStyle.CalcHeight(new GUIContent(questInfo.Description.text), scrollView.contentWidth - (2 * padding));
}
else
{
return 0;
}
}
private float QuestEntriesHeight(QuestInfo questInfo)
{
float height = 0;
for (int i = 0; i < questInfo.Entries.Length; i++)
{
QuestState entryState = questInfo.EntryStates[i];
GUIStyle questEntryStyle = GetQuestEntryStyle(entryState);
if (entryState != QuestState.Unassigned)
{
string entryDescription = questInfo.Entries[i].text;
height += questEntryStyle.CalcHeight(new GUIContent(entryDescription), scrollView.contentWidth - (2 * padding));
}
}
return height;
}
private float QuestButtonsHeight(QuestInfo questInfo)
{
if (questInfo.Trackable || questInfo.Abandonable)
{
questButtonStyle = UseGUIStyle(questButtonStyle, questEntryButtonStyleName, GUI.skin.button);
questButtonStyle.wordWrap = false;
return questButtonStyle.CalcHeight(new GUIContent("Abandon"), scrollView.contentWidth - (2 * padding));
}
else
{
return 0;
}
}
private void DrawQuests()
{
if ((scrollView != null))
{
float contentY = padding;
string currentGroup = null;
var isCurrentGroupCollapsed = false;
foreach (var questInfo in quests)
{
// Check for new group:
if (!string.Equals(questInfo.Group, currentGroup))
{
currentGroup = questInfo.Group;
if (!string.IsNullOrEmpty(currentGroup))
{
isCurrentGroupCollapsed = collapsedGroups.Contains(currentGroup);
var groupHeadingHeight = GroupHeadingHeight(currentGroup);
//---Was: GUI.Label(new Rect(padding, contentY, scrollView.contentWidth - (2 * padding), groupHeadingHeight), currentGroup, GetGroupHeadingStyle());
if (GUI.Button(new Rect(padding, contentY, scrollView.contentWidth - (2 * padding), groupHeadingHeight), currentGroup, GetGroupHeadingStyle()))
{
ClickQuestGroup(currentGroup);
}
contentY += groupHeadingHeight;
}
}
// Draw quest:
if (!isCurrentGroupCollapsed)
{
bool isSelectedQuest = IsSelectedQuest(questInfo);
float headingHeight = QuestHeadingHeight(questInfo);
if (GUI.Button(new Rect(padding, contentY, scrollView.contentWidth - (2 * padding), headingHeight), questInfo.Heading.text, GetQuestHeadingStyle(isSelectedQuest)))
{
ClickQuest(questInfo.Title);
}
contentY += headingHeight;
if (isSelectedQuest)
{
contentY = DrawQuestDescription(questInfo, contentY);
contentY = DrawQuestEntries(questInfo, contentY);
contentY = DrawQuestButtons(questInfo, contentY);
}
}
}
if (quests.Length == 0)
{
GUIStyle noQuestsStyle = UnityGUITools.GetGUIStyle(noQuestsGuiStyleName, GUI.skin.label);
float descriptionHeight = noQuestsStyle.CalcHeight(new GUIContent(noQuestsMessage), scrollView.contentWidth - 4);
GUI.Label(new Rect(2, contentY, scrollView.contentWidth, descriptionHeight), noQuestsMessage, noQuestsStyle);
contentY += descriptionHeight;
}
}
}
private float DrawQuestDescription(QuestInfo questInfo, float contentY)
{
if (questHeadingSource == QuestHeadingSource.Name)
{
questBodyStyle = UseGUIStyle(questBodyStyle, questBodyGuiStyleName, GUI.skin.label);
float descriptionHeight = questBodyStyle.CalcHeight(new GUIContent(questInfo.Description.text), scrollView.contentWidth - (2 * padding));
GUI.Label(new Rect(padding, contentY, scrollView.contentWidth, descriptionHeight), questInfo.Description.text, questBodyStyle);
return contentY + descriptionHeight;
}
else
{
return contentY;
}
}
private float DrawQuestEntries(QuestInfo questInfo, float contentY)
{
float currentY = contentY;
for (int i = 0; i < questInfo.Entries.Length; i++)
{
QuestState entryState = questInfo.EntryStates[i];
if (entryState != QuestState.Unassigned)
{
string entryDescription = questInfo.Entries[i].text;
GUIStyle questEntryStyle = GetQuestEntryStyle(entryState);
float entryHeight = questEntryStyle.CalcHeight(new GUIContent(entryDescription), scrollView.contentWidth - (2 * padding));
GUI.Label(new Rect(padding, currentY, scrollView.contentWidth, entryHeight), entryDescription, questEntryStyle);
currentY += entryHeight;
}
}
return currentY;
}
private float DrawQuestButtons(QuestInfo questInfo, float contentY)
{
float currentY = contentY;
if ((currentQuestStateMask == QuestState.Active) && (questInfo.Trackable || questInfo.Abandonable))
{
questButtonStyle = UseGUIStyle(questButtonStyle, questEntryButtonStyleName, GUI.skin.button);
questButtonStyle.wordWrap = false;
string trackText = GetLocalizedText("Track");
Vector2 trackSize = questButtonStyle.CalcSize(new GUIContent(trackText));
float buttonHeight = trackSize.y;
float trackWidth = trackSize.x;
string abandonText = GetLocalizedText("Abandon");
float abandonWidth = questButtonStyle.CalcSize(new GUIContent(abandonText)).x;
float rightX = scrollView.contentWidth - (2 * padding);
float abandonX = rightX - abandonWidth;
float trackX = questInfo.Abandonable ? (abandonX - padding) : rightX;
trackX -= trackWidth;
if (questInfo.Trackable)
{
if (GUI.Button(new Rect(trackX, currentY, trackWidth, buttonHeight), trackText))
{
ClickTrackQuest(questInfo.Title);
}
}
if (questInfo.Abandonable)
{
if (GUI.Button(new Rect(abandonX, currentY, abandonWidth, buttonHeight), abandonText))
{
ClickAbandonQuest(questInfo.Title);
}
}
currentY += questButtonStyle.CalcHeight(new GUIContent("Abandon"), scrollView.contentWidth - (2 * padding));
}
return currentY;
}
private void ClickQuestGroup(string group)
{
if (collapsedGroups.Contains(group))
{
collapsedGroups.Remove(group);
}
else
{
collapsedGroups.Add(group);
}
}
}
}