|
@@ -8,6 +8,7 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
+using System.Text.RegularExpressions;
|
|
|
using NStack;
|
|
|
|
|
|
namespace Terminal.Gui {
|
|
@@ -125,7 +126,7 @@ namespace Terminal.Gui {
|
|
|
// Get rid of any '\r' added by Windows
|
|
|
str = str.Replace ("\r", ustring.Empty);
|
|
|
int slen = str.RuneCount;
|
|
|
- if (slen > width){
|
|
|
+ if (slen > width) {
|
|
|
var uints = str.ToRunes (width);
|
|
|
var runes = new Rune [uints.Length];
|
|
|
for (int i = 0; i < uints.Length; i++)
|
|
@@ -134,11 +135,11 @@ namespace Terminal.Gui {
|
|
|
} else {
|
|
|
if (talign == TextAlignment.Justified) {
|
|
|
// TODO: ustring needs this
|
|
|
- var words = str.ToString ().Split (whitespace, StringSplitOptions.RemoveEmptyEntries);
|
|
|
+ var words = str.ToString ().Split (whitespace, StringSplitOptions.RemoveEmptyEntries);
|
|
|
int textCount = words.Sum (arg => arg.Length);
|
|
|
|
|
|
- var spaces = (width- textCount) / (words.Length - 1);
|
|
|
- var extras = (width - textCount) % words.Length;
|
|
|
+ var spaces = words.Length > 1 ? (width - textCount) / (words.Length - 1) : 0;
|
|
|
+ var extras = words.Length > 1 ? (width - textCount) % words.Length : 0;
|
|
|
|
|
|
var s = new System.Text.StringBuilder ();
|
|
|
//s.Append ($"tc={textCount} sp={spaces},x={extras} - ");
|
|
@@ -165,24 +166,62 @@ namespace Terminal.Gui {
|
|
|
Recalc (text, lines, Frame.Width, textAlignment);
|
|
|
}
|
|
|
|
|
|
+ static List<ustring> WordWrap (ustring text, int margin)
|
|
|
+ {
|
|
|
+ int start = 0, end;
|
|
|
+ var lines = new List<ustring> ();
|
|
|
+
|
|
|
+ text = text.Replace ("\f", " ")
|
|
|
+ .Replace ("\n", " ")
|
|
|
+ .Replace ("\r", " ")
|
|
|
+ .Replace ("\t", " ")
|
|
|
+ .Replace ("\v", " ")
|
|
|
+ .TrimSpace ();
|
|
|
+
|
|
|
+ while ((end = start + margin) < text.Length) {
|
|
|
+ while (text [end] != ' ' && end > start)
|
|
|
+ end -= 1;
|
|
|
+
|
|
|
+ if (end == start)
|
|
|
+ end = start + margin;
|
|
|
+
|
|
|
+ lines.Add (text [start, end]);
|
|
|
+ start = end + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (start < text.Length)
|
|
|
+ lines.Add (text.Substring (start));
|
|
|
+
|
|
|
+ return lines;
|
|
|
+ }
|
|
|
+
|
|
|
static void Recalc (ustring textStr, List<ustring> lineResult, int width, TextAlignment talign)
|
|
|
{
|
|
|
lineResult.Clear ();
|
|
|
- if (textStr.IndexOf ('\n') == -1) {
|
|
|
- lineResult.Add (ClipAndJustify (textStr, width, talign));
|
|
|
- return;
|
|
|
- }
|
|
|
int textLen = textStr.Length;
|
|
|
int lp = 0;
|
|
|
for (int i = 0; i < textLen; i++) {
|
|
|
Rune c = textStr [i];
|
|
|
-
|
|
|
if (c == '\n') {
|
|
|
- lineResult.Add (ClipAndJustify (textStr [lp, i], width, talign));
|
|
|
+ var wrappedLines = WordWrap (textStr [lp, i], width);
|
|
|
+ foreach (var line in wrappedLines) {
|
|
|
+ lineResult.Add (ClipAndJustify (line, width, talign));
|
|
|
+ }
|
|
|
+ if (wrappedLines.Count == 0) {
|
|
|
+ lineResult.Add (ustring.Empty);
|
|
|
+ }
|
|
|
lp = i + 1;
|
|
|
}
|
|
|
}
|
|
|
- lineResult.Add(ClipAndJustify(textStr[lp, textLen], width, talign));
|
|
|
+ foreach (var line in WordWrap (textStr [lp, textLen], width)) {
|
|
|
+ lineResult.Add (ClipAndJustify (line, width, talign));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ///<inheritdoc/>
|
|
|
+ public override void LayoutSubviews ()
|
|
|
+ {
|
|
|
+ recalcPending = true;
|
|
|
}
|
|
|
|
|
|
///<inheritdoc/>
|
|
@@ -198,7 +237,7 @@ namespace Terminal.Gui {
|
|
|
|
|
|
Clear ();
|
|
|
for (int line = 0; line < lines.Count; line++) {
|
|
|
- if (line < bounds.Top || line > bounds.Bottom)
|
|
|
+ if (line < bounds.Top || line >= bounds.Bottom)
|
|
|
continue;
|
|
|
var str = lines [line];
|
|
|
int x;
|
|
@@ -207,7 +246,6 @@ namespace Terminal.Gui {
|
|
|
x = 0;
|
|
|
break;
|
|
|
case TextAlignment.Justified:
|
|
|
- Recalc ();
|
|
|
x = Bounds.Left;
|
|
|
break;
|
|
|
case TextAlignment.Right:
|
|
@@ -243,11 +281,24 @@ namespace Terminal.Gui {
|
|
|
/// <returns>Max width of lines.</returns>
|
|
|
/// <param name="text">Text, may contain newlines.</param>
|
|
|
/// <param name="width">The width for the text.</param>
|
|
|
- public static int MaxWidth(ustring text, int width)
|
|
|
+ public static int MaxWidth (ustring text, int width)
|
|
|
{
|
|
|
- var result = new List<ustring>();
|
|
|
- Recalc(text, result, width, TextAlignment.Left);
|
|
|
- return result.Max(s => s.RuneCount);
|
|
|
+ var result = new List<ustring> ();
|
|
|
+ Recalc (text, result, width, TextAlignment.Left);
|
|
|
+ return result.Max (s => s.RuneCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Computes the max height of a line or multilines needed to render by the Label control
|
|
|
+ /// </summary>
|
|
|
+ /// <returns>Max height of lines.</returns>
|
|
|
+ /// <param name="text">Text, may contain newlines.</param>
|
|
|
+ /// <param name="width">The width for the text.</param>
|
|
|
+ public static int MaxHeight (ustring text, int width)
|
|
|
+ {
|
|
|
+ var result = new List<ustring> ();
|
|
|
+ Recalc (text, result, width, TextAlignment.Left);
|
|
|
+ return result.Count;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|