Browse Source

Merge branch 'v2_develop' of tig:gui-cs/Terminal.Gui into v2_develop

Tigger Kindel 2 years ago
parent
commit
bceb62f331

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

@@ -942,7 +942,7 @@ namespace Terminal.Gui {
 		/// Set flags to enable/disable <see cref="ConsoleDriver"/> diagnostics.
 		/// Set flags to enable/disable <see cref="ConsoleDriver"/> diagnostics.
 		/// </summary>
 		/// </summary>
 		public static DiagnosticFlags Diagnostics { get; set; }
 		public static DiagnosticFlags Diagnostics { get; set; }
-		
+
 		/// <summary>
 		/// <summary>
 		/// Suspend the application, typically needs to save the state, suspend the app and upon return, reset the console driver.
 		/// Suspend the application, typically needs to save the state, suspend the app and upon return, reset the console driver.
 		/// </summary>
 		/// </summary>
@@ -1118,42 +1118,32 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Horizontal double line character.
 		/// Horizontal double line character.
 		/// </summary>
 		/// </summary>
-		public Rune HDLine = '\u2550';
+		public Rune HDbLine = '\u2550';
 
 
 		/// <summary>
 		/// <summary>
 		/// Vertical double line character.
 		/// Vertical double line character.
 		/// </summary>
 		/// </summary>
-		public Rune VDLine = '\u2551';
+		public Rune VDbLine = '\u2551';
 
 
 		/// <summary>
 		/// <summary>
 		/// Upper left double corner
 		/// Upper left double corner
 		/// </summary>
 		/// </summary>
-		public Rune ULDCorner = '\u2554';
+		public Rune ULDbCorner = '\u2554';
 
 
 		/// <summary>
 		/// <summary>
 		/// Lower left double corner
 		/// Lower left double corner
 		/// </summary>
 		/// </summary>
-		public Rune LLDCorner = '\u255a';
+		public Rune LLDbCorner = '\u255a';
 
 
 		/// <summary>
 		/// <summary>
 		/// Upper right double corner
 		/// Upper right double corner
 		/// </summary>
 		/// </summary>
-		public Rune URDCorner = '\u2557';
+		public Rune URDbCorner = '\u2557';
 
 
 		/// <summary>
 		/// <summary>
 		/// Lower right double corner
 		/// Lower right double corner
 		/// </summary>
 		/// </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>
 		/// <summary>
 		/// Upper left rounded corner
 		/// Upper left rounded corner
@@ -1174,6 +1164,157 @@ namespace Terminal.Gui {
 		/// Lower right rounded corner
 		/// Lower right rounded corner
 		/// </summary>
 		/// </summary>
 		public Rune LRRCorner = '\u256f';
 		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;
 		private Attribute currentAttribute;
 
 
 		/// <summary>
 		/// <summary>

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

@@ -16,17 +16,45 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		None,
 		None,
 		/// <summary>
 		/// <summary>
-		/// The border is drawn using single-width line glyphs.
+		/// The border is drawn using thin line glyphs.
 		/// </summary>
 		/// </summary>
 		Single,
 		Single,
 		/// <summary>
 		/// <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>
 		/// </summary>
 		Double,
 		Double,
 		/// <summary>
 		/// <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>
 		/// </summary>
 		Rounded,
 		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
 		// TODO: Support Ruler
 		///// <summary> 
 		///// <summary> 
 		///// The border is drawn as a diagnostic ruler ("|123456789...").
 		///// The border is drawn as a diagnostic ruler ("|123456789...").
@@ -248,39 +276,59 @@ namespace Terminal.Gui {
 			readonly Rune doubleH;
 			readonly Rune doubleH;
 			readonly Rune doubleV;
 			readonly Rune doubleV;
 			readonly Rune doubleBoth;
 			readonly Rune doubleBoth;
+			readonly Rune thickH;
+			readonly Rune thickV;
+			readonly Rune thickBoth;
 			readonly Rune normal;
 			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.round = round;
 				this.doubleH = doubleH;
 				this.doubleH = doubleH;
 				this.doubleV = doubleV;
 				this.doubleV = doubleV;
 				this.doubleBoth = doubleBoth;
 				this.doubleBoth = doubleBoth;
+				this.thickH = thickH;
+				this.thickV = thickV;
+				this.thickBoth = thickBoth;
 				this.normal = normal;
 				this.normal = normal;
 			}
 			}
 
 
 			public Rune? GetRuneForIntersects (ConsoleDriver driver, IntersectionDefinition [] intersects)
 			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 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 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) {
 				if (doubleHorizontal) {
 					return doubleVertical ? doubleBoth : doubleH;
 					return doubleVertical ? doubleBoth : doubleH;
 				}
 				}
-
 				if (doubleVertical) {
 				if (doubleVertical) {
 					return doubleV;
 					return doubleV;
 				}
 				}
 
 
