// Copyright (c) Pixel Crushers. All rights reserved.
using UnityEngine;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace PixelCrushers.DialogueSystem
{
///
/// Tools for working with Unity UI.
///
public static class UITools
{
///
/// Dialogue databases may use Texture2Ds or Sprites for actor portraits. Unity UI uses sprites.
/// The CreateSprite method converts textures to sprites. This dictionary contains
/// converted sprites so we don't need to reconvert them every time we want to show
/// an actor's portrait.
///
public static Dictionary spriteCache = new Dictionary();
#if UNITY_2019_3_OR_NEWER && UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void InitStaticVariables()
{
ClearSpriteCache();
}
#endif
///
/// Ensures that the scene has an EventSystem.
///
public static void RequireEventSystem()
{
UIUtility.RequireEventSystem(DialogueDebug.logWarnings ? "Dialogue System: The scene is missing an EventSystem. Adding one." : null);
}
///
/// Returns the hash for an animator state.
///
public static int GetAnimatorNameHash(AnimatorStateInfo animatorStateInfo)
{
return animatorStateInfo.fullPathHash;
}
///
/// Clears the sprite cache, forcing all textures to be converted to sprites
/// the first time they're used.
///
public static void ClearSpriteCache()
{
spriteCache.Clear();
}
///
/// Gets the Sprite version of a Texture2D. Uses a cache so a texture will only be
/// converted to a sprite once.
///
/// Original Texture2D.
/// Sprite version.
public static Sprite CreateSprite(Texture2D texture)
{
if (texture == null) return null;
if (spriteCache.ContainsKey(texture))
{
var cachedSprite = spriteCache[texture];
if (cachedSprite != null) return spriteCache[texture];
}
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
spriteCache[texture] = sprite;
return sprite;
}
///
/// Given a Texture2D and/or Sprite, returns whichever one is not null.
/// Gives preference to the Texture2D.
public static Sprite GetSprite(Texture2D texture, Sprite sprite)
{
return (sprite != null)
? sprite
: (texture != null)
? UITools.CreateSprite(texture)
: null;
}
public static Texture2D GetTexture2D(Sprite sprite)
{
return (sprite != null) ? sprite.texture : null;
}
///
/// Returns the text inside a FormattedText object.
///
public static string GetUIFormattedText(FormattedText formattedText)
{
if (formattedText == null)
{
return string.Empty;
}
else if (formattedText.italic)
{
return "" + formattedText.text + "";
}
else
{
return formattedText.text;
}
}
private static AbstractDialogueUI dialogueUI = null;
///
/// Sends "OnTextChange(text)" to the dialogue UI GameObject.
///
public static void SendTextChangeMessage(UnityEngine.UI.Text text)
{
if (!Application.isPlaying) return;
if (text == null) return;
if (dialogueUI == null) dialogueUI = text.GetComponentInParent();
if (dialogueUI == null) return;
dialogueUI.SendMessage(DialogueSystemMessages.OnTextChange, text, SendMessageOptions.DontRequireReceiver);
}
///
/// Sends "OnTextChange(textField)" to the dialogue UI GameObject.
///
public static void SendTextChangeMessage(UITextField textField)
{
if (!Application.isPlaying) return;
if (textField.gameObject == null) return;
textField.gameObject.SendMessage(DialogueSystemMessages.OnTextChange, textField, SendMessageOptions.DontRequireReceiver);
}
///
/// Selects a Selectable UI element and visually shows it as selected.
///
///
///
public static void Select(UnityEngine.UI.Selectable selectable, bool allowStealFocus = true,
UnityEngine.EventSystems.EventSystem eventSystem = null)
{
UIUtility.Select(selectable, allowStealFocus, eventSystem);
}
public const string RPGMakerCodeQuarterPause = @"\,";
public const string RPGMakerCodeFullPause = @"\.";
public const string RPGMakerCodeSkipToEnd = @"\^";
public const string RPGMakerCodeInstantOpen = @"\>";
public const string RPGMakerCodeInstantClose = @"\<";
///
/// Returns a string without any embedded RPG Maker codes.
///
public static string StripRPGMakerCodes(string s)
{
if (string.IsNullOrEmpty(s)) return s;
return s.Contains(@"\") ? s.Replace(RPGMakerCodeQuarterPause, string.Empty).
Replace(RPGMakerCodeFullPause, string.Empty).
Replace(RPGMakerCodeSkipToEnd, string.Empty).
Replace(RPGMakerCodeInstantOpen, string.Empty).
Replace(RPGMakerCodeInstantClose, string.Empty)
: s;
}
public static string StripEmTags(string s)
{
return Regex.Replace(s, @"\[em\d+\]|\[/em\d+\]", string.Empty);
}
///
/// Wraps a string in rich text color codes. Properly handles nested
/// rich text codes.
///
/// Original text to be wrapped.
/// Color to wrap around text.
public static string WrapTextInColor(string text, Color color)
{
if (string.IsNullOrEmpty(text)) return string.Empty;
var colorCode = "";
// If text definitely has no other rich text codes, it's easy; just put a color code around the whole thing:
if (!text.Contains("<")) return colorCode + text + "";
// Otherwise put color codes only around substrings that aren't already in existing rich text codes:
var result = string.Empty;
int index = 0;
foreach (Match match in Regex.Matches(text, @")|)|)|)"))
{
result += colorCode + text.Substring(index, match.Index) + "" + match.Value;
index = match.Index + match.Value.Length;
}
if (index < text.Length)
{
result += colorCode + text.Substring(index) + "";
}
return result;
}
public static void EnableInteractivity(GameObject go)
{
var canvas = go.GetComponentInChildren