diff --git a/Terminal.Gui/Views/LineView.cs b/Terminal.Gui/Views/LineView.cs new file mode 100644 index 000000000..a0290281b --- /dev/null +++ b/Terminal.Gui/Views/LineView.cs @@ -0,0 +1,106 @@ +using System; +using Terminal.Gui.Graphs; + +namespace Terminal.Gui.Views { + + /// + /// A straight line control either horizontal or vertical + /// + public class LineView : View { + + /// + /// The rune to display at the start of the line (left end of horizontal line or top end of vertical) + /// If not specified then is used + /// + public Rune? StartingAnchor { get; set; } + + /// + /// The rune to display at the end of the line (right end of horizontal line or bottom end of vertical). + /// If not specified then is used + /// + public Rune? EndingAnchor { get; set; } + + /// + /// The symbol to use for drawing the line + /// + public Rune LineRune { get; set; } + + /// + /// The direction of the line. If you change this you will need to manually update the Width/Height + /// of the control to cover a relevant area based on the new direction. + /// + public Orientation Orientation { get; set; } + + /// + /// Creates a horizontal line + /// + public LineView () : this(Orientation.Horizontal) + { + + } + + /// + /// Creates a horizontal or vertical line based on + /// + public LineView (Orientation orientation) + { + CanFocus = false; + + switch (orientation) { + case Orientation.Horizontal: + Height = 1; + Width = Dim.Fill (); + LineRune = Driver.HLine; + + break; + case Orientation.Vertical: + Height = Dim.Fill (); + Width = 1; + LineRune = Driver.VLine; + break; + default: + throw new ArgumentException ($"Unknown Orientation {orientation}"); + } + Orientation = orientation; + } + + /// + /// Draws the line including any starting/ending anchors + /// + /// + public override void Redraw (Rect bounds) + { + base.Redraw (bounds); + + Move (0, 0); + Driver.SetAttribute (ColorScheme.Normal); + + var hLineWidth = Math.Max (1, Rune.ColumnWidth (Driver.HLine)); + + var dEnd = Orientation == Orientation.Horizontal ? + bounds.Width : + bounds.Height; + + for (int d = 0; d < dEnd; d += hLineWidth) { + + if(Orientation == Orientation.Horizontal) { + Move (d, 0); + } + else { + Move (0,d); + } + + Rune rune = LineRune; + + if(d == 0) { + rune = StartingAnchor ?? LineRune; + } else + if (d == dEnd - 1) { + rune = EndingAnchor ?? LineRune; + } + + Driver.AddRune (rune); + } + } + } +} diff --git a/UICatalog/Scenarios/LineViewExample.cs b/UICatalog/Scenarios/LineViewExample.cs new file mode 100644 index 000000000..f6216230e --- /dev/null +++ b/UICatalog/Scenarios/LineViewExample.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Terminal.Gui; +using Terminal.Gui.Views; +using static UICatalog.Scenario; + +namespace UICatalog.Scenarios { + + [ScenarioMetadata (Name: "Line View", Description: "Demonstrates the LineView control")] + [ScenarioCategory ("Controls")] + class LineViewExample : Scenario { + + public override void Setup () + { + Win.Title = this.GetName (); + Win.Y = 1; // menu + Win.Height = Dim.Fill (1); // status bar + Top.LayoutSubviews (); + + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem ("_File", new MenuItem [] { + new MenuItem ("_Quit", "", () => Quit()), + }) + }); + Top.Add (menu); + + + Win.Add (new Label ("Regular Line") { Y = 0 }); + + // creates a horizontal line + var line = new LineView () { + Y = 1, + }; + + Win.Add (line); + + Win.Add (new Label ("Double Width Line") { Y = 2 }); + + // creates a horizontal line + var doubleLine = new LineView () { + Y = 3, + LineRune = '\u2550' + }; + + Win.Add (doubleLine); + + Win.Add (new Label ("Short Line") { Y = 4 }); + + // creates a horizontal line + var shortLine = new LineView () { + Y = 5, + Width = 10 + }; + + Win.Add (shortLine); + + + Win.Add (new Label ("Arrow Line") { Y = 6 }); + + // creates a horizontal line + var arrowLine = new LineView () { + Y = 7, + Width = 10, + StartingAnchor = Application.Driver.LeftTee, + EndingAnchor = '>' + }; + + Win.Add (arrowLine); + + + Win.Add (new Label ("Vertical Line") { Y = 9,X=11 }); + + // creates a horizontal line + var verticalLine = new LineView (Terminal.Gui.Graphs.Orientation.Vertical) { + X = 25, + }; + + Win.Add (verticalLine); + + + Win.Add (new Label ("Vertical Arrow") { Y = 11, X = 28 }); + + // creates a horizontal line + var verticalArrow = new LineView (Terminal.Gui.Graphs.Orientation.Vertical) { + X = 27, + StartingAnchor = Application.Driver.TopTee, + EndingAnchor = 'V' + }; + + Win.Add (verticalArrow); + + var statusBar = new StatusBar (new StatusItem [] { + new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Quit", () => Quit()) + }); + Top.Add (statusBar); + + } + + private void Quit () + { + Application.RequestStop (); + } + } +} diff --git a/UnitTests/LineViewTests.cs b/UnitTests/LineViewTests.cs new file mode 100644 index 000000000..555d2ee5e --- /dev/null +++ b/UnitTests/LineViewTests.cs @@ -0,0 +1,40 @@ +using Terminal.Gui; +using Terminal.Gui.Graphs; +using Terminal.Gui.Views; +using Xunit; + +namespace UnitTests { + public class LineViewTests { + + [Fact] + [AutoInitShutdown] + public void LineView_DefaultConstructor() + { + var horizontal = new LineView(); + + Assert.Equal (Orientation.Horizontal, horizontal.Orientation); + Assert.Equal (Dim.Fill (), horizontal.Width); + Assert.Equal (1, horizontal.Height); + } + [Fact] + [AutoInitShutdown] + public void LineView_Horizontal () + { + var horizontal = new LineView (Orientation.Horizontal); + + Assert.Equal (Orientation.Horizontal, horizontal.Orientation); + Assert.Equal (Dim.Fill (), horizontal.Width); + Assert.Equal (1, horizontal.Height); + } + [Fact] + [AutoInitShutdown] + public void LineView_Vertical () + { + var vert = new LineView (Orientation.Vertical); + + Assert.Equal (Orientation.Vertical, vert.Orientation); + Assert.Equal (Dim.Fill(), vert.Height); + Assert.Equal (1, vert.Width); + } + } +}