public void SetExternalUnderlining(UnderlineInfo underlineInfo, bool setSelection) { ExternalUnderliningLoop.SendRewind( ); lock (this) { LastExternalUnderlineInfo = underlineInfo; LastExternalUnderlineSetSelection = setSelection; } ExternalUnderliningLoop.SendWaitAndExecute( ); }
private Stack <UnderlineInfo> tagHeadStack = new Stack <UnderlineInfo>(); //存储标签头,因为嵌套 private void DealUnderlineTag(string richText, IList <UIVertex> verts) { if (richText.Length * 4 > verts.Count) { return; //在标签输入的过程中,会出现 } tagHeadStack.Clear(); Match match = regex.Match(richText); while (match.Success) { if (match.Value == endStr) //匹配到标签尾 { if (tagHeadStack.Count == 0) { match = match.NextMatch(); continue; } UnderlineInfo tagParser = tagHeadStack.Pop(); int startIndex = tagParser.startIndex; int endIndex = match.Index; if (endIndex <= startIndex) //没有囊括内容 { match = match.NextMatch(); continue; } //标签类型 Match headMatch = tagRegex.Match(tagParser.content); if (!headMatch.Success) { match = match.NextMatch(); continue; } string tagName = headMatch.Groups[1].Value; if (tagName != "underline") { match = match.NextMatch(); continue; } //解析标签参数 Color color = Color.white; //颜色 float height = 1f; //线段高度 int controlID = -99999; string parameter = ""; //参数 var keyValueCollection = _PairRegex.Matches(headMatch.Groups[2].Value); for (int i = 0; i < keyValueCollection.Count; i++) { string key = keyValueCollection[i].Groups[1].Value; string value = keyValueCollection[i].Groups[2].Value; switch (key) { case "c": { ColorUtility.TryParseHtmlString(value, out color); break; } case "h": { float.TryParse(value, out height); break; } case "f": { int.TryParse(value, out controlID); break; } case "p": { parameter = value; break; } default: break; } } float unitsPerPixel = 1 / pixelsPerUnit; //0 1|4 5|8 9 |12 13 //3 2|7 6|11 10|14 15 //<material=underline c=#ffffff h=1 n=1 p=2>下划线</material> //以上面为例: //tag.start为42,对应“>” | start对应“下”的左上角顶点 //tag.end为44,对应“划” | end对应“线”下一个字符的左上角顶点 int start = startIndex * 4; int end = Mathf.Min(endIndex * 4, verts.Count); UIVertex vt1 = verts[start + 3]; float minY = vt1.position.y; float maxY = verts[start].position.y; //换行处理,如需换行,则将一条下划线分割成几条 //顶点取样分布,如上图的2,6,10,其中end - 2表示最后一个取样点,即10 //对应例子中的下、划、线的右下角顶点 for (int i = start + 2; i <= end - 2; i += 4) { UIVertex vt2 = verts[i]; bool newline = Mathf.Abs(vt2.position.y - vt1.position.y) > fontSize; if (newline || i == end - 2) { ImageInfo imageInfo = new ImageInfo(); //计算宽高 int tailIndex = !newline && i == end - 2 ? i : i - 4; vt2 = verts[tailIndex]; minY = vt2.position.y; imageInfo.size = new Vector2((vt2.position.x - vt1.position.x) * unitsPerPixel, height); //计算位置 Vector2 vertex = new Vector2(vt1.position.x, minY); vertex *= unitsPerPixel; vertex += new Vector2(imageInfo.size.x * 0.5f, -height * 0.5f); vertex += new Vector2(rectTransform.rect.size.x * (rectTransform.pivot.x - 0.5f), rectTransform.rect.size.y * (rectTransform.pivot.y - 0.5f)); imageInfo.position = vertex; imageInfo.color = color; _imgInfoList.Add(imageInfo); if (controlID != -99999) { EventInfo e = new EventInfo(); e.controlID = controlID; e.parameter = parameter; Vector2 pos = new Vector2(vt1.position.x, minY); pos *= unitsPerPixel; pos += new Vector2(rectTransform.rect.size.x * (rectTransform.pivot.x - 0.5f), rectTransform.rect.size.y * (rectTransform.pivot.y - 0.5f)); e.rect = new Rect(pos, new Vector2(imageInfo.size.x, (maxY - minY) * unitsPerPixel)); _eventList.Add(e); } maxY = minY; vt1 = verts[i + 1]; minY = vt1.position.y; if (newline && i == end - 2) { i -= 4; } } } } else //匹配到标签头 { UnderlineInfo tagParser = new UnderlineInfo(); tagParser.content = match.Value; tagParser.startIndex = match.Index + match.Length; //匹配位置+标签内容到长度 tagHeadStack.Push(tagParser); } match = match.NextMatch(); } }
public void SetMatches(RegexMatches matches, bool showCaptures, string eol) { if (matches == null) { throw new ArgumentNullException(nameof(matches)); } string last_text; RegexMatches last_matches; bool last_show_captures; string last_eol; lock (this) { last_text = LastText; last_matches = LastMatches; last_show_captures = LastShowCaptures; last_eol = LastEol; } string text = GetBaseTextData(eol).Text; if (last_matches != null) { var old_groups = last_matches.Matches.SelectMany(m => m.Groups).Select(g => (g.Index, g.Length, g.Value)); var new_groups = matches.Matches.SelectMany(m => m.Groups).Select(g => (g.Index, g.Length, g.Value)); if (string.Equals(text, last_text) && showCaptures == last_show_captures && eol == last_eol && new_groups.SequenceEqual(old_groups)) { lock (this) { LastMatches = matches; LastExternalUnderlineInfo = null; } MatchesUpdatedEvent.Set( ); return; } } RecolouringLoop.SendRewind( ); LocalUnderliningLoop.SendRewind( ); ExternalUnderliningLoop.SendRewind( ); lock (this) { LastText = text; LastMatches = matches; LastShowCaptures = showCaptures; LastEol = eol; LastExternalUnderlineInfo = null; } MatchesUpdatedEvent.Set( ); RecolouringLoop.SendWaitAndExecute( ); LocalUnderliningLoop.SendWaitAndExecute( ); ExternalUnderliningLoop.SendWaitAndExecute( ); }
void ParseText(string mText) { if (_emojiData == null || !Application.isPlaying) { _outputText = mText; return; } _builder.Length = 0; _emojis.Clear(); _hrefs.Clear(); _underlines.Clear(); ClearImages(); MatchCollection matches = Regex.Matches(mText, _regexTag); if (matches.Count > 0) { int textIndex = 0; int imgIdx = 0; int rectIdx = 0; for (int i = 0; i < matches.Count; i++) { var match = matches[i]; _matchResult.Parse(match, fontSize); switch (_matchResult.type) { case MatchType.Emoji: { SpriteInfo info; if (_emojiData.TryGetValue(_matchResult.title, out info)) { _builder.Append(mText.Substring(textIndex, match.Index - textIndex)); int temIndex = _builder.Length; _builder.Append("<quad size="); _builder.Append(_matchResult.height); _builder.Append(" width="); _builder.Append((_matchResult.width * 1.0f / _matchResult.height).ToString("f2")); _builder.Append(" />"); _emojis.Add(temIndex, new EmojiInfo() { type = MatchType.Emoji, sprite = info, width = _matchResult.width, height = _matchResult.height }); if (_matchResult.hasUrl) { var hrefInfo = new HrefInfo() { show = false, startIndex = temIndex * 4, endIndex = temIndex * 4 + 3, url = _matchResult.url, color = _matchResult.GetColor(color) }; _hrefs.Add(hrefInfo); } textIndex = match.Index + match.Length; } break; } case MatchType.HyperLink: { _builder.Append(mText.Substring(textIndex, match.Index - textIndex)); _builder.Append("<color="); _builder.Append(_matchResult.GetHexColor(color)); _builder.Append(">"); var href = new HrefInfo(); href.show = true; href.startIndex = _builder.Length * 4; _builder.Append(_matchResult.link); href.endIndex = _builder.Length * 4 - 1; href.url = _matchResult.url; href.color = _matchResult.GetColor(color); _hrefs.Add(href); _underlines.Add(href); _builder.Append("</color>"); textIndex = match.Index + match.Length; break; } case MatchType.CustomFill: case MatchType.Texture: { _builder.Append(mText.Substring(textIndex, match.Index - textIndex)); int temIndex = _builder.Length; _builder.Append("<quad size="); _builder.Append(_matchResult.height); _builder.Append(" width="); _builder.Append((_matchResult.width * 1.0f / _matchResult.height).ToString("f2")); _builder.Append(" />"); _emojis.Add(temIndex, new EmojiInfo() { type = _matchResult.type, width = _matchResult.width, height = _matchResult.height, texture = new TextureInfo() { link = _matchResult.link, index = _matchResult.type == MatchType.Texture? imgIdx++ : rectIdx++ } }); if (_matchResult.hasUrl) { var hrefInfo = new HrefInfo() { show = false, startIndex = temIndex * 4, endIndex = temIndex * 4 + 3, url = _matchResult.url, color = _matchResult.GetColor(color) }; _hrefs.Add(hrefInfo); //_underlines.Add(hrefInfo); } textIndex = match.Index + match.Length; break; } } } _builder.Append(mText.Substring(textIndex, mText.Length - textIndex)); _outputText = _builder.ToString(); } else { _outputText = mText; } matches = Regex.Matches(_outputText, _regexEffect); for (int i = 0; i < matches.Count; i++) { var match = matches[i]; if (match.Success && match.Groups.Count == 4) { string v1 = match.Groups[1].Value; Color lineColor; if (!string.IsNullOrEmpty(v1) && ColorUtility.TryParseHtmlString(v1, out lineColor)) { } else { lineColor = color; } var underline = new UnderlineInfo() { show = true, startIndex = match.Groups[2].Index * 4, endIndex = match.Groups[2].Index * 4 + match.Groups[2].Length * 4 - 1, color = lineColor }; _underlines.Add(underline); } } }