浏览代码

Robustness improvements in prep for implementing Virtual Terminal Sequences (#3094)

* Fixes #2616. Support combining sequences that don't normalize

* Decouples Application from ConsoleDriver in TestHelpers

* Updates driver tests to match new arch

* Start on making all driver tests test all drivers

* Improves handling if combining marks.

* Fix unit tests fails.

* Fix unit tests fails.

* Handling combining mask.

* Tying to fix this unit test that sometimes fail.

* Add support for combining mask on NetDriver.

* Enable CombiningMarks as List<Rune>.

* Prevents combining marks on invalid runes default and space.

* Formatting for CI tests.

* Fix non-normalized combining mark to add 1 to Col.

* Reformatting for retest the CI.

* Forces non-normalized CMs to be ignored.

* Initial experiment

* Created ANSiDriver. Updated UI Catalog command line handling

* Fixed ForceDriver logic

* Fixed ForceDriver logic

* Updating P/Invoke

* Force16 colors WIP

* Fixed 16 colo mode

* Updated unit tests

* UI catalog tweak

* Added chinese scenario from bdisp

* Disabled AnsiDriver unit tests for now.

* Code cleanup

* Initial commit (fork from v2_fixes_2610_WT_VTS)

* Code cleanup

* Removed nativemethods.txt

* Removed not needed native stuff

* Code cleanup

* Ensures command line handler doesn't eat exceptions

---------

Co-authored-by: BDisp <[email protected]>
Tig 1 年之前
父节点
当前提交
7af54f369d

+ 66 - 33
Terminal.Gui/Application.cs

@@ -33,15 +33,20 @@ namespace Terminal.Gui;
 /// </remarks>
 /// </remarks>
 public static partial class Application {
 public static partial class Application {
 	/// <summary>
 	/// <summary>
-	/// Gets the <see cref="ConsoleDriver"/> that has been selected. See also <see cref="UseSystemConsole"/>.
+	/// Gets the <see cref="ConsoleDriver"/> that has been selected. See also <see cref="ForceDriver"/>.
 	/// </summary>
 	/// </summary>
 	public static ConsoleDriver Driver { get; internal set; }
 	public static ConsoleDriver Driver { get; internal set; }
 
 
 	/// <summary>
 	/// <summary>
-	/// If <see langword="true"/>, forces the use of the System.Console-based (see <see cref="NetDriver"/>) driver. The default is <see langword="false"/>.
+	/// Forces the use of the specified driver (one of "fake", "ansi", "curses", "net", or "windows"). If
+	/// not specified, the driver is selected based on the platform.
 	/// </summary>
 	/// </summary>
+	/// <remarks>
+	/// Note, <see cref="Application.Init(ConsoleDriver, string)"/> will override this configuration setting if
+	/// called with either `driver` or `driverName` specified.
+	/// </remarks>
 	[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
 	[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
-	public static bool UseSystemConsole { get; set; } = false;
+	public static string ForceDriver { get; set; } = string.Empty;
 
 
 	/// <summary>
 	/// <summary>
 	/// Gets or sets whether <see cref="Application.Driver"/> will be forced to output only the 16 colors defined in <see cref="ColorName"/>.
 	/// Gets or sets whether <see cref="Application.Driver"/> will be forced to output only the 16 colors defined in <see cref="ColorName"/>.
@@ -98,14 +103,13 @@ public static partial class Application {
 	/// </para>
 	/// </para>
 	/// <para>
 	/// <para>
 	/// The <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver)"/> function 
 	/// The <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver)"/> function 
-	/// combines <see cref="Init(ConsoleDriver)"/> and <see cref="Run(Toplevel, Func{Exception, bool})"/>
+	/// combines <see cref="Init(ConsoleDriver, string)"/> and <see cref="Run(Toplevel, Func{Exception, bool})"/>
 	/// into a single call. An application cam use <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver)"/> 
 	/// into a single call. An application cam use <see cref="Run{T}(Func{Exception, bool}, ConsoleDriver)"/> 
-	/// without explicitly calling <see cref="Init(ConsoleDriver)"/>.
+	/// without explicitly calling <see cref="Init(ConsoleDriver, string)"/>.
 	/// </para>
 	/// </para>
-	/// <param name="driver">
-	/// The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the
-	/// platform will be used (see <see cref="WindowsDriver"/>, <see cref="CursesDriver"/>, and <see cref="NetDriver"/>).</param>
-	public static void Init (ConsoleDriver driver = null) => InternalInit (() => Toplevel.Create (), driver);
+	/// <param name="driver">The <see cref="ConsoleDriver"/> to use. If neither <paramref name="driver"/> or <paramref name="driverName"/> are specified the default driver for the platform will be used.</param>
+	/// <param name="driverName">The short name (e.g. "net", "windows", "ansi", "fake", or "curses") of the <see cref="ConsoleDriver"/> to use. If neither <paramref name="driver"/> or <paramref name="driverName"/> are specified the default driver for the platform will be used.</param>
+	public static void Init (ConsoleDriver driver = null, string driverName = null) => InternalInit (Toplevel.Create, driver, driverName);
 
 
 	internal static bool _initialized = false;
 	internal static bool _initialized = false;
 	internal static int _mainThreadId = -1;
 	internal static int _mainThreadId = -1;
@@ -119,7 +123,7 @@ public static partial class Application {
 	// Unit Tests - To initialize the app with a custom Toplevel, using the FakeDriver. calledViaRunT will be false, causing all state to be reset.
 	// Unit Tests - To initialize the app with a custom Toplevel, using the FakeDriver. calledViaRunT will be false, causing all state to be reset.
 	// 
 	// 
 	// calledViaRunT: If false (default) all state will be reset. If true the state will not be reset.
 	// calledViaRunT: If false (default) all state will be reset. If true the state will not be reset.
-	internal static void InternalInit (Func<Toplevel> topLevelFactory, ConsoleDriver driver = null, bool calledViaRunT = false)
+	internal static void InternalInit (Func<Toplevel> topLevelFactory, ConsoleDriver driver = null, string driverName = null, bool calledViaRunT = false)
 	{
 	{
 		if (_initialized && driver == null) {
 		if (_initialized && driver == null) {
 			return;
 			return;
@@ -147,15 +151,28 @@ public static partial class Application {
 		Load (true);
 		Load (true);
 		Apply ();
 		Apply ();
 
 
-		Driver ??= Environment.OSVersion.Platform switch {
-			_ when _forceFakeConsole => new FakeDriver (), // for unit testing only
-			_ when UseSystemConsole => new NetDriver (),
-			PlatformID.Win32NT or PlatformID.Win32S or PlatformID.Win32Windows => new WindowsDriver (),
-			_ => new CursesDriver ()
-		};
+		// Ignore Configuration for ForceDriver if driverName is specified
+		if (!string.IsNullOrEmpty (driverName)) {
+			ForceDriver = driverName;
+		}
 
 
 		if (Driver == null) {
 		if (Driver == null) {
-			throw new InvalidOperationException ("Init could not determine the ConsoleDriver to use.");
+			var p = Environment.OSVersion.Platform;
+			if (string.IsNullOrEmpty (ForceDriver)) {
+				if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
+					Driver = new WindowsDriver ();
+				} else {
+					Driver = new CursesDriver ();
+				}
+			} else {
+				var drivers = GetDriverTypes ();
+				var driverType = drivers.FirstOrDefault (t => t.Name.ToLower () == ForceDriver.ToLower ());
+				if (driverType != null) {
+					Driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+				} else {
+					throw new ArgumentException ($"Invalid driver name: {ForceDriver}. Valid names are {string.Join (", ", drivers.Select (t => t.Name))}");
+				}
+			}
 		}
 		}
 
 
 		try {
 		try {
@@ -168,10 +185,10 @@ public static partial class Application {
 			throw new InvalidOperationException ("Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.", ex);
 			throw new InvalidOperationException ("Unable to initialize the console. This can happen if the console is already in use by another process or in unit tests.", ex);
 		}
 		}
 
 
-		Driver.SizeChanged += Driver_SizeChanged;
-		Driver.KeyDown += Driver_KeyDown;
-		Driver.KeyUp += Driver_KeyUp;
-		Driver.MouseEvent += Driver_MouseEvent;
+		Driver.SizeChanged += (s, args) => OnSizeChanging (args);
+		Driver.KeyDown += (s, args) => OnKeyDown (args);
+		Driver.KeyUp += (s, args) => OnKeyUp (args);
+		Driver.MouseEvent += (s, args) => OnMouseEvent (args);
 
 
 		SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
 		SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext ());
 
 
@@ -190,12 +207,29 @@ public static partial class Application {
 
 
 	static void Driver_MouseEvent (object sender, MouseEventEventArgs e) => OnMouseEvent (e);
 	static void Driver_MouseEvent (object sender, MouseEventEventArgs e) => OnMouseEvent (e);
 
 
+	/// <summary>
+	/// Gets of list of <see cref="ConsoleDriver"/> types that are available.
+	/// </summary>
+	/// <returns></returns>
+	public static List<Type> GetDriverTypes ()
+	{
+		// use reflection to get the list of drivers
+		var driverTypes = new List<Type> ();
+		foreach (var asm in AppDomain.CurrentDomain.GetAssemblies ()) {
+			foreach (var type in asm.GetTypes ()) {
+				if (type.IsSubclassOf (typeof (ConsoleDriver)) && !type.IsAbstract) {
+					driverTypes.Add (type);
+				}
+			}
+		}
+		return driverTypes;
+	}
 
 
 	/// <summary>
 	/// <summary>
-	/// Shutdown an application initialized with <see cref="Init(ConsoleDriver)"/>.
+	/// Shutdown an application initialized with <see cref="Init"/>.
 	/// </summary>
 	/// </summary>
 	/// <remarks>
 	/// <remarks>
-	/// Shutdown must be called for every call to <see cref="Init(ConsoleDriver)"/> or <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>
+	/// Shutdown must be called for every call to <see cref="Init"/> or <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>
 	/// to ensure all resources are cleaned up (Disposed) and terminal settings are restored.
 	/// to ensure all resources are cleaned up (Disposed) and terminal settings are restored.
 	/// </remarks>
 	/// </remarks>
 	public static void Shutdown ()
 	public static void Shutdown ()
@@ -394,7 +428,7 @@ public static partial class Application {
 	/// Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool})"/> 
 	/// Runs the application by calling <see cref="Run(Toplevel, Func{Exception, bool})"/> 
 	/// with a new instance of the specified <see cref="Toplevel"/>-derived class.
 	/// with a new instance of the specified <see cref="Toplevel"/>-derived class.
 	/// <para>
 	/// <para>
-	/// Calling <see cref="Init(ConsoleDriver)"/> first is not needed as this function will initialize the application.
+	/// Calling <see cref="Init"/> first is not needed as this function will initialize the application.
 	/// </para>
 	/// </para>
 	/// <para>
 	/// <para>
 	/// <see cref="Shutdown"/> must be called when the application is closing (typically after Run> has 
 	/// <see cref="Shutdown"/> must be called when the application is closing (typically after Run> has 
@@ -407,7 +441,7 @@ public static partial class Application {
 	/// <param name="errorHandler"></param>
 	/// <param name="errorHandler"></param>
 	/// <param name="driver">The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the
 	/// <param name="driver">The <see cref="ConsoleDriver"/> to use. If not specified the default driver for the
 	/// platform will be used (<see cref="WindowsDriver"/>, <see cref="CursesDriver"/>, or <see cref="NetDriver"/>).
 	/// platform will be used (<see cref="WindowsDriver"/>, <see cref="CursesDriver"/>, or <see cref="NetDriver"/>).
-	/// Must be <see langword="null"/> if <see cref="Init(ConsoleDriver)"/> has already been called. 
+	/// Must be <see langword="null"/> if <see cref="Init"/> has already been called. 
 	/// </param>
 	/// </param>
 	public static void Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null) where T : Toplevel, new ()
 	public static void Run<T> (Func<Exception, bool> errorHandler = null, ConsoleDriver driver = null) where T : Toplevel, new ()
 	{
 	{
@@ -429,7 +463,7 @@ public static partial class Application {
 			}
 			}
 		} else {
 		} else {
 			// Init() has NOT been called.
 			// Init() has NOT been called.
-			InternalInit (() => new T (), driver, true);
+			InternalInit (() => new T (), driver, null, true);
 			Run (Top, errorHandler);
 			Run (Top, errorHandler);
 		}
 		}
 	}
 	}
@@ -838,13 +872,12 @@ public static partial class Application {
 	#endregion Run (Begin, Run, End)
 	#endregion Run (Begin, Run, End)
 
 
 	#region Toplevel handling
 	#region Toplevel handling
-
 	/// <summary>
 	/// <summary>
 	/// Holds the stack of TopLevel views.
 	/// Holds the stack of TopLevel views.
 	/// </summary>
 	/// </summary>
 	// BUGBUG: Techncally, this is not the full lst of TopLevels. THere be dragons hwre. E.g. see how Toplevel.Id is used. What
 	// BUGBUG: Techncally, this is not the full lst of TopLevels. THere be dragons hwre. E.g. see how Toplevel.Id is used. What
 	// about TopLevels that are just a SubView of another View?
 	// about TopLevels that are just a SubView of another View?
-	static readonly Stack<Toplevel> _topLevels = new ();
+	static readonly Stack<Toplevel> _topLevels = new Stack<Toplevel> ();
 
 
 	/// <summary>
 	/// <summary>
 	/// The <see cref="Toplevel"/> object used for the application on startup (<seealso cref="Application.Top"/>)
 	/// The <see cref="Toplevel"/> object used for the application on startup (<seealso cref="Application.Top"/>)
@@ -1296,7 +1329,7 @@ public static partial class Application {
 	#endregion Mouse handling
 	#endregion Mouse handling
 
 
 	#region Keyboard handling
 	#region Keyboard handling
-	static Key _alternateForwardKey = new (KeyCode.PageDown | KeyCode.CtrlMask);
+	static Key _alternateForwardKey = new Key (KeyCode.PageDown | KeyCode.CtrlMask);
 
 
 	/// <summary>
 	/// <summary>
 	/// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.
 	/// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.
@@ -1320,7 +1353,7 @@ public static partial class Application {
 		}
 		}
 	}
 	}
 
 
-	static Key _alternateBackwardKey = new (KeyCode.PageUp | KeyCode.CtrlMask);
+	static Key _alternateBackwardKey = new Key (KeyCode.PageUp | KeyCode.CtrlMask);
 
 
 	/// <summary>
 	/// <summary>
 	/// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.
 	/// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.
@@ -1344,7 +1377,7 @@ public static partial class Application {
 		}
 		}
 	}
 	}
 
 
-	static Key _quitKey = new (KeyCode.Q | KeyCode.CtrlMask);
+	static Key _quitKey = new Key (KeyCode.Q | KeyCode.CtrlMask);
 
 
 	/// <summary>
 	/// <summary>
 	/// Gets or sets the key to quit the application.
 	/// Gets or sets the key to quit the application.
@@ -1481,8 +1514,8 @@ public static partial class Application {
 	}
 	}
 	#endregion Keyboard handling
 	#endregion Keyboard handling
 }
 }
-
 /// <summary>
 /// <summary>
 /// Event arguments for the <see cref="Application.Iteration"/> event.
 /// Event arguments for the <see cref="Application.Iteration"/> event.
 /// </summary>
 /// </summary>
-public class IterationEventArgs { }
+public class IterationEventArgs {
+}

+ 4 - 2
Terminal.Gui/Configuration/ConfigurationManager.cs

@@ -257,7 +257,7 @@ public static partial class ConfigurationManager {
 
 
 	/// <summary>
 	/// <summary>
 	/// Resets the state of <see cref="ConfigurationManager"/>. Should be called whenever a new app session
 	/// Resets the state of <see cref="ConfigurationManager"/>. Should be called whenever a new app session
-	/// (e.g. in <see cref="Application.Init(ConsoleDriver)"/> starts. Called by <see cref="Load"/>
+	/// (e.g. in <see cref="Application.Init"/> starts. Called by <see cref="Load"/>
 	/// if the <c>reset</c> parameter is <see langword="true"/>.
 	/// if the <c>reset</c> parameter is <see langword="true"/>.
 	/// </summary>
 	/// </summary>
 	/// <remarks>
 	/// <remarks>
@@ -412,7 +412,9 @@ public static partial class ConfigurationManager {
 	{
 	{
 		Debug.WriteLine ($"ConfigurationManager.Load()");
 		Debug.WriteLine ($"ConfigurationManager.Load()");
 
 
-		if (reset) Reset ();
+		if (reset) {
+			Reset ();
+		}
 
 
 		// LibraryResources is always loaded by Reset
 		// LibraryResources is always loaded by Reset
 		if (Locations == ConfigLocations.All) {
 		if (Locations == ConfigLocations.All) {

+ 27 - 5
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -58,12 +58,24 @@ public abstract class ConsoleDriver {
 	/// <summary>
 	/// <summary>
 	/// The number of columns visible in the terminal.
 	/// The number of columns visible in the terminal.
 	/// </summary>
 	/// </summary>
-	public virtual int Cols { get; internal set; }
+	public virtual int Cols {
+		get => _cols;
+		internal set {
+			_cols = value;
+			ClearContents();
+		}
+	}
 
 
 	/// <summary>
 	/// <summary>
 	/// The number of rows visible in the terminal.
 	/// The number of rows visible in the terminal.
 	/// </summary>
 	/// </summary>
-	public virtual int Rows { get; internal set; }
+	public virtual int Rows {
+		get => _rows;
+		internal set {
+			_rows = value;
+			ClearContents();
+		}
+	}
 
 
 	/// <summary>
 	/// <summary>
 	/// The leftmost column in the terminal.
 	/// The leftmost column in the terminal.
@@ -152,11 +164,19 @@ public abstract class ConsoleDriver {
 			rune = rune.MakePrintable ();
 			rune = rune.MakePrintable ();
 			runeWidth = rune.GetColumns ();
 			runeWidth = rune.GetColumns ();
 			if (runeWidth == 0 && rune.IsCombiningMark ()) {
 			if (runeWidth == 0 && rune.IsCombiningMark ()) {
+				// AtlasEngine does not support NON-NORMALIZED combining marks in a way
+				// compatible with the driver architecture. Any CMs (except in the first col)
+				// are correctly combined with the base char, but are ALSO treated as 1 column
+				// width codepoints E.g. `echo "[e`u{0301}`u{0301}]"` will output `[é  ]`.
+				// 
+				// Until this is addressed (see Issue #), we do our best by 
+				// a) Attempting to normalize any CM with the base char to it's left
+				// b) Ignoring any CMs that don't normalize
 				if (Col > 0) {
 				if (Col > 0) {
 					if (Contents [Row, Col - 1].CombiningMarks.Count > 0) {
 					if (Contents [Row, Col - 1].CombiningMarks.Count > 0) {
 						// Just add this mark to the list
 						// Just add this mark to the list
 						Contents [Row, Col - 1].CombiningMarks.Add (rune);
 						Contents [Row, Col - 1].CombiningMarks.Add (rune);
-						// Don't move to next column (let the driver figure out what to do).
+						// Ignore. Don't move to next column (let the driver figure out what to do).
 					} else {
 					} else {
 						// Attempt to normalize the cell to our left combined with this mark
 						// Attempt to normalize the cell to our left combined with this mark
 						string combined = Contents [Row, Col - 1].Rune + rune.ToString ();
 						string combined = Contents [Row, Col - 1].Rune + rune.ToString ();
@@ -167,11 +187,11 @@ public abstract class ConsoleDriver {
 							// It normalized! We can just set the Cell to the left with the
 							// It normalized! We can just set the Cell to the left with the
 							// normalized codepoint 
 							// normalized codepoint 
 							Contents [Row, Col - 1].Rune = (Rune)normalized [0];
 							Contents [Row, Col - 1].Rune = (Rune)normalized [0];
-							// Don't move to next column because we're already there
+							// Ignore. Don't move to next column because we're already there
 						} else {
 						} else {
 							// It didn't normalize. Add it to the Cell to left's CM list
 							// It didn't normalize. Add it to the Cell to left's CM list
 							Contents [Row, Col - 1].CombiningMarks.Add (rune);
 							Contents [Row, Col - 1].CombiningMarks.Add (rune);
-							// Don't move to next column (let the driver figure out what to do).
+							// Ignore. Don't move to next column (let the driver figure out what to do).
 						}
 						}
 					}
 					}
 					Contents [Row, Col - 1].Attribute = CurrentAttribute;
 					Contents [Row, Col - 1].Attribute = CurrentAttribute;
@@ -398,6 +418,8 @@ public abstract class ConsoleDriver {
 	}
 	}
 
 
 	Attribute _currentAttribute;
 	Attribute _currentAttribute;
+	int _cols;
+	int _rows;
 
 
 	/// <summary>
 	/// <summary>
 	/// The <see cref="Attribute"/> that will be used for the next <see cref="AddRune(Rune)"/> or <see cref="AddStr"/> call.
 	/// The <see cref="Attribute"/> that will be used for the next <see cref="AddRune(Rune)"/> or <see cref="AddStr"/> call.

+ 4 - 0
Terminal.Gui/ConsoleDrivers/ConsoleKeyMapping.cs

@@ -90,6 +90,10 @@ public static class ConsoleKeyMapping {
 	[DllImport ("user32.dll")]
 	[DllImport ("user32.dll")]
 	extern static bool GetKeyboardLayoutName ([Out] StringBuilder pwszKLID);
 	extern static bool GetKeyboardLayoutName ([Out] StringBuilder pwszKLID);
 
 
+	/// <summary>
+	/// Retrieves the name of the active input locale identifier (formerly called the keyboard layout) for the calling thread.
+	/// </summary>
+	/// <returns></returns>
 	public static string GetKeyboardLayoutName ()
 	public static string GetKeyboardLayoutName ()
 	{
 	{
 		if (Environment.OSVersion.Platform != PlatformID.Win32NT) {
 		if (Environment.OSVersion.Platform != PlatformID.Win32NT) {

+ 8 - 2
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -17,12 +17,18 @@ namespace Terminal.Gui;
 class CursesDriver : ConsoleDriver {
 class CursesDriver : ConsoleDriver {
 	public override int Cols {
 	public override int Cols {
 		get => Curses.Cols;
 		get => Curses.Cols;
-		internal set => Curses.Cols = value;
+		internal set {
+			Curses.Cols = value;
+			ClearContents();
+		}
 	}
 	}
 
 
 	public override int Rows {
 	public override int Rows {
 		get => Curses.Lines;
 		get => Curses.Lines;
-		internal set => Curses.Lines = value;
+		internal set {
+			Curses.Lines = value;
+			ClearContents();
+		}
 	}
 	}
 
 
 	CursorVisibility? _initialCursorVisibility = null;
 	CursorVisibility? _initialCursorVisibility = null;

+ 19 - 5
Terminal.Gui/ConsoleDrivers/EscSeqUtils/EscSeqUtils.cs

@@ -170,10 +170,10 @@ public static class EscSeqUtils {
 	/// <summary>
 	/// <summary>
 	/// ESC [ y ; x H - CUP Cursor Position - Cursor moves to x ; y coordinate within the viewport, where x is the column of the y line
 	/// ESC [ y ; x H - CUP Cursor Position - Cursor moves to x ; y coordinate within the viewport, where x is the column of the y line
 	/// </summary>
 	/// </summary>
-	/// <param name="x"></param>
-	/// <param name="y"></param>
+	/// <param name="row">Origin is (1,1).</param>
+	/// <param name="col">Origin is (1,1).</param>
 	/// <returns></returns>
 	/// <returns></returns>
-	public static string CSI_SetCursorPosition (int y, int x) => $"{CSI}{y};{x}H";
+	public static string CSI_SetCursorPosition (int row, int col) => $"{CSI}{row};{col}H";
 
 
 
 
 	//ESC [ <y> ; <x> f - HVP     Horizontal Vertical Position* Cursor moves to<x>; <y> coordinate within the viewport, where <x> is the column of the<y> line
 	//ESC [ <y> ; <x> f - HVP     Horizontal Vertical Position* Cursor moves to<x>; <y> coordinate within the viewport, where <x> is the column of the<y> line
@@ -248,15 +248,29 @@ public static class EscSeqUtils {
 	/// </summary>
 	/// </summary>
 	public static string CSI_SetGraphicsRendition (params int [] parameters) => $"{CSI}{string.Join (";", parameters)}m";
 	public static string CSI_SetGraphicsRendition (params int [] parameters) => $"{CSI}{string.Join (";", parameters)}m";
 
 
+	/// <summary>
+	/// ESC [ (n) m - Uses <see cref="CSI_SetGraphicsRendition(int[])" /> to set the foreground color.
+	/// </summary>
+	/// <param name="code">One of the 16 color codes.</param>
+	/// <returns></returns>
+	public static string CSI_SetForegroundColor (AnsiColorCode code) => CSI_SetGraphicsRendition ((int)code);
+
+	/// <summary>
+	/// ESC [ (n) m - Uses <see cref="CSI_SetGraphicsRendition(int[])" /> to set the background color.
+	/// </summary>
+	/// <param name="code">One of the 16 color codes.</param>
+	/// <returns></returns>
+	public static string CSI_SetBackgroundColor (AnsiColorCode code) => CSI_SetGraphicsRendition ((int)code+10);
+
 	/// <summary>
 	/// <summary>
 	/// ESC[38;5;{id}m - Set foreground color (256 colors)
 	/// ESC[38;5;{id}m - Set foreground color (256 colors)
 	/// </summary>
 	/// </summary>
-	public static string CSI_SetForegroundColor (int id) => $"{CSI}38;5;{id}m";
+	public static string CSI_SetForegroundColor256 (int color) => $"{CSI}38;5;{color}m";
 
 
 	/// <summary>
 	/// <summary>
 	/// ESC[48;5;{id}m - Set background color (256 colors)
 	/// ESC[48;5;{id}m - Set background color (256 colors)
 	/// </summary>
 	/// </summary>
-	public static string CSI_SetBackgroundColor (int id) => $"{CSI}48;5;{id}m";
+	public static string CSI_SetBackgroundColor256 (int color) => $"{CSI}48;5;{color}m";
 
 
 	/// <summary>
 	/// <summary>
 	/// ESC[38;2;{r};{g};{b}m	Set foreground color as RGB.
 	/// ESC[38;2;{r};{g};{b}m	Set foreground color as RGB.

+ 1 - 6
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -837,9 +837,8 @@ class NetDriver : ConsoleDriver {
 						} else if (lastCol == -1) {
 						} else if (lastCol == -1) {
 							lastCol = col;
 							lastCol = col;
 						}
 						}
-						if (lastCol + 1 < cols) {
+						if (lastCol + 1 < cols)
 							lastCol++;
 							lastCol++;
-						}
 						continue;
 						continue;
 					}
 					}
 
 
@@ -1167,10 +1166,6 @@ class NetDriver : ConsoleDriver {
 				// and passing on Shift would be redundant.
 				// and passing on Shift would be redundant.
 				return MapToKeyCodeModifiers (keyInfo.Modifiers & ~ConsoleModifiers.Shift, (KeyCode)keyInfo.KeyChar);
 				return MapToKeyCodeModifiers (keyInfo.Modifiers & ~ConsoleModifiers.Shift, (KeyCode)keyInfo.KeyChar);
 			}
 			}
-			break;
-
-
-			return (KeyCode)(uint)keyInfo.KeyChar;
 		}
 		}
 
 
 		var key = keyInfo.Key;
 		var key = keyInfo.Key;

+ 226 - 192
Terminal.Gui/Drawing/Color.cs

@@ -9,6 +9,7 @@ using System.Text.Json.Serialization;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
+
 /// <summary>
 /// <summary>
 /// Defines the 16 legacy color names and values that can be used to set the
 /// Defines the 16 legacy color names and values that can be used to set the
 /// foreground and background colors in Terminal.Gui apps. Used with <see cref="Color"/>.
 /// foreground and background colors in Terminal.Gui apps. Used with <see cref="Color"/>.
@@ -88,14 +89,82 @@ public enum ColorName {
 	/// </summary>
 	/// </summary>
 	White
 	White
 }
 }
+/// <summary>
+/// The 16 foreground color codes used by ANSI Esc sequences for 256 color terminals. Add 10 to these values for background color.
+/// </summary>
+public enum AnsiColorCode {
+	/// <summary>
+	/// The ANSI color code for Black.
+	/// </summary>
+	BLACK = 30,
 
 
+	/// <summary>
+	/// The ANSI color code for Red.
+	/// </summary>
+	RED = 31,
+	/// <summary>
+	/// The ANSI color code for Green.
+	/// </summary>
+	GREEN = 32,
+	/// <summary>
+	/// The ANSI color code for Yellow.
+	/// </summary>
+	YELLOW = 33,
+	/// <summary>
+	/// The ANSI color code for Blue.
+	/// </summary>
+	BLUE = 34,
+	/// <summary>
+	/// The ANSI color code for Magenta.
+	/// </summary>
+	MAGENTA = 35,
+	/// <summary>
+	/// The ANSI color code for Cyan.
+	/// </summary>
+	CYAN = 36,
+	/// <summary>
+	/// The ANSI color code for White.
+	/// </summary>
+	WHITE = 37,
+	/// <summary>
+	/// The ANSI color code for Bright Black.
+	/// </summary>
+	BRIGHT_BLACK = 90,
+	/// <summary>
+	/// The ANSI color code for Bright Red.
+	/// </summary>
+	BRIGHT_RED = 91,
+	/// <summary>
+	/// The ANSI color code for Bright Green.
+	/// </summary>
+	BRIGHT_GREEN = 92,
+	/// <summary>
+	/// The ANSI color code for Bright Yellow.
+	/// </summary>
+	BRIGHT_YELLOW = 93,
+	/// <summary>
+	/// The ANSI color code for Bright Blue.
+	/// </summary>
+	BRIGHT_BLUE = 94,
+	/// <summary>
+	/// The ANSI color code for Bright Magenta.
+	/// </summary>
+	BRIGHT_MAGENTA = 95,
+	/// <summary>
+	/// The ANSI color code for Bright Cyan.
+	/// </summary>
+	BRIGHT_CYAN = 96,
+	/// <summary>
+	/// The ANSI color code for Bright White.
+	/// </summary>
+	BRIGHT_WHITE = 97
+}
 /// <summary>
 /// <summary>
 /// Represents a 24-bit color. Provides automatic mapping between the legacy 4-bit (16 color) system and 24-bit colors (see <see cref="ColorName"/>).
 /// Represents a 24-bit color. Provides automatic mapping between the legacy 4-bit (16 color) system and 24-bit colors (see <see cref="ColorName"/>).
 /// Used with <see cref="Attribute"/>. 
 /// Used with <see cref="Attribute"/>. 
 /// </summary>
 /// </summary>
 [JsonConverter (typeof (ColorJsonConverter))]
 [JsonConverter (typeof (ColorJsonConverter))]
 public class Color : IEquatable<Color> {
 public class Color : IEquatable<Color> {
-
 	/// <summary>
 	/// <summary>
 	/// Initializes a new instance of the <see cref="Color"/> class.
 	/// Initializes a new instance of the <see cref="Color"/> class.
 	/// </summary>
 	/// </summary>
@@ -115,10 +184,7 @@ public class Color : IEquatable<Color> {
 	/// Initializes a new instance of the <see cref="Color"/> class with an encoded 24-bit color value.
 	/// Initializes a new instance of the <see cref="Color"/> class with an encoded 24-bit color value.
 	/// </summary>
 	/// </summary>
 	/// <param name="rgba">The encoded 24-bit color value (see <see cref="Rgba"/>).</param>
 	/// <param name="rgba">The encoded 24-bit color value (see <see cref="Rgba"/>).</param>
-	public Color (int rgba)
-	{
-		Rgba = rgba;
-	}
+	public Color (int rgba) => Rgba = rgba;
 
 
 	/// <summary>
 	/// <summary>
 	/// Initializes a new instance of the <see cref="Color"/> color from a legacy 16-color value.
 	/// Initializes a new instance of the <see cref="Color"/> color from a legacy 16-color value.
@@ -126,7 +192,7 @@ public class Color : IEquatable<Color> {
 	/// <param name="colorName">The 16-color value.</param>
 	/// <param name="colorName">The 16-color value.</param>
 	public Color (ColorName colorName)
 	public Color (ColorName colorName)
 	{
 	{
-		var c = Color.FromColorName (colorName);
+		var c = FromColorName (colorName);
 		R = c.R;
 		R = c.R;
 		G = c.G;
 		G = c.G;
 		B = c.B;
 		B = c.B;
@@ -188,11 +254,11 @@ public class Color : IEquatable<Color> {
 	/// </code>
 	/// </code>
 	/// </summary>
 	/// </summary>
 	public int Rgba {
 	public int Rgba {
-		get => (A << 24) | (R << 16) | (G << 8) | B;
+		get => A << 24 | R << 16 | G << 8 | B;
 		set {
 		set {
-			A = (byte)((value >> 24) & 0xFF);
-			R = (byte)((value >> 16) & 0xFF);
-			G = (byte)((value >> 8) & 0xFF);
+			A = (byte)(value >> 24 & 0xFF);
+			R = (byte)(value >> 16 & 0xFF);
+			G = (byte)(value >> 8 & 0xFF);
 			B = (byte)(value & 0xFF);
 			B = (byte)(value & 0xFF);
 		}
 		}
 	}
 	}
@@ -203,39 +269,61 @@ public class Color : IEquatable<Color> {
 	/// Maps legacy 16-color values to the corresponding 24-bit RGB value.
 	/// Maps legacy 16-color values to the corresponding 24-bit RGB value.
 	/// </summary>
 	/// </summary>
 	internal static ImmutableDictionary<Color, ColorName> _colorToNameMap = new Dictionary<Color, ColorName> () {
 	internal static ImmutableDictionary<Color, ColorName> _colorToNameMap = new Dictionary<Color, ColorName> () {
-			// using "Windows 10 Console/PowerShell 6" here: https://i.stack.imgur.com/9UVnC.png
-			// See also: https://en.wikipedia.org/wiki/ANSI_escape_code
-			{ new Color (12, 12, 12),Gui.ColorName.Black },
-			{ new Color (0, 55, 218),Gui.ColorName.Blue },
-			{ new Color (19, 161, 14),Gui.ColorName.Green},
-			{ new Color (58, 150, 221),Gui.ColorName.Cyan},
-			{ new Color (197, 15, 31),Gui.ColorName.Red},
-			{ new Color (136, 23, 152),Gui.ColorName.Magenta},
-			{ new Color (128, 64, 32),Gui.ColorName.Yellow},
-			{ new Color (204, 204, 204),Gui.ColorName.Gray},
-			{ new Color (118, 118, 118),Gui.ColorName.DarkGray},
-			{ new Color (59, 120, 255),Gui.ColorName.BrightBlue},
-			{ new Color (22, 198, 12),Gui.ColorName.BrightGreen},
-			{ new Color (97, 214, 214),Gui.ColorName.BrightCyan},
-			{ new Color (231, 72, 86),Gui.ColorName.BrightRed},
-			{ new Color (180, 0, 158),Gui.ColorName.BrightMagenta },
-			{ new Color (249, 241, 165),Gui.ColorName.BrightYellow},
-			{ new Color (242, 242, 242),Gui.ColorName.White},
-		}.ToImmutableDictionary ();
+		// using "Windows 10 Console/PowerShell 6" here: https://i.stack.imgur.com/9UVnC.png
+		// See also: https://en.wikipedia.org/wiki/ANSI_escape_code
+		{ new Color (12, 12, 12), ColorName.Black },
+		{ new Color (0, 55, 218), ColorName.Blue },
+		{ new Color (19, 161, 14), ColorName.Green },
+		{ new Color (58, 150, 221), ColorName.Cyan },
+		{ new Color (197, 15, 31), ColorName.Red },
+		{ new Color (136, 23, 152), ColorName.Magenta },
+		{ new Color (128, 64, 32), ColorName.Yellow },
+		{ new Color (204, 204, 204), ColorName.Gray },
+		{ new Color (118, 118, 118), ColorName.DarkGray },
+		{ new Color (59, 120, 255), ColorName.BrightBlue },
+		{ new Color (22, 198, 12), ColorName.BrightGreen },
+		{ new Color (97, 214, 214), ColorName.BrightCyan },
+		{ new Color (231, 72, 86), ColorName.BrightRed },
+		{ new Color (180, 0, 158), ColorName.BrightMagenta },
+		{ new Color (249, 241, 165), ColorName.BrightYellow },
+		{ new Color (242, 242, 242), ColorName.White }
+	}.ToImmutableDictionary ();
+
+
+	/// <summary>
+	/// Defines the 16 legacy color names and values that can be used to set the
+	/// </summary>
+	internal static ImmutableDictionary<ColorName, AnsiColorCode> _colorNameToAnsiColorMap = new Dictionary<ColorName, AnsiColorCode> {
+		{ ColorName.Black, AnsiColorCode.BLACK },
+		{ ColorName.Blue, AnsiColorCode.BLUE },
+		{ ColorName.Green, AnsiColorCode.GREEN },
+		{ ColorName.Cyan, AnsiColorCode.CYAN },
+		{ ColorName.Red, AnsiColorCode.RED },
+		{ ColorName.Magenta, AnsiColorCode.MAGENTA },
+		{ ColorName.Yellow, AnsiColorCode.YELLOW },
+		{ ColorName.Gray, AnsiColorCode.WHITE },
+		{ ColorName.DarkGray, AnsiColorCode.BRIGHT_BLACK },
+		{ ColorName.BrightBlue, AnsiColorCode.BRIGHT_BLUE },
+		{ ColorName.BrightGreen, AnsiColorCode.BRIGHT_GREEN },
+		{ ColorName.BrightCyan, AnsiColorCode.BRIGHT_CYAN },
+		{ ColorName.BrightRed, AnsiColorCode.BRIGHT_RED },
+		{ ColorName.BrightMagenta, AnsiColorCode.BRIGHT_MAGENTA },
+		{ ColorName.BrightYellow, AnsiColorCode.BRIGHT_YELLOW },
+		{ ColorName.White, AnsiColorCode.BRIGHT_WHITE }
+	}.ToImmutableDictionary ();
 
 
 	/// <summary>
 	/// <summary>
 	/// Gets or sets the 24-bit color value for each of the legacy 16-color values.
 	/// Gets or sets the 24-bit color value for each of the legacy 16-color values.
 	/// </summary>
 	/// </summary>
 	[SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]
 	[SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]
 	public static Dictionary<ColorName, string> Colors {
 	public static Dictionary<ColorName, string> Colors {
-		get {
+		get =>
 			// Transform _colorToNameMap into a Dictionary<ColorNames,string>
 			// Transform _colorToNameMap into a Dictionary<ColorNames,string>
-			return _colorToNameMap.ToDictionary (kvp => kvp.Value, kvp => $"#{kvp.Key.R:X2}{kvp.Key.G:X2}{kvp.Key.B:X2}");
-		}
+			_colorToNameMap.ToDictionary (kvp => kvp.Value, kvp => $"#{kvp.Key.R:X2}{kvp.Key.G:X2}{kvp.Key.B:X2}");
 		set {
 		set {
 			// Transform Dictionary<ColorNames,string> into _colorToNameMap
 			// Transform Dictionary<ColorNames,string> into _colorToNameMap
 			var newMap = value.ToDictionary (kvp => new Color (kvp.Value), kvp => {
 			var newMap = value.ToDictionary (kvp => new Color (kvp.Value), kvp => {
-				if (Enum.TryParse<ColorName> (kvp.Key.ToString (), ignoreCase: true, out ColorName colorName)) {
+				if (Enum.TryParse<ColorName> (kvp.Key.ToString (), true, out var colorName)) {
 					return colorName;
 					return colorName;
 				}
 				}
 				throw new ArgumentException ($"Invalid color name: {kvp.Key}");
 				throw new ArgumentException ($"Invalid color name: {kvp.Key}");
@@ -247,9 +335,9 @@ public class Color : IEquatable<Color> {
 	/// <summary>
 	/// <summary>
 	/// Converts a legacy <see cref="Gui.ColorName"/> to a 24-bit <see cref="Color"/>.
 	/// Converts a legacy <see cref="Gui.ColorName"/> to a 24-bit <see cref="Color"/>.
 	/// </summary>
 	/// </summary>
-	/// <param name="consoleColor">The <see cref="Color"/> to convert.</param>
+	/// <param name="colorName">The <see cref="Color"/> to convert.</param>
 	/// <returns></returns>
 	/// <returns></returns>
-	private static Color FromColorName (ColorName consoleColor) => _colorToNameMap.FirstOrDefault (x => x.Value == consoleColor).Key;
+	static Color FromColorName (ColorName colorName) => _colorToNameMap.FirstOrDefault (x => x.Value == colorName).Key;
 
 
 	// Iterates through the entries in the _colorNames dictionary, calculates the
 	// Iterates through the entries in the _colorNames dictionary, calculates the
 	// Euclidean distance between the input color and each dictionary color in RGB space,
 	// Euclidean distance between the input color and each dictionary color in RGB space,
@@ -257,11 +345,11 @@ public class Color : IEquatable<Color> {
 	// representing the closest color entry and its associated color name.
 	// representing the closest color entry and its associated color name.
 	internal static ColorName FindClosestColor (Color inputColor)
 	internal static ColorName FindClosestColor (Color inputColor)
 	{
 	{
-		ColorName closestColor = Gui.ColorName.Black; // Default to Black
+		var closestColor = ColorName.Black; // Default to Black
 		double closestDistance = double.MaxValue;
 		double closestDistance = double.MaxValue;
 
 
 		foreach (var colorEntry in _colorToNameMap) {
 		foreach (var colorEntry in _colorToNameMap) {
-			var distance = CalculateColorDistance (inputColor, colorEntry.Key);
+			double distance = CalculateColorDistance (inputColor, colorEntry.Key);
 			if (distance < closestDistance) {
 			if (distance < closestDistance) {
 				closestDistance = distance;
 				closestDistance = distance;
 				closestColor = colorEntry.Value;
 				closestColor = colorEntry.Value;
@@ -271,12 +359,12 @@ public class Color : IEquatable<Color> {
 		return closestColor;
 		return closestColor;
 	}
 	}
 
 
-	private static double CalculateColorDistance (Color color1, Color color2)
+	static double CalculateColorDistance (Color color1, Color color2)
 	{
 	{
 		// Calculate the Euclidean distance between two colors
 		// Calculate the Euclidean distance between two colors
-		var deltaR = (double)color1.R - (double)color2.R;
-		var deltaG = (double)color1.G - (double)color2.G;
-		var deltaB = (double)color1.B - (double)color2.B;
+		double deltaR = (double)color1.R - (double)color2.R;
+		double deltaG = (double)color1.G - (double)color2.G;
+		double deltaB = (double)color1.B - (double)color2.B;
 
 
 		return Math.Sqrt (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
 		return Math.Sqrt (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
 	}
 	}
@@ -300,6 +388,16 @@ public class Color : IEquatable<Color> {
 		}
 		}
 	}
 	}
 
 
+	/// <summary>
+	/// Gets or sets the <see cref="Color"/> using a legacy 16-color <see cref="Gui.ColorName"/> value.
+	/// <see langword="get"/> will return the closest 16 color match to the true color when no exact value is found.
+	/// </summary>
+	/// <remarks>
+	/// Get returns the <see cref="ColorName"/> of the closest 24-bit color value. Set sets the RGB value using a hard-coded map.
+	/// </remarks>
+	[JsonIgnore]
+	public AnsiColorCode AnsiColorCode => _colorNameToAnsiColorMap [ColorName];
+
 	#region Legacy Color Names
 	#region Legacy Color Names
 	/// <summary>
 	/// <summary>
 	/// The black color.
 	/// The black color.
@@ -382,49 +480,49 @@ public class Color : IEquatable<Color> {
 	public static bool TryParse (string text, [NotNullWhen (true)] out Color color)
 	public static bool TryParse (string text, [NotNullWhen (true)] out Color color)
 	{
 	{
 		// empty color
 		// empty color
-		if ((text == null) || (text.Length == 0)) {
+		if (text == null || text.Length == 0) {
 			color = null;
 			color = null;
 			return false;
 			return false;
 		}
 		}
 
 
 		// #RRGGBB, #RGB
 		// #RRGGBB, #RGB
-		if ((text [0] == '#') && text.Length is 7 or 4) {
+		if (text [0] == '#' && text.Length is 7 or 4) {
 			if (text.Length == 7) {
 			if (text.Length == 7) {
-				var r = Convert.ToInt32 (text.Substring (1, 2), 16);
-				var g = Convert.ToInt32 (text.Substring (3, 2), 16);
-				var b = Convert.ToInt32 (text.Substring (5, 2), 16);
+				int r = Convert.ToInt32 (text.Substring (1, 2), 16);
+				int g = Convert.ToInt32 (text.Substring (3, 2), 16);
+				int b = Convert.ToInt32 (text.Substring (5, 2), 16);
 				color = new Color (r, g, b);
 				color = new Color (r, g, b);
 			} else {
 			} else {
-				var rText = char.ToString (text [1]);
-				var gText = char.ToString (text [2]);
-				var bText = char.ToString (text [3]);
+				string rText = char.ToString (text [1]);
+				string gText = char.ToString (text [2]);
+				string bText = char.ToString (text [3]);
 
 
-				var r = Convert.ToInt32 (rText + rText, 16);
-				var g = Convert.ToInt32 (gText + gText, 16);
-				var b = Convert.ToInt32 (bText + bText, 16);
+				int r = Convert.ToInt32 (rText + rText, 16);
+				int g = Convert.ToInt32 (gText + gText, 16);
+				int b = Convert.ToInt32 (bText + bText, 16);
 				color = new Color (r, g, b);
 				color = new Color (r, g, b);
 			}
 			}
 			return true;
 			return true;
 		}
 		}
 
 
 		// #RRGGBB, #RGBA
 		// #RRGGBB, #RGBA
-		if ((text [0] == '#') && text.Length is 8 or 5) {
+		if (text [0] == '#' && text.Length is 8 or 5) {
 			if (text.Length == 7) {
 			if (text.Length == 7) {
-				var r = Convert.ToInt32 (text.Substring (1, 2), 16);
-				var g = Convert.ToInt32 (text.Substring (3, 2), 16);
-				var b = Convert.ToInt32 (text.Substring (5, 2), 16);
-				var a = Convert.ToInt32 (text.Substring (7, 2), 16);
+				int r = Convert.ToInt32 (text.Substring (1, 2), 16);
+				int g = Convert.ToInt32 (text.Substring (3, 2), 16);
+				int b = Convert.ToInt32 (text.Substring (5, 2), 16);
+				int a = Convert.ToInt32 (text.Substring (7, 2), 16);
 				color = new Color (a, r, g, b);
 				color = new Color (a, r, g, b);
 			} else {
 			} else {
-				var rText = char.ToString (text [1]);
-				var gText = char.ToString (text [2]);
-				var bText = char.ToString (text [3]);
-				var aText = char.ToString (text [4]);
-
-				var r = Convert.ToInt32 (aText + aText, 16);
-				var g = Convert.ToInt32 (rText + rText, 16);
-				var b = Convert.ToInt32 (gText + gText, 16);
-				var a = Convert.ToInt32 (bText + bText, 16);
+				string rText = char.ToString (text [1]);
+				string gText = char.ToString (text [2]);
+				string bText = char.ToString (text [3]);
+				string aText = char.ToString (text [4]);
+
+				int r = Convert.ToInt32 (aText + aText, 16);
+				int g = Convert.ToInt32 (rText + rText, 16);
+				int b = Convert.ToInt32 (gText + gText, 16);
+				int a = Convert.ToInt32 (bText + bText, 16);
 				color = new Color (r, g, b, a);
 				color = new Color (r, g, b, a);
 			}
 			}
 			return true;
 			return true;
@@ -433,9 +531,9 @@ public class Color : IEquatable<Color> {
 		// rgb(r,g,b)
 		// rgb(r,g,b)
 		var match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+)\)");
 		var match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+)\)");
 		if (match.Success) {
 		if (match.Success) {
-			var r = int.Parse (match.Groups [1].Value);
-			var g = int.Parse (match.Groups [2].Value);
-			var b = int.Parse (match.Groups [3].Value);
+			int r = int.Parse (match.Groups [1].Value);
+			int g = int.Parse (match.Groups [2].Value);
+			int b = int.Parse (match.Groups [3].Value);
 			color = new Color (r, g, b);
 			color = new Color (r, g, b);
 			return true;
 			return true;
 		}
 		}
@@ -443,15 +541,15 @@ public class Color : IEquatable<Color> {
 		// rgb(r,g,b,a)
 		// rgb(r,g,b,a)
 		match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+),(\d+)\)");
 		match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+),(\d+)\)");
 		if (match.Success) {
 		if (match.Success) {
-			var r = int.Parse (match.Groups [1].Value);
-			var g = int.Parse (match.Groups [2].Value);
-			var b = int.Parse (match.Groups [3].Value);
-			var a = int.Parse (match.Groups [4].Value);
+			int r = int.Parse (match.Groups [1].Value);
+			int g = int.Parse (match.Groups [2].Value);
+			int b = int.Parse (match.Groups [3].Value);
+			int a = int.Parse (match.Groups [4].Value);
 			color = new Color (r, g, b, a);
 			color = new Color (r, g, b, a);
 			return true;
 			return true;
 		}
 		}
 
 
-		if (Enum.TryParse<ColorName> (text, ignoreCase: true, out ColorName colorName)) {
+		if (Enum.TryParse<ColorName> (text, true, out var colorName)) {
 			color = new Color (colorName);
 			color = new Color (colorName);
 			return true;
 			return true;
 		}
 		}
@@ -465,37 +563,25 @@ public class Color : IEquatable<Color> {
 	/// Cast from int.
 	/// Cast from int.
 	/// </summary>
 	/// </summary>
 	/// <param name="rgba"></param>
 	/// <param name="rgba"></param>
-	public static implicit operator Color (int rgba)
-	{
-		return new Color (rgba);
-	}
+	public static implicit operator Color (int rgba) => new Color (rgba);
 
 
 	/// <summary>
 	/// <summary>
 	/// Cast to int.
 	/// Cast to int.
 	/// </summary>
 	/// </summary>
 	/// <param name="color"></param>
 	/// <param name="color"></param>
-	public static explicit operator int (Color color)
-	{
-		return color.Rgba;
-	}
+	public static explicit operator int (Color color) => color.Rgba;
 
 
 	/// <summary>
 	/// <summary>
 	/// Cast from <see cref="Gui.ColorName"/>.
 	/// Cast from <see cref="Gui.ColorName"/>.
 	/// </summary>
 	/// </summary>
 	/// <param name="colorName"></param>
 	/// <param name="colorName"></param>
-	public static explicit operator Color (ColorName colorName)
-	{
-		return new Color (colorName);
-	}
+	public static explicit operator Color (ColorName colorName) => new Color (colorName);
 
 
 	/// <summary>
 	/// <summary>
 	/// Cast to <see cref="Gui.ColorName"/>.
 	/// Cast to <see cref="Gui.ColorName"/>.
 	/// </summary>
 	/// </summary>
 	/// <param name="color"></param>
 	/// <param name="color"></param>
-	public static explicit operator ColorName (Color color)
-	{
-		return color.ColorName;
-	}
+	public static explicit operator ColorName (Color color) => color.ColorName;
 
 
 
 
 	/// <summary>
 	/// <summary>
@@ -506,11 +592,13 @@ public class Color : IEquatable<Color> {
 	/// <returns></returns>
 	/// <returns></returns>
 	public static bool operator == (Color left, Color right)
 	public static bool operator == (Color left, Color right)
 	{
 	{
-		if (left is null && right is null)
+		if (left is null && right is null) {
 			return true;
 			return true;
+		}
 
 
-		if (left is null || right is null)
+		if (left is null || right is null) {
 			return false;
 			return false;
+		}
 
 
 		return left.Equals (right);
 		return left.Equals (right);
 	}
 	}
@@ -524,11 +612,13 @@ public class Color : IEquatable<Color> {
 	/// <returns></returns>
 	/// <returns></returns>
 	public static bool operator != (Color left, Color right)
 	public static bool operator != (Color left, Color right)
 	{
 	{
-		if (left is null && right is null)
+		if (left is null && right is null) {
 			return false;
 			return false;
+		}
 
 
-		if (left is null || right is null)
+		if (left is null || right is null) {
 			return true;
 			return true;
+		}
 
 
 		return !left.Equals (right);
 		return !left.Equals (right);
 	}
 	}
@@ -539,10 +629,7 @@ public class Color : IEquatable<Color> {
 	/// <param name="left"></param>
 	/// <param name="left"></param>
 	/// <param name="right"></param>
 	/// <param name="right"></param>
 	/// <returns></returns>
 	/// <returns></returns>
-	public static bool operator == (ColorName left, Color right)
-	{
-		return left == right.ColorName;
-	}
+	public static bool operator == (ColorName left, Color right) => left == right.ColorName;
 
 
 	/// <summary>
 	/// <summary>
 	/// Inequality operator for <see cref="Color"/> and <see cref="Gui.ColorName"/> objects.
 	/// Inequality operator for <see cref="Color"/> and <see cref="Gui.ColorName"/> objects.
@@ -550,10 +637,7 @@ public class Color : IEquatable<Color> {
 	/// <param name="left"></param>
 	/// <param name="left"></param>
 	/// <param name="right"></param>
 	/// <param name="right"></param>
 	/// <returns></returns>
 	/// <returns></returns>
-	public static bool operator != (ColorName left, Color right)
-	{
-		return left != right.ColorName;
-	}
+	public static bool operator != (ColorName left, Color right) => left != right.ColorName;
 
 
 	/// <summary>
 	/// <summary>
 	/// Equality operator for <see cref="Color"/> and <see cref="Gui.ColorName"/> objects.
 	/// Equality operator for <see cref="Color"/> and <see cref="Gui.ColorName"/> objects.
@@ -561,10 +645,7 @@ public class Color : IEquatable<Color> {
 	/// <param name="left"></param>
 	/// <param name="left"></param>
 	/// <param name="right"></param>
 	/// <param name="right"></param>
 	/// <returns></returns>
 	/// <returns></returns>
-	public static bool operator == (Color left, ColorName right)
-	{
-		return left.ColorName == right;
-	}
+	public static bool operator == (Color left, ColorName right) => left.ColorName == right;
 
 
 	/// <summary>
 	/// <summary>
 	/// Inequality operator for <see cref="Color"/> and <see cref="Gui.ColorName"/> objects.
 	/// Inequality operator for <see cref="Color"/> and <see cref="Gui.ColorName"/> objects.
@@ -572,33 +653,20 @@ public class Color : IEquatable<Color> {
 	/// <param name="left"></param>
 	/// <param name="left"></param>
 	/// <param name="right"></param>
 	/// <param name="right"></param>
 	/// <returns></returns>
 	/// <returns></returns>
-	public static bool operator != (Color left, ColorName right)
-	{
-		return left.ColorName != right;
-	}
+	public static bool operator != (Color left, ColorName right) => left.ColorName != right;
 
 
 
 
 	/// <inheritdoc/>
 	/// <inheritdoc/>
-	public override bool Equals (object obj)
-	{
-		return obj is Color other && Equals (other);
-	}
+	public override bool Equals (object obj) => obj is Color other && Equals (other);
 
 
 	/// <inheritdoc/>
 	/// <inheritdoc/>
-	public bool Equals (Color other)
-	{
-		return
-			R == other.R &&
-			G == other.G &&
-			B == other.B &&
-			A == other.A;
-	}
+	public bool Equals (Color other) => R == other.R &&
+					G == other.G &&
+					B == other.B &&
+					A == other.A;
 
 
 	/// <inheritdoc/>
 	/// <inheritdoc/>
-	public override int GetHashCode ()
-	{
-		return HashCode.Combine (R, G, B, A);
-	}
+	public override int GetHashCode () => HashCode.Combine (R, G, B, A);
 	#endregion
 	#endregion
 
 
 	/// <summary>
 	/// <summary>
@@ -616,14 +684,13 @@ public class Color : IEquatable<Color> {
 	public override string ToString ()
 	public override string ToString ()
 	{
 	{
 		// If Values has an exact match with a named color (in _colorNames), use that.
 		// If Values has an exact match with a named color (in _colorNames), use that.
-		if (_colorToNameMap.TryGetValue (this, out ColorName colorName)) {
+		if (_colorToNameMap.TryGetValue (this, out var colorName)) {
 			return Enum.GetName (typeof (ColorName), colorName);
 			return Enum.GetName (typeof (ColorName), colorName);
 		}
 		}
 		// Otherwise return as an RGB hex value.
 		// Otherwise return as an RGB hex value.
 		return $"#{R:X2}{G:X2}{B:X2}";
 		return $"#{R:X2}{G:X2}{B:X2}";
 	}
 	}
 }
 }
-
 /// <summary>
 /// <summary>
 /// Attributes represent how text is styled when displayed in the terminal. 
 /// Attributes represent how text is styled when displayed in the terminal. 
 /// </summary>
 /// </summary>
@@ -634,7 +701,6 @@ public class Color : IEquatable<Color> {
 /// </remarks>
 /// </remarks>
 [JsonConverter (typeof (AttributeJsonConverter))]
 [JsonConverter (typeof (AttributeJsonConverter))]
 public readonly struct Attribute : IEquatable<Attribute> {
 public readonly struct Attribute : IEquatable<Attribute> {
-
 	/// <summary>
 	/// <summary>
 	/// Default empty attribute.
 	/// Default empty attribute.
 	/// </summary>
 	/// </summary>
@@ -665,19 +731,20 @@ public readonly struct Attribute : IEquatable<Attribute> {
 	{
 	{
 		PlatformColor = -1;
 		PlatformColor = -1;
 		var d = Default;
 		var d = Default;
-		Foreground = new (d.Foreground.ColorName);
-		Background = new (d.Background.ColorName);
+		Foreground = new Color (d.Foreground.ColorName);
+		Background = new Color (d.Background.ColorName);
 	}
 	}
 
 
 	/// <summary>
 	/// <summary>
 	/// Initializes a new instance with platform specific color value.
 	/// Initializes a new instance with platform specific color value.
 	/// </summary>
 	/// </summary>
 	/// <param name="platformColor">Value.</param>
 	/// <param name="platformColor">Value.</param>
-	internal Attribute (int platformColor) {
+	internal Attribute (int platformColor)
+	{
 		PlatformColor = platformColor;
 		PlatformColor = platformColor;
 		var d = Default;
 		var d = Default;
-		Foreground = new (d.Foreground.ColorName);
-		Background = new (d.Background.ColorName);
+		Foreground = new Color (d.Foreground.ColorName);
+		Background = new Color (d.Background.ColorName);
 	}
 	}
 
 
 	/// <summary>
 	/// <summary>
@@ -775,30 +842,21 @@ public readonly struct Attribute : IEquatable<Attribute> {
 	public static bool operator != (Attribute left, Attribute right) => !(left == right);
 	public static bool operator != (Attribute left, Attribute right) => !(left == right);
 
 
 	/// <inheritdoc />
 	/// <inheritdoc />
-	public override bool Equals (object obj)
-	{
-		return obj is Attribute other && Equals (other);
-	}
+	public override bool Equals (object obj) => obj is Attribute other && Equals (other);
 
 
 	/// <inheritdoc />
 	/// <inheritdoc />
-	public bool Equals (Attribute other)
-	{
-		return PlatformColor == other.PlatformColor &&
-			Foreground == other.Foreground &&
-			Background == other.Background;
-	}
+	public bool Equals (Attribute other) => PlatformColor == other.PlatformColor &&
+						Foreground == other.Foreground &&
+						Background == other.Background;
 
 
 	/// <inheritdoc />
 	/// <inheritdoc />
 	public override int GetHashCode () => HashCode.Combine (PlatformColor, Foreground, Background);
 	public override int GetHashCode () => HashCode.Combine (PlatformColor, Foreground, Background);
 
 
 	/// <inheritdoc />
 	/// <inheritdoc />
-	public override string ToString ()
-	{
+	public override string ToString () =>
 		// Note, Unit tests are dependent on this format
 		// Note, Unit tests are dependent on this format
-		return $"{Foreground},{Background}";
-	}
+		$"{Foreground},{Background}";
 }
 }
-
 /// <summary>
 /// <summary>
 /// Defines the <see cref="Attribute"/>s for common visible elements in a <see cref="View"/>. 
 /// Defines the <see cref="Attribute"/>s for common visible elements in a <see cref="View"/>. 
 /// Containers such as <see cref="Window"/> and <see cref="FrameView"/> use <see cref="ColorScheme"/> to determine
 /// Containers such as <see cref="Window"/> and <see cref="FrameView"/> use <see cref="ColorScheme"/> to determine
@@ -899,25 +957,19 @@ public class ColorScheme : IEquatable<ColorScheme> {
 	/// </summary>
 	/// </summary>
 	/// <param name="obj"></param>
 	/// <param name="obj"></param>
 	/// <returns>true if the two objects are equal</returns>
 	/// <returns>true if the two objects are equal</returns>
-	public override bool Equals (object obj)
-	{
-		return Equals (obj as ColorScheme);
-	}
+	public override bool Equals (object obj) => Equals (obj as ColorScheme);
 
 
 	/// <summary>
 	/// <summary>
 	/// Compares two <see cref="ColorScheme"/> objects for equality.
 	/// Compares two <see cref="ColorScheme"/> objects for equality.
 	/// </summary>
 	/// </summary>
 	/// <param name="other"></param>
 	/// <param name="other"></param>
 	/// <returns>true if the two objects are equal</returns>
 	/// <returns>true if the two objects are equal</returns>
-	public bool Equals (ColorScheme other)
-	{
-		return other != null &&
-	       EqualityComparer<Attribute>.Default.Equals (_normal, other._normal) &&
-	       EqualityComparer<Attribute>.Default.Equals (_focus, other._focus) &&
-	       EqualityComparer<Attribute>.Default.Equals (_hotNormal, other._hotNormal) &&
-	       EqualityComparer<Attribute>.Default.Equals (_hotFocus, other._hotFocus) &&
-	       EqualityComparer<Attribute>.Default.Equals (_disabled, other._disabled);
-	}
+	public bool Equals (ColorScheme other) => other != null &&
+						EqualityComparer<Attribute>.Default.Equals (_normal, other._normal) &&
+						EqualityComparer<Attribute>.Default.Equals (_focus, other._focus) &&
+						EqualityComparer<Attribute>.Default.Equals (_hotNormal, other._hotNormal) &&
+						EqualityComparer<Attribute>.Default.Equals (_hotFocus, other._hotFocus) &&
+						EqualityComparer<Attribute>.Default.Equals (_disabled, other._disabled);
 
 
 	/// <summary>
 	/// <summary>
 	/// Returns a hashcode for this instance.
 	/// Returns a hashcode for this instance.
@@ -940,10 +992,7 @@ public class ColorScheme : IEquatable<ColorScheme> {
 	/// <param name="left"></param>
 	/// <param name="left"></param>
 	/// <param name="right"></param>
 	/// <param name="right"></param>
 	/// <returns><c>true</c> if the two objects are equivalent</returns>
 	/// <returns><c>true</c> if the two objects are equivalent</returns>
-	public static bool operator == (ColorScheme left, ColorScheme right)
-	{
-		return EqualityComparer<ColorScheme>.Default.Equals (left, right);
-	}
+	public static bool operator == (ColorScheme left, ColorScheme right) => EqualityComparer<ColorScheme>.Default.Equals (left, right);
 
 
 	/// <summary>
 	/// <summary>
 	/// Compares two <see cref="ColorScheme"/> objects for inequality.
 	/// Compares two <see cref="ColorScheme"/> objects for inequality.
@@ -951,12 +1000,8 @@ public class ColorScheme : IEquatable<ColorScheme> {
 	/// <param name="left"></param>
 	/// <param name="left"></param>
 	/// <param name="right"></param>
 	/// <param name="right"></param>
 	/// <returns><c>true</c> if the two objects are not equivalent</returns>
 	/// <returns><c>true</c> if the two objects are not equivalent</returns>
-	public static bool operator != (ColorScheme left, ColorScheme right)
-	{
-		return !(left == right);
-	}
+	public static bool operator != (ColorScheme left, ColorScheme right) => !(left == right);
 }
 }
-
 /// <summary>
 /// <summary>
 /// The default <see cref="ColorScheme"/>s for the application.
 /// The default <see cref="ColorScheme"/>s for the application.
 /// </summary>
 /// </summary>
@@ -964,7 +1009,7 @@ public class ColorScheme : IEquatable<ColorScheme> {
 /// This property can be set in a Theme to change the default <see cref="Colors"/> for the application.
 /// This property can be set in a Theme to change the default <see cref="Colors"/> for the application.
 /// </remarks>
 /// </remarks>
 public static class Colors {
 public static class Colors {
-	private class SchemeNameComparerIgnoreCase : IEqualityComparer<string> {
+	class SchemeNameComparerIgnoreCase : IEqualityComparer<string> {
 		public bool Equals (string x, string y)
 		public bool Equals (string x, string y)
 		{
 		{
 			if (x != null && y != null) {
 			if (x != null && y != null) {
@@ -973,29 +1018,21 @@ public static class Colors {
 			return false;
 			return false;
 		}
 		}
 
 
-		public int GetHashCode (string obj)
-		{
-			return obj.ToLowerInvariant ().GetHashCode ();
-		}
+		public int GetHashCode (string obj) => obj.ToLowerInvariant ().GetHashCode ();
 	}
 	}
 
 
-	static Colors ()
-	{
-		ColorSchemes = Create ();
-	}
+	static Colors () => ColorSchemes = Create ();
 
 
 	/// <summary>
 	/// <summary>
 	/// Creates a new dictionary of new <see cref="ColorScheme"/> objects.
 	/// Creates a new dictionary of new <see cref="ColorScheme"/> objects.
 	/// </summary>
 	/// </summary>
-	public static Dictionary<string, ColorScheme> Create ()
-	{
+	public static Dictionary<string, ColorScheme> Create () =>
 		// Use reflection to dynamically create the default set of ColorSchemes from the list defined 
 		// Use reflection to dynamically create the default set of ColorSchemes from the list defined 
 		// by the class. 
 		// by the class. 
-		return typeof (Colors).GetProperties ()
-			.Where (p => p.PropertyType == typeof (ColorScheme))
-			.Select (p => new KeyValuePair<string, ColorScheme> (p.Name, new ColorScheme ()))
-			.ToDictionary (t => t.Key, t => t.Value, comparer: new SchemeNameComparerIgnoreCase ());
-	}
+		typeof (Colors).GetProperties ()
+				.Where (p => p.PropertyType == typeof (ColorScheme))
+				.Select (p => new KeyValuePair<string, ColorScheme> (p.Name, new ColorScheme ()))
+				.ToDictionary (t => t.Key, t => t.Value, new SchemeNameComparerIgnoreCase ());
 
 
 	/// <summary>
 	/// <summary>
 	/// The application Toplevel color scheme, for the default Toplevel views.
 	/// The application Toplevel color scheme, for the default Toplevel views.
@@ -1047,10 +1084,7 @@ public static class Colors {
 	/// </remarks>
 	/// </remarks>
 	public static ColorScheme Error { get => GetColorScheme (); set => SetColorScheme (value); }
 	public static ColorScheme Error { get => GetColorScheme (); set => SetColorScheme (value); }
 
 
-	static ColorScheme GetColorScheme ([CallerMemberName] string schemeBeingSet = null)
-	{
-		return ColorSchemes [schemeBeingSet];
-	}
+	static ColorScheme GetColorScheme ([CallerMemberName] string schemeBeingSet = null) => ColorSchemes [schemeBeingSet];
 
 
 	static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string schemeBeingSet = null)
 	static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string schemeBeingSet = null)
 	{
 	{
@@ -1064,4 +1098,4 @@ public static class Colors {
 	[SerializableConfigurationProperty (Scope = typeof (ThemeScope), OmitClassName = true)]
 	[SerializableConfigurationProperty (Scope = typeof (ThemeScope), OmitClassName = true)]
 	[JsonConverter (typeof (DictionaryJsonConverter<ColorScheme>))]
 	[JsonConverter (typeof (DictionaryJsonConverter<ColorScheme>))]
 	public static Dictionary<string, ColorScheme> ColorSchemes { get; private set; }
 	public static Dictionary<string, ColorScheme> ColorSchemes { get; private set; }
-}
+}

+ 844 - 842
Terminal.Gui/Views/Toplevel.cs

@@ -3,238 +3,252 @@ using System.Collections.Generic;
 using System.ComponentModel;
 using System.ComponentModel;
 using System.Linq;
 using System.Linq;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui; 
+
+/// <summary>
+/// Toplevel views can be modally executed. They are used for both an application's main view (filling the entire screeN and
+/// for pop-up views such as <see cref="Dialog"/>, <see cref="MessageBox"/>, and <see cref="Wizard"/>.
+/// </summary>
+/// <remarks>
+///   <para>
+///     Toplevels can be modally executing views, started by calling <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>. 
+///     They return control to the caller when <see cref="Application.RequestStop(Toplevel)"/> has 
+///     been called (which sets the <see cref="Toplevel.Running"/> property to <c>false</c>). 
+///   </para>
+///   <para>
+///     A Toplevel is created when an application initializes Terminal.Gui by calling <see cref="Application.Init"/>.
+///     The application Toplevel can be accessed via <see cref="Application.Top"/>. Additional Toplevels can be created 
+///     and run (e.g. <see cref="Dialog"/>s. To run a Toplevel, create the <see cref="Toplevel"/> and 
+///     call <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>.
+///   </para>
+/// </remarks>
+public partial class Toplevel : View {
 	/// <summary>
 	/// <summary>
-	/// Toplevel views can be modally executed. They are used for both an application's main view (filling the entire screeN and
-	/// for pop-up views such as <see cref="Dialog"/>, <see cref="MessageBox"/>, and <see cref="Wizard"/>.
+	/// Gets or sets whether the main loop for this <see cref="Toplevel"/> is running or not. 
 	/// </summary>
 	/// </summary>
 	/// <remarks>
 	/// <remarks>
-	///   <para>
-	///     Toplevels can be modally executing views, started by calling <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>. 
-	///     They return control to the caller when <see cref="Application.RequestStop(Toplevel)"/> has 
-	///     been called (which sets the <see cref="Toplevel.Running"/> property to <c>false</c>). 
-	///   </para>
-	///   <para>
-	///     A Toplevel is created when an application initializes Terminal.Gui by calling <see cref="Application.Init(ConsoleDriver)"/>.
-	///     The application Toplevel can be accessed via <see cref="Application.Top"/>. Additional Toplevels can be created 
-	///     and run (e.g. <see cref="Dialog"/>s. To run a Toplevel, create the <see cref="Toplevel"/> and 
-	///     call <see cref="Application.Run(Toplevel, Func{Exception, bool})"/>.
-	///   </para>
+	///    Setting this property directly is discouraged. Use <see cref="Application.RequestStop"/> instead. 
 	/// </remarks>
 	/// </remarks>
-	public partial class Toplevel : View {
-		/// <summary>
-		/// Gets or sets whether the main loop for this <see cref="Toplevel"/> is running or not. 
-		/// </summary>
-		/// <remarks>
-		///    Setting this property directly is discouraged. Use <see cref="Application.RequestStop"/> instead. 
-		/// </remarks>
-		public bool Running { get; set; }
-
-		/// <summary>
-		/// Invoked when the <see cref="Toplevel"/> <see cref="RunState"/> has begun to be loaded.
-		/// A Loaded event handler is a good place to finalize initialization before calling 
-		/// <see cref="Application.RunLoop(RunState)"/>.
-		/// </summary>
-		public event EventHandler Loaded;
-
-		/// <summary>
-		/// Invoked when the <see cref="Toplevel"/> main loop has started it's first iteration.
-		/// Subscribe to this event to perform tasks when the <see cref="Toplevel"/> has been laid out and focus has been set.
-		/// changes. 
-		/// <para>A Ready event handler is a good place to finalize initialization after calling 
-		/// <see cref="Application.Run(Func{Exception, bool})"/> on this <see cref="Toplevel"/>.</para>
-		/// </summary>
-		public event EventHandler Ready;
-
-		/// <summary>
-		/// Invoked when the Toplevel <see cref="RunState"/> has been unloaded.
-		/// A Unloaded event handler is a good place to dispose objects after calling <see cref="Application.End(RunState)"/>.
-		/// </summary>
-		public event EventHandler Unloaded;
-
-		/// <summary>
-		/// Invoked when the Toplevel <see cref="RunState"/> becomes the <see cref="Application.Current"/> Toplevel.
-		/// </summary>
-		public event EventHandler<ToplevelEventArgs> Activate;
-
-		/// <summary>
-		/// Invoked when the Toplevel<see cref="RunState"/> ceases to be the <see cref="Application.Current"/> Toplevel.
-		/// </summary>
-		public event EventHandler<ToplevelEventArgs> Deactivate;
-
-		/// <summary>
-		/// Invoked when a child of the Toplevel <see cref="RunState"/> is closed by  
-		/// <see cref="Application.End(RunState)"/>.
-		/// </summary>
-		public event EventHandler<ToplevelEventArgs> ChildClosed;
-
-		/// <summary>
-		/// Invoked when the last child of the Toplevel <see cref="RunState"/> is closed from 
-		/// by <see cref="Application.End(RunState)"/>.
-		/// </summary>
-		public event EventHandler AllChildClosed;
-
-		/// <summary>
-		/// Invoked when the Toplevel's <see cref="RunState"/> is being closed by  
-		/// <see cref="Application.RequestStop(Toplevel)"/>.
-		/// </summary>
-		public event EventHandler<ToplevelClosingEventArgs> Closing;
-
-		/// <summary>
-		/// Invoked when the Toplevel's <see cref="RunState"/> is closed by <see cref="Application.End(RunState)"/>.
-		/// </summary>
-		public event EventHandler<ToplevelEventArgs> Closed;
-
-		/// <summary>
-		/// Invoked when a child Toplevel's <see cref="RunState"/> has been loaded.
-		/// </summary>
-		public event EventHandler<ToplevelEventArgs> ChildLoaded;
-
-		/// <summary>
-		/// Invoked when a cjhild Toplevel's <see cref="RunState"/> has been unloaded.
-		/// </summary>
-		public event EventHandler<ToplevelEventArgs> ChildUnloaded;
-
-		/// <summary>
-		/// Invoked when the terminal has been resized. The new <see cref="Size"/> of the terminal is provided.
-		/// </summary>
-		public event EventHandler<SizeChangedEventArgs> SizeChanging;
-
-		// TODO: Make cancelable?
-		internal virtual void OnSizeChanging (SizeChangedEventArgs size) => SizeChanging?.Invoke (this, size);
-
-		internal virtual void OnChildUnloaded (Toplevel top) => ChildUnloaded?.Invoke (this, new ToplevelEventArgs (top));
-
-		internal virtual void OnChildLoaded (Toplevel top) => ChildLoaded?.Invoke (this, new ToplevelEventArgs (top));
-
-		internal virtual void OnClosed (Toplevel top) => Closed?.Invoke (this, new ToplevelEventArgs (top));
-
-		internal virtual bool OnClosing (ToplevelClosingEventArgs ev)
-		{
-			Closing?.Invoke (this, ev);
-			return ev.Cancel;
-		}
-
-		internal virtual void OnAllChildClosed () => AllChildClosed?.Invoke (this, EventArgs.Empty);
-
-		internal virtual void OnChildClosed (Toplevel top)
-		{
-			if (IsOverlappedContainer) {
-				SetSubViewNeedsDisplay ();
-			}
-			ChildClosed?.Invoke (this, new ToplevelEventArgs (top));
-		}
+	public bool Running { get; set; }
+
+	/// <summary>
+	/// Invoked when the <see cref="Toplevel"/> <see cref="RunState"/> has begun to be loaded.
+	/// A Loaded event handler is a good place to finalize initialization before calling 
+	/// <see cref="Application.RunLoop(RunState)"/>.
+	/// </summary>
+	public event EventHandler Loaded;
+
+	/// <summary>
+	/// Invoked when the <see cref="Toplevel"/> main loop has started it's first iteration.
+	/// Subscribe to this event to perform tasks when the <see cref="Toplevel"/> has been laid out and focus has been set.
+	/// changes. 
+	/// <para>A Ready event handler is a good place to finalize initialization after calling 
+	/// <see cref="Application.Run(Func{Exception, bool})"/> on this <see cref="Toplevel"/>.</para>
+	/// </summary>
+	public event EventHandler Ready;
+
+	/// <summary>
+	/// Invoked when the Toplevel <see cref="RunState"/> has been unloaded.
+	/// A Unloaded event handler is a good place to dispose objects after calling <see cref="Application.End(RunState)"/>.
+	/// </summary>
+	public event EventHandler Unloaded;
+
+	/// <summary>
+	/// Invoked when the Toplevel <see cref="RunState"/> becomes the <see cref="Application.Current"/> Toplevel.
+	/// </summary>
+	public event EventHandler<ToplevelEventArgs> Activate;
+
+	/// <summary>
+	/// Invoked when the Toplevel<see cref="RunState"/> ceases to be the <see cref="Application.Current"/> Toplevel.
+	/// </summary>
+	public event EventHandler<ToplevelEventArgs> Deactivate;
 
 
-		internal virtual void OnDeactivate (Toplevel activated)
-		{
-			Deactivate?.Invoke (this, new ToplevelEventArgs (activated));
+	/// <summary>
+	/// Invoked when a child of the Toplevel <see cref="RunState"/> is closed by  
+	/// <see cref="Application.End(RunState)"/>.
+	/// </summary>
+	public event EventHandler<ToplevelEventArgs> ChildClosed;
+
+	/// <summary>
+	/// Invoked when the last child of the Toplevel <see cref="RunState"/> is closed from 
+	/// by <see cref="Application.End(RunState)"/>.
+	/// </summary>
+	public event EventHandler AllChildClosed;
+
+	/// <summary>
+	/// Invoked when the Toplevel's <see cref="RunState"/> is being closed by  
+	/// <see cref="Application.RequestStop(Toplevel)"/>.
+	/// </summary>
+	public event EventHandler<ToplevelClosingEventArgs> Closing;
+
+	/// <summary>
+	/// Invoked when the Toplevel's <see cref="RunState"/> is closed by <see cref="Application.End(RunState)"/>.
+	/// </summary>
+	public event EventHandler<ToplevelEventArgs> Closed;
+
+	/// <summary>
+	/// Invoked when a child Toplevel's <see cref="RunState"/> has been loaded.
+	/// </summary>
+	public event EventHandler<ToplevelEventArgs> ChildLoaded;
+
+	/// <summary>
+	/// Invoked when a cjhild Toplevel's <see cref="RunState"/> has been unloaded.
+	/// </summary>
+	public event EventHandler<ToplevelEventArgs> ChildUnloaded;
+
+	/// <summary>
+	/// Invoked when the terminal has been resized. The new <see cref="Size"/> of the terminal is provided.
+	/// </summary>
+	public event EventHandler<SizeChangedEventArgs> SizeChanging;
+
+	// TODO: Make cancelable?
+	internal virtual void OnSizeChanging (SizeChangedEventArgs size) => SizeChanging?.Invoke (this, size);
+
+	internal virtual void OnChildUnloaded (Toplevel top) => ChildUnloaded?.Invoke (this, new ToplevelEventArgs (top));
+
+	internal virtual void OnChildLoaded (Toplevel top) => ChildLoaded?.Invoke (this, new ToplevelEventArgs (top));
+
+	internal virtual void OnClosed (Toplevel top) => Closed?.Invoke (this, new ToplevelEventArgs (top));
+
+	internal virtual bool OnClosing (ToplevelClosingEventArgs ev)
+	{
+		Closing?.Invoke (this, ev);
+		return ev.Cancel;
+	}
+
+	internal virtual void OnAllChildClosed () => AllChildClosed?.Invoke (this, EventArgs.Empty);
+
+	internal virtual void OnChildClosed (Toplevel top)
+	{
+		if (IsOverlappedContainer) {
+			SetSubViewNeedsDisplay ();
 		}
 		}
+		ChildClosed?.Invoke (this, new ToplevelEventArgs (top));
+	}
+
+	internal virtual void OnDeactivate (Toplevel activated) => Deactivate?.Invoke (this, new ToplevelEventArgs (activated));
 
 
-		internal virtual void OnActivate (Toplevel deactivated)
-		{
-			Activate?.Invoke (this, new ToplevelEventArgs (deactivated));
+	internal virtual void OnActivate (Toplevel deactivated) => Activate?.Invoke (this, new ToplevelEventArgs (deactivated));
+
+	/// <summary>
+	/// Called from <see cref="Application.Begin(Toplevel)"/> before the <see cref="Toplevel"/> redraws for the first time. 
+	/// </summary>
+	public virtual void OnLoaded ()
+	{
+		IsLoaded = true;
+		foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
+			tl.OnLoaded ();
 		}
 		}
+		Loaded?.Invoke (this, EventArgs.Empty);
+	}
 
 
-		/// <summary>
-		/// Called from <see cref="Application.Begin(Toplevel)"/> before the <see cref="Toplevel"/> redraws for the first time. 
-		/// </summary>
-		public virtual void OnLoaded ()
-		{
-			IsLoaded = true;
-			foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
-				tl.OnLoaded ();
-			}
-			Loaded?.Invoke (this, EventArgs.Empty);
+	/// <summary>
+	/// Called from <see cref="Application.RunLoop"/> after the <see cref="Toplevel"/> has entered the 
+	/// first iteration of the loop.
+	/// </summary>
+	internal virtual void OnReady ()
+	{
+		foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
+			tl.OnReady ();
 		}
 		}
+		Ready?.Invoke (this, EventArgs.Empty);
+	}
 
 
-		/// <summary>
-		/// Called from <see cref="Application.RunLoop"/> after the <see cref="Toplevel"/> has entered the 
-		/// first iteration of the loop.
-		/// </summary>
-		internal virtual void OnReady ()
-		{
-			foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
-				tl.OnReady ();
-			}
-			Ready?.Invoke (this, EventArgs.Empty);
+	/// <summary>
+	/// Called from <see cref="Application.End(RunState)"/> before the <see cref="Toplevel"/> is disposed.
+	/// </summary>
+	internal virtual void OnUnloaded ()
+	{
+		foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
+			tl.OnUnloaded ();
 		}
 		}
+		Unloaded?.Invoke (this, EventArgs.Empty);
+	}
+
+	/// <summary>
+	/// Initializes a new instance of the <see cref="Toplevel"/> class with the specified <see cref="LayoutStyle.Absolute"/> layout.
+	/// </summary>
+	/// <param name="frame">A Superview-relative rectangle specifying the location and size for the new Toplevel</param>
+	public Toplevel (Rect frame) : base (frame) => SetInitialProperties ();
 
 
-		/// <summary>
-		/// Called from <see cref="Application.End(RunState)"/> before the <see cref="Toplevel"/> is disposed.
-		/// </summary>
-		internal virtual void OnUnloaded ()
-		{
-			foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
-				tl.OnUnloaded ();
+	/// <summary>
+	/// Initializes a new instance of the <see cref="Toplevel"/> class with <see cref="LayoutStyle.Computed"/> layout, 
+	/// defaulting to full screen.
+	/// </summary>
+	public Toplevel () : base ()
+	{
+		SetInitialProperties ();
+		Width = Dim.Fill ();
+		Height = Dim.Fill ();
+	}
+
+	void SetInitialProperties ()
+	{
+		ColorScheme = Colors.TopLevel;
+
+		Application.GrabbingMouse += Application_GrabbingMouse;
+		Application.UnGrabbingMouse += Application_UnGrabbingMouse;
+
+		// TODO: v2 - ALL Views (Responders??!?!) should support the commands related to 
+		//    - Focus
+		//  Move the appropriate AddCommand calls to `Responder`
+
+		// Things this view knows how to do
+		AddCommand (Command.QuitToplevel, () => {
+			QuitToplevel ();
+			return true;
+		});
+		AddCommand (Command.Suspend, () => {
+			Driver.Suspend ();
+			;
+			return true;
+		});
+		AddCommand (Command.NextView, () => {
+			MoveNextView ();
+			return true;
+		});
+		AddCommand (Command.PreviousView, () => {
+			MovePreviousView ();
+			return true;
+		});
+		AddCommand (Command.NextViewOrTop, () => {
+			MoveNextViewOrTop ();
+			return true;
+		});
+		AddCommand (Command.PreviousViewOrTop, () => {
+			MovePreviousViewOrTop ();
+			return true;
+		});
+		AddCommand (Command.Refresh, () => {
+			Application.Refresh ();
+			return true;
+		});
+		AddCommand (Command.Accept, () => {
+			// TODO: Perhaps all views should support the concept of being default?
+			// TODO: It's bad that Toplevel is tightly coupled with Button
+			if (Subviews.FirstOrDefault (v => v is Button && ((Button)v).IsDefault && ((Button)v).Enabled) is Button defaultBtn) {
+				defaultBtn.InvokeCommand (Command.Accept);
+				return true;
 			}
 			}
-			Unloaded?.Invoke (this, EventArgs.Empty);
-		}
-
-		/// <summary>
-		/// Initializes a new instance of the <see cref="Toplevel"/> class with the specified <see cref="LayoutStyle.Absolute"/> layout.
-		/// </summary>
-		/// <param name="frame">A Superview-relative rectangle specifying the location and size for the new Toplevel</param>
-		public Toplevel (Rect frame) : base (frame)
-		{
-			SetInitialProperties ();
-		}
-
-		/// <summary>
-		/// Initializes a new instance of the <see cref="Toplevel"/> class with <see cref="LayoutStyle.Computed"/> layout, 
-		/// defaulting to full screen.
-		/// </summary>
-		public Toplevel () : base ()
-		{
-			SetInitialProperties ();
-			Width = Dim.Fill ();
-			Height = Dim.Fill ();
-		}
-
-		void SetInitialProperties ()
-		{
-			ColorScheme = Colors.TopLevel;
-
-			Application.GrabbingMouse += Application_GrabbingMouse;
-			Application.UnGrabbingMouse += Application_UnGrabbingMouse;
-
-			// TODO: v2 - ALL Views (Responders??!?!) should support the commands related to 
-			//    - Focus
-			//  Move the appropriate AddCommand calls to `Responder`
-
-			// Things this view knows how to do
-			AddCommand (Command.QuitToplevel, () => { QuitToplevel (); return true; });
-			AddCommand (Command.Suspend, () => { Driver.Suspend (); ; return true; });
-			AddCommand (Command.NextView, () => { MoveNextView (); return true; });
-			AddCommand (Command.PreviousView, () => { MovePreviousView (); return true; });
-			AddCommand (Command.NextViewOrTop, () => { MoveNextViewOrTop (); return true; });
-			AddCommand (Command.PreviousViewOrTop, () => { MovePreviousViewOrTop (); return true; });
-			AddCommand (Command.Refresh, () => { Application.Refresh (); return true; });
-			AddCommand (Command.Accept, () => {
-				// TODO: Perhaps all views should support the concept of being default?
-				// TODO: It's bad that Toplevel is tightly coupled with Button
-				if (Subviews.FirstOrDefault(v => v is Button && ((Button)v).IsDefault && ((Button)v).Enabled) is Button defaultBtn) {
-					defaultBtn.InvokeCommand (Command.Accept);
-					return true;
-				}
-				return false;
-			});
+			return false;
+		});
 
 
-			// Default keybindings for this view
-			KeyBindings.Add ((KeyCode)Application.QuitKey, Command.QuitToplevel);
+		// Default keybindings for this view
+		KeyBindings.Add ((KeyCode)Application.QuitKey, Command.QuitToplevel);
 
 
-			KeyBindings.Add (KeyCode.CursorRight, Command.NextView);
-			KeyBindings.Add (KeyCode.CursorDown, Command.NextView);
-			KeyBindings.Add (KeyCode.CursorLeft, Command.PreviousView);
-			KeyBindings.Add (KeyCode.CursorUp, Command.PreviousView);
+		KeyBindings.Add (KeyCode.CursorRight, Command.NextView);
+		KeyBindings.Add (KeyCode.CursorDown, Command.NextView);
+		KeyBindings.Add (KeyCode.CursorLeft, Command.PreviousView);
+		KeyBindings.Add (KeyCode.CursorUp, Command.PreviousView);
 
 
-			KeyBindings.Add (KeyCode.Tab, Command.NextView);
-			KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask, Command.PreviousView);
-			KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask, Command.NextViewOrTop);
-			KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask | KeyCode.CtrlMask, Command.PreviousViewOrTop);
+		KeyBindings.Add (KeyCode.Tab, Command.NextView);
+		KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask, Command.PreviousView);
+		KeyBindings.Add (KeyCode.Tab | KeyCode.CtrlMask, Command.NextViewOrTop);
+		KeyBindings.Add (KeyCode.Tab | KeyCode.ShiftMask | KeyCode.CtrlMask, Command.PreviousViewOrTop);
 
 
-			KeyBindings.Add (KeyCode.F5, Command.Refresh);
-			KeyBindings.Add ((KeyCode)Application.AlternateForwardKey, Command.NextViewOrTop); // Needed on Unix
-			KeyBindings.Add ((KeyCode)Application.AlternateBackwardKey, Command.PreviousViewOrTop); // Needed on Unix
+		KeyBindings.Add (KeyCode.F5, Command.Refresh);
+		KeyBindings.Add ((KeyCode)Application.AlternateForwardKey, Command.NextViewOrTop); // Needed on Unix
+		KeyBindings.Add ((KeyCode)Application.AlternateBackwardKey, Command.PreviousViewOrTop); // Needed on Unix
 
 
 #if UNIX_KEY_BINDINGS
 #if UNIX_KEY_BINDINGS
 			KeyBindings.Add (Key.Z | Key.CtrlMask, Command.Suspend);
 			KeyBindings.Add (Key.Z | Key.CtrlMask, Command.Suspend);
@@ -243,726 +257,714 @@ namespace Terminal.Gui {
 			KeyBindings.Add (Key.I | Key.CtrlMask, Command.NextView); // Unix
 			KeyBindings.Add (Key.I | Key.CtrlMask, Command.NextView); // Unix
 			KeyBindings.Add (Key.B | Key.CtrlMask, Command.PreviousView);// Unix
 			KeyBindings.Add (Key.B | Key.CtrlMask, Command.PreviousView);// Unix
 #endif
 #endif
-			// This enables the default button to be activated by the Enter key.
-			KeyBindings.Add (KeyCode.Enter, Command.Accept);
-		}
+		// This enables the default button to be activated by the Enter key.
+		KeyBindings.Add (KeyCode.Enter, Command.Accept);
+	}
 
 
-		private void Application_UnGrabbingMouse (object sender, GrabMouseEventArgs e)
-		{
-			if (Application.MouseGrabView == this && _dragPosition.HasValue) {
-				e.Cancel = true;
-			}
+	void Application_UnGrabbingMouse (object sender, GrabMouseEventArgs e)
+	{
+		if (Application.MouseGrabView == this && _dragPosition.HasValue) {
+			e.Cancel = true;
 		}
 		}
+	}
 
 
-		private void Application_GrabbingMouse (object sender, GrabMouseEventArgs e)
-		{
-			if (Application.MouseGrabView == this && _dragPosition.HasValue) {
-				e.Cancel = true;
-			}
+	void Application_GrabbingMouse (object sender, GrabMouseEventArgs e)
+	{
+		if (Application.MouseGrabView == this && _dragPosition.HasValue) {
+			e.Cancel = true;
 		}
 		}
+	}
+
+	/// <summary>
+	/// Invoked when the <see cref="Application.AlternateForwardKey"/> is changed.
+	/// </summary>
+	public event EventHandler<KeyChangedEventArgs> AlternateForwardKeyChanged;
+
+	/// <summary>
+	/// Virtual method to invoke the <see cref="AlternateForwardKeyChanged"/> event.
+	/// </summary>
+	/// <param name="e"></param>
+	public virtual void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
+	{
+		KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
+		AlternateForwardKeyChanged?.Invoke (this, e);
+	}
+
+	/// <summary>
+	/// Invoked when the <see cref="Application.AlternateBackwardKey"/> is changed.
+	/// </summary>
+	public event EventHandler<KeyChangedEventArgs> AlternateBackwardKeyChanged;
+
+	/// <summary>
+	/// Virtual method to invoke the <see cref="AlternateBackwardKeyChanged"/> event.
+	/// </summary>
+	/// <param name="e"></param>
+	public virtual void OnAlternateBackwardKeyChanged (KeyChangedEventArgs e)
+	{
+		KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
+		AlternateBackwardKeyChanged?.Invoke (this, e);
+	}
+
+	/// <summary>
+	/// Invoked when the <see cref="Application.QuitKey"/> is changed.
+	/// </summary>
+	public event EventHandler<KeyChangedEventArgs> QuitKeyChanged;
+
+	/// <summary>
+	/// Virtual method to invoke the <see cref="QuitKeyChanged"/> event.
+	/// </summary>
+	/// <param name="e"></param>
+	public virtual void OnQuitKeyChanged (KeyChangedEventArgs e)
+	{
+		KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
+		QuitKeyChanged?.Invoke (this, e);
+	}
+
+	/// <summary>
+	/// Convenience factory method that creates a new Toplevel with the current terminal dimensions.
+	/// </summary>
+	/// <returns>The created Toplevel.</returns>
+	public static Toplevel Create () => new Toplevel (new Rect (0, 0, Driver.Cols, Driver.Rows));
+
+	/// <summary>
+	/// Gets or sets a value indicating whether this <see cref="Toplevel"/> can focus.
+	/// </summary>
+	/// <value><c>true</c> if can focus; otherwise, <c>false</c>.</value>
+	public override bool CanFocus => SuperView == null ? true : base.CanFocus;
+
+	/// <summary>
+	/// Determines whether the <see cref="Toplevel"/> is modal or not. 
+	/// If set to <c>false</c> (the default):
+	/// 
+	/// <list type="bullet">
+	///   <item>
+	///		<description><see cref="View.OnKeyDown"/> events will propagate keys upwards.</description>
+	///   </item>
+	///   <item>
+	///		<description>The Toplevel will act as an embedded view (not a modal/pop-up).</description>
+	///   </item>
+	/// </list>
+	///
+	/// If set to <c>true</c>:
+	/// 
+	/// <list type="bullet">
+	///   <item>
+	///		<description><see cref="View.OnKeyDown"/> events will NOT propagate keys upwards.</description>
+	///	  </item>
+	///   <item>
+	///		<description>The Toplevel will and look like a modal (pop-up) (e.g. see <see cref="Dialog"/>.</description>
+	///   </item>
+	/// </list>
+	/// </summary>
+	public bool Modal { get; set; }
 
 
-		/// <summary>
-		/// Invoked when the <see cref="Application.AlternateForwardKey"/> is changed.
-		/// </summary>
-		public event EventHandler<KeyChangedEventArgs> AlternateForwardKeyChanged;
-
-		/// <summary>
-		/// Virtual method to invoke the <see cref="AlternateForwardKeyChanged"/> event.
-		/// </summary>
-		/// <param name="e"></param>
-		public virtual void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
-		{
-			KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
-			AlternateForwardKeyChanged?.Invoke (this, e);
-		}
-
-		/// <summary>
-		/// Invoked when the <see cref="Application.AlternateBackwardKey"/> is changed.
-		/// </summary>
-		public event EventHandler<KeyChangedEventArgs> AlternateBackwardKeyChanged;
-
-		/// <summary>
-		/// Virtual method to invoke the <see cref="AlternateBackwardKeyChanged"/> event.
-		/// </summary>
-		/// <param name="e"></param>
-		public virtual void OnAlternateBackwardKeyChanged (KeyChangedEventArgs e)
-		{
-			KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
-			AlternateBackwardKeyChanged?.Invoke (this, e);
-		}
-
-		/// <summary>
-		/// Invoked when the <see cref="Application.QuitKey"/> is changed.
-		/// </summary>
-		public event EventHandler<KeyChangedEventArgs> QuitKeyChanged;
-
-		/// <summary>
-		/// Virtual method to invoke the <see cref="QuitKeyChanged"/> event.
-		/// </summary>
-		/// <param name="e"></param>
-		public virtual void OnQuitKeyChanged (KeyChangedEventArgs e)
-		{
-			KeyBindings.Replace ((KeyCode)e.OldKey, (KeyCode)e.NewKey);
-			QuitKeyChanged?.Invoke (this, e);
-		}
-
-		/// <summary>
-		/// Convenience factory method that creates a new Toplevel with the current terminal dimensions.
-		/// </summary>
-		/// <returns>The created Toplevel.</returns>
-		public static Toplevel Create ()
-		{
-			return new Toplevel (new Rect (0, 0, Driver.Cols, Driver.Rows));
-		}
-
-		/// <summary>
-		/// Gets or sets a value indicating whether this <see cref="Toplevel"/> can focus.
-		/// </summary>
-		/// <value><c>true</c> if can focus; otherwise, <c>false</c>.</value>
-		public override bool CanFocus {
-			get => SuperView == null ? true : base.CanFocus;
-		}
-
-		/// <summary>
-		/// Determines whether the <see cref="Toplevel"/> is modal or not. 
-		/// If set to <c>false</c> (the default):
-		/// 
-		/// <list type="bullet">
-		///   <item>
-		///		<description><see cref="View.OnKeyDown"/> events will propagate keys upwards.</description>
-		///   </item>
-		///   <item>
-		///		<description>The Toplevel will act as an embedded view (not a modal/pop-up).</description>
-		///   </item>
-		/// </list>
-		///
-		/// If set to <c>true</c>:
-		/// 
-		/// <list type="bullet">
-		///   <item>
-		///		<description><see cref="View.OnKeyDown"/> events will NOT propagate keys upwards.</description>
-		///	  </item>
-		///   <item>
-		///		<description>The Toplevel will and look like a modal (pop-up) (e.g. see <see cref="Dialog"/>.</description>
-		///   </item>
-		/// </list>
-		/// </summary>
-		public bool Modal { get; set; }
-
-		/// <summary>
-		/// Gets or sets the menu for this Toplevel.
-		/// </summary>
-		public virtual MenuBar MenuBar { get; set; }
-
-		/// <summary>
-		/// Gets or sets the status bar for this Toplevel.
-		/// </summary>
-		public virtual StatusBar StatusBar { get; set; }
-
-		/// <summary>
-		/// <see langword="true"/> if was already loaded by the <see cref="Application.Begin(Toplevel)"/>
-		/// <see langword="false"/>, otherwise.
-		/// </summary>
-		public bool IsLoaded { get; private set; }
-
-		private void MovePreviousViewOrTop ()
-		{
-			if (Application.OverlappedTop == null) {
-				var top = Modal ? this : Application.Top;
+	/// <summary>
+	/// Gets or sets the menu for this Toplevel.
+	/// </summary>
+	public virtual MenuBar MenuBar { get; set; }
+
+	/// <summary>
+	/// Gets or sets the status bar for this Toplevel.
+	/// </summary>
+	public virtual StatusBar StatusBar { get; set; }
+
+	/// <summary>
+	/// <see langword="true"/> if was already loaded by the <see cref="Application.Begin(Toplevel)"/>
+	/// <see langword="false"/>, otherwise.
+	/// </summary>
+	public bool IsLoaded { get; private set; }
+
+	void MovePreviousViewOrTop ()
+	{
+		if (Application.OverlappedTop == null) {
+			var top = Modal ? this : Application.Top;
+			top.FocusPrev ();
+			if (top.Focused == null) {
 				top.FocusPrev ();
 				top.FocusPrev ();
-				if (top.Focused == null) {
-					top.FocusPrev ();
-				}
-				top.SetNeedsDisplay ();
-				Application.BringOverlappedTopToFront ();
-			} else {
-				Application.OverlappedMovePrevious ();
 			}
 			}
+			top.SetNeedsDisplay ();
+			Application.BringOverlappedTopToFront ();
+		} else {
+			Application.OverlappedMovePrevious ();
 		}
 		}
+	}
 
 
-		private void MoveNextViewOrTop ()
-		{
-			if (Application.OverlappedTop == null) {
-				var top = Modal ? this : Application.Top;
+	void MoveNextViewOrTop ()
+	{
+		if (Application.OverlappedTop == null) {
+			var top = Modal ? this : Application.Top;
+			top.FocusNext ();
+			if (top.Focused == null) {
 				top.FocusNext ();
 				top.FocusNext ();
-				if (top.Focused == null) {
-					top.FocusNext ();
-				}
-				top.SetNeedsDisplay ();
-				Application.BringOverlappedTopToFront ();
-			} else {
-				Application.OverlappedMoveNext ();
 			}
 			}
+			top.SetNeedsDisplay ();
+			Application.BringOverlappedTopToFront ();
+		} else {
+			Application.OverlappedMoveNext ();
 		}
 		}
+	}
 
 
-		private void MovePreviousView ()
-		{
-			var old = GetDeepestFocusedSubview (Focused);
-			if (!FocusPrev ())
-				FocusPrev ();
-			if (old != Focused && old != Focused?.Focused) {
-				old?.SetNeedsDisplay ();
-				Focused?.SetNeedsDisplay ();
-			} else {
-				FocusNearestView (SuperView?.TabIndexes?.Reverse (), Direction.Backward);
-			}
+	void MovePreviousView ()
+	{
+		var old = GetDeepestFocusedSubview (Focused);
+		if (!FocusPrev ()) {
+			FocusPrev ();
+		}
+		if (old != Focused && old != Focused?.Focused) {
+			old?.SetNeedsDisplay ();
+			Focused?.SetNeedsDisplay ();
+		} else {
+			FocusNearestView (SuperView?.TabIndexes?.Reverse (), Direction.Backward);
 		}
 		}
+	}
 
 
-		private void MoveNextView ()
-		{
-			var old = GetDeepestFocusedSubview (Focused);
-			if (!FocusNext ())
-				FocusNext ();
-			if (old != Focused && old != Focused?.Focused) {
-				old?.SetNeedsDisplay ();
-				Focused?.SetNeedsDisplay ();
-			} else {
-				FocusNearestView (SuperView?.TabIndexes, Direction.Forward);
-			}
+	void MoveNextView ()
+	{
+		var old = GetDeepestFocusedSubview (Focused);
+		if (!FocusNext ()) {
+			FocusNext ();
 		}
 		}
+		if (old != Focused && old != Focused?.Focused) {
+			old?.SetNeedsDisplay ();
+			Focused?.SetNeedsDisplay ();
+		} else {
+			FocusNearestView (SuperView?.TabIndexes, Direction.Forward);
+		}
+	}
 
 
-		private void QuitToplevel ()
-		{
-			if (Application.OverlappedTop != null) {
-				Application.OverlappedTop.RequestStop ();
-			} else {
-				Application.RequestStop ();
-			}
+	void QuitToplevel ()
+	{
+		if (Application.OverlappedTop != null) {
+			Application.OverlappedTop.RequestStop ();
+		} else {
+			Application.RequestStop ();
 		}
 		}
+	}
 
 
-		View GetDeepestFocusedSubview (View view)
-		{
-			if (view == null) {
-				return null;
-			}
+	View GetDeepestFocusedSubview (View view)
+	{
+		if (view == null) {
+			return null;
+		}
 
 
-			foreach (var v in view.Subviews) {
-				if (v.HasFocus) {
-					return GetDeepestFocusedSubview (v);
-				}
+		foreach (var v in view.Subviews) {
+			if (v.HasFocus) {
+				return GetDeepestFocusedSubview (v);
 			}
 			}
-			return view;
 		}
 		}
+		return view;
+	}
 
 
-		void FocusNearestView (IEnumerable<View> views, Direction direction)
-		{
-			if (views == null) {
-				return;
-			}
+	void FocusNearestView (IEnumerable<View> views, Direction direction)
+	{
+		if (views == null) {
+			return;
+		}
 
 
-			bool found = false;
-			bool focusProcessed = false;
-			int idx = 0;
+		bool found = false;
+		bool focusProcessed = false;
+		int idx = 0;
 
 
-			foreach (var v in views) {
-				if (v == this) {
-					found = true;
+		foreach (var v in views) {
+			if (v == this) {
+				found = true;
+			}
+			if (found && v != this) {
+				if (direction == Direction.Forward) {
+					SuperView?.FocusNext ();
+				} else {
+					SuperView?.FocusPrev ();
 				}
 				}
-				if (found && v != this) {
-					if (direction == Direction.Forward) {
-						SuperView?.FocusNext ();
-					} else {
-						SuperView?.FocusPrev ();
-					}
-					focusProcessed = true;
-					if (SuperView.Focused != null && SuperView.Focused != this) {
-						return;
-					}
-				} else if (found && !focusProcessed && idx == views.Count () - 1) {
-					views.ToList () [0].SetFocus ();
+				focusProcessed = true;
+				if (SuperView.Focused != null && SuperView.Focused != this) {
+					return;
 				}
 				}
-				idx++;
+			} else if (found && !focusProcessed && idx == views.Count () - 1) {
+				views.ToList () [0].SetFocus ();
 			}
 			}
+			idx++;
 		}
 		}
+	}
 
 
-		///<inheritdoc/>
-		public override void Add (View view)
-		{
-			CanFocus = true;
-			AddMenuStatusBar (view);
-			base.Add (view);
-		}
+	///<inheritdoc/>
+	public override void Add (View view)
+	{
+		CanFocus = true;
+		AddMenuStatusBar (view);
+		base.Add (view);
+	}
 
 
-		internal void AddMenuStatusBar (View view)
-		{
-			if (view is MenuBar) {
-				MenuBar = view as MenuBar;
-			}
-			if (view is StatusBar) {
-				StatusBar = view as StatusBar;
-			}
+	internal void AddMenuStatusBar (View view)
+	{
+		if (view is MenuBar) {
+			MenuBar = view as MenuBar;
 		}
 		}
+		if (view is StatusBar) {
+			StatusBar = view as StatusBar;
+		}
+	}
 
 
-		///<inheritdoc/>
-		public override void Remove (View view)
-		{
-			if (this is Toplevel Toplevel && Toplevel.MenuBar != null) {
-				RemoveMenuStatusBar (view);
-			}
-			base.Remove (view);
+	///<inheritdoc/>
+	public override void Remove (View view)
+	{
+		if (this is Toplevel Toplevel && Toplevel.MenuBar != null) {
+			RemoveMenuStatusBar (view);
 		}
 		}
+		base.Remove (view);
+	}
 
 
-		///<inheritdoc/>
-		public override void RemoveAll ()
-		{
-			if (this == Application.Top) {
-				MenuBar?.Dispose ();
-				MenuBar = null;
-				StatusBar?.Dispose ();
-				StatusBar = null;
-			}
-			base.RemoveAll ();
+	///<inheritdoc/>
+	public override void RemoveAll ()
+	{
+		if (this == Application.Top) {
+			MenuBar?.Dispose ();
+			MenuBar = null;
+			StatusBar?.Dispose ();
+			StatusBar = null;
 		}
 		}
+		base.RemoveAll ();
+	}
 
 
-		internal void RemoveMenuStatusBar (View view)
-		{
-			if (view is MenuBar) {
-				MenuBar?.Dispose ();
-				MenuBar = null;
-			}
-			if (view is StatusBar) {
-				StatusBar?.Dispose ();
-				StatusBar = null;
-			}
+	internal void RemoveMenuStatusBar (View view)
+	{
+		if (view is MenuBar) {
+			MenuBar?.Dispose ();
+			MenuBar = null;
 		}
 		}
+		if (view is StatusBar) {
+			StatusBar?.Dispose ();
+			StatusBar = null;
+		}
+	}
 
 
-		/// <summary>
-		///  Gets a new location of the <see cref="Toplevel"/> that is within the Bounds of the <paramref name="top"/>'s 
-		///  <see cref="View.SuperView"/> (e.g. for dragging a Window).
-		///  The `out` parameters are the new X and Y coordinates.
-		/// </summary>
-		/// <remarks>
-		/// If <paramref name="top"/> does not have a <see cref="View.SuperView"/> or it's SuperView is not <see cref="Application.Top"/>
-		/// the position will be bound by the <see cref="ConsoleDriver.Cols"/> and <see cref="ConsoleDriver.Rows"/>.
-		/// </remarks>
-		/// <param name="top">The Toplevel that is to be moved.</param>
-		/// <param name="targetX">The target x location.</param>
-		/// <param name="targetY">The target y location.</param>
-		/// <param name="nx">The x location that will ensure <paramref name="top"/> will be visible.</param>
-		/// <param name="ny">The y location that will ensure <paramref name="top"/> will be visible.</param>
-		/// <param name="menuBar">The new top most menuBar</param>
-		/// <param name="statusBar">The new top most statusBar</param>
-		/// <returns>
-		///  Either <see cref="Application.Top"/> (if <paramref name="top"/> does not have a Super View) or
-		///  <paramref name="top"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.
-		///  </returns>
-		internal View GetLocationThatFits (Toplevel top, int targetX, int targetY,
+	/// <summary>
+	///  Gets a new location of the <see cref="Toplevel"/> that is within the Bounds of the <paramref name="top"/>'s 
+	///  <see cref="View.SuperView"/> (e.g. for dragging a Window).
+	///  The `out` parameters are the new X and Y coordinates.
+	/// </summary>
+	/// <remarks>
+	/// If <paramref name="top"/> does not have a <see cref="View.SuperView"/> or it's SuperView is not <see cref="Application.Top"/>
+	/// the position will be bound by the <see cref="ConsoleDriver.Cols"/> and <see cref="ConsoleDriver.Rows"/>.
+	/// </remarks>
+	/// <param name="top">The Toplevel that is to be moved.</param>
+	/// <param name="targetX">The target x location.</param>
+	/// <param name="targetY">The target y location.</param>
+	/// <param name="nx">The x location that will ensure <paramref name="top"/> will be visible.</param>
+	/// <param name="ny">The y location that will ensure <paramref name="top"/> will be visible.</param>
+	/// <param name="menuBar">The new top most menuBar</param>
+	/// <param name="statusBar">The new top most statusBar</param>
+	/// <returns>
+	///  Either <see cref="Application.Top"/> (if <paramref name="top"/> does not have a Super View) or
+	///  <paramref name="top"/>'s SuperView. This can be used to ensure LayoutSubviews is called on the correct View.
+	///  </returns>
+	internal View GetLocationThatFits (Toplevel top, int targetX, int targetY,
 					out int nx, out int ny, out MenuBar menuBar, out StatusBar statusBar)
 					out int nx, out int ny, out MenuBar menuBar, out StatusBar statusBar)
-		{
-			int maxWidth;
-			View superView;
-			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
-				maxWidth = Driver.Cols;
-				superView = Application.Top;
-			} else {
-				// Use the SuperView's Bounds, not Frame
-				maxWidth = top.SuperView.Bounds.Width;
-				superView = top.SuperView;
-			}
-			if (superView.Margin != null && superView == top.SuperView) {
-				maxWidth -= superView.GetFramesThickness ().Left + superView.GetFramesThickness ().Right;
-			}
-			if (top.Frame.Width <= maxWidth) {
-				nx = Math.Max (targetX, 0);
-				nx = nx + top.Frame.Width > maxWidth ? Math.Max (maxWidth - top.Frame.Width, 0) : nx;
-				if (nx > top.Frame.X + top.Frame.Width) {
-					nx = Math.Max (top.Frame.Right, 0);
-				}
-			} else {
-				nx = targetX;
-			}
-			//System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
-			bool menuVisible, statusVisible;
-			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
-				menuVisible = Application.Top.MenuBar?.Visible == true;
-				menuBar = Application.Top.MenuBar;
-			} else {
-				var t = top.SuperView;
-				while (t is not Toplevel) {
-					t = t.SuperView;
-				}
-				menuVisible = ((Toplevel)t).MenuBar?.Visible == true;
-				menuBar = ((Toplevel)t).MenuBar;
-			}
-			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
-				maxWidth = menuVisible ? 1 : 0;
-			} else {
-				maxWidth = 0;
-			}
-			ny = Math.Max (targetY, maxWidth);
-			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
-				statusVisible = Application.Top.StatusBar?.Visible == true;
-				statusBar = Application.Top.StatusBar;
-			} else {
-				var t = top.SuperView;
-				while (t is not Toplevel) {
-					t = t.SuperView;
-				}
-				statusVisible = ((Toplevel)t).StatusBar?.Visible == true;
-				statusBar = ((Toplevel)t).StatusBar;
-			}
-			if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
-				maxWidth = statusVisible ? Driver.Rows - 1 : Driver.Rows;
-			} else {
-				maxWidth = statusVisible ? top.SuperView.Frame.Height - 1 : top.SuperView.Frame.Height;
-			}
-			if (superView.Margin != null && superView == top.SuperView) {
-				maxWidth -= superView.GetFramesThickness ().Top + superView.GetFramesThickness ().Bottom;
-			}
-			ny = Math.Min (ny, maxWidth);
-			if (top.Frame.Height <= maxWidth) {
-				ny = ny + top.Frame.Height > maxWidth ? Math.Max (maxWidth - top.Frame.Height, menuVisible ? 1 : 0) : ny;
-				if (ny > top.Frame.Y + top.Frame.Height) {
-					ny = Math.Max (top.Frame.Bottom, 0);
-				}
-			}
-			//System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
-
-			return superView;
-		}
+	{
+		int maxWidth;
+		View superView;
+		if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
+			maxWidth = Driver.Cols;
+			superView = Application.Top;
+		} else {
+			// Use the SuperView's Bounds, not Frame
+			maxWidth = top.SuperView.Bounds.Width;
+			superView = top.SuperView;
+		}
+		if (superView.Margin != null && superView == top.SuperView) {
+			maxWidth -= superView.GetFramesThickness ().Left + superView.GetFramesThickness ().Right;
+		}
+		if (top.Frame.Width <= maxWidth) {
+			nx = Math.Max (targetX, 0);
+			nx = nx + top.Frame.Width > maxWidth ? Math.Max (maxWidth - top.Frame.Width, 0) : nx;
+			if (nx > top.Frame.X + top.Frame.Width) {
+				nx = Math.Max (top.Frame.Right, 0);
+			}
+		} else {
+			nx = targetX;
+		}
+		//System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
+		bool menuVisible, statusVisible;
+		if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
+			menuVisible = Application.Top.MenuBar?.Visible == true;
+			menuBar = Application.Top.MenuBar;
+		} else {
+			var t = top.SuperView;
+			while (t is not Toplevel) {
+				t = t.SuperView;
+			}
+			menuVisible = ((Toplevel)t).MenuBar?.Visible == true;
+			menuBar = ((Toplevel)t).MenuBar;
+		}
+		if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
+			maxWidth = menuVisible ? 1 : 0;
+		} else {
+			maxWidth = 0;
+		}
+		ny = Math.Max (targetY, maxWidth);
+		if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
+			statusVisible = Application.Top.StatusBar?.Visible == true;
+			statusBar = Application.Top.StatusBar;
+		} else {
+			var t = top.SuperView;
+			while (t is not Toplevel) {
+				t = t.SuperView;
+			}
+			statusVisible = ((Toplevel)t).StatusBar?.Visible == true;
+			statusBar = ((Toplevel)t).StatusBar;
+		}
+		if (top?.SuperView == null || top == Application.Top || top?.SuperView == Application.Top) {
+			maxWidth = statusVisible ? Driver.Rows - 1 : Driver.Rows;
+		} else {
+			maxWidth = statusVisible ? top.SuperView.Frame.Height - 1 : top.SuperView.Frame.Height;
+		}
+		if (superView.Margin != null && superView == top.SuperView) {
+			maxWidth -= superView.GetFramesThickness ().Top + superView.GetFramesThickness ().Bottom;
+		}
+		ny = Math.Min (ny, maxWidth);
+		if (top.Frame.Height <= maxWidth) {
+			ny = ny + top.Frame.Height > maxWidth ? Math.Max (maxWidth - top.Frame.Height, menuVisible ? 1 : 0) : ny;
+			if (ny > top.Frame.Y + top.Frame.Height) {
+				ny = Math.Max (top.Frame.Bottom, 0);
+			}
+		}
+		//System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
+
+		return superView;
+	}
 
 
-		// TODO: v2 - Not sure this is needed anymore.
-		internal void PositionToplevels ()
-		{
-			PositionToplevel (this);
-			foreach (var top in Subviews) {
-				if (top is Toplevel) {
-					PositionToplevel ((Toplevel)top);
-				}
+	// TODO: v2 - Not sure this is needed anymore.
+	internal void PositionToplevels ()
+	{
+		PositionToplevel (this);
+		foreach (var top in Subviews) {
+			if (top is Toplevel) {
+				PositionToplevel ((Toplevel)top);
 			}
 			}
 		}
 		}
+	}
 
 
-		/// <summary>
-		/// Adjusts the location and size of <paramref name="top"/> within this Toplevel.
-		/// Virtual method enabling implementation of specific positions for inherited <see cref="Toplevel"/> views.
-		/// </summary>
-		/// <param name="top">The Toplevel to adjust.</param>
-		public virtual void PositionToplevel (Toplevel top)
-		{
-			var superView = GetLocationThatFits (top, top.Frame.X, top.Frame.Y,
-				out int nx, out int ny, out _, out StatusBar sb);
-			bool layoutSubviews = false;
-			var maxWidth = 0;
-			if (superView.Margin != null && superView == top.SuperView) {
-				maxWidth -= superView.GetFramesThickness ().Left + superView.GetFramesThickness ().Right;
-			}
-			if ((superView != top || top?.SuperView != null || (top != Application.Top && top.Modal)
-				|| (top?.SuperView == null && top.IsOverlapped))
-				&& (top.Frame.X + top.Frame.Width > maxWidth || ny > top.Frame.Y) && top.LayoutStyle == LayoutStyle.Computed) {
-
-				if ((top.X == null || top.X is Pos.PosAbsolute) && top.Frame.X != nx) {
-					top.X = nx;
-					layoutSubviews = true;
-				}
-				if ((top.Y == null || top.Y is Pos.PosAbsolute) && top.Frame.Y != ny) {
-					top.Y = ny;
-					layoutSubviews = true;
-				}
+	/// <summary>
+	/// Adjusts the location and size of <paramref name="top"/> within this Toplevel.
+	/// Virtual method enabling implementation of specific positions for inherited <see cref="Toplevel"/> views.
+	/// </summary>
+	/// <param name="top">The Toplevel to adjust.</param>
+	public virtual void PositionToplevel (Toplevel top)
+	{
+		var superView = GetLocationThatFits (top, top.Frame.X, top.Frame.Y,
+			out int nx, out int ny, out _, out var sb);
+		bool layoutSubviews = false;
+		int maxWidth = 0;
+		if (superView.Margin != null && superView == top.SuperView) {
+			maxWidth -= superView.GetFramesThickness ().Left + superView.GetFramesThickness ().Right;
+		}
+		if ((superView != top || top?.SuperView != null || top != Application.Top && top.Modal
+			|| top?.SuperView == null && top.IsOverlapped)
+		&& (top.Frame.X + top.Frame.Width > maxWidth || ny > top.Frame.Y) && top.LayoutStyle == LayoutStyle.Computed) {
+
+			if ((top.X == null || top.X is Pos.PosAbsolute) && top.Frame.X != nx) {
+				top.X = nx;
+				layoutSubviews = true;
 			}
 			}
-
-			// TODO: v2 - This is a hack to get the StatusBar to be positioned correctly.
-			if (sb != null && !top.Subviews.Contains (sb) && ny + top.Frame.Height != superView.Frame.Height - (sb.Visible ? 1 : 0)
-				&& top.Height is Dim.DimFill && -top.Height.Anchor (0) < 1) {
-
-				top.Height = Dim.Fill (sb.Visible ? 1 : 0);
+			if ((top.Y == null || top.Y is Pos.PosAbsolute) && top.Frame.Y != ny) {
+				top.Y = ny;
 				layoutSubviews = true;
 				layoutSubviews = true;
 			}
 			}
+		}
 
 
-			if (superView.LayoutNeeded || layoutSubviews) {
-				superView.LayoutSubviews ();
-			}
-			if (LayoutNeeded) {
-				LayoutSubviews ();
-			}
+		// TODO: v2 - This is a hack to get the StatusBar to be positioned correctly.
+		if (sb != null && !top.Subviews.Contains (sb) && ny + top.Frame.Height != superView.Frame.Height - (sb.Visible ? 1 : 0)
+		&& top.Height is Dim.DimFill && -top.Height.Anchor (0) < 1) {
+
+			top.Height = Dim.Fill (sb.Visible ? 1 : 0);
+			layoutSubviews = true;
 		}
 		}
 
 
-		///<inheritdoc/>
-		public override void OnDrawContent (Rect contentArea)
-		{
-			if (!Visible) {
-				return;
-			}
+		if (superView.LayoutNeeded || layoutSubviews) {
+			superView.LayoutSubviews ();
+		}
+		if (LayoutNeeded) {
+			LayoutSubviews ();
+		}
+	}
 
 
-			if (NeedsDisplay || SubViewNeedsDisplay || LayoutNeeded) {
-				//Driver.SetAttribute (GetNormalColor ());
-				// TODO: It's bad practice for views to always clear. Defeats the purpose of clipping etc...
-				Clear ();
-				LayoutSubviews ();
-				PositionToplevels ();
-
-				if (this == Application.OverlappedTop) {
-					foreach (var top in Application.OverlappedChildren.AsEnumerable ().Reverse ()) {
-						if (top.Frame.IntersectsWith (Bounds)) {
-							if (top != this && !top.IsCurrentTop && !OutsideTopFrame (top) && top.Visible) {
-								top.SetNeedsLayout ();
-								top.SetNeedsDisplay (top.Bounds);
-								top.Draw ();
-								top.OnRenderLineCanvas ();
-							}
+	///<inheritdoc/>
+	public override void OnDrawContent (Rect contentArea)
+	{
+		if (!Visible) {
+			return;
+		}
+
+		if (NeedsDisplay || SubViewNeedsDisplay || LayoutNeeded) {
+			//Driver.SetAttribute (GetNormalColor ());
+			// TODO: It's bad practice for views to always clear. Defeats the purpose of clipping etc...
+			Clear ();
+			LayoutSubviews ();
+			PositionToplevels ();
+
+			if (this == Application.OverlappedTop) {
+				foreach (var top in Application.OverlappedChildren.AsEnumerable ().Reverse ()) {
+					if (top.Frame.IntersectsWith (Bounds)) {
+						if (top != this && !top.IsCurrentTop && !OutsideTopFrame (top) && top.Visible) {
+							top.SetNeedsLayout ();
+							top.SetNeedsDisplay (top.Bounds);
+							top.Draw ();
+							top.OnRenderLineCanvas ();
 						}
 						}
 					}
 					}
 				}
 				}
+			}
 
 
-				// This should not be here, but in base
-				foreach (var view in Subviews) {
-					if (view.Frame.IntersectsWith (Bounds) && !OutsideTopFrame (this)) {
-						//view.SetNeedsLayout ();
-						view.SetNeedsDisplay (view.Bounds);
-						view.SetSubViewNeedsDisplay ();
-					}
+			// This should not be here, but in base
+			foreach (var view in Subviews) {
+				if (view.Frame.IntersectsWith (Bounds) && !OutsideTopFrame (this)) {
+					//view.SetNeedsLayout ();
+					view.SetNeedsDisplay (view.Bounds);
+					view.SetSubViewNeedsDisplay ();
 				}
 				}
+			}
 
 
-				base.OnDrawContent (contentArea);
+			base.OnDrawContent (contentArea);
 
 
-				// This is causing the menus drawn incorrectly if UseSubMenusSingleFrame is true
-				//if (this.MenuBar != null && this.MenuBar.IsMenuOpen && this.MenuBar.openMenu != null) {
-				//	// TODO: Hack until we can get compositing working right.
-				//	this.MenuBar.openMenu.Redraw (this.MenuBar.openMenu.Bounds);
-				//}
-			}
+			// This is causing the menus drawn incorrectly if UseSubMenusSingleFrame is true
+			//if (this.MenuBar != null && this.MenuBar.IsMenuOpen && this.MenuBar.openMenu != null) {
+			//	// TODO: Hack until we can get compositing working right.
+			//	this.MenuBar.openMenu.Redraw (this.MenuBar.openMenu.Bounds);
+			//}
 		}
 		}
+	}
 
 
-		bool OutsideTopFrame (Toplevel top)
-		{
-			if (top.Frame.X > Driver.Cols || top.Frame.Y > Driver.Rows) {
-				return true;
-			}
-			return false;
+	bool OutsideTopFrame (Toplevel top)
+	{
+		if (top.Frame.X > Driver.Cols || top.Frame.Y > Driver.Rows) {
+			return true;
 		}
 		}
+		return false;
+	}
 
 
-		internal static Point? _dragPosition;
-		Point _startGrabPoint;
-
-		///<inheritdoc/>
-		public override bool MouseEvent (MouseEvent mouseEvent)
-		{
-			if (!CanFocus) {
-				return true;
-			}
-
-			//System.Diagnostics.Debug.WriteLine ($"dragPosition before: {dragPosition.HasValue}");
-
-			int nx, ny;
-			if (!_dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed
-				|| mouseEvent.Flags == MouseFlags.Button2Pressed
-				|| mouseEvent.Flags == MouseFlags.Button3Pressed)) {
-
-				SetFocus ();
-				Application.BringOverlappedTopToFront ();
-
-				// Only start grabbing if the user clicks on the title bar.
-				// BUGBUG: Assumes Frame == Border and Title is always at Y == 0
-				if (mouseEvent.Y == 0 && mouseEvent.Flags == MouseFlags.Button1Pressed) {
-					_startGrabPoint = new Point (mouseEvent.X, mouseEvent.Y);
-					_dragPosition = new Point ();
-					nx = mouseEvent.X - mouseEvent.OfX;
-					ny = mouseEvent.Y - mouseEvent.OfY;
-					_dragPosition = new Point (nx, ny);
-					Application.GrabMouse (this);
+	internal static Point? _dragPosition;
+	Point _startGrabPoint;
+
+	///<inheritdoc/>
+	public override bool MouseEvent (MouseEvent mouseEvent)
+	{
+		if (!CanFocus) {
+			return true;
+		}
+
+		//System.Diagnostics.Debug.WriteLine ($"dragPosition before: {dragPosition.HasValue}");
+
+		int nx, ny;
+		if (!_dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed
+						|| mouseEvent.Flags == MouseFlags.Button2Pressed
+						|| mouseEvent.Flags == MouseFlags.Button3Pressed)) {
+
+			SetFocus ();
+			Application.BringOverlappedTopToFront ();
+
+			// Only start grabbing if the user clicks on the title bar.
+			// BUGBUG: Assumes Frame == Border and Title is always at Y == 0
+			if (mouseEvent.Y == 0 && mouseEvent.Flags == MouseFlags.Button1Pressed) {
+				_startGrabPoint = new Point (mouseEvent.X, mouseEvent.Y);
+				_dragPosition = new Point ();
+				nx = mouseEvent.X - mouseEvent.OfX;
+				ny = mouseEvent.Y - mouseEvent.OfY;
+				_dragPosition = new Point (nx, ny);
+				Application.GrabMouse (this);
+			}
+
+			//System.Diagnostics.Debug.WriteLine ($"Starting at {dragPosition}");
+			return true;
+		} else if (mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition) ||
+			mouseEvent.Flags == MouseFlags.Button3Pressed) {
+			if (_dragPosition.HasValue) {
+				if (SuperView == null) {
+					// Redraw the entire app window using just our Frame. Since we are 
+					// Application.Top, and our Frame always == our Bounds (Location is always (0,0))
+					// our Frame is actually view-relative (which is what Redraw takes).
+					// We need to pass all the view bounds because since the windows was 
+					// moved around, we don't know exactly what was the affected region.
+					Application.Top.SetNeedsDisplay ();
+				} else {
+					SuperView.SetNeedsDisplay ();
 				}
 				}
+				// BUGBUG: Assumes Frame == Border?
+				GetLocationThatFits (this, mouseEvent.X + (SuperView == null ? mouseEvent.OfX - _startGrabPoint.X : Frame.X - _startGrabPoint.X),
+					mouseEvent.Y + (SuperView == null ? mouseEvent.OfY - _startGrabPoint.Y : Frame.Y - _startGrabPoint.Y),
+					out nx, out ny, out _, out _);
 
 
-				//System.Diagnostics.Debug.WriteLine ($"Starting at {dragPosition}");
-				return true;
-			} else if (mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition) ||
-				mouseEvent.Flags == MouseFlags.Button3Pressed) {
-				if (_dragPosition.HasValue) {
-					if (SuperView == null) {
-						// Redraw the entire app window using just our Frame. Since we are 
-						// Application.Top, and our Frame always == our Bounds (Location is always (0,0))
-						// our Frame is actually view-relative (which is what Redraw takes).
-						// We need to pass all the view bounds because since the windows was 
-						// moved around, we don't know exactly what was the affected region.
-						Application.Top.SetNeedsDisplay ();
-					} else {
-						SuperView.SetNeedsDisplay ();
-					}
-					// BUGBUG: Assumes Frame == Border?
-					GetLocationThatFits (this, mouseEvent.X + (SuperView == null ? mouseEvent.OfX - _startGrabPoint.X : Frame.X - _startGrabPoint.X),
-						mouseEvent.Y + (SuperView == null ? mouseEvent.OfY - _startGrabPoint.Y : Frame.Y - _startGrabPoint.Y),
-						out nx, out ny, out _, out _);
-
-					_dragPosition = new Point (nx, ny);
-					X = nx;
-					Y = ny;
-					//System.Diagnostics.Debug.WriteLine ($"Drag: nx:{nx},ny:{ny}");
-
-					SetNeedsDisplay ();
-					return true;
-				}
-			}
+				_dragPosition = new Point (nx, ny);
+				X = nx;
+				Y = ny;
+				//System.Diagnostics.Debug.WriteLine ($"Drag: nx:{nx},ny:{ny}");
 
 
-			if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Released) && _dragPosition.HasValue) {
-				_dragPosition = null;
-				Application.UngrabMouse ();
+				SetNeedsDisplay ();
+				return true;
 			}
 			}
+		}
 
 
-			//System.Diagnostics.Debug.WriteLine ($"dragPosition after: {dragPosition.HasValue}");
-			//System.Diagnostics.Debug.WriteLine ($"Toplevel: {mouseEvent}");
-			return false;
+		if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Released) && _dragPosition.HasValue) {
+			_dragPosition = null;
+			Application.UngrabMouse ();
 		}
 		}
 
 
-		/// <summary>
-		/// Stops and closes this <see cref="Toplevel"/>. If this Toplevel is the top-most Toplevel, 
-		/// <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to exit.
-		/// </summary>
-		public virtual void RequestStop ()
-		{
-			if (IsOverlappedContainer && Running
-				&& (Application.Current == this
-				|| Application.Current?.Modal == false
-				|| Application.Current?.Modal == true && Application.Current?.Running == false)) {
-
-				foreach (var child in Application.OverlappedChildren) {
-					var ev = new ToplevelClosingEventArgs (this);
-					if (child.OnClosing (ev)) {
-						return;
-					}
-					child.Running = false;
-					Application.RequestStop (child);
-				}
-				Running = false;
-				Application.RequestStop (this);
-			} else if (IsOverlappedContainer && Running && Application.Current?.Modal == true && Application.Current?.Running == true) {
-				var ev = new ToplevelClosingEventArgs (Application.Current);
-				if (OnClosing (ev)) {
-					return;
-				}
-				Application.RequestStop (Application.Current);
-			} else if (!IsOverlappedContainer && Running && (!Modal || (Modal && Application.Current != this))) {
+		//System.Diagnostics.Debug.WriteLine ($"dragPosition after: {dragPosition.HasValue}");
+		//System.Diagnostics.Debug.WriteLine ($"Toplevel: {mouseEvent}");
+		return false;
+	}
+
+	/// <summary>
+	/// Stops and closes this <see cref="Toplevel"/>. If this Toplevel is the top-most Toplevel, 
+	/// <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to exit.
+	/// </summary>
+	public virtual void RequestStop ()
+	{
+		if (IsOverlappedContainer && Running
+					&& (Application.Current == this
+					|| Application.Current?.Modal == false
+					|| Application.Current?.Modal == true && Application.Current?.Running == false)) {
+
+			foreach (var child in Application.OverlappedChildren) {
 				var ev = new ToplevelClosingEventArgs (this);
 				var ev = new ToplevelClosingEventArgs (this);
-				if (OnClosing (ev)) {
+				if (child.OnClosing (ev)) {
 					return;
 					return;
 				}
 				}
-				Running = false;
-				Application.RequestStop (this);
-			} else {
-				Application.RequestStop (Application.Current);
+				child.Running = false;
+				Application.RequestStop (child);
+			}
+			Running = false;
+			Application.RequestStop (this);
+		} else if (IsOverlappedContainer && Running && Application.Current?.Modal == true && Application.Current?.Running == true) {
+			var ev = new ToplevelClosingEventArgs (Application.Current);
+			if (OnClosing (ev)) {
+				return;
 			}
 			}
+			Application.RequestStop (Application.Current);
+		} else if (!IsOverlappedContainer && Running && (!Modal || Modal && Application.Current != this)) {
+			var ev = new ToplevelClosingEventArgs (this);
+			if (OnClosing (ev)) {
+				return;
+			}
+			Running = false;
+			Application.RequestStop (this);
+		} else {
+			Application.RequestStop (Application.Current);
 		}
 		}
+	}
 
 
-		/// <summary>
-		/// Stops and closes the <see cref="Toplevel"/> specified by <paramref name="top"/>. If <paramref name="top"/> is the top-most Toplevel, 
-		/// <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to exit.
-		/// </summary>
-		/// <param name="top">The Toplevel to request stop.</param>
-		public virtual void RequestStop (Toplevel top)
-		{
-			top.RequestStop ();
-		}
+	/// <summary>
+	/// Stops and closes the <see cref="Toplevel"/> specified by <paramref name="top"/>. If <paramref name="top"/> is the top-most Toplevel, 
+	/// <see cref="Application.RequestStop(Toplevel)"/> will be called, causing the application to exit.
+	/// </summary>
+	/// <param name="top">The Toplevel to request stop.</param>
+	public virtual void RequestStop (Toplevel top) => top.RequestStop ();
 
 
-		///<inheritdoc/>
-		public override void PositionCursor ()
-		{
-			if (!IsOverlappedContainer) {
-				base.PositionCursor ();
+	///<inheritdoc/>
+	public override void PositionCursor ()
+	{
+		if (!IsOverlappedContainer) {
+			base.PositionCursor ();
+			if (Focused == null) {
+				EnsureFocus ();
 				if (Focused == null) {
 				if (Focused == null) {
-					EnsureFocus ();
-					if (Focused == null) {
-						Driver.SetCursorVisibility (CursorVisibility.Invisible);
-					}
+					Driver.SetCursorVisibility (CursorVisibility.Invisible);
 				}
 				}
-				return;
 			}
 			}
+			return;
+		}
 
 
-			if (Focused == null) {
-				foreach (var top in Application.OverlappedChildren) {
-					if (top != this && top.Visible) {
-						top.SetFocus ();
-						return;
-					}
+		if (Focused == null) {
+			foreach (var top in Application.OverlappedChildren) {
+				if (top != this && top.Visible) {
+					top.SetFocus ();
+					return;
 				}
 				}
 			}
 			}
-			base.PositionCursor ();
-			if (Focused == null) {
-				Driver.SetCursorVisibility (CursorVisibility.Invisible);
-			}
 		}
 		}
-
-		///<inheritdoc/>
-		public override bool OnEnter (View view)
-		{
-			return MostFocused?.OnEnter (view) ?? base.OnEnter (view);
+		base.PositionCursor ();
+		if (Focused == null) {
+			Driver.SetCursorVisibility (CursorVisibility.Invisible);
 		}
 		}
+	}
 
 
-		///<inheritdoc/>
-		public override bool OnLeave (View view)
-		{
-			return MostFocused?.OnLeave (view) ?? base.OnLeave (view);
-		}
+	///<inheritdoc/>
+	public override bool OnEnter (View view) => MostFocused?.OnEnter (view) ?? base.OnEnter (view);
 
 
-		///<inheritdoc/>
-		protected override void Dispose (bool disposing)
-		{
-			Application.GrabbingMouse -= Application_GrabbingMouse;
-			Application.UnGrabbingMouse -= Application_UnGrabbingMouse;
+	///<inheritdoc/>
+	public override bool OnLeave (View view) => MostFocused?.OnLeave (view) ?? base.OnLeave (view);
 
 
-			_dragPosition = null;
-			base.Dispose (disposing);
+	///<inheritdoc/>
+	protected override void Dispose (bool disposing)
+	{
+		Application.GrabbingMouse -= Application_GrabbingMouse;
+		Application.UnGrabbingMouse -= Application_UnGrabbingMouse;
+
+		_dragPosition = null;
+		base.Dispose (disposing);
+	}
+}
+/// <summary>
+/// Implements the <see cref="IEqualityComparer{T}"/> for comparing two <see cref="Toplevel"/>s
+/// used by <see cref="StackExtensions"/>.
+/// </summary>
+public class ToplevelEqualityComparer : IEqualityComparer<Toplevel> {
+	/// <summary>Determines whether the specified objects are equal.</summary>
+	/// <param name="x">The first object of type <see cref="Toplevel" /> to compare.</param>
+	/// <param name="y">The second object of type <see cref="Toplevel" /> to compare.</param>
+	/// <returns>
+	///     <see langword="true" /> if the specified objects are equal; otherwise, <see langword="false" />.</returns>
+	public bool Equals (Toplevel x, Toplevel y)
+	{
+		if (y == null && x == null) {
+			return true;
+		} else if (x == null || y == null) {
+			return false;
+		} else if (x.Id == y.Id) {
+			return true;
+		} else {
+			return false;
 		}
 		}
 	}
 	}
 
 
-	/// <summary>
-	/// Implements the <see cref="IEqualityComparer{T}"/> for comparing two <see cref="Toplevel"/>s
-	/// used by <see cref="StackExtensions"/>.
-	/// </summary>
-	public class ToplevelEqualityComparer : IEqualityComparer<Toplevel> {
-		/// <summary>Determines whether the specified objects are equal.</summary>
-		/// <param name="x">The first object of type <see cref="Toplevel" /> to compare.</param>
-		/// <param name="y">The second object of type <see cref="Toplevel" /> to compare.</param>
-		/// <returns>
-		///     <see langword="true" /> if the specified objects are equal; otherwise, <see langword="false" />.</returns>
-		public bool Equals (Toplevel x, Toplevel y)
-		{
-			if (y == null && x == null)
-				return true;
-			else if (x == null || y == null)
-				return false;
-			else if (x.Id == y.Id)
-				return true;
-			else
-				return false;
-		}
-
-		/// <summary>Returns a hash code for the specified object.</summary>
-		/// <param name="obj">The <see cref="Toplevel" /> for which a hash code is to be returned.</param>
-		/// <returns>A hash code for the specified object.</returns>
-		/// <exception cref="ArgumentNullException">The type of <paramref name="obj" /> 
-		/// is a reference type and <paramref name="obj" /> is <see langword="null" />.</exception>
-		public int GetHashCode (Toplevel obj)
-		{
-			if (obj == null)
-				throw new ArgumentNullException ();
-
-			int hCode = 0;
-			if (int.TryParse (obj.Id, out int result)) {
-				hCode = result;
-			}
-			return hCode.GetHashCode ();
+	/// <summary>Returns a hash code for the specified object.</summary>
+	/// <param name="obj">The <see cref="Toplevel" /> for which a hash code is to be returned.</param>
+	/// <returns>A hash code for the specified object.</returns>
+	/// <exception cref="ArgumentNullException">The type of <paramref name="obj" /> 
+	/// is a reference type and <paramref name="obj" /> is <see langword="null" />.</exception>
+	public int GetHashCode (Toplevel obj)
+	{
+		if (obj == null) {
+			throw new ArgumentNullException ();
 		}
 		}
-	}
 
 
-	/// <summary>
-	/// Implements the <see cref="IComparer{T}"/> to sort the <see cref="Toplevel"/> 
-	/// from the <see cref="Application.OverlappedChildren"/> if needed.
-	/// </summary>
-	public sealed class ToplevelComparer : IComparer<Toplevel> {
-		/// <summary>Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.</summary>
-		/// <param name="x">The first object to compare.</param>
-		/// <param name="y">The second object to compare.</param>
-		/// <returns>A signed integer that indicates the relative values of <paramref name="x" /> and <paramref name="y" />, as shown in the following table.Value Meaning Less than zero
-		///             <paramref name="x" /> is less than <paramref name="y" />.Zero
-		///             <paramref name="x" /> equals <paramref name="y" />.Greater than zero
-		///             <paramref name="x" /> is greater than <paramref name="y" />.</returns>
-		public int Compare (Toplevel x, Toplevel y)
-		{
-			if (ReferenceEquals (x, y))
-				return 0;
-			else if (x == null)
-				return -1;
-			else if (y == null)
-				return 1;
-			else
-				return string.Compare (x.Id, y.Id);
+		int hCode = 0;
+		if (int.TryParse (obj.Id, out int result)) {
+			hCode = result;
 		}
 		}
+		return hCode.GetHashCode ();
 	}
 	}
 }
 }
+/// <summary>
+/// Implements the <see cref="IComparer{T}"/> to sort the <see cref="Toplevel"/> 
+/// from the <see cref="Application.OverlappedChildren"/> if needed.
+/// </summary>
+public sealed class ToplevelComparer : IComparer<Toplevel> {
+	/// <summary>Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.</summary>
+	/// <param name="x">The first object to compare.</param>
+	/// <param name="y">The second object to compare.</param>
+	/// <returns>A signed integer that indicates the relative values of <paramref name="x" /> and <paramref name="y" />, as shown in the following table.Value Meaning Less than zero
+	///             <paramref name="x" /> is less than <paramref name="y" />.Zero
+	///             <paramref name="x" /> equals <paramref name="y" />.Greater than zero
+	///             <paramref name="x" /> is greater than <paramref name="y" />.</returns>
+	public int Compare (Toplevel x, Toplevel y)
+	{
+		if (ReferenceEquals (x, y)) {
+			return 0;
+		} else if (x == null) {
+			return -1;
+		} else if (y == null) {
+			return 1;
+		} else {
+			return string.Compare (x.Id, y.Id);
+		}
+	}
+}

+ 10 - 9
UICatalog/Properties/launchSettings.json

@@ -1,10 +1,15 @@
 {
 {
   "profiles": {
   "profiles": {
     "UICatalog": {
     "UICatalog": {
+      "commandName": "Project"
+    },
+    "UICatalog --driver NetDriver": {
+      "commandName": "Project",
+      "commandLineArgs": "--driver NetDriver"
+    },
+    "UICatalog --driver WindowsDriver": {
       "commandName": "Project",
       "commandName": "Project",
-      "environmentVariables": {
-        "WT_SESSION": "yes"
-      }
+      "commandLineArgs": "--driver WindowsDriver"
     },
     },
     "WSL : UICatalog": {
     "WSL : UICatalog": {
       "commandName": "Executable",
       "commandName": "Executable",
@@ -12,14 +17,10 @@
       "commandLineArgs": "dotnet UICatalog.dll",
       "commandLineArgs": "dotnet UICatalog.dll",
       "distributionName": ""
       "distributionName": ""
     },
     },
-    "UICatalog -usc": {
-      "commandName": "Project",
-      "commandLineArgs": "-usc"
-    },
-    "WSL: UICatalog -usc": {
+    "WSL: UICatalog --driver NetDriver": {
       "commandName": "Executable",
       "commandName": "Executable",
       "executablePath": "wsl",
       "executablePath": "wsl",
-      "commandLineArgs": "dotnet UICatalog.dll -usc",
+      "commandLineArgs": "dotnet UICatalog.dll --driver NetDriver",
       "distributionName": ""
       "distributionName": ""
     },
     },
     "Sliders": {
     "Sliders": {

+ 7 - 6
UICatalog/Scenarios/CharacterMap.cs

@@ -230,6 +230,7 @@ public class CharacterMap : Scenario {
 }
 }
 
 
 class CharMap : ScrollView {
 class CharMap : ScrollView {
+	const CursorVisibility _cursor = CursorVisibility.Default;
 	/// <summary>
 	/// <summary>
 	/// Specifies the starting offset for the character map. The default is 0x2500 
 	/// Specifies the starting offset for the character map. The default is 0x2500 
 	/// which is the Box Drawing characters.
 	/// which is the Box Drawing characters.
@@ -296,11 +297,11 @@ class CharMap : ScrollView {
 	public override void PositionCursor ()
 	public override void PositionCursor ()
 	{
 	{
 		if (HasFocus &&
 		if (HasFocus &&
-		Cursor.X >= RowLabelWidth &&
-		Cursor.X < Bounds.Width - (ShowVerticalScrollIndicator ? 1 : 0) &&
-		Cursor.Y > 0 &&
-		Cursor.Y < Bounds.Height - (ShowHorizontalScrollIndicator ? 1 : 0)) {
-			Driver.SetCursorVisibility (CursorVisibility.Default);
+			Cursor.X >= RowLabelWidth &&
+			Cursor.X < Bounds.Width - (ShowVerticalScrollIndicator ? 1 : 0) &&
+			Cursor.Y > 0 &&
+			Cursor.Y < Bounds.Height - (ShowHorizontalScrollIndicator ? 1 : 0)) {
+			Driver.SetCursorVisibility (_cursor);
 			Move (Cursor.X, Cursor.Y);
 			Move (Cursor.X, Cursor.Y);
 		} else {
 		} else {
 			Driver.SetCursorVisibility (CursorVisibility.Invisible);
 			Driver.SetCursorVisibility (CursorVisibility.Invisible);
@@ -807,7 +808,7 @@ class CharMap : ScrollView {
 	public override bool OnEnter (View view)
 	public override bool OnEnter (View view)
 	{
 	{
 		if (IsInitialized) {
 		if (IsInitialized) {
-			Application.Driver.SetCursorVisibility (CursorVisibility.Default);
+			Application.Driver.SetCursorVisibility (_cursor);
 		}
 		}
 		return base.OnEnter (view);
 		return base.OnEnter (view);
 	}
 	}

+ 53 - 0
UICatalog/Scenarios/ChineseUI.cs

@@ -0,0 +1,53 @@
+using Terminal.Gui;
+
+namespace UICatalog.Scenarios; 
+
+[ScenarioMetadata ("ChineseUI", "Chinese UI")]
+[ScenarioCategory ("Unicode")]
+public class ChineseUI : Scenario {
+	public override void Init ()
+	{
+		Application.Init ();
+		var top = Application.Top;
+
+		var win = new Window () {
+			Title = "Test",
+			X = 0,
+			Y = 0,
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+		top.Add (win);
+
+		var buttonPanel = new FrameView () {
+			Title = "Command",
+			X = 0,
+			Y = 1,
+			Width = Dim.Fill (),
+			Height = 5
+		};
+		win.Add (buttonPanel);
+
+		var btn = new Button (1, 1, "你", true); // v1: A
+		btn.Clicked += (s, e) => {
+			int result = MessageBox.Query ("Confirm",
+				"Are you sure you want to quit ui?", 0,
+				"Yes", "No");
+			if (result == 0) {
+				RequestStop ();
+			}
+		};
+
+		buttonPanel.Add (
+			btn,
+			new Button (12, 1, "好"), // v1: B
+			new Button (22, 1, "呀") // v1: C
+		);
+
+		Application.Run ();
+	}
+
+	public override void Run ()
+	{
+	}
+}

+ 111 - 83
UICatalog/UICatalog.cs

@@ -1,24 +1,23 @@
-global using CM = Terminal.Gui.ConfigurationManager;
 global using Attribute = Terminal.Gui.Attribute;
 global using Attribute = Terminal.Gui.Attribute;
+global using CM = Terminal.Gui.ConfigurationManager;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.CommandLine;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Globalization;
 using System.Globalization;
+using System.IO;
 using System.Linq;
 using System.Linq;
+using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.Text;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
 using Terminal.Gui;
 using Terminal.Gui;
-using System.IO;
-using System.Reflection;
-using System.Threading;
 using static Terminal.Gui.ConfigurationManager;
 using static Terminal.Gui.ConfigurationManager;
-using System.Text.Json.Serialization;
-using static Terminal.Gui.TableView;
-
 
 
 #nullable enable
 #nullable enable
 
 
-namespace UICatalog; 
+namespace UICatalog;
 
 
 /// <summary>
 /// <summary>
 /// UI Catalog is a comprehensive sample library for Terminal.Gui. It provides a simple UI for adding to the catalog of scenarios.
 /// UI Catalog is a comprehensive sample library for Terminal.Gui. It provides a simple UI for adding to the catalog of scenarios.
@@ -51,13 +50,20 @@ namespace UICatalog;
 /// </para>	
 /// </para>	
 /// </remarks>
 /// </remarks>
 class UICatalogApp {
 class UICatalogApp {
-	[SerializableConfigurationProperty (Scope = typeof (AppScope), OmitClassName = true)] [JsonPropertyName ("UICatalog.StatusBar")]
+	[SerializableConfigurationProperty (Scope = typeof (AppScope), OmitClassName = true)]
+	[JsonPropertyName ("UICatalog.StatusBar")]
 	public static bool ShowStatusBar { get; set; } = true;
 	public static bool ShowStatusBar { get; set; } = true;
 
 
-	static readonly FileSystemWatcher _currentDirWatcher = new ();
-	static readonly FileSystemWatcher _homeDirWatcher = new ();
+	static readonly FileSystemWatcher _currentDirWatcher = new FileSystemWatcher ();
+	static readonly FileSystemWatcher _homeDirWatcher = new FileSystemWatcher ();
+
+	struct Options {
+		public string Driver;
+		public string Scenario;
+		/* etc. */
+	}
 
 
-	static void Main (string [] args)
+	static int Main (string [] args)
 	{
 	{
 		Console.OutputEncoding = Encoding.Default;
 		Console.OutputEncoding = Encoding.Default;
 
 
@@ -68,22 +74,68 @@ class UICatalogApp {
 		_scenarios = Scenario.GetScenarios ();
 		_scenarios = Scenario.GetScenarios ();
 		_categories = Scenario.GetAllCategories ();
 		_categories = Scenario.GetAllCategories ();
 
 
-		if (args.Length > 0 && args.Contains ("-usc")) {
-			_useSystemConsole = true;
-			args = args.Where (val => val != "-usc").ToArray ();
+		// Process command line args
+		// "UICatalog [-driver <driver>] [scenario name]"
+		// If no driver is provided, the default driver is used.
+		var driverOption = new Option<string> (
+			"--driver",
+			"The ConsoleDriver to use."
+		).FromAmong (Application.GetDriverTypes ().Select (d => d.Name).ToArray ());
+		driverOption.AddAlias ("-d");
+		driverOption.AddAlias ("--d");
+
+		var scenarioArgument = new Argument<string> (
+			"scenario",
+			description: "The name of the scenario to run.",
+			getDefaultValue: () => "none"
+		).FromAmong (_scenarios.Select (s => s.GetName ()).Append ("none").ToArray ());
+
+		var rootCommand = new RootCommand (description: "A comprehensive sample library for Terminal.Gui") {
+			scenarioArgument,
+			driverOption
+		};
+
+		rootCommand.SetHandler ((context) => {
+			Options options = new Options () {
+				Driver = context.ParseResult.GetValueForOption (driverOption),
+				Scenario = context.ParseResult.GetValueForArgument (scenarioArgument),
+				/* etc. */
+			};
+			context.ExitCode = CommandWrapper (options);
+		});
+
+		return rootCommand.Invoke (args);
+	}
+
+	// See https://github.com/dotnet/command-line-api/issues/796 for the rationale behind this hackery
+	static int CommandWrapper (Options options)
+	{
+		try {
+			UICatalogMain (options);
+		} catch (Exception e) {
+			Console.WriteLine (e.ToString());
+			return 1;
 		}
 		}
+		return 0;
+	}
 
 
+	static void UICatalogMain (Options options)
+	{
 		StartConfigFileWatcher ();
 		StartConfigFileWatcher ();
 
 
+		// By setting _forceDriver we ensure that if the user has specified a driver on the command line, it will be used
+		// regardless of what's in a config file.
+		Application.ForceDriver = _forceDriver = options.Driver;
+
 		// If a Scenario name has been provided on the commandline
 		// If a Scenario name has been provided on the commandline
 		// run it and exit when done.
 		// run it and exit when done.
-		if (args.Length > 0) {
+		if (options.Scenario != "none") {
 			_topLevelColorScheme = "Base";
 			_topLevelColorScheme = "Base";
 
 
-			int item = _scenarios.FindIndex (s => s.GetName ().Equals (args [0], StringComparison.OrdinalIgnoreCase));
+			int item = _scenarios!.FindIndex (s => s.GetName ().Equals (options.Scenario, StringComparison.OrdinalIgnoreCase));
 			_selectedScenario = (Scenario)Activator.CreateInstance (_scenarios [item].GetType ())!;
 			_selectedScenario = (Scenario)Activator.CreateInstance (_scenarios [item].GetType ())!;
-			Application.UseSystemConsole = _useSystemConsole;
-			Application.Init ();
+
+			Application.Init (driverName: _forceDriver);
 			_selectedScenario.Theme = _cachedTheme;
 			_selectedScenario.Theme = _cachedTheme;
 			_selectedScenario.TopLevelColorScheme = _topLevelColorScheme;
 			_selectedScenario.TopLevelColorScheme = _topLevelColorScheme;
 			_selectedScenario.Init ();
 			_selectedScenario.Init ();
@@ -148,14 +200,14 @@ class UICatalogApp {
 		// Setup a file system watcher for `./.tui/`
 		// Setup a file system watcher for `./.tui/`
 		_currentDirWatcher.NotifyFilter = NotifyFilters.LastWrite;
 		_currentDirWatcher.NotifyFilter = NotifyFilters.LastWrite;
 
 
-		var assemblyLocation = Assembly.GetExecutingAssembly ().Location;
+		string assemblyLocation = Assembly.GetExecutingAssembly ().Location;
 		string tuiDir;
 		string tuiDir;
 
 
 		if (!string.IsNullOrEmpty (assemblyLocation)) {
 		if (!string.IsNullOrEmpty (assemblyLocation)) {
 			var assemblyFile = new FileInfo (assemblyLocation);
 			var assemblyFile = new FileInfo (assemblyLocation);
 			tuiDir = Path.Combine (assemblyFile.Directory!.FullName, ".tui");
 			tuiDir = Path.Combine (assemblyFile.Directory!.FullName, ".tui");
 		} else {
 		} else {
-			tuiDir = Path.Combine (System.AppContext.BaseDirectory, ".tui");
+			tuiDir = Path.Combine (AppContext.BaseDirectory, ".tui");
 		}
 		}
 
 
 
 
@@ -206,11 +258,14 @@ class UICatalogApp {
 	/// <returns></returns>
 	/// <returns></returns>
 	static Scenario RunUICatalogTopLevel ()
 	static Scenario RunUICatalogTopLevel ()
 	{
 	{
-		Application.UseSystemConsole = _useSystemConsole;
 
 
 		// Run UI Catalog UI. When it exits, if _selectedScenario is != null then
 		// Run UI Catalog UI. When it exits, if _selectedScenario is != null then
 		// a Scenario was selected. Otherwise, the user wants to quit UI Catalog.
 		// a Scenario was selected. Otherwise, the user wants to quit UI Catalog.
-		Application.Init ();
+
+		// If the user specified a driver on the command line then use it,
+		// ignoring Config files.
+
+		Application.Init (driverName: _forceDriver);
 
 
 		if (_cachedTheme is null) {
 		if (_cachedTheme is null) {
 			_cachedTheme = Themes?.Theme;
 			_cachedTheme = Themes?.Theme;
@@ -240,7 +295,7 @@ class UICatalogApp {
 	// If set, holds the scenario the user selected
 	// If set, holds the scenario the user selected
 	static Scenario? _selectedScenario = null;
 	static Scenario? _selectedScenario = null;
 
 
-	static bool _useSystemConsole = false;
+	static string _forceDriver = string.Empty;
 	static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
 	static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
 	static bool _isFirstRunning = true;
 	static bool _isFirstRunning = true;
 	static string _topLevelColorScheme = string.Empty;
 	static string _topLevelColorScheme = string.Empty;
@@ -264,7 +319,7 @@ class UICatalogApp {
 		// TableView works. There's no real reason not to use ListView. Because we use TableView, and TableView
 		// TableView works. There's no real reason not to use ListView. Because we use TableView, and TableView
 		// doesn't (currently) have CollectionNavigator support built in, we implement it here, within the app.
 		// doesn't (currently) have CollectionNavigator support built in, we implement it here, within the app.
 		public TableView ScenarioList;
 		public TableView ScenarioList;
-		CollectionNavigator _scenarioCollectionNav = new ();
+		CollectionNavigator _scenarioCollectionNav = new CollectionNavigator ();
 
 
 		public StatusItem DriverName;
 		public StatusItem DriverName;
 		public StatusItem OS;
 		public StatusItem OS;
@@ -274,16 +329,15 @@ class UICatalogApp {
 			_themeMenuItems = CreateThemeMenuItems ();
 			_themeMenuItems = CreateThemeMenuItems ();
 			_themeMenuBarItem = new MenuBarItem ("_Themes", _themeMenuItems);
 			_themeMenuBarItem = new MenuBarItem ("_Themes", _themeMenuItems);
 			MenuBar = new MenuBar (new MenuBarItem [] {
 			MenuBar = new MenuBar (new MenuBarItem [] {
-				new ("_File", new MenuItem [] {
-					new ("_Quit", "Quit UI Catalog", RequestStop, null, null)
+				new MenuBarItem ("_File", new MenuItem [] {
+					new MenuItem ("_Quit", "Quit UI Catalog", RequestStop, null, null)
 				}),
 				}),
 				_themeMenuBarItem,
 				_themeMenuBarItem,
-				new ("Diag_nostics", CreateDiagnosticMenuItems ()),
-				new ("_Help", new MenuItem [] {
-					new ("_Documentation", "", () => OpenUrl ("https://gui-cs.github.io/Terminal.GuiV2Docs"), null, null, (KeyCode)Key.F1),
-					new ("_README", "", () => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"), null, null, (KeyCode)Key.F2),
-					new ("_About...",
-						"About UI Catalog", () => MessageBox.Query ("About UI Catalog", _aboutMessage!.ToString (), 0, false, "_Ok"), null, null, (KeyCode)Key.A.WithCtrl)
+				new MenuBarItem ("Diag_nostics", CreateDiagnosticMenuItems ()),
+				new MenuBarItem ("_Help", new MenuItem [] {
+					new MenuItem ("_Documentation", "", () => OpenUrl ("https://gui-cs.github.io/Terminal.GuiV2Docs"), null, null, (KeyCode)Key.F1),
+					new MenuItem ("_README", "", () => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"), null, null, (KeyCode)Key.F2),
+					new MenuItem ("_About...", "About UI Catalog", () => MessageBox.Query ("About UI Catalog", _aboutMessage!.ToString (), 0, false, "_Ok"), null, null, (KeyCode)Key.A.WithCtrl)
 				})
 				})
 			});
 			});
 
 
@@ -295,7 +349,7 @@ class UICatalogApp {
 			};
 			};
 
 
 			StatusBar.Items = new StatusItem [] {
 			StatusBar.Items = new StatusItem [] {
-				new (Application.QuitKey, $"~{Application.QuitKey} to quit", () => {
+				new StatusItem (Application.QuitKey, $"~{Application.QuitKey} to quit", () => {
 					if (_selectedScenario is null) {
 					if (_selectedScenario is null) {
 						// This causes GetScenarioToRun to return null
 						// This causes GetScenarioToRun to return null
 						_selectedScenario = null;
 						_selectedScenario = null;
@@ -304,7 +358,7 @@ class UICatalogApp {
 						_selectedScenario.RequestStop ();
 						_selectedScenario.RequestStop ();
 					}
 					}
 				}),
 				}),
-				new (Key.F10, "~F10~ Status Bar", () => {
+				new StatusItem (Key.F10, "~F10~ Status Bar", () => {
 					StatusBar.Visible = !StatusBar.Visible;
 					StatusBar.Visible = !StatusBar.Visible;
 					//ContentPane!.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
 					//ContentPane!.Height = Dim.Fill(StatusBar.Visible ? 1 : 0);
 					LayoutSubviews ();
 					LayoutSubviews ();
@@ -390,8 +444,8 @@ class UICatalogApp {
 			ScenarioList.CellActivated += ScenarioView_OpenSelectedItem;
 			ScenarioList.CellActivated += ScenarioView_OpenSelectedItem;
 
 
 			// TableView typically is a grid where nav keys are biased for moving left/right.
 			// TableView typically is a grid where nav keys are biased for moving left/right.
-			ScenarioList.KeyBindings.Add (Key.Home, Command.TopHome);
-			ScenarioList.KeyBindings.Add (Key.End, Command.BottomEnd);
+			ScenarioList.KeyBindings.Add (Key.Home, Terminal.Gui.Command.TopHome);
+			ScenarioList.KeyBindings.Add (Key.End, Terminal.Gui.Command.BottomEnd);
 
 
 			// Ideally, TableView.MultiSelect = false would turn off any keybindings for
 			// Ideally, TableView.MultiSelect = false would turn off any keybindings for
 			// multi-select options. But it currently does not. UI Catalog uses Ctrl-A for
 			// multi-select options. But it currently does not. UI Catalog uses Ctrl-A for
@@ -453,10 +507,7 @@ class UICatalogApp {
 			Unloaded -= UnloadedHandler;
 			Unloaded -= UnloadedHandler;
 		}
 		}
 
 
-		void ConfigAppliedHandler (object? sender, ConfigurationManagerEventArgs? a)
-		{
-			ConfigChanged ();
-		}
+		void ConfigAppliedHandler (object? sender, ConfigurationManagerEventArgs? a) => ConfigChanged ();
 
 
 		/// <summary>
 		/// <summary>
 		/// Launches the selected scenario, setting the global _selectedScenario
 		/// Launches the selected scenario, setting the global _selectedScenario
@@ -516,7 +567,7 @@ class UICatalogApp {
 			miIsMenuBorderDisabled = new MenuItem {
 			miIsMenuBorderDisabled = new MenuItem {
 				Title = "Disable Menu _Border"
 				Title = "Disable Menu _Border"
 			};
 			};
-			miIsMenuBorderDisabled.Shortcut = (KeyCode)(new Key (miIsMenuBorderDisabled!.Title!.Substring (14, 1) [0])).WithAlt.WithCtrl;
+			miIsMenuBorderDisabled.Shortcut = (KeyCode)new Key (miIsMenuBorderDisabled!.Title!.Substring (14, 1) [0]).WithAlt.WithCtrl;
 			miIsMenuBorderDisabled.CheckType |= MenuItemCheckStyle.Checked;
 			miIsMenuBorderDisabled.CheckType |= MenuItemCheckStyle.Checked;
 			miIsMenuBorderDisabled.Action += () => {
 			miIsMenuBorderDisabled.Action += () => {
 				miIsMenuBorderDisabled.Checked = (bool)!miIsMenuBorderDisabled.Checked!;
 				miIsMenuBorderDisabled.Checked = (bool)!miIsMenuBorderDisabled.Checked!;
@@ -553,7 +604,7 @@ class UICatalogApp {
 			miIsMouseDisabled = new MenuItem {
 			miIsMouseDisabled = new MenuItem {
 				Title = "_Disable Mouse"
 				Title = "_Disable Mouse"
 			};
 			};
-			miIsMouseDisabled.Shortcut = (KeyCode)(new Key (miIsMouseDisabled!.Title!.Substring (1, 1) [0])).WithAlt.WithCtrl;
+			miIsMouseDisabled.Shortcut = (KeyCode)new Key (miIsMouseDisabled!.Title!.Substring (1, 1) [0]).WithAlt.WithCtrl;
 			miIsMouseDisabled.CheckType |= MenuItemCheckStyle.Checked;
 			miIsMouseDisabled.CheckType |= MenuItemCheckStyle.Checked;
 			miIsMouseDisabled.Action += () => {
 			miIsMouseDisabled.Action += () => {
 				miIsMouseDisabled.Checked = Application.IsMouseDisabled = (bool)!miIsMouseDisabled.Checked!;
 				miIsMouseDisabled.Checked = Application.IsMouseDisabled = (bool)!miIsMouseDisabled.Checked!;
@@ -592,7 +643,7 @@ class UICatalogApp {
 			foreach (Enum diag in Enum.GetValues (_diagnosticFlags.GetType ())) {
 			foreach (Enum diag in Enum.GetValues (_diagnosticFlags.GetType ())) {
 				var item = new MenuItem {
 				var item = new MenuItem {
 					Title = GetDiagnosticsTitle (diag),
 					Title = GetDiagnosticsTitle (diag),
-					Shortcut = (KeyCode)(new Key(index.ToString () [0])).WithAlt
+					Shortcut = (KeyCode)new Key (index.ToString () [0]).WithAlt
 				};
 				};
 				index++;
 				index++;
 				item.CheckType |= MenuItemCheckStyle.Checked;
 				item.CheckType |= MenuItemCheckStyle.Checked;
@@ -633,24 +684,18 @@ class UICatalogApp {
 			}
 			}
 			return menuItems.ToArray ();
 			return menuItems.ToArray ();
 
 
-			string GetDiagnosticsTitle (Enum diag)
-			{
-				return Enum.GetName (_diagnosticFlags.GetType (), diag) switch {
-					"Off" => OFF,
-					"FrameRuler" => FRAME_RULER,
-					"FramePadding" => FRAME_PADDING,
-					_ => ""
-				};
-			}
+			string GetDiagnosticsTitle (Enum diag) => Enum.GetName (_diagnosticFlags.GetType (), diag) switch {
+				"Off" => OFF,
+				"FrameRuler" => FRAME_RULER,
+				"FramePadding" => FRAME_PADDING,
+				_ => ""
+			};
 
 
-			Enum GetDiagnosticsEnumValue (string title)
-			{
-				return title switch {
-					FRAME_RULER => ConsoleDriver.DiagnosticFlags.FrameRuler,
-					FRAME_PADDING => ConsoleDriver.DiagnosticFlags.FramePadding,
-					_ => null!
-				};
-			}
+			Enum GetDiagnosticsEnumValue (string title) => title switch {
+				FRAME_RULER => ConsoleDriver.DiagnosticFlags.FrameRuler,
+				FRAME_PADDING => ConsoleDriver.DiagnosticFlags.FramePadding,
+				_ => null!
+			};
 
 
 			void SetDiagnosticsFlag (Enum diag, bool add)
 			void SetDiagnosticsFlag (Enum diag, bool add)
 			{
 			{
@@ -685,7 +730,7 @@ class UICatalogApp {
 			foreach (var theme in Themes!) {
 			foreach (var theme in Themes!) {
 				var item = new MenuItem {
 				var item = new MenuItem {
 					Title = $"_{theme.Key}",
 					Title = $"_{theme.Key}",
-					Shortcut = (KeyCode)(new Key ((KeyCode)((uint)KeyCode.D1 + (schemeCount++))).WithCtrl)
+					Shortcut = (KeyCode)new Key ((KeyCode)((uint)KeyCode.D1 + schemeCount++)).WithCtrl
 				};
 				};
 				item.CheckType |= MenuItemCheckStyle.Checked;
 				item.CheckType |= MenuItemCheckStyle.Checked;
 				item.Checked = theme.Key == _cachedTheme; // CM.Themes.Theme;
 				item.Checked = theme.Key == _cachedTheme; // CM.Themes.Theme;
@@ -723,13 +768,13 @@ class UICatalogApp {
 
 
 		public void ConfigChanged ()
 		public void ConfigChanged ()
 		{
 		{
-			miForce16Colors!.Checked = Application.Force16Colors;
-
 			if (_topLevelColorScheme == null || !Colors.ColorSchemes.ContainsKey (_topLevelColorScheme)) {
 			if (_topLevelColorScheme == null || !Colors.ColorSchemes.ContainsKey (_topLevelColorScheme)) {
 				_topLevelColorScheme = "Base";
 				_topLevelColorScheme = "Base";
 			}
 			}
 
 
-			_themeMenuItems = ((UICatalogTopLevel)Application.Top).CreateThemeMenuItems ();
+			_cachedTheme = Themes?.Theme;
+
+			_themeMenuItems = CreateThemeMenuItems ();
 			_themeMenuBarItem!.Children = _themeMenuItems;
 			_themeMenuBarItem!.Children = _themeMenuItems;
 			foreach (var mi in _themeMenuItems!) {
 			foreach (var mi in _themeMenuItems!) {
 				if (mi is { Parent: null }) {
 				if (mi is { Parent: null }) {
@@ -737,25 +782,8 @@ class UICatalogApp {
 				}
 				}
 			}
 			}
 
 
-			var checkedThemeMenu = _themeMenuItems?.Where (m => m?.Checked ?? false).FirstOrDefault ();
-			if (checkedThemeMenu != null) {
-				checkedThemeMenu.Checked = false;
-			}
-			checkedThemeMenu = _themeMenuItems?.Where (m => m != null && m.Title == Themes?.Theme).FirstOrDefault ();
-			if (checkedThemeMenu != null) {
-				Themes!.Theme = checkedThemeMenu.Title!;
-				checkedThemeMenu.Checked = true;
-			}
-
-			var schemeMenuItems = ((MenuBarItem)_themeMenuItems?.Where (i => i is MenuBarItem)!.FirstOrDefault ()!)!.Children;
-			foreach (var schemeMenuItem in schemeMenuItems) {
-				schemeMenuItem.Checked = (string)schemeMenuItem.Data == _topLevelColorScheme;
-			}
-
 			ColorScheme = Colors.ColorSchemes [_topLevelColorScheme];
 			ColorScheme = Colors.ColorSchemes [_topLevelColorScheme];
 
 
-			//ContentPane.LineStyle = FrameView.DefaultBorderStyle;
-
 			MenuBar.Menus [0].Children [0].Shortcut = (KeyCode)Application.QuitKey;
 			MenuBar.Menus [0].Children [0].Shortcut = (KeyCode)Application.QuitKey;
 			StatusBar.Items [0].Shortcut = Application.QuitKey;
 			StatusBar.Items [0].Shortcut = Application.QuitKey;
 			StatusBar.Items [0].Title = $"~{Application.QuitKey} to quit";
 			StatusBar.Items [0].Title = $"~{Application.QuitKey} to quit";
@@ -763,7 +791,7 @@ class UICatalogApp {
 			miIsMouseDisabled!.Checked = Application.IsMouseDisabled;
 			miIsMouseDisabled!.Checked = Application.IsMouseDisabled;
 
 
 			int height = ShowStatusBar ? 1 : 0; // + (MenuBar.Visible ? 1 : 0);
 			int height = ShowStatusBar ? 1 : 0; // + (MenuBar.Visible ? 1 : 0);
-			//ContentPane.Height = Dim.Fill (height);
+							    //ContentPane.Height = Dim.Fill (height);
 
 
 			StatusBar.Visible = ShowStatusBar;
 			StatusBar.Visible = ShowStatusBar;
 
 

+ 1 - 0
UICatalog/UICatalog.csproj

@@ -32,6 +32,7 @@
     <PackageReference Include="SixLabors.ImageSharp" Version="3.1.1" />
     <PackageReference Include="SixLabors.ImageSharp" Version="3.1.1" />
     <PackageReference Include="CsvHelper" Version="30.0.1" />
     <PackageReference Include="CsvHelper" Version="30.0.1" />
     <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
     <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
+    <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />

+ 37 - 27
UnitTests/Application/ApplicationTests.cs

@@ -1,5 +1,6 @@
 using System;
 using System;
 using System.Diagnostics;
 using System.Diagnostics;
+using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading;
@@ -17,7 +18,9 @@ public class ApplicationTests {
 
 
 	public ApplicationTests (ITestOutputHelper output)
 	public ApplicationTests (ITestOutputHelper output)
 	{
 	{
-		this._output = output;
+		_output = output;
+		ConsoleDriver.RunningUnitTests = true;
+
 #if DEBUG_IDISPOSABLE
 #if DEBUG_IDISPOSABLE
 		Responder.Instances.Clear ();
 		Responder.Instances.Clear ();
 		RunState.Instances.Clear ();
 		RunState.Instances.Clear ();
@@ -52,10 +55,7 @@ public class ApplicationTests {
 		Assert.NotNull (SynchronizationContext.Current);
 		Assert.NotNull (SynchronizationContext.Current);
 	}
 	}
 
 
-	void Shutdown ()
-	{
-		Application.Shutdown ();
-	}
+	void Shutdown () => Application.Shutdown ();
 
 
 	[Fact]
 	[Fact]
 	public void Init_Shutdown_Cleans_Up ()
 	public void Init_Shutdown_Cleans_Up ()
@@ -73,10 +73,10 @@ public class ApplicationTests {
 		// Verify state is back to initial
 		// Verify state is back to initial
 		//Pre_Init_State ();
 		//Pre_Init_State ();
 #if DEBUG_IDISPOSABLE
 #if DEBUG_IDISPOSABLE
-			// Validate there are no outstanding Responder-based instances 
-			// after a scenario was selected to run. This proves the main UI Catalog
-			// 'app' closed cleanly.
-			Assert.Empty (Responder.Instances);
+		// Validate there are no outstanding Responder-based instances 
+		// after a scenario was selected to run. This proves the main UI Catalog
+		// 'app' closed cleanly.
+		Assert.Empty (Responder.Instances);
 #endif
 #endif
 	}
 	}
 
 
@@ -106,10 +106,7 @@ public class ApplicationTests {
 	}
 	}
 
 
 	class TestToplevel : Toplevel {
 	class TestToplevel : Toplevel {
-		public TestToplevel ()
-		{
-			IsOverlappedContainer = false;
-		}
+		public TestToplevel () => IsOverlappedContainer = false;
 	}
 	}
 
 
 	[Fact]
 	[Fact]
@@ -122,6 +119,21 @@ public class ApplicationTests {
 		Shutdown ();
 		Shutdown ();
 	}
 	}
 
 
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void Init_DriverName_Should_Pick_Correct_Driver (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		Application.Init (driverName: driverType.Name);
+		Assert.NotNull (Application.Driver);
+		Assert.Equal (driverType, Application.Driver.GetType ());
+		Shutdown ();
+	}
+
 	[Fact]
 	[Fact]
 	public void Init_Begin_End_Cleans_Up ()
 	public void Init_Begin_End_Cleans_Up ()
 	{
 	{
@@ -140,7 +152,7 @@ public class ApplicationTests {
 		};
 		};
 		Application.NotifyNewRunState += NewRunStateFn;
 		Application.NotifyNewRunState += NewRunStateFn;
 
 
-		Toplevel topLevel = new Toplevel ();
+		var topLevel = new Toplevel ();
 		var rs = Application.Begin (topLevel);
 		var rs = Application.Begin (topLevel);
 		Assert.NotNull (rs);
 		Assert.NotNull (rs);
 		Assert.NotNull (runstate);
 		Assert.NotNull (runstate);
@@ -225,7 +237,6 @@ public class ApplicationTests {
 	}
 	}
 
 
 	#region RunTests
 	#region RunTests
-
 	[Fact]
 	[Fact]
 	public void Run_T_After_InitWithDriver_with_TopLevel_Throws ()
 	public void Run_T_After_InitWithDriver_with_TopLevel_Throws ()
 	{
 	{
@@ -249,7 +260,7 @@ public class ApplicationTests {
 		Init ();
 		Init ();
 
 
 		// Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not dervied from TopLevel)
 		// Run<Toplevel> when already initialized with a Driver will throw (because Toplevel is not dervied from TopLevel)
-		Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> (errorHandler: null, new FakeDriver ()));
+		Assert.Throws<ArgumentException> (() => Application.Run<Toplevel> (null, new FakeDriver ()));
 
 
 		Shutdown ();
 		Shutdown ();
 
 
@@ -281,7 +292,7 @@ public class ApplicationTests {
 	[Fact]
 	[Fact]
 	public void Run_T_After_InitNullDriver_with_TestTopLevel_Throws ()
 	public void Run_T_After_InitNullDriver_with_TestTopLevel_Throws ()
 	{
 	{
-		Application._forceFakeConsole = true;
+		Application.ForceDriver = "FakeDriver";
 
 
 		Application.Init (null);
 		Application.Init (null);
 		Assert.Equal (typeof (FakeDriver), Application.Driver.GetType ());
 		Assert.Equal (typeof (FakeDriver), Application.Driver.GetType ());
@@ -324,7 +335,7 @@ public class ApplicationTests {
 	[Fact]
 	[Fact]
 	public void Run_T_NoInit_DoesNotThrow ()
 	public void Run_T_NoInit_DoesNotThrow ()
 	{
 	{
-		Application._forceFakeConsole = true;
+		Application.ForceDriver = "FakeDriver";
 
 
 		Application.Iteration += (s, a) => {
 		Application.Iteration += (s, a) => {
 			Application.RequestStop ();
 			Application.RequestStop ();
@@ -348,7 +359,7 @@ public class ApplicationTests {
 		};
 		};
 
 
 		// Init has NOT been called and we're passing a valid driver to Run<TestTopLevel>. This is ok.
 		// Init has NOT been called and we're passing a valid driver to Run<TestTopLevel>. This is ok.
-		Application.Run<TestToplevel> (errorHandler: null, new FakeDriver ());
+		Application.Run<TestToplevel> (null, new FakeDriver ());
 
 
 		Shutdown ();
 		Shutdown ();
 
 
@@ -410,7 +421,7 @@ public class ApplicationTests {
 	{
 	{
 		Init ();
 		Init ();
 		var top = Application.Top;
 		var top = Application.Top;
-		var count = 0;
+		int count = 0;
 		top.Loaded += (s, e) => count++;
 		top.Loaded += (s, e) => count++;
 		top.Ready += (s, e) => count++;
 		top.Ready += (s, e) => count++;
 		top.Unloaded += (s, e) => count++;
 		top.Unloaded += (s, e) => count++;
@@ -425,12 +436,12 @@ public class ApplicationTests {
 	public void Run_Toplevel_With_Modal_View_Does_Not_Refresh_If_Not_Dirty ()
 	public void Run_Toplevel_With_Modal_View_Does_Not_Refresh_If_Not_Dirty ()
 	{
 	{
 		Init ();
 		Init ();
-		var count = 0;
+		int count = 0;
 		// Don't use Dialog here as it has more layout logic. Use Window instead.
 		// Don't use Dialog here as it has more layout logic. Use Window instead.
 		Dialog d = null;
 		Dialog d = null;
 		var top = Application.Top;
 		var top = Application.Top;
 		top.DrawContent += (s, a) => count++;
 		top.DrawContent += (s, a) => count++;
-		var iteration = -1;
+		int iteration = -1;
 		Application.Iteration += (s, a) => {
 		Application.Iteration += (s, a) => {
 			iteration++;
 			iteration++;
 			if (iteration == 0) {
 			if (iteration == 0) {
@@ -439,7 +450,7 @@ public class ApplicationTests {
 				d.DrawContent += (s, a) => count++;
 				d.DrawContent += (s, a) => count++;
 				Application.Run (d);
 				Application.Run (d);
 			} else if (iteration < 3) {
 			} else if (iteration < 3) {
-				Application.OnMouseEvent (new (new () { X = 0, Y = 0, Flags = MouseFlags.ReportMousePosition }));
+				Application.OnMouseEvent (new MouseEventEventArgs (new MouseEvent { X = 0, Y = 0, Flags = MouseFlags.ReportMousePosition }));
 				Assert.False (top.NeedsDisplay);
 				Assert.False (top.NeedsDisplay);
 				Assert.False (top.SubViewNeedsDisplay);
 				Assert.False (top.SubViewNeedsDisplay);
 				Assert.False (top.LayoutNeeded);
 				Assert.False (top.LayoutNeeded);
@@ -521,7 +532,6 @@ public class ApplicationTests {
 	}
 	}
 
 
 	// TODO: Add tests for Run that test errorHandler
 	// TODO: Add tests for Run that test errorHandler
-
 	#endregion
 	#endregion
 
 
 	#region ShutdownTests
 	#region ShutdownTests
@@ -556,7 +566,7 @@ public class ApplicationTests {
 	}
 	}
 	#endregion
 	#endregion
 
 
-	[Fact, AutoInitShutdown]
+	[Fact] [AutoInitShutdown]
 	public void Begin_Sets_Application_Top_To_Console_Size ()
 	public void Begin_Sets_Application_Top_To_Console_Size ()
 	{
 	{
 		Assert.Equal (new Rect (0, 0, 80, 25), Application.Top.Frame);
 		Assert.Equal (new Rect (0, 0, 80, 25), Application.Top.Frame);
@@ -580,7 +590,7 @@ public class ApplicationTests {
 		var t4 = new Toplevel ();
 		var t4 = new Toplevel ();
 
 
 		// t1, t2, t3, d, t4
 		// t1, t2, t3, d, t4
-		var iterations = 5;
+		int iterations = 5;
 
 
 		t1.Ready += (s, e) => {
 		t1.Ready += (s, e) => {
 			Assert.Equal (t1, Application.Top);
 			Assert.Equal (t1, Application.Top);
@@ -667,7 +677,7 @@ public class ApplicationTests {
 		var rs = Application.Begin (top);
 		var rs = Application.Begin (top);
 		bool firstIteration = false;
 		bool firstIteration = false;
 
 
-		var actionCalled = 0;
+		int actionCalled = 0;
 		Application.Invoke (() => { actionCalled++; });
 		Application.Invoke (() => { actionCalled++; });
 		Application.MainLoop.Running = true;
 		Application.MainLoop.Running = true;
 		Application.RunIteration (ref rs, ref firstIteration);
 		Application.RunIteration (ref rs, ref firstIteration);

+ 12 - 10
UnitTests/ConsoleDrivers/AddRuneTests.cs

@@ -7,20 +7,22 @@ using Xunit.Abstractions;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 
 
 namespace Terminal.Gui.DriverTests;
 namespace Terminal.Gui.DriverTests;
+
 public class AddRuneTests {
 public class AddRuneTests {
 	readonly ITestOutputHelper _output;
 	readonly ITestOutputHelper _output;
 
 
 	public AddRuneTests (ITestOutputHelper output)
 	public AddRuneTests (ITestOutputHelper output)
 	{
 	{
 		ConsoleDriver.RunningUnitTests = true;
 		ConsoleDriver.RunningUnitTests = true;
-		this._output = output;
+		_output = output;
 	}
 	}
 
 
 	[Theory]
 	[Theory]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (NetDriver))]
 	[InlineData (typeof (NetDriver))]
-	[InlineData (typeof (CursesDriver))]
+	//[InlineData (typeof (ANSIDriver))]
 	[InlineData (typeof (WindowsDriver))]
 	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
 	public void AddRune (Type driverType)
 	public void AddRune (Type driverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
@@ -44,8 +46,8 @@ public class AddRuneTests {
 		driver.Move (driver.Cols, driver.Rows);
 		driver.Move (driver.Cols, driver.Rows);
 		driver.AddRune ('a');
 		driver.AddRune ('a');
 
 
-		for (var col = 0; col < driver.Cols; col++) {
-			for (var row = 0; row < driver.Rows; row++) {
+		for (int col = 0; col < driver.Cols; col++) {
+			for (int row = 0; row < driver.Rows; row++) {
 				Assert.Equal ((Rune)' ', driver.Contents [row, col].Rune);
 				Assert.Equal ((Rune)' ', driver.Contents [row, col].Rune);
 			}
 			}
 		}
 		}
@@ -70,7 +72,7 @@ public class AddRuneTests {
 		Assert.Equal (2, driver.Col);
 		Assert.Equal (2, driver.Col);
 
 
 		// Move to the last column of the first row
 		// Move to the last column of the first row
-		var lastCol = driver.Cols - 1;
+		int lastCol = driver.Cols - 1;
 		driver.Move (lastCol, 0);
 		driver.Move (lastCol, 0);
 		Assert.Equal (0, driver.Row);
 		Assert.Equal (0, driver.Row);
 		Assert.Equal (lastCol, driver.Col);
 		Assert.Equal (lastCol, driver.Col);
@@ -83,8 +85,8 @@ public class AddRuneTests {
 		// Add a rune; should succeed but do nothing as it's outside of Contents
 		// Add a rune; should succeed but do nothing as it's outside of Contents
 		driver.AddRune ('d');
 		driver.AddRune ('d');
 		Assert.Equal (lastCol + 2, driver.Col);
 		Assert.Equal (lastCol + 2, driver.Col);
-		for (var col = 0; col < driver.Cols; col++) {
-			for (var row = 0; row < driver.Rows; row++) {
+		for (int col = 0; col < driver.Cols; col++) {
+			for (int row = 0; row < driver.Rows; row++) {
 				Assert.NotEqual ((Rune)'d', driver.Contents [row, col].Rune);
 				Assert.NotEqual ((Rune)'d', driver.Contents [row, col].Rune);
 			}
 			}
 		}
 		}
@@ -99,7 +101,7 @@ public class AddRuneTests {
 		driver.Init ();
 		driver.Init ();
 
 
 		// 🍕 Slice of Pizza "\U0001F355"
 		// 🍕 Slice of Pizza "\U0001F355"
-		var operationStatus = Rune.DecodeFromUtf16 ("\U0001F355", out Rune rune, out int charsConsumed);
+		var operationStatus = Rune.DecodeFromUtf16 ("\U0001F355", out var rune, out int charsConsumed);
 		Assert.Equal (OperationStatus.Done, operationStatus);
 		Assert.Equal (OperationStatus.Done, operationStatus);
 		Assert.Equal (charsConsumed, rune.Utf16SequenceLength);
 		Assert.Equal (charsConsumed, rune.Utf16SequenceLength);
 		Assert.Equal (2, rune.GetColumns ());
 		Assert.Equal (2, rune.GetColumns ());
@@ -145,7 +147,7 @@ public class AddRuneTests {
 
 
 		var expected = new Rune ('ắ');
 		var expected = new Rune ('ắ');
 
 
-		var text = "\u1eaf";
+		string text = "\u1eaf";
 		driver.AddStr (text);
 		driver.AddStr (text);
 		Assert.Equal (expected, driver.Contents [0, 0].Rune);
 		Assert.Equal (expected, driver.Contents [0, 0].Rune);
 		Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune);
 		Assert.Equal ((Rune)' ', driver.Contents [0, 1].Rune);
@@ -188,4 +190,4 @@ public class AddRuneTests {
 		//ắ", output);
 		//ắ", output);
 		driver.End ();
 		driver.End ();
 	}
 	}
-}
+}

+ 121 - 104
UnitTests/ConsoleDrivers/ClipRegionTests.cs

@@ -9,108 +9,125 @@ using Xunit.Abstractions;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.DriverTests {
-	public class ClipRegionTests {
-		readonly ITestOutputHelper output;
-
-		public ClipRegionTests (ITestOutputHelper output)
-		{
-			this.output = output;
-		}
-		
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void IsValidLocation (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			// positive
-			Assert.True (driver.IsValidLocation (0, 0));
-			Assert.True (driver.IsValidLocation (1, 1));
-			Assert.True (driver.IsValidLocation (driver.Cols - 1, driver.Rows - 1));
-			// negative
-			Assert.False (driver.IsValidLocation (-1, 0));
-			Assert.False (driver.IsValidLocation (0, -1));
-			Assert.False (driver.IsValidLocation (-1, -1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows));
-
-			// Define a clip rectangle
-			driver.Clip = new Rect (5, 5, 5, 5);
-			// positive
-			Assert.True (driver.IsValidLocation (5, 5));
-			Assert.True (driver.IsValidLocation (9, 9));
-			// negative
-			Assert.False (driver.IsValidLocation (4, 5));
-			Assert.False (driver.IsValidLocation (5, 4));
-			Assert.False (driver.IsValidLocation (10, 9));
-			Assert.False (driver.IsValidLocation (9, 10));
-			Assert.False (driver.IsValidLocation (-1, 0));
-			Assert.False (driver.IsValidLocation (0, -1));
-			Assert.False (driver.IsValidLocation (-1, -1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows));
-
-			Application.Shutdown ();
-		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void Clip_Set_To_Empty_AllInvalid (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			// Define a clip rectangle
-			driver.Clip = Rect.Empty;
-
-			// negative
-			Assert.False (driver.IsValidLocation (4, 5));
-			Assert.False (driver.IsValidLocation (5, 4));
-			Assert.False (driver.IsValidLocation (10, 9));
-			Assert.False (driver.IsValidLocation (9, 10));
-			Assert.False (driver.IsValidLocation (-1, 0));
-			Assert.False (driver.IsValidLocation (0, -1));
-			Assert.False (driver.IsValidLocation (-1, -1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
-			Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows));
-
-			Application.Shutdown ();
-		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void AddRune_Is_Clipped (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			driver.Move (0, 0);
-			driver.AddRune ('x');
-			Assert.Equal ((Rune)'x', driver.Contents [0, 0].Rune);
-
-			driver.Move (5, 5);
-			driver.AddRune ('x');
-			Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune);
-
-			// Clear the contents
-			driver.FillRect (new Rect (0, 0, driver.Rows, driver.Cols), ' ');
-			Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune);
-
-			// Setup the region with a single rectangle, fill screen with 'x'
-			driver.Clip = new Rect (5, 5, 5, 5);
-			driver.FillRect (new Rect (0, 0, driver.Rows, driver.Cols), 'x');
-			Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune);
-			Assert.Equal ((Rune)' ', driver.Contents [4, 9].Rune);
-			Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune);
-			Assert.Equal ((Rune)'x', driver.Contents [9, 9].Rune);
-			Assert.Equal ((Rune)' ', driver.Contents [10, 10].Rune);
-
-			Application.Shutdown ();
-		}
+namespace Terminal.Gui.DriverTests; 
+
+public class ClipRegionTests {
+	readonly ITestOutputHelper output;
+
+	public ClipRegionTests (ITestOutputHelper output)
+	{
+		ConsoleDriver.RunningUnitTests = true;
+		this.output = output;
+	}
+
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void IsValidLocation (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		Application.Init (driver);
+		Application.Driver.Rows = 10;
+		Application.Driver.Cols = 10;
+
+		// positive
+		Assert.True (driver.IsValidLocation (0, 0));
+		Assert.True (driver.IsValidLocation (1, 1));
+		Assert.True (driver.IsValidLocation (driver.Cols - 1, driver.Rows - 1));
+		// negative
+		Assert.False (driver.IsValidLocation (-1, 0));
+		Assert.False (driver.IsValidLocation (0, -1));
+		Assert.False (driver.IsValidLocation (-1, -1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows));
+
+		// Define a clip rectangle
+		driver.Clip = new Rect (5, 5, 5, 5);
+		// positive
+		Assert.True (driver.IsValidLocation (5, 5));
+		Assert.True (driver.IsValidLocation (9, 9));
+		// negative
+		Assert.False (driver.IsValidLocation (4, 5));
+		Assert.False (driver.IsValidLocation (5, 4));
+		Assert.False (driver.IsValidLocation (10, 9));
+		Assert.False (driver.IsValidLocation (9, 10));
+		Assert.False (driver.IsValidLocation (-1, 0));
+		Assert.False (driver.IsValidLocation (0, -1));
+		Assert.False (driver.IsValidLocation (-1, -1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows));
+
+		Application.Shutdown ();
+	}
+
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void Clip_Set_To_Empty_AllInvalid (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		Application.Init (driver);
+
+		// Define a clip rectangle
+		driver.Clip = Rect.Empty;
+
+		// negative
+		Assert.False (driver.IsValidLocation (4, 5));
+		Assert.False (driver.IsValidLocation (5, 4));
+		Assert.False (driver.IsValidLocation (10, 9));
+		Assert.False (driver.IsValidLocation (9, 10));
+		Assert.False (driver.IsValidLocation (-1, 0));
+		Assert.False (driver.IsValidLocation (0, -1));
+		Assert.False (driver.IsValidLocation (-1, -1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows - 1));
+		Assert.False (driver.IsValidLocation (driver.Cols, driver.Rows));
+
+		Application.Shutdown ();
+	}
+
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void AddRune_Is_Clipped (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		Application.Init (driver);
+		Application.Driver.Rows = 25;
+		Application.Driver.Cols = 80;
+
+		driver.Move (0, 0);
+		driver.AddRune ('x');
+		Assert.Equal ((Rune)'x', driver.Contents [0, 0].Rune);
+
+		driver.Move (5, 5);
+		driver.AddRune ('x');
+		Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune);
+
+		// Clear the contents
+		driver.FillRect (new Rect (0, 0, driver.Rows, driver.Cols), ' ');
+		Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune);
+
+		// Setup the region with a single rectangle, fill screen with 'x'
+		driver.Clip = new Rect (5, 5, 5, 5);
+		driver.FillRect (new Rect (0, 0, driver.Rows, driver.Cols), 'x');
+		Assert.Equal ((Rune)' ', driver.Contents [0, 0].Rune);
+		Assert.Equal ((Rune)' ', driver.Contents [4, 9].Rune);
+		Assert.Equal ((Rune)'x', driver.Contents [5, 5].Rune);
+		Assert.Equal ((Rune)'x', driver.Contents [9, 9].Rune);
+		Assert.Equal ((Rune)' ', driver.Contents [10, 10].Rune);
+
+		Application.Shutdown ();
 	}
 	}
-}
+}

+ 254 - 247
UnitTests/ConsoleDrivers/ConsoleDriverTests.cs

@@ -8,264 +8,271 @@ using Xunit.Abstractions;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.DriverTests {
-	public class ConsoleDriverTests {
-		readonly ITestOutputHelper output;
-
-		public ConsoleDriverTests (ITestOutputHelper output)
-		{
-			ConsoleDriver.RunningUnitTests = true;
-			this.output = output;
-		}
+namespace Terminal.Gui.DriverTests; 
 
 
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		[InlineData (typeof (NetDriver))]
-		[InlineData (typeof (CursesDriver))]
-		[InlineData (typeof (WindowsDriver))]
-		public void Init_Inits (Type driverType)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			var ml = driver.Init ();
-			Assert.NotNull (ml);
-			Assert.NotNull (driver.Clipboard);
-			Console.ForegroundColor = ConsoleColor.Red;
-			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
-			Console.BackgroundColor = ConsoleColor.Green;
-			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
-
-			driver.End ();
-		}
+public class ConsoleDriverTests {
+	readonly ITestOutputHelper output;
 
 
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		[InlineData (typeof (NetDriver))]
-		[InlineData (typeof (CursesDriver))]
-		[InlineData (typeof (WindowsDriver))]
-		public void End_Cleans_Up (Type driverType)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			driver.Init ();
-			driver.End ();
-		}
+	public ConsoleDriverTests (ITestOutputHelper output)
+	{
+		ConsoleDriver.RunningUnitTests = true;
+		this.output = output;
+	}
 
 
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void FakeDriver_Only_Sends_Keystrokes_Through_MockKeyPresses (Type driverType)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void Init_Inits (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		var ml = driver.Init ();
+		Assert.NotNull (ml);
+		Assert.NotNull (driver.Clipboard);
+		Console.ForegroundColor = ConsoleColor.Red;
+		Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
+		Console.BackgroundColor = ConsoleColor.Green;
+		Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
+
+		driver.End ();
+	}
 
 
-			var top = Application.Top;
-			var view = new View () {
-				CanFocus = true
-			};
-			var count = 0;
-			var wasKeyPressed = false;
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void End_Cleans_Up (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		driver.Init ();
+		driver.End ();
+	}
 
 
-			view.KeyDown += (s, e) => {
-				wasKeyPressed = true;
-			};
-			top.Add (view);
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	public void FakeDriver_Only_Sends_Keystrokes_Through_MockKeyPresses (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		Application.Init (driver);
+
+		var top = Application.Top;
+		var view = new View () {
+			CanFocus = true
+		};
+		int count = 0;
+		bool wasKeyPressed = false;
+
+		view.KeyDown += (s, e) => {
+			wasKeyPressed = true;
+		};
+		top.Add (view);
+
+		Application.Iteration += (s, a) => {
+			count++;
+			if (count == 10) {
+				Application.RequestStop ();
+			}
+		};
 
 
-			Application.Iteration += (s, a) => {
-				count++;
-				if (count == 10) Application.RequestStop ();
-			};
+		Application.Run ();
 
 
-			Application.Run ();
+		Assert.False (wasKeyPressed);
 
 
-			Assert.False (wasKeyPressed);
+		// Shutdown must be called to safely clean up Application if Init has been called
+		Application.Shutdown ();
+	}
 
 
-			// Shutdown must be called to safely clean up Application if Init has been called
-			Application.Shutdown ();
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	public void FakeDriver_MockKeyPresses (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		Application.Init (driver);
+
+		string text = "MockKeyPresses";
+		var mKeys = new Stack<ConsoleKeyInfo> ();
+		foreach (char r in text.Reverse ()) {
+			var ck = char.IsLetter (r) ? (ConsoleKey)char.ToUpper (r) : (ConsoleKey)r;
+			var cki = new ConsoleKeyInfo (r, ck, false, false, false);
+			mKeys.Push (cki);
 		}
 		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void FakeDriver_MockKeyPresses (Type driverType)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			var text = "MockKeyPresses";
-			var mKeys = new Stack<ConsoleKeyInfo> ();
-			foreach (var r in text.Reverse ()) {
-				var ck = char.IsLetter (r) ? (ConsoleKey)char.ToUpper (r) : (ConsoleKey)r;
-				var cki = new ConsoleKeyInfo (r, ck, false, false, false);
-				mKeys.Push (cki);
+		Console.MockKeyPresses = mKeys;
+
+		var top = Application.Top;
+		var view = new View () {
+			CanFocus = true
+		};
+		string rText = "";
+		int idx = 0;
+
+		view.KeyDown += (s, e) => {
+			Assert.Equal (text [idx], (char)e.KeyCode);
+			rText += (char)e.KeyCode;
+			Assert.Equal (rText, text.Substring (0, idx + 1));
+			e.Handled = true;
+			idx++;
+		};
+		top.Add (view);
+
+		Application.Iteration += (s, a) => {
+			if (mKeys.Count == 0) {
+				Application.RequestStop ();
 			}
 			}
-			Console.MockKeyPresses = mKeys;
-
-			var top = Application.Top;
-			var view = new View () {
-				CanFocus = true
-			};
-			var rText = "";
-			var idx = 0;
-
-			view.KeyDown += (s, e) => {
-				Assert.Equal (text [idx], (char)e.KeyCode);
-				rText += (char)e.KeyCode;
-				Assert.Equal (rText, text.Substring (0, idx + 1));
-				e.Handled = true;
-				idx++;
-			};
-			top.Add (view);
-
-			Application.Iteration += (s, a) => {
-				if (mKeys.Count == 0) Application.RequestStop ();
-			};
-
-			Application.Run ();
-
-			Assert.Equal ("MockKeyPresses", rText);
-
-			// Shutdown must be called to safely clean up Application if Init has been called
-			Application.Shutdown ();
-		}
+		};
 
 
-		//[Theory]
-		//[InlineData (typeof (FakeDriver))]
-		//public void FakeDriver_MockKeyPresses_Press_AfterTimeOut (Type driverType)
-		//{
-		//	var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-		//	Application.Init (driver);
-
-		//	// Simulating pressing of QuitKey after a short period of time
-		//	uint quitTime = 100;
-		//	Func<MainLoop, bool> closeCallback = (MainLoop loop) => {
-		//		// Prove the scenario is using Application.QuitKey correctly
-		//		output.WriteLine ($"  {quitTime}ms elapsed; Simulating keypresses...");
-		//		FakeConsole.PushMockKeyPress (Key.F);
-		//		FakeConsole.PushMockKeyPress (Key.U);
-		//		FakeConsole.PushMockKeyPress (Key.C);
-		//		FakeConsole.PushMockKeyPress (Key.K);
-		//		return false;
-		//	};
-		//	output.WriteLine ($"Add timeout to simulate key presses after {quitTime}ms");
-		//	_ = Application.AddTimeout (TimeSpan.FromMilliseconds (quitTime), closeCallback);
-
-		//	// If Top doesn't quit within abortTime * 5 (500ms), this will force it
-		//	uint abortTime = quitTime * 5;
-		//	Func<MainLoop, bool> forceCloseCallback = (MainLoop loop) => {
-		//		Application.RequestStop ();
-		//		Assert.Fail ($"  failed to Quit after {abortTime}ms. Force quit.");
-		//		return false;
-		//	};
-		//	output.WriteLine ($"Add timeout to force quit after {abortTime}ms");
-		//	_ = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), forceCloseCallback);
-
-		//	Key key = Key.Unknown;
-			
-		//	Application.Top.KeyPress += (e) => {
-		//		key = e.Key;
-		//		output.WriteLine ($"  Application.Top.KeyPress: {key}");
-		//		e.Handled = true;
-				
-		//	};
-
-		//	int iterations = 0;
-		//	Application.Iteration += (s, a) => {
-		//		output.WriteLine ($"  iteration {++iterations}");
-
-		//		if (Console.MockKeyPresses.Count == 0) {
-		//			output.WriteLine ($"    No more MockKeyPresses; RequestStop");
-		//			Application.RequestStop ();
-		//		}
-		//	};
-
-		//	Application.Run ();
-
-		//	// Shutdown must be called to safely clean up Application if Init has been called
-		//	Application.Shutdown ();
-		//}
-		
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		[InlineData (typeof (NetDriver))]
-		[InlineData (typeof (CursesDriver))]
-		[InlineData (typeof (WindowsDriver))]
-		public void TerminalResized_Simulation (Type driverType)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			driver?.Init ();
-			driver.Cols = 80;
-			driver.Rows = 25;
-			
-			var wasTerminalResized = false;
-			driver.SizeChanged += (s, e) => {
-				wasTerminalResized = true;
-				Assert.Equal (120, e.Size.Width);
-				Assert.Equal (40, e.Size.Height);
-			};
-
-			Assert.Equal (80, driver.Cols);
-			Assert.Equal (25, driver.Rows);
-			Assert.False (wasTerminalResized);
-
-			driver.Cols = 120;
-			driver.Rows = 40;
-			driver.OnSizeChanged (new SizeChangedEventArgs(new Size(driver.Cols, driver.Rows)));
-			Assert.Equal (120, driver.Cols);
-			Assert.Equal (40, driver.Rows);
-			Assert.True (wasTerminalResized);
-			driver.End ();
-		}
+		Application.Run ();
+
+		Assert.Equal ("MockKeyPresses", rText);
 
 
-		// Disabled due to test error - Change Task.Delay to an await
-		//		[Fact, AutoInitShutdown]
-		//		public void Write_Do_Not_Change_On_ProcessKey ()
-		//		{
-		//			var win = new Window ();
-		//			Application.Begin (win);
-		//			((FakeDriver)Application.Driver).SetBufferSize (20, 8);
-
-		//			System.Threading.Tasks.Task.Run (() => {
-		//				System.Threading.Tasks.Task.Delay (500).Wait ();
-		//				Application.Invoke (() => {
-		//					var lbl = new Label ("Hello World") { X = Pos.Center () };
-		//					var dlg = new Dialog ();
-		//					dlg.Add (lbl);
-		//					Application.Begin (dlg);
-
-		//					var expected = @"
-		//┌──────────────────┐
-		//│┌───────────────┐ │
-		//││  Hello World  │ │
-		//││               │ │
-		//││               │ │
-		//││               │ │
-		//│└───────────────┘ │
-		//└──────────────────┘
-		//";
-
-		//					var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-		//					Assert.Equal (new Rect (0, 0, 20, 8), pos);
-
-		//					Assert.True (dlg.ProcessKey (new (Key.Tab)));
-		//					dlg.Draw ();
-
-		//					expected = @"
-		//┌──────────────────┐
-		//│┌───────────────┐ │
-		//││  Hello World  │ │
-		//││               │ │
-		//││               │ │
-		//││               │ │
-		//│└───────────────┘ │
-		//└──────────────────┘
-		//";
-
-		//					pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
-		//					Assert.Equal (new Rect (0, 0, 20, 8), pos);
-
-		//					win.RequestStop ();
-		//				});
-		//			});
-
-		//			Application.Run (win);
-		//			Application.Shutdown ();
-		//		}
+		// Shutdown must be called to safely clean up Application if Init has been called
+		Application.Shutdown ();
 	}
 	}
-}
+
+	//[Theory]
+	//[InlineData (typeof (FakeDriver))]
+	//public void FakeDriver_MockKeyPresses_Press_AfterTimeOut (Type driverType)
+	//{
+	//	var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+	//	Application.Init (driver);
+
+	//	// Simulating pressing of QuitKey after a short period of time
+	//	uint quitTime = 100;
+	//	Func<MainLoop, bool> closeCallback = (MainLoop loop) => {
+	//		// Prove the scenario is using Application.QuitKey correctly
+	//		output.WriteLine ($"  {quitTime}ms elapsed; Simulating keypresses...");
+	//		FakeConsole.PushMockKeyPress (Key.F);
+	//		FakeConsole.PushMockKeyPress (Key.U);
+	//		FakeConsole.PushMockKeyPress (Key.C);
+	//		FakeConsole.PushMockKeyPress (Key.K);
+	//		return false;
+	//	};
+	//	output.WriteLine ($"Add timeout to simulate key presses after {quitTime}ms");
+	//	_ = Application.AddTimeout (TimeSpan.FromMilliseconds (quitTime), closeCallback);
+
+	//	// If Top doesn't quit within abortTime * 5 (500ms), this will force it
+	//	uint abortTime = quitTime * 5;
+	//	Func<MainLoop, bool> forceCloseCallback = (MainLoop loop) => {
+	//		Application.RequestStop ();
+	//		Assert.Fail ($"  failed to Quit after {abortTime}ms. Force quit.");
+	//		return false;
+	//	};
+	//	output.WriteLine ($"Add timeout to force quit after {abortTime}ms");
+	//	_ = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), forceCloseCallback);
+
+	//	Key key = Key.Unknown;
+
+	//	Application.Top.KeyPress += (e) => {
+	//		key = e.Key;
+	//		output.WriteLine ($"  Application.Top.KeyPress: {key}");
+	//		e.Handled = true;
+
+	//	};
+
+	//	int iterations = 0;
+	//	Application.Iteration += (s, a) => {
+	//		output.WriteLine ($"  iteration {++iterations}");
+
+	//		if (Console.MockKeyPresses.Count == 0) {
+	//			output.WriteLine ($"    No more MockKeyPresses; RequestStop");
+	//			Application.RequestStop ();
+	//		}
+	//	};
+
+	//	Application.Run ();
+
+	//	// Shutdown must be called to safely clean up Application if Init has been called
+	//	Application.Shutdown ();
+	//}
+
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void TerminalResized_Simulation (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		driver?.Init ();
+		driver.Cols = 80;
+		driver.Rows = 25;
+
+		bool wasTerminalResized = false;
+		driver.SizeChanged += (s, e) => {
+			wasTerminalResized = true;
+			Assert.Equal (120, e.Size.Width);
+			Assert.Equal (40, e.Size.Height);
+		};
+
+		Assert.Equal (80, driver.Cols);
+		Assert.Equal (25, driver.Rows);
+		Assert.False (wasTerminalResized);
+
+		driver.Cols = 120;
+		driver.Rows = 40;
+		driver.OnSizeChanged (new SizeChangedEventArgs (new Size (driver.Cols, driver.Rows)));
+		Assert.Equal (120, driver.Cols);
+		Assert.Equal (40, driver.Rows);
+		Assert.True (wasTerminalResized);
+		driver.End ();
+	}
+
+	// Disabled due to test error - Change Task.Delay to an await
+	//		[Fact, AutoInitShutdown]
+	//		public void Write_Do_Not_Change_On_ProcessKey ()
+	//		{
+	//			var win = new Window ();
+	//			Application.Begin (win);
+	//			((FakeDriver)Application.Driver).SetBufferSize (20, 8);
+
+	//			System.Threading.Tasks.Task.Run (() => {
+	//				System.Threading.Tasks.Task.Delay (500).Wait ();
+	//				Application.Invoke (() => {
+	//					var lbl = new Label ("Hello World") { X = Pos.Center () };
+	//					var dlg = new Dialog ();
+	//					dlg.Add (lbl);
+	//					Application.Begin (dlg);
+
+	//					var expected = @"
+	//┌──────────────────┐
+	//│┌───────────────┐ │
+	//││  Hello World  │ │
+	//││               │ │
+	//││               │ │
+	//││               │ │
+	//│└───────────────┘ │
+	//└──────────────────┘
+	//";
+
+	//					var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
+	//					Assert.Equal (new Rect (0, 0, 20, 8), pos);
+
+	//					Assert.True (dlg.ProcessKey (new (Key.Tab)));
+	//					dlg.Draw ();
+
+	//					expected = @"
+	//┌──────────────────┐
+	//│┌───────────────┐ │
+	//││  Hello World  │ │
+	//││               │ │
+	//││               │ │
+	//││               │ │
+	//│└───────────────┘ │
+	//└──────────────────┘
+	//";
+
+	//					pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
+	//					Assert.Equal (new Rect (0, 0, 20, 8), pos);
+
+	//					win.RequestStop ();
+	//				});
+	//			});
+
+	//			Application.Run (win);
+	//			Application.Shutdown ();
+	//		}
+}

+ 31 - 27
UnitTests/ConsoleDrivers/ConsoleScrolllingTests.cs

@@ -8,31 +8,35 @@ using Xunit.Abstractions;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.DriverTests {
-	public class ConsoleScrollingTests {
-		readonly ITestOutputHelper output;
-
-		public ConsoleScrollingTests (ITestOutputHelper output)
-		{
-			this.output = output;
-		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		public void Left_And_Top_Is_Always_Zero (Type driverType)
-		{
-			var driver = (FakeDriver)Activator.CreateInstance (driverType);
-			Application.Init (driver);
-
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			driver.SetWindowPosition (5, 5);
-			Assert.Equal (0, Console.WindowLeft);
-			Assert.Equal (0, Console.WindowTop);
-
-			Application.Shutdown ();
-		}
-		
+namespace Terminal.Gui.DriverTests; 
+
+public class ConsoleScrollingTests {
+	readonly ITestOutputHelper output;
+
+	public ConsoleScrollingTests (ITestOutputHelper output)
+	{
+		ConsoleDriver.RunningUnitTests = true;
+		this.output = output;
+	}
+
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	//[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	//[InlineData (typeof (WindowsDriver))]
+	//[InlineData (typeof (CursesDriver))]
+	public void Left_And_Top_Is_Always_Zero (Type driverType)
+	{
+		var driver = (FakeDriver)Activator.CreateInstance (driverType);
+		Application.Init (driver);
+
+		Assert.Equal (0, Console.WindowLeft);
+		Assert.Equal (0, Console.WindowTop);
+
+		driver.SetWindowPosition (5, 5);
+		Assert.Equal (0, Console.WindowLeft);
+		Assert.Equal (0, Console.WindowTop);
+
+		Application.Shutdown ();
 	}
 	}
-}
+}

+ 12 - 9
UnitTests/ConsoleDrivers/ContentsTests.cs

@@ -10,6 +10,7 @@ using Xunit.Abstractions;
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
 namespace Terminal.Gui.DriverTests;
 namespace Terminal.Gui.DriverTests;
+
 public class ContentsTests {
 public class ContentsTests {
 	readonly ITestOutputHelper output;
 	readonly ITestOutputHelper output;
 
 
@@ -23,13 +24,14 @@ public class ContentsTests {
 	[Theory]
 	[Theory]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (NetDriver))]
 	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
 	//[InlineData (typeof (CursesDriver))] // TODO: Uncomment when #2796 and #2615 are fixed
 	//[InlineData (typeof (CursesDriver))] // TODO: Uncomment when #2796 and #2615 are fixed
 	//[InlineData (typeof (WindowsDriver))] // TODO: Uncomment when #2610 is fixed
 	//[InlineData (typeof (WindowsDriver))] // TODO: Uncomment when #2610 is fixed
 	public void AddStr_Combining_Character_1st_Column (Type driverType)
 	public void AddStr_Combining_Character_1st_Column (Type driverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		driver.Init ();
 		driver.Init ();
-		var expected = "\u0301!";
+		string expected = "\u0301!";
 		driver.AddStr ("\u0301!"); // acute accent + exclamation mark
 		driver.AddStr ("\u0301!"); // acute accent + exclamation mark
 		TestHelpers.AssertDriverContentsAre (expected, output, driver);
 		TestHelpers.AssertDriverContentsAre (expected, output, driver);
 
 
@@ -39,6 +41,7 @@ public class ContentsTests {
 	[Theory]
 	[Theory]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (NetDriver))]
 	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
 	//[InlineData (typeof (CursesDriver))] // TODO: Uncomment when #2796 and #2615 are fixed
 	//[InlineData (typeof (CursesDriver))] // TODO: Uncomment when #2796 and #2615 are fixed
 	//[InlineData (typeof (WindowsDriver))] // TODO: Uncomment when #2610 is fixed
 	//[InlineData (typeof (WindowsDriver))] // TODO: Uncomment when #2610 is fixed
 	public void AddStr_With_Combining_Characters (Type driverType)
 	public void AddStr_With_Combining_Characters (Type driverType)
@@ -46,18 +49,18 @@ public class ContentsTests {
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		driver.Init ();
 		driver.Init ();
 
 
-		var acuteaccent = new System.Text.Rune (0x0301); // Combining acute accent (é)
-		var combined = "e" + acuteaccent;
-		var expected = "é";
+		var acuteaccent = new Rune (0x0301); // Combining acute accent (é)
+		string combined = "e" + acuteaccent;
+		string expected = "é";
 
 
 		driver.AddStr (combined);
 		driver.AddStr (combined);
 		TestHelpers.AssertDriverContentsAre (expected, output, driver);
 		TestHelpers.AssertDriverContentsAre (expected, output, driver);
 
 
 		// 3 char combine
 		// 3 char combine
 		// a + ogonek + acute = <U+0061, U+0328, U+0301> ( ą́ )
 		// a + ogonek + acute = <U+0061, U+0328, U+0301> ( ą́ )
-		var ogonek = new System.Text.Rune (0x0328); // Combining ogonek (a small hook or comma shape)
+		var ogonek = new Rune (0x0328); // Combining ogonek (a small hook or comma shape)
 		combined = "a" + ogonek + acuteaccent;
 		combined = "a" + ogonek + acuteaccent;
-		expected = ("a" + ogonek).Normalize(NormalizationForm.FormC); // See Issue #2616
+		expected = ("a" + ogonek).Normalize (NormalizationForm.FormC); // See Issue #2616
 
 
 		driver.Move (0, 0);
 		driver.Move (0, 0);
 		driver.AddStr (combined);
 		driver.AddStr (combined);
@@ -93,8 +96,9 @@ public class ContentsTests {
 	[Theory]
 	[Theory]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (FakeDriver))]
 	[InlineData (typeof (NetDriver))]
 	[InlineData (typeof (NetDriver))]
-	[InlineData (typeof (CursesDriver))]
+	//[InlineData (typeof (ANSIDriver))]
 	[InlineData (typeof (WindowsDriver))]
 	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
 	public void Move_Bad_Coordinates (Type driverType)
 	public void Move_Bad_Coordinates (Type driverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
@@ -160,5 +164,4 @@ public class ContentsTests {
 	// Refresh works correctly
 	// Refresh works correctly
 
 
 	// IsDirty tests
 	// IsDirty tests
-}
-
+}

+ 64 - 64
UnitTests/ConsoleDrivers/DriverColorTests.cs

@@ -4,69 +4,69 @@ using Xunit;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui.DriverTests {
-	public class DriverColorTests {
-		public DriverColorTests ()
-		{
-			ConsoleDriver.RunningUnitTests = true;
-		}
-		
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		[InlineData (typeof (NetDriver))]
-		[InlineData (typeof (CursesDriver))]
-		[InlineData (typeof (WindowsDriver))]
-		public void SetColors_Changes_Colors (Type driverType)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			driver.Init ();
-
-			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
-			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
-
-			Console.ForegroundColor = ConsoleColor.Red;
-			Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
-
-			Console.BackgroundColor = ConsoleColor.Green;
-			Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
-
-			Console.ResetColor ();
-			Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
-			Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
-
-			driver.End ();
-		}
-
-
-		[Theory]
-		[InlineData (typeof (FakeDriver), false)]
-		[InlineData (typeof (NetDriver), true)]
-		[InlineData (typeof (CursesDriver), false)]
-		[InlineData (typeof (WindowsDriver), true)] // Because we're not Windows Terminal
-		public void SupportsTrueColor_Defaults (Type driverType, bool expectedSetting)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			driver.Init ();
-
-			Assert.Equal (expectedSetting, driver.SupportsTrueColor);
-
-			driver.End ();
-		}
-
-		[Theory]
-		[InlineData (typeof (FakeDriver))]
-		[InlineData (typeof (NetDriver))]
-		[InlineData (typeof (CursesDriver))]
-		[InlineData (typeof (WindowsDriver))]
-		public void Force16Colors_Sets (Type driverType)
-		{
-			var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
-			driver.Init ();
-
-			driver.Force16Colors = true;
-			Assert.True (driver.Force16Colors);
-
-			driver.End ();
-		}
+namespace Terminal.Gui.DriverTests; 
+
+public class DriverColorTests {
+	public DriverColorTests () => ConsoleDriver.RunningUnitTests = true;
+
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void SetColors_Changes_Colors (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		driver.Init ();
+
+		Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
+		Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
+
+		Console.ForegroundColor = ConsoleColor.Red;
+		Assert.Equal (ConsoleColor.Red, Console.ForegroundColor);
+
+		Console.BackgroundColor = ConsoleColor.Green;
+		Assert.Equal (ConsoleColor.Green, Console.BackgroundColor);
+
+		Console.ResetColor ();
+		Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor);
+		Assert.Equal (ConsoleColor.Black, Console.BackgroundColor);
+
+		driver.End ();
+	}
+
+
+	[Theory]
+	[InlineData (typeof (FakeDriver), false)]
+	[InlineData (typeof (NetDriver), true)]
+	//[InlineData (typeof (ANSIDriver), true)]
+	[InlineData (typeof (WindowsDriver), true)]
+	[InlineData (typeof (CursesDriver), false)]
+	public void SupportsTrueColor_Defaults (Type driverType, bool expectedSetting)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		driver.Init ();
+
+		Assert.Equal (expectedSetting, driver.SupportsTrueColor);
+
+		driver.End ();
+	}
+
+	[Theory]
+	[InlineData (typeof (FakeDriver))]
+	[InlineData (typeof (NetDriver))]
+	//[InlineData (typeof (ANSIDriver))]
+	[InlineData (typeof (WindowsDriver))]
+	[InlineData (typeof (CursesDriver))]
+	public void Force16Colors_Sets (Type driverType)
+	{
+		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
+		driver.Init ();
+
+		driver.Force16Colors = true;
+		Assert.True (driver.Force16Colors);
+
+		driver.End ();
 	}
 	}
 }
 }

+ 29 - 22
UnitTests/ConsoleDrivers/MainLoopDriverTests.cs

@@ -12,17 +12,14 @@ using Console = Terminal.Gui.FakeConsole;
 namespace Terminal.Gui.DriverTests;
 namespace Terminal.Gui.DriverTests;
 
 
 public class MainLoopDriverTests {
 public class MainLoopDriverTests {
-
-	public MainLoopDriverTests (ITestOutputHelper output)
-	{
-		ConsoleDriver.RunningUnitTests = true;
-	}
+	public MainLoopDriverTests (ITestOutputHelper output) => ConsoleDriver.RunningUnitTests = true;
 
 
 	[Theory]
 	[Theory]
 	[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
 	[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_Constructs_Disposes (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_Constructs_Disposes (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
@@ -45,20 +42,21 @@ public class MainLoopDriverTests {
 		Assert.Empty (mainLoop.Timeouts);
 		Assert.Empty (mainLoop.Timeouts);
 		Assert.False (mainLoop.Running);
 		Assert.False (mainLoop.Running);
 	}
 	}
-	
+
 	[Theory]
 	[Theory]
 	[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
 	[InlineData (typeof (FakeDriver), typeof (FakeMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_AddTimeout_ValidParameters_ReturnsToken (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_AddTimeout_ValidParameters_ReturnsToken (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
-		var callbackInvoked = false;
+		bool callbackInvoked = false;
 
 
-		var token = mainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), () => {
+		object token = mainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), () => {
 			callbackInvoked = true;
 			callbackInvoked = true;
 			return false;
 			return false;
 		});
 		});
@@ -77,14 +75,15 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_RemoveTimeout_ValidToken_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_RemoveTimeout_ValidToken_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
 
 
-		var token = mainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), () => false);
-		var result = mainLoop.RemoveTimeout (token);
+		object token = mainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), () => false);
+		bool result = mainLoop.RemoveTimeout (token);
 
 
 		Assert.True (result);
 		Assert.True (result);
 		mainLoop.Dispose ();
 		mainLoop.Dispose ();
@@ -95,13 +94,14 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_RemoveTimeout_InvalidToken_ReturnsFalse (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_RemoveTimeout_InvalidToken_ReturnsFalse (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
 
 
-		var result = mainLoop.RemoveTimeout (new object ());
+		bool result = mainLoop.RemoveTimeout (new object ());
 
 
 		Assert.False (result);
 		Assert.False (result);
 	}
 	}
@@ -111,12 +111,13 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_AddIdle_ValidIdleHandler_ReturnsToken (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_AddIdle_ValidIdleHandler_ReturnsToken (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
-		var idleHandlerInvoked = false;
+		bool idleHandlerInvoked = false;
 
 
 		bool IdleHandler ()
 		bool IdleHandler ()
 		{
 		{
@@ -124,7 +125,7 @@ public class MainLoopDriverTests {
 			return false;
 			return false;
 		}
 		}
 
 
-		Func<bool> token = mainLoop.AddIdle (IdleHandler);
+		var token = mainLoop.AddIdle (IdleHandler);
 
 
 		Assert.NotNull (token);
 		Assert.NotNull (token);
 		Assert.False (idleHandlerInvoked); // Idle handler should not be invoked immediately
 		Assert.False (idleHandlerInvoked); // Idle handler should not be invoked immediately
@@ -138,6 +139,7 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_RemoveIdle_ValidToken_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_RemoveIdle_ValidToken_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
@@ -145,8 +147,8 @@ public class MainLoopDriverTests {
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
 
 
 		bool IdleHandler () => false;
 		bool IdleHandler () => false;
-		Func<bool> token = mainLoop.AddIdle (IdleHandler);
-		var result = mainLoop.RemoveIdle (token);
+		var token = mainLoop.AddIdle (IdleHandler);
+		bool result = mainLoop.RemoveIdle (token);
 
 
 		Assert.True (result);
 		Assert.True (result);
 		mainLoop.Dispose ();
 		mainLoop.Dispose ();
@@ -157,13 +159,14 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_RemoveIdle_InvalidToken_ReturnsFalse (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_RemoveIdle_InvalidToken_ReturnsFalse (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
 
 
-		var result = mainLoop.RemoveIdle (() => false);
+		bool result = mainLoop.RemoveIdle (() => false);
 
 
 		Assert.False (result);
 		Assert.False (result);
 		mainLoop.Dispose ();
 		mainLoop.Dispose ();
@@ -174,14 +177,15 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_RunIteration_ValidIdleHandler_CallsIdleHandler (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_RunIteration_ValidIdleHandler_CallsIdleHandler (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
-		var idleHandlerInvoked = false;
+		bool idleHandlerInvoked = false;
 
 
-		Func<bool> idleHandler = () => {
+		var idleHandler = () => {
 			idleHandlerInvoked = true;
 			idleHandlerInvoked = true;
 			return false;
 			return false;
 		};
 		};
@@ -198,13 +202,14 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_CheckTimersAndIdleHandlers_NoTimersOrIdleHandlers_ReturnsFalse (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_CheckTimersAndIdleHandlers_NoTimersOrIdleHandlers_ReturnsFalse (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoopDriver = (IMainLoopDriver)Activator.CreateInstance (mainLoopDriverType, new object [] { driver });
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
 
 
-		var result = mainLoop.CheckTimersAndIdleHandlers (out var waitTimeout);
+		bool result = mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout);
 
 
 		Assert.False (result);
 		Assert.False (result);
 		Assert.Equal (-1, waitTimeout);
 		Assert.Equal (-1, waitTimeout);
@@ -216,6 +221,7 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_CheckTimersAndIdleHandlers_TimersActive_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_CheckTimersAndIdleHandlers_TimersActive_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
@@ -223,7 +229,7 @@ public class MainLoopDriverTests {
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
 
 
 		mainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), () => false);
 		mainLoop.AddTimeout (TimeSpan.FromMilliseconds (100), () => false);
-		var result = mainLoop.CheckTimersAndIdleHandlers (out var waitTimeout);
+		bool result = mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout);
 
 
 		Assert.True (result);
 		Assert.True (result);
 		Assert.True (waitTimeout >= 0);
 		Assert.True (waitTimeout >= 0);
@@ -235,6 +241,7 @@ public class MainLoopDriverTests {
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (NetDriver), typeof (NetMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (CursesDriver), typeof (UnixMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
 	[InlineData (typeof (WindowsDriver), typeof (WindowsMainLoop))]
+	//[InlineData (typeof (ANSIDriver), typeof (AnsiMainLoopDriver))]
 	public void MainLoop_CheckTimersAndIdleHandlers_IdleHandlersActive_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	public void MainLoop_CheckTimersAndIdleHandlers_IdleHandlersActive_ReturnsTrue (Type driverType, Type mainLoopDriverType)
 	{
 	{
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
 		var driver = (ConsoleDriver)Activator.CreateInstance (driverType);
@@ -242,7 +249,7 @@ public class MainLoopDriverTests {
 		var mainLoop = new MainLoop (mainLoopDriver);
 		var mainLoop = new MainLoop (mainLoopDriver);
 
 
 		mainLoop.AddIdle (() => false);
 		mainLoop.AddIdle (() => false);
-		var result = mainLoop.CheckTimersAndIdleHandlers (out var waitTimeout);
+		bool result = mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout);
 
 
 		Assert.True (result);
 		Assert.True (result);
 		Assert.Equal (-1, waitTimeout);
 		Assert.Equal (-1, waitTimeout);
@@ -267,4 +274,4 @@ public class MainLoopDriverTests {
 	//	Assert.True (actionInvoked);
 	//	Assert.True (actionInvoked);
 	//	mainLoop.Dispose ();
 	//	mainLoop.Dispose ();
 	//}
 	//}
-}
+}