Created
September 22, 2014 12:55
-
-
Save stramit/234f36f2c7ff9510bf40 to your computer and use it in GitHub Desktop.
Text Element
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
namespace UnityEngine.UI | |
{ | |
/// <summary> | |
/// Labels are graphics that display text. | |
/// </summary> | |
[AddComponentMenu("UI/Text", 11)] | |
public class Text : MaskableGraphic, ILayoutElement | |
{ | |
[SerializeField] private FontData m_FontData = FontData.defaultFontData; | |
[TextArea(3, 10)] [SerializeField] private string m_Text = String.Empty; | |
private TextGenerator m_TextCache; | |
private TextGenerator m_TextCacheForLayout; | |
private static float kEpsilon = 0.0001f; | |
//We use this flag instead of Unregistering/Registering the callback to avoid allocation. | |
[NonSerialized] private bool m_DisableFontTextureChangedCallback = false; | |
protected Text() | |
{} | |
/// <summary> | |
/// Get or set the material used by this Text. | |
/// </summary> | |
public TextGenerator cachedTextGenerator | |
{ | |
get { return m_TextCache ?? (m_TextCache = m_Text.Length != 0 ? new TextGenerator(m_Text.Length) : new TextGenerator()); } | |
} | |
public TextGenerator cachedTextGeneratorForLayout | |
{ | |
get { return m_TextCacheForLayout ?? (m_TextCacheForLayout = new TextGenerator()); } | |
} | |
public override Material defaultMaterial | |
{ | |
get | |
{ | |
if (s_DefaultText == null) | |
{ | |
Shader shader = Shader.Find("UI/Default Font"); | |
s_DefaultText = new Material(shader); | |
s_DefaultText.hideFlags = HideFlags.DontSave; | |
s_DefaultText.name = "Default Text Material"; | |
} | |
return s_DefaultText; | |
} | |
} | |
/// <summary> | |
/// Text's texture comes from the font. | |
/// </summary> | |
public override Texture mainTexture | |
{ | |
get | |
{ | |
if (font != null && font.material != null && font.material.mainTexture != null) | |
return font.material.mainTexture; | |
if (m_Material != null) | |
return m_Material.mainTexture; | |
return base.mainTexture; | |
} | |
} | |
private void FontTextureChanged() | |
{ | |
//Only invoke if we are not destroyed. | |
if (!this) | |
{ | |
UnregisterFontTextureChanged (); | |
return; | |
} | |
if (m_DisableFontTextureChangedCallback) | |
return; | |
cachedTextGenerator.Invalidate(); | |
if (!IsActive ()) | |
return; | |
// this is a bit hacky, but it is currently the | |
// cleanest solution.... | |
// if we detect the font texture has changed and are in a rebuild loop | |
// we just regenerate the verts for the new UV's | |
if (CanvasUpdateRegistry.IsRebuildingGraphics () || CanvasUpdateRegistry.IsRebuildingLayout ()) | |
UpdateGeometry (); | |
else | |
SetAllDirty(); | |
} | |
/// <summary> | |
/// Set the font used by this Text. | |
/// </summary> | |
[NonSerialized] | |
private bool callbackRegistered = false; | |
public Font font | |
{ | |
get | |
{ | |
return m_FontData.font; | |
} | |
set | |
{ | |
if (m_FontData.font == value) | |
return; | |
UnregisterFontTextureChanged (); | |
m_FontData.font = value; | |
RegisterFontTextureChanged(); | |
SetAllDirty(); | |
} | |
} | |
/// <summary> | |
/// Text that's being displayed by the Text. | |
/// </summary> | |
public string text | |
{ | |
get | |
{ | |
return m_Text; | |
} | |
set | |
{ | |
if (String.IsNullOrEmpty(value)) | |
{ | |
if (String.IsNullOrEmpty(m_Text)) | |
return; | |
m_Text = ""; | |
SetVerticesDirty (); | |
} | |
else if (m_Text != value) | |
{ | |
m_Text = value; | |
SetAllDirty(); | |
} | |
} | |
} | |
/// <summary> | |
/// Whether this Text will support rich text. | |
/// </summary> | |
public bool supportRichText | |
{ | |
get | |
{ | |
return m_FontData.richText; | |
} | |
set | |
{ | |
if (m_FontData.richText == value) | |
return; | |
m_FontData.richText = value; | |
SetAllDirty (); | |
} | |
} | |
/// <summary> | |
/// Wrap mode used by the text. | |
/// </summary> | |
public bool resizeTextForBestFit | |
{ | |
get | |
{ | |
return m_FontData.bestFit; | |
} | |
set | |
{ | |
if (m_FontData.bestFit == value) | |
return; | |
m_FontData.bestFit = value; | |
SetAllDirty (); | |
} | |
} | |
public int resizeTextMinSize | |
{ | |
get | |
{ | |
return m_FontData.minSize; | |
} | |
set | |
{ | |
if (m_FontData.minSize == value) | |
return; | |
m_FontData.minSize = value; | |
SetAllDirty (); | |
} | |
} | |
public int resizeTextMaxSize | |
{ | |
get | |
{ | |
return m_FontData.maxSize; | |
} | |
set | |
{ | |
if (m_FontData.maxSize == value) | |
return; | |
m_FontData.maxSize = value; | |
SetAllDirty (); | |
} | |
} | |
/// <summary> | |
/// Alignment anchor used by the text. | |
/// </summary> | |
public TextAnchor alignment | |
{ | |
get | |
{ | |
return m_FontData.alignment; | |
} | |
set | |
{ | |
if (m_FontData.alignment == value) | |
return; | |
m_FontData.alignment = value; | |
SetAllDirty (); | |
} | |
} | |
public int fontSize | |
{ | |
get | |
{ | |
return m_FontData.fontSize; | |
} | |
set | |
{ | |
if (m_FontData.fontSize == value) | |
return; | |
m_FontData.fontSize = value; | |
SetAllDirty (); | |
} | |
} | |
public float lineSpacing | |
{ | |
get | |
{ | |
return m_FontData.lineSpacing; | |
} | |
set | |
{ | |
if (m_FontData.lineSpacing == value) | |
return; | |
m_FontData.lineSpacing = value; | |
SetAllDirty (); | |
} | |
} | |
/// <summary> | |
/// Font style used by the Text's text. | |
/// </summary> | |
public FontStyle fontStyle | |
{ | |
get | |
{ | |
return m_FontData.fontStyle; | |
} | |
set | |
{ | |
if (m_FontData.fontStyle == value) | |
return; | |
m_FontData.fontStyle = value; | |
SetAllDirty (); | |
} | |
} | |
private void RegisterFontTextureChanged() | |
{ | |
if (m_FontData.font != null && !callbackRegistered) | |
{ | |
m_FontData.font.textureRebuildCallback += FontTextureChanged; | |
callbackRegistered = true; | |
} | |
} | |
private void UnregisterFontTextureChanged() | |
{ | |
if (m_FontData.font != null) | |
{ | |
m_FontData.font.textureRebuildCallback -= FontTextureChanged; | |
callbackRegistered = false; | |
} | |
} | |
protected override void OnEnable () | |
{ | |
base.OnEnable (); | |
cachedTextGenerator.Invalidate(); | |
RegisterFontTextureChanged (); | |
} | |
protected override void OnDisable() | |
{ | |
UnregisterFontTextureChanged(); | |
base.OnDisable(); | |
} | |
protected override void UpdateGeometry () | |
{ | |
if (font != null) | |
{ | |
base.UpdateGeometry(); | |
} | |
} | |
#if UNITY_EDITOR | |
protected override void Reset () | |
{ | |
font = Resources.GetBuiltinResource<Font> ("Arial.ttf"); | |
} | |
#endif | |
public TextGenerationSettings GetGenerationSettings(Vector2 extents) | |
{ | |
var settings = new TextGenerationSettings(); | |
settings.textAnchor = m_FontData.alignment; | |
settings.color = color; | |
settings.generationExtents = extents * pixelsPerUnit + Vector2.one * kEpsilon; | |
settings.font = font; | |
settings.pivot = rectTransform.pivot; | |
settings.richText = m_FontData.richText; | |
settings.fontSize = Mathf.RoundToInt (m_FontData.fontSize * pixelsPerUnit); | |
settings.lineSpacing = m_FontData.lineSpacing; | |
settings.fontStyle = m_FontData.fontStyle; | |
settings.resizeTextForBestFit = m_FontData.bestFit; | |
settings.resizeTextMinSize = m_FontData.minSize; | |
settings.resizeTextMaxSize = m_FontData.maxSize; | |
settings.updateBounds = false; | |
settings.horizontalOverflow = m_FontData.horizontalOverflow; | |
settings.verticalOverflow = m_FontData.verticalOverflow; | |
return settings; | |
} | |
static public Vector2 GetTextAnchorPivot (TextAnchor anchor) | |
{ | |
switch (anchor) | |
{ | |
case TextAnchor.LowerLeft: return new Vector2 (0, 0); | |
case TextAnchor.LowerCenter: return new Vector2 (0.5f, 0); | |
case TextAnchor.LowerRight: return new Vector2 (1, 0); | |
case TextAnchor.MiddleLeft: return new Vector2 (0, 0.5f); | |
case TextAnchor.MiddleCenter: return new Vector2 (0.5f, 0.5f); | |
case TextAnchor.MiddleRight: return new Vector2 (1, 0.5f); | |
case TextAnchor.UpperLeft: return new Vector2 (0, 1); | |
case TextAnchor.UpperCenter: return new Vector2 (0.5f, 1); | |
case TextAnchor.UpperRight: return new Vector2 (1, 1); | |
default: return Vector2.zero; | |
} | |
} | |
/// <summary> | |
/// Draw the Text. | |
/// </summary> | |
protected override void OnFillVBO (List<UIVertex> vbo) | |
{ | |
if (font == null) | |
return; | |
// We dont care if we the font Texture changes while we are doing our Update. | |
// The end result of cachedTextGenerator will be valid for this instance. | |
// Otherwise we can get issues like Case 619238. | |
m_DisableFontTextureChangedCallback = true; | |
Vector2 extents = rectTransform.rect.size; | |
var settings = GetGenerationSettings(extents); | |
cachedTextGenerator.Populate(m_Text, settings); | |
Rect inputRect = rectTransform.rect; | |
// get the text alignment anchor point for the text in local space | |
Vector2 textAnchorPivot = GetTextAnchorPivot (m_FontData.alignment); | |
Vector2 refPoint = Vector2.zero; | |
refPoint.x = (textAnchorPivot.x == 1 ? inputRect.xMax : inputRect.xMin); | |
refPoint.y = (textAnchorPivot.y == 0 ? inputRect.yMin : inputRect.yMax); | |
// Determine fraction of pixel to offset text mesh. | |
Vector2 roundingOffset = PixelAdjustPoint (refPoint) - refPoint; | |
// Apply the offset to the vertices | |
IList<UIVertex> verts = cachedTextGenerator.verts; | |
float unitsPerPixel = 1 / pixelsPerUnit; | |
if (roundingOffset != Vector2.zero) | |
{ | |
for (int i = 0; i < verts.Count; i++) | |
{ | |
UIVertex uiv = verts[i]; | |
uiv.position *= unitsPerPixel; | |
uiv.position.x += roundingOffset.x; | |
uiv.position.y += roundingOffset.y; | |
vbo.Add(uiv); | |
} | |
} | |
else | |
{ | |
for (int i = 0; i < verts.Count; i++) | |
{ | |
UIVertex uiv = verts[i]; | |
uiv.position *= unitsPerPixel; | |
vbo.Add(uiv); | |
} | |
} | |
m_DisableFontTextureChangedCallback = false; | |
} | |
public void CalculateLayoutInputHorizontal () {} | |
public void CalculateLayoutInputVertical () {} | |
public float minWidth | |
{ | |
get { return 0; } | |
} | |
public float preferredWidth | |
{ | |
get | |
{ | |
var settings = GetGenerationSettings (Vector2.zero); | |
return cachedTextGeneratorForLayout.GetPreferredWidth(m_Text, settings) / pixelsPerUnit; | |
} | |
} | |
public float flexibleWidth { get { return -1; } } | |
public float minHeight | |
{ | |
get { return 0; } | |
} | |
public float preferredHeight | |
{ | |
get | |
{ | |
var settings = GetGenerationSettings(new Vector2(rectTransform.rect.size.x, 0.0f)); | |
return cachedTextGeneratorForLayout.GetPreferredHeight(m_Text, settings) / pixelsPerUnit; | |
} | |
} | |
public float flexibleHeight { get { return -1; } } | |
public int layoutPriority { get { return 0; } } | |
#if UNITY_EDITOR | |
override protected void OnRebuildRequested() | |
{ | |
// After a Font asset gets re-imported the managed side gets deleted and recreated, | |
// that means the delegates are not persisted. | |
// so we need to properly enforce a consistent state here. | |
UnregisterFontTextureChanged (); | |
RegisterFontTextureChanged (); | |
// Also the textgenerator is no longer valid. | |
cachedTextGenerator.Invalidate(); | |
base.OnRebuildRequested(); | |
} | |
#endif | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment