Skip to content

Instantly share code, notes, and snippets.

@JamesMcMahon
Last active May 5, 2016 15:32
Show Gist options
  • Save JamesMcMahon/578a842fd18641ea9c36761b03b09801 to your computer and use it in GitHub Desktop.
Save JamesMcMahon/578a842fd18641ea9c36761b03b09801 to your computer and use it in GitHub Desktop.
Unity inline image in text script. Could never get it to work properly on Android (didn't even test iOS). Quad placeholder would leave behind vector noise. Heavily modified from original at http://forum.unity3d.com/threads/sprite-icons-with-text-e-g-emoticons.265927/#post-2466522. Hopefully DMGregor (http://gamedev.stackexchange.com/q/88502/6968)…
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.UI;
// Usage: icon name in text is replaced by image
public class TextPic : Text
{
[System.Serializable]
public struct IconName
{
public string name;
public Sprite sprite;
}
/// <summary>
/// Regular expression to replace
/// </summary>
static readonly Regex s_Regex =
new Regex(@"<quad name=(.+?) size=(\d*\.?\d+%?) width=(\d*\.?\d+%?) />", RegexOptions.Singleline);
public IconName[] inspectorIconList;
// Scale image by x, y
[SerializeField]
public Vector2 imageScalingFactor = Vector2.one;
// Offset image by x, y
[SerializeField]
public Vector2 imageOffset = Vector2.zero;
// Pad image by x
public float imagePad;
/// <summary>
/// Image Pool
/// </summary>
readonly List<Image> m_ImagesPool = new List<Image>();
/// <summary>
/// Vertex Index
/// </summary>
readonly List<int> m_ImagesVertexIndex = new List<int>();
/// <summary>
/// After parsing the final text
/// </summary>
string m_OutputText;
Dictionary<string, Sprite> iconList = new Dictionary<string, Sprite>();
List<Vector2> positions = new List<Vector2>();
public override void SetVerticesDirty()
{
base.SetVerticesDirty();
UpdateQuadImage();
}
protected override void OnPopulateMesh(VertexHelper toFill)
{
var orignText = m_Text;
m_Text = m_OutputText;
base.OnPopulateMesh(toFill);
m_Text = orignText;
positions.Clear();
var vert = new UIVertex();
for (var i = 0; i < m_ImagesVertexIndex.Count; i++)
{
var endIndex = m_ImagesVertexIndex[i];
var rt = m_ImagesPool[i].rectTransform;
var size = rt.sizeDelta;
if (endIndex < toFill.currentVertCount)
{
toFill.PopulateUIVertex(ref vert, endIndex);
var position = new Vector2((vert.position.x + size.x / 2), (vert.position.y + size.y / 2));
position += imageOffset;
if (i > 0)
{
var padVector = new Vector2(imagePad * i, 0);
position += padVector;
}
positions.Add(position);
// Erase the lower left corner of the black specks
var end = endIndex - 3;
toFill.PopulateUIVertex(ref vert, end);
var pos = vert.position;
for (int j = endIndex; j > end; j--)
{
toFill.PopulateUIVertex(ref vert, endIndex);
vert.position = pos;
toFill.SetUIVertex(vert, j);
}
}
}
if (m_ImagesVertexIndex.Count != 0)
{
m_ImagesVertexIndex.Clear();
}
}
/**
* Unity Inspector cant display Dictionary vars,
* so we use this little hack to setup the iconList
*/
new void Start()
{
if (inspectorIconList != null)
{
foreach (IconName icon in inspectorIconList)
{
iconList.Add(icon.name, icon.sprite);
}
}
}
void UpdateQuadImage()
{
#if UNITY_EDITOR
if (UnityEditor.PrefabUtility.GetPrefabType(this) == UnityEditor.PrefabType.Prefab)
{
return;
}
#endif
m_OutputText = GetOutputText();
m_ImagesVertexIndex.Clear();
foreach (Match match in s_Regex.Matches(m_OutputText))
{
var picIndex = match.Index;
var endIndex = picIndex * 4 + 3;
m_ImagesVertexIndex.Add(endIndex);
m_ImagesPool.RemoveAll(image => image == null);
if (m_ImagesPool.Count == 0)
{
GetComponentsInChildren<Image>(m_ImagesPool);
}
if (m_ImagesVertexIndex.Count > m_ImagesPool.Count)
{
var resources = new DefaultControls.Resources();
var go = DefaultControls.CreateImage(resources);
go.layer = gameObject.layer;
var rt = go.transform as RectTransform;
if (rt)
{
rt.SetParent(rectTransform);
rt.localPosition = Vector3.zero;
rt.localRotation = Quaternion.identity;
rt.localScale = Vector3.one;
}
m_ImagesPool.Add(go.GetComponent<Image>());
}
var spriteName = match.Groups[1].Value;
var img = m_ImagesPool[m_ImagesVertexIndex.Count - 1];
if (img.sprite == null || img.sprite.name != spriteName)
{
if (inspectorIconList != null && inspectorIconList.Length > 0)
{
foreach (IconName icon in inspectorIconList)
{
if (icon.name == spriteName)
{
img.sprite = icon.sprite;
break;
}
}
}
}
img.rectTransform.sizeDelta = new Vector2(fontSize * imageScalingFactor.x, fontSize * imageScalingFactor.y);
img.enabled = true;
if (positions.Count == m_ImagesPool.Count)
{
img.rectTransform.anchoredPosition = positions[m_ImagesVertexIndex.Count - 1];
}
}
for (var i = m_ImagesVertexIndex.Count; i < m_ImagesPool.Count; i++)
{
if (m_ImagesPool[i])
{
m_ImagesPool[i].enabled = false;
}
}
}
string GetOutputText()
{
var fixedString = this.text;
if (inspectorIconList != null && inspectorIconList.Length > 0)
{
foreach (IconName icon in inspectorIconList)
{
if (!string.IsNullOrEmpty(icon.name))
{
fixedString = fixedString.Replace(icon.name, "<quad name=" + icon.name + " size=" + fontSize + " width=1 />");
}
}
}
return fixedString;
}
}
using UnityEditor;
using UnityEngine;
using TextEditor = UnityEditor.UI.TextEditor;
[CanEditMultipleObjects]
[CustomEditor(typeof(TextPic))]
public class TextPicEditor : TextEditor
{
SerializedProperty imageScalingFactorProp;
SerializedProperty imageOffsetProp;
SerializedProperty imagePadProp;
SerializedProperty iconList;
protected override void OnEnable()
{
base.OnEnable();
imageScalingFactorProp = serializedObject.FindProperty("imageScalingFactor");
imageOffsetProp = serializedObject.FindProperty("imageOffset");
imagePadProp = serializedObject.FindProperty("imagePad");
iconList = serializedObject.FindProperty("inspectorIconList");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
EditorGUILayout.PropertyField(imageOffsetProp, new GUIContent("Image Offset"));
EditorGUILayout.PropertyField(imagePadProp, new GUIContent("Image Pad"));
EditorGUILayout.PropertyField(imageScalingFactorProp, new GUIContent("Image Scaling Factor"));
EditorGUILayout.PropertyField(iconList, new GUIContent("Icon List"), true);
serializedObject.ApplyModifiedProperties();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment