// Copyright (c) Pixel Crushers. All rights reserved. using UnityEngine; using System.Collections; namespace PixelCrushers.DialogueSystem { /// /// Subtitle Unity UI controls for UnityUIDialogueUI. /// [System.Serializable] public class UnityUISubtitleControls : AbstractUISubtitleControls { /// /// The panel containing the response menu controls. A panel is optional, but you may want one /// so you can include a background image, panel-wide effects, etc. /// [Tooltip("Optional panel for the subtitle elements")] public UnityEngine.UI.Graphic panel; /// /// The label that will show the text of the subtitle. /// [Tooltip("Subtitle text")] public UnityEngine.UI.Text line; /// /// The label that will show the portrait image. /// [Tooltip("Optional image for speaker's portrait")] public UnityEngine.UI.Image portraitImage; /// /// The label that will show the name of the speaker. /// [Tooltip("Optional label for speaker's name")] public UnityEngine.UI.Text portraitName; /// /// The continue button. This is only required if DisplaySettings.waitForContinueButton /// is true -- in which case this button should send "OnContinue" to the UI when clicked. /// [Tooltip("Optional continue button; configure OnClick to invoke dialogue UI's OnContinue method")] public UnityEngine.UI.Button continueButton; [Tooltip("Ignore RPGMaker-style pause codes")] public bool ignorePauseCodes = false; [Tooltip("Optional animation transitions; panel should have an Animator")] public UIAnimationTransitions animationTransitions = new UIAnimationTransitions(); [Tooltip("When the subtitle UI elements should be visible.")] public UIVisibility uiVisibility = UIVisibility.OnlyDuringContent; public bool isVisible { get { return (panel != null) ? panel.gameObject.activeInHierarchy : (line != null && line.gameObject.activeInHierarchy); } } /// /// Indicates whether this subtitle is currently assigned text. /// /// /// true if it has text; otherwise, false. /// public override bool hasText { get { return (line != null) && !string.IsNullOrEmpty(line.text); } } private UIShowHideController m_showHideController = null; private UIShowHideController showHideController { get { if (m_showHideController == null) m_showHideController = new UIShowHideController(null, panel, animationTransitions.transitionMode, animationTransitions.debug); return m_showHideController; } } private bool m_haveSavedOriginalColor = false; private Color m_originalColor = Color.white; // Called by UnityUIDialogueUI.Open. If visibility is AlwaysFromStart, set the portrait info. public void CheckSubtitlePortrait(CharacterType characterType) { if (uiVisibility == UIVisibility.AlwaysFromStart) { DialogueManager.instance.StartCoroutine(SetSubtitlePortrait(characterType)); } } private IEnumerator SetSubtitlePortrait(CharacterType characterType) { // Need to wait until end of frame: if (portraitName != null) portraitName.text = string.Empty; if (portraitImage != null) portraitImage.sprite = null; if (line != null) line.text = string.Empty; yield return CoroutineUtility.endOfFrame; var characterInfo = (characterType == CharacterType.NPC) ? DialogueManager.conversationModel.conversantInfo : DialogueManager.conversationModel.actorInfo; if (characterInfo != null) { if (portraitName != null && string.IsNullOrEmpty(portraitName.text)) portraitName.text = characterInfo.Name; if (portraitImage != null && portraitImage.sprite == null) portraitImage.sprite = characterInfo.portrait; } } public override void SetActive(bool value) { if (value == true || uiVisibility == UIVisibility.AlwaysFromStart || ((uiVisibility == UIVisibility.AlwaysOnceShown || UITools.CanBeSuperceded(uiVisibility)) && isVisible)) { ShowPanel(); } else { HidePanel(); } } public void ForceHide() { HidePanel(); } public void ForceShow() { showHideController.state = UIShowHideController.State.Hidden; ActivateUIElements(); } private void ShowPanel() { ActivateUIElements(); animationTransitions.ClearTriggers(showHideController); showHideController.Show(animationTransitions.showTrigger, false, null); } private void HidePanel() { animationTransitions.ClearTriggers(showHideController); showHideController.Hide(animationTransitions.hideTrigger, DeactivateUIElements); } public void ActivateUIElements() { SetUIElementsActive(true); } public void DeactivateUIElements() { SetUIElementsActive(false); } private void SetUIElementsActive(bool value) { Tools.SetGameObjectActive(panel, value); Tools.SetGameObjectActive(line, value); Tools.SetGameObjectActive(portraitImage, value); Tools.SetGameObjectActive(portraitName, value); Tools.SetGameObjectActive(continueButton, false); // Let ConversationView determine if continueButton should be shown. } public override void ShowContinueButton() { Tools.SetGameObjectActive(continueButton, true); } public override void HideContinueButton() { Tools.SetGameObjectActive(continueButton, false); } /// /// Sets the subtitle. /// /// /// Subtitle. /// public override void SetSubtitle(Subtitle subtitle) { if ((subtitle != null) && !string.IsNullOrEmpty(subtitle.formattedText.text)) { if (portraitImage != null) portraitImage.sprite = subtitle.GetSpeakerPortrait(); if (portraitName != null) { portraitName.text = subtitle.speakerInfo.Name; UITools.SendTextChangeMessage(portraitName); } if (line != null) { var typewriterEffect = line.GetComponent(); if (typewriterEffect != null && typewriterEffect.enabled) { typewriterEffect.Stop(); typewriterEffect.playOnEnable = false; } SetFormattedText(line, subtitle.formattedText); if (typewriterEffect != null && typewriterEffect.enabled) typewriterEffect.PlayText(subtitle.formattedText.text); } } else { if ((line != null) && (subtitle != null)) SetFormattedText(line, subtitle.formattedText); } } /// /// Clears the subtitle. /// public override void ClearSubtitle() { SetFormattedText(line, null); } /// /// Sets a label with formatted text. /// /// /// Label to set. /// /// /// Formatted text. /// private void SetFormattedText(UnityEngine.UI.Text label, FormattedText formattedText) { if (label != null) { if (formattedText != null) { var text = UITools.GetUIFormattedText(formattedText); if (ignorePauseCodes) text = UITools.StripRPGMakerCodes(text); label.text = text; UITools.SendTextChangeMessage(label); if (!m_haveSavedOriginalColor) { m_originalColor = label.color; m_haveSavedOriginalColor = true; } label.color = (formattedText.emphases.Length > 0) ? formattedText.emphases[0].color : m_originalColor; } else { label.text = string.Empty; } } } /// /// Sets the portrait sprite to use in the subtitle if the named actor is the speaker. /// This is used to immediately update the GUI control if the SetPortrait() sequencer /// command changes the portrait sprite. /// /// Actor name in database. /// Portrait sprite. public override void SetActorPortraitSprite(string actorName, Sprite portraitSprite) { if ((currentSubtitle != null) && string.Equals(currentSubtitle.speakerInfo.nameInDatabase, actorName)) { if (portraitImage != null) portraitImage.sprite = AbstractDialogueUI.GetValidPortraitSprite(actorName, portraitSprite); } } /// /// Auto-focuses the continue button. Useful for gamepads. /// public void AutoFocus(bool allowStealFocus = true) { UITools.Select(continueButton, allowStealFocus); } } }