diff options
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs')
-rw-r--r-- | Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs new file mode 100644 index 0000000..3d3d17b --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Font/Text.cs @@ -0,0 +1,576 @@ +using System; +using System.Collections.Generic; + +namespace UnityEngine.UI +{ + /// <summary> + /// Labels are graphics that display text. + /// </summary> + + [AddComponentMenu("UI/Text", 10)] + public class Text : MaskableGraphic, ILayoutElement + { + [SerializeField] private FontData m_FontData = FontData.defaultFontData; + +#if UNITY_EDITOR + // needed to track font changes from the inspector + private Font m_LastTrackedFont; +#endif + + [TextArea(3, 10)][SerializeField] protected string m_Text = String.Empty; + + private TextGenerator m_TextCache; + private TextGenerator m_TextCacheForLayout; + + static protected Material s_DefaultText = null; + + // We use this flag instead of Unregistering/Registering the callback to avoid allocation. + [NonSerialized] protected bool m_DisableFontTextureRebuiltCallback = false; + + protected Text() + { + useLegacyMeshGeneration = false; + } + + // text generator,得到字符串在glyph atlas中的UV,构建mesh + /// <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()); } + } + + /// <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; + } + } + + public void FontTextureChanged() + { + // Only invoke if we are not destroyed. + if (!this) + return; + + if (m_DisableFontTextureRebuiltCallback) + 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(); + } + + public Font font + { + get + { + return m_FontData.font; + } + set + { + if (m_FontData.font == value) + return; + + FontUpdateTracker.UntrackText(this); + + m_FontData.font = value; + + FontUpdateTracker.TrackText(this); + +#if UNITY_EDITOR + // needed to track font changes from the inspector + m_LastTrackedFont = value; +#endif + + SetAllDirty(); + } + } + + /// <summary> + /// Text that's being displayed by the Text. + /// </summary> + + public virtual 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; + SetVerticesDirty(); + SetLayoutDirty(); + } + } + } + + /// <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; + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + /// <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; + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public int resizeTextMinSize + { + get + { + return m_FontData.minSize; + } + set + { + if (m_FontData.minSize == value) + return; + m_FontData.minSize = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public int resizeTextMaxSize + { + get + { + return m_FontData.maxSize; + } + set + { + if (m_FontData.maxSize == value) + return; + m_FontData.maxSize = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + /// <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; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public bool alignByGeometry + { + get + { + return m_FontData.alignByGeometry; + } + set + { + if (m_FontData.alignByGeometry == value) + return; + m_FontData.alignByGeometry = value; + + SetVerticesDirty(); + } + } + + public int fontSize + { + get + { + return m_FontData.fontSize; + } + set + { + // font size改变的时候重建mesh + if (m_FontData.fontSize == value) + return; + m_FontData.fontSize = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public HorizontalWrapMode horizontalOverflow + { + get + { + return m_FontData.horizontalOverflow; + } + set + { + if (m_FontData.horizontalOverflow == value) + return; + m_FontData.horizontalOverflow = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public VerticalWrapMode verticalOverflow + { + get + { + return m_FontData.verticalOverflow; + } + set + { + if (m_FontData.verticalOverflow == value) + return; + m_FontData.verticalOverflow = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public float lineSpacing + { + get + { + return m_FontData.lineSpacing; + } + set + { + if (m_FontData.lineSpacing == value) + return; + m_FontData.lineSpacing = value; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + /// <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; + + SetVerticesDirty(); + SetLayoutDirty(); + } + } + + public float pixelsPerUnit + { + get + { + var localCanvas = canvas; + if (!localCanvas) + return 1; + // For dynamic fonts, ensure we use one pixel per pixel on the screen. + if (!font || font.dynamic) + return localCanvas.scaleFactor; + // For non-dynamic fonts, calculate pixels per unit based on specified font size relative to font object's own font size. + if (m_FontData.fontSize <= 0 || font.fontSize <= 0) + return 1; + return font.fontSize / (float)m_FontData.fontSize; + } + } + + protected override void OnEnable() + { + base.OnEnable(); + cachedTextGenerator.Invalidate(); + FontUpdateTracker.TrackText(this); + } + + protected override void OnDisable() + { + FontUpdateTracker.UntrackText(this); + base.OnDisable(); + } + + protected override void UpdateGeometry() + { + if (font != null) + { + base.UpdateGeometry(); + } + } + +#if UNITY_EDITOR + protected override void Reset() + { + AssignDefaultFont(); + } + +#endif + internal void AssignDefaultFont() + { + font = Resources.GetBuiltinResource<Font>("Arial.ttf"); + } + + // 根据FontData设置TextGenerationSettings + public TextGenerationSettings GetGenerationSettings(Vector2 extents) + { + var settings = new TextGenerationSettings(); + + settings.generationExtents = extents; + if (font != null && font.dynamic) + { + settings.fontSize = m_FontData.fontSize; + settings.resizeTextMinSize = m_FontData.minSize; + settings.resizeTextMaxSize = m_FontData.maxSize; + } + + // Other settings + settings.textAnchor = m_FontData.alignment; + settings.alignByGeometry = m_FontData.alignByGeometry; + settings.scaleFactor = pixelsPerUnit; + settings.color = color; // 这里是顶点颜色 + settings.font = font; + settings.pivot = rectTransform.pivot; + settings.richText = m_FontData.richText; + settings.lineSpacing = m_FontData.lineSpacing; + settings.fontStyle = m_FontData.fontStyle; + settings.resizeTextForBestFit = m_FontData.bestFit; + 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; + } + } + + readonly UIVertex[] m_TempVerts = new UIVertex[4]; + protected override void OnPopulateMesh(VertexHelper toFill) + { + if (font == null) + return; + + // We don't 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_DisableFontTextureRebuiltCallback = true; + + Vector2 extents = rectTransform.rect.size; + + // 生成对应的网格数据(顶点、UV) + var settings = GetGenerationSettings(extents); + cachedTextGenerator.PopulateWithErrors(text, settings, gameObject); + + // Apply the offset to the vertices + IList<UIVertex> verts = cachedTextGenerator.verts; + float unitsPerPixel = 1 / pixelsPerUnit; + //Last 4 verts are always a new line... (\n) + int vertCount = verts.Count - 4; + + Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel; + roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset; + toFill.Clear(); + if (roundingOffset != Vector2.zero) + { + for (int i = 0; i < vertCount; ++i) + { + int tempVertsIndex = i & 3; + m_TempVerts[tempVertsIndex] = verts[i]; + m_TempVerts[tempVertsIndex].position *= unitsPerPixel; + m_TempVerts[tempVertsIndex].position.x += roundingOffset.x; + m_TempVerts[tempVertsIndex].position.y += roundingOffset.y; + if (tempVertsIndex == 3) + toFill.AddUIVertexQuad(m_TempVerts); + } + } + else + { + for (int i = 0; i < vertCount; ++i) + { + int tempVertsIndex = i & 3; + m_TempVerts[tempVertsIndex] = verts[i]; + m_TempVerts[tempVertsIndex].position *= unitsPerPixel; + if (tempVertsIndex == 3) + toFill.AddUIVertexQuad(m_TempVerts); + } + } + + m_DisableFontTextureRebuiltCallback = false; + } + + public virtual void CalculateLayoutInputHorizontal() {} + public virtual void CalculateLayoutInputVertical() {} + + public virtual float minWidth + { + get { return 0; } + } + + public virtual float preferredWidth + { + get + { + var settings = GetGenerationSettings(Vector2.zero); + return cachedTextGeneratorForLayout.GetPreferredWidth(m_Text, settings) / pixelsPerUnit; + } + } + + public virtual float flexibleWidth { get { return -1; } } + + public virtual float minHeight + { + get { return 0; } + } + + public virtual float preferredHeight + { + get + { + var settings = GetGenerationSettings(new Vector2(GetPixelAdjustedRect().size.x, 0.0f)); + return cachedTextGeneratorForLayout.GetPreferredHeight(m_Text, settings) / pixelsPerUnit; + } + } + + public virtual float flexibleHeight { get { return -1; } } + + public virtual int layoutPriority { get { return 0; } } + +#if UNITY_EDITOR + public override 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. + FontUpdateTracker.UntrackText(this); + FontUpdateTracker.TrackText(this); + + // Also the textgenerator is no longer valid. + cachedTextGenerator.Invalidate(); + + base.OnRebuildRequested(); + } + + // 当编辑器里修改了参数值的时候调这个回调,setDirty,后续重建mesh + // The Text inspector editor can change the font, and we need a way to track changes so that we get the appropriate rebuild callbacks + // We can intercept changes in OnValidate, and keep track of the previous font reference + protected override void OnValidate() + { + if (!IsActive()) + { + base.OnValidate(); + return; + } + + if (m_FontData.font != m_LastTrackedFont) + { + Font newFont = m_FontData.font; + m_FontData.font = m_LastTrackedFont; + FontUpdateTracker.UntrackText(this); + m_FontData.font = newFont; + FontUpdateTracker.TrackText(this); + + m_LastTrackedFont = newFont; + } + base.OnValidate(); + } + +#endif // if UNITY_EDITOR + } +} |