From c78451d4cf1d89c800e72413e29d900ce284c8a3 Mon Sep 17 00:00:00 2001 From: ig Date: Tue, 20 Jun 2023 14:26:48 +0200 Subject: [PATCH] new implementation of TextBlock --- .../App/SaliMax/src/{AsciiArt.cs => Flow.cs} | 43 ++- csharp/App/SaliMax/src/Program.cs | 1 - csharp/Lib/Utils/TextBlock.cs | 284 ++++++++++++++---- 3 files changed, 275 insertions(+), 53 deletions(-) rename csharp/App/SaliMax/src/{AsciiArt.cs => Flow.cs} (60%) diff --git a/csharp/App/SaliMax/src/AsciiArt.cs b/csharp/App/SaliMax/src/Flow.cs similarity index 60% rename from csharp/App/SaliMax/src/AsciiArt.cs rename to csharp/App/SaliMax/src/Flow.cs index 8896d0487..a67ebf189 100644 --- a/csharp/App/SaliMax/src/AsciiArt.cs +++ b/csharp/App/SaliMax/src/Flow.cs @@ -1,4 +1,45 @@ -// using InnovEnergy.Lib.Utils; +using System.Diagnostics.CodeAnalysis; +using InnovEnergy.Lib.Units; +using InnovEnergy.Lib.Utils; + + + +namespace InnovEnergy.App.SaliMax; + +public static class Flow +{ + private static readonly String RightArrowChar = ">"; + private static readonly String LeftArrowChar = "<"; + private static readonly String DownArrowChar = "V"; + private static readonly String UpArrowChar = "^"; + + public static TextBlock Horizontal(Unit amount, Int32 width = 10) + { + var label = amount.ToString(); + var arrowChar = amount.Value < 0 ? LeftArrowChar : RightArrowChar; + var arrow = Enumerable.Repeat(arrowChar, width).Join(); + + // note : appending "fake label" below to make it vertically symmetric + return TextBlock.CenterHorizontal(label, arrow, ""); + } + + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + [SuppressMessage("ReSharper", "CoVariantArrayConversion")] + public static TextBlock Vertical(Unit amount, Int32 height = 8) + { + var label = amount.ToString(); + var arrowChar = amount.Value < 0 ? UpArrowChar : DownArrowChar; + var halfArrow = Enumerable.Repeat(arrowChar, height/2); + + var lines = halfArrow + .Append(label) + .Concat(halfArrow) + .ToArray(height / 2 * 2 + 1); + + return TextBlock.CenterHorizontal(lines); + } +} + // // namespace InnovEnergy.App.SaliMax; // diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index f63255f38..46e0f05d8 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -75,7 +75,6 @@ internal static class Program Console.WriteLine(e); } } - } private static async Task Run() diff --git a/csharp/Lib/Utils/TextBlock.cs b/csharp/Lib/Utils/TextBlock.cs index e3a11f1c6..dc7fcb924 100644 --- a/csharp/Lib/Utils/TextBlock.cs +++ b/csharp/Lib/Utils/TextBlock.cs @@ -1,76 +1,258 @@ + namespace InnovEnergy.Lib.Utils; +// public class TextBlock +// { +// public static TextBlock Empty { get; } = new TextBlock(Array.Empty()); +// +// public IReadOnlyList Lines { get; } +// +// public Int32 Width => Lines.Count == 0 +// ? 0 +// : Lines.Max(l=>l.Length); +// +// public Int32 Height => Lines.Count; +// +// public TextBlock(IReadOnlyList lines) => Lines = lines; +// +// public TextBlock AlignLeft (Int32 width = -1) => AlignHorizontal((l, w) => l.PadRight(w), width); +// public TextBlock AlignRight (Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft(w), width); +// public TextBlock AlignHCenter(Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width); +// +// public TextBlock AlignTop (Int32 height) => Lines.Concat(EmptyLines(height)).Take(height).ToArray(height); +// public TextBlock AlignBottom (Int32 height) => EmptyLines(Lines.Count - height).Concat(Lines).Take(height).ToArray(height); +// //public TextBlock AlignVCenter(Int32 height) => EmptyLines(height/2).Concat(Lines).Take(height).ToArray(height); +// //public TextBlock AlignVCenter(Int32 height) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width); +// +// private static IEnumerable EmptyLines(Int32 height) +// { +// return height > 0 +// ? Enumerable.Repeat("", height) +// : Enumerable.Empty(); +// } +// +// +// public static TextBlock HSpace(Int32 width ) => new TextBlock(new []{"".PadRight(width)}); +// public static TextBlock VSpace(Int32 height) => new TextBlock(Enumerable.Repeat("", height).ToArray(height)); +// +// public static TextBlock Space(Int32 width, Int32 height) +// { +// var lines = Enumerable +// .Repeat("".PadRight(width), height) +// .ToArray(height); +// +// return new TextBlock(lines); +// } +// +// private TextBlock AlignHorizontal(Func alignLine, Int32 width = -1) +// { +// if (!Lines.Any()) +// return Empty; +// +// var strings = Lines +// .SelectMany(GetLines) +// .ToList(); +// +// width = width < 0 ? strings.Max(l => l.Length) : width; +// +// var aligned = strings +// .Select(l => l.Length > width ? l.Substring(0, width) : l) +// .Select(l => alignLine(l, width)) +// .ToArray(strings.Count); +// +// return new TextBlock(aligned); +// } +// +// +// private static IReadOnlyList GetLines(Object l) +// { +// return l is TextBlock tb +// ? tb.Lines +// : l.ToString()?.SplitLines() ?? new[] { "" }; +// } +// +// public override String ToString() => String.Join(Environment.NewLine, Lines); +// +// public static implicit operator TextBlock(String[] lines) => new TextBlock(lines); +// } + + public class TextBlock { - public static TextBlock Empty { get; } = new TextBlock(Array.Empty()); + private readonly IReadOnlyList _Lines; - public IReadOnlyList Lines { get; } + private TextBlock(params String[] lines) => _Lines = lines; - public Int32 Width => Lines.Count == 0 - ? 0 - : Lines.Max(l=>l.Length); + public override String ToString() => _Lines.JoinLines(); - public Int32 Height => Lines.Count; - public TextBlock(IReadOnlyList lines) => Lines = lines; - - public TextBlock AlignLeft (Int32 width = -1) => AlignHorizontal((l, w) => l.PadRight(w), width); - public TextBlock AlignRight (Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft(w), width); - public TextBlock AlignHCenter(Int32 width = -1) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width); - - public TextBlock AlignTop (Int32 height) => Lines.Concat(EmptyLines(height)).Take(height).ToArray(height); - public TextBlock AlignBottom (Int32 height) => EmptyLines(Lines.Count - height).Concat(Lines).Take(height).ToArray(height); - //public TextBlock AlignVCenter(Int32 height) => EmptyLines(height/2).Concat(Lines).Take(height).ToArray(height); - //public TextBlock AlignVCenter(Int32 height) => AlignHorizontal((l, w) => l.PadLeft((w + l.Length) / 2).PadRight(w), width); - - private static IEnumerable EmptyLines(Int32 height) + public static TextBlock AlignLeft(params Object[] things) { - return height > 0 - ? Enumerable.Repeat("", height) - : Enumerable.Empty(); + var lines = things + .SelectMany(GetLines) + .ToList(); + + var width = lines.Max(l => l.Length); + + var alignedLines = lines.Select(l => l.PadRight(width)).ToArray(lines.Count); + + return new TextBlock(alignedLines); + } + + public static TextBlock AlignRight(params Object[] things) + { + var lines = things + .SelectMany(GetLines) + .ToList(); + + var width = lines.Max(l => l.Length); + + var alignedLines = lines.Select(l => l.PadLeft(width)).ToArray(lines.Count); + + return new TextBlock(alignedLines); + } + + public static TextBlock CenterHorizontal(params Object[] things) + { + var lines = things + .SelectMany(GetLines) + .ToList(); + + var width = lines.Max(l => l.Length); + + var alignedLines = lines + .Select(l => l.PadLeft((width + l.Length) / 2).PadRight(width)) + .ToArray(lines.Count); + + return new TextBlock(alignedLines); } - public static TextBlock HSpace(Int32 width ) => new TextBlock(new []{"".PadRight(width)}); - public static TextBlock VSpace(Int32 height) => new TextBlock(Enumerable.Repeat("", height).ToArray(height)); - - public static TextBlock Space(Int32 width, Int32 height) + public static TextBlock AlignTop(params Object[] things) { - var lines = Enumerable - .Repeat("".PadRight(width), height) - .ToArray(height); + var columns = things + .Select(GetLines) + .ToList(); + + var height = columns.Max(l => l.Count); + + var alignedLines = Enumerable + .Range(0, height) + .Select(l => columns.Select(c => c.ElementAtOr(l, Space(c[0].Length))).Join()) + .ToArray(height); + + return new TextBlock(alignedLines); + } + + + public static TextBlock AlignBottom(params Object[] things) + { + var columns = things + .Select(GetLines) + .ToList(); + + var height = columns.Max(l => l.Count); + + var alignedLines = Enumerable + .Range(0, height) + .Select(l => columns.Select(c => c.ElementAtOr(c.Count - height + l, Space(c[0].Length))).Join()) + .ToArray(height); + + return new TextBlock(alignedLines); + } + + + public static TextBlock CenterVertical(params Object[] things) + { + var columns = things + .Select(GetLines) + .ToList(); + + var height = columns.Max(l => l.Count); + + var alignedLines = Enumerable + .Range(0, height) + .Select(l => columns.Select(c => c.ElementAtOr((c.Count - height) / 2 + l, Space(c[0].Length))).Join()) + .ToArray(height); + + return new TextBlock(alignedLines); + } + + + + public TextBlock Box() + { + var width = _Lines.Max(l => l.Length); + + var hLine = "".PadRight(width + 2, '─'); + var top = "┌" + hLine + "┐"; + var bottom = "└" + hLine + "┘"; + + var lines = _Lines + .Select(l => l.SurroundWith(" ")) + .Select(l => l.SurroundWith("│")) + .Prepend(top) + .Append(bottom) + .ToArray(_Lines.Count + 2); + + return new TextBlock(lines); + } + + public TextBlock TitleBox(String title) + { + var linesWidth = _Lines.Max(l => l.Length); + var titleWidth = title.Length; + + var width = Math.Max(linesWidth, titleWidth); + + var hLine = "".PadRight(width + 2, '─'); + var top = "┌" + hLine + "┐"; + var between = "├" + hLine + "┤"; + var bottom = "└" + hLine + "┘"; + + var centeredTitle = "│ " + title.PadLeft((width + title.Length) / 2).PadRight(width) + " │"; + + var lines = _Lines + .Select(l => l.PadRight(width)) + .Select(l => l.SurroundWith(" ")) + .Select(l => l.SurroundWith("│")) + .Prepend(between) + .Prepend(centeredTitle) + .Prepend(top) + .Append(bottom) + .ToArray(); return new TextBlock(lines); } - private TextBlock AlignHorizontal(Func alignLine, Int32 width = -1) + + + + public static TextBlock Spacer(Int32 n) { - if (!Lines.Any()) - return Empty; - - var strings = Lines - .SelectMany(GetLines) - .ToList(); - - width = width < 0 ? strings.Max(l => l.Length) : width; - - var aligned = strings - .Select(l => l.Length > width ? l.Substring(0, width) : l) - .Select(l => alignLine(l, width)) - .ToArray(strings.Count); - - return new TextBlock(aligned); + return new TextBlock(Enumerable.Repeat("".PadRight(n), n).ToArray(n)); } - - private static IReadOnlyList GetLines(Object l) + public static TextBlock HorizontalSpace(Int32 n) { - return l is TextBlock tb - ? tb.Lines - : l.ToString()?.SplitLines() ?? new[] { "" }; + return new TextBlock("".PadRight(n)); + } + + public static TextBlock VerticalSpace(Int32 n) + { + return new TextBlock(Enumerable.Repeat("", n).ToArray(n)); } - public override String ToString() => String.Join(Environment.NewLine, Lines); - public static implicit operator TextBlock(String[] lines) => new TextBlock(lines); + private static IReadOnlyList GetLines(Object t) + { + return t is TextBlock tb + ? tb._Lines + : t.ToString()!.SplitLines(); + } + + private static String Space(Int32 totalWidth) + { + return "".PadRight(totalWidth); + } }