转载:http://blog.gamerisker.com/archives/530.html
之前发过一个图文混排的文章 《[Unity3D学习]NGUI UILabel 图文混排》
一直感觉那样比较消耗。又由于公司项目也需要做图文混排,就想了另一种图文混排思路,从性能来说比之前的思路要好很多,不过也有弊端,现在这种解决方案,做动态表情不太适应。不过我想的是,手机游戏对聊天功能其实已经比较弱化了,所以个人认为聊天不需要做得太复杂,一切从简就好。
说说这个版本的图文混排的思路吧:
创建了两个UILabel 一个是动态字体、一个是图集字体,一个用来显示文本内容,另一个就用来显示表情,再通过修改表情Label的顶点坐标来修改每个表情的位置,达到图文混排的效果。
这个思路我觉得还是合理的,不过有些地方我不满意,我在NGUI UILabel 的OnFill方法(1519行)中添加了一个回调,来修改最终的渲染坐标,我个人不喜欢去修改原作者的代码。不愿意去破坏原来的结构,这是我不满意的地方。
其实我最开始的想法是将文本和表情放在同一个mesh上,那样就能自己独立写一个CustomLabel。这样的性能应该是最好的。
不过总的来说,现在的这个方案,是用最少的代码实现了动态字体的图文混排。(这只是给出了实现的基本原理,其中还有很多的不足,需要自己去打磨!仔细看代码,相信你会对NGUI有一个很深程度的理解的。)
说了那么多,先看看 Demo : http://game.gamerisker.com/symbol
看完Demo就来看代码吧
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
///
/// 主要用来串联一下两个类 实现DEMO功能
/// Author : YangDan
/// Site : blog.gamerisker.com
///
public class Main : MonoBehaviour
{
public SymbolInput input;
public SymbolLabel label;
public List list = new List();
// Use this for initialization
void Start ()
{
foreach (UISprite item in list)
{
UIEventListener.Get(item.gameObject).onClick = OnClick;
}
}
private void OnClick(GameObject go)
{
input.value += go.name;
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Return)||Input.GetKeyDown(KeyCode.KeypadEnter))
{
label.text = input.value;
input.value = "";
}
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Text;
///
/// 支持动态字体的Label组件
///
public class SymbolLabel : MonoBehaviour
{
///
/// 表情转移字符定义
///
private List m_Symbols = new List { "{00}", "{01}", "{02}", "{03}", "{04}", "{05}"
, "{06}", "{07}", "{08}", "{09}", "{10}"};
private string m_Text;
private string m_realText;
public UIFont uifont;
public Font font;
public int fontSize = 26;
public int symbolSize = 26;
public int spacingY = 0;
public int width = 100;
public int depth = 0;
public int maxLine = 0;
public UILabel.Overflow overflowMethod = UILabel.Overflow.ResizeHeight;
private UILabel m_TextLabel;
private UILabel m_SymbolLabel;
private MatchCollection m_matchs;
private MatchCollection m_spaceMatchs;
private List m_realMatchs;
private int m_DrawStart = 0;
void Awake()
{
m_realMatchs = new List();
m_TextLabel = NGUITools.AddChild(gameObject);
m_TextLabel.name = "textLabel";
m_TextLabel.trueTypeFont = font;
m_TextLabel.spacingY = spacingY;
m_TextLabel.fontSize = fontSize;
m_TextLabel.overflowMethod = overflowMethod;
m_TextLabel.alignment = NGUIText.Alignment.Left;
m_TextLabel.pivot = UIWidget.Pivot.TopLeft;
m_TextLabel.width = width;
m_TextLabel.depth = depth;
m_TextLabel.transform.localPosition = Vector3.zero;
if (overflowMethod == UILabel.Overflow.ClampContent)
{
m_TextLabel.height = fontSize;
m_TextLabel.maxLineCount = maxLine;
}
m_SymbolLabel = NGUITools.AddChild(gameObject);
m_SymbolLabel.name = "symbolLabel";
m_SymbolLabel.bitmapFont = uifont;
m_SymbolLabel.fontSize = symbolSize;
m_SymbolLabel.overflowMethod = UILabel.Overflow.ShrinkContent;
m_SymbolLabel.alignment = NGUIText.Alignment.Left;
m_SymbolLabel.pivot = UIWidget.Pivot.TopLeft;
m_SymbolLabel.depth = depth + 1;
m_SymbolLabel.transform.localPosition = Vector3.zero;
m_SymbolLabel.SetSymbolOffset(SymbolOffset);
}
public int height
{
get
{
return m_TextLabel.height;
}
}
public UILabel labelText
{
get
{
return m_TextLabel;
}
}
public UILabel labelSymbol
{
get
{
return m_SymbolLabel;
}
}
public string text
{
get { return m_Text; }
set
{
if(string.IsNullOrEmpty(value))
{
m_Text = "";
m_TextLabel.text = null;
m_SymbolLabel.text = null;
m_realMatchs.Clear();
return;
}
m_realMatchs.Clear();
m_Text = value;
string mProcessedText = m_TextLabel.processedText;
if (overflowMethod == UILabel.Overflow.ResizeHeight) mProcessedText = m_Text;
else NGUIText.WrapText(m_Text, out mProcessedText);
StringBuilder sString = new StringBuilder();
string t = value;
const string pattern = "\\{\\w\\w\\}";
m_realText = NGUIText.StripSymbols(mProcessedText);
m_matchs = Regex.Matches(m_realText, pattern);
const string pat = " ";
m_spaceMatchs = Regex.Matches(mProcessedText, pat);
if (m_matchs.Count > 0)
{
Match item;
for (int i = 0; i < m_matchs.Count; i++)
{
item = m_matchs[i];
if (m_Symbols.IndexOf(item.Value) > -1)
{
m_realMatchs.Add(item);
sString.Append(item.Value);
}
}
}
m_TextLabel.text = t;
m_SymbolLabel.text = sString.ToString();
m_SymbolLabel.width = m_TextLabel.width;
m_SymbolLabel.height = m_TextLabel.height;
m_SymbolLabel.MarkAsChanged();
}
}
///
/// 修改顶点坐标 适配表情位置
/// 1 — 2
/// | / |
/// 0 — 3
///
private void SymbolOffset()
{
BetterList textVerts = m_TextLabel.geometry.verts;
BetterList symbolVerts = m_SymbolLabel.geometry.verts;
Vector3 spacing = new Vector3(0,0);
if (textVerts.size > 0 && symbolVerts.size > 0)
{
Match item;
float tw, sw, x = 0;
int end, start;
for (int i = 0; i < m_realMatchs.Count; i++)
{
item = m_realMatchs[i];
//获取表情转移字符顶点开始、结束索引
start = GetIndex(item.Index) * 4;
end = start + (item.Length - 1) * 4 + 3;
//表情都顶点索引
int p = i * 4;
//表情宽度
sw = Mathf.Abs(symbolVerts.buffer[p].x - symbolVerts.buffer[p + 3].x);
//如果不换行,计算文本表情转移符都宽带 否则换行不需要计算 添加1个单位距离 跟在后面
if (textVerts.buffer[start].y == textVerts.buffer[end].y)
{
//文本表情转义符宽度
tw = Mathf.Abs(textVerts.buffer[start].x - textVerts.buffer[end].x);
//计算居中坐标
x = (tw - sw) / 2;
}
else x = 1;
//居中显示表情
spacing.x = x;
//计算偏移
Vector2 po = m_TextLabel.pivotOffset;
float fx = Mathf.Lerp(0f, -NGUIText.rectWidth, po.x);
float fy = Mathf.Lerp(NGUIText.rectHeight, 0f, po.y) + Mathf.Lerp((m_TextLabel.printedSize.y - NGUIText.rectHeight), 0f, po.y);
fx = Mathf.Round(fx);
fy = Mathf.Round(fy);
//计算出位移向量
Vector3 v = textVerts.buffer[start] - symbolVerts.buffer[p];
//第一个顶点
symbolVerts.buffer[p] = textVerts.buffer[start] + spacing;
symbolVerts.buffer[p].x -= fx;
symbolVerts.buffer[p++].y -= fy;
//第二个顶点
symbolVerts.buffer[p] = symbolVerts.buffer[p] + v + spacing;
symbolVerts.buffer[p].x -= fx;
symbolVerts.buffer[p++].y -= fy;
//第三个顶点
symbolVerts.buffer[p] = symbolVerts.buffer[p] + v + spacing;
symbolVerts.buffer[p].x -= fx;
symbolVerts.buffer[p++].y -= fy;
//第四个顶点
symbolVerts.buffer[p] = symbolVerts.buffer[p] + v + spacing;
symbolVerts.buffer[p].x -= fx;
symbolVerts.buffer[p++].y -= fy;
for (int j = 0; j < item.Length; j++)
{
//本来是希望将顶点坐标抹除、但是由于会出现坐标不对都情况、所以放弃了该方法,将顶点都颜色清除掉。
//textVerts.buffer[start++] = Vector3.zero;
//textVerts.buffer[start++] = Vector3.zero;
//textVerts.buffer[start++] = Vector3.zero;
//textVerts.buffer[start++] = Vector3.zero;
if (m_TextLabel.geometry.cols.size >= (start + 4))
{
m_TextLabel.geometry.cols[start++] = Color.clear;
m_TextLabel.geometry.cols[start++] = Color.clear;
m_TextLabel.geometry.cols[start++] = Color.clear;
m_TextLabel.geometry.cols[start++] = Color.clear;
}
}
}
}
}
///
/// 获取表情转移字符'{'顶点索引,并且需要排除空格符的部分,因为空格符UILabel是不会生成顶点的 所以需要减去空格符都数量,才能正确获得表情索引
///
///
private int GetIndex(int itemIndex)
{
Match item;
int count = 0;
for (int i = 0; i < m_spaceMatchs.Count; i++)
{
item = m_spaceMatchs[i];
if (item.Index < itemIndex)
{
count++;
}
}
return itemIndex - count;
}
}
//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2014 Tasharen Entertainment
//----------------------------------------------
#if !UNITY_EDITOR && (UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY)
#define MOBILE
#endif
using UnityEngine;
using System.Collections.Generic;
using System.Text;
///
/// Input field makes it possible to enter custom information within the UI.
/// 使用这个类时,请去UIInputEditor.cs文件中将 [CustomEditor(typeof(UIInput), true)]改为[CustomEditor(typeof(UIInput), false)]
/// 如果不修改,你将无法设置newLabel这个属性。
///
//[AddComponentMenu("NGUI/UI/Input Field")]
public class SymbolInput : UIInput
{
///
/// Text label used to display the input's value.
///
public SymbolLabel newLabel;
///
/// Input field's value.
///
//[SerializeField][HideInInspector] protected string mValue;
//protected string mDefaultText = "";
//protected Color mDefaultColor = Color.white;
//protected float mPosition = 0f;
//protected bool mDoInit = true;
//protected UIWidget.Pivot mPivot = UIWidget.Pivot.TopLeft;
//static protected int mDrawStart = 0;
//#if MOBILE
// static protected TouchScreenKeyboard mKeyboard;
//#else
// protected int mSelectionStart = 0;
// protected int mSelectionEnd = 0;
// protected UITexture mHighlight = null;
// protected UITexture mCaret = null;
// protected Texture2D mBlankTex = null;
// protected float mNextBlink = 0f;
// protected float mLastAlpha = 0f;
// static protected string mLastIME = "";
//#endif
///
/// Default text used by the input's label.
///
public new string defaultText
{
get
{
return mDefaultText;
}
set
{
if (mDoInit) Init();
mDefaultText = value;
UpdateLabel();
}
}
[System.Obsolete("Use UIInput.value instead")]
public new string text { get { return this.value; } set { this.value = value; } }
///
/// Input field's current text value.
///
public new string value
{
get
{
#if UNITY_EDITOR
if (!Application.isPlaying) return "";
#endif
if (mDoInit) Init();
return mValue;
}
set
{
#if UNITY_EDITOR
if (!Application.isPlaying) return;
#endif
if (mDoInit) Init();
mDrawStart = 0;
#if MOBILE && !UNITY_3_5
// BB10's implementation has a bug in Unity
if (Application.platform == RuntimePlatform.BB10Player)
value = value.Replace("\\b", "\b");
#endif
// Validate all input
value = Validate(value);
#if MOBILE
if (isSelected && mKeyboard != null && mCached != value)
{
mKeyboard.text = value;
mCached = value;
}
if (mValue != value)
{
mValue = value;
if (!isSelected) SaveToPlayerPrefs(value);
UpdateLabel();
ExecuteOnChange();
}
#else
if (mValue != value)
{
mValue = value;
if (isSelected)
{
if (string.IsNullOrEmpty(value))
{
mSelectionStart = 0;
mSelectionEnd = 0;
}
else
{
mSelectionStart = value.Length;
mSelectionEnd = mSelectionStart;
}
}
else SaveToPlayerPrefs(value);
UpdateLabel();
ExecuteOnChange();
}
#endif
}
}
[System.Obsolete("Use UIInput.isSelected instead")]
public new bool selected { get { return isSelected; } set { isSelected = value; } }
///
/// Whether the input is currently selected.
///
public new bool isSelected
{
get
{
return selection == this;
}
set
{
if (!value) { if (isSelected) UICamera.selectedObject = null; }
else UICamera.selectedObject = gameObject;
}
}
#if MOBILE
///
/// Current position of the cursor.
///
public int cursorPosition { get { return value.Length; } set {} }
///
/// Index of the character where selection begins.
///
public int selectionStart { get { return value.Length; } set {} }
///
/// Index of the character where selection ends.
///
public int selectionEnd { get { return value.Length; } set {} }
#else
///
/// Current position of the cursor.
///
public new int cursorPosition
{
get
{
return isSelected ? mSelectionEnd : value.Length;
}
set
{
if (isSelected)
{
mSelectionEnd = value;
UpdateLabel();
}
}
}
///
/// Index of the character where selection begins.
///
public new int selectionStart
{
get
{
return isSelected ? mSelectionStart : value.Length;
}
set
{
if (isSelected)
{
mSelectionStart = value;
UpdateLabel();
}
}
}
///
/// Index of the character where selection ends.
///
public new int selectionEnd
{
get
{
return isSelected ? mSelectionEnd : value.Length;
}
set
{
if (isSelected)
{
mSelectionEnd = value;
UpdateLabel();
}
}
}
#endif
///
/// Validate the specified text, returning the validated version.
///
public new string Validate (string val)
{
if (string.IsNullOrEmpty(val)) return "";
StringBuilder sb = new StringBuilder(val.Length);
for (int i = 0; i < val.Length; ++i)
{
char c = val[i];
if (onValidate != null) c = onValidate(sb.ToString(), sb.Length, c);
else if (validation != Validation.None) c = Validate(sb.ToString(), sb.Length, c);
if (c != 0) sb.Append(c);
}
if (characterLimit > 0 && sb.Length > characterLimit)
return sb.ToString(0, characterLimit);
return sb.ToString();
}
///
/// Automatically set the value by loading it from player prefs if possible.
///
void Start ()
{
if (string.IsNullOrEmpty(mValue))
{
if (!string.IsNullOrEmpty(savedAs) && PlayerPrefs.HasKey(savedAs))
value = PlayerPrefs.GetString(savedAs);
}
else value = mValue.Replace("\\n", "\n");
}
///
/// Labels used for input shouldn't support rich text.
///
protected new void Init ()
{
if (mDoInit && newLabel != null)
{
mDoInit = false;
mDefaultText = newLabel.text;
mDefaultColor = newLabel.labelText.color;
//newLabel.labelText.supportEncoding = false;
if (newLabel.labelText.alignment == NGUIText.Alignment.Justified)
{
newLabel.labelText.alignment = NGUIText.Alignment.Left;
Debug.LogWarning("Input fields using labels with justified alignment are not supported at this time", this);
}
mPivot = newLabel.labelText.pivot;
mPosition = newLabel.labelText.cachedTransform.localPosition.x;
UpdateLabel();
}
}
///
/// Save the specified value to player prefs.
///
protected new void SaveToPlayerPrefs (string val)
{
if (!string.IsNullOrEmpty(savedAs))
{
if (string.IsNullOrEmpty(val)) PlayerPrefs.DeleteKey(savedAs);
else PlayerPrefs.SetString(savedAs, val);
}
}
///
/// Selection event, sent by the EventSystem.
///
override protected void OnSelect (bool isSelected)
{
if (isSelected) OnSelectEvent();
else OnDeselectEvent();
}
///
/// Notification of the input field gaining selection.
///
protected new void OnSelectEvent ()
{
selection = this;
if (mDoInit) Init();
if (newLabel != null && NGUITools.GetActive(this))
{
newLabel.labelText.color = activeTextColor;
#if MOBILE
if (Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.Android
#if UNITY_WP8
|| Application.platform == RuntimePlatform.WP8Player
#endif
#if UNITY_BLACKBERRY
|| Application.platform == RuntimePlatform.BB10Player
#endif
)
{
mKeyboard = (inputType == InputType.Password) ?
TouchScreenKeyboard.Open(mValue, TouchScreenKeyboardType.Default, false, false, true) :
TouchScreenKeyboard.Open(mValue, (TouchScreenKeyboardType)((int)keyboardType), inputType == InputType.AutoCorrect, newLabel.labelText.multiLine, false, false, defaultText);
}
else
#endif
{
Vector2 pos = (UICamera.current != null && UICamera.current.cachedCamera != null) ?
UICamera.current.cachedCamera.WorldToScreenPoint(newLabel.labelText.worldCorners[0]) :
newLabel.labelText.worldCorners[0];
pos.y = Screen.height - pos.y;
Input.imeCompositionMode = IMECompositionMode.On;
Input.compositionCursorPos = pos;
#if !MOBILE
mSelectionStart = 0;
mSelectionEnd = string.IsNullOrEmpty(mValue) ? 0 : mValue.Length;
#endif
mDrawStart = 0;
}
UpdateLabel();
}
}
///
/// Notification of the input field losing selection.
///
protected new void OnDeselectEvent ()
{
if (mDoInit) Init();
if (newLabel != null && NGUITools.GetActive(this))
{
mValue = value;
#if MOBILE
if (mKeyboard != null)
{
mKeyboard.active = false;
mKeyboard = null;
}
#endif
if (string.IsNullOrEmpty(mValue))
{
newLabel.text = mDefaultText;
newLabel.labelText.color = mDefaultColor;
}
else newLabel.text = mValue;
Input.imeCompositionMode = IMECompositionMode.Auto;
RestoreLabelPivot();
}
selection = null;
UpdateLabel();
}
///
/// Update the text based on input.
///
#if MOBILE
string mCached = "";
void Update()
{
if (mKeyboard != null && isSelected)
{
string text = mKeyboard.text;
if (mCached != text)
{
mCached = text;
value = text;
}
if (mKeyboard.done)
{
#if !UNITY_3_5
if (!mKeyboard.wasCanceled)
#endif
Submit();
mKeyboard = null;
isSelected = false;
mCached = "";
}
}
}
#else
void Update ()
{
#if UNITY_EDITOR
if (!Application.isPlaying) return;
#endif
if (isSelected)
{
if (mDoInit) Init();
if (selectOnTab != null && Input.GetKeyDown(KeyCode.Tab))
{
UICamera.selectedObject = selectOnTab;
return;
}
string ime = Input.compositionString;
// There seems to be an inconsistency between IME on Windows, and IME on OSX.
// On Windows, Input.inputString is always empty while IME is active. On the OSX it is not.
if (string.IsNullOrEmpty(ime) && !string.IsNullOrEmpty(Input.inputString))
{
// Process input ignoring non-printable characters as they are not consistent.
// Windows has them, OSX may not. They get handled inside OnGUI() instead.
string s = Input.inputString;
for (int i = 0; i < s.Length; ++i)
{
char ch = s[i];
if (ch < ' ') continue;
// OSX inserts these characters for arrow keys
if (ch == '\uF700') continue;
if (ch == '\uF701') continue;
if (ch == '\uF702') continue;
if (ch == '\uF703') continue;
Insert(ch.ToString());
}
}
// Append IME composition
if (mLastIME != ime)
{
mSelectionEnd = string.IsNullOrEmpty(ime) ? mSelectionStart : mValue.Length + ime.Length;
mLastIME = ime;
UpdateLabel();
ExecuteOnChange();
}
// Blink the caret
if (mCaret != null && mNextBlink < RealTime.time)
{
mNextBlink = RealTime.time + 0.5f;
mCaret.enabled = !mCaret.enabled;
}
// If the label's final alpha changes, we need to update the drawn geometry,
// or the highlight widgets (which have their geometry set manually) won't update.
if (isSelected && mLastAlpha != newLabel.labelText.finalAlpha)
UpdateLabel();
}
}
///
/// Unfortunately Unity 4.3 and earlier doesn't offer a way to properly process events outside of OnGUI.
///
void OnGUI ()
{
if (isSelected && Event.current.rawType == EventType.KeyDown)
ProcessEvent(Event.current);
}
///
/// Handle the specified event.
///
bool ProcessEvent (Event ev)
{
if (newLabel == null) return false;
RuntimePlatform rp = Application.platform;
bool isMac = (
rp == RuntimePlatform.OSXEditor ||
rp == RuntimePlatform.OSXPlayer ||
rp == RuntimePlatform.OSXWebPlayer);
bool ctrl = isMac ?
((ev.modifiers & EventModifiers.Command) != 0) :
((ev.modifiers & EventModifiers.Control) != 0);
bool shift = ((ev.modifiers & EventModifiers.Shift) != 0);
switch (ev.keyCode)
{
case KeyCode.Backspace:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
if (mSelectionStart == mSelectionEnd)
{
if (mSelectionStart < 1) return true;
--mSelectionEnd;
}
Insert("");
}
return true;
}
case KeyCode.Delete:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
if (mSelectionStart == mSelectionEnd)
{
if (mSelectionStart >= mValue.Length) return true;
++mSelectionEnd;
}
Insert("");
}
return true;
}
case KeyCode.LeftArrow:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
mSelectionEnd = Mathf.Max(mSelectionEnd - 1, 0);
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
case KeyCode.RightArrow:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
mSelectionEnd = Mathf.Min(mSelectionEnd + 1, mValue.Length);
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
case KeyCode.PageUp:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
mSelectionEnd = 0;
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
case KeyCode.PageDown:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
mSelectionEnd = mValue.Length;
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
case KeyCode.Home:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
if (newLabel.labelText.multiLine)
{
mSelectionEnd = newLabel.labelText.GetCharacterIndex(mSelectionEnd, KeyCode.Home);
}
else mSelectionEnd = 0;
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
case KeyCode.End:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
if (newLabel.labelText.multiLine)
{
mSelectionEnd = newLabel.labelText.GetCharacterIndex(mSelectionEnd, KeyCode.End);
}
else mSelectionEnd = mValue.Length;
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
case KeyCode.UpArrow:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
mSelectionEnd = newLabel.labelText.GetCharacterIndex(mSelectionEnd, KeyCode.UpArrow);
if (mSelectionEnd != 0) mSelectionEnd += mDrawStart;
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
case KeyCode.DownArrow:
{
ev.Use();
if (!string.IsNullOrEmpty(mValue))
{
mSelectionEnd = newLabel.labelText.GetCharacterIndex(mSelectionEnd, KeyCode.DownArrow);
if (mSelectionEnd != newLabel.labelText.processedText.Length) mSelectionEnd += mDrawStart;
else mSelectionEnd = mValue.Length;
if (!shift) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
return true;
}
// Copy
case KeyCode.C:
{
if (ctrl)
{
ev.Use();
NGUITools.clipboard = GetSelection();
}
return true;
}
// Paste
case KeyCode.V:
{
if (ctrl)
{
ev.Use();
Insert(NGUITools.clipboard);
}
return true;
}
// Cut
case KeyCode.X:
{
if (ctrl)
{
ev.Use();
NGUITools.clipboard = GetSelection();
Insert("");
}
return true;
}
// Submit
case KeyCode.Return:
case KeyCode.KeypadEnter:
{
ev.Use();
if (newLabel.labelText.multiLine && !ctrl && newLabel.labelText.overflowMethod != UILabel.Overflow.ClampContent)
{
Insert("\n");
}
else
{
UICamera.currentScheme = UICamera.ControlScheme.Controller;
UICamera.currentKey = ev.keyCode;
Submit();
UICamera.currentKey = KeyCode.None;
}
return true;
}
}
return false;
}
///
/// Insert the specified text string into the current input value, respecting selection and validation.
///
override protected void Insert (string text)
{
string left = GetLeftText();
string right = GetRightText();
int rl = right.Length;
StringBuilder sb = new StringBuilder(left.Length + right.Length + text.Length);
sb.Append(left);
// Append the new text
for (int i = 0, imax = text.Length; i < imax; ++i)
{
// Can't go past the character limit
if (characterLimit > 0 && sb.Length + rl >= characterLimit) break;
// If we have an input validator, validate the input first
char c = text[i];
if (onValidate != null) c = onValidate(sb.ToString(), sb.Length, c);
else if (validation != Validation.None) c = Validate(sb.ToString(), sb.Length, c);
// Append the character if it hasn't been invalidated
if (c != 0) sb.Append(c);
}
// Advance the selection
mSelectionStart = sb.Length;
mSelectionEnd = mSelectionStart;
// Append the text that follows it, ensuring that it's also validated after the inserted value
for (int i = 0, imax = right.Length; i < imax; ++i)
{
char c = right[i];
if (onValidate != null) c = onValidate(sb.ToString(), sb.Length, c);
else if (validation != Validation.None) c = Validate(sb.ToString(), sb.Length, c);
if (c != 0) sb.Append(c);
}
mValue = sb.ToString();
UpdateLabel();
ExecuteOnChange();
}
///
/// Get the text to the left of the selection.
///
protected new string GetLeftText ()
{
int min = Mathf.Min(mSelectionStart, mSelectionEnd);
return (string.IsNullOrEmpty(mValue) || min < 0) ? "" : mValue.Substring(0, min);
}
///
/// Get the text to the right of the selection.
///
protected new string GetRightText ()
{
int max = Mathf.Max(mSelectionStart, mSelectionEnd);
return (string.IsNullOrEmpty(mValue) || max >= mValue.Length) ? "" : mValue.Substring(max);
}
///
/// Get currently selected text.
///
protected new string GetSelection ()
{
if (string.IsNullOrEmpty(mValue) || mSelectionStart == mSelectionEnd)
{
return "";
}
else
{
int min = Mathf.Min(mSelectionStart, mSelectionEnd);
int max = Mathf.Max(mSelectionStart, mSelectionEnd);
return mValue.Substring(min, max - min);
}
}
///
/// Helper function that retrieves the index of the character under the mouse.
///
protected new int GetCharUnderMouse ()
{
Vector3[] corners = newLabel.labelText.worldCorners;
Ray ray = UICamera.currentRay;
Plane p = new Plane(corners[0], corners[1], corners[2]);
float dist;
return p.Raycast(ray, out dist) ? mDrawStart + newLabel.labelText.GetCharacterIndexAtPosition(ray.GetPoint(dist)) : 0;
}
///
/// Move the caret on press.
///
protected override void OnPress (bool isPressed)
{
if (isPressed && isSelected && newLabel != null && UICamera.currentScheme == UICamera.ControlScheme.Mouse)
{
mSelectionEnd = GetCharUnderMouse();
if (!Input.GetKey(KeyCode.LeftShift) &&
!Input.GetKey(KeyCode.RightShift)) mSelectionStart = mSelectionEnd;
UpdateLabel();
}
}
///
/// Drag selection.
///
protected override void OnDrag (Vector2 delta)
{
if (newLabel != null && UICamera.currentScheme == UICamera.ControlScheme.Mouse)
{
mSelectionEnd = GetCharUnderMouse();
UpdateLabel();
}
}
///
/// Ensure we've released the dynamically created resources.
///
void OnDisable () { Cleanup(); }
///
/// Cleanup.
///
protected override void Cleanup ()
{
if (mHighlight) mHighlight.enabled = false;
if (mCaret) mCaret.enabled = false;
if (mBlankTex)
{
NGUITools.Destroy(mBlankTex);
mBlankTex = null;
}
}
#endif // !MOBILE
///
/// Submit the input field's text.
///
public new void Submit ()
{
if (NGUITools.GetActive(this))
{
current = this;
mValue = value;
EventDelegate.Execute(onSubmit);
SaveToPlayerPrefs(mValue);
current = null;
}
}
///
/// Update the visual text label.
///
public new void UpdateLabel ()
{
if (newLabel != null)
{
if (mDoInit) Init();
bool selected = isSelected;
string fullText = value;
bool isEmpty = string.IsNullOrEmpty(fullText) && string.IsNullOrEmpty(Input.compositionString);
newLabel.labelText.color = (isEmpty && !selected) ? mDefaultColor : activeTextColor;
string processed;
if (isEmpty)
{
processed = selected ? "" : mDefaultText;
RestoreLabelPivot();
}
else
{
if (inputType == InputType.Password)
{
processed = "";
for (int i = 0, imax = fullText.Length; i < imax; ++i) processed += "*";
}
else processed = fullText;
// Start with text leading up to the selection
int selPos = selected ? Mathf.Min(processed.Length, cursorPosition) : 0;
string left = processed.Substring(0, selPos);
// Append the composition string and the cursor character
if (selected) left += Input.compositionString;
// Append the text from the selection onwards
processed = left + processed.Substring(selPos, processed.Length - selPos);
// Clamped content needs to be adjusted further
if (selected && newLabel.labelText.overflowMethod == UILabel.Overflow.ClampContent)
{
// Determine what will actually fit into the given line
int offset = newLabel.labelText.CalculateOffsetToFit(processed);
if (offset == 0)
{
mDrawStart = 0;
RestoreLabelPivot();
}
else if (selPos < mDrawStart)
{
mDrawStart = selPos;
SetPivotToLeft();
}
else if (offset < mDrawStart)
{
mDrawStart = offset;
SetPivotToLeft();
}
else
{
offset = newLabel.labelText.CalculateOffsetToFit(processed.Substring(0, selPos));
if (offset > mDrawStart)
{
mDrawStart = offset;
SetPivotToRight();
}
}
// If necessary, trim the front
// 处理末尾 开始 出现{ } 转义符
if (mDrawStart != 0)
{
processed = processed.Substring(mDrawStart, processed.Length - mDrawStart);
int back = 0;
int front = 0;
const int t = 3;
front = processed.IndexOf('}', 0, t);
if (front > -1)
{
processed = processed.Substring(front + 1);
}
back = processed.LastIndexOf('{', processed.Length - 1, 3);
if (back > -1)
{
int l = processed.Length;
processed = processed.Substring(0, back);
}
}
}
else
{
mDrawStart = 0;
RestoreLabelPivot();
}
}
newLabel.text = processed;
#if !MOBILE
if (selected)
{
int start = mSelectionStart - mDrawStart;
int end = mSelectionEnd - mDrawStart;
// Blank texture used by selection and caret
if (mBlankTex == null)
{
mBlankTex = new Texture2D(2, 2, TextureFormat.ARGB32, false);
for (int y = 0; y < 2; ++y)
for (int x = 0; x < 2; ++x)
mBlankTex.SetPixel(x, y, Color.white);
mBlankTex.Apply();
}
// Create the selection highlight
if (start != end)
{
if (mHighlight == null)
{
mHighlight = NGUITools.AddWidget(newLabel.labelText.cachedGameObject);
mHighlight.name = "Input Highlight";
mHighlight.mainTexture = mBlankTex;
mHighlight.fillGeometry = false;
mHighlight.pivot = newLabel.labelText.pivot;
mHighlight.SetAnchor(newLabel.labelText.cachedTransform);
}
else
{
mHighlight.pivot = newLabel.labelText.pivot;
mHighlight.mainTexture = mBlankTex;
mHighlight.MarkAsChanged();
mHighlight.enabled = true;
}
}
// Create the caret
if (mCaret == null)
{
mCaret = NGUITools.AddWidget(newLabel.labelText.cachedGameObject);
mCaret.name = "Input Caret";
mCaret.mainTexture = mBlankTex;
mCaret.fillGeometry = false;
mCaret.pivot = newLabel.labelText.pivot;
mCaret.SetAnchor(newLabel.labelText.cachedTransform);
}
else
{
mCaret.pivot = newLabel.labelText.pivot;
mCaret.mainTexture = mBlankTex;
mCaret.MarkAsChanged();
mCaret.enabled = true;
}
if (start != end)
{
newLabel.labelText.PrintOverlay(start, end, mCaret.geometry, mHighlight.geometry, caretColor, selectionColor);
mHighlight.enabled = mHighlight.geometry.hasVertices;
}
else
{
newLabel.labelText.PrintOverlay(start, end, mCaret.geometry, null, caretColor, selectionColor);
if (mHighlight != null) mHighlight.enabled = false;
}
// Reset the blinking time
mNextBlink = RealTime.time + 0.5f;
mLastAlpha = newLabel.labelText.finalAlpha;
}
else Cleanup();
#endif
}
}
///
/// Set the label's pivot to the left.
///
protected new void SetPivotToLeft ()
{
Vector2 po = NGUIMath.GetPivotOffset(mPivot);
po.x = 0f;
newLabel.labelText.pivot = NGUIMath.GetPivot(po);
}
///
/// Set the label's pivot to the right.
///
protected new void SetPivotToRight ()
{
Vector2 po = NGUIMath.GetPivotOffset(mPivot);
po.x = 1f;
newLabel.labelText.pivot = NGUIMath.GetPivot(po);
}
///
/// Restore the input label's pivot point.
///
protected new void RestoreLabelPivot ()
{
if (newLabel != null && newLabel.labelText.pivot != mPivot)
newLabel.labelText.pivot = mPivot;
}
///
/// Validate the specified input.
///
protected new char Validate (string text, int pos, char ch)
{
// Validation is disabled
if (validation == Validation.None || !enabled) return ch;
if (validation == Validation.Integer)
{
// Integer number validation
if (ch >= '0' && ch <= '9') return ch;
if (ch == '-' && pos == 0 && !text.Contains("-")) return ch;
}
else if (validation == Validation.Float)
{
// Floating-point number
if (ch >= '0' && ch <= '9') return ch;
if (ch == '-' && pos == 0 && !text.Contains("-")) return ch;
if (ch == '.' && !text.Contains(".")) return ch;
}
else if (validation == Validation.Alphanumeric)
{
// All alphanumeric characters
if (ch >= 'A' && ch <= 'Z') return ch;
if (ch >= 'a' && ch <= 'z') return ch;
if (ch >= '0' && ch <= '9') return ch;
}
else if (validation == Validation.Username)
{
// Lowercase and numbers
if (ch >= 'A' && ch <= 'Z') return (char)(ch - 'A' + 'a');
if (ch >= 'a' && ch <= 'z') return ch;
if (ch >= '0' && ch <= '9') return ch;
}
else if (validation == Validation.Name)
{
char lastChar = (text.Length > 0) ? text[Mathf.Clamp(pos, 0, text.Length - 1)] : ' ';
char nextChar = (text.Length > 0) ? text[Mathf.Clamp(pos + 1, 0, text.Length - 1)] : '\n';
if (ch >= 'a' && ch <= 'z')
{
// Space followed by a letter -- make sure it's capitalized
if (lastChar == ' ') return (char)(ch - 'a' + 'A');
return ch;
}
else if (ch >= 'A' && ch <= 'Z')
{
// Uppercase letters are only allowed after spaces (and apostrophes)
if (lastChar != ' ' && lastChar != '\'') return (char)(ch - 'A' + 'a');
return ch;
}
else if (ch == '\'')
{
// Don't allow more than one apostrophe
if (lastChar != ' ' && lastChar != '\'' && nextChar != '\'' && !text.Contains("'")) return ch;
}
else if (ch == ' ')
{
// Don't allow more than one space in a row
if (lastChar != ' ' && lastChar != '\'' && nextChar != ' ' && nextChar != '\'') return ch;
}
}
return (char)0;
}
///
/// Execute the OnChange callback.
///
protected new void ExecuteOnChange ()
{
if (EventDelegate.IsValid(onChange))
{
current = this;
EventDelegate.Execute(onChange);
current = null;
}
}
}
//----------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2014 Tasharen Entertainment
//----------------------------------------------
#if !UNITY_3_5 && !UNITY_FLASH
#define DYNAMIC_FONT
#endif
using UnityEngine;
using System.Collections.Generic;
using System;
using Alignment = NGUIText.Alignment;
[ExecuteInEditMode]
[AddComponentMenu("NGUI/UI/NGUI Label")]
public class UILabel : UIWidget
{
public enum Effect
{
None,
Shadow,
Outline,
}
public enum Overflow
{
ShrinkContent,
ClampContent,
ResizeFreely,
ResizeHeight,
}
public enum Crispness
{
Never,
OnDesktop,
Always,
}
///
/// Whether the label will keep its content crisp even when shrunk.
/// You may want to turn this off on mobile devices.
///
public Crispness keepCrispWhenShrunk = Crispness.OnDesktop;
[HideInInspector][SerializeField] Font mTrueTypeFont;
[HideInInspector][SerializeField] UIFont mFont;
#if !UNITY_3_5
[MultilineAttribute(6)]
#endif
[HideInInspector][SerializeField] string mText = "";
[HideInInspector][SerializeField] int mFontSize = 16;
[HideInInspector][SerializeField] FontStyle mFontStyle = FontStyle.Normal;
[HideInInspector][SerializeField] Alignment mAlignment = Alignment.Automatic;
[HideInInspector][SerializeField] bool mEncoding = true;
[HideInInspector][SerializeField] int mMaxLineCount = 0; // 0 denotes unlimited
[HideInInspector][SerializeField] Effect mEffectStyle = Effect.None;
[HideInInspector][SerializeField] Color mEffectColor = Color.black;
[HideInInspector][SerializeField] NGUIText.SymbolStyle mSymbols = NGUIText.SymbolStyle.Normal;
[HideInInspector][SerializeField] Vector2 mEffectDistance = Vector2.one;
[HideInInspector][SerializeField] Overflow mOverflow = Overflow.ShrinkContent;
[HideInInspector][SerializeField] Material mMaterial;
[HideInInspector][SerializeField] bool mApplyGradient = false;
[HideInInspector][SerializeField] Color mGradientTop = Color.white;
[HideInInspector][SerializeField] Color mGradientBottom = new Color(0.7f, 0.7f, 0.7f);
[HideInInspector][SerializeField] int mSpacingX = 0;
[HideInInspector][SerializeField] int mSpacingY = 0;
// Obsolete values
[HideInInspector][SerializeField] bool mShrinkToFit = false;
[HideInInspector][SerializeField] int mMaxLineWidth = 0;
[HideInInspector][SerializeField] int mMaxLineHeight = 0;
[HideInInspector][SerializeField] float mLineWidth = 0;
[HideInInspector][SerializeField] bool mMultiline = true;
#if DYNAMIC_FONT
[System.NonSerialized]
Font mActiveTTF = null;
float mDensity = 1f;
#endif
bool mShouldBeProcessed = true;
string mProcessedText = null;
bool mPremultiply = false;
Vector2 mCalculatedSize = Vector2.zero;
float mScale = 1f;
int mPrintedSize = 0;
int mLastWidth = 0;
int mLastHeight = 0;
///
/// Function used to determine if something has changed (and thus the geometry must be rebuilt)
///
bool shouldBeProcessed
{
get
{
return mShouldBeProcessed;
}
set
{
if (value)
{
mChanged = true;
mShouldBeProcessed = true;
}
else
{
mShouldBeProcessed = false;
}
}
}
///
/// Whether the rectangle is anchored horizontally.
///
public override bool isAnchoredHorizontally { get { return base.isAnchoredHorizontally || mOverflow == Overflow.ResizeFreely; } }
///
/// Whether the rectangle is anchored vertically.
///
public override bool isAnchoredVertically
{
get
{
return base.isAnchoredVertically ||
mOverflow == Overflow.ResizeFreely ||
mOverflow == Overflow.ResizeHeight;
}
}
///
/// Retrieve the material used by the font.
///
public override Material material
{
get
{
if (mMaterial != null) return mMaterial;
if (mFont != null) return mFont.material;
if (mTrueTypeFont != null) return mTrueTypeFont.material;
return null;
}
set
{
if (mMaterial != value)
{
MarkAsChanged();
mMaterial = value;
MarkAsChanged();
}
}
}
[Obsolete("Use UILabel.bitmapFont instead")]
public UIFont font { get { return bitmapFont; } set { bitmapFont = value; } }
///
/// Set the font used by this label.
///
public UIFont bitmapFont
{
get
{
return mFont;
}
set
{
if (mFont != value)
{
RemoveFromPanel();
mFont = value;
mTrueTypeFont = null;
MarkAsChanged();
}
}
}
///
/// Set the font used by this label.
///
public Font trueTypeFont
{
get
{
if (mTrueTypeFont != null) return mTrueTypeFont;
return (mFont != null ? mFont.dynamicFont : null);
}
set
{
if (mTrueTypeFont != value)
{
#if DYNAMIC_FONT
SetActiveFont(null);
RemoveFromPanel();
mTrueTypeFont = value;
shouldBeProcessed = true;
mFont = null;
SetActiveFont(value);
ProcessAndRequest();
if (mActiveTTF != null)
base.MarkAsChanged();
#else
mTrueTypeFont = value;
mFont = null;
#endif
}
}
}
///
/// Ambiguous helper function.
///
public UnityEngine.Object ambigiousFont
{
get
{
return (mFont != null) ? (UnityEngine.Object)mFont : (UnityEngine.Object)mTrueTypeFont;
}
set
{
UIFont bf = value as UIFont;
if (bf != null) bitmapFont = bf;
else trueTypeFont = value as Font;
}
}
///
/// Text that's being displayed by the label.
///
public string text
{
get
{
return mText;
}
set
{
if (mText == value) return;
if (string.IsNullOrEmpty(value))
{
if (!string.IsNullOrEmpty(mText))
{
mText = "";
MarkAsChanged();
ProcessAndRequest();
}
}
else if (mText != value)
{
mText = value;
MarkAsChanged();
ProcessAndRequest();
}
if (autoResizeBoxCollider) ResizeCollider();
}
}
///
/// Default font size.
///
public int defaultFontSize { get { return (trueTypeFont != null) ? mFontSize : (mFont != null ? mFont.defaultSize : 16); } }
///
/// Active font size used by the label.
///
public int fontSize
{
get
{
return mFontSize;
}
set
{
value = Mathf.Clamp(value, 0, 256);
if (mFontSize != value)
{
mFontSize = value;
shouldBeProcessed = true;
ProcessAndRequest();
}
}
}
///
/// Dynamic font style used by the label.
///
public FontStyle fontStyle
{
get
{
return mFontStyle;
}
set
{
if (mFontStyle != value)
{
mFontStyle = value;
shouldBeProcessed = true;
ProcessAndRequest();
}
}
}
///
/// Text alignment option.
///
public Alignment alignment
{
get
{
return mAlignment;
}
set
{
if (mAlignment != value)
{
mAlignment = value;
shouldBeProcessed = true;
ProcessAndRequest();
}
}
}
///
/// Whether a gradient will be applied.
///
public bool applyGradient
{
get
{
return mApplyGradient;
}
set
{
if (mApplyGradient != value)
{
mApplyGradient = value;
MarkAsChanged();
}
}
}
///
/// Top gradient color.
///
public Color gradientTop
{
get
{
return mGradientTop;
}
set
{
if (mGradientTop != value)
{
mGradientTop = value;
if (mApplyGradient) MarkAsChanged();
}
}
}
///
/// Bottom gradient color.
///
public Color gradientBottom
{
get
{
return mGradientBottom;
}
set
{
if (mGradientBottom != value)
{
mGradientBottom = value;
if (mApplyGradient) MarkAsChanged();
}
}
}
///
/// Additional horizontal spacing between characters when printing text.
///
public int spacingX
{
get
{
return mSpacingX;
}
set
{
if (mSpacingX != value)
{
mSpacingX = value;
MarkAsChanged();
}
}
}
///
/// Additional vertical spacing between lines when printing text.
///
public int spacingY
{
get
{
return mSpacingY;
}
set
{
if (mSpacingY != value)
{
mSpacingY = value;
MarkAsChanged();
}
}
}
#if DYNAMIC_FONT
///
/// Whether the label will use the printed size instead of font size when printing the label.
/// It's a dynamic font feature that will ensure that the text is crisp when shrunk.
///
bool keepCrisp
{
get
{
if (trueTypeFont != null && keepCrispWhenShrunk != Crispness.Never)
{
#if UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_BLACKBERRY
return (keepCrispWhenShrunk == Crispness.Always);
#else
return true;
#endif
}
return false;
}
}
#endif
///
/// Whether this label will support color encoding in the format of [RRGGBB] and new line in the form of a "\\n" string.
///
public bool supportEncoding
{
get
{
return mEncoding;
}
set
{
if (mEncoding != value)
{
mEncoding = value;
shouldBeProcessed = true;
}
}
}
///
/// Style used for symbols.
///
public NGUIText.SymbolStyle symbolStyle
{
get
{
return mSymbols;
}
set
{
if (mSymbols != value)
{
mSymbols = value;
shouldBeProcessed = true;
}
}
}
///
/// Overflow method controls the label's behaviour when its content doesn't fit the bounds.
///
public Overflow overflowMethod
{
get
{
return mOverflow;
}
set
{
if (mOverflow != value)
{
mOverflow = value;
shouldBeProcessed = true;
}
}
}
///
/// Maximum width of the label in pixels.
///
[System.Obsolete("Use 'width' instead")]
public int lineWidth
{
get { return width; }
set { width = value; }
}
///
/// Maximum height of the label in pixels.
///
[System.Obsolete("Use 'height' instead")]
public int lineHeight
{
get { return height; }
set { height = value; }
}
///
/// Whether the label supports multiple lines.
///
public bool multiLine
{
get
{
return mMaxLineCount != 1;
}
set
{
if ((mMaxLineCount != 1) != value)
{
mMaxLineCount = (value ? 0 : 1);
shouldBeProcessed = true;
}
}
}
///
/// Process the label's text before returning its corners.
///
public override Vector3[] localCorners
{
get
{
if (shouldBeProcessed) ProcessText();
return base.localCorners;
}
}
///
/// Process the label's text before returning its corners.
///
public override Vector3[] worldCorners
{
get
{
if (shouldBeProcessed) ProcessText();
return base.worldCorners;
}
}
///
/// Process the label's text before returning its drawing dimensions.
///
public override Vector4 drawingDimensions
{
get
{
if (shouldBeProcessed) ProcessText();
return base.drawingDimensions;
}
}
///
/// The max number of lines to be displayed for the label
///
public int maxLineCount
{
get
{
return mMaxLineCount;
}
set
{
if (mMaxLineCount != value)
{
mMaxLineCount = Mathf.Max(value, 0);
shouldBeProcessed = true;
if (overflowMethod == Overflow.ShrinkContent) MakePixelPerfect();
}
}
}
///
/// What effect is used by the label.
///
public Effect effectStyle
{
get
{
return mEffectStyle;
}
set
{
if (mEffectStyle != value)
{
mEffectStyle = value;
shouldBeProcessed = true;
}
}
}
///
/// Color used by the effect, if it's enabled.
///
public Color effectColor
{
get
{
return mEffectColor;
}
set
{
if (mEffectColor != value)
{
mEffectColor = value;
if (mEffectStyle != Effect.None) shouldBeProcessed = true;
}
}
}
///
/// Effect distance in pixels.
///
public Vector2 effectDistance
{
get
{
return mEffectDistance;
}
set
{
if (mEffectDistance != value)
{
mEffectDistance = value;
shouldBeProcessed = true;
}
}
}
///
/// Whether the label will automatically shrink its size in order to fit the maximum line width.
///
[System.Obsolete("Use 'overflowMethod == UILabel.Overflow.ShrinkContent' instead")]
public bool shrinkToFit
{
get
{
return mOverflow == Overflow.ShrinkContent;
}
set
{
if (value)
{
overflowMethod = Overflow.ShrinkContent;
}
}
}
///
/// Returns the processed version of 'text', with new line characters, line wrapping, etc.
///
public string processedText
{
get
{
if (mLastWidth != mWidth || mLastHeight != mHeight)
{
mLastWidth = mWidth;
mLastHeight = mHeight;
mShouldBeProcessed = true;
}
// Process the text if necessary
if (shouldBeProcessed) ProcessText();
return mProcessedText;
}
}
///
/// Actual printed size of the text, in pixels.
///
public Vector2 printedSize
{
get
{
if (shouldBeProcessed) ProcessText();
return mCalculatedSize;
}
}
///
/// Local size of the widget, in pixels.
///
public override Vector2 localSize
{
get
{
if (shouldBeProcessed) ProcessText();
return base.localSize;
}
}
///
/// Whether the label has a valid font.
///
#if DYNAMIC_FONT
bool isValid { get { return mFont != null || mTrueTypeFont != null; } }
#else
bool isValid { get { return mFont != null; } }
#endif
#if DYNAMIC_FONT
static BetterList mList = new BetterList();
static Dictionary mFontUsage = new Dictionary();
///
/// Register the font texture change listener.
///
protected override void OnInit ()
{
base.OnInit();
mList.Add(this);
SetActiveFont(trueTypeFont);
}
///
/// Remove the font texture change listener.
///
protected override void OnDisable ()
{
SetActiveFont(null);
mList.Remove(this);
base.OnDisable();
}
///
/// Set the active font, correctly setting and clearing callbacks.
///
protected void SetActiveFont (Font fnt)
{
if (mActiveTTF != fnt)
{
if (mActiveTTF != null)
{
int usage;
if (mFontUsage.TryGetValue(mActiveTTF, out usage))
{
usage = Mathf.Max(0, --usage);
if (usage == 0)
{
mActiveTTF.textureRebuildCallback = null;
mFontUsage.Remove(mActiveTTF);
}
else mFontUsage[mActiveTTF] = usage;
}
else mActiveTTF.textureRebuildCallback = null;
}
mActiveTTF = fnt;
if (mActiveTTF != null)
{
int usage = 0;
// Font hasn't been used yet? Register a change delegate callback
if (!mFontUsage.TryGetValue(mActiveTTF, out usage))
mActiveTTF.textureRebuildCallback = OnFontTextureChanged;
mFontUsage[mActiveTTF] = ++usage;
}
}
}
///
/// Notification called when the Unity's font's texture gets rebuilt.
/// Unity's font has a nice tendency to simply discard other characters when the texture's dimensions change.
/// By requesting them inside the notification callback, we immediately force them back in.
/// Originally I was subscribing each label to the font individually, but as it turned out
/// mono's delegate system causes an insane amount of memory allocations when += or -= to a delegate.
/// So... queue yet another work-around.
///
static void OnFontTextureChanged ()
{
for (int i = 0; i < mList.size; ++i)
{
UILabel lbl = mList[i];
if (lbl != null)
{
Font fnt = lbl.trueTypeFont;
if (fnt != null)
{
fnt.RequestCharactersInTexture(lbl.mText, lbl.mPrintedSize, lbl.mFontStyle);
lbl.MarkAsChanged();
}
}
}
}
#endif
///
/// Get the sides of the rectangle relative to the specified transform.
/// The order is left, top, right, bottom.
///
public override Vector3[] GetSides (Transform relativeTo)
{
if (shouldBeProcessed) ProcessText();
return base.GetSides(relativeTo);
}
///
/// Upgrading labels is a bit different.
///
protected override void UpgradeFrom265 ()
{
ProcessText(true, true);
if (mShrinkToFit)
{
overflowMethod = Overflow.ShrinkContent;
mMaxLineCount = 0;
}
if (mMaxLineWidth != 0)
{
width = mMaxLineWidth;
overflowMethod = mMaxLineCount > 0 ? Overflow.ResizeHeight : Overflow.ShrinkContent;
}
else overflowMethod = Overflow.ResizeFreely;
if (mMaxLineHeight != 0)
height = mMaxLineHeight;
if (mFont != null)
{
int min = mFont.defaultSize;
if (height < min) height = min;
}
mMaxLineWidth = 0;
mMaxLineHeight = 0;
mShrinkToFit = false;
NGUITools.UpdateWidgetCollider(gameObject, true);
}
///
/// If the label is anchored it should not auto-resize.
///
protected override void OnAnchor ()
{
if (mOverflow == Overflow.ResizeFreely)
{
if (isFullyAnchored)
mOverflow = Overflow.ShrinkContent;
}
else if (mOverflow == Overflow.ResizeHeight)
{
if (topAnchor.target != null && bottomAnchor.target != null)
mOverflow = Overflow.ShrinkContent;
}
base.OnAnchor();
}
///
/// Request the needed characters in the texture.
///
void ProcessAndRequest ()
{
#if UNITY_EDITOR
if (!Application.isPlaying && !NGUITools.GetActive(this)) return;
if (!mAllowProcessing) return;
#endif
if (ambigiousFont != null) ProcessText();
}
#if UNITY_EDITOR
// Used to ensure that we don't process font more than once inside OnValidate function below
bool mAllowProcessing = true;
bool mUsingTTF = true;
///
/// Validate the properties.
///
protected override void OnValidate ()
{
base.OnValidate();
if (NGUITools.GetActive(this))
{
Font ttf = mTrueTypeFont;
UIFont fnt = mFont;
// If the true type font was not used before, but now it is, clear the font reference
if (!mUsingTTF && ttf != null) fnt = null;
else if (mUsingTTF && fnt != null) ttf = null;
mFont = null;
mTrueTypeFont = null;
mAllowProcessing = false;
#if DYNAMIC_FONT
SetActiveFont(null);
#endif
if (fnt != null)
{
bitmapFont = fnt;
mUsingTTF = false;
}
else if (ttf != null)
{
trueTypeFont = ttf;
mUsingTTF = true;
}
shouldBeProcessed = true;
mAllowProcessing = true;
ProcessAndRequest();
if (autoResizeBoxCollider) ResizeCollider();
}
}
#endif
///
/// Determine start-up values.
///
protected override void OnStart ()
{
base.OnStart();
// Legacy support
if (mLineWidth > 0f)
{
mMaxLineWidth = Mathf.RoundToInt(mLineWidth);
mLineWidth = 0f;
}
if (!mMultiline)
{
mMaxLineCount = 1;
mMultiline = true;
}
// Whether this is a premultiplied alpha shader
mPremultiply = (material != null && material.shader != null && material.shader.name.Contains("Premultiplied"));
#if DYNAMIC_FONT
// Request the text within the font
ProcessAndRequest();
#endif
}
///
/// UILabel needs additional processing when something changes.
///
public override void MarkAsChanged ()
{
shouldBeProcessed = true;
base.MarkAsChanged();
}
///
/// Process the raw text, called when something changes.
///
public void ProcessText () { ProcessText(false, true); }
///
/// Process the raw text, called when something changes.
///
void ProcessText (bool legacyMode, bool full)
{
if (!isValid) return;
mChanged = true;
shouldBeProcessed = false;
NGUIText.rectWidth = legacyMode ? (mMaxLineWidth != 0 ? mMaxLineWidth : 1000000) : width;
NGUIText.rectHeight = legacyMode ? (mMaxLineHeight != 0 ? mMaxLineHeight : 1000000) : height;
mPrintedSize = Mathf.Abs(legacyMode ? Mathf.RoundToInt(cachedTransform.localScale.x) : defaultFontSize);
mScale = 1f;
if (NGUIText.rectWidth < 1 || NGUIText.rectHeight < 0)
{
mProcessedText = "";
return;
}
#if DYNAMIC_FONT
bool isDynamic = (trueTypeFont != null);
if (isDynamic && keepCrisp)
{
UIRoot rt = root;
if (rt != null) mDensity = (rt != null) ? rt.pixelSizeAdjustment : 1f;
}
else mDensity = 1f;
#endif
if (full) UpdateNGUIText();
if (mOverflow == Overflow.ResizeFreely) NGUIText.rectWidth = 1000000;
if (mOverflow == Overflow.ResizeFreely || mOverflow == Overflow.ResizeHeight)
NGUIText.rectHeight = 1000000;
if (mPrintedSize > 0)
{
#if DYNAMIC_FONT
bool adjustSize = keepCrisp;
#endif
for (int ps = mPrintedSize; ps > 0; --ps)
{
#if DYNAMIC_FONT
// Adjust either the size, or the scale
if (adjustSize)
{
mPrintedSize = ps;
NGUIText.fontSize = mPrintedSize;
}
else
#endif
{
mScale = (float)ps / mPrintedSize;
#if DYNAMIC_FONT
NGUIText.fontScale = isDynamic ? mScale : ((float)mFontSize / mFont.defaultSize) * mScale;
#else
NGUIText.fontScale = ((float)mFontSize / mFont.defaultSize) * mScale;
#endif
}
NGUIText.Update(false);
// Wrap the text
bool fits = NGUIText.WrapText(mText, out mProcessedText, true);
if (mOverflow == Overflow.ShrinkContent && !fits)
{
if (--ps > 1) continue;
else break;
}
else if (mOverflow == Overflow.ResizeFreely)
{
mCalculatedSize = NGUIText.CalculatePrintedSize(mProcessedText);
mWidth = Mathf.Max(minWidth, Mathf.RoundToInt(mCalculatedSize.x));
mHeight = Mathf.Max(minHeight, Mathf.RoundToInt(mCalculatedSize.y));
if ((mWidth & 1) == 1) ++mWidth;
if ((mHeight & 1) == 1) ++mHeight;
}
else if (mOverflow == Overflow.ResizeHeight)
{
mCalculatedSize = NGUIText.CalculatePrintedSize(mProcessedText);
mHeight = Mathf.Max(minHeight, Mathf.RoundToInt(mCalculatedSize.y));
if ((mHeight & 1) == 1) ++mHeight;
}
else
{
mCalculatedSize = NGUIText.CalculatePrintedSize(mProcessedText);
}
// Upgrade to the new system
if (legacyMode)
{
width = Mathf.RoundToInt(mCalculatedSize.x);
height = Mathf.RoundToInt(mCalculatedSize.y);
cachedTransform.localScale = Vector3.one;
}
break;
}
}
else
{
cachedTransform.localScale = Vector3.one;
mProcessedText = "";
mScale = 1f;
}
if (full)
{
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
}
}
///
/// Text is pixel-perfect when its scale matches the size.
///
public override void MakePixelPerfect ()
{
if (ambigiousFont != null)
{
Vector3 pos = cachedTransform.localPosition;
pos.x = Mathf.RoundToInt(pos.x);
pos.y = Mathf.RoundToInt(pos.y);
pos.z = Mathf.RoundToInt(pos.z);
cachedTransform.localPosition = pos;
cachedTransform.localScale = Vector3.one;
if (mOverflow == Overflow.ResizeFreely)
{
AssumeNaturalSize();
}
else
{
int w = width;
int h = height;
Overflow over = mOverflow;
if (over != Overflow.ResizeHeight) mWidth = 100000;
mHeight = 100000;
mOverflow = Overflow.ShrinkContent;
ProcessText(false, true);
mOverflow = over;
int minX = Mathf.RoundToInt(mCalculatedSize.x);
int minY = Mathf.RoundToInt(mCalculatedSize.y);
minX = Mathf.Max(minX, base.minWidth);
minY = Mathf.Max(minY, base.minHeight);
mWidth = Mathf.Max(w, minX);
mHeight = Mathf.Max(h, minY);
MarkAsChanged();
}
}
else base.MakePixelPerfect();
}
///
/// Make the label assume its natural size.
///
public void AssumeNaturalSize ()
{
if (ambigiousFont != null)
{
mWidth = 100000;
mHeight = 100000;
ProcessText(false, true);
mWidth = Mathf.RoundToInt(mCalculatedSize.x);
mHeight = Mathf.RoundToInt(mCalculatedSize.y);
if ((mWidth & 1) == 1) ++mWidth;
if ((mHeight & 1) == 1) ++mHeight;
MarkAsChanged();
}
}
[System.Obsolete("Use UILabel.GetCharacterAtPosition instead")]
public int GetCharacterIndex (Vector3 worldPos) { return GetCharacterIndexAtPosition(worldPos); }
[System.Obsolete("Use UILabel.GetCharacterAtPosition instead")]
public int GetCharacterIndex (Vector2 localPos) { return GetCharacterIndexAtPosition(localPos); }
static BetterList mTempVerts = new BetterList();
static BetterList mTempIndices = new BetterList();
///
/// Return the index of the character at the specified world position.
///
public int GetCharacterIndexAtPosition (Vector3 worldPos)
{
Vector2 localPos = cachedTransform.InverseTransformPoint(worldPos);
return GetCharacterIndexAtPosition(localPos);
}
///
/// Return the index of the character at the specified local position.
///
public int GetCharacterIndexAtPosition (Vector2 localPos)
{
if (isValid)
{
string text = processedText;
if (string.IsNullOrEmpty(text)) return 0;
UpdateNGUIText();
NGUIText.PrintCharacterPositions(text, mTempVerts, mTempIndices);
if (mTempVerts.size > 0)
{
ApplyOffset(mTempVerts, 0);
int retVal = NGUIText.GetClosestCharacter(mTempVerts, localPos);
retVal = mTempIndices[retVal];
mTempVerts.Clear();
mTempIndices.Clear();
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
return retVal;
}
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
}
return 0;
}
///
/// Retrieve the word directly below the specified world-space position.
///
public string GetWordAtPosition (Vector3 worldPos) { return GetWordAtCharacterIndex(GetCharacterIndexAtPosition(worldPos)); }
///
/// Retrieve the word directly below the specified relative-to-label position.
///
public string GetWordAtPosition (Vector2 localPos) { return GetWordAtCharacterIndex(GetCharacterIndexAtPosition(localPos)); }
///
/// Retrieve the word right under the specified character index.
///
public string GetWordAtCharacterIndex (int characterIndex)
{
if (characterIndex != -1 && characterIndex < mText.Length)
{
int linkStart = mText.LastIndexOf(' ', characterIndex) + 1;
int linkEnd = mText.IndexOf(' ', characterIndex);
if (linkEnd == -1) linkEnd = mText.Length;
if (linkStart != linkEnd)
{
int len = linkEnd - linkStart;
if (len > 0)
{
string word = mText.Substring(linkStart, len);
return NGUIText.StripSymbols(word);
}
}
}
return null;
}
///
/// Retrieve the URL directly below the specified world-space position.
///
public string GetUrlAtPosition (Vector3 worldPos) { return GetUrlAtCharacterIndex(GetCharacterIndexAtPosition(worldPos)); }
///
/// Retrieve the URL directly below the specified relative-to-label position.
///
public string GetUrlAtPosition (Vector2 localPos) { return GetUrlAtCharacterIndex(GetCharacterIndexAtPosition(localPos)); }
///
/// Retrieve the URL right under the specified character index.
///
public string GetUrlAtCharacterIndex (int characterIndex)
{
if (characterIndex != -1 && characterIndex < mText.Length)
{
int linkStart = mText.LastIndexOf("[url=", characterIndex);
if (linkStart != -1)
{
linkStart += 5;
int linkEnd = mText.IndexOf("]", linkStart);
if (linkEnd != -1) return mText.Substring(linkStart, linkEnd - linkStart);
}
}
return null;
}
///
/// Get the index of the character on the line directly above or below the current index.
///
public int GetCharacterIndex (int currentIndex, KeyCode key)
{
if (isValid)
{
string text = processedText;
if (string.IsNullOrEmpty(text)) return 0;
int def = defaultFontSize;
UpdateNGUIText();
NGUIText.PrintCharacterPositions(text, mTempVerts, mTempIndices);
if (mTempVerts.size > 0)
{
ApplyOffset(mTempVerts, 0);
for (int i = 0; i < mTempIndices.size; ++i)
{
if (mTempIndices[i] == currentIndex)
{
// Determine position on the line above or below this character
Vector2 localPos = mTempVerts[i];
if (key == KeyCode.UpArrow) localPos.y += def + spacingY;
else if (key == KeyCode.DownArrow) localPos.y -= def + spacingY;
else if (key == KeyCode.Home) localPos.x -= 1000f;
else if (key == KeyCode.End) localPos.x += 1000f;
// Find the closest character to this position
int retVal = NGUIText.GetClosestCharacter(mTempVerts, localPos);
retVal = mTempIndices[retVal];
if (retVal == currentIndex) break;
mTempVerts.Clear();
mTempIndices.Clear();
return retVal;
}
}
mTempVerts.Clear();
mTempIndices.Clear();
}
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
// If the selection doesn't move, then we're at the top or bottom-most line
if (key == KeyCode.UpArrow || key == KeyCode.Home) return 0;
if (key == KeyCode.DownArrow || key == KeyCode.End) return text.Length;
}
return currentIndex;
}
///
/// Fill the specified geometry buffer with vertices that would highlight the current selection.
///
public void PrintOverlay (int start, int end, UIGeometry caret, UIGeometry highlight, Color caretColor, Color highlightColor)
{
if (caret != null) caret.Clear();
if (highlight != null) highlight.Clear();
if (!isValid) return;
string text = processedText;
UpdateNGUIText();
int startingCaretVerts = caret.verts.size;
Vector2 center = new Vector2(0.5f, 0.5f);
float alpha = finalAlpha;
// If we have a highlight to work with, fill the buffer
if (highlight != null && start != end)
{
int startingVertices = highlight.verts.size;
NGUIText.PrintCaretAndSelection(text, start, end, caret.verts, highlight.verts);
if (highlight.verts.size > startingVertices)
{
ApplyOffset(highlight.verts, startingVertices);
Color32 c = new Color(highlightColor.r, highlightColor.g, highlightColor.b, highlightColor.a * alpha);
for (int i = startingVertices; i < highlight.verts.size; ++i)
{
highlight.uvs.Add(center);
highlight.cols.Add(c);
}
}
}
else NGUIText.PrintCaretAndSelection(text, start, end, caret.verts, null);
// Fill the caret UVs and colors
ApplyOffset(caret.verts, startingCaretVerts);
Color32 cc = new Color(caretColor.r, caretColor.g, caretColor.b, caretColor.a * alpha);
for (int i = startingCaretVerts; i < caret.verts.size; ++i)
{
caret.uvs.Add(center);
caret.cols.Add(cc);
}
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
}
///
/// Draw the label.
///
public override void OnFill (BetterList verts, BetterList uvs, BetterList cols)
{
if (!isValid) return;
int offset = verts.size;
Color col = color;
col.a = finalAlpha;
if (mFont != null && mFont.premultipliedAlphaShader) col = NGUITools.ApplyPMA(col);
string text = processedText;
int start = verts.size;
UpdateNGUIText();
NGUIText.tint = col;
NGUIText.Print(text, verts, uvs, cols);
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
// Center the content within the label vertically
Vector2 pos = ApplyOffset(verts, start);
// Effects don't work with packed fonts
if (mFont != null && mFont.packedFontShader) return;
// Apply an effect if one was requested
if (effectStyle != Effect.None)
{
int end = verts.size;
pos.x = mEffectDistance.x;
pos.y = mEffectDistance.y;
ApplyShadow(verts, uvs, cols, offset, end, pos.x, -pos.y);
if (effectStyle == Effect.Outline)
{
offset = end;
end = verts.size;
ApplyShadow(verts, uvs, cols, offset, end, -pos.x, pos.y);
offset = end;
end = verts.size;
ApplyShadow(verts, uvs, cols, offset, end, pos.x, pos.y);
offset = end;
end = verts.size;
ApplyShadow(verts, uvs, cols, offset, end, -pos.x, -pos.y);
}
}
if (m_callback!=null)
{
m_callback();
}
}
//---------------------------------
private System.Action m_callback;
public void SetSymbolOffset(System.Action callback)
{
m_callback = callback;
}
//--------------------------------
///
/// Align the vertices, making the label positioned correctly based on the pivot.
/// Returns the offset that was applied.
///
protected Vector2 ApplyOffset (BetterList verts, int start)
{
Vector2 po = pivotOffset;
float fx = Mathf.Lerp(0f, -mWidth, po.x);
float fy = Mathf.Lerp(mHeight, 0f, po.y) + Mathf.Lerp((mCalculatedSize.y - mHeight), 0f, po.y);
fx = Mathf.Round(fx);
fy = Mathf.Round(fy);
#if UNITY_FLASH
for (int i = start; i < verts.size; ++i)
{
Vector3 buff = verts.buffer[i];
buff.x += fx;
buff.y += fy;
verts.buffer[i] = buff;
}
#else
for (int i = start; i < verts.size; ++i)
{
verts.buffer[i].x += fx;
verts.buffer[i].y += fy;
}
#endif
return new Vector2(fx, fy);
}
///
/// Apply a shadow effect to the buffer.
///
void ApplyShadow (BetterList verts, BetterList uvs, BetterList cols, int start, int end, float x, float y)
{
Color c = mEffectColor;
c.a *= finalAlpha;
Color32 col = (bitmapFont != null && bitmapFont.premultipliedAlphaShader) ? NGUITools.ApplyPMA(c) : c;
for (int i = start; i < end; ++i)
{
verts.Add(verts.buffer[i]);
uvs.Add(uvs.buffer[i]);
cols.Add(cols.buffer[i]);
Vector3 v = verts.buffer[i];
v.x += x;
v.y += y;
verts.buffer[i] = v;
Color32 uc = cols.buffer[i];
if (uc.a == 255)
{
cols.buffer[i] = col;
}
else
{
Color fc = c;
fc.a = (uc.a / 255f * c.a);
cols.buffer[i] = (bitmapFont != null && bitmapFont.premultipliedAlphaShader) ? NGUITools.ApplyPMA(fc) : fc;
}
}
}
///
/// Calculate the character index offset necessary in order to print the end of the specified text.
///
public int CalculateOffsetToFit (string text)
{
UpdateNGUIText();
NGUIText.encoding = false;
NGUIText.symbolStyle = NGUIText.SymbolStyle.None;
int offset = NGUIText.CalculateOffsetToFit(text);
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
return offset;
}
///
/// Convenience function, in case you wanted to associate progress bar, slider or scroll bar's
/// OnValueChanged function in inspector with a label.
///
public void SetCurrentProgress ()
{
if (UIProgressBar.current != null)
text = UIProgressBar.current.value.ToString("F");
}
///
/// Convenience function, in case you wanted to associate progress bar, slider or scroll bar's
/// OnValueChanged function in inspector with a label.
///
public void SetCurrentPercent ()
{
if (UIProgressBar.current != null)
text = Mathf.RoundToInt(UIProgressBar.current.value * 100f) + "%";
}
///
/// Convenience function, in case you wanted to automatically set some label's text
/// by selecting a value in the UIPopupList.
///
public void SetCurrentSelection ()
{
if (UIPopupList.current != null)
{
text = UIPopupList.current.isLocalized ?
Localization.Get(UIPopupList.current.value) :
UIPopupList.current.value;
}
}
///
/// Convenience function -- wrap the current text given the label's settings and unlimited height.
///
public bool Wrap (string text, out string final) { return Wrap(text, out final, 1000000); }
///
/// Convenience function -- wrap the current text given the label's settings and the given height.
///
public bool Wrap (string text, out string final, int height)
{
UpdateNGUIText();
NGUIText.rectHeight = height;
bool retVal = NGUIText.WrapText(text, out final);
NGUIText.bitmapFont = null;
#if DYNAMIC_FONT
NGUIText.dynamicFont = null;
#endif
return retVal;
}
///
/// Update NGUIText.current with all the properties from this label.
///
public void UpdateNGUIText ()
{
Font ttf = trueTypeFont;
bool isDynamic = (ttf != null);
NGUIText.fontSize = mPrintedSize;
NGUIText.fontStyle = mFontStyle;
NGUIText.rectWidth = mWidth;
NGUIText.rectHeight = mHeight;
NGUIText.gradient = mApplyGradient && (mFont == null || !mFont.packedFontShader);
NGUIText.gradientTop = mGradientTop;
NGUIText.gradientBottom = mGradientBottom;
NGUIText.encoding = mEncoding;
NGUIText.premultiply = mPremultiply;
NGUIText.symbolStyle = mSymbols;
NGUIText.maxLines = mMaxLineCount;
NGUIText.spacingX = mSpacingX;
NGUIText.spacingY = mSpacingY;
NGUIText.fontScale = isDynamic ? mScale : ((float)mFontSize / mFont.defaultSize) * mScale;
if (mFont != null)
{
NGUIText.bitmapFont = mFont;
for (; ; )
{
UIFont fnt = NGUIText.bitmapFont.replacement;
if (fnt == null) break;
NGUIText.bitmapFont = fnt;
}
#if DYNAMIC_FONT
if (NGUIText.bitmapFont.isDynamic)
{
NGUIText.dynamicFont = NGUIText.bitmapFont.dynamicFont;
NGUIText.bitmapFont = null;
}
else NGUIText.dynamicFont = null;
#endif
}
#if DYNAMIC_FONT
else
{
NGUIText.dynamicFont = ttf;
NGUIText.bitmapFont = null;
}
if (isDynamic && keepCrisp)
{
UIRoot rt = root;
if (rt != null) NGUIText.pixelDensity = (rt != null) ? rt.pixelSizeAdjustment : 1f;
}
else NGUIText.pixelDensity = 1f;
if (mDensity != NGUIText.pixelDensity)
{
ProcessText(false, false);
NGUIText.rectWidth = mWidth;
NGUIText.rectHeight = mHeight;
}
#endif
if (alignment == Alignment.Automatic)
{
Pivot p = pivot;
if (p == Pivot.Left || p == Pivot.TopLeft || p == Pivot.BottomLeft)
{
NGUIText.alignment = Alignment.Left;
}
else if (p == Pivot.Right || p == Pivot.TopRight || p == Pivot.BottomRight)
{
NGUIText.alignment = Alignment.Right;
}
else NGUIText.alignment = Alignment.Center;
}
else NGUIText.alignment = alignment;
NGUIText.Update();
}
}
通过这次的修改,对NGUI的代码的熟悉程度得到了很大的提高,对NGUI如何实现的原理也有了一定的了解,还有就是挺佩服NGUI作者的,代码写得出神入化,膜拜!膜拜!
Demo的源码:http://blog.gamerisker.com/archives/530.html