Merge pull request #32 from BDisp/tig_v2_2432-DimAuto

Improving TextFormatter.
This commit is contained in:
Tig
2024-05-01 10:47:27 -06:00
committed by GitHub
4 changed files with 655 additions and 174 deletions

View File

@@ -269,17 +269,6 @@ public class TextFormatter
List<string> linesFormatted = GetLines ();
switch (Direction)
{
case TextDirection.TopBottom_RightLeft:
case TextDirection.LeftRight_BottomTop:
case TextDirection.RightLeft_BottomTop:
case TextDirection.BottomTop_RightLeft:
linesFormatted.Reverse ();
break;
}
bool isVertical = IsVerticalDirection (Direction);
Rectangle maxScreen = screen;
@@ -327,15 +316,6 @@ public class TextFormatter
Rune [] runes = linesFormatted [line].ToRunes ();
runes = Direction switch
{
TextDirection.RightLeft_BottomTop => runes.Reverse ().ToArray (),
TextDirection.RightLeft_TopBottom => runes.Reverse ().ToArray (),
TextDirection.BottomTop_LeftRight => runes.Reverse ().ToArray (),
TextDirection.BottomTop_RightLeft => runes.Reverse ().ToArray (),
_ => runes
};
// When text is justified, we lost left or right, so we use the direction to align.
int x, y;
@@ -345,7 +325,7 @@ public class TextFormatter
{
if (isVertical)
{
int runesWidth = GetWidestLineLength (linesFormatted, 0, linesFormatted.Count - line, TabWidth);
int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, line, linesFormatted.Count - line, TabWidth);
x = screen.Right - runesWidth;
CursorPosition = screen.Width - runesWidth + (_hotKeyPos > -1 ? _hotKeyPos : 0);
}
@@ -361,7 +341,7 @@ public class TextFormatter
if (isVertical)
{
int runesWidth = line > 0
? GetWidestLineLength (linesFormatted, 0, line, TabWidth)
? GetColumnsRequiredForVerticalText (linesFormatted, 0, line, TabWidth)
: 0;
x = screen.Left + runesWidth;
}
@@ -376,8 +356,9 @@ public class TextFormatter
{
if (isVertical)
{
int runesWidth = GetWidestLineLength (linesFormatted, line, 1, TabWidth);
x = screen.Left + line + (screen.Width - runesWidth) / 2;
int runesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, linesFormatted.Count, TabWidth);
int linesWidth = GetColumnsRequiredForVerticalText (linesFormatted, 0, line, TabWidth);
x = screen.Left + linesWidth + (screen.Width - runesWidth) / 2;
CursorPosition = (screen.Width - runesWidth) / 2 + (_hotKeyPos > -1 ? _hotKeyPos : 0);
}
@@ -466,8 +447,8 @@ public class TextFormatter
break;
}
if ((!isVertical && current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset)
|| (isVertical && idx > maxScreen.Top + maxScreen.Height - screen.Y))
if ((!isVertical && (current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset || (idx < runes.Length && runes [idx].GetColumns () > screen.Width)))
|| (isVertical && ((current > start + size + zeroLengthCount && idx > maxScreen.Top + maxScreen.Height - screen.Y) || (idx < runes.Length && runes [idx].GetColumns () > screen.Width))))
{
break;
}
@@ -1367,7 +1348,7 @@ public class TextFormatter
{
return StringExtensions.ToString (
runes.GetRange (
index,
Math.Max (index, 0),
GetLengthThatFits (text, width, tabWidth, textDirection)
)
);
@@ -1580,16 +1561,17 @@ public class TextFormatter
foreach (string line in lines)
{
lineResult.Add (ClipAndJustify (line, width, justify, textDirection, tabWidth, textFormatter));
lineResult.Add (ClipAndJustify (PerformCorrectFormatDirection (textDirection, line), width, justify, textDirection, tabWidth, textFormatter));
}
return lineResult;
return PerformCorrectFormatDirection (textDirection, lineResult);
}
text = ReplaceCRLFWithSpace (text);
lineResult.Add (ClipAndJustify (text, width, justify, textDirection, tabWidth, textFormatter));
lineResult.Add (ClipAndJustify (PerformCorrectFormatDirection (textDirection, text), width, justify, textDirection, tabWidth, textFormatter));
return lineResult;
return PerformCorrectFormatDirection (textDirection, lineResult);
}
List<Rune> runes = StripCRLF (text, true).ToRuneList ();
@@ -1604,7 +1586,7 @@ public class TextFormatter
{
List<string> wrappedLines =
WordWrapText (
StringExtensions.ToString (runes.GetRange (lp, i - lp)),
StringExtensions.ToString (PerformCorrectFormatDirection (textDirection, runes.GetRange (lp, i - lp))),
width,
preserveTrailingSpaces,
tabWidth,
@@ -1627,7 +1609,7 @@ public class TextFormatter
}
foreach (string line in WordWrapText (
StringExtensions.ToString (runes.GetRange (lp, runeCount - lp)),
StringExtensions.ToString (PerformCorrectFormatDirection (textDirection, runes.GetRange (lp, runeCount - lp))),
width,
preserveTrailingSpaces,
tabWidth,
@@ -1638,7 +1620,36 @@ public class TextFormatter
lineResult.Add (ClipAndJustify (line, width, justify, textDirection, tabWidth));
}
return lineResult;
return PerformCorrectFormatDirection (textDirection, lineResult);
}
private static string PerformCorrectFormatDirection (TextDirection textDirection, string line)
{
return textDirection switch
{
TextDirection.RightLeft_BottomTop
or TextDirection.RightLeft_TopBottom
or TextDirection.BottomTop_LeftRight
or TextDirection.BottomTop_RightLeft => StringExtensions.ToString (line.EnumerateRunes ().Reverse ()),
_ => line
};
}
private static List<Rune> PerformCorrectFormatDirection (TextDirection textDirection, List<Rune> runes)
{
return PerformCorrectFormatDirection (textDirection, StringExtensions.ToString (runes)).ToRuneList ();
}
private static List<string> PerformCorrectFormatDirection (TextDirection textDirection, List<string> lines)
{
return textDirection switch
{
TextDirection.TopBottom_RightLeft
or TextDirection.LeftRight_BottomTop
or TextDirection.RightLeft_BottomTop
or TextDirection.BottomTop_RightLeft => lines.ToArray ().Reverse ().ToList (),
_ => lines
};
}
/// <summary>Returns the number of lines needed to render the specified text given the width.</summary>
@@ -1705,43 +1716,6 @@ public class TextFormatter
return result.Max (x => GetRuneWidth (x, tabWidth));
}
/// <summary>
/// Returns the number of columns in the widest line in the list based on the <paramref name="startIndex"/> and
/// the <paramref name="length"/>.
/// </summary>
/// <remarks>
/// This API will return incorrect results if the text includes glyphs who's width is dependent on surrounding
/// glyphs (e.g. Arabic).
/// </remarks>
/// <param name="lines">The lines.</param>
/// <param name="startIndex">The start index.</param>
/// <param name="length">The length.</param>
/// <param name="tabWidth">The number of columns used for a tab.</param>
/// <returns>The maximum characters width.</returns>
public static int GetWidestLineLength (
List<string> lines,
int startIndex = -1,
int length = -1,
int tabWidth = 0
)
{
var max = 0;
for (int i = startIndex == -1 ? 0 : startIndex;
i < (length == -1 ? lines.Count : startIndex + length);
i++)
{
string runes = lines [i];
if (runes.Length > 0)
{
max += runes.EnumerateRunes ().Max (r => GetRuneWidth (r, tabWidth));
}
}
return max;
}
/// <summary>
/// Gets the maximum number of columns from the text based on the <paramref name="startIndex"/> and the
/// <paramref name="length"/>.