+				if (thickHorizontal) {
+					return thickVertical ? thickBoth : thickH;
+				}
+				if (thickVertical) {
+					return thickV;
+				}
+
 				return useRounded ? round : normal;
 				return useRounded ? round : normal;
 			}
 			}
 		}
 		}
 
 
 		private class ULIntersectionRuneResolver : IntersectionRuneResolver {
 		private class ULIntersectionRuneResolver : IntersectionRuneResolver {
 			public ULIntersectionRuneResolver () :
 			public ULIntersectionRuneResolver () :
-				base ('╭', '╒', '╓', '╔', '┌')
+				base ('╭', '╒', '╓', '╔', '┍', '┎', '┏', '┌')
 			{
 			{
 
 
 			}
 			}
@@ -288,7 +336,7 @@ namespace Terminal.Gui {
 		private class URIntersectionRuneResolver : IntersectionRuneResolver {
 		private class URIntersectionRuneResolver : IntersectionRuneResolver {
 
 
 			public URIntersectionRuneResolver () :
 			public URIntersectionRuneResolver () :
-				base ('╮', '╕', '╖', '╗', '┐')
+				base ('╮', '╕', '╖', '╗', '┑', '┒', '┓', '┐')
 			{
 			{
 
 
 			}
 			}
@@ -296,14 +344,14 @@ namespace Terminal.Gui {
 		private class LLIntersectionRuneResolver : IntersectionRuneResolver {
 		private class LLIntersectionRuneResolver : IntersectionRuneResolver {
 
 
 			public LLIntersectionRuneResolver () :
 			public LLIntersectionRuneResolver () :
-				base ('╰', '╘', '╙', '╚', '└')
+				base ('╰', '╘', '╙', '╚', '┕', '┖', '┗', '└')
 			{
 			{
 
 
 			}
 			}
 		}
 		}
 		private class LRIntersectionRuneResolver : IntersectionRuneResolver {
 		private class LRIntersectionRuneResolver : IntersectionRuneResolver {
 			public LRIntersectionRuneResolver () :
 			public LRIntersectionRuneResolver () :
-				base ('╯', '╛', '╜', '╝', '┘')
+				base ('╯', '╛', '╜', '╝', '┙', '┚', '┛', '┘')
 			{
 			{
 
 
 			}
 			}
@@ -311,35 +359,35 @@ namespace Terminal.Gui {
 
 
 		private class TopTeeIntersectionRuneResolver : IntersectionRuneResolver {
 		private class TopTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public TopTeeIntersectionRuneResolver () :
 			public TopTeeIntersectionRuneResolver () :
-				base ('┬', '╤', '╥', '╦', '┬')
+				base ('┬', '╤', '╥', '╦', '┯', '┰', '┳', '┬')
 			{
 			{
 
 
 			}
 			}
 		}
 		}
 		private class LeftTeeIntersectionRuneResolver : IntersectionRuneResolver {
 		private class LeftTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public LeftTeeIntersectionRuneResolver () :
 			public LeftTeeIntersectionRuneResolver () :
-				base ('├', '╞', '╟', '╠', '├')
+				base ('├', '╞', '╟', '╠', '┝', '┠', '┣', '├')
 			{
 			{
 
 
 			}
 			}
 		}
 		}
 		private class RightTeeIntersectionRuneResolver : IntersectionRuneResolver {
 		private class RightTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public RightTeeIntersectionRuneResolver () :
 			public RightTeeIntersectionRuneResolver () :
-				base ('┤', '╡', '╢', '╣', '┤')
+				base ('┤', '╡', '╢', '╣', '┥', '┨', '┫', '┤')
 			{
 			{
 
 
 			}
 			}
 		}
 		}
 		private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver {
 		private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver {
 			public BottomTeeIntersectionRuneResolver () :
 			public BottomTeeIntersectionRuneResolver () :
-				base ('┴', '╧', '╨', '╩', '┴')
+				base ('┴', '╧', '╨', '╩', '┷', '┸', '┻', '┴')
 			{
 			{
 
 
 			}
 			}
 		}
 		}
 		private class CrosshairIntersectionRuneResolver : IntersectionRuneResolver {
 		private class CrosshairIntersectionRuneResolver : IntersectionRuneResolver {
 			public CrosshairIntersectionRuneResolver () :
 			public CrosshairIntersectionRuneResolver () :
-				base ('┼', '╪', '╫', '╬', '┼')
+				base ('┼', '╪', '╫', '╬', '┿', '╂', '╋', '┼')
 			{
 			{
 
 
 			}
 			}
@@ -357,23 +405,46 @@ namespace Terminal.Gui {
 				return runeResolvers [runeType].GetRuneForIntersects (driver, intersects);
 				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 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
 			// TODO: Support ruler
 			//var useRuler = intersects.Any (i => i.Line.Style == LineStyle.Ruler && i.Line.Length != 0);
 			//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) {
 			switch (runeType) {
 			case IntersectionRuneType.None:
 			case IntersectionRuneType.None:
 				return null;
 				return null;
 			case IntersectionRuneType.Dot:
 			case IntersectionRuneType.Dot:
 				return (Rune)'.';
 				return (Rune)'.';
 			case IntersectionRuneType.HLine:
 			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:
 			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);
 			default: throw new Exception ("Could not find resolver or switch case for " + nameof (runeType) + ":" + runeType);
 			}
 			}
 		}
 		}

+ 5 - 1
Terminal.Gui/FileServices/FileDialogHistory.cs

@@ -19,12 +19,15 @@ namespace Terminal.Gui {
 
 
 			IDirectoryInfo goTo = null;
 			IDirectoryInfo goTo = null;
 			FileSystemInfoStats restoreSelection = null;
 			FileSystemInfoStats restoreSelection = null;
+			string restorePath = null;
 
 
 			if (this.CanBack ()) {
 			if (this.CanBack ()) {
 
 
 				var backTo = this.back.Pop ();
 				var backTo = this.back.Pop ();
 				goTo = backTo.Directory;
 				goTo = backTo.Directory;
 				restoreSelection = backTo.Selected;
 				restoreSelection = backTo.Selected;
+				restorePath = backTo.Path;
+
 			} else if (this.CanUp ()) {
 			} else if (this.CanUp ()) {
 				goTo = this.dlg.State?.Directory.Parent;
 				goTo = this.dlg.State?.Directory.Parent;
 			}
 			}
@@ -35,7 +38,8 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			this.forward.Push (this.dlg.State);
 			this.forward.Push (this.dlg.State);
-			this.dlg.PushState (goTo, false, true, false);
+			this.dlg.PushState (goTo, false, true, false, restorePath);
+
 
 
 			if (restoreSelection != null) {
 			if (restoreSelection != null) {
 				this.dlg.RestoreSelection (restoreSelection.FileSystemInfo);
 				this.dlg.RestoreSelection (restoreSelection.FileSystemInfo);

+ 11 - 3
Terminal.Gui/FileServices/FileDialogState.cs

@@ -10,10 +10,18 @@ namespace Terminal.Gui {
 
 
 		public FileSystemInfoStats Selected { get; set; }
 		public FileSystemInfoStats Selected { get; set; }
 		protected readonly FileDialog Parent;
 		protected readonly FileDialog Parent;
+
+		/// <summary>
+		/// Gets what was entered in the path text box of the dialog
+		/// when the state was active.
+		/// </summary>
+		public string Path { get; }
+		
 		public FileDialogState (IDirectoryInfo dir, FileDialog parent)
 		public FileDialogState (IDirectoryInfo dir, FileDialog parent)
 		{
 		{
 			this.Directory = dir;
 			this.Directory = dir;
 			Parent = parent;
 			Parent = parent;
+			Path = parent.Path;
 
 
 			this.RefreshChildren ();
 			this.RefreshChildren ();
 		}
 		}
@@ -36,9 +44,9 @@ namespace Terminal.Gui {
 
 
 				// if directories only
 				// if directories only
 				if (Parent.OpenMode == OpenMode.Directory) {
 				if (Parent.OpenMode == OpenMode.Directory) {
-					children = dir.GetDirectories ().Select (e => new FileSystemInfoStats (e)).ToList ();
+					children = dir.GetDirectories ().Select (e => new FileSystemInfoStats (e, Parent.Style.Culture)).ToList ();
 				} else {
 				} else {
-					children = dir.GetFileSystemInfos ().Select (e => new FileSystemInfoStats (e)).ToList ();
+					children = dir.GetFileSystemInfos ().Select (e => new FileSystemInfoStats (e, Parent.Style.Culture)).ToList ();
 				}
 				}
 
 
 				// if only allowing specific file types
 				// if only allowing specific file types
@@ -57,7 +65,7 @@ namespace Terminal.Gui {
 
 
 				// allow navigating up as '..'
 				// allow navigating up as '..'
 				if (dir.Parent != null) {
 				if (dir.Parent != null) {
-					children.Add (new FileSystemInfoStats (dir.Parent) { IsParent = true });
+					children.Add (new FileSystemInfoStats (dir.Parent, Parent.Style.Culture) { IsParent = true });
 				}
 				}
 
 
 				return children;
 				return children;

+ 6 - 0
Terminal.Gui/FileServices/FileDialogStyle.cs

@@ -37,6 +37,12 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public bool UseColors { get; set; }
 		public bool UseColors { get; set; }
 
 
+		/// <summary>
+		/// Gets or sets the culture to use (e.g. for number formatting).
+		/// Defaults to <see cref="CultureInfo.CurrentUICulture"/>.
+		/// <summary>
+		public CultureInfo Culture {get;set;} = CultureInfo.CurrentUICulture;
+
 		/// <summary>
 		/// <summary>
 		/// Sets a <see cref="ColorScheme"/> to use for directories rows of
 		/// Sets a <see cref="ColorScheme"/> to use for directories rows of
 		/// the <see cref="TableView"/>.
 		/// the <see cref="TableView"/>.

+ 7 - 6
Terminal.Gui/FileServices/FileSystemInfoStats.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.IO;
 using System.IO.Abstractions;
 using System.IO.Abstractions;
 using System.Linq;
 using System.Linq;
@@ -33,14 +34,15 @@ namespace Terminal.Gui {
 		/// Initializes a new instance of the <see cref="FileSystemInfoStats"/> class.
 		/// Initializes a new instance of the <see cref="FileSystemInfoStats"/> class.
 		/// </summary>
 		/// </summary>
 		/// <param name="fsi">The directory of path to wrap.</param>
 		/// <param name="fsi">The directory of path to wrap.</param>
-		public FileSystemInfoStats (IFileSystemInfo fsi)
+		/// <param name="culture"></param>
+		public FileSystemInfoStats (IFileSystemInfo fsi, CultureInfo culture)
 		{
 		{
 			this.FileSystemInfo = fsi;
 			this.FileSystemInfo = fsi;
 			this.LastWriteTime = fsi.LastWriteTime;
 			this.LastWriteTime = fsi.LastWriteTime;
 
 
 			if (fsi is IFileInfo fi) {
 			if (fsi is IFileInfo fi) {
 				this.MachineReadableLength = fi.Length;
 				this.MachineReadableLength = fi.Length;
-				this.HumanReadableLength = GetHumanReadableFileSize (this.MachineReadableLength);				
+				this.HumanReadableLength = GetHumanReadableFileSize (this.MachineReadableLength, culture);
 				this.Type = fi.Extension;
 				this.Type = fi.Extension;
 			} else {
 			} else {
 				this.HumanReadableLength = string.Empty;
 				this.HumanReadableLength = string.Empty;
@@ -112,11 +114,11 @@ namespace Terminal.Gui {
 			return 100;
 			return 100;
 		}
 		}
 
 
-		private static string GetHumanReadableFileSize (long value)
+		private static string GetHumanReadableFileSize (long value, CultureInfo culture)
 		{
 		{
 
 
 			if (value < 0) {
 			if (value < 0) {
-				return "-" + GetHumanReadableFileSize (-value);
+				return "-" + GetHumanReadableFileSize (-value, culture);
 			}
 			}
 
 
 			if (value == 0) {
 			if (value == 0) {
@@ -125,8 +127,7 @@ namespace Terminal.Gui {
 
 
 			int mag = (int)Math.Log (value, ByteConversion);
 			int mag = (int)Math.Log (value, ByteConversion);
 			double adjustedSize = value / Math.Pow (1000, mag);
 			double adjustedSize = value / Math.Pow (1000, mag);
-
-			return string.Format ("{0:n2} {1}", adjustedSize, SizeSuffixes [mag]);
+			return string.Format (culture.NumberFormat,"{0:n2} {1}", adjustedSize, SizeSuffixes [mag]);
 		}
 		}
 	}
 	}
 }
 }

+ 61 - 25
Terminal.Gui/Views/FileDialog.cs

@@ -148,7 +148,7 @@ namespace Terminal.Gui {
 					// TODO: Fiddle factor, seems the Bounds are wrong for someone
 					// TODO: Fiddle factor, seems the Bounds are wrong for someone
 					- 2)
 					- 2)
 			};
 			};
-			this.btnOk.Clicked += (s, e) => this.Accept ();
+			this.btnOk.Clicked += (s, e) => this.Accept (true);
 			this.btnOk.KeyPress += (s, k) => {
 			this.btnOk.KeyPress += (s, k) => {
 				this.NavigateIf (k, Key.CursorLeft, this.btnCancel);
 				this.NavigateIf (k, Key.CursorLeft, this.btnCancel);
 				this.NavigateIf (k, Key.CursorUp, this.tableView);
 				this.NavigateIf (k, Key.CursorUp, this.tableView);
@@ -772,7 +772,11 @@ namespace Terminal.Gui {
 		{
 		{
 			if (!keyEvent.Handled && keyEvent.KeyEvent.Key == isKey) {
 			if (!keyEvent.Handled && keyEvent.KeyEvent.Key == isKey) {
 				keyEvent.Handled = true;
 				keyEvent.Handled = true;
-				this.Accept ();
+
+				// User hit Enter in text box so probably wants the
+				// contents of the text box as their selection not
+				// whatever lingering selection is in TableView
+				this.Accept (false);
 			}
 			}
 		}
 		}
 
 
@@ -782,7 +786,12 @@ namespace Terminal.Gui {
 				return;
 				return;
 			}
 			}
 
 
-			this.MultiSelected = toMultiAccept.Select (s => s.FileSystemInfo.FullName).ToList ().AsReadOnly ();
+			// Don't include ".." (IsParent) in multiselections
+			this.MultiSelected = toMultiAccept
+				.Where(s=>!s.IsParent)
+				.Select (s => s.FileSystemInfo.FullName)
+				.ToList ().AsReadOnly ();
+
 			this.tbPath.Text = this.MultiSelected.Count == 1 ? this.MultiSelected [0] : string.Empty;
 			this.tbPath.Text = this.MultiSelected.Count == 1 ? this.MultiSelected [0] : string.Empty;
 
 
 			FinishAccept ();
 			FinishAccept ();
@@ -805,8 +814,13 @@ namespace Terminal.Gui {
 			FinishAccept ();
 			FinishAccept ();
 		}
 		}
 
 
-		private void Accept ()
+		private void Accept (bool allowMulti)
 		{
 		{
+			if(allowMulti && TryAcceptMulti())
+			{
+				return;
+			}
+
 			if (!this.IsCompatibleWithOpenMode (this.tbPath.Text.ToString (), out string reason)) {
 			if (!this.IsCompatibleWithOpenMode (this.tbPath.Text.ToString (), out string reason)) {
 				if (reason != null) {
 				if (reason != null) {
 					feedback = reason;
 					feedback = reason;
@@ -1004,20 +1018,9 @@ namespace Terminal.Gui {
 
 
 		private void CellActivate (object sender, CellActivatedEventArgs obj)
 		private void CellActivate (object sender, CellActivatedEventArgs obj)
 		{
 		{
-			var multi = this.MultiRowToStats ();
-			string reason = null;
-			if (multi.Any ()) {
-				if (multi.All (m => this.IsCompatibleWithOpenMode (m.FileSystemInfo.FullName, out reason))) {
-					this.Accept (multi);
-					return;
-				} else {
-					if (reason != null) {
-						feedback = reason;
-						SetNeedsDisplay ();
-					}
-
-					return;
-				}
+			if(TryAcceptMulti())
+			{
+				return;
 			}
 			}
 
 
 			var stats = this.RowToStats (obj.Row);
 			var stats = this.RowToStats (obj.Row);
@@ -1032,6 +1035,33 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
+		private bool TryAcceptMulti ()
+		{
+			var multi = this.MultiRowToStats ();
+			string reason = null;
+			
+			if (!multi.Any ())
+			{
+				return false;
+			}
+			
+			if (multi.All (m => this.IsCompatibleWithOpenMode (
+				m.FileSystemInfo.FullName, out reason)))
+			{
+				this.Accept (multi);
+				return true;
+			} 
+			else 
+			{
+				if (reason != null) {
+					feedback = reason;
+					SetNeedsDisplay ();
+				}
+
+				return false;
+			}
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Returns true if there are no <see cref="AllowedTypes"/> or one of them agrees
 		/// Returns true if there are no <see cref="AllowedTypes"/> or one of them agrees
 		/// that <paramref name="file"/> <see cref="IAllowedType.IsAllowed(string)"/>.
 		/// that <paramref name="file"/> <see cref="IAllowedType.IsAllowed(string)"/>.
@@ -1118,7 +1148,8 @@ namespace Terminal.Gui {
 		/// <param name="addCurrentStateToHistory"></param>
 		/// <param name="addCurrentStateToHistory"></param>
 		/// <param name="setPathText"></param>
 		/// <param name="setPathText"></param>
 		/// <param name="clearForward"></param>
 		/// <param name="clearForward"></param>
-		internal void PushState (IDirectoryInfo d, bool addCurrentStateToHistory, bool setPathText = true, bool clearForward = true)
+		/// <param name="pathText">Optional alternate string to set path to.</param>
+		internal void PushState (IDirectoryInfo d, bool addCurrentStateToHistory, bool setPathText = true, bool clearForward = true, string pathText = null)
 		{
 		{
 			// no change of state
 			// no change of state
 			if (d == this.State?.Directory) {
 			if (d == this.State?.Directory) {
@@ -1128,7 +1159,7 @@ namespace Terminal.Gui {
 				return;
 				return;
 			}
 			}
 
 
-			PushState (new FileDialogState (d, this), addCurrentStateToHistory, setPathText, clearForward);
+			PushState (new FileDialogState (d, this), addCurrentStateToHistory, setPathText, clearForward, pathText);
 		}
 		}
 
 
 		private void RefreshState ()
 		private void RefreshState ()
@@ -1137,7 +1168,7 @@ namespace Terminal.Gui {
 			PushState (State, false, false, false);
 			PushState (State, false, false, false);
 		}
 		}
 
 
-		private void PushState (FileDialogState newState, bool addCurrentStateToHistory, bool setPathText = true, bool clearForward = true)
+		private void PushState (FileDialogState newState, bool addCurrentStateToHistory, bool setPathText = true, bool clearForward = true, string pathText = null)
 		{
 		{
 			if (State is SearchState search) {
 			if (State is SearchState search) {
 				search.Cancel ();
 				search.Cancel ();
@@ -1153,6 +1184,12 @@ namespace Terminal.Gui {
 
 
 				this.tbPath.Autocomplete.ClearSuggestions ();
 				this.tbPath.Autocomplete.ClearSuggestions ();
 
 
+				if(pathText != null)
+				{
+					this.tbPath.Text = pathText;
+					this.tbPath.MoveEnd ();
+				}
+				else
 				if (setPathText) {
 				if (setPathText) {
 					this.tbPath.Text = newState.Directory.FullName;
 					this.tbPath.Text = newState.Directory.FullName;
 					this.tbPath.MoveEnd ();
 					this.tbPath.MoveEnd ();
@@ -1228,10 +1265,9 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// If <see cref="TableView.MultiSelect"/> is on and multiple rows are selected
-		/// this returns a union of all <see cref="FileSystemInfoStats"/> in the selection.
+		/// If <see cref="TableView.MultiSelect"/> is this returns a union of all
+		/// <see cref="FileSystemInfoStats"/> in the selection.
 		/// </summary>
 		/// </summary>
-		/// <remarks>Returns an empty collection if there are not at least 2 rows in the selection</remarks>
 		/// <returns></returns>
 		/// <returns></returns>
 		private IEnumerable<FileSystemInfoStats> MultiRowToStats ()
 		private IEnumerable<FileSystemInfoStats> MultiRowToStats ()
 		{
 		{
@@ -1248,7 +1284,7 @@ namespace Terminal.Gui {
 				}
 				}
 			}
 			}
 
 
-			return toReturn.Count > 1 ? toReturn : Enumerable.Empty<FileSystemInfoStats> ();
+			return toReturn;
 		}
 		}
 		private FileSystemInfoStats RowToStats (int rowIndex)
 		private FileSystemInfoStats RowToStats (int rowIndex)
 		{
 		{

+ 19 - 6
Terminal.Gui/Views/TableView/TableView.cs

@@ -530,10 +530,6 @@ namespace Terminal.Gui {
 			var rowScheme = (Style.RowColorGetter?.Invoke (
 			var rowScheme = (Style.RowColorGetter?.Invoke (
 				new RowColorGetterArgs (Table, rowToRender))) ?? ColorScheme;
 				new RowColorGetterArgs (Table, rowToRender))) ?? ColorScheme;
 
 
-			//render start of line
-			if (style.ShowVerticalCellLines)
-				AddRune (0, row, Driver.VLine);
-
 			//start by clearing the entire line
 			//start by clearing the entire line
 			Move (0, row);
 			Move (0, row);
 
 
@@ -613,6 +609,11 @@ namespace Terminal.Gui {
 				if (!FullRowSelect)
 				if (!FullRowSelect)
 					Driver.SetAttribute (Enabled ? rowScheme.Normal : rowScheme.Disabled);
 					Driver.SetAttribute (Enabled ? rowScheme.Normal : rowScheme.Disabled);
 
 
+				if(style.AlwaysUseNormalColorForVerticalCellLines && style.ShowVerticalCellLines) {
+
+					Driver.SetAttribute (rowScheme.Normal);
+				}
+
 				RenderSeparator (current.X - 1, row, false);
 				RenderSeparator (current.X - 1, row, false);
 
 
 				if (Style.ExpandLastColumn == false && current.IsVeryLast) {
 				if (Style.ExpandLastColumn == false && current.IsVeryLast) {
@@ -620,9 +621,15 @@ namespace Terminal.Gui {
 				}
 				}
 			}
 			}
 
 
-			//render end of line
-			if (style.ShowVerticalCellLines)
+			if (style.ShowVerticalCellLines) {
+
+				Driver.SetAttribute (rowScheme.Normal);
+
+				//render start and end of line
+				AddRune (0, row, Driver.VLine);
 				AddRune (Bounds.Width - 1, row, Driver.VLine);
 				AddRune (Bounds.Width - 1, row, Driver.VLine);
+			}
+				
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -1858,6 +1865,12 @@ namespace Terminal.Gui {
 			/// </summary>
 			/// </summary>
 			public bool InvertSelectedCellFirstCharacter { get; set; } = false;
 			public bool InvertSelectedCellFirstCharacter { get; set; } = false;
 
 
+			/// <summary>
+			/// Gets or sets a flag indicating whether to force <see cref="ColorScheme.Normal"/> use when rendering
+			/// vertical cell lines (even when <see cref="FullRowSelect"/> is on).
+			/// </summary>
+			public bool AlwaysUseNormalColorForVerticalCellLines { get; set; } = false;
+
 			/// <summary>
 			/// <summary>
 			/// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc)
 			/// Collection of columns for which you want special rendering (e.g. custom column lengths, text alignment etc)
 			/// </summary>
 			/// </summary>

+ 3 - 3
Terminal.Gui/Views/ToplevelEventArgs.cs

@@ -9,10 +9,10 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Creates a new instance of the <see cref="ToplevelClosingEventArgs"/> class.
 		/// Creates a new instance of the <see cref="ToplevelClosingEventArgs"/> class.
 		/// </summary>
 		/// </summary>
-		/// <param name="Toplevel"></param>
-		public ToplevelEventArgs (Toplevel Toplevel)
+		/// <param name="toplevel"></param>
+		public ToplevelEventArgs (Toplevel toplevel)
 		{
 		{
-			Toplevel = Toplevel;
+			Toplevel = toplevel;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>

+ 2 - 2
UICatalog/Scenarios/BackgroundWorkerCollection.cs

@@ -107,7 +107,7 @@ namespace UICatalog.Scenarios {
 					var top = Application.OverlappedChildren.Find ((x) => x.Data.ToString () == "WorkerApp");
 					var top = Application.OverlappedChildren.Find ((x) => x.Data.ToString () == "WorkerApp");
 					item.Checked = top.Visible = (bool)!item.Checked;
 					item.Checked = top.Visible = (bool)!item.Checked;
 					if (top.Visible) {
 					if (top.Visible) {
-						Application.MoveToOverlappedChild (null);
+						Application.MoveToOverlappedChild (top);
 					} else {
 					} else {
 						Application.OverlappedTop.SetNeedsDisplay ();
 						Application.OverlappedTop.SetNeedsDisplay ();
 					}
 					}
@@ -139,7 +139,7 @@ namespace UICatalog.Scenarios {
 						item.Checked = false;
 						item.Checked = false;
 					}
 					}
 					item.Action += () => {
 					item.Action += () => {
-						Application.MoveToOverlappedChild (null);
+						Application.MoveToOverlappedChild (top);
 					};
 					};
 					menuItems.Add (item);
 					menuItems.Add (item);
 				}
 				}

+ 2 - 2
UICatalog/Scenarios/BordersOnContainers.cs

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

+ 2 - 2
UICatalog/Scenarios/LineCanvasExperiment.cs

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

+ 63 - 19
UICatalog/Scenarios/LineDrawing.cs

@@ -12,11 +12,12 @@ namespace UICatalog.Scenarios {
 
 
 		public override void Setup ()
 		public override void Setup ()
 		{
 		{
-			var toolsWidth = 8;
+			var toolsWidth = 12;
 
 
 			var canvas = new DrawingArea {
 			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) {
 			var tools = new ToolsView (toolsWidth) {
@@ -45,25 +46,26 @@ namespace UICatalog.Scenarios {
 				{ new Point(3,1),Color.Green},
 				{ new Point(3,1),Color.Green},
 				{ new Point(5,1),Color.BrightBlue},
 				{ new Point(5,1),Color.BrightBlue},
 				{ new Point(7,1),Color.Black},
 				{ 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)
 			public ToolsView (int width)
 			{
 			{
 				grid = new LineCanvas ();
 				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 (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);
 				grid.AddLine (new Point (0, 4), width + 1, Orientation.Horizontal, LineStyle.Single);
 			}
 			}
 			public override void Redraw (Rect bounds)
 			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));
 				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 (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)
 			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) {
 					if (mouseEvent.X == 3 && mouseEvent.Y == 3) {
 
 
-						SetStyle?.Invoke (LineStyle.Double);
+						SetStyle?.Invoke (LineStyle.Dashed);
 						return true;
 						return true;
 					}
 					}
 					if (mouseEvent.X == 5 && mouseEvent.Y == 3) {
 					if (mouseEvent.X == 5 && mouseEvent.Y == 3) {
 
 
-						SetStyle?.Invoke (LineStyle.Single);
+						SetStyle?.Invoke (LineStyle.Dotted);
 						return true;
 						return true;
 					}
 					}
 					if (mouseEvent.X == 7 && mouseEvent.Y == 3) {
 					if (mouseEvent.X == 7 && mouseEvent.Y == 3) {
@@ -115,6 +129,36 @@ namespace UICatalog.Scenarios {
 						SetStyle?.Invoke (LineStyle.Rounded);
 						SetStyle?.Invoke (LineStyle.Rounded);
 						return true;
 						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);
 				return base.OnMouseEvent (mouseEvent);
@@ -169,13 +213,13 @@ namespace UICatalog.Scenarios {
 
 
 				if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed)) {
 				if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed)) {
 					if (currentLineStart == null) {
 					if (currentLineStart == null) {
-						currentLineStart = new Point (mouseEvent.X, mouseEvent.Y);
+						currentLineStart = new Point (mouseEvent.X - 1, mouseEvent.Y - 1);
 					}
 					}
 				} else {
 				} else {
 					if (currentLineStart != null) {
 					if (currentLineStart != null) {
 
 
 						var start = currentLineStart.Value;
 						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 orientation = Orientation.Vertical;
 						var length = end.Y - start.Y;
 						var length = end.Y - start.Y;
 
 

+ 10 - 0
UICatalog/Scenarios/TableEditor.cs

@@ -25,6 +25,7 @@ namespace UICatalog.Scenarios {
 		private MenuItem miCellLines;
 		private MenuItem miCellLines;
 		private MenuItem miFullRowSelect;
 		private MenuItem miFullRowSelect;
 		private MenuItem miExpandLastColumn;
 		private MenuItem miExpandLastColumn;
+		private MenuItem miAlwaysUseNormalColorForVerticalCellLines;
 		private MenuItem miSmoothScrolling;
 		private MenuItem miSmoothScrolling;
 		private MenuItem miAlternatingColors;
 		private MenuItem miAlternatingColors;
 		private MenuItem miCursor;
 		private MenuItem miCursor;
@@ -67,6 +68,7 @@ namespace UICatalog.Scenarios {
 					miFullRowSelect =new MenuItem ("_FullRowSelect", "", () => ToggleFullRowSelect()){Checked = tableView.FullRowSelect, CheckType = MenuItemCheckStyle.Checked },
 					miFullRowSelect =new MenuItem ("_FullRowSelect", "", () => ToggleFullRowSelect()){Checked = tableView.FullRowSelect, CheckType = MenuItemCheckStyle.Checked },
 					miCellLines =new MenuItem ("_CellLines", "", () => ToggleCellLines()){Checked = tableView.Style.ShowVerticalCellLines, CheckType = MenuItemCheckStyle.Checked },
 					miCellLines =new MenuItem ("_CellLines", "", () => ToggleCellLines()){Checked = tableView.Style.ShowVerticalCellLines, CheckType = MenuItemCheckStyle.Checked },
 					miExpandLastColumn = new MenuItem ("_ExpandLastColumn", "", () => ToggleExpandLastColumn()){Checked = tableView.Style.ExpandLastColumn, CheckType = MenuItemCheckStyle.Checked },
 					miExpandLastColumn = new MenuItem ("_ExpandLastColumn", "", () => ToggleExpandLastColumn()){Checked = tableView.Style.ExpandLastColumn, CheckType = MenuItemCheckStyle.Checked },
+					miAlwaysUseNormalColorForVerticalCellLines = new MenuItem ("_AlwaysUseNormalColorForVerticalCellLines", "", () => ToggleAlwaysUseNormalColorForVerticalCellLines()){Checked = tableView.Style.AlwaysUseNormalColorForVerticalCellLines, CheckType = MenuItemCheckStyle.Checked },
 					miSmoothScrolling = new MenuItem ("_SmoothHorizontalScrolling", "", () => ToggleSmoothScrolling()){Checked = tableView.Style.SmoothHorizontalScrolling, CheckType = MenuItemCheckStyle.Checked },
 					miSmoothScrolling = new MenuItem ("_SmoothHorizontalScrolling", "", () => ToggleSmoothScrolling()){Checked = tableView.Style.SmoothHorizontalScrolling, CheckType = MenuItemCheckStyle.Checked },
 					new MenuItem ("_AllLines", "", () => ToggleAllCellLines()),
 					new MenuItem ("_AllLines", "", () => ToggleAllCellLines()),
 					new MenuItem ("_NoLines", "", () => ToggleNoCellLines()),
 					new MenuItem ("_NoLines", "", () => ToggleNoCellLines()),
@@ -435,6 +437,14 @@ namespace UICatalog.Scenarios {
 			tableView.Update ();
 			tableView.Update ();
 
 
 		}
 		}
+
+		private void ToggleAlwaysUseNormalColorForVerticalCellLines()
+		{
+			miAlwaysUseNormalColorForVerticalCellLines.Checked = !miAlwaysUseNormalColorForVerticalCellLines.Checked;
+			tableView.Style.AlwaysUseNormalColorForVerticalCellLines = (bool)miAlwaysUseNormalColorForVerticalCellLines.Checked;
+
+			tableView.Update ();
+		}
 		private void ToggleSmoothScrolling ()
 		private void ToggleSmoothScrolling ()
 		{
 		{
 			miSmoothScrolling.Checked = !miSmoothScrolling.Checked;
 			miSmoothScrolling.Checked = !miSmoothScrolling.Checked;

+ 14 - 14
UnitTests/Dialogs/WizardTests.cs

@@ -118,12 +118,12 @@ namespace Terminal.Gui.DialogTests {
 			var btnNextText = "Finish";
 			var btnNextText = "Finish";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 			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 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 wizard = new Wizard () { Title = title, Width = width, Height = height };
 			var runstate = Application.Begin (wizard);
 			var runstate = Application.Begin (wizard);
@@ -150,13 +150,13 @@ namespace Terminal.Gui.DialogTests {
 			var btnNextText = "Finish"; // "Next";
 			var btnNextText = "Finish"; // "Next";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 			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 row3 = row2;
 			var row4 = row3;
 			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 };
 			var wizard = new Wizard () { Title = title, Width = width, Height = height };
 			wizard.AddStep (new Wizard.WizardStep () { Title = stepTitle });
 			wizard.AddStep (new Wizard.WizardStep () { Title = stepTitle });
@@ -220,13 +220,13 @@ namespace Terminal.Gui.DialogTests {
 			var btnNextText = "Finish";
 			var btnNextText = "Finish";
 			var btnNext = $"{d.LeftBracket}{d.LeftDefaultIndicator} {btnNextText} {d.RightDefaultIndicator}{d.RightBracket}";
 			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
 			// 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 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 };
 			var wizard = new Wizard () { Title = title, Width = width, Height = height };
 			wizard.AddStep (new Wizard.WizardStep () { Title = "ABCD" });
 			wizard.AddStep (new Wizard.WizardStep () { Title = "ABCD" });

+ 92 - 4
UnitTests/Drawing/LineCanvasTests.cs

@@ -581,7 +581,7 @@ namespace Terminal.Gui.DrawingTests {
 			// outer box
 			// outer box
 			canvas.AddLine (new Point (0, 0), 10, Orientation.Horizontal, LineStyle.Rounded);
 			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.
 			// this results in a rounded corner being used.
 			canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Single);
 			canvas.AddLine (new Point (9, 0), 5, Orientation.Vertical, LineStyle.Single);
 			canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Rounded);
 			canvas.AddLine (new Point (9, 4), -10, Orientation.Horizontal, LineStyle.Rounded);
@@ -688,8 +688,96 @@ namespace Terminal.Gui.DrawingTests {
 			TestHelpers.AssertDriverContentsAre (looksLike, output);
 			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 ();
 			var canvas = new LineCanvas ();
 
 
@@ -705,7 +793,7 @@ namespace Terminal.Gui.DrawingTests {
 		}
 		}
 
 
 		[Fact, SetupFakeDriver]
 		[Fact, SetupFakeDriver]
-		public void Top_Left_From_TopRigth_LeftUp ()
+		public void Top_Left_From_TopRight_LeftUp ()
 		{
 		{
 			var canvas = new LineCanvas ();
 			var canvas = new LineCanvas ();
 
 

+ 324 - 46
UnitTests/FileServices/FileDialogTests.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.IO;
 using System.IO.Abstractions.TestingHelpers;
 using System.IO.Abstractions.TestingHelpers;
 using System.Linq;
 using System.Linq;
@@ -128,40 +129,279 @@ namespace Terminal.Gui.FileServicesTests {
 			Assert.False (dlg.Canceled);
 			Assert.False (dlg.Canceled);
 		}
 		}
 
 
-		[Fact, AutoInitShutdown]
-		public void TestDirectoryContents_Linux ()
+		[Theory, AutoInitShutdown]
+		[InlineData(true,true)]
+		[InlineData(true,false)]
+		[InlineData(false,true)]
+		[InlineData(false,false)]
+		public void PickDirectory_DirectTyping (bool openModeMixed, bool multiple)
 		{
 		{
-			if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform (System.Runtime.InteropServices.OSPlatform.Windows)) {
-				// Cannot run test except on linux :( 
-				// See: https://github.com/TestableIO/System.IO.Abstractions/issues/800
-				return;
+			var dlg = GetDialog();
+			dlg.OpenMode = openModeMixed ? OpenMode.Mixed : OpenMode.Directory;
+			dlg.AllowsMultipleSelection = multiple;
+
+			// whe first opening the text field will have select all on
+			// so to add to current path user must press End or right
+			Send ('>', ConsoleKey.RightArrow, false);
+
+			Send("subfolder");
+
+			// Dialog has not yet been confirmed with a choice
+			Assert.True(dlg.Canceled);
+
+			// Now it has
+			Send ('\n', ConsoleKey.Enter, false);
+			Assert.False(dlg.Canceled);
+			AssertIsTheSubfolder(dlg.Path);
+		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData(true,true)]
+		[InlineData(true,false)]
+		[InlineData(false,true)]
+		[InlineData(false,false)]
+		public void PickDirectory_ArrowNavigation (bool openModeMixed, bool multiple)
+		{
+			var dlg = GetDialog();
+			dlg.OpenMode = openModeMixed ? OpenMode.Mixed : OpenMode.Directory;
+			dlg.AllowsMultipleSelection = multiple;
+
+			Assert.IsType<TextField>(dlg.MostFocused);
+			Send ('v', ConsoleKey.DownArrow, false);
+			Assert.IsType<TableView>(dlg.MostFocused);
+
+			// Should be selecting ..
+			Send ('v', ConsoleKey.DownArrow, false);
+
+			// Down to the directory
+			Assert.True(dlg.Canceled);
+			// Alt+O to open (enter would just navigate into the child dir)
+			Send ('o', ConsoleKey.O, false,true);
+			Assert.False(dlg.Canceled);
+
+			AssertIsTheSubfolder(dlg.Path);
+		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData(true)]
+		[InlineData(false)]
+		public void MultiSelectDirectory_CannotToggleDotDot (bool acceptWithEnter)
+		{
+			var dlg = GetDialog();
+			dlg.OpenMode = OpenMode.Directory;
+			dlg.AllowsMultipleSelection = true;
+			IReadOnlyCollection<string> eventMultiSelected = null;
+			dlg.FilesSelected += (s,e)=>
+			{
+				eventMultiSelected  = e.Dialog.MultiSelected;
+			};
+
+			Assert.IsType<TextField>(dlg.MostFocused);
+			Send ('v', ConsoleKey.DownArrow, false);
+			Assert.IsType<TableView>(dlg.MostFocused);
+
+			// Try to toggle '..'
+			Send (' ', ConsoleKey.Spacebar, false);
+			Send ('v', ConsoleKey.DownArrow, false);
+			// Toggle subfolder
+			Send (' ', ConsoleKey.Spacebar, false);
+
+			Assert.True(dlg.Canceled);
+
+			if(acceptWithEnter)
+			{
+				Send ('\n', ConsoleKey.Enter);
+			}
+			else
+			{
+				Send ('o', ConsoleKey.O,false,true);
 			}
 			}
+			Assert.False(dlg.Canceled);
+
+			Assert.Multiple(
+				()=>{
+					// Only the subfolder should be selected
+					Assert.Equal(1,dlg.MultiSelected.Count);
+					AssertIsTheSubfolder(dlg.Path);
+					AssertIsTheSubfolder(dlg.MultiSelected.Single());
+				},
+				()=>{
+					// Event should also agree with the final state
+					Assert.NotNull(eventMultiSelected);
+					Assert.Equal(1,eventMultiSelected.Count);
+					AssertIsTheSubfolder(eventMultiSelected.Single());
+				}
+			);
+		}
+		
+		[Fact, AutoInitShutdown]
+		public void DotDot_MovesToRoot_ThenPressBack ()
+		{
+			var dlg = GetDialog();
+			dlg.OpenMode = OpenMode.Directory;
+			dlg.AllowsMultipleSelection = true;
+			bool selected = false;
+			dlg.FilesSelected += (s,e)=>
+			{
+				selected = true;
+			};
 
 
-			// Arrange
-			var fileSystem = new MockFileSystem (new Dictionary<string, MockFileData> (), "/");
-			fileSystem.MockTime (() => new DateTime (2010, 01, 01, 11, 12, 43));
+			AssertIsTheStartingDirectory(dlg.Path);
 
 
-			fileSystem.AddFile (@"/myfile.txt", new MockFileData ("Testing is meh.") { LastWriteTime = new DateTime (2001, 01, 01, 11, 12, 11) });
-			fileSystem.AddFile (@"/demo/jQuery.js", new MockFileData ("some js") { LastWriteTime = new DateTime (2001, 01, 01, 11, 44, 42) });
-			fileSystem.AddFile (@"/demo/image.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
+			Assert.IsType<TextField>(dlg.MostFocused);
+			Send ('v', ConsoleKey.DownArrow, false);
+			Assert.IsType<TableView>(dlg.MostFocused);
+			
+			// ".." should be the first thing selected
+			// ".." should not mess with the displayed path
+			AssertIsTheStartingDirectory(dlg.Path);
 
 
-			var m = (MockDirectoryInfo)fileSystem.DirectoryInfo.New (@"/demo/subfolder");
-			m.Create ();
-			m.LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10);
+			// Accept navigation up a directory
+			Send ('\n', ConsoleKey.Enter);
 
 
-			fileSystem.AddFile (@"/demo/subfolder/image2.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
+			AssertIsTheRootDirectory(dlg.Path);
+			
+			Assert.True(dlg.Canceled);
+			Assert.False(selected);
 
 
-			var fd = new FileDialog (fileSystem) {
-				Height = 15
+			// Now press the back button (in table view)
+			Send ('<', ConsoleKey.Backspace);
+
+			// Should move us back to the root
+			AssertIsTheStartingDirectory(dlg.Path);
+
+			Assert.True(dlg.Canceled);
+			Assert.False(selected);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void MultiSelectDirectory_EnterOpensFolder ()
+		{
+			var dlg = GetDialog();
+			dlg.OpenMode = OpenMode.Directory;
+			dlg.AllowsMultipleSelection = true;
+			IReadOnlyCollection<string> eventMultiSelected = null;
+			dlg.FilesSelected += (s,e)=>
+			{
+				eventMultiSelected  = e.Dialog.MultiSelected;
 			};
 			};
-			fd.Path = @"/demo/";
-			Begin (fd);
-			fd.Title = string.Empty;
 
 
-			fd.Redraw (fd.Bounds);
+			Assert.IsType<TextField>(dlg.MostFocused);
+			Send ('v', ConsoleKey.DownArrow, false);
+			Assert.IsType<TableView>(dlg.MostFocused);
+			// Move selection to subfolder
+			Send ('v', ConsoleKey.DownArrow, false);
+
+			Send ('\n', ConsoleKey.Enter);
+
+			// Path should update to the newly opened folder
+			AssertIsTheSubfolder(dlg.Path);
+
+			// No selection will have been confirmed
+			Assert.True(dlg.Canceled);
+			Assert.Empty(dlg.MultiSelected);
+			Assert.Null(eventMultiSelected);
+		}
+
+		[Theory, AutoInitShutdown]
+		[InlineData(true)]
+		[InlineData(false)]
+		public void MultiSelectDirectory_CanToggleThenAccept (bool acceptWithEnter)
+		{
+			var dlg = GetDialog();
+			dlg.OpenMode = OpenMode.Directory;
+			dlg.AllowsMultipleSelection = true;
+			IReadOnlyCollection<string> eventMultiSelected = null;
+			dlg.FilesSelected += (s,e)=>
+			{
+				eventMultiSelected  = e.Dialog.MultiSelected;
+			};
+
+			Assert.IsType<TextField>(dlg.MostFocused);
+			Send ('v', ConsoleKey.DownArrow, false);
+			Assert.IsType<TableView>(dlg.MostFocused);
+			// Move selection to subfolder
+			Send ('v', ConsoleKey.DownArrow, false);
+			// Toggle subfolder
+			Send (' ', ConsoleKey.Spacebar, false);
+
+			Assert.True(dlg.Canceled);
+
+			if(acceptWithEnter)
+			{
+				Send ('\n', ConsoleKey.Enter);
+			}
+			else
+			{
+				Send ('o', ConsoleKey.O,false,true);
+			}
+			Assert.False(dlg.Canceled);
+
+			Assert.Multiple(
+				()=>{
+					// Only the subfolder should be selected
+					Assert.Equal(1,dlg.MultiSelected.Count);
+					AssertIsTheSubfolder(dlg.Path);
+					AssertIsTheSubfolder(dlg.MultiSelected.Single());
+				},
+				()=>{
+					// Event should also agree with the final state
+					Assert.NotNull(eventMultiSelected);
+					Assert.Equal(1,eventMultiSelected.Count);
+					AssertIsTheSubfolder(eventMultiSelected.Single());
+				}
+			);
+		}
+
+		private void AssertIsTheStartingDirectory (string path)
+		{
+			if(IsWindows())
+			{
+				Assert.Equal (@"c:\demo\",path);
+			}
+			else
+			{
+				Assert.Equal ("/demo/",path);
+			}
+		}
+
+		private void AssertIsTheRootDirectory (string path)
+		{
+			if(IsWindows())
+			{
+				Assert.Equal (@"c:\",path);
+			}
+			else
+			{
+				Assert.Equal ("/",path);
+			}
+		}
+
+		private void AssertIsTheSubfolder (string path)
+		{
+			if(IsWindows())
+			{
+				Assert.Equal (@"c:\demo\subfolder",path);
+			}
+			else
+			{
+				Assert.Equal ("/demo/subfolder",path);
+			}
+		}
+
+		[Fact, AutoInitShutdown]
+		public void TestDirectoryContents_Linux ()
+		{
+			if (IsWindows()) {
+				return;
+			}
+			var fd = GetLinuxDialog();
+			fd.Title = string.Empty;
 
 
-			fd.Style.DateFormat = "yyyy-MM-dd hh:mm:ss";
+			fd.Style.Culture = new CultureInfo("en-US");
 
 
+			fd.Redraw (fd.Bounds);
+			
 			string expected =
 			string expected =
 			@"
 			@"
  ┌──────────────────────────────────────────────────────────────────┐
  ┌──────────────────────────────────────────────────────────────────┐
@@ -186,35 +426,17 @@ namespace Terminal.Gui.FileServicesTests {
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void TestDirectoryContents_Windows ()
 		public void TestDirectoryContents_Windows ()
 		{
 		{
-			if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform (System.Runtime.InteropServices.OSPlatform.Windows)) {
-				// Can only run this test on windows :( 
-				// See: https://github.com/TestableIO/System.IO.Abstractions/issues/800
+			if (!IsWindows()) {
 				return;
 				return;
 			}
 			}
-			// Arrange
-			var fileSystem = new MockFileSystem (new Dictionary<string, MockFileData> (), @"c:\");
-			fileSystem.MockTime (() => new DateTime (2010, 01, 01, 11, 12, 43));
-
-			fileSystem.AddFile (@"c:\myfile.txt", new MockFileData ("Testing is meh.") { LastWriteTime = new DateTime (2001, 01, 01, 11, 12, 11) });
-			fileSystem.AddFile (@"c:\demo\jQuery.js", new MockFileData ("some js") { LastWriteTime = new DateTime (2001, 01, 01, 11, 44, 42) });
-			fileSystem.AddFile (@"c:\demo\image.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
 
 
-			var m = (MockDirectoryInfo)fileSystem.DirectoryInfo.New (@"c:\demo\subfolder");
-			m.Create ();
-			m.LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10);
-
-			fileSystem.AddFile (@"c:\demo\subfolder\image2.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
-
-			var fd = new FileDialog (fileSystem) {
-				Height = 15
-			};
-			fd.Path = @"c:\demo\";
-			Begin (fd);
+			var fd = GetWindowsDialog();
 			fd.Title = string.Empty;
 			fd.Title = string.Empty;
 
 
+			fd.Style.Culture = new CultureInfo("en-US");
+
 			fd.Redraw (fd.Bounds);
 			fd.Redraw (fd.Bounds);
 
 
-			fd.Style.DateFormat = "yyyy-MM-dd hh:mm:ss";
 
 
 			string expected =
 			string expected =
 			@"
 			@"
@@ -265,7 +487,6 @@ namespace Terminal.Gui.FileServicesTests {
 			foreach (var ch in chars) {
 			foreach (var ch in chars) {
 				Application.Driver.SendKeys (ch, ConsoleKey.NoName, false, false, false);
 				Application.Driver.SendKeys (ch, ConsoleKey.NoName, false, false, false);
 			}
 			}
-
 		}
 		}
 		/*
 		/*
 				[Fact, AutoInitShutdown]
 				[Fact, AutoInitShutdown]
@@ -297,6 +518,63 @@ namespace Terminal.Gui.FileServicesTests {
 					Assert.Equal (@"/bob/fish", tb.Text);
 					Assert.Equal (@"/bob/fish", tb.Text);
 				}*/
 				}*/
 
 
+		private bool IsWindows()
+		{
+			return System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform (System.Runtime.InteropServices.OSPlatform.Windows);
+		}
+
+		private FileDialog GetDialog()
+		{
+			return IsWindows() ? GetWindowsDialog() : GetLinuxDialog();			
+		}
+
+		private FileDialog GetWindowsDialog()
+		{
+			// Arrange
+			var fileSystem = new MockFileSystem (new Dictionary<string, MockFileData> (), @"c:\");
+			fileSystem.MockTime (() => new DateTime (2010, 01, 01, 11, 12, 43));
+
+			fileSystem.AddFile (@"c:\myfile.txt", new MockFileData ("Testing is meh.") { LastWriteTime = new DateTime (2001, 01, 01, 11, 12, 11) });
+			fileSystem.AddFile (@"c:\demo\jQuery.js", new MockFileData ("some js") { LastWriteTime = new DateTime (2001, 01, 01, 11, 44, 42) });
+			fileSystem.AddFile (@"c:\demo\image.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
+
+			var m = (MockDirectoryInfo)fileSystem.DirectoryInfo.New (@"c:\demo\subfolder");
+			m.Create ();
+			m.LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10);
+
+			fileSystem.AddFile (@"c:\demo\subfolder\image2.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
+
+			var fd = new FileDialog (fileSystem) {
+				Height = 15
+			};
+			fd.Path = @"c:\demo\";
+			Begin (fd);
+			return fd;
+		}
+
+		private FileDialog GetLinuxDialog()
+		{
+			// Arrange
+			var fileSystem = new MockFileSystem (new Dictionary<string, MockFileData> (), "/");
+			fileSystem.MockTime (() => new DateTime (2010, 01, 01, 11, 12, 43));
+
+			fileSystem.AddFile (@"/myfile.txt", new MockFileData ("Testing is meh.") { LastWriteTime = new DateTime (2001, 01, 01, 11, 12, 11) });
+			fileSystem.AddFile (@"/demo/jQuery.js", new MockFileData ("some js") { LastWriteTime = new DateTime (2001, 01, 01, 11, 44, 42) });
+			fileSystem.AddFile (@"/demo/image.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
+
+			var m = (MockDirectoryInfo)fileSystem.DirectoryInfo.New (@"/demo/subfolder");
+			m.Create ();
+			m.LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10);
+
+			fileSystem.AddFile (@"/demo/subfolder/image2.gif", new MockFileData (new byte [] { 0x12, 0x34, 0x56, 0xd2 }) { LastWriteTime = new DateTime (2002, 01, 01, 22, 42, 10) });
+
+			var fd = new FileDialog (fileSystem) {
+				Height = 15
+			};
+			fd.Path = @"/demo/";
+			Begin (fd);
+			return fd;
+		}
 		private FileDialog GetInitializedFileDialog ()
 		private FileDialog GetInitializedFileDialog ()
 		{
 		{
 			var dlg = new FileDialog ();
 			var dlg = new FileDialog ();

+ 1 - 1
UnitTests/TestHelpers.cs

@@ -267,7 +267,7 @@ class TestHelpers {
 	/// </summary>
 	/// </summary>
 	/// <param name="expectedLook">Numbers between 0 and 9 for each row/col of the console.  Must be valid indexes of <paramref name="expectedColors"/></param>
 	/// <param name="expectedLook">Numbers between 0 and 9 for each row/col of the console.  Must be valid indexes of <paramref name="expectedColors"/></param>
 	/// <param name="expectedColors"></param>
 	/// <param name="expectedColors"></param>
-	public static void AssertDriverColorsAre (string expectedLook, Attribute [] expectedColors)
+	public static void AssertDriverColorsAre (string expectedLook, params Attribute [] expectedColors)
 	{
 	{
 #pragma warning restore xUnit1013 // Public method should be marked as test
 #pragma warning restore xUnit1013 // Public method should be marked as test
 
 

+ 23 - 17
UnitTests/Views/OverlappedTests.cs

@@ -90,15 +90,15 @@ namespace Terminal.Gui.ViewsTests {
 				Assert.True (Application.Current == d);
 				Assert.True (Application.Current == d);
 			};
 			};
 
 
-			d.Closed += (s,e) => Application.RequestStop (top1);
+			d.Closed += (s, e) => Application.RequestStop (top1);
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
 				Assert.Null (Application.OverlappedChildren);
 				Assert.Null (Application.OverlappedChildren);
-				if (iterations == 4) 					Assert.True (Application.Current == d);
-else if (iterations == 3) 					Assert.True (Application.Current == top4);
-else if (iterations == 2) 					Assert.True (Application.Current == top3);
-else if (iterations == 1) 					Assert.True (Application.Current == top2);
-else 					Assert.True (Application.Current == top1);
+				if (iterations == 4) Assert.True (Application.Current == d);
+				else if (iterations == 3) Assert.True (Application.Current == top4);
+				else if (iterations == 2) Assert.True (Application.Current == top3);
+				else if (iterations == 1) Assert.True (Application.Current == top2);
+				else Assert.True (Application.Current == top1);
 				Application.RequestStop (top1);
 				Application.RequestStop (top1);
 				iterations--;
 				iterations--;
 			};
 			};
@@ -154,7 +154,7 @@ else 					Assert.True (Application.Current == top1);
 			};
 			};
 
 
 			// Now this will close the OverlappedContainer propagating through the OverlappedChildren.
 			// Now this will close the OverlappedContainer propagating through the OverlappedChildren.
-			d.Closed += (s,e) => {
+			d.Closed += (s, e) => {
 				overlapped.RequestStop ();
 				overlapped.RequestStop ();
 			};
 			};
 
 
@@ -165,7 +165,7 @@ else 					Assert.True (Application.Current == top1);
 					Assert.False (d.Running);
 					Assert.False (d.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
-					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
+					for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -214,7 +214,7 @@ else 					Assert.True (Application.Current == top1);
 			};
 			};
 
 
 			// Now this will close the OverlappedContainer propagating through the OverlappedChildren.
 			// Now this will close the OverlappedContainer propagating through the OverlappedChildren.
-			d.Closed += (s,e) => Application.RequestStop (overlapped);
+			d.Closed += (s, e) => Application.RequestStop (overlapped);
 
 
 			Application.Iteration += () => {
 			Application.Iteration += () => {
 				if (iterations == 4) {
 				if (iterations == 4) {
@@ -223,7 +223,7 @@ else 					Assert.True (Application.Current == top1);
 					Assert.False (d.Running);
 					Assert.False (d.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
-					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
+					for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -282,7 +282,7 @@ else 					Assert.True (Application.Current == top1);
 					Assert.False (d.Running);
 					Assert.False (d.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
-					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
+					for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -380,7 +380,7 @@ else 					Assert.True (Application.Current == top1);
 					Assert.False (Application.Current.Running);
 					Assert.False (Application.Current.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
-					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
+					for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + 1).ToString (), Application.OverlappedChildren [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
 			};
 			};
@@ -447,7 +447,7 @@ else 					Assert.True (Application.Current == top1);
 					Assert.True (c4.Running);
 					Assert.True (c4.Running);
 				} else {
 				} else {
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
-					for (int i = 0; i < iterations; i++) 						Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
+					for (int i = 0; i < iterations; i++) Assert.Equal ((iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
 							Application.OverlappedChildren [i].Id);
 							Application.OverlappedChildren [i].Id);
 				}
 				}
 				iterations--;
 				iterations--;
@@ -570,7 +570,7 @@ else 					Assert.True (Application.Current == top1);
 					};
 					};
 
 
 					stage.Closed += (_, _) => {
 					stage.Closed += (_, _) => {
-						if (iterations == 11) 							allStageClosed = true;
+						if (iterations == 11) allStageClosed = true;
 						Assert.Equal (iterations, Application.OverlappedChildren.Count);
 						Assert.Equal (iterations, Application.OverlappedChildren.Count);
 						if (running) {
 						if (running) {
 							stageCompleted = true;
 							stageCompleted = true;
@@ -592,12 +592,12 @@ else 					Assert.True (Application.Current == top1);
 					running = false;
 					running = false;
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 
 
-				} else if (!overlappedRequestStop && running && !allStageClosed) 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
-else if (!overlappedRequestStop && !running && allStageClosed) {
+				} else if (!overlappedRequestStop && running && !allStageClosed) Assert.Equal (iterations, Application.OverlappedChildren.Count);
+				else if (!overlappedRequestStop && !running && allStageClosed) {
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					Assert.Equal (iterations, Application.OverlappedChildren.Count);
 					overlappedRequestStop = true;
 					overlappedRequestStop = true;
 					overlapped.RequestStop ();
 					overlapped.RequestStop ();
-				} else 					Assert.Empty (Application.OverlappedChildren);
+				} else Assert.Empty (Application.OverlappedChildren);
 			};
 			};
 
 
 			Application.Run (overlapped);
 			Application.Run (overlapped);
@@ -672,5 +672,11 @@ else if (!overlappedRequestStop && !running && allStageClosed) {
 
 
 			Assert.Empty (Application.OverlappedChildren);
 			Assert.Empty (Application.OverlappedChildren);
 		}
 		}
+
+		[Fact]
+		public void MoveToOverlappedChild_Throw_NullReferenceException_Passing_Null_Parameter ()
+		{
+			Assert.Throws<NullReferenceException> (delegate { Application.MoveToOverlappedChild (null); });
+		}
 	}
 	}
 }
 }

+ 175 - 7
UnitTests/Views/TableViewTests.cs

@@ -1786,14 +1786,14 @@ namespace Terminal.Gui.ViewsTests {
 			tableView.EnsureSelectedCellIsVisible ();
 			tableView.EnsureSelectedCellIsVisible ();
 			Assert.Equal (smooth ? 1 : 3, tableView.ColumnOffset);
 			Assert.Equal (smooth ? 1 : 3, tableView.ColumnOffset);
 		}
 		}
-		
+
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void LongColumnTest ()
 		public void LongColumnTest ()
 		{
 		{
 			var tableView = new TableView ();
 			var tableView = new TableView ();
 
 
-			Application.Top.Add(tableView);
-			Application.Begin(Application.Top);
+			Application.Top.Add (tableView);
+			Application.Begin (Application.Top);
 
 
 			tableView.ColorScheme = Colors.TopLevel;
 			tableView.ColorScheme = Colors.TopLevel;
 
 
@@ -1896,8 +1896,8 @@ namespace Terminal.Gui.ViewsTests {
 			// Now test making the width too small for the MinAcceptableWidth
 			// Now test making the width too small for the MinAcceptableWidth
 			// the Column won't fit so should not be rendered
 			// the Column won't fit so should not be rendered
 			var driver = ((FakeDriver)Application.Driver);
 			var driver = ((FakeDriver)Application.Driver);
-			driver.UpdateOffScreen();
-			
+			driver.UpdateOffScreen ();
+
 
 
 			tableView.Bounds = new Rect (0, 0, 9, 5);
 			tableView.Bounds = new Rect (0, 0, 9, 5);
 			tableView.LayoutSubviews ();
 			tableView.LayoutSubviews ();
@@ -2075,7 +2075,7 @@ namespace Terminal.Gui.ViewsTests {
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void ShowHorizontalBottomLine_WithVerticalCellLines ()
 		public void ShowHorizontalBottomLine_WithVerticalCellLines ()
 		{
 		{
-			var tableView = GetABCDEFTableView(out _);
+			var tableView = GetABCDEFTableView (out _);
 			tableView.BeginInit (); tableView.EndInit ();
 			tableView.BeginInit (); tableView.EndInit ();
 
 
 			tableView.ColorScheme = Colors.TopLevel;
 			tableView.ColorScheme = Colors.TopLevel;
@@ -2087,7 +2087,7 @@ namespace Terminal.Gui.ViewsTests {
 			tableView.Style.AlwaysShowHeaders = true;
 			tableView.Style.AlwaysShowHeaders = true;
 			tableView.Style.SmoothHorizontalScrolling = true;
 			tableView.Style.SmoothHorizontalScrolling = true;
 			tableView.Style.ShowHorizontalBottomline = true;
 			tableView.Style.ShowHorizontalBottomline = true;
-						
+
 			tableView.Redraw (tableView.Bounds);
 			tableView.Redraw (tableView.Bounds);
 
 
 			// user can only scroll right so sees right indicator
 			// user can only scroll right so sees right indicator
@@ -2132,6 +2132,174 @@ namespace Terminal.Gui.ViewsTests {
 			TestHelpers.AssertDriverContentsAre (expected, output);
 			TestHelpers.AssertDriverContentsAre (expected, output);
 		}
 		}
 
 
+		[Fact, AutoInitShutdown]
+		public void TestFullRowSelect_SelectionColorStopsAtTableEdge_WithCellLines ()
+		{
+			var tv = GetTwoRowSixColumnTable ();
+			tv.Table.Rows.Add (1, 2, 3, 4, 5, 6);
+			tv.LayoutSubviews ();
+
+
+			tv.Bounds = new Rect (0, 0, 7, 6);
+
+			tv.FullRowSelect = true;
+			tv.Style.ShowHorizontalBottomline = true;
+
+			// Clicking in bottom row
+			tv.MouseEvent (new MouseEvent {
+				X = 1,
+				Y = 4,
+				Flags = MouseFlags.Button1Clicked
+			});
+
+			// should select that row
+			Assert.Equal (2, tv.SelectedRow);
+
+
+			tv.Redraw (tv.Bounds);
+
+			string expected =
+				@"
+│A│B│C│
+├─┼─┼─►
+│1│2│3│
+│1│2│3│
+│1│2│3│
+└─┴─┴─┘";
+
+			TestHelpers.AssertDriverContentsAre (expected, output);
+
+			var normal = tv.ColorScheme.Normal;
+			var focus = tv.ColorScheme.HotFocus = new Attribute (Color.Magenta, Color.White);
+
+			tv.Redraw (tv.Bounds);
+
+			// HotFocus color (1) should be used for rendering the selected line
+			// But should not spill into the borders.  Normal color (0) should be
+			// used for the rest.
+			expected =
+				@"
+0000000
+0000000
+0000000
+0000000
+0111110
+0000000";
+
+			TestHelpers.AssertDriverColorsAre (expected, normal, focus);
+		}
+
+		[Fact, AutoInitShutdown]
+		public void TestFullRowSelect_AlwaysUseNormalColorForVerticalCellLines ()
+		{
+			var tv = GetTwoRowSixColumnTable ();
+			tv.Table.Rows.Add (1, 2, 3, 4, 5, 6);
+			tv.LayoutSubviews ();
+
+
+			tv.Bounds = new Rect (0, 0, 7, 6);
+
+			tv.FullRowSelect = true;
+			tv.Style.ShowHorizontalBottomline = true;
+			tv.Style.AlwaysUseNormalColorForVerticalCellLines = true;
+
+			// Clicking in bottom row
+			tv.MouseEvent (new MouseEvent {
+				X = 1,
+				Y = 4,
+				Flags = MouseFlags.Button1Clicked
+			});
+
+			// should select that row
+			Assert.Equal (2, tv.SelectedRow);
+
+
+			tv.Redraw (tv.Bounds);
+
+			string expected =
+				@"
+│A│B│C│
+├─┼─┼─►
+│1│2│3│
+│1│2│3│
+│1│2│3│
+└─┴─┴─┘";
+
+			TestHelpers.AssertDriverContentsAre (expected, output);
+
+			var normal = tv.ColorScheme.Normal;
+			var focus = tv.ColorScheme.HotFocus = new Attribute (Color.Magenta, Color.White);
+
+			tv.Redraw (tv.Bounds);
+
+			// HotFocus color (1) should be used for cells only because
+			// AlwaysUseNormalColorForVerticalCellLines is true
+			expected =
+				@"
+0000000
+0000000
+0000000
+0000000
+0101010
+0000000";
+
+			TestHelpers.AssertDriverColorsAre (expected, normal, focus);
+		}
+		[Fact, AutoInitShutdown]
+		public void TestFullRowSelect_SelectionColorDoesNotStop_WhenShowVerticalCellLinesIsFalse ()
+		{
+			var tv = GetTwoRowSixColumnTable ();
+			tv.Table.Rows.Add (1, 2, 3, 4, 5, 6);
+			tv.LayoutSubviews ();
+
+
+			tv.Bounds = new Rect (0, 0, 7, 6);
+
+			tv.FullRowSelect = true;
+			tv.Style.ShowVerticalCellLines = false;
+			tv.Style.ShowVerticalHeaderLines = false;
+
+			// Clicking in bottom row
+			tv.MouseEvent (new MouseEvent {
+				X = 1,
+				Y = 4,
+				Flags = MouseFlags.Button1Clicked
+			});
+
+			// should select that row
+			Assert.Equal (2, tv.SelectedRow);
+
+
+			tv.Redraw (tv.Bounds);
+
+			string expected =
+				@"
+A B C
+───────
+1 2 3
+1 2 3
+1 2 3";
+
+			TestHelpers.AssertDriverContentsAre (expected, output);
+
+			var normal = tv.ColorScheme.Normal;
+			var focus = tv.ColorScheme.HotFocus = new Attribute (Color.Magenta, Color.White);
+
+			tv.Redraw (tv.Bounds);
+
+			// HotFocus color (1) should be used for rendering the selected line
+			// Note that because there are no vertical cell lines we use the hot focus
+			// color for the whole row
+			expected =
+				@"
+000000
+000000
+000000
+000000
+111111";
+
+			TestHelpers.AssertDriverColorsAre (expected, normal, focus);
+		}
 
 
 		/// <summary>
 		/// <summary>
 		/// Builds a simple table of string columns with the requested number of columns and rows
 		/// Builds a simple table of string columns with the requested number of columns and rows