private void UpdateText(Style style) { Lines.Clear(); if (string.IsNullOrEmpty(_text)) { return; } TextElement def = new TextElement(); def.Font = style.Font; List <TextElement> elements = BBCode.Parse(_text, style, false); List <TextElement> textElements = new List <TextElement>(); Point pos = new Point(); Point tsize = new Point(); int lineHeight = 0; List <TextElement> thisLine = new List <TextElement>(); TextSize = Point.Zero; if (TextWrap) { #region TextWrap = true foreach (TextElement element in elements) { int font = Gui.Renderer.GetFont(element.Font); if (element.Linebreak) { pos.x = 0; pos.y += lineHeight + Leading; element.Position = pos; element.Size = Gui.Renderer.GetTextSize(" ", font); foreach (TextElement el in thisLine) { if (!el.Linebreak) { el.Position.y += lineHeight - el.Size.y; } } thisLine.Clear(); lineHeight = element.Size.y; textElements.Add(element); } else { #region wrap string[] words = element.Text.Split(' '); List <TextElement> sub = new List <TextElement>(); TextElement e = new TextElement(element); e.Text = string.Empty; e.Position = pos; sub.Add(e); int i = 0; foreach (string word in words) { string temp = word; if (i > 0) { temp = " " + word; } tsize = Gui.Renderer.GetTextSize(temp, font); lineHeight = Math.Max(lineHeight, tsize.y); int limit = Size.x - (style.TextPadding.Left + style.TextPadding.Right); i++; // the word fits, add to current element if (pos.x + tsize.x < limit) { e.Text += temp; e.Size = Gui.Renderer.GetTextSize(e.Text, font); pos.x += tsize.x; } else { // the whole word is larger than the text area if (tsize.x > limit) { } // the whole word fits into text area else { pos.x = 0; pos.y += lineHeight + Leading; thisLine.Add(e); foreach (TextElement el in thisLine) { if (!el.Linebreak) { el.Position.y += lineHeight - el.Size.y; } } thisLine.Clear(); lineHeight = 0; TextElement linebreak = new TextElement(e); linebreak.Text = string.Empty; linebreak.Linebreak = true; linebreak.Position = pos; sub.Add(linebreak); e = new TextElement(element); e.Text = word; e.Position = pos; e.Size = Gui.Renderer.GetTextSize(e.Text, font); sub.Add(e); lineHeight = Math.Max(lineHeight, e.Size.y); pos.x += tsize.x; } } } thisLine.AddRange(sub); textElements.AddRange(sub); #endregion } } foreach (TextElement el in thisLine) { if (!el.Linebreak) { el.Position.y += lineHeight - el.Size.y; } } #endregion } else { foreach (TextElement element in elements) { int font = Gui.Renderer.GetFont(element.Font); if (element.Linebreak) { pos.x = 0; pos.y += lineHeight + Leading; element.Position = pos; element.Size = Gui.Renderer.GetTextSize(" ", font); foreach (TextElement el in thisLine) { if (!el.Linebreak) { el.Position.y += lineHeight - el.Size.y; } } thisLine.Clear(); lineHeight = element.Size.y; textElements.Add(element); } else { //if (!string.IsNullOrEmpty(element.Text)) //{ tsize = Gui.Renderer.GetTextSize(string.IsNullOrEmpty(element.Text) ? " " : element.Text, font); lineHeight = Math.Max(lineHeight, tsize.y); element.Position = pos; element.Size = tsize; textElements.Add(element); pos.x += tsize.x; thisLine.Add(element); //} } } foreach (TextElement el in thisLine) { if (!el.Linebreak) { el.Position.y += lineHeight - el.Size.y; } } } TextLine line = new TextLine(); foreach (TextElement element in textElements) { if (element.Linebreak) { line.CharLength += 1; line.Elements.Add(element); Lines.Add(line); line = new TextLine(); } else { line.Width += element.Size.x; line.CharLength += element.Text.Length; line.Elements.Add(element); } TextSize.x = Math.Max(TextSize.x, line.Width); TextSize.y = Math.Max(TextSize.y, element.Position.y + element.Size.y); } Lines.Add(line); TextSize += new Point(style.TextPadding.Left + style.TextPadding.Right, style.TextPadding.Top + style.TextPadding.Bottom); LastSize = Size; IsDirty = false; //GetLineAndCol(); }
/// <summary> /// Initializes a new instance of the <see cref="TextElement"/> class. /// </summary> /// <param name="copy">The copy.</param> public TextElement(TextElement copy) { Font = copy.Font; Color = copy.Color; Href = copy.Href; }
private void UpdateText(Style style) { activeLibrary.Clear(); Lines.Clear(); TextElement def = new TextElement(); def.Font = style.Font; List <TextElement> elements = BBCode.Parse(_text, style, BBCodeEnabled); List <TextElement> textElements = new List <TextElement>(); Point pos = new Point(); Point tsize = new Point(); int advx = 0; int lineHeight = 0; List <TextElement> thisLine = new List <TextElement>(); TextSize = Point.Zero; if (TextWrap) { #region TextWrap = true bool firstInLine = true; foreach (TextElement element in elements) { int font = Gui.Renderer.GetFont(element.Font); if (element.Linebreak) { if (firstInLine) { lineHeight = Gui.Renderer.GetTextSize(" ", font).y; } pos.x = 0; pos.y += lineHeight + Leading; foreach (TextElement el in thisLine) { el.Position.y += lineHeight - el.Size.y; } thisLine.Clear(); lineHeight = 0; textElements.Add(element); firstInLine = true; } else if (element.IsControl) { Control ctrl = null; if (library.ContainsKey(element.Control)) { ctrl = library[element.Control]; } else if (ControlRequest != null) { ctrl = ControlRequest(element.Control); library.Add(element.Control, ctrl); } if (ctrl != null) { activeLibrary.Add(element.Control, true); ctrl.Position = pos; ctrl.UserData = element.Control; if (ctrl.Parent == null) { Elements.Add(ctrl); } element.Size = ctrl.Size; tsize = ctrl.Size; if (pos.x + tsize.x < Size.x - (style.TextPadding.Left + style.TextPadding.Right)) { element.Position = pos; pos.x += ctrl.Size.x; lineHeight = Math.Max(lineHeight, tsize.y); } else { pos.x = 0; pos.y += lineHeight + Leading; foreach (TextElement el in thisLine) { el.Position.y += lineHeight - el.Size.y; } thisLine.Clear(); textElements.Add(new TextElement { Linebreak = true }); firstInLine = true; element.Position = pos; pos.x += ctrl.Size.x; lineHeight = tsize.y; } textElements.Add(element); //thisLine.Add(element); } } else { #region wrap string[] words = System.Text.RegularExpressions.Regex.Split(element.Text, @"(?=(?<=[^\s])\s+)"); List <TextElement> sub = new List <TextElement>(); TextElement e = new TextElement(element); e.Text = string.Empty; e.Position = pos; int c = 0; bool isBreak = false; foreach (string word in words) { if (word.Length == 0) { continue; } string temp = word; // if this is the first word in a new line // remove leading whitespaces if (firstInLine) { temp = word.TrimStart(); } tsize = Gui.Renderer.GetTextSize(e.Text + temp, font); lineHeight = Math.Max(lineHeight, tsize.y); if (pos.x + tsize.x < Size.x - (style.TextPadding.Left + style.TextPadding.Right)) { // the word fits, add to current element e.Text += temp; e.Size = tsize; firstInLine = false; } else { #region new if (firstInLine) { // the word fits, add to current element e.Text += temp; e.Size = tsize; firstInLine = false; } else { // word does not fit, add the current element thisLine.Add(e); sub.Add(e); textElements.AddRange(sub); foreach (TextElement el in thisLine) { el.Position.y += lineHeight - el.Size.y; } sub.Clear(); thisLine.Clear(); // reset line pos pos.x = 0; pos.y += lineHeight + Leading; lineHeight = 0; // add a break TextElement linebreak = new TextElement(e); linebreak.Linebreak = true; sub.Add(linebreak); // create new starting element e = new TextElement(element); e.Text = temp.TrimStart(); e.Position = pos; e.Size = Gui.Renderer.GetTextSize(e.Text, font); lineHeight = Math.Max(lineHeight, e.Size.y); firstInLine = false; } #endregion #region old //if (c > 0) //{ // isBreak = true; // // the word does not fit // pos.x = 0; // pos.y += lineHeight + Leading; //} //// is more than one word in this line exceeding the break limit? //if (c > 0) //{ // // if so, we need to first add the current element, // thisLine.Add(e); // sub.Add(e); // foreach (TextElement el in thisLine) // { // el.Position.y += lineHeight - el.Size.y; // // el.Size.y += lineHeight - el.Size.y; // } // thisLine.Clear(); // lineHeight = 0; // TextElement linebreak = new TextElement(e); // linebreak.Linebreak = true; // sub.Add(linebreak); // e = new TextElement(element); // e.Text = temp.TrimStart(); // e.Position = pos; // e.Size = Gui.Renderer.GetTextSize(e.Text, font); // lineHeight = Math.Max(lineHeight, e.Size.y); // if (c <= words.Length) // isBreak = false; //} //else //{ // // if not, we just add the current word // e.Position = pos; // e.Text = temp; // e.Size = Gui.Renderer.GetTextSize(e.Text, font); // //sub.Add(e); //} #endregion //pos.x += tsize.x; } c++; } if (!isBreak) { //e.Size = Gui.Renderer.GetTextSize(e.Text, font); pos.x = pos.x + e.Size.x; lineHeight = Math.Max(lineHeight, e.Size.y); sub.Add(e); } thisLine.AddRange(sub); textElements.AddRange(sub); #endregion } } foreach (TextElement el in thisLine) { el.Position.y += lineHeight - el.Size.y; } #endregion } else { #region TextWrap = false bool firstInLine = true; bool singleLine = true; foreach (TextElement element in elements) { int font = Gui.Renderer.GetFont(element.Font); if (element.Linebreak) { if (firstInLine) { lineHeight = Gui.Renderer.GetTextSize(" ", font).y; } pos.x = 0; pos.y += lineHeight + Leading; foreach (TextElement el in thisLine) { el.Position.y += lineHeight - el.Size.y; // el.Size.y += lineHeight - el.Size.y; } thisLine.Clear(); lineHeight = 0; element.Position = pos; textElements.Add(element); firstInLine = true; singleLine = false; } else if (element.IsControl) { Control ctrl = null; if (library.ContainsKey(element.Control)) { ctrl = library[element.Control]; } else if (ControlRequest != null) { ctrl = ControlRequest(element.Control); library.Add(element.Control, ctrl); } if (ctrl != null) { ctrl.Position = pos; if (ctrl.Parent == null) { Elements.Add(ctrl); } activeLibrary.Add(element.Control, true); element.Position = pos; element.Size = ctrl.Size; pos.x += ctrl.Size.x; tsize = element.Size; lineHeight = Math.Max(lineHeight, tsize.y); textElements.Add(element); //thisLine.Add(element); } } else { if (firstInLine) { element.Text = element.Text.TrimStart(); firstInLine = false; } tsize = Gui.Renderer.GetTextSize(string.IsNullOrEmpty(element.Text) ? " " : element.Text, font); lineHeight = Math.Max(lineHeight, tsize.y); element.Position = pos; element.Size = tsize; textElements.Add(element); pos.x += tsize.x; thisLine.Add(element); } } foreach (TextElement el in thisLine) { el.Position.y += lineHeight - el.Size.y; } #endregion #region AutoEllipsis (...) if (singleLine && AutoEllipsis && (AutoSize == Squid.AutoSize.None || AutoSize == AutoSize.Vertical)) { int removeAt = -1; int width = 0; int limit = Size.x - style.TextPadding.Left - style.TextPadding.Right; Alignment align = TextAlign != Alignment.Inherit ? TextAlign : style.TextAlign; if (align == Alignment.TopLeft || align == Alignment.MiddleLeft || align == Alignment.BottomLeft) { for (int i = 0; i < textElements.Count; i++) { int font = Gui.Renderer.GetFont(textElements[i].Font); int ellipsis = Gui.Renderer.GetTextSize("...", font).x; if (width + textElements[i].Size.x + ellipsis <= limit) { width += textElements[i].Size.x; continue; } else { string text = string.Empty; string final = string.Empty; removeAt = i + 1; foreach (char c in textElements[i].Text) { final = text + c + "..."; int w = Gui.Renderer.GetTextSize(final, font).x; if (width + w >= limit) { textElements[i].Text = text + "..."; break; } else { text += c; } } break; } } if (removeAt > -1) { textElements.RemoveRange(removeAt, textElements.Count - removeAt); } } else if (align == Alignment.TopRight || align == Alignment.MiddleRight || align == Alignment.BottomRight) { for (int i = textElements.Count - 1; i >= 0; i--) { int font = Gui.Renderer.GetFont(textElements[i].Font); int ellipsis = Gui.Renderer.GetTextSize("...", font).x; int fullsize = textElements[i].Size.x; Point oldpos = textElements[i].Position; if (width + textElements[i].Size.x + ellipsis <= limit) { width += textElements[i].Size.x; } else { string inc = string.Empty; string final = string.Empty; string text = textElements[i].Text; removeAt = i; for (int j = text.Length; j >= 0; j--) { char c = new char(); if (j < text.Length) { c = text[j]; final = "..." + c + inc; inc = c + inc; } else { final = "..." + inc; } if (j == 0 && removeAt == 0) { final = inc; } int w = Gui.Renderer.GetTextSize(final, font).x; Point position = oldpos; position.x = oldpos.x + (fullsize - w); textElements[i].Text = final; textElements[i].Position = position; if (width + w > limit && j > 0) { break; } } break; } } if (removeAt > 0) { int ww = 0; for (int i = 0; i < removeAt; i++) { ww += textElements[i].Size.x; } textElements.RemoveRange(0, removeAt); for (int i = 0; i < textElements.Count; i++) { Point position = textElements[i].Position; position.x -= ww; textElements[i].Position = position; } } } } #endregion } TextLine line = new TextLine(); foreach (TextElement element in textElements) { line.Width += element.Size.x; line.Elements.Add(element); TextSize.x = Math.Max(TextSize.x, line.Width); TextSize.y = Math.Max(TextSize.y, element.Position.y + element.Size.y); if (element.Linebreak) { Lines.Add(line); line = new TextLine(); } } TextSize += new Point(style.TextPadding.Left + style.TextPadding.Right, style.TextPadding.Top + style.TextPadding.Bottom); Lines.Add(line); LastSize = Size; IsDirty = false; FinalizeTextLayout(style); foreach (KeyValuePair <string, Control> pair in library) { if (!activeLibrary.ContainsKey(pair.Key)) { Elements.Remove(pair.Value); } } }
public static List <TextElement> Parse(string text, Style style, bool enabled) { if (string.IsNullOrEmpty(text)) { return(new List <TextElement>()); } if (enabled) { text = ConvertBBCodeToHTML(text); } else { text = EscapeXML(text); text = text.Replace("\r\n", "<br/>"); text = text.Replace("\n", "<br/>"); text = text.Replace(""r"n", "<br/>"); text = text.Replace(""n", "<br/>"); } var element = new TextElement { Font = style.Font, Color = style.TextColor }; var lastElement = new TextElement { Font = style.Font, Color = style.TextColor }; var result = new List <TextElement>(); if (reader == null) { reader = new Xml.XmlReader(text); } else { reader.New(text); } while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.Name.ToLower()) { case "control": if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if (reader.Name.Equals("key")) { element.Control = reader.Value; } else if (reader.Name.Equals("data")) { // element.Data = reader.Value; } } } result.Add(element); element = new TextElement(element); break; case "font": if (reader.HasAttributes) { lastElement.Color = element.Color; lastElement.Font = element.Font; while (reader.MoveToNextAttribute()) { if (reader.Name.Equals("name")) { element.Font = reader.Value; } else if (reader.Name.Equals("color")) { var color = element.Color.Value; if (int.TryParse(reader.Value, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out color)) { element.Color = color; } else if (int.TryParse(reader.Value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out color)) { element.Color = color; } } } } break; case "a": if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if (reader.Name.Equals("href")) { element.Href = reader.Value; } } } break; case "br": element.Linebreak = true; result.Add(element); element = new TextElement(element); break; default: break; } break; case XmlNodeType.EndElement: switch (reader.Name.ToLower()) { case "control": element.Font = lastElement.Font; element.Color = lastElement.Color; break; case "font": element.Font = lastElement.Font; element.Color = lastElement.Color; break; case "a": element.Href = null; break; } break; case XmlNodeType.Text: if (reader.Value.Length > 0) { element.Text = UnescapeXML(reader.Value); result.Add(element); element = new TextElement(element); } break; default: break; } } return(result); }