View File

@@ -34,33 +34,31 @@ public class DimAutoDemo : Scenario
};
view.Add (textEdit);
var hlabel = new Label
{
Text = textEdit.Text,
X = Pos.Left (textEdit) + 1,
Y = Pos.Bottom (textEdit),
AutoSize = false,
Width = Auto (DimAutoStyle.Text, 20),
Height = 1,
ColorScheme = Colors.ColorSchemes ["Error"]
};
view.Add (hlabel);
var vlabel = new Label
{
Text = textEdit.Text,
X = Pos.Left (textEdit),
Y = Pos.Bottom (textEdit) + 1,
AutoSize = false,
Width = 1,
Width = Auto (DimAutoStyle.Text, 1),
Height = Auto (DimAutoStyle.Text, 8),
ColorScheme = Colors.ColorSchemes ["Error"]
//TextDirection = TextDirection.TopBottom_LeftRight
ColorScheme = Colors.ColorSchemes ["Error"],
TextDirection = TextDirection.TopBottom_LeftRight
};
vlabel.Id = "vlabel";
view.Add (vlabel);
var hlabel = new Label
{
Text = textEdit.Text,
X = Pos.Right (vlabel) + 1,
Y = Pos.Bottom (textEdit),
Width = Auto (DimAutoStyle.Text, 20),
Height = Auto (DimAutoStyle.Text, 1),
ColorScheme = Colors.ColorSchemes ["Error"]
};
hlabel.Id = "hlabel";
view.Add (hlabel);
var heightAuto = new View
{
X = Pos.Right (vlabel) + 1,

View File

@@ -33,7 +33,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = 1,
Y = 1,
AutoSize = false,
Width = 9,
Height = 1,
TextAlignment = TextAlignment.Right,
@@ -45,7 +44,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = 1,
Y = 2,
AutoSize = false,
Width = 9,
Height = 1,
TextAlignment = TextAlignment.Right,
@@ -57,7 +55,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = 1,
Y = 3,
AutoSize = false,
Width = 9,
Height = 1,
TextAlignment = TextAlignment.Right,
@@ -69,7 +66,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = 1,
Y = 4,
AutoSize = false,
Width = 9,
Height = 1,
TextAlignment = TextAlignment.Right,
@@ -81,7 +77,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = Pos.Right (labelHL) + 1,
Y = Pos.Y (labelHL),
AutoSize = false,
Width = Dim.Fill (1) - 9,
Height = 1,
ColorScheme = color1,
@@ -93,7 +88,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = Pos.Right (labelHC) + 1,
Y = Pos.Y (labelHC),
AutoSize = false,
Width = Dim.Fill (1) - 9,
Height = 1,
ColorScheme = color2,
@@ -105,7 +99,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = Pos.Right (labelHR) + 1,
Y = Pos.Y (labelHR),
AutoSize = false,
Width = Dim.Fill (1) - 9,
Height = 1,
ColorScheme = color1,
@@ -117,7 +110,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = Pos.Right (labelHJ) + 1,
Y = Pos.Y (labelHJ),
AutoSize = false,
Width = Dim.Fill (1) - 9,
Height = 1,
ColorScheme = color2,
@@ -145,7 +137,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = Pos.AnchorEnd (8),
Y = 1,
AutoSize = false,
Width = 2,
Height = 9,
ColorScheme = color1,
@@ -153,12 +144,12 @@ public class TextAlignmentsAndDirections : Scenario
VerticalTextAlignment = VerticalTextAlignment.Bottom,
Text = "Top"
};
labelVT.TextFormatter.WordWrap = false;
var labelVM = new Label
{
X = Pos.AnchorEnd (6),
Y = 1,
AutoSize = false,
Width = 2,
Height = 9,
ColorScheme = color1,
@@ -166,12 +157,12 @@ public class TextAlignmentsAndDirections : Scenario
VerticalTextAlignment = VerticalTextAlignment.Bottom,
Text = "Middle"
};
labelVM.TextFormatter.WordWrap = false;
var labelVB = new Label
{
X = Pos.AnchorEnd (4),
Y = 1,
AutoSize = false,
Width = 2,
Height = 9,
ColorScheme = color1,
@@ -179,71 +170,72 @@ public class TextAlignmentsAndDirections : Scenario
VerticalTextAlignment = VerticalTextAlignment.Bottom,
Text = "Bottom"
};
labelVB.TextFormatter.WordWrap = false;
var labelVJ = new Label
{
X = Pos.AnchorEnd (2),
Y = 1,
AutoSize = false,
Width = 1,
Width = 2,
Height = 9,
ColorScheme = color1,
TextDirection = TextDirection.TopBottom_LeftRight,
VerticalTextAlignment = VerticalTextAlignment.Bottom,
Text = "Justified"
};
labelVJ.TextFormatter.WordWrap = false;
var txtLabelVT = new Label
{
X = Pos.X (labelVT),
Y = Pos.Bottom (labelVT) + 1,
AutoSize = false,
Width = 1,
Width = 2,
Height = Dim.Fill (1),
ColorScheme = color1,
TextDirection = TextDirection.TopBottom_LeftRight,
VerticalTextAlignment = VerticalTextAlignment.Top,
Text = txt
};
txtLabelVT.TextFormatter.WordWrap = false;
var txtLabelVM = new Label
{
X = Pos.X (labelVM),
Y = Pos.Bottom (labelVM) + 1,
AutoSize = false,
Width = 1,
Width = 2,
Height = Dim.Fill (1),
ColorScheme = color2,
TextDirection = TextDirection.TopBottom_LeftRight,
VerticalTextAlignment = VerticalTextAlignment.Middle,
Text = txt
};
txtLabelVM.TextFormatter.WordWrap = false;
var txtLabelVB = new Label
{
X = Pos.X (labelVB),
Y = Pos.Bottom (labelVB) + 1,
AutoSize = false,
Width = 1,
Width = 2,
Height = Dim.Fill (1),
ColorScheme = color1,
TextDirection = TextDirection.TopBottom_LeftRight,
VerticalTextAlignment = VerticalTextAlignment.Bottom,
Text = txt
};
txtLabelVB.TextFormatter.WordWrap = false;
var txtLabelVJ = new Label
{
X = Pos.X (labelVJ),
Y = Pos.Bottom (labelVJ) + 1,
AutoSize = false,
Width = 1,
Width = 2,
Height = Dim.Fill (1),
ColorScheme = color2,
TextDirection = TextDirection.TopBottom_LeftRight,
VerticalTextAlignment = VerticalTextAlignment.Justified,
Text = txt
};
txtLabelVJ.TextFormatter.WordWrap = false;
txts.Add (txtLabelVT);
txts.Add (txtLabelVM);
@@ -266,7 +258,7 @@ public class TextAlignmentsAndDirections : Scenario
X = 0,
Y = Pos.Bottom (txtLabelHJ),
Width = Dim.Fill (31),
Height = Dim.Fill (6),
Height = Dim.Fill (4),
ColorScheme = color2
};
@@ -274,7 +266,6 @@ public class TextAlignmentsAndDirections : Scenario
{
X = 1 /* */,
Y = 1,
AutoSize = false,
Width = Dim.Percent (100f / 3f),
Height = Dim.Percent (100f / 3f),
TextAlignment = TextAlignment.Left,
@@ -282,12 +273,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelTL.TextFormatter.MultiLine = true;
var txtLabelTC = new Label
{
X = Pos.Right (txtLabelTL) + 2,
Y = 1,
AutoSize = false,
Width = Dim.Percent (100f / 3f),
Height = Dim.Percent (100f / 3f),
TextAlignment = TextAlignment.Centered,
@@ -295,12 +286,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelTC.TextFormatter.MultiLine = true;
var txtLabelTR = new Label
{
X = Pos.Right (txtLabelTC) + 2,
Y = 1,
AutoSize = false,
Width = Dim.Percent (100f, true),
Height = Dim.Percent (100f / 3f),
TextAlignment = TextAlignment.Right,
@@ -308,12 +299,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelTR.TextFormatter.MultiLine = true;
var txtLabelML = new Label
{
X = Pos.X (txtLabelTL),
Y = Pos.Bottom (txtLabelTL) + 1,
AutoSize = false,
Width = Dim.Width (txtLabelTL),
Height = Dim.Percent (100f / 3f),
TextAlignment = TextAlignment.Left,
@@ -321,12 +312,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelML.TextFormatter.MultiLine = true;
var txtLabelMC = new Label
{
X = Pos.X (txtLabelTC),
Y = Pos.Bottom (txtLabelTC) + 1,
AutoSize = false,
Width = Dim.Width (txtLabelTC),
Height = Dim.Percent (100f / 3f),
TextAlignment = TextAlignment.Centered,
@@ -334,12 +325,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelMC.TextFormatter.MultiLine = true;
var txtLabelMR = new Label
{
X = Pos.X (txtLabelTR),
Y = Pos.Bottom (txtLabelTR) + 1,
AutoSize = false,
Width = Dim.Percent (100f, true),
Height = Dim.Percent (100f / 3f),
TextAlignment = TextAlignment.Right,
@@ -347,12 +338,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelMR.TextFormatter.MultiLine = true;
var txtLabelBL = new Label
{
X = Pos.X (txtLabelML),
Y = Pos.Bottom (txtLabelML) + 1,
AutoSize = false,
Width = Dim.Width (txtLabelML),
Height = Dim.Percent (100f, true),
TextAlignment = TextAlignment.Left,
@@ -360,12 +351,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelBL.TextFormatter.MultiLine = true;
var txtLabelBC = new Label
{
X = Pos.X (txtLabelMC),
Y = Pos.Bottom (txtLabelMC) + 1,
AutoSize = false,
Width = Dim.Width (txtLabelMC),
Height = Dim.Percent (100f, true),
TextAlignment = TextAlignment.Centered,
@@ -373,12 +364,12 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelBC.TextFormatter.MultiLine = true;
var txtLabelBR = new Label
{
X = Pos.X (txtLabelMR),
Y = Pos.Bottom (txtLabelMR) + 1,
AutoSize = false,
Width = Dim.Percent (100f, true),
Height = Dim.Percent (100f, true),
TextAlignment = TextAlignment.Right,
@@ -386,6 +377,7 @@ public class TextAlignmentsAndDirections : Scenario
ColorScheme = color1,
Text = txt
};
txtLabelBR.TextFormatter.MultiLine = true;
mtxts.Add (txtLabelTL);
mtxts.Add (txtLabelTC);
@@ -465,42 +457,77 @@ public class TextAlignmentsAndDirections : Scenario
{
X = Pos.Right (container) + 1,
Y = Pos.Y (container) + 1,
AutoSize = false,
Width = Dim.Fill (10),
Height = 1,
Text = "Justify"
};
justifyCheckbox.Toggled += (s, e) =>
{
if (e.OldValue == true)
{
foreach (Label t in mtxts)
{
t.TextAlignment = (TextAlignment)((dynamic)t.Data).h;
t.VerticalTextAlignment = (VerticalTextAlignment)((dynamic)t.Data).v;
}
}
else
{
foreach (Label t in mtxts)
{
if (TextFormatter.IsVerticalDirection (t.TextDirection))
{
t.VerticalTextAlignment = VerticalTextAlignment.Justified;
t.TextAlignment = ((dynamic)t.Data).h;
}
else
{
t.TextAlignment = TextAlignment.Justified;
t.VerticalTextAlignment = ((dynamic)t.Data).v;
}
}
}
};
justifyCheckbox.Toggled += (s, e) => ToggleJustify (e.OldValue is { } && (bool)e.OldValue);
app.Add (justifyCheckbox);
// WRAP CHECKBOX
var wrapCheckbox = new CheckBox
{
X = Pos.Right (container) + 1,
Y = Pos.Y (justifyCheckbox) + 1,
Width = Dim.Fill (10),
Height = 1,
Text = "Word Wrap",
};
wrapCheckbox.Checked = wrapCheckbox.TextFormatter.WordWrap;
wrapCheckbox.Toggled += (s, e) =>
{
if (e.OldValue == true)
{
foreach (Label t in mtxts)
{
t.TextFormatter.WordWrap = false;
}
}
else
{
foreach (Label t in mtxts)
{
t.TextFormatter.WordWrap = true;
}
}
};
app.Add (wrapCheckbox);
// AUTOSIZE CHECKBOX
var autoSizeCheckbox = new CheckBox
{
X = Pos.Right (container) + 1,
Y = Pos.Y (wrapCheckbox) + 1,
Width = Dim.Fill (10),
Height = 1,
Text = "AutoSize",
};
autoSizeCheckbox.Checked = autoSizeCheckbox.TextFormatter.AutoSize;
autoSizeCheckbox.Toggled += (s, e) =>
{
if (e.OldValue == true)
{
foreach (Label t in mtxts)
{
t.TextFormatter.AutoSize = false;
}
}
else
{
foreach (Label t in mtxts)
{
t.TextFormatter.AutoSize = true;
}
}
};
app.Add (autoSizeCheckbox);
// Direction Options
List<TextDirection> directionsEnum = Enum.GetValues (typeof (TextDirection)).Cast<TextDirection> ().ToList ();
@@ -508,7 +535,7 @@ public class TextAlignmentsAndDirections : Scenario
var directionOptions = new RadioGroup
{
X = Pos.Right (container) + 1,
Y = Pos.Bottom (justifyCheckbox) + 1,
Y = Pos.Bottom (autoSizeCheckbox) + 1,
Width = Dim.Fill (10),
Height = Dim.Fill (1),
HotKeySpecifier = (Rune)'\xffff',
@@ -517,15 +544,52 @@ public class TextAlignmentsAndDirections : Scenario
directionOptions.SelectedItemChanged += (s, ev) =>
{
var justChecked = justifyCheckbox.Checked is { } && (bool)justifyCheckbox.Checked;
if (justChecked)
{
ToggleJustify (true);
}
foreach (Label v in mtxts)
{
v.TextDirection = (TextDirection)ev.SelectedItem;
}
if (justChecked)
{
ToggleJustify (false);
}
};
app.Add (directionOptions);
Application.Run (app);
app.Dispose ();
void ToggleJustify (bool oldValue)
{
if (oldValue == true)
{
foreach (Label t in mtxts)
{
t.TextAlignment = (TextAlignment)((dynamic)t.Data).h;
t.VerticalTextAlignment = (VerticalTextAlignment)((dynamic)t.Data).v;
}
}
else
{
foreach (Label t in mtxts)
{
if (TextFormatter.IsVerticalDirection (t.TextDirection))
{
t.VerticalTextAlignment = VerticalTextAlignment.Justified;
t.TextAlignment = ((dynamic)t.Data).h;
}
else
{
t.TextAlignment = TextAlignment.Justified;
t.VerticalTextAlignment = ((dynamic)t.Data).v;
}
}
}
}
}
}

View File

@@ -3639,6 +3639,214 @@ ek")]
TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
}
[SetupFakeDriver]
[Theory]
[InlineData ("A", 0, 1, false, "", 0)]
[InlineData ("A", 1, 1, false, "A", 0)]
[InlineData ("A", 2, 2, false, " A", 1)]
[InlineData ("AB", 1, 1, false, "B", 0)]
[InlineData ("AB", 2, 2, false, " A\n B", 0)]
[InlineData ("ABC", 3, 2, false, " B\n C", 0)]
[InlineData ("ABC", 4, 2, false, " B\n C", 0)]
[InlineData ("ABC", 6, 2, false, " B\n C", 0)]
[InlineData ("こんにちは", 0, 1, false, "", 0)]
[InlineData ("こんにちは", 1, 0, false, "", 0)]
[InlineData ("こんにちは", 1, 1, false, "", 0)]
[InlineData ("こんにちは", 2, 1, false, "は", 0)]
[InlineData ("こんにちは", 2, 2, false, "ち\nは", 0)]
[InlineData ("こんにちは", 2, 3, false, "に\nち\nは", 0)]
[InlineData ("こんにちは", 2, 4, false, "ん\nに\nち\nは", 0)]
[InlineData ("こんにちは", 2, 5, false, "こ\nん\nに\nち\nは", 0)]
[InlineData ("こんにちは", 2, 6, false, "こ\nん\nに\nち\nは", 1)]
[InlineData ("ABCD\nこんにちは", 4, 7, false, " こ\n Aん\n Bに\n Cち\n Dは", 2)]
[InlineData ("こんにちは\nABCD", 3, 7, false, "こ \nんA\nにB\nちC\nはD", 2)]
[InlineData ("A", 0, 1, true, "", 0)]
[InlineData ("A", 1, 1, true, "A", 0)]
[InlineData ("A", 2, 2, true, " A", 1)]
[InlineData ("AB", 1, 1, true, "B", 0)]
[InlineData ("AB", 2, 2, true, " A\n B", 0)]
[InlineData ("ABC", 3, 2, true, " B\n C", 0)]
[InlineData ("ABC", 4, 2, true, " B\n C", 0)]
[InlineData ("ABC", 6, 2, true, " B\n C", 0)]
[InlineData ("こんにちは", 0, 1, true, "", 0)]
[InlineData ("こんにちは", 1, 0, true, "", 0)]
[InlineData ("こんにちは", 1, 1, true, "", 0)]
[InlineData ("こんにちは", 2, 1, true, "は", 0)]
[InlineData ("こんにちは", 2, 2, true, "ち\nは", 0)]
[InlineData ("こんにちは", 2, 3, true, "に\nち\nは", 0)]
[InlineData ("こんにちは", 2, 4, true, "ん\nに\nち\nは", 0)]
[InlineData ("こんにちは", 2, 5, true, "こ\nん\nに\nち\nは", 0)]
[InlineData ("こんにちは", 2, 6, true, "こ\nん\nに\nち\nは", 1)]
[InlineData ("ABCD\nこんにちは", 4, 7, true, " こ\n Aん\n Bに\n Cち\n Dは", 2)]
[InlineData ("こんにちは\nABCD", 3, 7, true, "こ \nんA\nにB\nちC\nはD", 2)]
public void Draw_Vertical_Bottom_Horizontal_Right (string text, int width, int height, bool autoSize, string expectedText, int expectedY)
{
TextFormatter tf = new ()
{
Text = text,
Alignment = TextAlignment.Right,
Direction = TextDirection.TopBottom_LeftRight,
VerticalAlignment = VerticalTextAlignment.Bottom,
AutoSize = autoSize,
};
if (!autoSize)
{
tf.Size = new Size (width, height);
}
tf.Draw (new Rectangle (Point.Empty, new (width, height)), Attribute.Default, Attribute.Default);
Rectangle rect = TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
Assert.Equal (expectedY, rect.Y);
}
[SetupFakeDriver]
[Theory]
[InlineData ("A", 5, false, "A")]
[InlineData ("AB12", 5, false, @"
A
B
1
2")]
[InlineData ("AB\n12", 5, false, @"
A1
B2")]
[InlineData ("", 1, false, "")]
[InlineData ("AB1 2", 2, false, @"
A12
B ")]
[InlineData ("こんにちは", 1, false, @"
こん")]
[InlineData ("こんにちは", 2, false, @"
こに
んち")]
[InlineData ("こんにちは", 5, false, @"
は")]
[InlineData ("A", 5, true, "A")]
[InlineData ("AB12", 5, true, @"
A
B
1
2")]
[InlineData ("AB\n12", 5, true, @"
A1
B2")]
[InlineData ("", 1, true, "")]
[InlineData ("AB1 2", 2, true, @"
A
B")]
[InlineData ("こんにちは", 1, true, @"
こ")]
[InlineData ("こんにちは", 2, true, @"
ん")]
[InlineData ("こんにちは", 5, true, @"
は")]
public void Draw_Vertical_TopBottom_LeftRight_Top (string text, int height, bool autoSize, string expectedText)
{
TextFormatter tf = new ()
{
Text = text,
AutoSize = autoSize,
Direction = TextDirection.TopBottom_LeftRight,
};
if (!autoSize)
{
tf.Size = new Size (5, height);
}
tf.Draw (new Rectangle (0, 0, 5, height), Attribute.Default, Attribute.Default);
TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
}
[SetupFakeDriver]
[Theory]
// The expectedY param is to probe that the expectedText param start at that Y coordinate
[InlineData ("A", 0, false, "", 0)]
[InlineData ("A", 1, false, "A", 0)]
[InlineData ("A", 2, false, "A", 0)]
[InlineData ("A", 3, false, "A", 1)]
[InlineData ("AB", 1, false, "A", 0)]
[InlineData ("AB", 2, false, "A\nB", 0)]
[InlineData ("ABC", 2, false, "A\nB", 0)]
[InlineData ("ABC", 3, false, "A\nB\nC", 0)]
[InlineData ("ABC", 4, false, "A\nB\nC", 0)]
[InlineData ("ABC", 5, false, "A\nB\nC", 1)]
[InlineData ("ABC", 6, false, "A\nB\nC", 1)]
[InlineData ("ABC", 9, false, "A\nB\nC", 3)]
[InlineData ("ABCD", 2, false, "B\nC", 0)]
[InlineData ("こんにちは", 0, false, "", 0)]
[InlineData ("こんにちは", 1, false, "に", 0)]
[InlineData ("こんにちは", 2, false, "ん\nに", 0)]
[InlineData ("こんにちは", 3, false, "ん\nに\nち", 0)]
[InlineData ("こんにちは", 4, false, "こ\nん\nに\nち", 0)]
[InlineData ("こんにちは", 5, false, "こ\nん\nに\nち\nは", 0)]
[InlineData ("こんにちは", 6, false, "こ\nん\nに\nち\nは", 0)]
[InlineData ("ABCD\nこんにちは", 7, false, "Aこ\nBん\nCに\nDち\n は", 1)]
[InlineData ("こんにちは\nABCD", 7, false, "こA\nんB\nにC\nちD\nは ", 1)]
[InlineData ("A", 0, true, "", 0)]
[InlineData ("A", 1, true, "A", 0)]
[InlineData ("A", 2, true, "A", 0)]
[InlineData ("A", 3, true, "A", 1)]
[InlineData ("AB", 1, true, "A", 0)]
[InlineData ("AB", 2, true, "A\nB", 0)]
[InlineData ("ABC", 2, true, "A\nB", 0)]
[InlineData ("ABC", 3, true, "A\nB\nC", 0)]
[InlineData ("ABC", 4, true, "A\nB\nC", 0)]
[InlineData ("ABC", 5, true, "A\nB\nC", 1)]
[InlineData ("ABC", 6, true, "A\nB\nC", 1)]
[InlineData ("ABC", 9, true, "A\nB\nC", 3)]
[InlineData ("ABCD", 2, true, "B\nC", 0)]
[InlineData ("こんにちは", 0, true, "", 0)]
[InlineData ("こんにちは", 1, true, "に", 0)]
[InlineData ("こんにちは", 2, true, "ん\nに", 0)]
[InlineData ("こんにちは", 3, true, "ん\nに\nち", 0)]
[InlineData ("こんにちは", 4, true, "こ\nん\nに\nち", 0)]
[InlineData ("こんにちは", 5, true, "こ\nん\nに\nち\nは", 0)]
[InlineData ("こんにちは", 6, true, "こ\nん\nに\nち\nは", 0)]
[InlineData ("こんにちは", 7, true, "こ\nん\nに\nち\nは", 1)]
[InlineData ("ABCD\nこんにちは", 7, true, "Aこ\nBん\nCに\nDち\n は", 1)]
[InlineData ("こんにちは\nABCD", 7, true, "こA\nんB\nにC\nちD\nは ", 1)]
public void Draw_Vertical_TopBottom_LeftRight_Middle (string text, int height, bool autoSize, string expectedText, int expectedY)
{
TextFormatter tf = new ()
{
Text = text,
Direction = TextDirection.TopBottom_LeftRight,
VerticalAlignment = VerticalTextAlignment.Middle,
AutoSize = autoSize,
};
if (!autoSize)
{
int width = text.ToRunes ().Max (r => r.GetColumns ());
if (text.Contains ("\n"))
{
width++;
}
tf.Size = new Size (width, height);
}
tf.Draw (new Rectangle (0, 0, 5, height), Attribute.Default, Attribute.Default);
Rectangle rect = TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
Assert.Equal (expectedY, rect.Y);
}
[Theory]
[InlineData ("1234", 4)]
@@ -3665,6 +3873,178 @@ ek")]
Assert.Equal (new (1, expected), tf.Size);
}
[SetupFakeDriver]
[Theory]
[InlineData ("A", 1, 0, false, "")]
[InlineData ("A", 0, 1, false, "")]
[InlineData ("AB1 2", 2, 1, false, "2")]
[InlineData ("AB12", 5, 1, false, "21BA")]
[InlineData ("AB\n12", 5, 2, false, "BA\n21")]
[InlineData ("ABC 123 456", 7, 2, false, "654 321\nCBA ")]
[InlineData ("こんにちは", 1, 1, false, "")]
[InlineData ("こんにちは", 2, 1, false, "は")]
[InlineData ("こんにちは", 5, 1, false, "はち")]
[InlineData ("こんにちは", 10, 1, false, "はちにんこ")]
[InlineData ("こんにちは\nAB\n12", 10, 3, false, "はちにんこ\nBA \n21 ")]
[InlineData ("A", 1, 0, true, "")]
[InlineData ("A", 0, 1, true, "")]
[InlineData ("AB1 2", 2, 1, true, "2")]
[InlineData ("AB12", 5, 1, true, "21BA")]
[InlineData ("AB\n12", 5, 2, true, "BA\n21")]
[InlineData ("ABC 123 456", 7, 2, true, "654 321")]
[InlineData ("こんにちは", 1, 1, true, "")]
[InlineData ("こんにちは", 2, 1, true, "は")]
[InlineData ("こんにちは", 5, 1, true, "はち")]
[InlineData ("こんにちは", 10, 1, true, "はちにんこ")]
[InlineData ("こんにちは\nAB\n12", 10, 3, true, "はちにんこ\nBA \n21 ")]
public void Draw_Horizontal_RightLeft_TopBottom (string text, int width, int height, bool autoSize, string expectedText)
{
TextFormatter tf = new ()
{
Text = text,
Direction = TextDirection.RightLeft_TopBottom,
AutoSize = autoSize,
};
if (!autoSize)
{
tf.Size = new Size (width, height);
}
tf.Draw (new Rectangle (0, 0, width, height), Attribute.Default, Attribute.Default);
TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
}
[SetupFakeDriver]
[Theory]
[InlineData ("A", 1, 0, false, "")]
[InlineData ("A", 0, 1, false, "")]
[InlineData ("AB1 2", 2, 1, false, "2")]
[InlineData ("AB12", 5, 1, false, "21BA")]
[InlineData ("AB\n12", 5, 2, false, "21\nBA")]
[InlineData ("ABC 123 456", 7, 2, false, "CBA \n654 321")]
[InlineData ("こんにちは", 1, 1, false, "")]
[InlineData ("こんにちは", 2, 1, false, "は")]
[InlineData ("こんにちは", 5, 1, false, "はち")]
[InlineData ("こんにちは", 10, 1, false, "はちにんこ")]
[InlineData ("こんにちは\nAB\n12", 10, 3, false, "21 \nBA \nはちにんこ")]
[InlineData ("A", 1, 0, true, "")]
[InlineData ("A", 0, 1, true, "")]
[InlineData ("AB1 2", 2, 1, true, "2")]
[InlineData ("AB12", 5, 1, true, "21BA")]
[InlineData ("AB\n12", 5, 2, true, "21\nBA")]
[InlineData ("ABC 123 456", 7, 2, true, "654 321")]
[InlineData ("こんにちは", 1, 1, true, "")]
[InlineData ("こんにちは", 2, 1, true, "は")]
[InlineData ("こんにちは", 5, 1, true, "はち")]
[InlineData ("こんにちは", 10, 1, true, "はちにんこ")]
[InlineData ("こんにちは\nAB\n12", 10, 3, true, "21 \nBA \nはちにんこ")]
public void Draw_Horizontal_RightLeft_BottomTop (string text, int width, int height, bool autoSize, string expectedText)
{
TextFormatter tf = new ()
{
Text = text,
Direction = TextDirection.RightLeft_BottomTop,
AutoSize = autoSize,
};
if (!autoSize)
{
tf.Size = new Size (width, height);
}
tf.Draw (new Rectangle (0, 0, width, height), Attribute.Default, Attribute.Default);
TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
}
[SetupFakeDriver]
[Theory]
[InlineData ("A", 1, 0, false, "")]
[InlineData ("A", 0, 1, false, "")]
[InlineData ("AB1 2", 1, 2, false, "2")]
[InlineData ("AB12", 1, 5, false, "2\n1\nB\nA")]
[InlineData ("AB\n12", 2, 5, false, "B2\nA1")]
[InlineData ("ABC 123 456", 2, 7, false, "6C\n5B\n4A\n \n3 \n2 \n1 ")]
[InlineData ("こんにちは", 1, 1, false, "")]
[InlineData ("こんにちは", 2, 1, false, "は")]
[InlineData ("こんにちは", 2, 5, false, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは", 2, 10, false, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは\nAB\n12", 4, 10, false, "はB2\nちA1\nに \nん \nこ ")]
[InlineData ("A", 1, 0, true, "")]
[InlineData ("A", 0, 1, true, "")]
[InlineData ("AB1 2", 1, 2, true, "2")]
[InlineData ("AB12", 1, 5, true, "2\n1\nB\nA")]
[InlineData ("AB\n12", 2, 5, true, "B2\nA1")]
[InlineData ("ABC 123 456", 2, 7, true, "6\n5\n4\n \n3\n2\n1")]
[InlineData ("こんにちは", 1, 1, true, "")]
[InlineData ("こんにちは", 2, 1, true, "は")]
[InlineData ("こんにちは", 2, 5, true, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは", 2, 10, true, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは\nAB\n12", 4, 10, true, "はB2\nちA1\nに \nん \nこ ")]
public void Draw_Vertical_BottomTop_LeftRight (string text, int width, int height, bool autoSize, string expectedText)
{
TextFormatter tf = new ()
{
Text = text,
Direction = TextDirection.BottomTop_LeftRight,
AutoSize = autoSize,
};
if (!autoSize)
{
tf.Size = new Size (width, height);
}
tf.Draw (new Rectangle (0, 0, width, height), Attribute.Default, Attribute.Default);
TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
}
[SetupFakeDriver]
[Theory]
[InlineData ("A", 1, 0, false, "")]
[InlineData ("A", 0, 1, false, "")]
[InlineData ("AB1 2", 1, 2, false, "2")]
[InlineData ("AB12", 1, 5, false, "2\n1\nB\nA")]
[InlineData ("AB\n12", 2, 5, false, "2B\n1A")]
[InlineData ("ABC 123 456", 2, 7, false, "C6\nB5\nA4\n \n 3\n 2\n 1")]
[InlineData ("こんにちは", 1, 1, false, "")]
[InlineData ("こんにちは", 2, 1, false, "は")]
[InlineData ("こんにちは", 2, 5, false, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは", 2, 10, false, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは\nAB\n12", 4, 10, false, "2Bは\n1Aち\n に\n ん\n こ")]
[InlineData ("A", 1, 0, true, "")]
[InlineData ("A", 0, 1, true, "")]
[InlineData ("AB1 2", 1, 2, true, "2")]
[InlineData ("AB12", 1, 5, true, "2\n1\nB\nA")]
[InlineData ("AB\n12", 2, 5, true, "2B\n1A")]
[InlineData ("ABC 123 456", 2, 7, true, "6\n5\n4\n \n3\n2\n1")]
[InlineData ("こんにちは", 1, 1, true, "")]
[InlineData ("こんにちは", 2, 1, true, "は")]
[InlineData ("こんにちは", 2, 5, true, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは", 2, 10, true, "は\nち\nに\nん\nこ")]
[InlineData ("こんにちは\nAB\n12", 4, 10, true, "2Bは\n1Aち\n に\n ん\n こ")]
public void Draw_Vertical_BottomTop_RightLeft (string text, int width, int height, bool autoSize, string expectedText)
{
TextFormatter tf = new ()
{
Text = text,
Direction = TextDirection.BottomTop_RightLeft,
AutoSize = autoSize,
};
if (!autoSize)
{
tf.Size = new Size (width, height);
}
tf.Draw (new Rectangle (0, 0, width, height), Attribute.Default, Attribute.Default);
TestHelpers.AssertDriverContentsWithFrameAre (expectedText, _output);
}
// Draw tests - Note that these depend on View
[Fact]
@@ -3700,10 +4080,10 @@ ek")]
Application.Shutdown ();
}
//TODO: Expand this test to cover Vertical Alignment as well
//FIXED: Expand this test to cover Vertical Alignment as well
[SetupFakeDriver]
[Theory]
[InlineData ("0 2 4", TextAlignment.Left, TextDirection.LeftRight_BottomTop, @"
[InlineData ("0 2 4", TextAlignment.Left, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
0 2 4**
*******
*******
@@ -3711,7 +4091,7 @@ ek")]
*******
*******
*******")]
[InlineData ("0 2 4", TextAlignment.Right, TextDirection.LeftRight_BottomTop, @"
[InlineData ("0 2 4", TextAlignment.Right, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
**0 2 4
*******
*******
@@ -3719,7 +4099,7 @@ ek")]
*******
*******
*******")]
[InlineData ("0 2 4", TextAlignment.Centered, TextDirection.LeftRight_BottomTop, @"
[InlineData ("0 2 4", TextAlignment.Centered, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
*0 2 4*
*******
*******
@@ -3727,8 +4107,7 @@ ek")]
*******
*******
*******")]
[InlineData ("0 2 4", TextAlignment.Justified, TextDirection.LeftRight_BottomTop, @"
[InlineData ("0 2 4", TextAlignment.Justified, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
0 2 4
*******
*******
@@ -3737,23 +4116,7 @@ ek")]
*******
*******")]
[InlineData ("0 2 4", TextAlignment.Left, TextDirection.LeftRight_BottomTop, @"
0 2 4**
*******
*******
*******
*******
*******
*******")]
[InlineData ("0 你 4", TextAlignment.Right, TextDirection.LeftRight_BottomTop, @"
*0 你 4
*******
*******
*******
*******
*******
*******")]
[InlineData ("0 你 4", TextAlignment.Centered, TextDirection.LeftRight_BottomTop, @"
[InlineData ("0 4", TextAlignment.Left, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
0 你 4*
*******
*******
@@ -3761,8 +4124,23 @@ ek")]
*******
*******
*******")]
[InlineData ("0 你 4", TextAlignment.Justified, TextDirection.LeftRight_BottomTop, @"
[InlineData ("0 你 4", TextAlignment.Right, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
*0 你 4
*******
*******
*******
*******
*******
*******")]
[InlineData ("0 你 4", TextAlignment.Centered, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
0 你 4*
*******
*******
*******
*******
*******
*******")]
[InlineData ("0 你 4", TextAlignment.Justified, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"
0 你 4
*******
*******
@@ -3770,11 +4148,78 @@ ek")]
*******
*******
*******")]
public void Draw_Text_Alignment (string text, TextAlignment horizontalTextAlignment, TextDirection textDirection, string expectedText)
[InlineData ("0 2 4", TextAlignment.Left, VerticalTextAlignment.Top, TextDirection.TopBottom_RightLeft, @"
0******
******
2******
******
4******
*******
*******")]
[InlineData ("0 2 4", TextAlignment.Left, VerticalTextAlignment.Bottom, TextDirection.TopBottom_RightLeft, @"
*******
*******
0******
******
2******
******
4******")]
[InlineData ("0 2 4", TextAlignment.Left, VerticalTextAlignment.Middle, TextDirection.TopBottom_RightLeft, @"
*******
0******
******
2******
******
4******
*******")]
[InlineData ("0 2 4", TextAlignment.Left, VerticalTextAlignment.Justified, TextDirection.TopBottom_RightLeft, @"
0******
******
******
2******
******
******
4******")]
[InlineData ("0 你 4", TextAlignment.Left, VerticalTextAlignment.Top, TextDirection.TopBottom_RightLeft, @"
0******
******
你*****
******
4******
*******
*******")]
[InlineData ("0 你 4", TextAlignment.Left, VerticalTextAlignment.Bottom, TextDirection.TopBottom_RightLeft, @"
*******
*******
0******
******
你*****
******
4******")]
[InlineData ("0 你 4", TextAlignment.Left, VerticalTextAlignment.Middle, TextDirection.TopBottom_RightLeft, @"
*******
0******
******
你*****
******
4******
*******")]
[InlineData ("0 你 4", TextAlignment.Left, VerticalTextAlignment.Justified, TextDirection.TopBottom_RightLeft, @"
0******
******
******
你*****
******
******
4******")]
public void Draw_Text_Alignment (string text, TextAlignment horizontalTextAlignment, VerticalTextAlignment verticalTextAlignment, TextDirection textDirection, string expectedText)
{
TextFormatter tf = new ()
{
Alignment = horizontalTextAlignment,
VerticalAlignment = verticalTextAlignment,
Direction = textDirection,
Size = new (7, 7),
Text = text