using UnityEngine.EventSystems; namespace textUtility { using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using UnityEngine; using UnityEngine.UI; [Serializable] public class RichText : Text, IPointerClickHandler { private class ParseResult { public int ExtraOffset; public string NewText; public BaseMatch Match; } #region Config private List OpenPatterns { get { if (!openPatterns.IsAvailable()) { openPatterns = new List(); openPatterns.Add(SpriteOpenPattern); openPatterns.Add(UnderlineOpenPattern); openPatterns.Add(SuperlinkOpenPattern); } return openPatterns; } } private List openPatterns; private List ClosePatterns { get { if (!closePatterns.IsAvailable()) { closePatterns = new List(); closePatterns.Add(SpriteClosePattern); closePatterns.Add(UnderlineClosePattern); closePatterns.Add(SuperlinkClosePattern); } return closePatterns; } } private List closePatterns; private Dictionary> OpenCloseParseFunctionDictionary { get { if (!openCloseParseFunctionDictionary.IsAvailable()) { openCloseParseFunctionDictionary = new Dictionary>(); openCloseParseFunctionDictionary.Add(SpriteOpenPattern, ParseSpritePattern); openCloseParseFunctionDictionary.Add(UnderlineOpenPattern, ParseUnderlinePattern); openCloseParseFunctionDictionary.Add(SuperlinkOpenPattern, ParseSuperlinkPattern); } return openCloseParseFunctionDictionary; } } private Dictionary> openCloseParseFunctionDictionary; public bool SpriteFoldout; public string SpriteOpenPattern = "<("; public string SpriteClosePattern = ")>"; public char SpriteReplaceChar = ' '; public List SpriteSettings; //todo 可能为空 private Dictionary SpriteSettingDictionary { get { if (!spriteSettingDictionary.IsAvailable()) { spriteSettingDictionary = new Dictionary(); foreach (var item in SpriteSettings) { spriteSettingDictionary.Add(item.ID, item); } } return spriteSettingDictionary; } set { spriteSettingDictionary = value; } } private Dictionary spriteSettingDictionary; private List AvailableSpriteMatches = new List(); private List TruncateSpriteMatches = new List(); public bool UnderlineFoldout; public string UnderlineOpenPattern = "<["; public string UnderlineClosePattern = "]>"; public List UnderlineSettings; //todo 可能为空 private Dictionary UnderlineSettingDictionary { get { if (!underlineSettingDictionary.IsAvailable()) { underlineSettingDictionary = new Dictionary(); foreach (var item in UnderlineSettings) { underlineSettingDictionary.Add(item.ID, item); } } return underlineSettingDictionary; } set { underlineSettingDictionary = value; } } private Dictionary underlineSettingDictionary; private List UnderlineMatches = new List(); public bool SuperlinkFoldout; public string SuperlinkOpenPattern = "<{"; public string SuperlinkClosePattern = "}>"; public List SuperlinkSettings; //todo 可能为空 public Dictionary> SuperlinkCallbackDictionary = new Dictionary>(); private Dictionary SuperlinkSettingDictionary { get { if (superlinkSettingDictionary == null) { superlinkSettingDictionary = new Dictionary(); foreach (var item in SuperlinkSettings) { superlinkSettingDictionary.Add(item.ID, item); } } return superlinkSettingDictionary; } } private Dictionary superlinkSettingDictionary; private List SuperlinkMatches = new List(); private char TransferSpaceReplaceChar = 'i'; private List TransferSpaceMatches = new List(); private List> MatchesList = new List>(); public int MinSize { get { return minSize; } set { minSize = value; ApplyVerticalBestfitSize(); } } public int minSize = 10; public int MaxSize { get { return maxSize; } set { maxSize = value; ApplyVerticalBestfitSize(); } } public int maxSize = 40; public bool VerticalBestfitFoldout; public bool UseOriginBestfit; public bool UseVerticalBestfit; public bool VerticalBestfitDirty; public bool Debug; public bool Foldout = true; public bool CalculateFlag; public string Content; public string IDPattern = "\\(\\d+\\)"; public KerningSolution KerningSolution; public RichTextImageManager ImageManager; private char CalculateReferenceChar = 'i'; private TextGenerator CalculateTextGenerator; #endregion protected override void Awake() { base.Awake(); if (Debug) { text = Content; UnityEngine.Debug.LogWarning("没有关闭Debug", gameObject); } } protected override void OnPopulateMesh(VertexHelper toFill) { if (CalculateFlag) { CalculateFlag = false; } else { string newText = Content; if (Application.isPlaying || Debug) { bool addNewOpenCloseMatch = ParseAndFillMatches(ref newText); if (addNewOpenCloseMatch) { AddNewOpenCloseMatch(newText); } CalculateFlag = addNewOpenCloseMatch; } if (UseVerticalBestfit && horizontalOverflow != HorizontalWrapMode.Overflow && verticalOverflow != VerticalWrapMode.Overflow) { if (VerticalBestfitDirty) { int verticalBestfitFontSize = GetVerticalBestfitFontSize(newText); if (fontSize != verticalBestfitFontSize) { DelayCall.Call(1, () => { fontSize = verticalBestfitFontSize; }); VerticalBestfitDirty = false; CalculateFlag = true; } } else { VerticalBestfitDirty = true; } } if (CalculateFlag) { return; } } base.OnPopulateMesh(toFill); List vertices = new List(); toFill.GetUIVertexStream(vertices); ImageManager.Vertices = vertices; HandleTransferSpaceMatch(toFill, vertices); for (int i = 0; i < vertices.Count; i += 6) { Vector3 position0 = transform.TransformPoint(vertices[0 + i].position); Vector3 position1 = transform.TransformPoint(vertices[1 + i].position); Vector3 position2 = transform.TransformPoint(vertices[2 + i].position); Vector3 position3 = transform.TransformPoint(vertices[4 + i].position); UnityEngine.Debug.DrawLine(position0, position1, Color.black, 1); UnityEngine.Debug.DrawLine(position1, position2, Color.black, 1); UnityEngine.Debug.DrawLine(position2, position3, Color.black, 1); UnityEngine.Debug.DrawLine(position3, position0, Color.black, 1); } if (KerningSolution == KerningSolution.Precalculate) { for (int i = 0; i < AvailableSpriteMatches.Count; i++) { SpriteMatch spriteMatch = (SpriteMatch)AvailableSpriteMatches[i]; int index0 = 4 + spriteMatch.StartIndex * 6; int index1 = 3 + spriteMatch.EndIndex * 6; Vector3 leftPosition = vertices[index0].position; Vector3 rightPosition = vertices[index1].position; Vector3 bottomMiddle = (leftPosition + rightPosition) / 2; Vector3 position0; Vector3 position1; Vector3 position2; Vector3 position3; spriteMatch.ScaledHeight = spriteMatch.SpriteInfo.GetScaledHeight(spriteMatch.ScaledWidth); position0 = bottomMiddle + new Vector3(-spriteMatch.ScaledWidth / 2, 0, 0); position1 = bottomMiddle + new Vector3(spriteMatch.ScaledWidth / 2, 0, 0); position2 = bottomMiddle + new Vector3(spriteMatch.ScaledWidth / 2, spriteMatch.ScaledHeight, 0); position3 = bottomMiddle + new Vector3(-spriteMatch.ScaledWidth / 2, spriteMatch.ScaledHeight, 0); position0 = transform.TransformPoint(position0); position1 = transform.TransformPoint(position1); position2 = transform.TransformPoint(position2); position3 = transform.TransformPoint(position3); spriteMatch.Positions.Add(position0); spriteMatch.Positions.Add(position1); spriteMatch.Positions.Add(position2); spriteMatch.Positions.Add(position3); } } else if (KerningSolution == KerningSolution.Shrink) { Dictionary>> dictionary = new Dictionary>>(); for (int i = 0; i < AvailableSpriteMatches.Count; i++) { SpriteMatch spriteMatch = (SpriteMatch)AvailableSpriteMatches[i]; if (dictionary.ContainsKey(spriteMatch.SpriteInfo)) { if (dictionary[spriteMatch.SpriteInfo].ContainsKey(spriteMatch.Length)) { dictionary[spriteMatch.SpriteInfo][spriteMatch.Length].Add(spriteMatch); } else { List matches = new List(); matches.Add(spriteMatch); dictionary[spriteMatch.SpriteInfo].Add(spriteMatch.Length, matches); } } else { List matches = new List(); matches.Add(spriteMatch); Dictionary> lengthDictionary = new Dictionary>(); lengthDictionary.Add(spriteMatch.Length, matches); dictionary.Add(spriteMatch.SpriteInfo, lengthDictionary); } } foreach (var lengthDictionary in dictionary) { foreach (var matches in lengthDictionary.Value.Values) { float minScaledWidth = Mathf.Infinity; for (int i = 0; i < matches.Count; i++) { float scaledWidth = matches[i].ScaledWidth; int frontIndex = matches[i].StartIndex - 1; int rearIndex = matches[i].EndIndex + 1; float frontKerning; float rearKerning; if (frontIndex < 0) { frontKerning = 0; } else { frontKerning = GetKerning(text[frontIndex], SpriteReplaceChar); } if (rearIndex >= text.Length) { rearKerning = 0; } else { rearKerning = GetKerning(SpriteReplaceChar, text[rearIndex]); } if (frontKerning < 0) { scaledWidth += frontKerning; } if (rearKerning < 0) { scaledWidth += rearKerning; } if (minScaledWidth > scaledWidth) { minScaledWidth = scaledWidth; } matches[i].FrontKerning = frontKerning; matches[i].RearKerning = rearKerning; } float minScaledHeight = lengthDictionary.Key.GetScaledHeight(minScaledWidth); for (int i = 0; i < matches.Count; i++) { matches[i].ScaledWidth = minScaledWidth; matches[i].ScaledHeight = minScaledHeight; } } } for (int i = 0; i < AvailableSpriteMatches.Count; i++) { SpriteMatch spriteMatch = (SpriteMatch)AvailableSpriteMatches[i]; int index0 = 4 + spriteMatch.StartIndex * 6; int index1 = 3 + spriteMatch.EndIndex * 6; Vector3 leftPosition = vertices[index0].position; Vector3 rightPosition = vertices[index1].position; leftPosition.x -= spriteMatch.FrontKerning; rightPosition.x += spriteMatch.RearKerning; Vector3 bottomMiddle = (leftPosition + rightPosition) / 2; Vector3 position0; Vector3 position1; Vector3 position2; Vector3 position3; position0 = bottomMiddle + new Vector3(-spriteMatch.ScaledWidth / 2, 0, 0); position1 = bottomMiddle + new Vector3(spriteMatch.ScaledWidth / 2, 0, 0); position2 = bottomMiddle + new Vector3(spriteMatch.ScaledWidth / 2, spriteMatch.ScaledHeight, 0); position3 = bottomMiddle + new Vector3(-spriteMatch.ScaledWidth / 2, spriteMatch.ScaledHeight, 0); position0 = transform.TransformPoint(position0); position1 = transform.TransformPoint(position1); position2 = transform.TransformPoint(position2); position3 = transform.TransformPoint(position3); spriteMatch.Positions.Add(position0); spriteMatch.Positions.Add(position1); spriteMatch.Positions.Add(position2); spriteMatch.Positions.Add(position3); } } for (int i = 0; i < UnderlineMatches.Count; i++) { UnderlineMatch match = UnderlineMatches[i] as UnderlineMatch; //print(match.StartIndex + " " + match.EndIndex); GetSegments(text, CalculateTextGenerator, match, match.UnderlineSetting.UnderlineExcludeChars); for (int j = 0; j < match.Segments.Count; j++) { int startCharIdx = match.Segments[j][0]; int endCharIdx = match.Segments[j][1]; //print(startCharIdx + " " + endCharIdx); int lineIndex = GetLineIndex(CalculateTextGenerator, startCharIdx); int lineEndCharacterIndex; float penPositionY = GetPenPositionY(lineIndex, CalculateTextGenerator.lineCount); float lineHeight = CalculateTextGenerator.lines[lineIndex].height; if (lineIndex != -1) { lineEndCharacterIndex = GetLineEndCharacterIndex(CalculateTextGenerator, lineIndex, text.Length); } else { break; } int newEndCharIdx = Mathf.Min(lineEndCharacterIndex, endCharIdx); List positions = new List(); Vector3 position0 = vertices[4 + startCharIdx * 6].position; Vector3 position1 = vertices[2 + newEndCharIdx * 6].position; position0.y = penPositionY; position1.y = penPositionY; Vector3 position2 = position1; Vector3 position3 = position0; float underlineHeight = lineHeight * match.UnderlineSetting.Scale; position2.y -= underlineHeight; position3.y -= underlineHeight; if (match.UnderlineSetting.Style == UnderlineStyle.Ellipse) { if (vertices[1 + endCharIdx*6].position.x - vertices[0 + startCharIdx*6].position.x > underlineHeight*2) { position0.x += underlineHeight; position1.x -= underlineHeight; position2.x -= underlineHeight; position3.x += underlineHeight; List topHemispherePositions = new List(); List bottomHemispherePositions = new List(); int cutCount = Mathf.Max(4, Mathf.CeilToInt(underlineHeight)); float radius = underlineHeight/2; for (int k = 0; k <= cutCount; k++) { float angle = 90f/cutCount*k; float radian = angle*Mathf.Deg2Rad; float x = radius * Mathf.Sin(radian); float y = radius * Mathf.Cos(radian); topHemispherePositions.Add(new Vector3(x, y, 0)); if (k != cutCount) { bottomHemispherePositions.Insert(0, new Vector3(x, -y, 0)); } } List> ellipsePositionsList = new List>(); List ellipsePositions = new List(); //右半球 ellipsePositions.Add((position1+position2)/2); foreach (var position in topHemispherePositions) { Vector3 newPosition = ellipsePositions[0] + position; ellipsePositions.Add(newPosition); } //ellipsePositions.Add(ellipsePositions[0] + new Vector3(radius, 0, 0)); foreach (var position in bottomHemispherePositions) { Vector3 newPosition = ellipsePositions[0] + position; ellipsePositions.Add(newPosition); } for (int k = 0; k < ellipsePositions.Count; k++) { ellipsePositions[k] = rectTransform.TransformPoint(ellipsePositions[k]); } ellipsePositionsList.Add(ellipsePositions); ellipsePositions = new List(); //左半球 ellipsePositions.Add((position0 + position3) / 2); foreach (var position in topHemispherePositions) { Vector3 newPosition = ellipsePositions[0]; newPosition.x -= position.x; newPosition.y += position.y; ellipsePositions.Add(newPosition); } //ellipsePositions.Add(ellipsePositions[0] + new Vector3(-radius, 0, 0)); foreach (var position in bottomHemispherePositions) { Vector3 newPosition = ellipsePositions[0]; newPosition.x -= position.x; newPosition.y += position.y; ellipsePositions.Add(newPosition); } for (int k = 0; k < ellipsePositions.Count; k++) { ellipsePositions[k] = rectTransform.TransformPoint(ellipsePositions[k]); } ellipsePositionsList.Add(ellipsePositions); match.EllipsePositionsList.Add(ellipsePositionsList); } } positions.Add(position0); positions.Add(position1); positions.Add(position2); positions.Add(position3); positions[0] = rectTransform.TransformPoint(positions[0]); positions[1] = rectTransform.TransformPoint(positions[1]); positions[2] = rectTransform.TransformPoint(positions[2]); positions[3] = rectTransform.TransformPoint(positions[3]); match.RectanglePositionsList.Add(positions); if (endCharIdx > lineEndCharacterIndex) { break; } } } //print(SuperlinkMatches.Count); for (int i = 0; i < SuperlinkMatches.Count; i++) { SuperlinkMatch match = SuperlinkMatches[i] as SuperlinkMatch; //print(match.StartIndex + " " + match.EndIndex); GetSegments(text, CalculateTextGenerator, match, match.SuperlinkSetting.SuperlinkExcludeChars); for (int j = 0; j < match.Segments.Count; j++) { int startCharIdx = match.Segments[j][0]; int endCharIdx = match.Segments[j][1]; //print(startCharIdx + " " + endCharIdx); int lineIndex = GetLineIndex(CalculateTextGenerator, startCharIdx); int lineEndCharacterIndex; float lineCenterY = GetLineCenterY(lineIndex, CalculateTextGenerator.lineCount); float lineHeight = CalculateTextGenerator.lines[lineIndex].height; if (lineIndex != -1) { lineEndCharacterIndex = GetLineEndCharacterIndex(CalculateTextGenerator, lineIndex, text.Length); } else { break; } int newEndCharIdx = Mathf.Min(lineEndCharacterIndex, endCharIdx); List positions = new List(); float lineMaxY = lineCenterY + (lineHeight / 2) * match.SuperlinkSetting.Scale; float lineMinY = lineCenterY - (lineHeight / 2) * match.SuperlinkSetting.Scale; Vector3 position0 = vertices[4 + startCharIdx * 6].position; Vector3 position1 = vertices[2 + newEndCharIdx * 6].position; Vector3 position2 = position1; Vector3 position3 = position0; position0.y = lineMaxY; position1.y = lineMaxY; position2.y = lineMinY; position3.y = lineMinY; positions.Add(position0); positions.Add(position1); positions.Add(position2); positions.Add(position3); positions[0] = rectTransform.TransformPoint(positions[0]); positions[1] = rectTransform.TransformPoint(positions[1]); positions[2] = rectTransform.TransformPoint(positions[2]); positions[3] = rectTransform.TransformPoint(positions[3]); match.RectanglePositionsList.Add(positions); if (endCharIdx > lineEndCharacterIndex) { break; } } } for (int i = 0; i < AvailableSpriteMatches.Count; i++) { SpriteMatch match = (SpriteMatch)AvailableSpriteMatches[i]; Vector3 position0 = match.Positions[0]; Vector3 position1 = match.Positions[1]; Vector3 position2 = match.Positions[2]; Vector3 position3 = match.Positions[3]; UnityEngine.Debug.DrawLine(position0, position1, Color.red, 1); UnityEngine.Debug.DrawLine(position1, position2, Color.red, 1); UnityEngine.Debug.DrawLine(position2, position3, Color.red, 1); UnityEngine.Debug.DrawLine(position3, position0, Color.red, 1); } for (int i = 0; i < UnderlineMatches.Count; i++) { UnderlineMatch match = (UnderlineMatch)UnderlineMatches[i]; for (int j = 0; j < match.RectanglePositionsList.Count; j++) { Vector3 position0 = match.RectanglePositionsList[j][0]; Vector3 position1 = match.RectanglePositionsList[j][1]; Vector3 position2 = match.RectanglePositionsList[j][2]; Vector3 position3 = match.RectanglePositionsList[j][3]; UnityEngine.Debug.DrawLine(position0, position1, Color.blue, 1); UnityEngine.Debug.DrawLine(position1, position2, Color.blue, 1); UnityEngine.Debug.DrawLine(position2, position3, Color.blue, 1); UnityEngine.Debug.DrawLine(position3, position0, Color.blue, 1); } for (int j = 0; j < match.EllipsePositionsList.Count; j++) { for (int k = 0; k < match.EllipsePositionsList[j].Count; k++) { for (int l = 1; l < match.EllipsePositionsList[j][k].Count - 1; l++) { Vector3 position0 = match.EllipsePositionsList[j][k][0]; Vector3 position1 = match.EllipsePositionsList[j][k][l + 0]; Vector3 position2 = match.EllipsePositionsList[j][k][l + 1]; UnityEngine.Debug.DrawLine(position0, position1, Color.blue, 1); UnityEngine.Debug.DrawLine(position1, position2, Color.blue, 1); UnityEngine.Debug.DrawLine(position2, position0, Color.blue, 1); } } } } for (int i = 0; i < SuperlinkMatches.Count; i++) { SuperlinkMatch match = (SuperlinkMatch)SuperlinkMatches[i]; for (int j = 0; j < match.RectanglePositionsList.Count; j++) { Vector3 position0 = match.RectanglePositionsList[j][0]; Vector3 position1 = match.RectanglePositionsList[j][1]; Vector3 position2 = match.RectanglePositionsList[j][2]; Vector3 position3 = match.RectanglePositionsList[j][3]; UnityEngine.Debug.DrawLine(position0, position1, Color.green, 1); UnityEngine.Debug.DrawLine(position1, position2, Color.green, 1); UnityEngine.Debug.DrawLine(position2, position3, Color.green, 1); UnityEngine.Debug.DrawLine(position3, position0, Color.green, 1); } } } public void SetContent(string content) { Content = content; text = content; } public void ClearMatches() { AvailableSpriteMatches = new List(); TruncateSpriteMatches = new List(); UnderlineMatches = new List(); SuperlinkMatches = new List(); TransferSpaceMatches = new List(); MatchesList = new List>(); SuperlinkCallbackDictionary = new Dictionary>(); } private bool ParseMatches(ref string newText) { bool haveMatch = false; AvailableSpriteMatches = new List(); UnderlineMatches = new List(); SuperlinkMatches = new List(); TransferSpaceMatches = new List(); MatchesList = new List> { AvailableSpriteMatches, UnderlineMatches, SuperlinkMatches, TransferSpaceMatches, }; newText = ParseTransferSpaceMatches(newText); newText = ParseOpenCloseMatches(newText); if (TransferSpaceMatches.Count > 0) { haveMatch = true; } if (AvailableSpriteMatches.Count > 0) { haveMatch = true; } if (UnderlineMatches.Count > 0) { haveMatch = true; } if (SuperlinkMatches.Count > 0) { haveMatch = true; } return haveMatch; } private string ParseTransferSpaceMatches(string newText) { string pattern = "\\\\ "; Match match = Regex.Match(newText, pattern); while (match.Success) { MatchData matchData = new MatchData(); matchData.OpenPatternIndex = match.Index; matchData.MatchLength = match.Length; TransferSpaceMatch transferSpaceMatch = new TransferSpaceMatch(); transferSpaceMatch.StartIndex = matchData.OpenPatternIndex; transferSpaceMatch.EndIndex = matchData.OpenPatternIndex; TransferSpaceMatches.Add(transferSpaceMatch); newText = newText.Replace(match.Index, match.Length, TransferSpaceReplaceChar.ToString()); match = Regex.Match(newText, pattern); } return newText; } private string ParseOpenCloseMatches(string newText) { if (OpenPatterns.Count == 0 || ClosePatterns.Count == 0) { return newText; } if (OpenPatterns.Count != ClosePatterns.Count) { return newText; } List transferedOpenPatterns = new List(); foreach (var openPattern in OpenPatterns) { transferedOpenPatterns.Add(openPattern.GetTransferedPattern()); } List transferedClosePatterns = new List(); foreach (var closePattern in ClosePatterns) { transferedClosePatterns.Add(closePattern.GetTransferedPattern()); } string orOpenPattern = transferedOpenPatterns.ToOrPattern(); string orClosePattern = transferedClosePatterns.ToOrPattern(); string regexPattern = string.Format("{0}.+{1}", orOpenPattern, orClosePattern); Match match = Regex.Match(newText, regexPattern, RegexOptions.Singleline); while (match.Success) { Dictionary openPatternIndexDictionary = new Dictionary(); Dictionary closePatternIndexDictionary = new Dictionary(); for (int i = 0; i < OpenPatterns.Count; i++) { int index = match.Value.LastIndexOf(OpenPatterns[i]); if (index == -1) continue; else openPatternIndexDictionary.Add(OpenPatterns[i], index); } for (int i = 0; i < ClosePatterns.Count; i++) { string closeRegexPattern = ClosePatterns[i].GetTransferedPattern(); Match closePatternMatch = Regex.Match(match.Value, closeRegexPattern); while (closePatternMatch.Success) { if (openPatternIndexDictionary[OpenPatterns[i]] > closePatternMatch.Index) { closePatternMatch = closePatternMatch.NextMatch(); } else { closePatternIndexDictionary.Add(ClosePatterns[i], closePatternMatch.Index); break; } } } int[] openPatternIndexLength = new int[2]; int[] closePatternIndexLength = new int[2]; int dictionaryIndex = openPatternIndexDictionary.MyMax((pattern, index) => index); KVPair pair = openPatternIndexDictionary.GetAtIndex(dictionaryIndex); openPatternIndexLength[0] = pair.value; openPatternIndexLength[1] = pair.key.Length; pair = closePatternIndexDictionary.GetAtIndex(dictionaryIndex); closePatternIndexLength[0] = pair.value; closePatternIndexLength[1] = pair.key.Length; int openPatternIndex = openPatternIndexLength[0]; int openPatternLength = openPatternIndexLength[1]; int closePatternIndex = closePatternIndexLength[0]; int closePatternLength = closePatternIndexLength[1]; int contentIndex = openPatternIndex + openPatternLength; int contentLength = closePatternIndex - contentIndex; int matchLength = closePatternIndex + closePatternLength - openPatternIndex; string matchValue = match.Value.Substring(openPatternIndex, matchLength); string openPattern = match.Value.Substring(openPatternIndex, openPatternLength); string closePattern = match.Value.Substring(closePatternIndex, closePatternLength); MatchData matchData = new MatchData(); matchData.OpenPatternIndex = openPatternIndex + match.Index; matchData.OpenPatternLength = openPatternLength; matchData.ClosePatternIndex = closePatternIndex + match.Index; matchData.ClosePatternLength = closePatternLength; matchData.ContentIndex = contentIndex + match.Index; matchData.ContentLength = contentLength; matchData.MatchLength = matchLength; matchData.MatchValue = matchValue; matchData.OpenPattern = openPattern; matchData.ClosePattern = closePattern; ParseResult parseResult = OpenCloseParseFunctionDictionary[openPattern].Invoke(newText, matchData); for (int i = 0; i < OpenPatterns.Count; i++) { if (matchData.OpenPattern != OpenPatterns[i]) continue; MatchesList[i].Add(parseResult.Match); for (int j = 0; j < MatchesList.Count; j++) { AdjustIndicesByMatch(parseResult.ExtraOffset, parseResult.Match, MatchesList[j]); } } newText = parseResult.NewText; match = Regex.Match(newText, regexPattern); } return newText; } private ParseResult ParseSpritePattern(string newText, MatchData matchData) { int id = 0; string name; string content = newText.Substring(matchData.ContentIndex, matchData.ContentLength); Match idMatch = Regex.Match(content, IDPattern); if (idMatch.Success) { Match match = Regex.Match(idMatch.Value, "\\d+"); id = int.Parse(match.Value); name = content.Replace(idMatch.Index, idMatch.Length, ""); } else { name = content; } newText = newText.Replace(matchData.OpenPatternIndex, matchData.MatchLength, SpriteReplaceChar.ToString()); SpriteMatch spriteMatch = new SpriteMatch(); spriteMatch.ID = id; spriteMatch.Name = name; spriteMatch.SpriteSetting = SpriteSettingDictionary[id]; spriteMatch.MatchData = matchData; spriteMatch.StartIndex = matchData.OpenPatternIndex; spriteMatch.EndIndex = matchData.OpenPatternIndex; ParseResult parseResult = new ParseResult(); parseResult.Match = spriteMatch; parseResult.ExtraOffset = -matchData.ContentLength + 1; parseResult.NewText = newText; return parseResult; } private ParseResult ParseUnderlinePattern(string newText, MatchData matchData) { newText = newText.Replace(matchData.ClosePatternIndex, matchData.ClosePatternLength, ""); int id = 0; int extraOffset = 0; string content = newText.Substring(matchData.ContentIndex, matchData.ContentLength); Match idMatch = Regex.Match(content, IDPattern); if (idMatch.Success) { Match match = Regex.Match(idMatch.Value, "\\d+"); id = int.Parse(match.Value); extraOffset = idMatch.Length; newText = newText.Replace(matchData.ContentIndex + idMatch.Index, idMatch.Length, ""); } newText = newText.Replace(matchData.OpenPatternIndex, matchData.OpenPatternLength, ""); UnderlineMatch underlineMatch = new UnderlineMatch(); underlineMatch.ID = id; underlineMatch.UnderlineSetting = UnderlineSettingDictionary[id]; underlineMatch.MatchData = matchData; underlineMatch.StartIndex = matchData.OpenPatternIndex; underlineMatch.EndIndex = matchData.OpenPatternIndex + matchData.MatchLength - matchData.OpenPatternLength - matchData.ClosePatternLength - 1 - extraOffset; //print(newText); //print(underlineMatch.StartIndex + " " + underlineMatch.EndIndex); ParseResult parseResult = new ParseResult(); parseResult.Match = underlineMatch; parseResult.ExtraOffset = extraOffset; parseResult.NewText = newText; return parseResult; } private ParseResult ParseSuperlinkPattern(string newText, MatchData matchData) { newText = newText.Replace(matchData.ClosePatternIndex, matchData.ClosePatternLength, ""); int id = 0; int extraOffset = 0; string content = newText.Substring(matchData.ContentIndex, matchData.ContentLength); Match idMatch = Regex.Match(content, IDPattern); if (idMatch.Success) { Match match = Regex.Match(idMatch.Value, "\\d+"); id = int.Parse(match.Value); extraOffset = idMatch.Length; newText = newText.Replace(matchData.ContentIndex + idMatch.Index, idMatch.Length, ""); } newText = newText.Replace(matchData.OpenPatternIndex, matchData.OpenPatternLength, ""); SuperlinkMatch superlinkMatch = new SuperlinkMatch(); superlinkMatch.ID = id; superlinkMatch.SuperlinkSetting = SuperlinkSettingDictionary[id]; superlinkMatch.MatchData = matchData; superlinkMatch.StartIndex = matchData.OpenPatternIndex; superlinkMatch.EndIndex = matchData.OpenPatternIndex + matchData.MatchLength - matchData.OpenPatternLength - matchData.ClosePatternLength - 1 - extraOffset; ParseResult parseResult = new ParseResult(); parseResult.Match = superlinkMatch; parseResult.ExtraOffset = extraOffset; parseResult.NewText = newText; return parseResult; } private void AddNewOpenCloseMatch(string newText) { DelayCall.Call ( 1, () => { text = newText; //ImageManager.Init(this); //ImageManager.ClearRenderTask(); //ImageManager.RenderSprites(SpriteMatches); //ImageManager.RenderUnderlines(UnderlineMatches); //ImageManager.RenderSuperlinks(SuperlinkMatches); } ); } private void FillSpriteMatches(List spriteMatches, List truncateSpriteMatches, ref string newText/*, bool fillTruncate*/) { spriteMatches.MySort((match0, match1) => match1.StartIndex < match0.StartIndex); float replaceCharWidth = GetCharacterWidth(SpriteReplaceChar); //bool isTextChanged = false; //if (!fillTruncate) //{ /*isTextChanged = */ReplaceAllSpriteMatch(spriteMatches, replaceCharWidth, ref newText); //} if (horizontalOverflow == HorizontalWrapMode.Overflow) { return; } /*isTextChanged = isTextChanged | */CalculateSpriteMatchPosition(spriteMatches, truncateSpriteMatches, replaceCharWidth, ref newText); //return isTextChanged; } private void ReplaceAllSpriteMatch(List spriteMatches, float replaceCharWidth, ref string newText) { foreach (var match in spriteMatches) { SpriteMatch spriteMatch = match as SpriteMatch; SpriteInfo spriteInfo = SpriteInfoManager.GetSpriteInfo(spriteMatch.Name); float scaledWidth = replaceCharWidth * 2 * spriteMatch.SpriteSetting.Scale; float minReplaceWidth = scaledWidth; if (KerningSolution == KerningSolution.Precalculate) { int frontIndex = spriteMatch.StartIndex - 1; int rearIndex = spriteMatch.EndIndex + 1; float frontKerning; float rearKerning; if (frontIndex < 0) { frontKerning = 0; } else { frontKerning = GetKerning(text[frontIndex], SpriteReplaceChar); } if (rearIndex >= text.Length) { rearKerning = 0; } else { rearKerning = GetKerning(SpriteReplaceChar, text[rearIndex]); } if (frontKerning < 0) { minReplaceWidth -= frontKerning; } if (rearKerning < 0) { minReplaceWidth -= rearKerning; } spriteMatch.FrontKerning = frontKerning; spriteMatch.RearKerning = rearKerning; } int replaceCharCount = Mathf.CeilToInt(minReplaceWidth / replaceCharWidth); for (int j = 0; j < MatchesList.Count; j++) { AdjustIndicesByIndex(replaceCharCount - 1, spriteMatch, MatchesList[j]); } StringBuilder stringBuilder = new StringBuilder(); for (int j = 0; j < replaceCharCount; j++) { stringBuilder.Append(SpriteReplaceChar); } newText = newText.Replace(spriteMatch.StartIndex, spriteMatch.Length, stringBuilder.ToString()); spriteMatch.SpriteInfo = spriteInfo; spriteMatch.ReplaceWidth = replaceCharCount*replaceCharWidth; spriteMatch.ScaledWidth = scaledWidth; spriteMatch.EndIndex += replaceCharCount - 1; } } private void CalculateSpriteMatchPosition(List spriteMatches, List stashSpriteMatches, float replaceCharWidth, ref string newText/*, bool fillTruncate*/) { float changeLineAccuracy = replaceCharWidth/5; //bool isTextChanged = false; TextGenerationSettings settings = GetGenerationSettings(rectTransform.rect.size); settings.textAnchor = alignment; CalculateTextGenerator = new TextGenerator(); CalculateTextGenerator.Populate(newText, settings); AdjustVerts(CalculateTextGenerator.verts); //if (IsSpritesOutOfBound(spriteMatches)) //{ // UnityEngine.Debug.LogWarning("文本框过小"); // if (!fillTruncate) // { // StashSpriteMatch(0, spriteMatches, stashSpriteMatches); // } // return false; //} for (int i = 0; i < spriteMatches.Count; i++) { SpriteMatch spriteMatch = spriteMatches[i] as SpriteMatch; //print(CalculateTextGenerator.lineCount); int lineIndex = GetLineIndex(CalculateTextGenerator, spriteMatch.StartIndex); int lineStartCharacterIndex; int lineEndCharacterIndex; if (lineIndex != -1) { lineStartCharacterIndex = CalculateTextGenerator.lines[lineIndex].startCharIdx; lineEndCharacterIndex = GetLineEndCharacterIndex(CalculateTextGenerator, lineIndex, newText.Length); } else { lineStartCharacterIndex = -1; lineEndCharacterIndex = -1; } //int lineCharacterCount = lineEndCharacterIndex - lineStartCharacterIndex; //print(spriteMatch.EndIndex); //print(lineEndCharacterIndex); if (spriteMatch.EndIndex > lineEndCharacterIndex) //被Truncate { //if (!fillTruncate) //{ StashSpriteMatch(i, spriteMatches, stashSpriteMatches); //} break; } List matches = GetMatchesInLine(spriteMatches, CalculateTextGenerator, lineIndex, lineEndCharacterIndex); if (matches.Count == 1) { continue; } else if (matches.Count > 1) { bool changeLine = false; if (spriteMatch.ReplaceWidth > rectTransform.rect.width) //图片太大 需要换行 { if (i < spriteMatches.Count - 1) { i++; spriteMatch = spriteMatches[i] as SpriteMatch; changeLine = true; //isTextChanged = true; } } else { float leftMargin = rectTransform.rect.xMin - CalculateTextGenerator.verts[0 + lineStartCharacterIndex * 4].position.x; float rightMargin = CalculateTextGenerator.verts[1 + lineEndCharacterIndex * 4].position.x - rectTransform.rect.xMax; float horizontalMargin = CalculateTextGenerator.verts[1 + lineEndCharacterIndex * 4].position.x - CalculateTextGenerator.verts[0 + lineStartCharacterIndex * 4].position.x - rectTransform.rect.width; if (alignment == TextAnchor.LowerLeft || alignment == TextAnchor.MiddleLeft || alignment == TextAnchor.UpperLeft) { if (leftMargin <= 0 && rightMargin > changeLineAccuracy) { //向右突出 matches.MySort((match0, match1) => match1.StartIndex > match0.StartIndex); float margin = horizontalMargin; spriteMatch = GetMarginSpriteMatch(matches, margin, replaceCharWidth) as SpriteMatch; i = spriteMatches.IndexOf(spriteMatch); changeLine = true; //isTextChanged = true; } } else if (alignment == TextAnchor.LowerCenter || alignment == TextAnchor.MiddleCenter || alignment == TextAnchor.UpperCenter) { if (leftMargin > changeLineAccuracy && rightMargin > changeLineAccuracy) { //左右同时突出 matches.MySort((match0, match1) => match1.StartIndex > match0.StartIndex); float margin = leftMargin + rightMargin; spriteMatch = GetMarginSpriteMatch(matches, margin, replaceCharWidth) as SpriteMatch; i = spriteMatches.IndexOf(spriteMatch); changeLine = true; //isTextChanged = true; } else if (leftMargin <= 0 && rightMargin > changeLineAccuracy) { //向右突出 matches.MySort((match0, match1) => match1.StartIndex > match0.StartIndex); float margin = horizontalMargin; spriteMatch = GetMarginSpriteMatch(matches, margin, replaceCharWidth) as SpriteMatch; i = spriteMatches.IndexOf(spriteMatch); changeLine = true; //isTextChanged = true; } } else if (alignment == TextAnchor.LowerRight || alignment == TextAnchor.MiddleRight || alignment == TextAnchor.UpperRight) { if (leftMargin > changeLineAccuracy && rightMargin <= 0) { //向左突出 matches.MySort((match0, match1) => match1.StartIndex > match0.StartIndex); float margin = leftMargin; spriteMatch = GetMarginSpriteMatch(matches, margin, replaceCharWidth) as SpriteMatch; i = spriteMatches.IndexOf(spriteMatch); changeLine = true; //isTextChanged = true; } else if (leftMargin <= 0 && rightMargin > changeLineAccuracy) { //向右突出 matches.MySort((match0, match1) => match1.StartIndex > match0.StartIndex); float margin = horizontalMargin; spriteMatch = GetMarginSpriteMatch(matches, margin, replaceCharWidth) as SpriteMatch; i = spriteMatches.IndexOf(spriteMatch); changeLine = true; //isTextChanged = true; } } } if (changeLine) { lineIndex++; if (lineIndex < GetMaxLineCount()) //换行后不被Truncate { newText = newText.Insert(spriteMatch.StartIndex, "\n"); for (int j = 0; j < MatchesList.Count; j++) { AdjustIndicesByIndex(1, spriteMatch, MatchesList[j]); } spriteMatch.StartIndex += 1; spriteMatch.EndIndex += 1; CalculateTextGenerator = new TextGenerator(); CalculateTextGenerator.Populate(newText, settings); AdjustVerts(CalculateTextGenerator.verts); } } } //if (fillTruncate) //{ // stashSpriteMatches.Add(spriteMatch); // spriteMatches.Remove(spriteMatch); //} } //return isTextChanged; } //private bool IsSpritesOutOfBound(List spriteMatches) //{ // for (int i = 0; i < spriteMatches.Count; i++) // { // SpriteMatch spriteMatch = spriteMatches[i] as SpriteMatch; // if (spriteMatch.ReplaceWidth > rectTransform.rect.width) // { // return true; // } // } // return false; //} private void StashSpriteMatch(int startIndex, List spriteMatches, List stashSpriteMatches) { for (int i = startIndex; i < spriteMatches.Count; i++) { stashSpriteMatches.Add(spriteMatches[i]); spriteMatches.Remove(spriteMatches[i]); i--; } } private List GetMatchesInLine(List matches, TextGenerator textGenerator, int lineIndex, int endCharacterIndex) { List result = new List(); foreach (var match in matches) { if (match.StartIndex > endCharacterIndex) { continue; } int matchLineIndex = GetLineIndex(textGenerator, match.StartIndex); if (matchLineIndex == lineIndex) { result.Add(match); } } return result; } private BaseMatch GetMarginSpriteMatch(List matches, float margin, float replaceCharWidth) { foreach (var match in matches) { margin -= replaceCharWidth * match.Length; if (margin <= 0) { return match; } } throw new Exception(); } //private bool IsCharacterTruncated(TextGenerator textGenerator, int characterIndex) //{ // print(textGenerator.characterCount - 1); // print(characterIndex + 1); // if (textGenerator.characterCount - 1 < characterIndex + 1) // { // return true; // } // else // { // return false; // } //} private void HandleTransferSpaceMatch(VertexHelper toFill, List vertices) { foreach (var transferSpaceMatch in TransferSpaceMatches) { int index0 = 0 + transferSpaceMatch.StartIndex * 4; int index1 = 1 + transferSpaceMatch.EndIndex * 4; int index2 = 2 + transferSpaceMatch.EndIndex * 4; int index3 = 3 + transferSpaceMatch.StartIndex * 4; UIVertex vertex0 = vertices[index0]; UIVertex vertex1 = vertices[index1]; UIVertex vertex2 = vertices[index2]; UIVertex vertex3 = vertices[index3]; vertex0.color = new Color32(0, 0, 0, 0); vertex1.color = new Color32(0, 0, 0, 0); vertex2.color = new Color32(0, 0, 0, 0); vertex3.color = new Color32(0, 0, 0, 0); vertices[index0] = vertex0; vertices[index1] = vertex1; vertices[index2] = vertex2; vertices[index3] = vertex3; toFill.SetUIVertex(vertex0, index0); toFill.SetUIVertex(vertex1, index1); toFill.SetUIVertex(vertex2, index2); toFill.SetUIVertex(vertex3, index3); } } public string GetUnparsedText() { List matches = new List(); matches.AddRange(TransferSpaceMatches); matches.AddRange(AvailableSpriteMatches); matches.AddRange(UnderlineMatches); matches.AddRange(SuperlinkMatches); matches.MySort((match0, match1) => match1.StartIndex > match0.StartIndex); string result = text; foreach (var baseMatch in matches) { if (baseMatch is TransferSpaceMatch) { result = result.Insert(baseMatch.StartIndex, "\\"); } else { string openPattern = baseMatch.MatchData.OpenPattern; string idPattern = IDPattern.Replace("\\d+", baseMatch.ID.ToString()); idPattern = idPattern.Replace("\\", ""); string closePattern = baseMatch.MatchData.ClosePattern; result = result.Insert(baseMatch.StartIndex + baseMatch.EndIndex, idPattern + closePattern); result = result.Insert(baseMatch.StartIndex, openPattern); } } return result; } private Vector3[] GetLocalCorners() { Vector3[] corners = new Vector3[4]; rectTransform.GetLocalCorners(corners); return corners; } private Vector3[] GetWorldCorners() { Vector3[] corners = new Vector3[4]; rectTransform.GetWorldCorners(corners); return corners; } private float GetKerning(char c0, char c1) { TextGenerator textGenerator = new TextGenerator(0); textGenerator.Populate(string.Format("{0}{1}", c0, c1), GetGenerationSettings(rectTransform.rect.size)); //AdjustVerts(textGenerator.verts); float kerning = textGenerator.verts[4].position.x - textGenerator.verts[1].position.x; kerning /= canvas.scaleFactor; return kerning; //return textGenerator.verts[4].position.x - textGenerator.verts[1].position.x; } private float GetCharacterHeight(char c) { TextGenerator textGenerator = new TextGenerator(0); textGenerator.Populate(c.ToString(), GetGenerationSettings(rectTransform.rect.size)); //AdjustVerts(textGenerator.verts); float height = textGenerator.verts[0].position.y - textGenerator.verts[2].position.y; height /= canvas.scaleFactor; return height; //return textGenerator.verts[0].position.y - textGenerator.verts[2].position.y; } private float GetCharacterWidth(char c) { TextGenerator textGenerator = new TextGenerator(0); textGenerator.Populate(c.ToString(), GetGenerationSettings(rectTransform.rect.size)); //AdjustVerts(textGenerator.verts); float width = textGenerator.verts[1].position.x - textGenerator.verts[0].position.x; width /= canvas.scaleFactor; return width; //return textGenerator.verts[1].position.x - textGenerator.verts[0].position.x; } public float GetPenPositionY(int lineIndex, int lineCount) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < lineCount; i++) { stringBuilder.Append(CalculateReferenceChar); if (i < lineCount - 1) { stringBuilder.Append("\n"); } } TextGenerator textGenerator = new TextGenerator(); textGenerator.Populate(stringBuilder.ToString(), GetGenerationSettings(rectTransform.rect.size)); AdjustVerts(textGenerator.verts); return textGenerator.verts[2 + lineIndex*8].position.y; } public float GetLineCenterY(int lineIndex, int lineCount) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < lineCount; i++) { stringBuilder.Append(CalculateReferenceChar); if (i < lineCount - 1) { stringBuilder.Append("\n"); } } TextGenerator textGenerator = new TextGenerator(); textGenerator.Populate(stringBuilder.ToString(), GetGenerationSettings(rectTransform.rect.size)); AdjustVerts(textGenerator.verts); return (textGenerator.verts[0 + lineIndex*8].position.y + textGenerator.verts[2 + lineIndex*8].position.y)/2; } public int GetLineIndex(TextGenerator textGenerator, int charIndex) { for (int i = 0; i < textGenerator.lines.Count; i++) { if (charIndex >= textGenerator.lines.Back(i).startCharIdx) { return textGenerator.lines.Count - 1 - i; } } return -1; } public int GetMaxLineCount() { TextGenerationSettings settings = GetGenerationSettings(rectTransform.rect.size); settings.textAnchor = alignment; CalculateTextGenerator = new TextGenerator(); int lineCount = 0; StringBuilder stringBuilder = new StringBuilder(); while (CalculateTextGenerator.GetPreferredHeight(stringBuilder.ToString(), settings) / canvas.scaleFactor < rectTransform.rect.height) { lineCount++; stringBuilder.Append("\n"); } return lineCount; } public int GetLineEndCharacterIndex(TextGenerator textGenerator, int lineIndex, int realCharacterCount) { if (lineIndex >= textGenerator.lines.Count) { throw new Exception(); } if (textGenerator.lines.Count == 1 || lineIndex == textGenerator.lines.Count - 1) { if (textGenerator.characterCount - 1 == realCharacterCount) //TextGenerator会自动在结尾添加换行符 { return realCharacterCount - 1; } else { return textGenerator.characterCount - 1; } } else { return textGenerator.lines[lineIndex + 1].startCharIdx - 1; } } public int GetLineCharacterCount(TextGenerator textGenerator, int lineIndex) { if (lineIndex >= textGenerator.lines.Count) { throw new Exception(); } if (textGenerator.lines.Count == 1) { return textGenerator.characterCount; } if (lineIndex == textGenerator.lines.Count - 1) { return textGenerator.characterCount - textGenerator.lines.Back(0).startCharIdx; } else { return textGenerator.lines[lineIndex + 1].startCharIdx - textGenerator.lines[lineIndex].startCharIdx; } } public float GetLineMaxY(TextGenerator textGenerator, int lineIndex) { float lineCenterY = GetLineCenterY(lineIndex, textGenerator.lineCount); float lineHeight = textGenerator.lines[lineIndex].height; return lineCenterY + lineHeight/2; } public float GetLineMinY(TextGenerator textGenerator, int lineIndex) { float lineCenterY = GetLineCenterY(lineIndex, textGenerator.lineCount); float lineHeight = textGenerator.lines[lineIndex].height; return lineCenterY - lineHeight/2; } public float GetLineTopY(TextGenerator textGenerator, int lineIndex) { return textGenerator.lines[lineIndex].topY; } public float GetLineBottomY(TextGenerator textGenerator, int lineIndex) { return textGenerator.lines[lineIndex].topY - textGenerator.lines[lineIndex].height; } public bool IsSameLine(TextGenerator textGenerator, int charIndex0, int charIndex1) { if (textGenerator.lines.Count == 1) { return true; } else { for (int i = 0; i < textGenerator.lines.Count - 1; i++) { if ((charIndex0 >= textGenerator.lines[i].startCharIdx && charIndex0 < textGenerator.lines[i + 1].startCharIdx) && charIndex1 >= textGenerator.lines[i + 1].startCharIdx) { return false; } } return true; } } private void AdjustVerts(IList verts) //取自UGUI源代码 { float unitsPerPixel = 1/pixelsPerUnit; int vertCount = verts.Count - 4; Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y)*unitsPerPixel; roundingOffset = PixelAdjustPoint(roundingOffset) - roundingOffset; if (roundingOffset != Vector2.zero) { for (int i = 0; i < vertCount; ++i) { UIVertex vertex = verts[i]; vertex.position *= unitsPerPixel; vertex.position.x += roundingOffset.x; vertex.position.y += roundingOffset.y; verts[i] = vertex; } } else { for (int i = 0; i < vertCount; ++i) { UIVertex vertex = verts[i]; vertex.position *= unitsPerPixel; verts[i] = vertex; } } } private void AdjustIndicesByIndex(int indexOffset, BaseMatch referenceMatch, List adjusteeMatches) { for (int i = 0; i < adjusteeMatches.Count; i++) { BaseMatch adjusteeMatch = adjusteeMatches[i]; if (referenceMatch == adjusteeMatch) continue; if (referenceMatch.StartIndex < adjusteeMatch.StartIndex) //referenceIndex-adjusteeMatch-adjusteeMatch { adjusteeMatch.StartIndex += indexOffset; adjusteeMatch.EndIndex += indexOffset; } else if (referenceMatch.StartIndex < adjusteeMatch.EndIndex) //adjusteeMatch-referenceIndex-adjusteeMatch { adjusteeMatch.EndIndex += indexOffset; } } } private void AdjustIndicesByMatch(int extraOffset, BaseMatch referenceMatch, List adjusteeMatches) { for (int i = 0; i < adjusteeMatches.Count; i++) { BaseMatch adjusteeMatch = adjusteeMatches[i]; if (referenceMatch == adjusteeMatch) continue; if (referenceMatch.StartIndex < adjusteeMatch.EndIndex) //排除 adjusteeMatch...adjusteeMatch...refeMatch-refeMatch { if (referenceMatch.EndIndex < adjusteeMatch.StartIndex) //refeMatch-refeMatch...adjusteeMatch-adjusteeMatch { int indexOffset = -referenceMatch.MatchData.OpenPatternLength - referenceMatch.MatchData.ClosePatternLength + extraOffset; adjusteeMatch.StartIndex += indexOffset; adjusteeMatch.EndIndex += indexOffset; } else if (referenceMatch.EndIndex < adjusteeMatch.EndIndex) //refeMatch...adjusteeMatch...refeMatch...adjusteeMatch { int indexOffset = -referenceMatch.MatchData.ClosePatternLength + extraOffset; adjusteeMatch.StartIndex += indexOffset; adjusteeMatch.EndIndex += indexOffset; } else if (referenceMatch.EndIndex > adjusteeMatch.EndIndex) //adjusteeMatch...refeMatch...adjusteeMatch...refeMatch { int indexOffset = -referenceMatch.MatchData.OpenPatternLength + extraOffset; adjusteeMatch.StartIndex += indexOffset; adjusteeMatch.EndIndex += indexOffset; } //不应该出现的情况refeMatch...adjusteeMatch-adjusteeMatch...refeMatch adjusteeMatch...refeMatch...refeMatch...adjusteeMatch } } } public void GetSegments(string newText, TextGenerator textGenerator, T match, List excludeChars) where T : SegmentMatch { //print(excludeChars.Count); if (textGenerator.lines.Count == 1) { match.Segments.Add(new List {match.StartIndex, match.EndIndex}); } else { int endLineIndex; int startLineIndex; for (int i = 0; i < textGenerator.lines.Count; i++) { startLineIndex = textGenerator.lines.Count - 1 - i; if (match.StartIndex >= textGenerator.lines[startLineIndex].startCharIdx) { if (startLineIndex == textGenerator.lines.Count - 1) { match.Segments.Add(new List {match.StartIndex, match.EndIndex}); goto jumpOut; } else { if (match.EndIndex >= textGenerator.lines.Back(0).startCharIdx) { endLineIndex = textGenerator.lines.Count - 1; } else { for (int j = startLineIndex; j < textGenerator.lines.Count; j++) { if (match.EndIndex < textGenerator.lines[j + 1].startCharIdx) { if (j == startLineIndex) { match.Segments.Add(new List {match.StartIndex, match.EndIndex}); goto jumpOut; } else { endLineIndex = j; goto segment; } } } throw new Exception(); } segment: int segmentCount = endLineIndex - startLineIndex + 1; match.Segments.Add(new List {match.StartIndex, textGenerator.lines[startLineIndex + 1].startCharIdx - 1}); //第一段 match.Segments.Add(new List {textGenerator.lines[endLineIndex].startCharIdx, match.EndIndex}); //最后一段 for (int k = 0; k < segmentCount - 2; k++) { match.Segments.Add(new List {textGenerator.lines[startLineIndex + 1 + k].startCharIdx, textGenerator.lines[startLineIndex + 2 + k].startCharIdx - 1}); } goto jumpOut; } } } } jumpOut: //for (int i = 0; i < match.Segments.Count; i++) //{ // Debug.LogWarning(match.Segments[i][0] + "\t" + match.Segments[i][1]); //} exclude: for (int i = 0; i < match.Segments.Count; i++) { int startIndex = match.Segments[i][0]; int endIndex = match.Segments[i][1]; for (int j = startIndex; j <= endIndex; j++) { //print((int)newText[j]); if (excludeChars.Contains(newText[j])) { if (j == startIndex) { //Debug.Log("start " + match.Segments[i][0] + "\t" + match.Segments[i][1]); //Debug.Log(j); //newText = newText.Remove(startIndex, 1); match.Segments[i][0] = startIndex + 1; //Debug.Log("start " + match.Segments[i][0] + "\t" + match.Segments[i][1]); } else if (j == endIndex) { //Debug.Log("end " + match.Segments[i][0] + "\t" + match.Segments[i][1]); //Debug.Log(j); //newText = newText.Remove(endIndex, 1); match.Segments[i][1] = endIndex - 1; //Debug.Log("end " + match.Segments[i][0] + "\t" + match.Segments[i][1]); } else { //Debug.Log(j); //newText = newText.Remove(j, 1); //Debug.Log("remove " + match.Segments[i][0] + "\t" + match.Segments[i][1]); match.Segments.RemoveAt(i); match.Segments.Insert(0, new List {startIndex, j - 1}); //Debug.Log("add " + match.Segments[0][0] + "\t" + match.Segments[0][1]); match.Segments.Insert(0, new List {j + 1, endIndex}); //Debug.Log("add " + match.Segments[0][0] + "\t" + match.Segments[0][1]); } goto exclude; } } } for (int i = 0; i < match.Segments.Count; i++) { if (match.Segments[i][1] < match.Segments[i][0]) { match.Segments.RemoveAt(i--); } } //for (int i = 0; i < match.Segments.Count; i++) //{ // Debug.Log(match.Segments[i][0] + "\t" + match.Segments[i][1]); //} } private int GetVerticalBestfitFontSize(string newText) { int antiCrush = 0; TextGenerationSettings settings = GetGenerationSettings(rectTransform.rect.size); List leftSizes = new List {resizeTextMinSize}; List rightSizes = new List {resizeTextMaxSize}; settings.fontSize = (leftSizes[0] + rightSizes[0])/2; while (true) { if (antiCrush++ > 300) { throw new Exception("Crush"); } float preferredHeight = cachedTextGenerator.GetPreferredHeight(newText, settings); if (preferredHeight > rectTransform.rect.size.y*canvas.scaleFactor) { rightSizes.Add(settings.fontSize); settings.fontSize = (leftSizes[leftSizes.Count - 1] + settings.fontSize)/2; } else if (preferredHeight < rectTransform.rect.size.y*canvas.scaleFactor) { if (leftSizes.Contains(settings.fontSize)) { return settings.fontSize; } else { leftSizes.Add(settings.fontSize); } settings.fontSize = (rightSizes[rightSizes.Count - 1] + settings.fontSize)/2; } else { return settings.fontSize; } } } public void ApplyVerticalBestfitSize() { resizeTextMinSize = MinSize; resizeTextMaxSize = MaxSize; } public void DisableOriginBestfit() { resizeTextForBestFit = false; } public void EnableVerticalBestfit() { UseOriginBestfit = resizeTextForBestFit; MinSize = resizeTextMinSize; MaxSize = resizeTextMaxSize; UseVerticalBestfit = true; VerticalBestfitDirty = true; DisableOriginBestfit(); } public void DisableVerticalBestfit() { resizeTextForBestFit = UseOriginBestfit; UseVerticalBestfit = false; } private bool ParseAndFillMatches(ref string newText) { bool haveMatch = ParseMatches(ref newText); if (haveMatch) { FillSpriteMatches(AvailableSpriteMatches, TruncateSpriteMatches, ref newText); } return haveMatch; } public void EnableDebugMode() { //TextGenerationSettings settings = GetGenerationSettings(rectTransform.rect.size); //settings.textAnchor = alignment; //CalculateTextGenerator = new TextGenerator(); //print(CalculateTextGenerator.GetPreferredHeight("", settings) / canvas.scaleFactor); //print(cachedTextGenerator.characterCount); //print(cachedTextGenerator.lineCount); Debug = true; Content = text; SetVerticesDirty(); SetLayoutDirty(); //string newText = Content; //if (ParseAndFillMatches(ref newText)) //{ // AddNewOpenCloseMatch(newText); //} } public void DisableDebugMode() { Debug = false; text = Content; ClearMatches(); ImageManager.ClearRenderTask(); } public void OnPointerClick(PointerEventData eventData) { //Vector3 clickPosition = eventData.position; //Debug.Log(clickPosition); OnPointerClick(eventData.position); } private Dictionary>> SuperlinkPositionsDictionary = new Dictionary>>(); public void OnPointerClick(Vector3 worldPosition) { SuperlinkPositionsDictionary = new Dictionary>>(); foreach (var match in SuperlinkMatches) { SuperlinkMatch superlinkMatch = (SuperlinkMatch) match; SuperlinkPositionsDictionary.Add(superlinkMatch.ID, superlinkMatch.RectanglePositionsList); } Vector3 clickPosition = worldPosition; //Vector3 clickPosition = rectTransform.InverseTransformPoint(worldPosition); foreach (var kv in SuperlinkPositionsDictionary) { foreach (var positions in kv.Value) { float minX = positions.MyMin(vector => vector.x).x; float maxX = positions.MyMax(vector => vector.x).x; float minY = positions.MyMin(vector => vector.y).y; float maxY = positions.MyMax(vector => vector.y).y; //UnityEngine.Debug.Log(clickPosition); //UnityEngine.Debug.Log(minX + " " + maxX + " " + minY + " " + maxY); if ((minX <= clickPosition.x && clickPosition.x <= maxX) && (minY <= clickPosition.y && clickPosition.y <= maxY)) { if (SuperlinkCallbackDictionary.ContainsKey(kv.Key)) { SuperlinkCallbackDictionary[kv.Key].Invoke(kv.Key); } else { UnityEngine.Debug.LogWarning(string.Format("没有找到事件 id : {0}", kv.Key)); } } } } } } }