/// <summary> /// Splits the text in this <see cref="TextBoxLine"/> at the given character index in the line. /// </summary> /// <param name="lineCharacterIndex">The index of the character to split the line at. This character /// at this index will be the first character on the new line.</param> /// <param name="currentLine">A <see cref="TextBoxLine"/> representing the remainder of the current /// line (the one the split initially was made on).</param> /// <param name="nextLine">A <see cref="TextBoxLine"/> representing the additional line created /// from the split.</param> public void SplitAt(int lineCharacterIndex, out TextBoxLine currentLine, out TextBoxLine nextLine) { if (lineCharacterIndex == 0) { // Split at the start of the line // First line is empty, second line is the full line currentLine = new TextBoxLine(TextBoxLines); nextLine = this; return; } else if (lineCharacterIndex == LineText.Length) { // Split at the end of the line // First line is the full line, second line is empty currentLine = this; nextLine = new TextBoxLine(TextBoxLines); return; } else { // Split up somewhere in the middle // Find the StyledText for the character StyledText text; int textIndex; int listIndex; FindLineCharacter(lineCharacterIndex, out text, out textIndex, out listIndex); // Split the StyledText StyledText left; StyledText right; text.SplitAt(textIndex, out left, out right); // The first line will be all the StyledTexts before the one split, plus the left side of the split // The second line will be the right side of the split, plus all the StyledTexts after the one split currentLine = new TextBoxLine(TextBoxLines); for (var i = 0; i < listIndex; i++) { currentLine.Append(_texts[i]); } currentLine.Append(left); nextLine = new TextBoxLine(TextBoxLines); nextLine.Append(right); for (var i = listIndex + 1; i < _texts.Count; i++) { nextLine.Append(_texts[i]); } } }
/// <summary> /// Appends the <paramref name="text"/> to the <see cref="TextBox"/> at the end. /// </summary> /// <param name="text">The text to append.</param> public void Append(StyledText text) { if (text.Text.Length == 0) { return; } if (!IsMultiLine) { _lines.LastLine.Append(text.ToSingleline()); } else { var textLines = StyledText.ToMultiline(text); _lines.LastLine.Append(textLines[0]); for (var i = 1; i < textLines.Count; i++) { var newLine = new TextBoxLine(_lines); _lines.Insert(_lines.Count, newLine); newLine.Append(textLines[i]); } TruncateIfNeeded(); } _numCharsToDraw.Invalidate(); _hasTextChanged = true; }
/// <summary> /// A callback for the <see cref="TextBoxLine"/> to notify this <see cref="TextBoxLines"/> that the line /// was increased in length. /// </summary> /// <param name="line">The <see cref="TextBoxLine"/> that had text added to it.</param> internal void NotifyTextAdded(TextBoxLine line) { if (_font == null) { return; } var width = line.GetWidth(_font); if (width <= _maxLineLength) { return; } var newLines = StyledText.ToMultiline(line.GetLineTexts, false, _font, _maxLineLength); if (newLines.Count <= 1) { return; } // Avoid infinite recursion by not updating if the text didn't change var first = newLines[0]; if (first.Sum(x => x.Text.Length) == line.LineText.Length && StyledText.ToString(first).Equals(line.LineText, StringComparison.Ordinal)) { return; } line.Clear(); line.Append(newLines[0]); var lineIndex = _lines.IndexOf(line); if (lineIndex != _lines.Count - 1 && _lines[lineIndex + 1].WasAutoBroken) { // We're not at the last line AND the next line was auto-split, so keep inserting at the // start of the next line in reverse for (var i = newLines.Count - 1; i > 0; i--) { foreach (var j in newLines[i].Reverse <StyledText>()) { _lines[lineIndex + 1].Insert(j, 0); } } } else { // We're at the last line or the next line was not an auto-split line for (var i = 1; i < newLines.Count; i++) { var newLine = new TextBoxLine(this, true); newLine.Append(newLines[i]); _lines.Insert(lineIndex + i, newLine); } } }
/// <summary> /// A callback for the <see cref="TextBoxLine"/> to notify this <see cref="TextBoxLines"/> that the line /// was increased in length. /// </summary> /// <param name="line">The <see cref="TextBoxLine"/> that had text added to it.</param> internal void NotifyTextAdded(TextBoxLine line) { if (_font == null) return; var width = line.GetWidth(_font); if (width <= _maxLineLength) return; var newLines = StyledText.ToMultiline(line.GetLineTexts, false, _font, _maxLineLength); if (newLines.Count <= 1) return; // Avoid infinite recursion by not updating if the text didn't change var first = newLines[0]; if (first.Sum(x => x.Text.Length) == line.LineText.Length && StyledText.ToString(first).Equals(line.LineText, StringComparison.Ordinal)) return; line.Clear(); line.Append(newLines[0]); var lineIndex = _lines.IndexOf(line); if (lineIndex != _lines.Count - 1 && _lines[lineIndex + 1].WasAutoBroken) { // We're not at the last line AND the next line was auto-split, so keep inserting at the // start of the next line in reverse for (var i = newLines.Count - 1; i > 0; i--) { foreach (var j in newLines[i].Reverse<StyledText>()) { _lines[lineIndex + 1].Insert(j, 0); } } } else { // We're at the last line or the next line was not an auto-split line for (var i = 1; i < newLines.Count; i++) { var newLine = new TextBoxLine(this, true); newLine.Append(newLines[i]); _lines.Insert(lineIndex + i, newLine); } } }
/// <summary> /// Appends the <paramref name="text"/> to the <see cref="TextBox"/> at the end. /// </summary> /// <param name="text">The text to append.</param> public void Append(StyledText text) { if (text.Text.Length == 0) return; if (!IsMultiLine) _lines.LastLine.Append(text.ToSingleline()); else { var textLines = StyledText.ToMultiline(text); _lines.LastLine.Append(textLines[0]); for (var i = 1; i < textLines.Count; i++) { var newLine = new TextBoxLine(_lines); _lines.Insert(_lines.Count, newLine); newLine.Append(textLines[i]); } TruncateIfNeeded(); } _numCharsToDraw.Invalidate(); _hasTextChanged = true; }
/// <summary> /// Splits the text in this <see cref="TextBoxLine"/> at the given character index in the line. /// </summary> /// <param name="lineCharacterIndex">The index of the character to split the line at. This character /// at this index will be the first character on the new line.</param> /// <param name="currentLine">A <see cref="TextBoxLine"/> representing the remainder of the current /// line (the one the split initially was made on).</param> /// <param name="nextLine">A <see cref="TextBoxLine"/> representing the additional line created /// from the split.</param> public void SplitAt(int lineCharacterIndex, out TextBoxLine currentLine, out TextBoxLine nextLine) { if (lineCharacterIndex == 0) { // Split at the start of the line // First line is empty, second line is the full line currentLine = new TextBoxLine(TextBoxLines); nextLine = this; return; } else if (lineCharacterIndex == LineText.Length) { // Split at the end of the line // First line is the full line, second line is empty currentLine = this; nextLine = new TextBoxLine(TextBoxLines); return; } else { // Split up somewhere in the middle // Find the StyledText for the character StyledText text; int textIndex; int listIndex; FindLineCharacter(lineCharacterIndex, out text, out textIndex, out listIndex); // Split the StyledText StyledText left; StyledText right; text.SplitAt(textIndex, out left, out right); // The first line will be all the StyledTexts before the one split, plus the left side of the split // The second line will be the right side of the split, plus all the StyledTexts after the one split currentLine = new TextBoxLine(TextBoxLines); for (var i = 0; i < listIndex; i++) { currentLine.Append(_texts[i]); } currentLine.Append(left); nextLine = new TextBoxLine(TextBoxLines); nextLine.Append(right); for (var i = listIndex + 1; i < _texts.Count; i++) { nextLine.Append(_texts[i]); } } }