From 214fe97bd821229ba0efaf9eef4cf33911529d77 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Wed, 22 Feb 2023 19:38:01 +1300 Subject: [PATCH] Diagnostic padding and ruler --- Example/Example.csproj | 2 +- ReactiveExample/ReactiveExample.csproj | 2 +- Terminal.Gui/Core/Border.cs | 121 +++++++++++++++++++------ Terminal.Gui/Core/ConsoleDriver.cs | 19 ---- Terminal.Gui/Core/Container.cs | 3 - Terminal.Gui/Core/Graphs/LineCanvas.cs | 2 + Terminal.Gui/Terminal.Gui.csproj | 2 +- 7 files changed, 97 insertions(+), 54 deletions(-) diff --git a/Example/Example.csproj b/Example/Example.csproj index 2ebf163bc..69d7bd305 100644 --- a/Example/Example.csproj +++ b/Example/Example.csproj @@ -1,7 +1,7 @@  Exe - net6.0 + net7.0 diff --git a/ReactiveExample/ReactiveExample.csproj b/ReactiveExample/ReactiveExample.csproj index c2ce6640c..736cd84a0 100644 --- a/ReactiveExample/ReactiveExample.csproj +++ b/ReactiveExample/ReactiveExample.csproj @@ -1,7 +1,7 @@  Exe - net6.0 + net7.0 diff --git a/Terminal.Gui/Core/Border.cs b/Terminal.Gui/Core/Border.cs index 9f17835db..f6c4b65c7 100644 --- a/Terminal.Gui/Core/Border.cs +++ b/Terminal.Gui/Core/Border.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; using Terminal.Gui.Graphs; using System.Text.Json.Serialization; +using System.Data; +using System.Text; namespace Terminal.Gui { /// @@ -14,17 +16,22 @@ namespace Terminal.Gui { /// None, /// - /// The border is drawn with a single line limits. + /// The border is drawn using single-width line glyphs. /// Single, /// - /// The border is drawn with a double line limits. + /// The border is drawn using double-width line glyphs. /// Double, /// - /// The border is drawn with a single line and rounded corners limits. + /// The border is drawn using single-width line glyphs with rounded corners. /// - Rounded + Rounded, + // TODO: Support Ruler + ///// + ///// The border is drawn as a diagnostic ruler ("|123456789..."). + ///// + //Ruler } /// @@ -103,45 +110,83 @@ namespace Terminal.Gui { return new Rect (new Point (rect.X + Left, rect.Y + Top), size); } + private void FillRect (Rect rect, System.Rune rune = default) + { + for (var r = rect.Y; r < rect.Y + rect.Height; r++) { + for (var c = rect.X; c < rect.X + rect.Width; c++) { + Application.Driver.Move (c, r); + Application.Driver.AddRune (rune == default ? ' ' : rune); + } + } + } /// - /// Draws the thickness rectangle with an optional diagnostics label. + /// Draws the rectangle with an optional diagnostics label. /// + /// + /// If is set to then + /// 'T', 'L', 'R', and 'B' glyphs will be used instead of space. If + /// is set to then a ruler will be drawn on the outer edge of the + /// Thickness. + /// /// The location and size of the rectangle that bounds the thickness rectangle, in /// screen coordinates. /// The diagnostics label to draw on the bottom of the . /// The inner rectangle remaining to be drawn. public Rect Draw (Rect rect, string label = null) { - // Draw the Top side - for (var r = rect.Y; r < Math.Min (rect.Y + rect.Height, rect.Y + Top); r++) { - for (var c = rect.X; c < rect.X + rect.Width; c++) { - Application.Driver.Move (c, r); - Application.Driver.AddRune (' '); - } + System.Rune clearChar = ' '; + System.Rune leftChar = clearChar; + System.Rune rightChar = clearChar; + System.Rune topChar = clearChar; + System.Rune bottomChar = clearChar; + + if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FramePadding) == ConsoleDriver.DiagnosticFlags.FramePadding) { + leftChar = 'L'; + rightChar = 'R'; + topChar = 'T'; + bottomChar = 'B'; } + ustring hrule = ustring.Empty; + ustring vrule = ustring.Empty; + if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) { + + string h = "0123456789"; + hrule = h.Repeat ((int)Math.Ceiling ((double)(rect.Width) / (double)h.Length)) [0..(rect.Width)]; + string v = "0123456789"; + vrule = v.Repeat ((int)Math.Ceiling ((double)(rect.Height * 2) / (double)v.Length)) [0..(rect.Height * 2)]; + }; + + // Draw the Top side + FillRect (new Rect (rect.X, rect.Y, rect.Width, Math.Min (rect.Height, Top)), topChar); + // Draw the Left side - for (var r = rect.Y; r < rect.Y + rect.Height; r++) { - for (var c = rect.X; c < Math.Min (rect.X + rect.Width, rect.X + Left); c++) { - Application.Driver.Move (c, r); - Application.Driver.AddRune (' '); - } - } + FillRect (new Rect (rect.X, rect.Y, Math.Min (rect.Width, Left), rect.Height), leftChar); // Draw the Right side - for (var r = rect.Y; r < rect.Y + rect.Height; r++) { - for (var c = rect.X + Math.Max (0, rect.Width - Right); c < rect.X + rect.Width; c++) { - Application.Driver.Move (c, r); - Application.Driver.AddRune (' '); - } - } + FillRect (new Rect (Math.Max (0, rect.X + rect.Width - Right), rect.Y, Math.Min (rect.Width, Right), rect.Height), rightChar); // Draw the Bottom side - for (var r = rect.Y + Math.Max (0, rect.Height - Bottom); r < rect.Y + rect.Height; r++) { - for (var c = rect.X; c < rect.X + rect.Width; c++) { - Application.Driver.Move (c, r); - Application.Driver.AddRune (' '); + FillRect (new Rect (rect.X, rect.Y + Math.Max (0, rect.Height - Bottom), rect.Width, Bottom), bottomChar); + + // TODO: This should be moved to LineCanvas as a new BorderStyle.Ruler + if ((ConsoleDriver.Diagnostics & ConsoleDriver.DiagnosticFlags.FrameRuler) == ConsoleDriver.DiagnosticFlags.FrameRuler) { + // Top + Application.Driver.Move (rect.X, rect.Y); + Application.Driver.AddStr (hrule); + //Left + for (var r = rect.Y; r < rect.Y + rect.Height; r++) { + Application.Driver.Move (rect.X, r); + Application.Driver.AddRune (vrule [r - rect.Y]); + } + // Bottom + Application.Driver.Move (rect.X, rect.Y + rect.Height - Bottom + 1); + Application.Driver.AddStr (hrule); + // Right + for (var r = rect.Y + 1; r < rect.Y + rect.Height; r++) { + Application.Driver.Move (rect.X + rect.Width - Right + 1, r); + Application.Driver.AddRune (vrule [r - rect.Y]); } } @@ -151,7 +196,7 @@ namespace Terminal.Gui { Alignment = TextAlignment.Centered, VerticalAlignment = VerticalTextAlignment.Bottom }; - tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute); + tf.Draw (rect, Application.Driver.CurrentAttribute, Application.Driver.CurrentAttribute, rect, false); return GetInnerRect (rect); @@ -208,6 +253,24 @@ namespace Terminal.Gui { { return !(left == right); } + + } + + internal static class StringExtensions { + public static string Repeat (this string instr, int n) + { + if (n <= 0) { + return null; + } + + if (string.IsNullOrEmpty (instr) || n == 1) { + return instr; + } + + return new StringBuilder (instr.Length * n) + .Insert (0, instr, n) + .ToString (); + } } /// @@ -450,7 +513,7 @@ namespace Terminal.Gui { /// /// Specifies the for a view. /// - [JsonInclude, JsonConverter (typeof(JsonStringEnumConverter))] + [JsonInclude, JsonConverter (typeof (JsonStringEnumConverter))] public BorderStyle BorderStyle { get => borderStyle; set { diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index e0527a6ce..46e1ce018 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -1198,25 +1198,6 @@ namespace Terminal.Gui { } } - /// - /// Draws a frame on the specified region with the specified padding around the frame. - /// - /// Screen relative region where the frame will be drawn. - /// Padding to add on the sides. - /// If set to true it will clear the contents with the current color, otherwise the contents will be left untouched. - /// This API has been superseded by . - /// This API is equivalent to calling DrawWindowFrame(Rect, p - 1, p - 1, p - 1, p - 1). In other words, - /// A padding value of 0 means there is actually a one cell border. - /// - public virtual void DrawFrame (Rect region, int padding, bool fill) - { - // DrawFrame assumes the border is always at least one row/col thick - // DrawWindowFrame assumes a padding of 0 means NO padding and no frame - DrawWindowFrame (new Rect (region.X, region.Y, region.Width, region.Height), - padding + 1, padding + 1, padding + 1, padding + 1, border: false, fill: fill); - } - - /// /// Suspend the application, typically needs to save the state, suspend the app and upon return, reset the console driver. /// diff --git a/Terminal.Gui/Core/Container.cs b/Terminal.Gui/Core/Container.cs index 71e08e390..0400f7459 100644 --- a/Terminal.Gui/Core/Container.cs +++ b/Terminal.Gui/Core/Container.cs @@ -68,9 +68,6 @@ namespace Terminal.Gui { //OnDrawContent (bounds); - //if (Text != null) { - // Thickness?.Draw (Frame, $"{Text} {DiagnosticsLabel?.Text}"); - //} if (BorderStyle != BorderStyle.None) { var lc = new LineCanvas (); lc.AddLine (Frame.Location, Frame.Width - 1, Orientation.Horizontal, BorderStyle); diff --git a/Terminal.Gui/Core/Graphs/LineCanvas.cs b/Terminal.Gui/Core/Graphs/LineCanvas.cs index e3710aac6..ebd4d690e 100644 --- a/Terminal.Gui/Core/Graphs/LineCanvas.cs +++ b/Terminal.Gui/Core/Graphs/LineCanvas.cs @@ -201,6 +201,8 @@ namespace Terminal.Gui.Graphs { // TODO: Remove these two once we have all of the below ported to IntersectionRuneResolvers var useDouble = intersects.Any (i => i.Line.Style == BorderStyle.Double && i.Line.Length != 0); var useRounded = intersects.Any (i => i.Line.Style == BorderStyle.Rounded && i.Line.Length != 0); + // TODO: Support ruler + //var useRuler = intersects.Any (i => i.Line.Style == BorderStyle.Ruler && i.Line.Length != 0); // TODO: maybe make these resolvers to for simplicity? // or for dotted lines later on or that kind of thing? diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index cdcd28732..87ed2bcc7 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -62,7 +62,7 @@ - net472;netstandard2.0;net6.0 + net7.0 9.0 Terminal.Gui Terminal.Gui