From 253fcf195b0bcc865a8078d98169cb106bc01b03 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 29 Apr 2024 13:20:13 +0100 Subject: [PATCH 01/10] Replace with GetColumnsRequiredForVerticalText. --- Terminal.Gui/Text/TextFormatter.cs | 48 ++++-------------------------- 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/Terminal.Gui/Text/TextFormatter.cs b/Terminal.Gui/Text/TextFormatter.cs index d9bba800d..4acc14554 100644 --- a/Terminal.Gui/Text/TextFormatter.cs +++ b/Terminal.Gui/Text/TextFormatter.cs @@ -345,7 +345,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 +361,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 +376,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); } @@ -467,7 +468,7 @@ public class TextFormatter } if ((!isVertical && current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset) - || (isVertical && idx > maxScreen.Top + maxScreen.Height - screen.Y)) + || (isVertical && current > start + size + zeroLengthCount && idx > maxScreen.Top + maxScreen.Height - screen.Y)) { break; } @@ -1705,43 +1706,6 @@ public class TextFormatter return result.Max (x => GetRuneWidth (x, tabWidth)); } - /// - /// Returns the number of columns in the widest line in the list based on the and - /// the . - /// - /// - /// This API will return incorrect results if the text includes glyphs who's width is dependent on surrounding - /// glyphs (e.g. Arabic). - /// - /// The lines. - /// The start index. - /// The length. - /// The number of columns used for a tab. - /// The maximum characters width. - public static int GetWidestLineLength ( - List 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; - } - /// /// Gets the maximum number of columns from the text based on the and the /// . From d3b47adc861c58e13b2302688790c4557b9fcc7c Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 29 Apr 2024 13:21:50 +0100 Subject: [PATCH 02/10] Improving scenario. --- .../Scenarios/TextAlignmentsAndDirection.cs | 156 +++++++++++------- 1 file changed, 95 insertions(+), 61 deletions(-) diff --git a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs index 52c7c5b5e..f70501034 100644 --- a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs +++ b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs @@ -35,7 +35,6 @@ public class TextAlignmentsAndDirections : Scenario { X = 1, Y = 1, - AutoSize = false, Width = 9, Height = 1, TextAlignment = TextAlignment.Right, @@ -47,7 +46,6 @@ public class TextAlignmentsAndDirections : Scenario { X = 1, Y = 2, - AutoSize = false, Width = 9, Height = 1, TextAlignment = TextAlignment.Right, @@ -59,7 +57,6 @@ public class TextAlignmentsAndDirections : Scenario { X = 1, Y = 3, - AutoSize = false, Width = 9, Height = 1, TextAlignment = TextAlignment.Right, @@ -71,7 +68,6 @@ public class TextAlignmentsAndDirections : Scenario { X = 1, Y = 4, - AutoSize = false, Width = 9, Height = 1, TextAlignment = TextAlignment.Right, @@ -83,7 +79,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, @@ -95,7 +90,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, @@ -107,7 +101,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, @@ -119,7 +112,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, @@ -147,7 +139,6 @@ public class TextAlignmentsAndDirections : Scenario { X = Pos.AnchorEnd (8), Y = 1, - AutoSize = false, Width = 2, Height = 9, ColorScheme = color1, @@ -155,12 +146,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, @@ -168,84 +159,84 @@ 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, TextDirection = TextDirection.TopBottom_LeftRight, 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); @@ -268,7 +259,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 }; @@ -276,7 +267,6 @@ public class TextAlignmentsAndDirections : Scenario { X = 1 /* */, Y = 1, - AutoSize = false, Width = Dim.Percent (100f / 3f), Height = Dim.Percent (100f / 3f), TextAlignment = TextAlignment.Left, @@ -284,12 +274,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, @@ -297,12 +287,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, @@ -310,12 +300,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, @@ -323,12 +313,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, @@ -336,12 +326,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, @@ -349,12 +339,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, @@ -362,12 +352,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, @@ -375,12 +365,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, @@ -388,6 +378,7 @@ public class TextAlignmentsAndDirections : Scenario ColorScheme = color1, Text = txt }; + txtLabelBR.TextFormatter.MultiLine = true; mtxts.Add (txtLabelTL); mtxts.Add (txtLabelTC); @@ -467,42 +458,48 @@ 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, + AutoSize = false, + Width = Dim.Fill (10), + Height = 1, + Text = "Word Wrap", + Checked = true + }; + + 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); + // Direction Options List directionsEnum = Enum.GetValues (typeof (TextDirection)).Cast ().ToList (); @@ -510,7 +507,7 @@ public class TextAlignmentsAndDirections : Scenario var directionOptions = new RadioGroup { X = Pos.Right (container) + 1, - Y = Pos.Bottom (justifyCheckbox) + 1, + Y = Pos.Bottom (wrapCheckbox) + 1, Width = Dim.Fill (10), Height = Dim.Fill (1), HotKeySpecifier = (Rune)'\xffff', @@ -519,15 +516,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; + } + } + } + } } } From d66a28e9e6222d3973dbc8dea2b4e018e5e267da Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 29 Apr 2024 13:22:45 +0100 Subject: [PATCH 03/10] Add more unit tests. --- UnitTests/Text/TextFormatterTests.cs | 208 +++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index a879c9d5d..ef54b187e 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -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)] From 6dff7d8e4c9cc6940370e2a1744230112b06a507 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 29 Apr 2024 19:07:53 +0100 Subject: [PATCH 04/10] Fix vertical bottom label. --- UICatalog/Scenarios/TextAlignmentsAndDirection.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs index f70501034..eb21159d4 100644 --- a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs +++ b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs @@ -165,6 +165,7 @@ public class TextAlignmentsAndDirections : Scenario { X = Pos.AnchorEnd (4), Y = 1, + Width = 2, Height = 9, ColorScheme = color1, TextDirection = TextDirection.TopBottom_LeftRight, From b7293e0470ec37d056d9609487818bcb0b1bdce2 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 29 Apr 2024 23:21:32 +0100 Subject: [PATCH 05/10] Performing text reverse during formatting instead during drawing. --- Terminal.Gui/Text/TextFormatter.cs | 70 ++++++----- UnitTests/Text/TextFormatterTests.cs | 172 +++++++++++++++++++++++++++ 2 files changed, 212 insertions(+), 30 deletions(-) diff --git a/Terminal.Gui/Text/TextFormatter.cs b/Terminal.Gui/Text/TextFormatter.cs index 4acc14554..ba2182f77 100644 --- a/Terminal.Gui/Text/TextFormatter.cs +++ b/Terminal.Gui/Text/TextFormatter.cs @@ -269,17 +269,6 @@ public class TextFormatter List 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; @@ -467,8 +447,8 @@ public class TextFormatter break; } - if ((!isVertical && current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset) - || (isVertical && current > start + size + zeroLengthCount && 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; } @@ -1368,7 +1348,7 @@ public class TextFormatter { return StringExtensions.ToString ( runes.GetRange ( - index, + Math.Max (index, 0), GetLengthThatFits (text, width, tabWidth, textDirection) ) ); @@ -1581,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 runes = StripCRLF (text, true).ToRuneList (); @@ -1605,7 +1586,7 @@ public class TextFormatter { List wrappedLines = WordWrapText ( - StringExtensions.ToString (runes.GetRange (lp, i - lp)), + StringExtensions.ToString (PerformCorrectFormatDirection (textDirection, runes.GetRange (lp, i - lp))), width, preserveTrailingSpaces, tabWidth, @@ -1628,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, @@ -1639,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 PerformCorrectFormatDirection (TextDirection textDirection, List runes) + { + return PerformCorrectFormatDirection (textDirection, StringExtensions.ToString (runes)).ToRuneList (); + } + + private static List PerformCorrectFormatDirection (TextDirection textDirection, List lines) + { + return textDirection switch + { + TextDirection.TopBottom_RightLeft + or TextDirection.LeftRight_BottomTop + or TextDirection.RightLeft_BottomTop + or TextDirection.BottomTop_RightLeft => lines.ToArray ().Reverse ().ToList (), + _ => lines + }; } /// Returns the number of lines needed to render the specified text given the width. diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index ef54b187e..799e33fe1 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -3872,4 +3872,176 @@ B")] }; 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); + } } From b64e2d1f4f3de9cb519d0cb529430a967e4c0eb5 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 30 Apr 2024 12:36:32 +0100 Subject: [PATCH 06/10] Remove AutoSize and improve a bit. --- UICatalog/Scenarios/DimAutoDemo.cs | 32 ++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/UICatalog/Scenarios/DimAutoDemo.cs b/UICatalog/Scenarios/DimAutoDemo.cs index 0c852cc3d..09d09ac93 100644 --- a/UICatalog/Scenarios/DimAutoDemo.cs +++ b/UICatalog/Scenarios/DimAutoDemo.cs @@ -30,33 +30,31 @@ public class DimAutoDemo : Scenario var textEdit = new TextView { Text = "", X = 1, Y = 0, Width = 20, Height = 4 }; 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, From 9f1f2c7dac78e64c13d05550c8c0636d6c1f80de Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 30 Apr 2024 12:55:39 +0100 Subject: [PATCH 07/10] Remove View AutoSize and add TextFormatter.AutoSize. --- .../Scenarios/TextAlignmentsAndDirection.cs | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs index eb21159d4..77b41ec1b 100644 --- a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs +++ b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs @@ -474,13 +474,11 @@ public class TextAlignmentsAndDirections : Scenario { X = Pos.Right (container) + 1, Y = Pos.Y (justifyCheckbox) + 1, - AutoSize = false, Width = Dim.Fill (10), Height = 1, Text = "Word Wrap", - Checked = true }; - + wrapCheckbox.Checked = wrapCheckbox.TextFormatter.WordWrap; wrapCheckbox.Toggled += (s, e) => { if (e.OldValue == true) @@ -501,6 +499,37 @@ public class TextAlignmentsAndDirections : Scenario 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 directionsEnum = Enum.GetValues (typeof (TextDirection)).Cast ().ToList (); @@ -508,7 +537,7 @@ public class TextAlignmentsAndDirections : Scenario var directionOptions = new RadioGroup { X = Pos.Right (container) + 1, - Y = Pos.Bottom (wrapCheckbox) + 1, + Y = Pos.Bottom (autoSizeCheckbox) + 1, Width = Dim.Fill (10), Height = Dim.Fill (1), HotKeySpecifier = (Rune)'\xffff', From 96af3564288b71538f0d85aaae69a6a07375543e Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 30 Apr 2024 21:02:50 +0100 Subject: [PATCH 08/10] Fix unit test. --- UnitTests/Text/TextFormatterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index c2d987215..ffcdd825d 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -4117,8 +4117,8 @@ B")] ******* *******")] - [InlineData ("0 2 4", TextAlignment.Left, TextDirection.LeftRight_BottomTop, @" -0 2 4** + [InlineData ("0 你 4", TextAlignment.Left, TextDirection.LeftRight_BottomTop, @" +0 你 4* ******* ******* ******* From d1189648da1e775a87ac3562d408a4b37ca0defa Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 30 Apr 2024 22:17:49 +0100 Subject: [PATCH 09/10] Add vertical unit tests to the Draw_Text_Alignment method. --- UnitTests/Text/TextFormatterTests.cs | 87 ++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 11 deletions(-) diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index ffcdd825d..428aca003 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -4083,7 +4083,7 @@ B")] //TODO: 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** ******* ******* @@ -4091,7 +4091,7 @@ B")] ******* ******* *******")] - [InlineData ("0 2 4", TextAlignment.Right, TextDirection.LeftRight_BottomTop, @" + [InlineData ("0 2 4", TextAlignment.Right, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @" **0 2 4 ******* ******* @@ -4099,7 +4099,7 @@ B")] ******* ******* *******")] - [InlineData ("0 2 4", TextAlignment.Centered, TextDirection.LeftRight_BottomTop, @" + [InlineData ("0 2 4", TextAlignment.Centered, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @" *0 2 4* ******* ******* @@ -4107,8 +4107,7 @@ B")] ******* ******* *******")] - - [InlineData ("0 2 4", TextAlignment.Justified, TextDirection.LeftRight_BottomTop, @" + [InlineData ("0 2 4", TextAlignment.Justified, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @" 0 2 4 ******* ******* @@ -4117,7 +4116,7 @@ B")] ******* *******")] - [InlineData ("0 你 4", TextAlignment.Left, TextDirection.LeftRight_BottomTop, @" + [InlineData ("0 你 4", TextAlignment.Left, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @" 0 你 4* ******* ******* @@ -4125,7 +4124,7 @@ B")] ******* ******* *******")] - [InlineData ("0 你 4", TextAlignment.Right, TextDirection.LeftRight_BottomTop, @" + [InlineData ("0 你 4", TextAlignment.Right, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @" *0 你 4 ******* ******* @@ -4133,7 +4132,7 @@ B")] ******* ******* *******")] - [InlineData ("0 你 4", TextAlignment.Centered, TextDirection.LeftRight_BottomTop, @" + [InlineData ("0 你 4", TextAlignment.Centered, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @" 0 你 4* ******* ******* @@ -4141,8 +4140,7 @@ B")] ******* ******* *******")] - - [InlineData ("0 你 4", TextAlignment.Justified, TextDirection.LeftRight_BottomTop, @" + [InlineData ("0 你 4", TextAlignment.Justified, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @" 0 你 4 ******* ******* @@ -4150,11 +4148,78 @@ B")] ******* ******* *******")] - 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 From 5031faaa505ffacdd8d98dc3066f513c266b7dc6 Mon Sep 17 00:00:00 2001 From: BDisp Date: Tue, 30 Apr 2024 22:23:33 +0100 Subject: [PATCH 10/10] Change TODO to FIXED. --- UnitTests/Text/TextFormatterTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs index 428aca003..a3c655da6 100644 --- a/UnitTests/Text/TextFormatterTests.cs +++ b/UnitTests/Text/TextFormatterTests.cs @@ -4080,7 +4080,7 @@ B")] 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, VerticalTextAlignment.Top, TextDirection.LeftRight_BottomTop, @"