Browse Source

Add additional LineStyles (#2533)

* Add additional LineStyles

* Fix WizardTests because of renamed runes

* BorderFrame -> Border

* Fix the layout of Border Scenarios

* Fix for LineCanvas clipping

Based on comment https://github.com/gui-cs/Terminal.Gui/pull/2533#issuecomment-1508982468

* Update LineCanvasTests.cs

* Rename Thick border to Heavy

(less confusion with "Thickness")
Also:
* Add a few more runes for potential future use
* Fix Unit Tests

* Fix LineDrawing scenario to use 1 unit longer lines (matching new LineCanvas API).

* Fix LineDrawing scenario to better match mouse cursor location

---------

Co-authored-by: tznind <[email protected]>
Nutzzz 2 years ago
parent
commit
1bc25900e7

+ 158 - 17
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -942,7 +942,7 @@ namespace Terminal.Gui {
 		/// Set flags to enable/disable <see cref="ConsoleDriver"/> diagnostics.
 		/// </summary>
 		public static DiagnosticFlags Diagnostics { get; set; }
-		
+
 		/// <summary>
 		/// Suspend the application, typically needs to save the state, suspend the app and upon return, reset the console driver.
 		/// </summary>
@@ -1118,42 +1118,32 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Horizontal double line character.
 		/// </summary>
-		public Rune HDLine = '\u2550';
+		public Rune HDbLine = '\u2550';
 
 		/// <summary>
 		/// Vertical double line character.
 		/// </summary>
-		public Rune VDLine = '\u2551';
+		public Rune VDbLine = '\u2551';
 
 		/// <summary>
 		/// Upper left double corner
 		/// </summary>
-		public Rune ULDCorner = '\u2554';
+		public Rune ULDbCorner = '\u2554';
 
 		/// <summary>
 		/// Lower left double corner
 		/// </summary>
-		public Rune LLDCorner = '\u255a';
+		public Rune LLDbCorner = '\u255a';
 
 		/// <summary>
 		/// Upper right double corner
 		/// </summary>
-		public Rune URDCorner = '\u2557';
+		public Rune URDbCorner = '\u2557';
 
 		/// <summary>
 		/// Lower right double corner
 		/// </summary>
-		public Rune LRDCorner = '\u255d';
-
-		/// <summary>
-		/// Horizontal line character for rounded corners.
-		/// </summary>
-		public Rune HRLine = '\u2500';
-
-		/// <summary>
-		/// Vertical line character for rounded corners.
-		/// </summary>
-		public Rune VRLine = '\u2502';
+		public Rune LRDbCorner = '\u255d';
 
 		/// <summary>
 		/// Upper left rounded corner
@@ -1174,6 +1164,157 @@ namespace Terminal.Gui {
 		/// Lower right rounded corner
 		/// </summary>
 		public Rune LRRCorner = '\u256f';
+
+		/// <summary>
+		/// Horizontal double dashed line character.
+		/// </summary>
+		public Rune HDsLine = '\u254c';
+
+		/// <summary>
+		/// Vertical triple dashed line character.
+		/// </summary>
+		public Rune VDsLine = '\u2506';
+
+		/// <summary>
+		/// Horizontal triple dashed line character.
+		/// </summary>
+		public Rune HDtLine = '\u2504';
+
+		/// <summary>
+		/// Horizontal quadruple dashed line character.
+		/// </summary>
+		public Rune HD4Line = '\u2508';
+
+		/// <summary>
+		/// Vertical double dashed line character.
+		/// </summary>
+		public Rune VD2Line = '\u254e';
+
+		/// <summary>
+		/// Vertical quadruple dashed line character.
+		/// </summary>
+		public Rune VDtLine = '\u250a';
+
+		/// <summary>
+		/// Horizontal heavy line character.
+		/// </summary>
+		public Rune HThLine = '\u2501';
+
+		/// <summary>
+		/// Vertical heavy line character.
+		/// </summary>
+		public Rune VThLine = '\u2503';
+
+		/// <summary>
+		/// Upper left heavy corner
+		/// </summary>
+		public Rune ULThCorner = '\u250f';
+
+		/// <summary>
+		/// Lower left heavy corner
+		/// </summary>
+		public Rune LLThCorner = '\u2517';
+
+		/// <summary>
+		/// Upper right heavy corner
+		/// </summary>
+		public Rune URThCorner = '\u2513';
+
+		/// <summary>
+		/// Lower right heavy corner
+		/// </summary>
+		public Rune LRThCorner = '\u251b';
+
+		/// <summary>
+		/// Horizontal heavy double dashed line character.
+		/// </summary>
+		public Rune HThDsLine = '\u254d';
+
+		/// <summary>
+		/// Vertical heavy triple dashed line character.
+		/// </summary>
+		public Rune VThDsLine = '\u2507';
+
+		/// <summary>
+		/// Horizontal heavy triple dashed line character.
+		/// </summary>
+		public Rune HThDtLine = '\u2505';
+
+		/// <summary>
+		/// Horizontal heavy quadruple dashed line character.
+		/// </summary>
+		public Rune HThD4Line = '\u2509';
+
+		/// <summary>
+		/// Vertical heavy double dashed line character.
+		/// </summary>
+		public Rune VThD2Line = '\u254f';
+
+		/// <summary>
+		/// Vertical heavy quadruple dashed line character.
+		/// </summary>
+		public Rune VThDtLine = '\u250b';
+
+		/// <summary>
+		/// The left half line.
+		/// </summary>
+		public Rune HalfLeftLine = '\u2574';
+
+		/// <summary>
+		/// The up half line.
+		/// </summary>
+		public Rune HalfTopLine = '\u2575';
+
+		/// <summary>
+		/// The right half line.
+		/// </summary>
+		public Rune HalfRightLine = '\u2576';
+
+		/// <summary>
+		/// The down half line.
+		/// </summary>
+		public Rune HalfBottomLine = '\u2577';
+
+		/// <summary>
+		/// The heavy left half line.
+		/// </summary>
+		public Rune ThHalfLeftLine = '\u2578';
+
+		/// <summary>
+		/// The heavy up half line.
+		/// </summary>
+		public Rune ThHalfTopLine = '\u2579';
+
+		/// <summary>
+		/// The heavy right half line.
+		/// </summary>
+		public Rune ThHalfRightLine = '\u257a';
+
+		/// <summary>
+		/// The heavy light down half line.
+		/// </summary>
+		public Rune ThHalfBottomLine = '\u257b';
+
+		/// <summary>
+		/// The light left and heavy right line.
+		/// </summary>
+		public Rune ThRightSideLine = '\u257c';
+
+		/// <summary>
+		/// The light up and heavy down line.
+		/// </summary>
+		public Rune ThBottomSideLine = '\u257d';
+
+		/// <summary>
+		/// The heavy left and light right line.
+		/// </summary>
+		public Rune ThLeftSideLine = '\u257e';
+
+		/// <summary>
+		/// The heavy up and light down line.
+		/// </summary>
+		public Rune ThTopSideLine = '\u257f';
+
 		private Attribute currentAttribute;
 
 		/// <summary>

+ 92 - 21
Terminal.Gui/Drawing/LineCanvas.cs

@@ -16,17 +16,45 @@ namespace Terminal.Gui {
 		/// </summary>
 		None,
 		/// <summary>
-		/// The border is drawn using single-width line glyphs.
+		/// The border is drawn using thin line glyphs.
 		/// </summary>
 		Single,
 		/// <summary>
-		/// The border is drawn using double-width line glyphs.
+		/// The border is drawn using thin line glyphs with dashed (double and triple) straight lines.
+		/// </summary>
+		Dashed,
+		/// <summary>
+		/// The border is drawn using thin line glyphs with short dashed (triple and quadruple) straight lines.
+		/// </summary>
+		Dotted,
+		/// <summary>
+		/// The border is drawn using thin double line glyphs.
 		/// </summary>
 		Double,
 		/// <summary>
-		/// The border is drawn using single-width line glyphs with rounded corners.
+		/// The border is drawn using heavy line glyphs.
+		/// </summary>
+		Heavy,
+		/// <summary>
+		/// The border is drawn using heavy line glyphs with dashed (double and triple) straight lines.
+		/// </summary>
+		HeavyDashed,
+		/// <summary>
+		/// The border is drawn using heavy line glyphs with short dashed (triple and quadruple) straight lines.
+		/// </summary>
+		HeavyDotted,
+		/// <summary>
+		/// The border is drawn using thin line glyphs with rounded corners.
 		/// </summary>
 		Rounded,
+		/// <summary>
+		/// The border is drawn using thin line glyphs with rounded corners and dashed (double and triple) straight lines.
+		/// </summary>
+		RoundedDashed,
+		/// <summary>
+		/// The border is drawn using thin line glyphs with rounded corners and short dashed (triple and quadruple) straight lines.
+		/// </summary>
+		RoundedDotted,
 		// TODO: Support Ruler
 		///// <summary> 
 		///// The border is drawn as a diagnostic ruler ("|123456789...").
@@ -248,39 +276,59 @@ namespace Terminal.Gui {
 			readonly Rune doubleH;
 			readonly Rune doubleV;
 			readonly Rune doubleBoth;
+			readonly Rune thickH;
+			readonly Rune thickV;
+			readonly Rune thickBoth;
 			readonly Rune normal;
 
-			public IntersectionRuneResolver (Rune round, Rune doubleH, Rune doubleV, Rune doubleBoth, Rune normal)
+			public IntersectionRuneResolver (Rune round, Rune doubleH, Rune doubleV, Rune doubleBoth, Rune thickH, Rune thickV, Rune thickBoth, Rune normal)
 			{
 				this.round = round;
 				this.doubleH = doubleH;
 				this.doubleV = doubleV;
 				this.doubleBoth = doubleBoth;
+				this.thickH = thickH;
+				this.thickV = thickV;
+				this.thickBoth = thickBoth;
 				this.normal = normal;
 			}
 
 			public Rune? GetRuneForIntersects (ConsoleDriver driver, IntersectionDefinition [] intersects)
 			{
-				var useRounded = intersects.Any (i => i.Line.Style == LineStyle.Rounded && i.Line.Length != 0);
+				var useRounded = intersects.Any (i => i.Line.Length != 0 && (
+					i.Line.Style == LineStyle.Rounded || i.Line.Style == LineStyle.RoundedDashed || i.Line.Style == LineStyle.RoundedDotted));
+
+				// Note that there aren't any glyphs for intersections of double lines with heavy lines
 
 				bool doubleHorizontal = intersects.Any (l => l.Line.Orientation == Orientation.Horizontal && l.Line.Style == LineStyle.Double);
 				bool doubleVertical = intersects.Any (l => l.Line.Orientation == Orientation.Vertical && l.Line.Style == LineStyle.Double);
 
+				bool thickHorizontal = intersects.Any (l => l.Line.Orientation == Orientation.Horizontal && (
+					l.Line.Style == LineStyle.Heavy || l.Line.Style == LineStyle.HeavyDashed || l.Line.Style == LineStyle.HeavyDotted));
+				bool thickVertical = intersects.Any (l => l.Line.Orientation == Orientation.Vertical && (
+					l.Line.Style == LineStyle.Heavy || l.Line.Style == LineStyle.HeavyDashed || l.Line.Style == LineStyle.HeavyDotted));
+
 				if (doubleHorizontal) {
 					return doubleVertical ? doubleBoth : doubleH;
 				}
-
 				if (doubleVertical) {
 					return doubleV;
 				}
 
+				if (thickHorizontal) {
+					return thickVertical ? thickBoth : thickH;
+				}
+				if (thickVertical) {
+					return thickV;
+				}
+
 				return useRounded ? round : normal;
 			}
 		}
 
 		private class ULIntersectionRuneResolver : IntersectionRuneResolver {
 			public ULIntersectionRuneResolver () :
-				base ('╭', '╒', '╓', '╔', '┌')
+				base ('╭', '╒', '╓', '╔', '┍', '┎', '┏', '┌')
 			{
 
 			}
@@ -288,7 +336,7 @@ namespace Terminal.Gui {
 		private class URIntersectionRuneResolver : IntersectionRuneResolver {
 
 			public URIntersectionRuneResolver () :
-				base ('╮', '╕', '╖', '╗', '┐')
+				base ('╮', '╕', '╖', '╗', '┑', '┒', '┓', '┐')
 			{
 
 			}
@@ -296,14 +344,14 @@ namespace Terminal.Gui {
 		private class LLIntersectionRuneResolver : IntersectionRuneResolver {
 
 			public LLIntersectionRuneResolver () :
-				base ('╰', '╘', '╙', '╚', '└')
+				base ('╰', '╘', '╙', '╚', '┕', '┖', '┗', '└')
 			{
 
 			}
 		}
 		private class LRIntersectionRuneResolver : IntersectionRuneResolver {
 			public LRIntersectionRuneResolver () :
-				base ('╯', '╛', '╜', '╝', '┘')
+				base ('╯', '╛', '╜', '╝', '┙', '┚', '┛', '┘')
 			{
 
 			}
@@ -311,35 +359,35 @@ namespace Terminal.Gui {
 
 		private class TopTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public TopTeeIntersectionRuneResolver () :
-				base ('┬', '╤', '╥', '╦', '┬')
+				base ('┬', '╤', '╥', '╦', '┯', '┰', '┳', '┬')
 			{
 
 			}
 		}
 		private class LeftTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public LeftTeeIntersectionRuneResolver () :
-				base ('├', '╞', '╟', '╠', '├')
+				base ('├', '╞', '╟', '╠', '┝', '┠', '┣', '├')
 			{
 
 			}
 		}
 		private class RightTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public RightTeeIntersectionRuneResolver () :
-				base ('┤', '╡', '╢', '╣', '┤')
+				base ('┤', '╡', '╢', '╣', '┥', '┨', '┫', '┤')
 			{
 
 			}
 		}
 		private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public BottomTeeIntersectionRuneResolver () :
-				base ('┴', '╧', '╨', '╩', '┴')
+				base ('┴', '╧', '╨', '╩', '┷', '┸', '┻', '┴')
 			{
 
 			}
 		}
 		private class CrosshairIntersectionRuneResolver : IntersectionRuneResolver {
 			public CrosshairIntersectionRuneResolver () :
-				base ('┼', '╪', '╫', '╬', '┼')
+				base ('┼', '╪', '╫', '╬', '┿', '╂', '╋', '┼')
 			{
 
 			}
@@ -357,23 +405,46 @@ namespace Terminal.Gui {
 				return runeResolvers [runeType].GetRuneForIntersects (driver, intersects);
 			}
 
-			// TODO: Remove these two once we have all of the below ported to IntersectionRuneResolvers
+			// TODO: Remove these once we have all of the below ported to IntersectionRuneResolvers
 			var useDouble = intersects.Any (i => i.Line.Style == LineStyle.Double);
-			var useRounded = intersects.Any (i => i.Line.Style == LineStyle.Rounded);
+			var useDashed = intersects.Any (i => i.Line.Style == LineStyle.Dashed || i.Line.Style == LineStyle.RoundedDashed);
+			var useDotted = intersects.Any (i => i.Line.Style == LineStyle.Dotted || i.Line.Style == LineStyle.RoundedDotted);
+			// horiz and vert lines same as Single for Rounded
+			var useThick = intersects.Any (i => i.Line.Style == LineStyle.Heavy);
+			var useThickDashed = intersects.Any (i => i.Line.Style == LineStyle.HeavyDashed);
+			var useThickDotted = intersects.Any (i => i.Line.Style == LineStyle.HeavyDotted);
 			// TODO: Support ruler
 			//var useRuler = intersects.Any (i => i.Line.Style == LineStyle.Ruler && i.Line.Length != 0);
 
-			// TODO: maybe make these resolvers to for simplicity?
-			// or for dotted lines later on or that kind of thing?
+			// TODO: maybe make these resolvers too for simplicity?
 			switch (runeType) {
 			case IntersectionRuneType.None:
 				return null;
 			case IntersectionRuneType.Dot:
 				return (Rune)'.';
 			case IntersectionRuneType.HLine:
-				return useDouble ? driver.HDLine : driver.HLine;
+				if (useDouble) {
+					return driver.HDbLine;
+				}
+				if (useDashed) {
+					return driver.HDsLine;
+				}
+				if (useDotted) {
+					return driver.HDtLine;
+				}
+				return useThick ? driver.HThLine : (useThickDashed ? driver.HThDsLine : (useThickDotted ? driver.HThDtLine : driver.HLine));
 			case IntersectionRuneType.VLine:
-				return useDouble ? driver.VDLine : driver.VLine;
+				if (useDouble) {
+					return driver.VDbLine;
+				}
+				if (useDashed) {
+					return driver.VDsLine;
+				}
+				if (useDotted) {
+					return driver.VDtLine;
+				}
+				return useThick ? driver.VThLine : (useThickDashed ? driver.VThDsLine : (useThickDotted ? driver.VThDtLine : driver.VLine));
+
 			default: throw new Exception ("Could not find resolver or switch case for " + nameof (runeType) + ":" + runeType);
 			}
 		}

+ 2 - 2
UICatalog/Scenarios/BordersOnContainers.cs

@@ -253,7 +253,7 @@ namespace UICatalog.Scenarios {
 			};
 
 			Add (new Label ("Background:") {
-				Y = 5
+				Y = 12
 			});
 
 			var colorEnum = Enum.GetValues (typeof (Color)).Cast<Color> ().ToList ();
@@ -261,7 +261,7 @@ namespace UICatalog.Scenarios {
 				e => NStack.ustring.Make (e.ToString ())).ToArray ()) {
 
 				X = 2,
-				Y = 6,
+				Y = 13,
 				//SelectedItem = (int)smartView.BorderFrame.BackgroundColor
 			};
 			rbBackground.SelectedItemChanged += (s, e) => {

+ 2 - 2
UICatalog/Scenarios/LineCanvasExperiment.cs

@@ -41,13 +41,13 @@ namespace UICatalog.Scenarios {
 			var win1 = new Window () {
 				AutoSize = false,
 				Title = "win1",
-				Text = "Win1 30%/50% Single",
+				Text = "Win1 30%/50% Heavy",
 				X = 20,
 				Y = 0,
 				Width = 30, //Dim.Percent (30) - 5,
 				Height = 10, //Dim.Percent (50) - 5,
 				//ColorScheme = Colors.ColorSchemes ["Base"],
-				BorderStyle = LineStyle.Double,
+				BorderStyle = LineStyle.Heavy,
 				SuperViewRendersLineCanvas = true
 			};
 			win1.Padding.Thickness = new Thickness (1);

+ 63 - 19
UICatalog/Scenarios/LineDrawing.cs

@@ -12,11 +12,12 @@ namespace UICatalog.Scenarios {
 
 		public override void Setup ()
 		{
-			var toolsWidth = 8;
+			var toolsWidth = 12;
 
 			var canvas = new DrawingArea {
-				Width = Dim.Fill (-toolsWidth),
-				Height = Dim.Fill ()
+				Width = Dim.Fill (toolsWidth + 1),
+				Height = Dim.Fill (),
+				BorderStyle = LineStyle.Single
 			};
 
 			var tools = new ToolsView (toolsWidth) {
@@ -45,25 +46,26 @@ namespace UICatalog.Scenarios {
 				{ new Point(3,1),Color.Green},
 				{ new Point(5,1),Color.BrightBlue},
 				{ new Point(7,1),Color.Black},
-				{ new Point(1,3),Color.White},
+				{ new Point(9,1),Color.DarkGray},
+				{ new Point(11,1),Color.White},
 			};
 
 			public ToolsView (int width)
 			{
 				grid = new LineCanvas ();
 
-				int maxHeight = 10000;
+				grid.AddLine (new Point (0, 0), 7, Orientation.Vertical, LineStyle.Single);
+				grid.AddLine (new Point (0, 0), width + 1, Orientation.Horizontal, LineStyle.Single);
+				grid.AddLine (new Point (width, 0), 7, Orientation.Vertical, LineStyle.Single);
+				grid.AddLine (new Point (0, 6), width + 1, Orientation.Horizontal, LineStyle.Single);
 
-				grid.AddLine (new Point (0, 0), maxHeight, Orientation.Vertical, LineStyle.Single);
-				grid.AddLine (new Point (0, 0), width+1, Orientation.Horizontal, LineStyle.Single);
-				grid.AddLine (new Point (width, 0), maxHeight, Orientation.Vertical, LineStyle.Single);
+				grid.AddLine (new Point (2, 0), 7, Orientation.Vertical, LineStyle.Single);
+				grid.AddLine (new Point (4, 0), 7, Orientation.Vertical, LineStyle.Single);
+				grid.AddLine (new Point (6, 0), 7, Orientation.Vertical, LineStyle.Single);
+				grid.AddLine (new Point (8, 0), 7, Orientation.Vertical, LineStyle.Single);
+				grid.AddLine (new Point (10, 0), 7, Orientation.Vertical, LineStyle.Single);
 
 				grid.AddLine (new Point (0, 2), width + 1, Orientation.Horizontal, LineStyle.Single);
-
-				grid.AddLine (new Point (2, 0), maxHeight, Orientation.Vertical, LineStyle.Single);
-				grid.AddLine (new Point (4, 0), maxHeight, Orientation.Vertical, LineStyle.Single);
-				grid.AddLine (new Point (6, 0), maxHeight, Orientation.Vertical, LineStyle.Single);
-
 				grid.AddLine (new Point (0, 4), width + 1, Orientation.Horizontal, LineStyle.Single);
 			}
 			public override void Redraw (Rect bounds)
@@ -84,9 +86,16 @@ namespace UICatalog.Scenarios {
 				}
 
 				Driver.SetAttribute (new Terminal.Gui.Attribute (ColorScheme.Normal.Foreground, ColorScheme.Normal.Background));
-				AddRune (3, 3, Application.Driver.HDLine);
-				AddRune (5, 3, Application.Driver.HLine);
+				AddRune (1, 3, Application.Driver.HLine);
+				AddRune (3, 3, Application.Driver.HDsLine);
+				AddRune (5, 3, Application.Driver.HDtLine);
 				AddRune (7, 3, Application.Driver.ULRCorner);
+				AddRune (9, 3, Application.Driver.HDsLine);
+				AddRune (11, 3, Application.Driver.HDtLine);
+				AddRune (1, 5, Application.Driver.HThLine);
+				AddRune (3, 5, Application.Driver.HThDsLine);
+				AddRune (5, 5, Application.Driver.HThDtLine);
+				AddRune (7, 5, Application.Driver.HDbLine);
 			}
 
 			public override bool OnMouseEvent (MouseEvent mouseEvent)
@@ -100,14 +109,19 @@ namespace UICatalog.Scenarios {
 						}
 					}
 
+					if (mouseEvent.X == 1 && mouseEvent.Y == 3) {
+
+						SetStyle?.Invoke (LineStyle.Single);
+						return true;
+					}
 					if (mouseEvent.X == 3 && mouseEvent.Y == 3) {
 
-						SetStyle?.Invoke (LineStyle.Double);
+						SetStyle?.Invoke (LineStyle.Dashed);
 						return true;
 					}
 					if (mouseEvent.X == 5 && mouseEvent.Y == 3) {
 
-						SetStyle?.Invoke (LineStyle.Single);
+						SetStyle?.Invoke (LineStyle.Dotted);
 						return true;
 					}
 					if (mouseEvent.X == 7 && mouseEvent.Y == 3) {
@@ -115,6 +129,36 @@ namespace UICatalog.Scenarios {
 						SetStyle?.Invoke (LineStyle.Rounded);
 						return true;
 					}
+					if (mouseEvent.X == 9 && mouseEvent.Y == 3) {
+
+						SetStyle?.Invoke (LineStyle.RoundedDashed);
+						return true;
+					}
+					if (mouseEvent.X == 11 && mouseEvent.Y == 3) {
+
+						SetStyle?.Invoke (LineStyle.RoundedDotted);
+						return true;
+					}
+					if (mouseEvent.X == 1 && mouseEvent.Y == 5) {
+
+						SetStyle?.Invoke (LineStyle.Heavy);
+						return true;
+					}
+					if (mouseEvent.X == 3 && mouseEvent.Y == 5) {
+
+						SetStyle?.Invoke (LineStyle.HeavyDashed);
+						return true;
+					}
+					if (mouseEvent.X == 5 && mouseEvent.Y == 5) {
+
+						SetStyle?.Invoke (LineStyle.HeavyDotted);
+						return true;
+					}
+					if (mouseEvent.X == 7 && mouseEvent.Y == 5) {
+
+						SetStyle?.Invoke (LineStyle.Double);
+						return true;
+					}
 				}
 
 				return base.OnMouseEvent (mouseEvent);
@@ -169,13 +213,13 @@ namespace UICatalog.Scenarios {
 
 				if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed)) {
 					if (currentLineStart == null) {
-						currentLineStart = new Point (mouseEvent.X, mouseEvent.Y);
+						currentLineStart = new Point (mouseEvent.X - 1, mouseEvent.Y - 1);
 					}
 				} else {
 					if (currentLineStart != null) {
 
 						var start = currentLineStart.Value;
-						var end = new Point (mouseEvent.X, mouseEvent.Y);
+						var end = new Point (mouseEvent.X - 1, mouseEvent.Y - 1);
 						var orientation = Orientation.Vertical;
 						var length = end.Y - start.Y;
 

+ 14 - 14
UnitTests/Dialogs/WizardTests.cs

@@ -118,12 +118,12 @@ namespace Terminal.Gui.DialogTests {
 			var btnNextText = "Finish";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 
-			var topRow = $"{d.ULDCorner}╡{title}{stepTitle}╞{new string (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDCorner}";
-			var row2 = $"{d.VDLine}{new string (' ', width - 2)}{d.VDLine}";
+			var topRow = $"{d.ULDbCorner}╡{title}{stepTitle}╞{new string (d.HDbLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDbCorner}";
+			var row2 = $"{d.VDbLine}{new string (' ', width - 2)}{d.VDbLine}";
 			var row3 = row2;
-			var separatorRow = $"{d.VDLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDLine}";
-			var buttonRow = $"{d.VDLine}{btnBack}{new string (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDLine}";
-			var bottomRow = $"{d.LLDCorner}{new string (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
+			var separatorRow = $"{d.VDbLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDbLine}";
+			var buttonRow = $"{d.VDbLine}{btnBack}{new string (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDbLine}";
+			var bottomRow = $"{d.LLDbCorner}{new string (d.HDbLine.ToString () [0], width - 2)}{d.LRDbCorner}";
 
 			var wizard = new Wizard () { Title = title, Width = width, Height = height };
 			var runstate = Application.Begin (wizard);
@@ -150,13 +150,13 @@ namespace Terminal.Gui.DialogTests {
 			var btnNextText = "Finish"; // "Next";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 
-			var topRow = $"{d.ULDCorner}╡{title} - {stepTitle}╞{new string (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 7)}{d.URDCorner}";
-			var row2 = $"{d.VDLine}{new string (' ', width - 2)}{d.VDLine}";
+			var topRow = $"{d.ULDbCorner}╡{title} - {stepTitle}╞{new string (d.HDbLine.ToString () [0], width - title.Length - stepTitle.Length - 7)}{d.URDbCorner}";
+			var row2 = $"{d.VDbLine}{new string (' ', width - 2)}{d.VDbLine}";
 			var row3 = row2;
 			var row4 = row3;
-			var separatorRow = $"{d.VDLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDLine}";
-			var buttonRow = $"{d.VDLine}{btnBack}{new string (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDLine}";
-			var bottomRow = $"{d.LLDCorner}{new string (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
+			var separatorRow = $"{d.VDbLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDbLine}";
+			var buttonRow = $"{d.VDbLine}{btnBack}{new string (' ', width - btnBack.Length - btnNext.Length - 2)}{btnNext}{d.VDbLine}";
+			var bottomRow = $"{d.LLDbCorner}{new string (d.HDbLine.ToString () [0], width - 2)}{d.LRDbCorner}";
 
 			var wizard = new Wizard () { Title = title, Width = width, Height = height };
 			wizard.AddStep (new Wizard.WizardStep () { Title = stepTitle });
@@ -220,13 +220,13 @@ namespace Terminal.Gui.DialogTests {
 			var btnNextText = "Finish";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 
-			var topRow = $"{d.ULDCorner}╡{title}{stepTitle}╞{new string (d.HDLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDCorner}";
-			var separatorRow = $"{d.VDLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDLine}";
+			var topRow = $"{d.ULDbCorner}╡{title}{stepTitle}╞{new string (d.HDbLine.ToString () [0], width - title.Length - stepTitle.Length - 4)}{d.URDbCorner}";
+			var separatorRow = $"{d.VDbLine}{new string (d.HLine.ToString () [0], width - 2)}{d.VDbLine}";
 
 			// Once this is fixed, revert to commented out line: https://github.com/gui-cs/Terminal.Gui/issues/1791
-			var buttonRow = $"{d.VDLine}{new string (' ', width - btnNext.Length - 2)}{btnNext}{d.VDLine}";
+			var buttonRow = $"{d.VDbLine}{new string (' ', width - btnNext.Length - 2)}{btnNext}{d.VDbLine}";
 			//var buttonRow = $"{d.VDLine}{new String (' ', width - btnNext.Length - 2)}{btnNext}{d.VDLine}";
-			var bottomRow = $"{d.LLDCorner}{new string (d.HDLine.ToString () [0], width - 2)}{d.LRDCorner}";
+			var bottomRow = $"{d.LLDbCorner}{new string (d.HDbLine.ToString () [0], width - 2)}{d.LRDbCorner}";
 
 			var wizard = new Wizard () { Title = title, Width = width, Height = height };
 			wizard.AddStep (new Wizard.WizardStep () { Title = "ABCD" });

+ 92 - 4
UnitTests/Drawing/LineCanvasTests.cs

@@ -581,7 +581,7 @@ namespace Terminal.Gui.DrawingTests {
 			// outer box
 			canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Rounded);
 
-			// BorderStyle.Single is ignored because corner overlaps with the above line which is Rounded
+			// LineStyle.Single is ignored because corner overlaps with the above line which is Rounded
 			// this results in a rounded corner being used.
 			canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Single);
 			canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Rounded);
@@ -688,8 +688,96 @@ namespace Terminal.Gui.DrawingTests {
 			TestHelpers.AssertDriverContentsAre (looksLike, output);
 		}
 
-		[Fact, SetupFakeDriver]
-		public void Top_Left_From_TopRigth_TopDown ()
+		[Fact, AutoInitShutdown]
+		public void TestLineCanvas_Window_Heavy ()
+		{
+			var v = GetCanvas (out var canvas);
+
+			// outer box
+			canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Heavy);
+			canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Heavy);
+			canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy);
+			canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Heavy);
+
+
+			canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Heavy);
+			canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy);
+
+			v.Redraw (v.Bounds);
+
+			string looksLike =
+@"    
+┏━━━━┳━━━┓
+┃    ┃   ┃
+┣━━━━╋━━━┫
+┃    ┃   ┃
+┗━━━━┻━━━┛";
+			TestHelpers.AssertDriverContentsAre (looksLike, output);
+		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData (LineStyle.Single)]
+		[InlineData (LineStyle.Rounded)]
+		public void TestLineCanvas_Window_HeavyTop_ThinSides (LineStyle thinStyle)
+		{
+			var v = GetCanvas (out var canvas);
+
+			// outer box
+			canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Heavy);
+			canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, thinStyle);
+			canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Heavy);
+			canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, thinStyle);
+
+
+			canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, thinStyle);
+			canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, LineStyle.Heavy);
+
+			v.Redraw (v.Bounds);
+
+			string looksLike =
+@"    
+┍━━━━┯━━━┑
+│    │   │
+┝━━━━┿━━━┥
+│    │   │
+┕━━━━┷━━━┙
+";
+			TestHelpers.AssertDriverContentsAre (looksLike, output);
+		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData (LineStyle.Single)]
+		[InlineData (LineStyle.Rounded)]
+		public void TestLineCanvas_Window_ThinTop_HeavySides (LineStyle thinStyle)
+		{
+			var v = GetCanvas (out var canvas);
+
+			// outer box
+			canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, thinStyle);
+			canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Heavy);
+			canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, thinStyle);
+			canvas.AddLine (new Point (0, 4), -5, Orientation.Vertical, LineStyle.Heavy);
+
+
+			canvas.AddLine (new Point (5, 0), 5, Orientation.Vertical, LineStyle.Heavy);
+			canvas.AddLine (new Point (0, 2), 10, Orientation.Horizontal, thinStyle);
+
+			v.Redraw (v.Bounds);
+
+			string looksLike =
+@"    
+┎────┰───┒
+┃    ┃   ┃
+┠────╂───┨
+┃    ┃   ┃
+┖────┸───┚
+
+";
+			TestHelpers.AssertDriverContentsAre (looksLike, output);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void TestLineCanvas_LeaveMargin_Top1_Left1 ()
 		{
 			var canvas = new LineCanvas ();
 
@@ -705,7 +793,7 @@ namespace Terminal.Gui.DrawingTests {
 		}
 
 		[Fact, SetupFakeDriver]
-		public void Top_Left_From_TopRigth_LeftUp ()
+		public void Top_Left_From_TopRight_LeftUp ()
 		{
 			var canvas = new LineCanvas ();