2
0
Эх сурвалжийг харах

Merge branch 'v2_develop' into caption

Thomas Nind 2 жил өмнө
parent
commit
4bc5a3b23a
100 өөрчлөгдсөн 4193 нэмэгдсэн , 3241 устгасан
  1. 2 2
      .github/workflows/dotnet-core.yml
  2. 2 2
      Example/Example.cs
  3. 4 4
      Example/Example.csproj
  4. 6 4
      README.md
  5. 6 6
      ReactiveExample/ReactiveExample.csproj
  6. 20 34
      Terminal.Gui/Configuration/ConfigurationManager.cs
  7. 36 0
      Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs
  8. 10 2
      Terminal.Gui/Configuration/Scope.cs
  9. 3 0
      Terminal.Gui/Configuration/SettingsScope.cs
  10. 10 28
      Terminal.Gui/Configuration/ThemeScope.cs
  11. 79 395
      Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
  12. 3 27
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
  13. 14 21
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs
  14. 0 5
      Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs
  15. 2 2
      Terminal.Gui/ConsoleDrivers/CursesDriver/constants.cs
  16. 284 289
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs
  17. 11 12
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
  18. 4 4
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeMainLoop.cs
  19. 258 828
      Terminal.Gui/ConsoleDrivers/NetDriver.cs
  20. 56 41
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  21. 102 65
      Terminal.Gui/Core/Application.cs
  22. 5 4
      Terminal.Gui/Core/Autocomplete/Autocomplete.cs
  23. 137 55
      Terminal.Gui/Core/Border.cs
  24. 3 22
      Terminal.Gui/Core/CollectionNavigator.cs
  25. 19 72
      Terminal.Gui/Core/ConsoleDriver.cs
  26. 40 1
      Terminal.Gui/Core/ConsoleKeyMapping.cs
  27. 109 0
      Terminal.Gui/Core/EscSeqUtils/EscSeqReq.cs
  28. 907 0
      Terminal.Gui/Core/EscSeqUtils/EscSeqUtils.cs
  29. 1 1
      Terminal.Gui/Core/Event.cs
  30. 29 0
      Terminal.Gui/Core/GrabMouseEventArgs.cs
  31. 13 24
      Terminal.Gui/Core/Graphs/LineCanvas.cs
  32. 34 0
      Terminal.Gui/Core/KeyChangedEventArgs.cs
  33. 24 0
      Terminal.Gui/Core/KeyEventEventArgs.cs
  34. 22 0
      Terminal.Gui/Core/KeystrokeNavigatorEventArgs.cs
  35. 2 2
      Terminal.Gui/Core/MainLoop.cs
  36. 31 0
      Terminal.Gui/Core/MouseEventEventArgs.cs
  37. 30 0
      Terminal.Gui/Core/MouseFlagsChangedEventArgs.cs
  38. 23 0
      Terminal.Gui/Core/PointEventArgs.cs
  39. 2 2
      Terminal.Gui/Core/PosDim.cs
  40. 32 0
      Terminal.Gui/Core/ResizedEventArgs.cs
  41. 24 0
      Terminal.Gui/Core/RunStateEventArgs.cs
  42. 26 0
      Terminal.Gui/Core/SizeChangedEventArgs.cs
  43. 33 0
      Terminal.Gui/Core/SuperViewChangedEventArgs.cs
  44. 22 11
      Terminal.Gui/Core/TextFormatter.cs
  45. 32 0
      Terminal.Gui/Core/TimeoutEventArgs.cs
  46. 46 0
      Terminal.Gui/Core/TitleEventArgs.cs
  47. 30 0
      Terminal.Gui/Core/ToggleEventArgs.cs
  48. 101 97
      Terminal.Gui/Core/Toplevel.cs
  49. 51 0
      Terminal.Gui/Core/ToplevelEventArgs.cs
  50. 218 215
      Terminal.Gui/Core/View.cs
  51. 0 27
      Terminal.Gui/Core/View2.cs
  52. 80 0
      Terminal.Gui/Core/ViewEventArgs.cs
  53. 27 54
      Terminal.Gui/Core/Window.cs
  54. 1 1
      Terminal.Gui/Resources/config.json
  55. 9 10
      Terminal.Gui/Terminal.Gui.csproj
  56. 1 1
      Terminal.Gui/Types/Rect.cs
  57. 14 9
      Terminal.Gui/Views/Button.cs
  58. 43 0
      Terminal.Gui/Views/CellActivatedEventArgs.cs
  59. 17 10
      Terminal.Gui/Views/CheckBox.cs
  60. 2 2
      Terminal.Gui/Views/ColorPicker.cs
  61. 21 19
      Terminal.Gui/Views/ComboBox.cs
  62. 32 0
      Terminal.Gui/Views/ContentsChangedEventArgs.cs
  63. 7 7
      Terminal.Gui/Views/ContextMenu.cs
  64. 5 38
      Terminal.Gui/Views/DateField.cs
  65. 43 0
      Terminal.Gui/Views/DateTimeEventArgs.cs
  66. 30 45
      Terminal.Gui/Views/FrameView.cs
  67. 9 41
      Terminal.Gui/Views/HexView.cs
  68. 70 0
      Terminal.Gui/Views/HexViewEventArgs.cs
  69. 36 0
      Terminal.Gui/Views/HistoryTextItem.cs
  70. 3 3
      Terminal.Gui/Views/Label.cs
  71. 25 86
      Terminal.Gui/Views/ListView.cs
  72. 52 0
      Terminal.Gui/Views/ListViewEventArgs.cs
  73. 30 83
      Terminal.Gui/Views/Menu.cs
  74. 98 0
      Terminal.Gui/Views/MenuEventArgs.cs
  75. 1 1
      Terminal.Gui/Views/PanelView.cs
  76. 2 28
      Terminal.Gui/Views/RadioGroup.cs
  77. 5 5
      Terminal.Gui/Views/ScrollBarView.cs
  78. 5 5
      Terminal.Gui/Views/ScrollView.cs
  79. 63 0
      Terminal.Gui/Views/SelectedCellChangedEventArgs.cs
  80. 29 0
      Terminal.Gui/Views/SelectedItemChangedArgs.cs
  81. 38 0
      Terminal.Gui/Views/SplitterEventArgs.cs
  82. 31 0
      Terminal.Gui/Views/TabChangedEventArgs.cs
  83. 35 0
      Terminal.Gui/Views/TabMouseEventArgs.cs
  84. 1 59
      Terminal.Gui/Views/TabView.cs
  85. 5 98
      Terminal.Gui/Views/TableView.cs
  86. 31 0
      Terminal.Gui/Views/TextChangedEventArgs.cs
  87. 34 0
      Terminal.Gui/Views/TextChangingEventArgs.cs
  88. 17 39
      Terminal.Gui/Views/TextField.cs
  89. 21 76
      Terminal.Gui/Views/TextView.cs
  90. 7 73
      Terminal.Gui/Views/TileView.cs
  91. 5 5
      Terminal.Gui/Views/TimeField.cs
  92. 42 0
      Terminal.Gui/Views/TitleEventArgs.cs
  93. 2 2
      Terminal.Gui/Views/TreeView.cs
  94. 42 3
      Terminal.Gui/Windows/Dialog.cs
  95. 6 6
      Terminal.Gui/Windows/FileDialog.cs
  96. 61 30
      Terminal.Gui/Windows/MessageBox.cs
  97. 28 78
      Terminal.Gui/Windows/Wizard.cs
  98. 54 0
      Terminal.Gui/Windows/WizardEventArgs.cs
  99. 9 6
      UICatalog/KeyBindingsDialog.cs
  100. 6 14
      UICatalog/Properties/launchSettings.json

+ 2 - 2
.github/workflows/dotnet-core.yml

@@ -2,9 +2,9 @@ name: Build & Test Terminal.Gui with .NET Core
 
 on:
   push:
-    branches: [ main, develop ]
+    branches: [ main, develop, v2_develop ]
   pull_request:
-    branches: [ main, develop ]
+    branches: [ main, develop, v2_develop ]
 
 jobs:
   build:

+ 2 - 2
Example/Example.cs

@@ -18,7 +18,7 @@ public class ExampleWindow : Window {
 	
 	public ExampleWindow ()
 	{
-		Title = "Example App (Ctrl+Q to quit)";
+		Title = $"Example App ({Application.QuitKey} to quit)";
 
 		// Create input components and labels
 		var usernameLabel = new Label () { 
@@ -57,7 +57,7 @@ public class ExampleWindow : Window {
 		};
 
 		// When login button is clicked display a message popup
-		btnLogin.Clicked += () => {
+		btnLogin.Clicked += (s,e) => {
 			if (usernameText.Text == "admin" && passwordText.Text == "password") {
 				MessageBox.Query ("Logging In", "Login Successful", "Ok");
 				Application.RequestStop ();

+ 4 - 4
Example/Example.csproj

@@ -5,10 +5,10 @@
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- In the source tree the version will always be 1.0 for all projects. -->
     <!-- Do not modify these. -->
-    <AssemblyVersion>1.0</AssemblyVersion>
-    <FileVersion>1.0</FileVersion>
-    <Version>1.0</Version>
-    <InformationalVersion>1.0</InformationalVersion>
+    <AssemblyVersion>2.0</AssemblyVersion>
+    <FileVersion>2.0</FileVersion>
+    <Version>2.0</Version>
+    <InformationalVersion>2.0</InformationalVersion>
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\Terminal.Gui\Terminal.Gui.csproj" />

+ 6 - 4
README.md

@@ -6,17 +6,19 @@
 [![License](https://img.shields.io/github/license/gui-cs/gui.cs.svg)](LICENSE)
 ![Bugs](https://img.shields.io/github/issues/gui-cs/gui.cs/bug)
 
-# Terminal.Gui - Cross Platform Terminal UI toolkit for .NET
+# Terminal.Gui v2.x - Cross Platform Terminal UI toolkit for .NET
 
 A toolkit for building rich console apps for .NET, .NET Core, and Mono that works on Windows, the Mac, and Linux/Unix.
 
+NOTE: This is the WORK IN PROGRESS `v2.x` branch. The `main` branch is the stable `v1.x` branch.
+
 ![Sample app](docfx/images/sample.gif)
 
 ## Quick Start
 
 Paste these commands into your favorite terminal on Windows, Mac, or Linux. This will install the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates), create a new "Hello World" TUI app, and run it.
 
-(Press `CTRL-Q` to exit the app)
+(Press `CTRL-Q` to quit the app)
 
 ```powershell
 dotnet new --install Terminal.Gui.templates
@@ -80,7 +82,7 @@ public class ExampleWindow : Window {
 	
 	public ExampleWindow ()
 	{
-		Title = "Example App (Ctrl+Q to quit)";
+		Title = $"Example App ({Application.QuitKey} to quit)";
 
 		// Create input components and labels
 		var usernameLabel = new Label () { 
@@ -119,7 +121,7 @@ public class ExampleWindow : Window {
 		};
 
 		// When login button is clicked display a message popup
-		btnLogin.Clicked += () => {
+		btnLogin.Clicked += (s,e) => {
 			if (usernameText.Text == "admin" && passwordText.Text == "password") {
 				MessageBox.Query ("Logging In", "Login Successful", "Ok");
 				Application.RequestStop ();

+ 6 - 6
ReactiveExample/ReactiveExample.csproj

@@ -5,14 +5,14 @@
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- In the source tree the version will always be 2.0 for all projects. -->
     <!-- Do not modify these. -->
-    <AssemblyVersion>1.0</AssemblyVersion>
-    <FileVersion>1.0</FileVersion>
-    <Version>1.0</Version>
-    <InformationalVersion>1.0</InformationalVersion>
+    <AssemblyVersion>2.0</AssemblyVersion>
+    <FileVersion>2.0</FileVersion>
+    <Version>2.0</Version>
+    <InformationalVersion>2.0</InformationalVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="ReactiveUI.Fody" Version="18.4.1" />
-    <PackageReference Include="ReactiveUI" Version="18.4.1" />
+    <PackageReference Include="ReactiveUI.Fody" Version="18.4.22" />
+    <PackageReference Include="ReactiveUI" Version="18.4.22" />
     <PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="1.2.3" PrivateAssets="all" />
   </ItemGroup>
   <ItemGroup>

+ 20 - 34
Terminal.Gui/Configuration/ConfigurationManager.cs

@@ -44,7 +44,7 @@ namespace Terminal.Gui.Configuration {
 	///	3. Application configuration found in the applications's resources (<c>Resources/config.json</c>). 
 	/// </para>
 	/// <para>
-	///	4. Global configuration found in the the user's home directory (<c>~/.tui/config.json</c>).
+	///	4. Global configuration found in the user's home directory (<c>~/.tui/config.json</c>).
 	/// </para>
 	/// <para>
 	///	5. Global configuration found in the directory the app was launched from (<c>./.tui/config.json</c>).
@@ -63,7 +63,7 @@ namespace Terminal.Gui.Configuration {
 			DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
 			WriteIndented = true,
 			Converters = {
-				// No need to set converterss - the ConfigRootConverter uses property attributes apply the correct
+				// No need to set converters - the ConfigRootConverter uses property attributes apply the correct
 				// Converter.
 			},
 		};
@@ -196,7 +196,7 @@ namespace Terminal.Gui.Configuration {
 		/// </summary>
 		/// <remarks>
 		/// Is <see langword="null"/> until <see cref="Reset"/> is called. Gets set to a new instance by
-		/// deserializtion (see <see cref="Load"/>).
+		/// deserialization (see <see cref="Load"/>).
 		/// </remarks>
 		private static SettingsScope? _settings;
 
@@ -223,14 +223,14 @@ namespace Terminal.Gui.Configuration {
 		public static ThemeManager? Themes => ThemeManager.Instance;
 
 		/// <summary>
-		/// Aplication-specific configuration settings scope.
+		/// Application-specific configuration settings scope.
 		/// </summary>
 		[SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true), JsonPropertyName ("AppSettings")]
 		public static AppScope? AppSettings { get; set; }
 
 		/// <summary>
-		/// Initializes the internal state of ConfiguraitonManager. Nominally called once as part of application
-		/// startup to initilaize global state. Also called from some Unit Tests to ensure correctness (e.g. Reset()).
+		/// Initializes the internal state of ConfigurationManager. Nominally called once as part of application
+		/// startup to initialize global state. Also called from some Unit Tests to ensure correctness (e.g. Reset()).
 		/// </summary>
 		internal static void Initialize ()
 		{
@@ -260,7 +260,7 @@ namespace Terminal.Gui.Configuration {
 					  select p) {
 				if (p.GetCustomAttribute (typeof (SerializableConfigurationProperty)) is SerializableConfigurationProperty scp) {
 					if (p.GetGetMethod (true)!.IsStatic) {
-						// If the class name is ommited, JsonPropertyName is allowed. 
+						// If the class name is omitted, JsonPropertyName is allowed. 
 						_allConfigProperties!.Add (scp.OmitClassName ? ConfigProperty.GetJsonPropertyName (p) : $"{p.DeclaringType?.Name}.{p.Name}", new ConfigProperty {
 							PropertyInfo = p,
 							PropertyValue = null
@@ -301,19 +301,6 @@ namespace Terminal.Gui.Configuration {
 			return stream;
 		}
 
-		/// <summary>
-		/// Event arguments for the <see cref="ConfigurationManager"/> events.
-		/// </summary>
-		public class ConfigurationManagerEventArgs : EventArgs {
-
-			/// <summary>
-			/// Initializes a new instance of <see cref="ConfigurationManagerEventArgs"/>
-			/// </summary>
-			public ConfigurationManagerEventArgs ()
-			{
-			}
-		}
-
 		/// <summary>
 		/// Gets or sets whether the <see cref="ConfigurationManager"/> should throw an exception if it encounters 
 		/// an error on deserialization. If <see langword="false"/> (the default), the error is logged and printed to the 
@@ -353,14 +340,14 @@ namespace Terminal.Gui.Configuration {
 		public static void OnUpdated ()
 		{
 			Debug.WriteLine ($"ConfigurationManager.OnApplied()");
-			Updated?.Invoke (new ConfigurationManagerEventArgs ());
+			Updated?.Invoke (null, new ConfigurationManagerEventArgs ());
 		}
 
 		/// <summary>
-		/// Event fired when the configuration has been upddated from a configuration source.  
+		/// Event fired when the configuration has been updated from a configuration source.  
 		/// application.
 		/// </summary>
-		public static event Action<ConfigurationManagerEventArgs>? Updated;
+		public static event EventHandler<ConfigurationManagerEventArgs>? Updated;
 
 		/// <summary>
 		/// Resets the state of <see cref="ConfigurationManager"/>. Should be called whenever a new app session
@@ -378,7 +365,7 @@ namespace Terminal.Gui.Configuration {
 			}
 
 			ClearJsonErrors ();
-			
+
 			Settings = new SettingsScope ();
 			ThemeManager.Reset ();
 			AppSettings = new AppScope ();
@@ -402,7 +389,7 @@ namespace Terminal.Gui.Configuration {
 		/// to generate the JSON doc that is embedded into Terminal.Gui (during development). 
 		/// </para>
 		/// <para>
-		/// WARNING: The <c>Terminal.Gui.Resources.config.json</c> resource has setting defintions (Themes)
+		/// WARNING: The <c>Terminal.Gui.Resources.config.json</c> resource has setting definitions (Themes)
 		/// that are NOT generated by this function. If you use this function to regenerate <c>Terminal.Gui.Resources.config.json</c>,
 		/// make sure you copy the Theme definitions from the existing <c>Terminal.Gui.Resources.config.json</c> file.
 		/// </para>		
@@ -440,14 +427,14 @@ namespace Terminal.Gui.Configuration {
 		public static void OnApplied ()
 		{
 			Debug.WriteLine ($"ConfigurationManager.OnApplied()");
-			Applied?.Invoke (new ConfigurationManagerEventArgs ());
+			Applied?.Invoke (null, new ConfigurationManagerEventArgs ());
 		}
 
 		/// <summary>
 		/// Event fired when an updated configuration has been applied to the  
 		/// application.
 		/// </summary>
-		public static event Action<ConfigurationManagerEventArgs>? Applied;
+		public static event EventHandler<ConfigurationManagerEventArgs>? Applied;
 
 		/// <summary>
 		/// Name of the running application. By default this property is set to the application's assembly name.
@@ -455,7 +442,7 @@ namespace Terminal.Gui.Configuration {
 		public static string AppName { get; set; } = Assembly.GetEntryAssembly ()?.FullName?.Split (',') [0]?.Trim ()!;
 
 		/// <summary>
-		/// Describes the location of the configuration files. The constancts can be
+		/// Describes the location of the configuration files. The constants can be
 		/// combined (bitwise) to specify multiple locations.
 		/// </summary>
 		[Flags]
@@ -488,27 +475,26 @@ namespace Terminal.Gui.Configuration {
 		public static ConfigLocations Locations { get; set; } = ConfigLocations.All;
 
 		/// <summary>
-		/// Loads all settings found in the various configuraiton storage locations to 
+		/// Loads all settings found in the various configuration storage locations to 
 		/// the <see cref="ConfigurationManager"/>. Optionally,
-		/// resets all settings attributed with <see cref="SerializableConfigurationProperty"/> to the defaults 
-		/// defined in <see cref="LoadAppResources"/>.
+		/// resets all settings attributed with <see cref="SerializableConfigurationProperty"/> to the defaults.
 		/// </summary>
 		/// <remarks>
 		/// Use <see cref="Apply"/> to cause the loaded settings to be applied to the running application.
 		/// </remarks>
 		/// <param name="reset">If <see langword="true"/> the state of <see cref="ConfigurationManager"/> will
-		/// be reset to the defaults defined in <see cref="LoadAppResources"/>.</param>
+		/// be reset to the defaults.</param>
 		public static void Load (bool reset = false)
 		{
 			Debug.WriteLine ($"ConfigurationManager.Load()");
 
 			if (reset) Reset ();
 
-			// LibraryResoruces is always loaded by Reset
+			// LibraryResources is always loaded by Reset
 			if (Locations == ConfigLocations.All) {
 				var embeddedStylesResourceName = Assembly.GetEntryAssembly ()?
 					.GetManifestResourceNames ().FirstOrDefault (x => x.EndsWith (_configFilename));
-				if (string.IsNullOrEmpty(embeddedStylesResourceName)) {
+				if (string.IsNullOrEmpty (embeddedStylesResourceName)) {
 					embeddedStylesResourceName = _configFilename;
 				}
 

+ 36 - 0
Terminal.Gui/Configuration/ConfigurationManagerEventArgs.cs

@@ -0,0 +1,36 @@
+using System;
+
+#nullable enable
+
+namespace Terminal.Gui.Configuration {
+	/// <summary>
+	/// Event arguments for the <see cref="ConfigurationManager"/> events.
+	/// </summary>
+	public class ConfigurationManagerEventArgs : EventArgs {
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="ConfigurationManagerEventArgs"/>
+		/// </summary>
+		public ConfigurationManagerEventArgs ()
+		{
+		}
+	}
+
+	/// <summary>
+	/// Event arguments for the <see cref="ConfigurationManager.ThemeManager"/> events.
+	/// </summary>
+	public class ThemeManagerEventArgs : EventArgs {
+		/// <summary>
+		/// The name of the new active theme..
+		/// </summary>
+		public string NewTheme { get; set; } = string.Empty;
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="ThemeManagerEventArgs"/>
+		/// </summary>
+		public ThemeManagerEventArgs (string newTheme)
+		{
+			NewTheme = newTheme;
+		}
+	}
+}

+ 10 - 2
Terminal.Gui/Configuration/Scope.cs

@@ -129,9 +129,17 @@ namespace Terminal.Gui.Configuration {
 								}
 							}
 							var readHelper = Activator.CreateInstance ((Type?)typeof (ReadHelper<>).MakeGenericType (typeof (scopeT), propertyType!)!, converter) as ReadHelper;
-							scope! [propertyName].PropertyValue = readHelper?.Read (ref reader, propertyType!, options);
+							try {
+								scope! [propertyName].PropertyValue = readHelper?.Read (ref reader, propertyType!, options);
+							} catch (NotSupportedException e) {
+								throw new JsonException ($"Error reading property \"{propertyName}\" of type \"{propertyType?.Name}\".", e);
+							}
 						} else {
-							scope! [propertyName].PropertyValue = JsonSerializer.Deserialize (ref reader, propertyType!, options);
+							try {
+								scope! [propertyName].PropertyValue = JsonSerializer.Deserialize (ref reader, propertyType!, options);
+							} catch (Exception ex) {
+								System.Diagnostics.Debug.WriteLine ($"scopeT Read: {ex}");
+							}
 						}
 					} else {
 						// It is not a config property. Maybe it's just a property on the Scope with [JsonInclude]

+ 3 - 0
Terminal.Gui/Configuration/SettingsScope.cs

@@ -34,6 +34,9 @@ namespace Terminal.Gui.Configuration {
 			[JsonInclude, JsonPropertyName ("$schema")]
 			public string Schema { get; set; } = "https://gui-cs.github.io/Terminal.Gui/schemas/tui-config-schema.json";
 
+			/// <summary>
+			/// The list of paths to the configuration files.
+			/// </summary>
 			public List<string> Sources = new List<string> ();
 
 			/// <summary>

+ 10 - 28
Terminal.Gui/Configuration/ThemeScope.cs

@@ -110,7 +110,7 @@ namespace Terminal.Gui.Configuration {
 		/// 		}
 		/// 	}
 		/// </code></example> 
-		public class ThemeManager : IDictionary<string, ThemeScope> {
+		public partial class ThemeManager : IDictionary<string, ThemeScope> {
 			private static readonly ThemeManager _instance = new ThemeManager ();
 			static ThemeManager () { } // Make sure it's truly lazy
 			private ThemeManager () { } // Prevent instantiation outside
@@ -120,21 +120,21 @@ namespace Terminal.Gui.Configuration {
 			/// </summary>
 			public static ThemeManager Instance { get { return _instance; } }
 
-			private static string theme = string.Empty;
+			private static string _theme = string.Empty;
 
 			/// <summary>
 			/// The currently selected theme. This is the internal version; see <see cref="Theme"/>.
 			/// </summary>
 			[JsonInclude, SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true), JsonPropertyName ("Theme")]
 			internal static string SelectedTheme {
-				get => theme;
+				get => _theme;
 				set {
-					var oldTheme = theme;
-					theme = value;
-					if (oldTheme != theme &&
+					var oldTheme = _theme;
+					_theme = value;
+					if (oldTheme != _theme &&
 						ConfigurationManager.Settings! ["Themes"]?.PropertyValue is Dictionary<string, ThemeScope> themes &&
-						themes.ContainsKey (theme)) {
-						ConfigurationManager.Settings! ["Theme"].PropertyValue = theme;
+						themes.ContainsKey (_theme)) {
+						ConfigurationManager.Settings! ["Theme"].PropertyValue = _theme;
 						Instance.OnThemeChanged (oldTheme);
 					}
 				}
@@ -152,38 +152,20 @@ namespace Terminal.Gui.Configuration {
 				}
 			}
 
-			/// <summary>
-			/// Event arguments for the <see cref="ThemeManager"/> events.
-			/// </summary>
-			public class ThemeManagerEventArgs : EventArgs {
-				/// <summary>
-				/// The name of the new active theme..
-				/// </summary>
-				public string NewTheme { get; set; } = string.Empty;
-
-				/// <summary>
-				/// Initializes a new instance of <see cref="ThemeManagerEventArgs"/>
-				/// </summary>
-				public ThemeManagerEventArgs (string newTheme)
-				{
-					NewTheme = newTheme;
-				}
-			}
-
 			/// <summary>
 			/// Called when the selected theme has changed. Fires the <see cref="ThemeChanged"/> event.
 			/// </summary>
 			internal void OnThemeChanged (string theme)
 			{
 				Debug.WriteLine ($"Themes.OnThemeChanged({theme}) -> {Theme}");
-				ThemeChanged?.Invoke (new ThemeManagerEventArgs (theme));
+				ThemeChanged?.Invoke (this, new ThemeManagerEventArgs (theme));
 			}
 
 			/// <summary>
 			/// Event fired he selected theme has changed.
 			/// application.
 			/// </summary>
-			public event Action<ThemeManagerEventArgs>? ThemeChanged;
+			public event EventHandler<ThemeManagerEventArgs>? ThemeChanged;
 
 			/// <summary>
 			/// Holds the <see cref="ThemeScope"/> definitions. 

+ 79 - 395
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -1,9 +1,6 @@
 //
 // Driver.cs: Curses-based Driver
 //
-// Authors:
-//   Miguel de Icaza ([email protected])
-//
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -23,7 +20,7 @@ namespace Terminal.Gui {
 		public override int Rows => Curses.Lines;
 		public override int Left => 0;
 		public override int Top => 0;
-		public override bool HeightAsBuffer { get; set; }
+		public override bool EnableConsoleScrolling { get; set; }
 		public override IClipboard Clipboard { get => clipboard; }
 
 		CursorVisibility? initialCursorVisibility = null;
@@ -116,7 +113,7 @@ namespace Terminal.Gui {
 			if (runeWidth < 0 || runeWidth > 0) {
 				ccol++;
 			}
-			
+
 			if (runeWidth > 1) {
 				if (validClip && ccol < Clip.Right) {
 					contents [crow, ccol, 1] = CurrentAttribute;
@@ -158,26 +155,10 @@ namespace Terminal.Gui {
 
 		public override void End ()
 		{
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition)) {
-				StopReportingMouseMoves ();
-			}
-
+			StopReportingMouseMoves ();
 			SetCursorVisibility (CursorVisibility.Default);
 
 			Curses.endwin ();
-
-			// I'm commenting this because was used in a trying to fix the Linux hanging and forgot to exclude it.
-			// Clear and reset entire screen.
-			//Console.Out.Write ("\x1b[2J");
-			//Console.Out.Flush ();
-
-			// Set top and bottom lines of a window.
-			//Console.Out.Write ("\x1b[1;25r");
-			//Console.Out.Flush ();
-
-			//Set cursor key to cursor.
-			//Console.Out.Write ("\x1b[?1l");
-			//Console.Out.Flush ();
 		}
 
 		public override void UpdateScreen () => window.redrawwin ();
@@ -324,305 +305,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-		Curses.Event? lastMouseButtonPressed;
-		bool isButtonPressed;
-		bool cancelButtonClicked;
-		bool isReportMousePosition;
-		Point point;
-		int buttonPressedCount;
-
-		MouseEvent ToDriverMouse (Curses.MouseEvent cev)
-		{
-			MouseFlags mouseFlag = MouseFlags.AllEvents;
-
-			if (lastMouseButtonPressed != null && cev.ButtonState != Curses.Event.ReportMousePosition) {
-				lastMouseButtonPressed = null;
-				isButtonPressed = false;
-			}
-
-			if (cev.ButtonState == Curses.Event.Button1Pressed
-				|| cev.ButtonState == Curses.Event.Button2Pressed
-				|| cev.ButtonState == Curses.Event.Button3Pressed) {
-
-				isButtonPressed = true;
-				buttonPressedCount++;
-			} else {
-				buttonPressedCount = 0;
-			}
-			//System.Diagnostics.Debug.WriteLine ($"buttonPressedCount: {buttonPressedCount}");
-
-			if (buttonPressedCount == 2
-				&& (cev.ButtonState == Curses.Event.Button1Pressed
-				|| cev.ButtonState == Curses.Event.Button2Pressed
-				|| cev.ButtonState == Curses.Event.Button3Pressed)) {
-
-				switch (cev.ButtonState) {
-				case Curses.Event.Button1Pressed:
-					mouseFlag = MouseFlags.Button1DoubleClicked;
-					break;
-
-				case Curses.Event.Button2Pressed:
-					mouseFlag = MouseFlags.Button2DoubleClicked;
-					break;
-
-				case Curses.Event.Button3Pressed:
-					mouseFlag = MouseFlags.Button3DoubleClicked;
-					break;
-				}
-				cancelButtonClicked = true;
-
-			} else if (buttonPressedCount == 3
-			       && (cev.ButtonState == Curses.Event.Button1Pressed
-			       || cev.ButtonState == Curses.Event.Button2Pressed
-			       || cev.ButtonState == Curses.Event.Button3Pressed)) {
-
-				switch (cev.ButtonState) {
-				case Curses.Event.Button1Pressed:
-					mouseFlag = MouseFlags.Button1TripleClicked;
-					break;
-
-				case Curses.Event.Button2Pressed:
-					mouseFlag = MouseFlags.Button2TripleClicked;
-					break;
-
-				case Curses.Event.Button3Pressed:
-					mouseFlag = MouseFlags.Button3TripleClicked;
-					break;
-				}
-				buttonPressedCount = 0;
-
-			} else if ((cev.ButtonState == Curses.Event.Button1Clicked || cev.ButtonState == Curses.Event.Button2Clicked ||
-			       cev.ButtonState == Curses.Event.Button3Clicked) &&
-			       lastMouseButtonPressed == null) {
-
-				isButtonPressed = false;
-				mouseFlag = ProcessButtonClickedEvent (cev);
-
-			} else if (((cev.ButtonState == Curses.Event.Button1Pressed || cev.ButtonState == Curses.Event.Button2Pressed ||
-				cev.ButtonState == Curses.Event.Button3Pressed) && lastMouseButtonPressed == null) ||
-				isButtonPressed && lastMouseButtonPressed != null && cev.ButtonState == Curses.Event.ReportMousePosition) {
-
-				mouseFlag = MapCursesButton (cev.ButtonState);
-				if (cev.ButtonState != Curses.Event.ReportMousePosition)
-					lastMouseButtonPressed = cev.ButtonState;
-				isButtonPressed = true;
-				isReportMousePosition = false;
-
-				if (cev.ButtonState == Curses.Event.ReportMousePosition) {
-					mouseFlag = MapCursesButton ((Curses.Event)lastMouseButtonPressed) | MouseFlags.ReportMousePosition;
-					cancelButtonClicked = true;
-				}
-				point = new Point () {
-					X = cev.X,
-					Y = cev.Y
-				};
-
-				if ((mouseFlag & MouseFlags.ReportMousePosition) == 0) {
-					Application.MainLoop.AddIdle (() => {
-						Task.Run (async () => await ProcessContinuousButtonPressedAsync (mouseFlag));
-						return false;
-					});
-				}
-
-
-			} else if ((cev.ButtonState == Curses.Event.Button1Released || cev.ButtonState == Curses.Event.Button2Released ||
-				cev.ButtonState == Curses.Event.Button3Released)) {
-
-				mouseFlag = ProcessButtonReleasedEvent (cev);
-				isButtonPressed = false;
-
-			} else if (cev.ButtonState == Curses.Event.ButtonWheeledUp) {
-
-				mouseFlag = MouseFlags.WheeledUp;
-
-			} else if (cev.ButtonState == Curses.Event.ButtonWheeledDown) {
-
-				mouseFlag = MouseFlags.WheeledDown;
-
-			} else if ((cev.ButtonState & (Curses.Event.ButtonWheeledUp & Curses.Event.ButtonShift)) != 0) {
-
-				mouseFlag = MouseFlags.WheeledLeft;
-
-			} else if ((cev.ButtonState & (Curses.Event.ButtonWheeledDown & Curses.Event.ButtonShift)) != 0) {
-
-				mouseFlag = MouseFlags.WheeledRight;
-
-			} else if (cev.ButtonState == Curses.Event.ReportMousePosition) {
-				if (cev.X != point.X || cev.Y != point.Y) {
-					mouseFlag = MouseFlags.ReportMousePosition;
-					isReportMousePosition = true;
-					point = new Point ();
-				} else {
-					mouseFlag = 0;
-				}
-
-			} else {
-				mouseFlag = 0;
-				var eFlags = cev.ButtonState;
-				foreach (Enum value in Enum.GetValues (eFlags.GetType ())) {
-					if (eFlags.HasFlag (value)) {
-						mouseFlag |= MapCursesButton ((Curses.Event)value);
-					}
-				}
-			}
-
-			mouseFlag = SetControlKeyStates (cev, mouseFlag);
-
-			return new MouseEvent () {
-				X = cev.X,
-				Y = cev.Y,
-				//Flags = MapCursesButton (cev.ButtonState)
-				Flags = mouseFlag
-			};
-		}
-
-		MouseFlags ProcessButtonClickedEvent (Curses.MouseEvent cev)
-		{
-			lastMouseButtonPressed = cev.ButtonState;
-			var mf = GetButtonState (cev, true);
-			mouseHandler (ProcessButtonState (cev, mf));
-			if (lastMouseButtonPressed != null && lastMouseButtonPressed == cev.ButtonState) {
-				mf = GetButtonState (cev, false);
-				mouseHandler (ProcessButtonState (cev, mf));
-				if (lastMouseButtonPressed != null && lastMouseButtonPressed == cev.ButtonState) {
-					mf = MapCursesButton (cev.ButtonState);
-				}
-			}
-			lastMouseButtonPressed = null;
-			isButtonPressed = false;
-			return mf;
-		}
-
-		MouseFlags ProcessButtonReleasedEvent (Curses.MouseEvent cev)
-		{
-			var mf = MapCursesButton (cev.ButtonState);
-			if (!cancelButtonClicked && lastMouseButtonPressed == null && !isReportMousePosition) {
-				mouseHandler (ProcessButtonState (cev, mf));
-				mf = GetButtonState (cev);
-			} else if (isReportMousePosition) {
-				mf = MouseFlags.ReportMousePosition;
-			}
-			cancelButtonClicked = false;
-			return mf;
-		}
-
-		async Task ProcessContinuousButtonPressedAsync (MouseFlags mouseFlag)
-		{
-			while (isButtonPressed) {
-				await Task.Delay (100);
-				var me = new MouseEvent () {
-					X = point.X,
-					Y = point.Y,
-					Flags = mouseFlag
-				};
-
-				var view = Application.WantContinuousButtonPressedView;
-				if (view == null)
-					break;
-				if (isButtonPressed && lastMouseButtonPressed != null && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
-					Application.MainLoop.Invoke (() => mouseHandler (me));
-				}
-			}
-		}
-
-		MouseFlags GetButtonState (Curses.MouseEvent cev, bool pressed = false)
-		{
-			MouseFlags mf = default;
-			switch (cev.ButtonState) {
-			case Curses.Event.Button1Clicked:
-				if (pressed)
-					mf = MouseFlags.Button1Pressed;
-				else
-					mf = MouseFlags.Button1Released;
-				break;
-
-			case Curses.Event.Button2Clicked:
-				if (pressed)
-					mf = MouseFlags.Button2Pressed;
-				else
-					mf = MouseFlags.Button2Released;
-				break;
-
-			case Curses.Event.Button3Clicked:
-				if (pressed)
-					mf = MouseFlags.Button3Pressed;
-				else
-					mf = MouseFlags.Button3Released;
-				break;
-
-			case Curses.Event.Button1Released:
-				mf = MouseFlags.Button1Clicked;
-				break;
-
-			case Curses.Event.Button2Released:
-				mf = MouseFlags.Button2Clicked;
-				break;
-
-			case Curses.Event.Button3Released:
-				mf = MouseFlags.Button3Clicked;
-				break;
-
-			}
-			return mf;
-		}
-
-		MouseEvent ProcessButtonState (Curses.MouseEvent cev, MouseFlags mf)
-		{
-			return new MouseEvent () {
-				X = cev.X,
-				Y = cev.Y,
-				Flags = mf
-			};
-		}
-
-		MouseFlags MapCursesButton (Curses.Event cursesButton)
-		{
-			switch (cursesButton) {
-			case Curses.Event.Button1Pressed: return MouseFlags.Button1Pressed;
-			case Curses.Event.Button1Released: return MouseFlags.Button1Released;
-			case Curses.Event.Button1Clicked: return MouseFlags.Button1Clicked;
-			case Curses.Event.Button1DoubleClicked: return MouseFlags.Button1DoubleClicked;
-			case Curses.Event.Button1TripleClicked: return MouseFlags.Button1TripleClicked;
-			case Curses.Event.Button2Pressed: return MouseFlags.Button2Pressed;
-			case Curses.Event.Button2Released: return MouseFlags.Button2Released;
-			case Curses.Event.Button2Clicked: return MouseFlags.Button2Clicked;
-			case Curses.Event.Button2DoubleClicked: return MouseFlags.Button2DoubleClicked;
-			case Curses.Event.Button2TrippleClicked: return MouseFlags.Button2TripleClicked;
-			case Curses.Event.Button3Pressed: return MouseFlags.Button3Pressed;
-			case Curses.Event.Button3Released: return MouseFlags.Button3Released;
-			case Curses.Event.Button3Clicked: return MouseFlags.Button3Clicked;
-			case Curses.Event.Button3DoubleClicked: return MouseFlags.Button3DoubleClicked;
-			case Curses.Event.Button3TripleClicked: return MouseFlags.Button3TripleClicked;
-			case Curses.Event.ButtonWheeledUp: return MouseFlags.WheeledUp;
-			case Curses.Event.ButtonWheeledDown: return MouseFlags.WheeledDown;
-			case Curses.Event.Button4Pressed: return MouseFlags.Button4Pressed;
-			case Curses.Event.Button4Released: return MouseFlags.Button4Released;
-			case Curses.Event.Button4Clicked: return MouseFlags.Button4Clicked;
-			case Curses.Event.Button4DoubleClicked: return MouseFlags.Button4DoubleClicked;
-			case Curses.Event.Button4TripleClicked: return MouseFlags.Button4TripleClicked;
-			case Curses.Event.ButtonShift: return MouseFlags.ButtonShift;
-			case Curses.Event.ButtonCtrl: return MouseFlags.ButtonCtrl;
-			case Curses.Event.ButtonAlt: return MouseFlags.ButtonAlt;
-			case Curses.Event.ReportMousePosition: return MouseFlags.ReportMousePosition;
-			case Curses.Event.AllEvents: return MouseFlags.AllEvents;
-			default: return 0;
-			}
-		}
-
-		static MouseFlags SetControlKeyStates (Curses.MouseEvent cev, MouseFlags mouseFlag)
-		{
-			if ((cev.ButtonState & Curses.Event.ButtonCtrl) != 0 && (mouseFlag & MouseFlags.ButtonCtrl) == 0)
-				mouseFlag |= MouseFlags.ButtonCtrl;
-
-			if ((cev.ButtonState & Curses.Event.ButtonShift) != 0 && (mouseFlag & MouseFlags.ButtonShift) == 0)
-				mouseFlag |= MouseFlags.ButtonShift;
-
-			if ((cev.ButtonState & Curses.Event.ButtonAlt) != 0 && (mouseFlag & MouseFlags.ButtonAlt) == 0)
-				mouseFlag |= MouseFlags.ButtonAlt;
-			return mouseFlag;
-		}
-
-
 		KeyModifiers keyModifiers;
 
 		KeyModifiers MapKeyModifiers (Key key)
@@ -656,9 +338,18 @@ namespace Terminal.Gui {
 					ProcessWinChange ();
 				}
 				if (wch == Curses.KeyMouse) {
-					Curses.getmouse (out Curses.MouseEvent ev);
-					//System.Diagnostics.Debug.WriteLine ($"ButtonState: {ev.ButtonState}; ID: {ev.ID}; X: {ev.X}; Y: {ev.Y}; Z: {ev.Z}");
-					mouseHandler (ToDriverMouse (ev));
+					int wch2 = wch;
+
+					while (wch2 == Curses.KeyMouse) {
+						KeyEvent key = null;
+						ConsoleKeyInfo [] cki = new ConsoleKeyInfo [] {
+							new ConsoleKeyInfo ((char)Key.Esc, 0, false, false, false),
+							new ConsoleKeyInfo ('[', 0, false, false, false),
+							new ConsoleKeyInfo ('<', 0, false, false, false)
+						};
+						code = 0;
+						GetEscSeq (ref code, ref k, ref wch2, ref key, ref cki);
+					}
 					return;
 				}
 				k = MapCursesKey (wch);
@@ -694,7 +385,7 @@ namespace Terminal.Gui {
 					k = Key.AltMask | MapCursesKey (wch);
 				}
 				if (code == 0) {
-					KeyEvent key;
+					KeyEvent key = null;
 
 					// The ESC-number handling, debatable.
 					// Simulates the AltMask itself by pressing Alt + Space.
@@ -706,55 +397,13 @@ namespace Terminal.Gui {
 						k = (Key)((uint)(Key.AltMask | Key.CtrlMask) + (wch2 + 64));
 					} else if (wch2 >= (uint)Key.D0 && wch2 <= (uint)Key.D9) {
 						k = (Key)((uint)Key.AltMask + (uint)Key.D0 + (wch2 - (uint)Key.D0));
-					} else if (wch2 == 27) {
-						k = (Key)wch2;
-					} else if (wch2 == Curses.KEY_CODE_SEQ) {
-						int [] c = null;
-						while (code == 0) {
-							code = Curses.get_wch (out wch2);
-							if (wch2 > 0) {
-								Array.Resize (ref c, c == null ? 1 : c.Length + 1);
-								c [c.Length - 1] = wch2;
-							}
-						}
-						if (c [0] == 49 && c [1] == 59 && c [2] == 55 && c [3] >= 80 && c [3] <= 83) { // Ctrl+Alt+(F1 - F4)
-							wch2 = c [3] + 185;
-							k = Key.CtrlMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [2] == 59 && c [3] == 55 && c [4] == 126 && c [1] >= 53 && c [1] <= 57) { // Ctrl+Alt+(F5 - F8)
-							wch2 = c [1] == 53 ? c [1] + 216 : c [1] + 215;
-							k = Key.CtrlMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 50 && c [2] == 59 && c [3] == 55 && c [4] == 126 && c [1] >= 48 && c [1] <= 52) { // Ctrl+Alt+(F9 - F12)
-							wch2 = c [1] < 51 ? c [1] + 225 : c [1] + 224;
-							k = Key.CtrlMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 56 && c [3] >= 80 && c [3] <= 83) { // Ctrl+Shift+Alt+(F1 - F4)
-							wch2 = c [3] + 185;
-							k = Key.CtrlMask | Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [2] == 59 && c [3] == 56 && c [4] == 126 && c [1] >= 53 && c [1] <= 57) { // Ctrl+Shift+Alt+(F5 - F8)
-							wch2 = c [1] == 53 ? c [1] + 216 : c [1] + 215;
-							k = Key.CtrlMask | Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 50 && c [2] == 59 && c [3] == 56 && c [4] == 126 && c [1] >= 48 && c [1] <= 52) {  // Ctrl+Shift+Alt+(F9 - F12)
-							wch2 = c [1] < 51 ? c [1] + 225 : c [1] + 224;
-							k = Key.CtrlMask | Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 52 && c [3] == 83) {  // Shift+Alt+(F4)
-							wch2 = 268;
-							k = Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [2] == 59 && c [3] == 52 && c [4] == 126 && c [1] >= 53 && c [1] <= 57) {  // Shift+Alt+(F5 - F8)
-							wch2 = c [1] < 55 ? c [1] + 216 : c [1] + 215;
-							k = Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 50 && c [2] == 59 && c [3] == 52 && c [4] == 126 && c [1] >= 48 && c [1] <= 52) {  // Shift+Alt+(F9 - F12)
-							wch2 = c [1] < 51 ? c [1] + 225 : c [1] + 224;
-							k = Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 54 && c [1] == 59 && c [2] == 56 && c [3] == 126) {  // Shift+Ctrl+Alt+KeyNPage
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.PageDown;
-						} else if (c [0] == 53 && c [1] == 59 && c [2] == 56 && c [3] == 126) {  // Shift+Ctrl+Alt+KeyPPage
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.PageUp;
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 56 && c [3] == 72) {  // Shift+Ctrl+Alt+KeyHome
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.Home;
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 56 && c [3] == 70) {  // Shift+Ctrl+Alt+KeyEnd
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.End;
-						} else {
-							k = MapCursesKey (wch2);
-						}
+					} else if (wch2 == Curses.KeyCSI) {
+						ConsoleKeyInfo [] cki = new ConsoleKeyInfo [] {
+							new ConsoleKeyInfo ((char)Key.Esc, 0, false, false, false),
+							new ConsoleKeyInfo ('[', 0, false, false, false)
+						};
+						GetEscSeq (ref code, ref k, ref wch2, ref key, ref cki);
+						return;
 					} else {
 						// Unfortunately there are no way to differentiate Ctrl+Alt+alfa and Ctrl+Shift+Alt+alfa.
 						if (((Key)wch2 & Key.CtrlMask) != 0) {
@@ -809,6 +458,52 @@ namespace Terminal.Gui {
 			//}
 		}
 
+		void GetEscSeq (ref int code, ref Key k, ref int wch2, ref KeyEvent key, ref ConsoleKeyInfo [] cki)
+		{
+			ConsoleKey ck = 0;
+			ConsoleModifiers mod = 0;
+			while (code == 0) {
+				code = Curses.get_wch (out wch2);
+				var consoleKeyInfo = new ConsoleKeyInfo ((char)wch2, 0, false, false, false);
+				if (wch2 == 0 || wch2 == 27 || wch2 == Curses.KeyMouse) {
+					EscSeqUtils.DecodeEscSeq (null, ref consoleKeyInfo, ref ck, cki, ref mod, out _, out _, out _, out _, out bool isKeyMouse, out List<MouseFlags> mouseFlags, out Point pos, out _, ProcessContinuousButtonPressed);
+					if (isKeyMouse) {
+						foreach (var mf in mouseFlags) {
+							ProcessMouseEvent (mf, pos);
+						}
+						cki = null;
+						if (wch2 == 27) {
+							cki = EscSeqUtils.ResizeArray (new ConsoleKeyInfo ((char)Key.Esc, 0,
+								false, false, false), cki);
+						}
+					} else {
+						k = ConsoleKeyMapping.MapConsoleKeyToKey (consoleKeyInfo.Key, out _);
+						k = ConsoleKeyMapping.MapKeyModifiers (consoleKeyInfo, k);
+						key = new KeyEvent (k, MapKeyModifiers (k));
+						keyDownHandler (key);
+						keyHandler (key);
+					}
+				} else {
+					cki = EscSeqUtils.ResizeArray (consoleKeyInfo, cki);
+				}
+			}
+		}
+
+		void ProcessMouseEvent (MouseFlags mouseFlag, Point pos)
+		{
+			var me = new MouseEvent () {
+				Flags = mouseFlag,
+				X = pos.X,
+				Y = pos.Y
+			};
+			mouseHandler (me);
+		}
+
+		void ProcessContinuousButtonPressed (MouseFlags mouseFlag, Point pos)
+		{
+			ProcessMouseEvent (mouseFlag, pos);
+		}
+
 		Action<KeyEvent> keyHandler;
 		Action<KeyEvent> keyDownHandler;
 		Action<KeyEvent> keyUpHandler;
@@ -835,17 +530,12 @@ namespace Terminal.Gui {
 			};
 		}
 
-		Curses.Event oldMouseEvents, reportableMouseEvents;
 		public override void Init (Action terminalResized)
 		{
 			if (window != null)
 				return;
 
 			try {
-				//Set cursor key to application.
-				//Console.Out.Write ("\x1b[?1h");
-				//Console.Out.Flush ();
-
 				window = Curses.initscr ();
 				Curses.set_escdelay (10);
 			} catch (Exception e) {
@@ -892,10 +582,8 @@ namespace Terminal.Gui {
 			Curses.noecho ();
 
 			Curses.Window.Standard.keypad (true);
-			reportableMouseEvents = Curses.mousemask (Curses.Event.AllEvents | Curses.Event.ReportMousePosition, out oldMouseEvents);
 			TerminalResized = terminalResized;
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition))
-				StartReportingMouseMoves ();
+			StartReportingMouseMoves ();
 
 			CurrentAttribute = MakeColor (Color.White, Color.Black);
 
@@ -944,8 +632,7 @@ namespace Terminal.Gui {
 		public override void ResizeScreen ()
 		{
 			Clip = new Rect (0, 0, Cols, Rows);
-			Console.Out.Write ("\x1b[3J");
-			Console.Out.Flush ();
+			Curses.refresh ();
 		}
 
 		public override void UpdateOffScreen ()
@@ -1065,25 +752,21 @@ namespace Terminal.Gui {
 
 		public override void Suspend ()
 		{
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition))
-				StopReportingMouseMoves ();
+			StopReportingMouseMoves ();
 			Platform.Suspend ();
 			Curses.Window.Standard.redrawwin ();
 			Curses.refresh ();
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition))
-				StartReportingMouseMoves ();
+			StartReportingMouseMoves ();
 		}
 
 		public override void StartReportingMouseMoves ()
 		{
-			Console.Out.Write ("\x1b[?1003h");
-			Console.Out.Flush ();
+			Console.Out.Write (EscSeqUtils.EnableMouseEvents);
 		}
 
 		public override void StopReportingMouseMoves ()
 		{
-			Console.Out.Write ("\x1b[?1003l");
-			Console.Out.Flush ();
+			Console.Out.Write (EscSeqUtils.DisableMouseEvents);
 		}
 
 		//int lastMouseInterval;
@@ -1126,7 +809,6 @@ namespace Terminal.Gui {
 
 			if (visibility != CursorVisibility.Invisible) {
 				Console.Out.Write ("\x1b[{0} q", ((int)visibility >> 24) & 0xFF);
-				Console.Out.Flush ();
 			}
 
 			currentCursorVisibility = visibility;
@@ -1191,8 +873,8 @@ namespace Terminal.Gui {
 			background = default;
 			int back = -1;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains ((value >> 12) & 0xffff)) {
 				hasColor = true;
 				back = (value >> 12) & 0xffff;
@@ -1285,6 +967,7 @@ namespace Terminal.Gui {
 
 		bool CheckSupport ()
 		{
+#pragma warning disable RCS1075 // Avoid empty catch clause that catches System.Exception.
 			try {
 				var (exitCode, result) = ClipboardProcessRunner.Bash ("which xclip", waitForOutput: true);
 				if (exitCode == 0 && result.FileExists ()) {
@@ -1294,6 +977,7 @@ namespace Terminal.Gui {
 			} catch (Exception) {
 				// Permissions issue.
 			}
+#pragma warning restore RCS1075 // Avoid empty catch clause that catches System.Exception.
 			return false;
 		}
 

+ 3 - 27
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -1,30 +1,6 @@
 //
 // mainloop.cs: Simple managed mainloop implementation.
 //
-// Authors:
-//   Miguel de Icaza ([email protected])
-//
-// Copyright (C) 2011 Novell (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
 using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
@@ -52,7 +28,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		///   Condition on which to wake up from file descriptor activity.  These match the Linux/BSD poll definitions.
+		///	Condition on which to wake up from file descriptor activity.  These match the Linux/BSD poll definitions.
 		/// </summary>
 		[Flags]
 		public enum Condition : short {
@@ -127,10 +103,10 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		///   Removes an active watch from the mainloop.
+		///	Removes an active watch from the mainloop.
 		/// </summary>
 		/// <remarks>
-		///   The token parameter is the value returned from AddWatch
+		///	The token parameter is the value returned from AddWatch
 		/// </remarks>
 		public void RemoveWatch (object token)
 		{

+ 14 - 21
Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs

@@ -6,7 +6,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+//	 http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,8 +21,6 @@ using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Threading;
 
-
-
 namespace Unix.Terminal {
 	/// <summary>
 	/// Represents a dynamically loaded unmanaged library in a (partially) platform independent manner.
@@ -45,7 +43,7 @@ namespace Unix.Terminal {
 		static bool IsNetCore;
 
 		public static bool IsMacOSPlatform => IsMacOS;
-		
+
 		[DllImport ("libc")]
 		static extern int uname (IntPtr buf);
 
@@ -105,11 +103,11 @@ namespace Unix.Terminal {
 		//
 		public UnmanagedLibrary (string [] libraryPathAlternatives, bool isFullPath)
 		{
-			if (isFullPath){
+			if (isFullPath) {
 				this.libraryPath = FirstValidLibraryPath (libraryPathAlternatives);
 				this.handle = PlatformSpecificLoadLibrary (this.libraryPath);
 			} else {
-				foreach (var lib in libraryPathAlternatives){
+				foreach (var lib in libraryPathAlternatives) {
 					this.handle = PlatformSpecificLoadLibrary (lib);
 					if (this.handle != IntPtr.Zero)
 						break;
@@ -164,13 +162,13 @@ namespace Unix.Terminal {
 		}
 
 		public T GetNativeMethodDelegate<T> (string methodName)
-		    where T : class
+			where T : class
 		{
 			var ptr = LoadSymbol (methodName);
 			if (ptr == IntPtr.Zero) {
 				throw new MissingMethodException (string.Format ("The native method \"{0}\" does not exist", methodName));
 			}
-			return Marshal.GetDelegateForFunctionPointer<T>(ptr);  // non-generic version is obsolete
+			return Marshal.GetDelegateForFunctionPointer<T> (ptr);  // non-generic version is obsolete
 		}
 
 		/// <summary>
@@ -209,12 +207,11 @@ namespace Unix.Terminal {
 				}
 			}
 			throw new FileNotFoundException (
-			    String.Format ("Error loading native library. Not found in any of the possible locations: {0}",
+				String.Format ("Error loading native library. Not found in any of the possible locations: {0}",
 				string.Join (",", libraryPathAlternatives)));
 		}
 
-		static class Windows
-		{
+		static class Windows {
 			[DllImport ("kernel32.dll")]
 			internal static extern IntPtr LoadLibrary (string filename);
 
@@ -222,8 +219,7 @@ namespace Unix.Terminal {
 			internal static extern IntPtr GetProcAddress (IntPtr hModule, string procName);
 		}
 
-		static class Linux
-		{
+		static class Linux {
 			[DllImport ("libdl.so")]
 			internal static extern IntPtr dlopen (string filename, int flags);
 
@@ -231,8 +227,7 @@ namespace Unix.Terminal {
 			internal static extern IntPtr dlsym (IntPtr handle, string symbol);
 		}
 
-		static class MacOSX
-		{
+		static class MacOSX {
 			[DllImport ("libSystem.dylib")]
 			internal static extern IntPtr dlopen (string filename, int flags);
 
@@ -247,8 +242,7 @@ namespace Unix.Terminal {
 		/// dlopen and dlsym from the current process as on Linux
 		/// Mono sure is linked against these symbols.
 		/// </summary>
-		static class Mono
-		{
+		static class Mono {
 			[DllImport ("__Internal")]
 			internal static extern IntPtr dlopen (string filename, int flags);
 
@@ -261,13 +255,12 @@ namespace Unix.Terminal {
 		/// dlopen and dlsym from the "libcoreclr.so",
 		/// to avoid the dependency on libc-dev Linux.
 		/// </summary>
-		static class CoreCLR
-		{
+		static class CoreCLR {
 #if NET6_0
 			// Custom resolver to support true single-file apps
 			// (those which run directly from bundle; in-memory).
-			//     -1 on Unix means self-referencing binary (libcoreclr.so)
-			//     0 means fallback to CoreCLR's internal resolution
+			//	 -1 on Unix means self-referencing binary (libcoreclr.so)
+			//	 0 means fallback to CoreCLR's internal resolution
 			// Note: meaning of -1 stay the same even for non-single-file form factors.
 			static CoreCLR() =>  NativeLibrary.SetDllImportResolver(typeof(CoreCLR).Assembly,
 				(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) =>

+ 0 - 5
Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs

@@ -145,11 +145,6 @@ namespace Unix.Terminal {
 			if (l == 1 || l != lines || c != cols) {
 				lines = l;
 				cols = c;
-				//if (l <= 0 || c <= 0) {
-				//	Console.Out.Write ($"\x1b[8;50;{c}t");
-				//	Console.Out.Flush ();
-				//	return false;
-				//}
 				return true;
 			}
 			return false;

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

@@ -53,7 +53,6 @@ namespace Unix.Terminal {
 		public const int COLOR_WHITE = unchecked((int)0x7);
 		public const int COLOR_GRAY = unchecked((int)0x8);
 		public const int KEY_CODE_YES = unchecked((int)0x100);
-		public const int KEY_CODE_SEQ = unchecked((int)0x5b);
 		public const int ERR = unchecked((int)0xffffffff);
 		public const int TIOCGWINSZ  = unchecked((int)0x5413);
 		public const int TIOCGWINSZ_MAC  = unchecked((int)0x40087468);
@@ -69,7 +68,7 @@ namespace Unix.Terminal {
 			Button2Released = unchecked((int)0x20),
 			Button2Clicked = unchecked((int)0x80),
 			Button2DoubleClicked = unchecked((int)0x100),
-			Button2TrippleClicked = unchecked((int)0x200),
+			Button2TripleClicked = unchecked((int)0x200),
 			Button3Pressed = unchecked((int)0x800),
 			Button3Released = unchecked((int)0x400),
 			Button3Clicked = unchecked((int)0x1000),
@@ -106,6 +105,7 @@ namespace Unix.Terminal {
 		public const int KeyPPage = unchecked((int)0x153);
 		public const int KeyHome = unchecked((int)0x106);
 		public const int KeyMouse = unchecked((int)0x199);
+		public const int KeyCSI = unchecked((int)0x5b);
 		public const int KeyEnd = unchecked((int)0x168);
 		public const int KeyDeleteChar = unchecked((int)0x14a);
 		public const int KeyInsertChar = unchecked((int)0x14b);

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 284 - 289
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs


+ 11 - 12
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -1,9 +1,6 @@
 //
 // FakeDriver.cs: A fake ConsoleDriver for unit tests. 
 //
-// Authors:
-//   Charlie Kindel (github.com/tig)
-//
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -48,7 +45,7 @@ namespace Terminal.Gui {
 		// Only handling left here because not all terminals has a horizontal scroll bar.
 		public override int Left => 0;
 		public override int Top => 0;
-		public override bool HeightAsBuffer { get; set; }
+		public override bool EnableConsoleScrolling { get; set; }
 		private IClipboard clipboard = null;
 		public override IClipboard Clipboard => clipboard;
 
@@ -223,6 +220,8 @@ namespace Terminal.Gui {
 
 		public override void Init (Action terminalResized)
 		{
+			FakeConsole.MockKeyPresses.Clear ();
+
 			TerminalResized = terminalResized;
 
 			cols = FakeConsole.WindowWidth = FakeConsole.BufferWidth = FakeConsole.WIDTH;
@@ -245,8 +244,8 @@ namespace Terminal.Gui {
 		{
 			redrawColor = color;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains (color & 0xffff)) {
 				FakeConsole.BackgroundColor = (ConsoleColor)(color & 0xffff);
 			}
@@ -535,7 +534,7 @@ namespace Terminal.Gui {
 			FakeConsole.SetBufferSize (width, height);
 			cols = width;
 			rows = height;
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				SetWindowSize (width, height);
 			}
 			ProcessResize ();
@@ -544,7 +543,7 @@ namespace Terminal.Gui {
 		public void SetWindowSize (int width, int height)
 		{
 			FakeConsole.SetWindowSize (width, height);
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				if (width != cols || height != rows) {
 					SetBufferSize (width, height);
 					cols = width;
@@ -556,7 +555,7 @@ namespace Terminal.Gui {
 
 		public void SetWindowPosition (int left, int top)
 		{
-			if (HeightAsBuffer) {
+			if (EnableConsoleScrolling) {
 				this.left = Math.Max (Math.Min (left, Cols - FakeConsole.WindowWidth), 0);
 				this.top = Math.Max (Math.Min (top, Rows - FakeConsole.WindowHeight), 0);
 			} else if (this.left > 0 || this.top > 0) {
@@ -575,7 +574,7 @@ namespace Terminal.Gui {
 
 		public override void ResizeScreen ()
 		{
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				if (FakeConsole.WindowHeight > 0) {
 					// Can raise an exception while is still resizing.
 					try {
@@ -629,8 +628,8 @@ namespace Terminal.Gui {
 			foreground = default;
 			background = default;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains (value & 0xffff)) {
 				hasColor = true;
 				background = (Color)(ConsoleColor)(value & 0xffff);

+ 4 - 4
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeMainLoop.cs

@@ -15,7 +15,7 @@ namespace Terminal.Gui {
 		AutoResetEvent waitForProbe = new AutoResetEvent (false);
 		ConsoleKeyInfo? keyResult = null;
 		MainLoop mainLoop;
-		Func<ConsoleKeyInfo> consoleKeyReaderFn = () => FakeConsole.ReadKey (true);
+		//Func<ConsoleKeyInfo> consoleKeyReaderFn = () => ;
 
 		/// <summary>
 		/// Invoked when a Key is pressed.
@@ -31,11 +31,11 @@ namespace Terminal.Gui {
 			// consoleDriver is not needed/used in FakeConsole
 		}
 
-		void WindowsKeyReader ()
+		void MockKeyReader ()
 		{
 			while (true) {
 				waitForProbe.WaitOne ();
-				keyResult = consoleKeyReaderFn ();
+				keyResult = FakeConsole.ReadKey (true);
 				keyReady.Set ();
 			}
 		}
@@ -43,7 +43,7 @@ namespace Terminal.Gui {
 		void IMainLoopDriver.Setup (MainLoop mainLoop)
 		{
 			this.mainLoop = mainLoop;
-			Thread readThread = new Thread (WindowsKeyReader);
+			Thread readThread = new Thread (MockKeyReader);
 			readThread.Start ();
 		}
 

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 258 - 828
Terminal.Gui/ConsoleDrivers/NetDriver.cs


+ 56 - 41
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -1,30 +1,6 @@
 //
 // WindowsDriver.cs: Windows specific driver
 //
-// Authors:
-//   Miguel de Icaza ([email protected])
-//   Nick Van Dyck ([email protected])
-//
-// Copyright (c) 2018
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-//
 using NStack;
 using System;
 using System.Collections.Generic;
@@ -646,7 +622,7 @@ namespace Terminal.Gui {
 			}
 		}
 
-#if false      // Not needed on the constructor. Perhaps could be used on resizing. To study.
+#if false      // Not needed on the constructor. Perhaps could be used on resizing. To study.                                                                                     
 		[DllImport ("kernel32.dll", ExactSpelling = true)]
 		static extern IntPtr GetConsoleWindow ();
 
@@ -739,7 +715,7 @@ namespace Terminal.Gui {
 		public override int Rows => rows;
 		public override int Left => left;
 		public override int Top => top;
-		public override bool HeightAsBuffer { get; set; }
+		public override bool EnableConsoleScrolling { get; set; }
 		public override IClipboard Clipboard => clipboard;
 		public override int [,,] Contents => contents;
 
@@ -767,14 +743,14 @@ namespace Terminal.Gui {
 
 			mLoop.ProcessInput = (e) => ProcessInput (e);
 
-			mLoop.WinChanged = (e) => {
-				ChangeWin (e);
+			mLoop.WinChanged = (s,e) => {
+				ChangeWin (e.Size);
 			};
 		}
 
 		private void ChangeWin (Size e)
 		{
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				var w = e.Width;
 				if (w == cols - 3 && e.Height < rows) {
 					w += 3;
@@ -915,8 +891,12 @@ namespace Terminal.Gui {
 				left = pos.X;
 				top = pos.Y;
 				cols = inputEvent.WindowBufferSizeEvent.size.X;
-				rows = inputEvent.WindowBufferSizeEvent.size.Y;
-				//System.Diagnostics.Debug.WriteLine ($"{HeightAsBuffer},{cols},{rows}");
+				if (EnableConsoleScrolling) {
+					rows = Math.Max (inputEvent.WindowBufferSizeEvent.size.Y, rows);
+				} else {
+					rows = inputEvent.WindowBufferSizeEvent.size.Y;
+				}
+				//System.Diagnostics.Debug.WriteLine ($"{EnableConsoleScrolling},{cols},{rows}");
 				ResizeScreen ();
 				UpdateOffScreen ();
 				TerminalResized?.Invoke ();
@@ -1459,6 +1439,19 @@ namespace Terminal.Gui {
 			TerminalResized = terminalResized;
 
 			try {
+				// Needed for Windows Terminal
+				// ESC [ ? 1047 h  Activate xterm alternative buffer (no backscroll)
+				// ESC [ ? 1047 l  Restore xterm working buffer (with backscroll)
+				// ESC [ ? 1048 h  Save cursor position
+				// ESC [ ? 1048 l  Restore cursor position
+				// ESC [ ? 1049 h  Save cursor position and activate xterm alternative buffer (no backscroll)
+				// ESC [ ? 1049 l  Restore cursor position and restore xterm working buffer (with backscroll)
+				// Per Issue #2264 using the alterantive screen buffer is required for Windows Terminal to not 
+				// wipe out the backscroll buffer when the application exits.
+				Console.Out.Write ("\x1b[?1047h");
+
+				// Console.Out.Flush () is not needed. See https://stackoverflow.com/a/20450486/297526
+
 				var winSize = WinConsole.GetConsoleOutputWindow (out Point pos);
 				cols = winSize.Width;
 				rows = winSize.Height;
@@ -1467,6 +1460,9 @@ namespace Terminal.Gui {
 				CurrentAttribute = MakeColor (Color.White, Color.Black);
 				InitalizeColorSchemes ();
 
+				CurrentAttribute = MakeColor (Color.White, Color.Black);
+				InitalizeColorSchemes ();
+
 				ResizeScreen ();
 				UpdateOffScreen ();
 			} catch (Win32Exception e) {
@@ -1485,8 +1481,15 @@ namespace Terminal.Gui {
 				Right = (short)Cols
 			};
 			WinConsole.ForceRefreshCursorVisibility ();
-			Console.Out.Write ("\x1b[3J");
-			Console.Out.Flush ();
+			if (!EnableConsoleScrolling) {
+				// ANSI ESC "[xJ" Clears part of the screen.
+				// If n is 0 (or missing), clear from cursor to end of screen.
+				// If n is 1, clear from cursor to beginning of the screen.
+				// If n is 2, clear entire screen (and moves cursor to upper left on DOS ANSI.SYS).
+				// If n is 3, clear entire screen and delete all lines saved in the scrollback buffer
+				// DO NOT USE 3J - even with the alternate screen buffer, it clears the entire scrollback buffer
+				Console.Out.Write ("\x1b[3J");
+			}
 		}
 
 		public override void UpdateOffScreen ()
@@ -1653,7 +1656,7 @@ namespace Terminal.Gui {
 			if (damageRegion.Left == -1)
 				return;
 
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				var windowSize = WinConsole.GetConsoleBufferWindow (out _);
 				if (!windowSize.IsEmpty && (windowSize.Width != Cols || windowSize.Height != Rows))
 					return;
@@ -1700,6 +1703,18 @@ namespace Terminal.Gui {
 		{
 			WinConsole.Cleanup ();
 			WinConsole = null;
+
+			// Needed for Windows Terminal
+			// Clear the alternative screen buffer from the cursor to the
+			// end of the screen.
+			// Note, [3J causes Windows Terminal to wipe out the entire NON ALTERNATIVE
+			// backbuffer! So we need to use [0J instead.
+			Console.Out.Write ("\x1b[0J");
+
+			// Disable alternative screen buffer.
+			Console.Out.Write ("\x1b[?1047l");
+
+			// Console.Out.Flush () is not needed. See https://stackoverflow.com/a/20450486/297526
 		}
 
 		/// <inheritdoc/>
@@ -1780,8 +1795,8 @@ namespace Terminal.Gui {
 			foreground = default;
 			background = default;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains ((value >> 4) & 0xffff)) {
 				hasColor = true;
 				background = (Color)(ConsoleColor)((value >> 4) & 0xffff);
@@ -1853,8 +1868,8 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Invoked when the window is changed.
 		/// </summary>
-		public Action<Size> WinChanged;
-
+		public EventHandler<SizeChangedEventArgs> WinChanged;
+		
 		public WindowsMainLoop (ConsoleDriver consoleDriver = null)
 		{
 			this.consoleDriver = consoleDriver ?? throw new ArgumentNullException ("Console driver instance must be provided.");
@@ -1897,9 +1912,9 @@ namespace Terminal.Gui {
 		{
 			while (true) {
 				Thread.Sleep (100);
-				if (!consoleDriver.HeightAsBuffer) {
+				if (!consoleDriver.EnableConsoleScrolling) {
 					windowSize = winConsole.GetConsoleBufferWindow (out _);
-					//System.Diagnostics.Debug.WriteLine ($"{consoleDriver.HeightAsBuffer},{windowSize.Width},{windowSize.Height}");
+					//System.Diagnostics.Debug.WriteLine ($"{consoleDriver.EnableConsoleScrolling},{windowSize.Width},{windowSize.Height}");
 					if (windowSize != Size.Empty && windowSize.Width != consoleDriver.Cols
 						|| windowSize.Height != consoleDriver.Rows) {
 						return;
@@ -1976,7 +1991,7 @@ namespace Terminal.Gui {
 			}
 			if (winChanged) {
 				winChanged = false;
-				WinChanged?.Invoke (windowSize);
+				WinChanged?.Invoke (this, new SizeChangedEventArgs(windowSize));
 			}
 		}
 	}

+ 102 - 65
Terminal.Gui/Core/Application.cs

@@ -34,7 +34,7 @@ namespace Terminal.Gui {
 	/// // A simple Terminal.Gui app that creates a window with a frame and title with 
 	/// // 5 rows/columns of padding.
 	/// Application.Init();
-	/// var win = new Window ("Hello World - CTRL-Q to quit") {
+	/// var win = new Window ($"Example App ({Application.QuitKey} to quit)") {
 	///     X = 5,
 	///     Y = 5,
 	///     Width = Dim.Fill (5),
@@ -59,7 +59,7 @@ namespace Terminal.Gui {
 	///     to the mainloop, allowing user code to use async/await.
 	///   </para>
 	/// </remarks>
-	public static class Application {
+	public static partial class Application {
 		static readonly Stack<Toplevel> toplevels = new Stack<Toplevel> ();
 
 		/// <summary>
@@ -114,27 +114,39 @@ namespace Terminal.Gui {
 		/// </summary>
 		public static View WantContinuousButtonPressedView { get; private set; }
 
-		private static bool? _heightAsBuffer;
+		private static bool? _enableConsoleScrolling;
 
 		/// <summary>
-		/// The current <see cref="ConsoleDriver.HeightAsBuffer"/> used in the terminal.
+		/// The current <see cref="ConsoleDriver.EnableConsoleScrolling"/> used in the terminal.
 		/// </summary>
-		/// 
-		[SerializableConfigurationProperty (Scope = typeof(SettingsScope))]
-		public static bool HeightAsBuffer {
+		/// <remarks>
+		/// <para>
+		/// If <see langword="false"/> (the default) the height of the Terminal.Gui application (<see cref="ConsoleDriver.Rows"/>) 
+		/// tracks to the height of the visible console view when the console is resized. In this case 
+		/// scrolling in the console will be disabled and all <see cref="ConsoleDriver.Rows"/> will remain visible.
+		/// </para>
+		/// <para>
+		/// If <see langword="true"/> then height of the Terminal.Gui application <see cref="ConsoleDriver.Rows"/> only tracks 
+		/// the height of the visible console view when the console is made larger (the application will only grow in height, never shrink). 
+		/// In this case console scrolling is enabled and the contents (<see cref="ConsoleDriver.Rows"/> high) will scroll
+		/// as the console scrolls. 
+		/// </para>
+		/// This API was previously named 'HeightAsBuffer` but was renamed to make its purpose more clear.
+		/// </remarks>
+		[SerializableConfigurationProperty (Scope = typeof (SettingsScope))]
+		public static bool EnableConsoleScrolling {
 			get {
 				if (Driver == null) {
-					return _heightAsBuffer.HasValue && _heightAsBuffer.Value;
+					return _enableConsoleScrolling.HasValue && _enableConsoleScrolling.Value;
 				}
-				return Driver.HeightAsBuffer;
+				return Driver.EnableConsoleScrolling;
 			}
 			set {
-				_heightAsBuffer = value;
+				_enableConsoleScrolling = value;
 				if (Driver == null) {
 					return;
 				}
-
-				Driver.HeightAsBuffer = _heightAsBuffer.Value;
+				Driver.EnableConsoleScrolling = value;
 			}
 		}
 
@@ -143,22 +155,22 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.
 		/// </summary>
-		[SerializableConfigurationProperty (Scope = typeof(SettingsScope)), JsonConverter(typeof(KeyJsonConverter))]
+		[SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
 		public static Key AlternateForwardKey {
 			get => alternateForwardKey;
 			set {
 				if (alternateForwardKey != value) {
 					var oldKey = alternateForwardKey;
 					alternateForwardKey = value;
-					OnAlternateForwardKeyChanged (oldKey);
+					OnAlternateForwardKeyChanged (new KeyChangedEventArgs (oldKey, value));
 				}
 			}
 		}
 
-		static void OnAlternateForwardKeyChanged (Key oldKey)
+		static void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
 		{
-			foreach (var top in toplevels.ToArray()) {
-				top.OnAlternateForwardKeyChanged (oldKey);
+			foreach (var top in toplevels.ToArray ()) {
+				top.OnAlternateForwardKeyChanged (e);
 			}
 		}
 
@@ -167,21 +179,21 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.
 		/// </summary>
-		[SerializableConfigurationProperty (Scope = typeof(SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
+		[SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
 		public static Key AlternateBackwardKey {
 			get => alternateBackwardKey;
 			set {
 				if (alternateBackwardKey != value) {
 					var oldKey = alternateBackwardKey;
 					alternateBackwardKey = value;
-					OnAlternateBackwardKeyChanged (oldKey);
+					OnAlternateBackwardKeyChanged (new KeyChangedEventArgs (oldKey, value));
 				}
 			}
 		}
 
-		static void OnAlternateBackwardKeyChanged (Key oldKey)
+		static void OnAlternateBackwardKeyChanged (KeyChangedEventArgs oldKey)
 		{
-			foreach (var top in toplevels.ToArray()) {
+			foreach (var top in toplevels.ToArray ()) {
 				top.OnAlternateBackwardKeyChanged (oldKey);
 			}
 		}
@@ -191,14 +203,14 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Gets or sets the key to quit the application.
 		/// </summary>
-		[SerializableConfigurationProperty (Scope = typeof(SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
+		[SerializableConfigurationProperty (Scope = typeof (SettingsScope)), JsonConverter (typeof (KeyJsonConverter))]
 		public static Key QuitKey {
 			get => quitKey;
 			set {
 				if (quitKey != value) {
 					var oldKey = quitKey;
 					quitKey = value;
-					OnQuitKeyChanged (oldKey);
+					OnQuitKeyChanged (new KeyChangedEventArgs (oldKey, value));
 				}
 			}
 		}
@@ -210,11 +222,11 @@ namespace Terminal.Gui {
 		/// </summary>
 		public static List<CultureInfo> SupportedCultures => supportedCultures;
 
-		static void OnQuitKeyChanged (Key oldKey)
+		static void OnQuitKeyChanged (KeyChangedEventArgs e)
 		{
 			// Duplicate the list so if it changes during enumeration we're safe
-			foreach (var top in toplevels.ToArray()) {
-				top.OnQuitKeyChanged (oldKey);
+			foreach (var top in toplevels.ToArray ()) {
+				top.OnQuitKeyChanged (e);
 			}
 		}
 
@@ -245,7 +257,7 @@ namespace Terminal.Gui {
 		///	<see cref="Begin(Toplevel)"/> must also subscribe to <see cref="NotifyStopRunState"/>
 		///	and manually dispose of the <see cref="RunState"/> token when the application is done.
 		/// </remarks>
-		public static event Action<RunState> NotifyNewRunState;
+		public static event EventHandler<RunStateEventArgs> NotifyNewRunState;
 
 		/// <summary>
 		/// Notify that a existent <see cref="RunState"/> is stopping (<see cref="End(RunState)"/> was called).
@@ -255,7 +267,7 @@ namespace Terminal.Gui {
 		///	<see cref="Begin(Toplevel)"/> must also subscribe to <see cref="NotifyStopRunState"/>
 		///	and manually dispose of the <see cref="RunState"/> token when the application is done.
 		/// </remarks>
-		public static event Action<Toplevel> NotifyStopRunState;
+		public static event EventHandler<ToplevelEventArgs> NotifyStopRunState;
 
 		/// <summary>
 		///   This event is raised on each iteration of the <see cref="MainLoop"/>. 
@@ -445,7 +457,7 @@ namespace Terminal.Gui {
 			MainLoop = new MainLoop (mainLoopDriver);
 
 			try {
-				Driver.HeightAsBuffer = HeightAsBuffer;
+				Driver.EnableConsoleScrolling = EnableConsoleScrolling;
 				Driver.Init (TerminalResized);
 			} catch (InvalidOperationException ex) {
 				// This is a case where the driver is unable to initialize the console.
@@ -708,15 +720,25 @@ namespace Terminal.Gui {
 		/// </summary>
 		public static View MouseGrabView => mouseGrabView;
 
+		/// <summary>
+		/// Event to be invoked when a view want grab the mouse which can be canceled.
+		/// </summary>
+		public static event EventHandler<GrabMouseEventArgs> GrabbingMouse;
+
+		/// <summary>
+		/// Event to be invoked when a view want ungrab the mouse which can be canceled.
+		/// </summary>
+		public static event EventHandler<GrabMouseEventArgs> UnGrabbingMouse;
+
 		/// <summary>
 		/// Event to be invoked when a view grab the mouse.
 		/// </summary>
-		public static event Action<View> GrabbedMouse;
+		public static event EventHandler<ViewEventArgs> GrabbedMouse;
 
 		/// <summary>
 		/// Event to be invoked when a view ungrab the mouse.
 		/// </summary>
-		public static event Action<View> UnGrabbedMouse;
+		public static event EventHandler<ViewEventArgs> UnGrabbedMouse;
 
 		/// <summary>
 		/// Grabs the mouse, forcing all mouse events to be routed to the specified view until UngrabMouse is called.
@@ -727,9 +749,11 @@ namespace Terminal.Gui {
 		{
 			if (view == null)
 				return;
-			OnGrabbedMouse (view);
-			mouseGrabView = view;
-			Driver.UncookMouse ();
+			if (!OnGrabbingMouse (view)) {
+				OnGrabbedMouse (view);
+				mouseGrabView = view;
+				Driver.UncookMouse ();
+			}
 		}
 
 		/// <summary>
@@ -739,23 +763,43 @@ namespace Terminal.Gui {
 		{
 			if (mouseGrabView == null)
 				return;
-			OnUnGrabbedMouse (mouseGrabView);
-			mouseGrabView = null;
-			Driver.CookMouse ();
+			if (!OnUnGrabbingMouse (mouseGrabView)) {
+				OnUnGrabbedMouse (mouseGrabView);
+				mouseGrabView = null;
+				Driver.CookMouse ();
+			}
+		}
+
+		static bool OnGrabbingMouse (View view)
+		{
+			if (view == null)
+				return false;
+			var evArgs = new GrabMouseEventArgs (view);
+			GrabbingMouse?.Invoke (view, evArgs);
+			return evArgs.Cancel;
+		}
+
+		static bool OnUnGrabbingMouse (View view)
+		{
+			if (view == null)
+				return false;
+			var evArgs = new GrabMouseEventArgs (view);
+			UnGrabbingMouse?.Invoke (view, evArgs);
+			return evArgs.Cancel;
 		}
 
 		static void OnGrabbedMouse (View view)
 		{
 			if (view == null)
 				return;
-			GrabbedMouse?.Invoke (view);
+			GrabbedMouse?.Invoke (view, new ViewEventArgs (view));
 		}
 
 		static void OnUnGrabbedMouse (View view)
 		{
 			if (view == null)
 				return;
-			UnGrabbedMouse?.Invoke (view);
+			UnGrabbedMouse?.Invoke (view, new ViewEventArgs (view));
 		}
 
 		/// <summary>
@@ -939,13 +983,10 @@ namespace Terminal.Gui {
 
 			var rs = new RunState (toplevel);
 
-			if (toplevel is ISupportInitializeNotification initializableNotification &&
-			    !initializableNotification.IsInitialized) {
-				initializableNotification.BeginInit ();
-				initializableNotification.EndInit ();
-			} else if (toplevel is ISupportInitialize initializable) {
-				initializable.BeginInit ();
-				initializable.EndInit ();
+			// View implements ISupportInitializeNotification which is derived from ISupportInitialize
+			if (!toplevel.IsInitialized) {
+				toplevel.BeginInit ();
+				toplevel.EndInit ();
 			}
 
 			lock (toplevels) {
@@ -1017,7 +1058,7 @@ namespace Terminal.Gui {
 				Driver.Refresh ();
 			}
 
-			NotifyNewRunState?.Invoke (rs);
+			NotifyNewRunState?.Invoke (toplevel, new RunStateEventArgs (rs));
 			return rs;
 		}
 
@@ -1121,6 +1162,8 @@ namespace Terminal.Gui {
 			NotifyStopRunState = null;
 			_initialized = false;
 			mouseGrabView = null;
+			_enableConsoleScrolling = false;
+			lastMouseOwnerView = null;
 
 			// Reset synchronization context to allow the user to run async/await,
 			// as the main loop has been ended, the synchronization context from 
@@ -1206,7 +1249,7 @@ namespace Terminal.Gui {
 					MdiTop?.OnDeactivate (state.Toplevel);
 					state.Toplevel = Current;
 					MdiTop?.OnActivate (state.Toplevel);
-					Top.SetChildNeedsDisplay ();
+					Top.SetSubViewNeedsDisplay ();
 					Refresh ();
 				}
 				if (Driver.EnsureCursorVisibility ()) {
@@ -1228,6 +1271,14 @@ namespace Terminal.Gui {
 				}
 				state.Toplevel.SetNeedsDisplay (state.Toplevel.Bounds);
 			}
+			if (toplevels.Count == 1 && state.Toplevel == Top
+				&& (Driver.Cols != state.Toplevel.Frame.Width || Driver.Rows != state.Toplevel.Frame.Height)
+				&& (!state.Toplevel.NeedDisplay.IsEmpty || state.Toplevel.ChildNeedsDisplay || state.Toplevel.LayoutNeeded)) {
+
+				Driver.SetAttribute (Colors.TopLevel.Normal);
+				state.Toplevel.Clear (new Rect (0, 0, Driver.Cols, Driver.Rows));
+
+			}
 			if (!state.Toplevel.NeedDisplay.IsEmpty || state.Toplevel.ChildNeedsDisplay || state.Toplevel.LayoutNeeded
 				|| MdiChildNeedsDisplay ()) {
 				state.Toplevel.Redraw (state.Toplevel.Bounds);
@@ -1270,7 +1321,7 @@ namespace Terminal.Gui {
 
 			foreach (var top in toplevels) {
 				if (top != Current && top.Visible && (!top.NeedDisplay.IsEmpty || top.ChildNeedsDisplay || top.LayoutNeeded)) {
-					MdiTop.SetChildNeedsDisplay ();
+					MdiTop.SetSubViewNeedsDisplay ();
 					return true;
 				}
 			}
@@ -1484,24 +1535,10 @@ namespace Terminal.Gui {
 		static void OnNotifyStopRunState (Toplevel top)
 		{
 			if (ExitRunLoopAfterFirstIteration) {
-				NotifyStopRunState?.Invoke (top);
+				NotifyStopRunState?.Invoke (top, new ToplevelEventArgs (top));
 			}
 		}
 
-		/// <summary>
-		/// Event arguments for the <see cref="Application.Resized"/> event.
-		/// </summary>
-		public class ResizedEventArgs : EventArgs {
-			/// <summary>
-			/// The number of rows in the resized terminal.
-			/// </summary>
-			public int Rows { get; set; }
-			/// <summary>
-			/// The number of columns in the resized terminal.
-			/// </summary>
-			public int Cols { get; set; }
-		}
-
 		/// <summary>
 		/// Invoked when the terminal was resized. The new size of the terminal is provided.
 		/// </summary>
@@ -1517,7 +1554,7 @@ namespace Terminal.Gui {
 				t.SetRelativeLayout (full);
 				t.LayoutSubviews ();
 				t.PositionToplevels ();
-				t.OnResized (full.Size);
+				t.OnResized (new SizeChangedEventArgs (full.Size));
 			}
 			Refresh ();
 		}

+ 5 - 4
Terminal.Gui/Core/Autocomplete/Autocomplete.cs

@@ -74,18 +74,18 @@ namespace Terminal.Gui {
 			}
 		}
 
-		private void Top_Removed (View obj)
+		private void Top_Removed (object sender, SuperViewChangedEventArgs e)
 		{
 			Visible = false;
 			ManipulatePopup ();
 		}
 
-		private void Top_DrawContentComplete (Rect obj)
+		private void Top_DrawContentComplete (object sender, DrawEventArgs e)
 		{
 			ManipulatePopup ();
 		}
 
-		private void Top_DrawContent (Rect obj)
+		private void Top_DrawContent (object sender, DrawEventArgs e)
 		{
 			if (!closed) {
 				ReopenSuggestions ();
@@ -106,7 +106,7 @@ namespace Terminal.Gui {
 			}
 
 			if (!Visible && popup != null) {
-				top.Remove (popup);
+				top?.Remove (popup);
 				popup.Dispose ();
 				popup = null;
 			}
@@ -323,6 +323,7 @@ namespace Terminal.Gui {
 		{
 			if (IsWordChar ((char)kb.Key)) {
 				Visible = true;
+				ManipulatePopup ();
 				closed = false;
 				return false;
 			}

+ 137 - 55
Terminal.Gui/Core/Border.cs

@@ -131,7 +131,7 @@ namespace Terminal.Gui {
 				}
 			}
 
-			void Border_BorderChanged (Border border)
+			void Border_BorderChanged (object sender, EventArgs e)
 			{
 				Rect frame;
 				if (Border.Child != null && (Border.Child.Width is Dim || Border.Child.Height is Dim)) {
@@ -319,7 +319,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Invoked when any property of Border changes (except <see cref="Child"/>).
 		/// </summary>
-		public event Action<Border> BorderChanged;
+		public event EventHandler BorderChanged;
 
 		private BorderStyle borderStyle;
 		private bool drawMarginFrame;
@@ -331,11 +331,12 @@ namespace Terminal.Gui {
 		private Point effect3DOffset = new Point (1, 1);
 		private Attribute? effect3DBrush;
 		private ustring title = ustring.Empty;
+		private View child;
 
 		/// <summary>
 		/// Specifies the <see cref="Gui.BorderStyle"/> for a view.
 		/// </summary>
-		[JsonInclude, JsonConverter (typeof(JsonStringEnumConverter))]
+		[JsonInclude, JsonConverter (typeof (JsonStringEnumConverter))]
 		public BorderStyle BorderStyle {
 			get => borderStyle;
 			set {
@@ -448,7 +449,47 @@ namespace Terminal.Gui {
 		/// Gets or sets the single child element of a <see cref="View"/>.
 		/// </summary>
 		[JsonIgnore]
-		public View Child { get; set; }
+		public View Child {
+			get => child;
+			set {
+				child = value;
+				if (child != null && Parent != null) {
+					Parent.Initialized += Parent_Initialized;
+					Parent.Removed += Parent_Removed;
+				}
+			}
+		}
+
+		private void Parent_Removed (object sender, SuperViewChangedEventArgs e)
+		{
+			BorderBrush = default;
+			Background = default;
+			child.Removed -= Parent_Removed;
+		}
+
+		private void Parent_Initialized (object s, EventArgs e)
+		{
+			SetMarginFrameTitleBrush ();
+			child.Initialized -= Parent_Initialized;
+		}
+
+		private void SetMarginFrameTitleBrush ()
+		{
+			if (child != null) {
+				var view = Parent?.Border != null ? Parent : child;
+				if (view.ColorScheme != null) {
+					if (borderBrush == default) {
+						BorderBrush = view.GetNormalColor ().Foreground;
+					}
+					if (background == default) {
+						Background = view.GetNormalColor ().Background;
+					}
+					return;
+				}
+			}
+			BorderBrush = default;
+			Background = default;
+		}
 
 		/// <summary>
 		/// Gets the parent <see cref="Child"/> parent if any.
@@ -611,7 +652,7 @@ namespace Terminal.Gui {
 				Child.Clear (borderRect);
 			}
 
-			driver.SetAttribute (savedAttribute);
+			driver.SetAttribute (new Attribute (BorderBrush, Background));
 
 			// Draw margin frame
 			if (DrawMarginFrame) {
@@ -635,6 +676,7 @@ namespace Terminal.Gui {
 					driver.DrawWindowFrame (borderRect, 1, 1, 1, 1, BorderStyle != BorderStyle.None, fill: true, this);
 				}
 			}
+			driver.SetAttribute (savedAttribute);
 		}
 
 		private void DrawChildBorder (Rect frame, bool fill = true)
@@ -651,9 +693,13 @@ namespace Terminal.Gui {
 
 			// Draw the upper BorderThickness
 			for (int r = frame.Y - drawMarginFrame - sumThickness.Top;
-				r > 0 && r < frame.Y - drawMarginFrame - padding.Top; r++) {
+				r < frame.Y - drawMarginFrame - padding.Top; r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-					c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -661,9 +707,13 @@ namespace Terminal.Gui {
 
 			// Draw the left BorderThickness
 			for (int r = frame.Y - drawMarginFrame - padding.Top;
-				r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-					c > 0 && c < frame.X - drawMarginFrame - padding.Left; c++) {
+					c < frame.X - drawMarginFrame - padding.Left; c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -671,9 +721,13 @@ namespace Terminal.Gui {
 
 			// Draw the right BorderThickness
 			for (int r = frame.Y - drawMarginFrame - padding.Top;
-				r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.Right + drawMarginFrame + padding.Right;
-					c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -681,9 +735,9 @@ namespace Terminal.Gui {
 
 			// Draw the lower BorderThickness
 			for (int r = frame.Bottom + drawMarginFrame + padding.Bottom;
-				r > 0 && r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + sumThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X - drawMarginFrame - sumThickness.Left;
-					c > 0 && c > 0 && c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + sumThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -693,9 +747,13 @@ namespace Terminal.Gui {
 
 			// Draw the upper Padding
 			for (int r = frame.Y - drawMarginFrame - padding.Top;
-				r > 0 && r < frame.Y - drawMarginFrame; r++) {
+				r < frame.Y - drawMarginFrame; r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.X - drawMarginFrame - padding.Left;
-					c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -703,9 +761,9 @@ namespace Terminal.Gui {
 
 			// Draw the left Padding
 			for (int r = frame.Y - drawMarginFrame;
-				r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
 				for (int c = frame.X - drawMarginFrame - padding.Left;
-					c > 0 && c < frame.X - drawMarginFrame; c++) {
+					c < frame.X - drawMarginFrame; c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -713,9 +771,9 @@ namespace Terminal.Gui {
 
 			// Draw the right Padding
 			for (int r = frame.Y - drawMarginFrame;
-				r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame, driver.Rows); r++) {
 				for (int c = frame.Right + drawMarginFrame;
-					c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -723,15 +781,15 @@ namespace Terminal.Gui {
 
 			// Draw the lower Padding
 			for (int r = frame.Bottom + drawMarginFrame;
-				r > 0 && r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom + drawMarginFrame + padding.Bottom, driver.Rows); r++) {
 				for (int c = frame.X - drawMarginFrame - padding.Left;
-					c > 0 && c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right + drawMarginFrame + padding.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
 			}
 
-			driver.SetAttribute (savedAttribute);
+			driver.SetAttribute (new Attribute (BorderBrush, Background));
 
 			// Draw the MarginFrame
 			if (DrawMarginFrame) {
@@ -825,9 +883,12 @@ namespace Terminal.Gui {
 
 			// Draw the upper BorderThickness
 			for (int r = frame.Y;
-				r > 0 && r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) {
+				r < Math.Min (frame.Y + borderThickness.Top, frame.Bottom); r++) {
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.X;
-					c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -835,9 +896,13 @@ namespace Terminal.Gui {
 
 			// Draw the left BorderThickness
 			for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
-				r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.X;
-					c > 0 && c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) {
+					c < Math.Min (frame.X + borderThickness.Left, frame.Right); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -845,9 +910,13 @@ namespace Terminal.Gui {
 
 			// Draw the right BorderThickness
 			for (int r = Math.Min (frame.Y + borderThickness.Top, frame.Bottom);
-				r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = Math.Max (frame.Right - borderThickness.Right, frame.X);
-					c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -855,9 +924,9 @@ namespace Terminal.Gui {
 
 			// Draw the lower BorderThickness
 			for (int r = Math.Max (frame.Bottom - borderThickness.Bottom, frame.Y);
-				r > 0 && r < Math.Min (frame.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom, driver.Rows); r++) {
 				for (int c = frame.X;
-					c > 0 && c < Math.Min (frame.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -867,9 +936,13 @@ namespace Terminal.Gui {
 
 			// Draw the upper Padding
 			for (int r = frame.Y + borderThickness.Top;
-				r > 0 && r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) {
+				r < Math.Min (frame.Y + sumThickness.Top, frame.Bottom - borderThickness.Bottom); r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.X + borderThickness.Left;
-					c > 0 && c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -877,9 +950,13 @@ namespace Terminal.Gui {
 
 			// Draw the left Padding
 			for (int r = frame.Y + sumThickness.Top;
-				r > 0 && r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = frame.X + borderThickness.Left;
-					c > 0 && c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) {
+					c < Math.Min (frame.X + sumThickness.Left, frame.Right - borderThickness.Right); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -887,9 +964,13 @@ namespace Terminal.Gui {
 
 			// Draw the right Padding
 			for (int r = frame.Y + sumThickness.Top;
-				r > 0 && r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom - sumThickness.Bottom, driver.Rows); r++) {
+
+				if (r < 0) {
+					continue;
+				}
 				for (int c = Math.Max (frame.Right - sumThickness.Right, frame.X + sumThickness.Left);
-					c > 0 && c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) {
+					c < Math.Max (frame.Right - borderThickness.Right, frame.X + sumThickness.Left); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
@@ -897,15 +978,15 @@ namespace Terminal.Gui {
 
 			// Draw the lower Padding
 			for (int r = Math.Max (frame.Bottom - sumThickness.Bottom, frame.Y + borderThickness.Top);
-				r > 0 && r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
+				r < Math.Min (frame.Bottom - borderThickness.Bottom, driver.Rows); r++) {
 				for (int c = frame.X + borderThickness.Left;
-					c > 0 && c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
+					c < Math.Min (frame.Right - borderThickness.Right, driver.Cols); c++) {
 
 					AddRuneAt (driver, c, r, ' ');
 				}
 			}
 
-			driver.SetAttribute (savedAttribute);
+			driver.SetAttribute (new Attribute (BorderBrush, Background));
 
 			// Draw the MarginFrame
 			if (DrawMarginFrame) {
@@ -926,9 +1007,9 @@ namespace Terminal.Gui {
 
 				// Draw the upper Effect3D
 				for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
-					r > 0 && r < frame.Y; r++) {
+					r < frame.Y; r++) {
 					for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
-						c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
+						c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
@@ -936,9 +1017,9 @@ namespace Terminal.Gui {
 
 				// Draw the left Effect3D
 				for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
-					r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
-						c > 0 && c < frame.X; c++) {
+						c < frame.X; c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
@@ -946,9 +1027,9 @@ namespace Terminal.Gui {
 
 				// Draw the right Effect3D
 				for (int r = Math.Max (frame.Y + effect3DOffset.Y, 0);
-					r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = frame.Right;
-						c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
+						c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
@@ -956,9 +1037,9 @@ namespace Terminal.Gui {
 
 				// Draw the lower Effect3D
 				for (int r = frame.Bottom;
-					r > 0 && r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
+					r < Math.Min (frame.Bottom + effect3DOffset.Y, driver.Rows); r++) {
 					for (int c = Math.Max (frame.X + effect3DOffset.X, 0);
-						c > 0 && c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
+						c < Math.Min (frame.Right + effect3DOffset.X, driver.Cols); c++) {
 
 						AddRuneAt (driver, c, r, (Rune)driver.Contents [r, c, 0]);
 					}
@@ -987,9 +1068,10 @@ namespace Terminal.Gui {
 		{
 			var driver = Application.Driver;
 			if (DrawMarginFrame) {
-				driver.SetAttribute (Child.GetNormalColor ());
-				if (Child.HasFocus)
-					driver.SetAttribute (Child.ColorScheme.HotNormal);
+				driver.SetAttribute (new Attribute (BorderBrush, Background));
+				if (view.HasFocus) {
+					driver.SetAttribute (new Attribute (Child.ColorScheme.HotNormal.Foreground, Background));
+				}
 				var padding = view.Border.GetSumThickness ();
 				Rect scrRect;
 				if (view == Child) {
@@ -998,7 +1080,7 @@ namespace Terminal.Gui {
 					driver.DrawWindowTitle (scrRect, Title, 0, 0, 0, 0);
 				} else {
 					scrRect = view.ViewToScreen (new Rect (0, 0, view.Frame.Width, view.Frame.Height));
-					driver.DrawWindowTitle (scrRect, Title,
+					driver.DrawWindowTitle (scrRect, Parent.Border.Title,
 						padding.Left, padding.Top, padding.Right, padding.Bottom);
 				}
 			}
@@ -1014,9 +1096,9 @@ namespace Terminal.Gui {
 		{
 			var driver = Application.Driver;
 			if (DrawMarginFrame) {
-				driver.SetAttribute (view.GetNormalColor ());
+				driver.SetAttribute (new Attribute (BorderBrush, Background));
 				if (view.HasFocus) {
-					driver.SetAttribute (view.ColorScheme.HotNormal);
+					driver.SetAttribute (new Attribute (view.ColorScheme.HotNormal.Foreground, Background));
 				}
 				var padding = Parent.Border.GetSumThickness ();
 				var scrRect = Parent.ViewToScreen (new Rect (0, 0, rect.Width, rect.Height));
@@ -1031,7 +1113,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnBorderChanged ()
 		{
-			BorderChanged?.Invoke (this);
+			BorderChanged?.Invoke (this, new EventArgs());
 		}
 	}
-}
+}

+ 3 - 22
Terminal.Gui/Core/CollectionNavigator.cs

@@ -15,7 +15,7 @@ namespace Terminal.Gui {
 	/// If the user pauses keystrokes for a short time (see <see cref="TypingDelay"/>), the search string is cleared.
 	/// </para>
 	/// </summary>
-	public class CollectionNavigator {
+	public partial class CollectionNavigator {
 		/// <summary>
 		/// Constructs a new CollectionNavigator.
 		/// </summary>
@@ -44,29 +44,10 @@ namespace Terminal.Gui {
 		/// </summary>
 		public IEnumerable<object> Collection { get; set; }
 
-		/// <summary>
-		/// Event arguments for the <see cref="CollectionNavigator.SearchStringChanged"/> event.
-		/// </summary>
-		public class KeystrokeNavigatorEventArgs {
-			/// <summary>
-			/// he current <see cref="SearchString"/>.
-			/// </summary>
-			public string SearchString { get; }
-
-			/// <summary>
-			/// Initializes a new instance of <see cref="KeystrokeNavigatorEventArgs"/>
-			/// </summary>
-			/// <param name="searchString">The current <see cref="SearchString"/>.</param>
-			public KeystrokeNavigatorEventArgs (string searchString)
-			{
-				SearchString = searchString;
-			}
-		}
-
 		/// <summary>
 		/// This event is invoked when <see cref="SearchString"/>  changes. Useful for debugging.
 		/// </summary>
-		public event Action<KeystrokeNavigatorEventArgs> SearchStringChanged;
+		public event EventHandler<KeystrokeNavigatorEventArgs> SearchStringChanged;
 
 		private string _searchString = "";
 		/// <summary>
@@ -87,7 +68,7 @@ namespace Terminal.Gui {
 		/// <param name="e"></param>
 		public virtual void OnSearchStringChanged (KeystrokeNavigatorEventArgs e)
 		{
-			SearchStringChanged?.Invoke (e);
+			SearchStringChanged?.Invoke (this, e);
 		}
 
 		/// <summary>

+ 19 - 72
Terminal.Gui/Core/ConsoleDriver.cs

@@ -89,7 +89,7 @@ namespace Terminal.Gui {
 	}
 
 	/// <summary>
-	/// 
+	/// Indicates the RGB for true colors.
 	/// </summary>
 	public class TrueColor {
 		/// <summary>
@@ -119,7 +119,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// 
+		/// Converts true color to console color.
 		/// </summary>
 		/// <returns></returns>
 		public Color ToConsoleColor ()
@@ -504,7 +504,7 @@ namespace Terminal.Gui {
 			public bool Equals (string x, string y)
 			{
 				if (x != null && y != null) {
-					return x.ToLowerInvariant () == y.ToLowerInvariant ();
+					return string.Equals (x, y, StringComparison.InvariantCultureIgnoreCase);
 				}
 				return false;
 			}
@@ -659,72 +659,7 @@ namespace Terminal.Gui {
 		/// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Block"/></remarks>
 		BoxFix = 0x02020164,
 	}
-
-	///// <summary>
-	///// Special characters that can be drawn with 
-	///// </summary>
-	//public enum SpecialChar {
-	//	/// <summary>
-	//	/// Horizontal line character.
-	//	/// </summary>
-	//	HLine,
-
-	//	/// <summary>
-	//	/// Vertical line character.
-	//	/// </summary>
-	//	VLine,
-
-	//	/// <summary>
-	//	/// Stipple pattern
-	//	/// </summary>
-	//	Stipple,
-
-	//	/// <summary>
-	//	/// Diamond character
-	//	/// </summary>
-	//	Diamond,
-
-	//	/// <summary>
-	//	/// Upper left corner
-	//	/// </summary>
-	//	ULCorner,
-
-	//	/// <summary>
-	//	/// Lower left corner
-	//	/// </summary>
-	//	LLCorner,
-
-	//	/// <summary>
-	//	/// Upper right corner
-	//	/// </summary>
-	//	URCorner,
-
-	//	/// <summary>
-	//	/// Lower right corner
-	//	/// </summary>
-	//	LRCorner,
-
-	//	/// <summary>
-	//	/// Left tee
-	//	/// </summary>
-	//	LeftTee,
-
-	//	/// <summary>
-	//	/// Right tee
-	//	/// </summary>
-	//	RightTee,
-
-	//	/// <summary>
-	//	/// Top tee
-	//	/// </summary>
-	//	TopTee,
-
-	//	/// <summary>
-	//	/// The bottom tee.
-	//	/// </summary>
-	//	BottomTee,
-	//}
-
+	
 	/// <summary>
 	/// ConsoleDriver is an abstract class that defines the requirements for a console driver.  
 	/// There are currently three implementations: <see cref="CursesDriver"/> (for Unix and Mac), <see cref="WindowsDriver"/>, and <see cref="NetDriver"/> that uses the .NET Console API.
@@ -761,10 +696,22 @@ namespace Terminal.Gui {
 		public abstract IClipboard Clipboard { get; }
 
 		/// <summary>
-		/// If false height is measured by the window height and thus no scrolling.
-		/// If true then height is measured by the buffer height, enabling scrolling.
+		/// <para>
+		/// If <see langword="false"/> (the default) the height of the Terminal.Gui application (<see cref="Rows"/>) 
+		/// tracks to the height of the visible console view when the console is resized. In this case 
+		/// scrolling in the console will be disabled and all <see cref="Rows"/> will remain visible.
+		/// </para>
+		/// <para>
+		/// If <see langword="true"/> then height of the Terminal.Gui application <see cref="Rows"/> only tracks 
+		/// the height of the visible console view when the console is made larger (the application will only grow in height, never shrink). 
+		/// In this case console scrolling is enabled and the contents (<see cref="Rows"/> high) will scroll
+		/// as the console scrolls. 
+		/// </para>
 		/// </summary>
-		public abstract bool HeightAsBuffer { get; set; }
+		/// <remarks>
+		/// NOTE: This functionaliy is currently broken on Windows Terminal.
+		/// </remarks>
+		public abstract bool EnableConsoleScrolling { get; set; }
 
 		/// <summary>
 		/// The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag

+ 40 - 1
Terminal.Gui/Core/ConsoleKeyMapping.cs

@@ -65,10 +65,30 @@ namespace Terminal.Gui {
 				}
 				return sCode;
 			}
-
+			
 			return null;
 		}
 
+		/// <summary>
+		/// Gets the <see cref="ConsoleKey"/> from the provided <see cref="Key"/>.
+		/// </summary>
+		/// <param name="key"></param>
+		/// <returns></returns>
+		public static ConsoleKey GetConsoleKeyFromKey (Key key)
+		{
+			ConsoleModifiers mod = new ConsoleModifiers ();
+			if (key.HasFlag (Key.ShiftMask)) {
+				mod |= ConsoleModifiers.Shift;
+			}
+			if (key.HasFlag (Key.AltMask)) {
+				mod |= ConsoleModifiers.Alt;
+			}
+			if (key.HasFlag (Key.CtrlMask)) {
+				mod |= ConsoleModifiers.Control;
+			}
+			return (ConsoleKey)ConsoleKeyMapping.GetConsoleKeyFromKey ((uint)(key & ~Key.CtrlMask & ~Key.ShiftMask & ~Key.AltMask), mod, out _, out _);
+		}
+
 		/// <summary>
 		/// Get the <see cref="ConsoleKey"/> from a <see cref="Key"/>.
 		/// </summary>
@@ -334,6 +354,25 @@ namespace Terminal.Gui {
 			return (Key)consoleKey;
 		}
 
+		/// <summary>
+		/// Maps a <see cref="ConsoleKeyInfo"/> to a <see cref="Key"/>.
+		/// </summary>
+		/// <param name="keyInfo">The console key info.</param>
+		/// <param name="key">The key.</param>
+		/// <returns>The <see cref="Key"/> with <see cref="ConsoleModifiers"/> or the <paramref name="key"/></returns>
+		public static Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key)
+		{
+			Key keyMod = new Key ();
+			if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0)
+				keyMod = Key.ShiftMask;
+			if ((keyInfo.Modifiers & ConsoleModifiers.Control) != 0)
+				keyMod |= Key.CtrlMask;
+			if ((keyInfo.Modifiers & ConsoleModifiers.Alt) != 0)
+				keyMod |= Key.AltMask;
+
+			return keyMod != Key.Null ? keyMod | key : key;
+		}
+
 		private static HashSet<ScanCodeMapping> scanCodes = new HashSet<ScanCodeMapping> {
 			new ScanCodeMapping (1,27,0,27),	// Escape
 			new ScanCodeMapping (1,27,ConsoleModifiers.Shift,27),

+ 109 - 0
Terminal.Gui/Core/EscSeqUtils/EscSeqReq.cs

@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Represents the state of an ANSI escape sequence request.
+	/// </summary>
+	/// <remarks>
+	/// This is needed because there are some escape sequence requests responses that are equal
+	/// with some normal escape sequences and thus, will be only considered the responses to the
+	/// requests that were registered with this object.
+	/// </remarks>
+	public class EscSeqReqStatus {
+		/// <summary>
+		/// Gets the terminating.
+		/// </summary>
+		public string Terminating { get; }
+		/// <summary>
+		/// Gets the number of requests.
+		/// </summary>
+		public int NumRequests { get; }
+		/// <summary>
+		/// Gets information about unfinished requests.
+		/// </summary>
+		public int NumOutstanding { get; set; }
+
+		/// <summary>
+		/// Creates a new state of escape sequence request.
+		/// </summary>
+		/// <param name="terminating">The terminating.</param>
+		/// <param name="numOfReq">The number of requests.</param>
+		public EscSeqReqStatus (string terminating, int numOfReq)
+		{
+			Terminating = terminating;
+			NumRequests = NumOutstanding = numOfReq;
+		}
+	}
+
+	/// <summary>
+	/// Manages a list of <see cref="EscSeqReqStatus"/>.
+	/// </summary>
+	public class EscSeqReqProc {
+		/// <summary>
+		/// Gets the <see cref="EscSeqReqStatus"/> list.
+		/// </summary>
+		public List<EscSeqReqStatus> EscSeqReqStats { get; } = new List<EscSeqReqStatus> ();
+
+		/// <summary>
+		/// Adds a new <see cref="EscSeqReqStatus"/> instance to the <see cref="EscSeqReqStats"/> list.
+		/// </summary>
+		/// <param name="terminating">The terminating.</param>
+		/// <param name="numOfReq">The number of requests.</param>
+		public void Add (string terminating, int numOfReq = 1)
+		{
+			lock (EscSeqReqStats) {
+				var found = EscSeqReqStats.Find (x => x.Terminating == terminating);
+				if (found == null) {
+					EscSeqReqStats.Add (new EscSeqReqStatus (terminating, numOfReq));
+				} else if (found != null && found.NumOutstanding < found.NumRequests) {
+					found.NumOutstanding = Math.Min (found.NumOutstanding + numOfReq, found.NumRequests);
+				}
+			}
+		}
+
+		/// <summary>
+		/// Removes a <see cref="EscSeqReqStatus"/> instance from the <see cref="EscSeqReqStats"/> list.
+		/// </summary>
+		/// <param name="terminating">The terminating string.</param>
+		public void Remove (string terminating)
+		{
+			lock (EscSeqReqStats) {
+				var found = EscSeqReqStats.Find (x => x.Terminating == terminating);
+				if (found == null) {
+					return;
+				}
+				if (found != null && found.NumOutstanding == 0) {
+					EscSeqReqStats.Remove (found);
+				} else if (found != null && found.NumOutstanding > 0) {
+					found.NumOutstanding--;
+					if (found.NumOutstanding == 0) {
+						EscSeqReqStats.Remove (found);
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// Indicates if a <see cref="EscSeqReqStatus"/> with the <paramref name="terminating"/> exist
+		/// in the <see cref="EscSeqReqStats"/> list.
+		/// </summary>
+		/// <param name="terminating"></param>
+		/// <returns><see langword="true"/> if exist, <see langword="false"/> otherwise.</returns>
+		public bool Requested (string terminating)
+		{
+			lock (EscSeqReqStats) {
+				var found = EscSeqReqStats.Find (x => x.Terminating == terminating);
+				if (found == null) {
+					return false;
+				}
+				if (found != null && found.NumOutstanding > 0) {
+					return true;
+				} else {
+					EscSeqReqStats.Remove (found);
+				}
+				return false;
+			}
+		}
+	}
+}

+ 907 - 0
Terminal.Gui/Core/EscSeqUtils/EscSeqUtils.cs

@@ -0,0 +1,907 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Management;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Provides a platform-independent API for managing ANSI escape sequence codes.
+	/// </summary>
+	public static class EscSeqUtils {
+		/// <summary>
+		/// Represents the escape key.
+		/// </summary>
+		public static readonly char KeyEsc = (char)Key.Esc;
+		/// <summary>
+		/// Represents the CSI (Control Sequence Introducer).
+		/// </summary>
+		public static readonly string KeyCSI = $"{KeyEsc}[";
+		/// <summary>
+		/// Represents the CSI for enable any mouse event tracking.
+		/// </summary>
+		public static readonly string CSI_EnableAnyEventMouse = KeyCSI + "?1003h";
+		/// <summary>
+		/// Represents the CSI for enable SGR (Select Graphic Rendition).
+		/// </summary>
+		public static readonly string CSI_EnableSgrExtModeMouse = KeyCSI + "?1006h";
+		/// <summary>
+		/// Represents the CSI for enable URXVT (Unicode Extended Virtual Terminal).
+		/// </summary>
+		public static readonly string CSI_EnableUrxvtExtModeMouse = KeyCSI + "?1015h";
+		/// <summary>
+		/// Represents the CSI for disable any mouse event tracking.
+		/// </summary>
+		public static readonly string CSI_DisableAnyEventMouse = KeyCSI + "?1003l";
+		/// <summary>
+		/// Represents the CSI for disable SGR (Select Graphic Rendition).
+		/// </summary>
+		public static readonly string CSI_DisableSgrExtModeMouse = KeyCSI + "?1006l";
+		/// <summary>
+		/// Represents the CSI for disable URXVT (Unicode Extended Virtual Terminal).
+		/// </summary>
+		public static readonly string CSI_DisableUrxvtExtModeMouse = KeyCSI + "?1015l";
+
+		/// <summary>
+		/// Control sequence for enable mouse events.
+		/// </summary>
+		public static string EnableMouseEvents { get; set; } =
+			CSI_EnableAnyEventMouse + CSI_EnableUrxvtExtModeMouse + CSI_EnableSgrExtModeMouse;
+		/// <summary>
+		/// Control sequence for disable mouse events.
+		/// </summary>
+		public static string DisableMouseEvents { get; set; } =
+			CSI_DisableAnyEventMouse + CSI_DisableUrxvtExtModeMouse + CSI_DisableSgrExtModeMouse;
+
+		/// <summary>
+		/// Ensures a console key is mapped to one that works correctly with ANSI escape sequences.
+		/// </summary>
+		/// <param name="consoleKeyInfo">The <see cref="ConsoleKeyInfo"/>.</param>
+		/// <returns>The <see cref="ConsoleKeyInfo"/> modified.</returns>
+		public static ConsoleKeyInfo GetConsoleInputKey (ConsoleKeyInfo consoleKeyInfo)
+		{
+			ConsoleKeyInfo newConsoleKeyInfo = consoleKeyInfo;
+			ConsoleKey key;
+			var keyChar = consoleKeyInfo.KeyChar;
+			switch ((uint)keyChar) {
+			case 0:
+				if (consoleKeyInfo.Key == (ConsoleKey)64) {    // Ctrl+Space in Windows.
+					newConsoleKeyInfo = new ConsoleKeyInfo (' ', ConsoleKey.Spacebar,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0);
+				}
+				break;
+			case uint n when (n >= '\u0001' && n <= '\u001a'):
+				if (consoleKeyInfo.Key == 0 && consoleKeyInfo.KeyChar == '\r') {
+					key = ConsoleKey.Enter;
+					newConsoleKeyInfo = new ConsoleKeyInfo (consoleKeyInfo.KeyChar,
+						key,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0);
+				} else if (consoleKeyInfo.Key == 0) {
+					key = (ConsoleKey)(char)(consoleKeyInfo.KeyChar + (uint)ConsoleKey.A - 1);
+					newConsoleKeyInfo = new ConsoleKeyInfo ((char)key,
+						key,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+						true);
+				}
+				break;
+			case 127:
+				newConsoleKeyInfo = new ConsoleKeyInfo (consoleKeyInfo.KeyChar, ConsoleKey.Backspace,
+					(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+					(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+					(consoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0);
+				break;
+			default:
+				newConsoleKeyInfo = consoleKeyInfo;
+				break;
+			}
+
+			return newConsoleKeyInfo;
+		}
+
+		/// <summary>
+		/// A helper to resize the <see cref="ConsoleKeyInfo"/> as needed.
+		/// </summary>
+		/// <param name="consoleKeyInfo">The <see cref="ConsoleKeyInfo"/>.</param>
+		/// <param name="cki">The <see cref="ConsoleKeyInfo"/> array to resize.</param>
+		/// <returns>The <see cref="ConsoleKeyInfo"/> resized.</returns>
+		public static ConsoleKeyInfo [] ResizeArray (ConsoleKeyInfo consoleKeyInfo, ConsoleKeyInfo [] cki)
+		{
+			Array.Resize (ref cki, cki == null ? 1 : cki.Length + 1);
+			cki [cki.Length - 1] = consoleKeyInfo;
+			return cki;
+		}
+
+		/// <summary>
+		/// Decodes a escape sequence to been processed in the appropriate manner.
+		/// </summary>
+		/// <param name="escSeqReqProc">The <see cref="EscSeqReqProc"/> which may contain a request.</param>
+		/// <param name="newConsoleKeyInfo">The <see cref="ConsoleKeyInfo"/> which may changes.</param>
+		/// <param name="key">The <see cref="ConsoleKey"/> which may changes.</param>
+		/// <param name="cki">The <see cref="ConsoleKeyInfo"/> array.</param>
+		/// <param name="mod">The <see cref="ConsoleModifiers"/> which may changes.</param>
+		/// <param name="c1Control">The control returned by the <see cref="GetC1ControlChar(char)"/> method.</param>
+		/// <param name="code">The code returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
+		/// <param name="values">The values returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
+		/// <param name="terminating">The terminating returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
+		/// <param name="isKeyMouse">Indicates if the escape sequence is a mouse key.</param>
+		/// <param name="buttonState">The <see cref="MouseFlags"/> button state.</param>
+		/// <param name="pos">The <see cref="MouseFlags"/> position.</param>
+		/// <param name="isReq">Indicates if the escape sequence is a response to a request.</param>
+		/// <param name="continuousButtonPressedHandler">The handler that will process the event.</param>
+		public static void DecodeEscSeq (EscSeqReqProc escSeqReqProc, ref ConsoleKeyInfo newConsoleKeyInfo, ref ConsoleKey key, ConsoleKeyInfo [] cki, ref ConsoleModifiers mod, out string c1Control, out string code, out string [] values, out string terminating, out bool isKeyMouse, out List<MouseFlags> buttonState, out Point pos, out bool isReq, Action<MouseFlags, Point> continuousButtonPressedHandler)
+		{
+			char [] kChars = GetKeyCharArray (cki);
+			(c1Control, code, values, terminating) = GetEscapeResult (kChars);
+			isKeyMouse = false;
+			buttonState = new List<MouseFlags> () { 0 };
+			pos = default;
+			isReq = false;
+			switch (c1Control) {
+			case "ESC":
+				if (values == null && string.IsNullOrEmpty (terminating)) {
+					key = ConsoleKey.Escape;
+					newConsoleKeyInfo = new ConsoleKeyInfo (cki [0].KeyChar, key,
+						(mod & ConsoleModifiers.Shift) != 0,
+						(mod & ConsoleModifiers.Alt) != 0,
+						(mod & ConsoleModifiers.Control) != 0);
+				} else if ((uint)cki [1].KeyChar >= 1 && (uint)cki [1].KeyChar <= 26) {
+					key = (ConsoleKey)(char)(cki [1].KeyChar + (uint)ConsoleKey.A - 1);
+					newConsoleKeyInfo = new ConsoleKeyInfo (cki [1].KeyChar,
+						key,
+						false,
+						true,
+						true);
+				} else {
+					if (cki [1].KeyChar >= 97 && cki [1].KeyChar <= 122) {
+						key = (ConsoleKey)cki [1].KeyChar.ToString ().ToUpper () [0];
+					} else {
+						key = (ConsoleKey)cki [1].KeyChar;
+					}
+					newConsoleKeyInfo = new ConsoleKeyInfo ((char)key,
+						(ConsoleKey)Math.Min ((uint)key, 255),
+						false,
+						true,
+						false);
+				}
+				break;
+			case "SS3":
+				key = GetConsoleKey (terminating [0], values [0], ref mod);
+				newConsoleKeyInfo = new ConsoleKeyInfo ('\0',
+					key,
+					(mod & ConsoleModifiers.Shift) != 0,
+					(mod & ConsoleModifiers.Alt) != 0,
+					(mod & ConsoleModifiers.Control) != 0);
+				break;
+			case "CSI":
+				if (!string.IsNullOrEmpty (code) && code == "<") {
+					GetMouse (cki, out buttonState, out pos, continuousButtonPressedHandler);
+					isKeyMouse = true;
+					return;
+				} else if (escSeqReqProc != null && escSeqReqProc.Requested (terminating)) {
+					isReq = true;
+					escSeqReqProc.Remove (terminating);
+					return;
+				}
+				key = GetConsoleKey (terminating [0], values [0], ref mod);
+				if (key != 0 && values.Length > 1) {
+					mod |= GetConsoleModifiers (values [1]);
+				}
+				newConsoleKeyInfo = new ConsoleKeyInfo ('\0',
+					key,
+					(mod & ConsoleModifiers.Shift) != 0,
+					(mod & ConsoleModifiers.Alt) != 0,
+					(mod & ConsoleModifiers.Control) != 0);
+				break;
+			}
+		}
+
+		/// <summary>
+		/// Gets all the needed information about a escape sequence.
+		/// </summary>
+		/// <param name="kChar">The array with all chars.</param>
+		/// <returns>
+		/// The c1Control returned by <see cref="GetC1ControlChar(char)"/>, code, values and terminating.
+		/// </returns>
+		public static (string c1Control, string code, string [] values, string terminating) GetEscapeResult (char [] kChar)
+		{
+			if (kChar == null || kChar.Length == 0) {
+				return (null, null, null, null);
+			}
+			if (kChar [0] != '\x1b') {
+				throw new InvalidOperationException ("Invalid escape character!");
+			}
+			if (kChar.Length == 1) {
+				return ("ESC", null, null, null);
+			}
+			if (kChar.Length == 2) {
+				return ("ESC", null, null, kChar [1].ToString ());
+			}
+			string c1Control = GetC1ControlChar (kChar [1]);
+			string code = null;
+			int nSep = kChar.Count (x => x == ';') + 1;
+			string [] values = new string [nSep];
+			int valueIdx = 0;
+			string terminating = "";
+			for (int i = 2; i < kChar.Length; i++) {
+				var c = kChar [i];
+				if (char.IsDigit (c)) {
+					values [valueIdx] += c.ToString ();
+				} else if (c == ';') {
+					valueIdx++;
+				} else if (valueIdx == nSep - 1 || i == kChar.Length - 1) {
+					terminating += c.ToString ();
+				} else {
+					code += c.ToString ();
+				}
+			}
+
+			return (c1Control, code, values, terminating);
+		}
+
+		/// <summary>
+		/// Gets the c1Control used in the called escape sequence.
+		/// </summary>
+		/// <param name="c">The char used.</param>
+		/// <returns>The c1Control.</returns>
+		public static string GetC1ControlChar (char c)
+		{
+			// These control characters are used in the vtXXX emulation.
+			switch (c) {
+			case 'D':
+				return "IND"; // Index
+			case 'E':
+				return "NEL"; // Next Line
+			case 'H':
+				return "HTS"; // Tab Set
+			case 'M':
+				return "RI"; // Reverse Index
+			case 'N':
+				return "SS2"; // Single Shift Select of G2 Character Set: affects next character only
+			case 'O':
+				return "SS3"; // Single Shift Select of G3 Character Set: affects next character only
+			case 'P':
+				return "DCS"; // Device Control String
+			case 'V':
+				return "SPA"; // Start of Guarded Area
+			case 'W':
+				return "EPA"; // End of Guarded Area
+			case 'X':
+				return "SOS"; // Start of String
+			case 'Z':
+				return "DECID"; // Return Terminal ID Obsolete form of CSI c (DA)
+			case '[':
+				return "CSI"; // Control Sequence Introducer
+			case '\\':
+				return "ST"; // String Terminator
+			case ']':
+				return "OSC"; // Operating System Command
+			case '^':
+				return "PM"; // Privacy Message
+			case '_':
+				return "APC"; // Application Program Command
+			default:
+				return ""; // Not supported
+			}
+		}
+
+		/// <summary>
+		/// Gets the <see cref="ConsoleModifiers"/> from the value.
+		/// </summary>
+		/// <param name="value">The value.</param>
+		/// <returns>The <see cref="ConsoleModifiers"/> or zero.</returns>
+		public static ConsoleModifiers GetConsoleModifiers (string value)
+		{
+			switch (value) {
+			case "2":
+				return ConsoleModifiers.Shift;
+			case "3":
+				return ConsoleModifiers.Alt;
+			case "4":
+				return ConsoleModifiers.Shift | ConsoleModifiers.Alt;
+			case "5":
+				return ConsoleModifiers.Control;
+			case "6":
+				return ConsoleModifiers.Shift | ConsoleModifiers.Control;
+			case "7":
+				return ConsoleModifiers.Alt | ConsoleModifiers.Control;
+			case "8":
+				return ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control;
+			default:
+				return 0;
+			}
+		}
+
+		/// <summary>
+		/// Gets the <see cref="ConsoleKey"/> depending on terminating and value.
+		/// </summary>
+		/// <param name="terminating">The terminating.</param>
+		/// <param name="value">The value.</param>
+		/// <param name="mod">The <see cref="ConsoleModifiers"/> which may changes.</param>
+		/// <returns>The <see cref="ConsoleKey"/> and probably the <see cref="ConsoleModifiers"/>.</returns>
+		public static ConsoleKey GetConsoleKey (char terminating, string value, ref ConsoleModifiers mod)
+		{
+			ConsoleKey key;
+			switch (terminating) {
+			case 'A':
+				key = ConsoleKey.UpArrow;
+				break;
+			case 'B':
+				key = ConsoleKey.DownArrow;
+				break;
+			case 'C':
+				key = ConsoleKey.RightArrow;
+				break;
+			case 'D':
+				key = ConsoleKey.LeftArrow;
+				break;
+			case 'F':
+				key = ConsoleKey.End;
+				break;
+			case 'H':
+				key = ConsoleKey.Home;
+				break;
+			case 'P':
+				key = ConsoleKey.F1;
+				break;
+			case 'Q':
+				key = ConsoleKey.F2;
+				break;
+			case 'R':
+				key = ConsoleKey.F3;
+				break;
+			case 'S':
+				key = ConsoleKey.F4;
+				break;
+			case 'Z':
+				key = ConsoleKey.Tab;
+				mod |= ConsoleModifiers.Shift;
+				break;
+			case '~':
+				switch (value) {
+				case "2":
+					key = ConsoleKey.Insert;
+					break;
+				case "3":
+					key = ConsoleKey.Delete;
+					break;
+				case "5":
+					key = ConsoleKey.PageUp;
+					break;
+				case "6":
+					key = ConsoleKey.PageDown;
+					break;
+				case "15":
+					key = ConsoleKey.F5;
+					break;
+				case "17":
+					key = ConsoleKey.F6;
+					break;
+				case "18":
+					key = ConsoleKey.F7;
+					break;
+				case "19":
+					key = ConsoleKey.F8;
+					break;
+				case "20":
+					key = ConsoleKey.F9;
+					break;
+				case "21":
+					key = ConsoleKey.F10;
+					break;
+				case "23":
+					key = ConsoleKey.F11;
+					break;
+				case "24":
+					key = ConsoleKey.F12;
+					break;
+				default:
+					key = 0;
+					break;
+				}
+				break;
+			default:
+				key = 0;
+				break;
+			}
+
+			return key;
+		}
+
+		/// <summary>
+		/// A helper to get only the <see cref="ConsoleKeyInfo.KeyChar"/> from the <see cref="ConsoleKeyInfo"/> array.
+		/// </summary>
+		/// <param name="cki"></param>
+		/// <returns>The char array of the escape sequence.</returns>
+		public static char [] GetKeyCharArray (ConsoleKeyInfo [] cki)
+		{
+			char [] kChar = new char [] { };
+			var length = 0;
+			foreach (var kc in cki) {
+				length++;
+				Array.Resize (ref kChar, length);
+				kChar [length - 1] = kc.KeyChar;
+			}
+
+			return kChar;
+		}
+
+		private static MouseFlags? lastMouseButtonPressed;
+		//private static MouseFlags? lastMouseButtonReleased;
+		private static bool isButtonPressed;
+		//private static bool isButtonReleased;
+		private static bool isButtonClicked;
+		private static bool isButtonDoubleClicked;
+		private static bool isButtonTripleClicked;
+		private static Point point;
+
+		/// <summary>
+		/// Gets the <see cref="MouseFlags"/> mouse button flags and the position.
+		/// </summary>
+		/// <param name="cki">The <see cref="ConsoleKeyInfo"/> array.</param>
+		/// <param name="mouseFlags">The mouse button flags.</param>
+		/// <param name="pos">The mouse position.</param>
+		/// <param name="continuousButtonPressedHandler">The handler that will process the event.</param>
+		public static void GetMouse (ConsoleKeyInfo [] cki, out List<MouseFlags> mouseFlags, out Point pos, Action<MouseFlags, Point> continuousButtonPressedHandler)
+		{
+			MouseFlags buttonState = 0;
+			pos = new Point ();
+			int buttonCode = 0;
+			bool foundButtonCode = false;
+			int foundPoint = 0;
+			string value = "";
+			var kChar = GetKeyCharArray (cki);
+			//System.Diagnostics.Debug.WriteLine ($"kChar: {new string (kChar)}");
+			for (int i = 0; i < kChar.Length; i++) {
+				var c = kChar [i];
+				if (c == '<') {
+					foundButtonCode = true;
+				} else if (foundButtonCode && c != ';') {
+					value += c.ToString ();
+				} else if (c == ';') {
+					if (foundButtonCode) {
+						foundButtonCode = false;
+						buttonCode = int.Parse (value);
+					}
+					if (foundPoint == 1) {
+						pos.X = int.Parse (value) - 1;
+					}
+					value = "";
+					foundPoint++;
+				} else if (foundPoint > 0 && c != 'm' && c != 'M') {
+					value += c.ToString ();
+				} else if (c == 'm' || c == 'M') {
+					//pos.Y = int.Parse (value) + Console.WindowTop - 1;
+					pos.Y = int.Parse (value) - 1;
+
+					switch (buttonCode) {
+					case 0:
+					case 8:
+					case 16:
+					case 24:
+					case 32:
+					case 36:
+					case 40:
+					case 48:
+					case 56:
+						buttonState = c == 'M' ? MouseFlags.Button1Pressed
+							: MouseFlags.Button1Released;
+						break;
+					case 1:
+					case 9:
+					case 17:
+					case 25:
+					case 33:
+					case 37:
+					case 41:
+					case 45:
+					case 49:
+					case 53:
+					case 57:
+					case 61:
+						buttonState = c == 'M' ? MouseFlags.Button2Pressed
+							: MouseFlags.Button2Released;
+						break;
+					case 2:
+					case 10:
+					case 14:
+					case 18:
+					case 22:
+					case 26:
+					case 30:
+					case 34:
+					case 42:
+					case 46:
+					case 50:
+					case 54:
+					case 58:
+					case 62:
+						buttonState = c == 'M' ? MouseFlags.Button3Pressed
+							: MouseFlags.Button3Released;
+						break;
+					case 35:
+					//// Needed for Windows OS
+					//if (isButtonPressed && c == 'm'
+					//	&& (lastMouseEvent.ButtonState == MouseFlags.Button1Pressed
+					//	|| lastMouseEvent.ButtonState == MouseFlags.Button2Pressed
+					//	|| lastMouseEvent.ButtonState == MouseFlags.Button3Pressed)) {
+
+					//	switch (lastMouseEvent.ButtonState) {
+					//	case MouseFlags.Button1Pressed:
+					//		buttonState = MouseFlags.Button1Released;
+					//		break;
+					//	case MouseFlags.Button2Pressed:
+					//		buttonState = MouseFlags.Button2Released;
+					//		break;
+					//	case MouseFlags.Button3Pressed:
+					//		buttonState = MouseFlags.Button3Released;
+					//		break;
+					//	}
+					//} else {
+					//	buttonState = MouseFlags.ReportMousePosition;
+					//}
+					//break;
+					case 39:
+					case 43:
+					case 47:
+					case 51:
+					case 55:
+					case 59:
+					case 63:
+						buttonState = MouseFlags.ReportMousePosition;
+						break;
+					case 64:
+						buttonState = MouseFlags.WheeledUp;
+						break;
+					case 65:
+						buttonState = MouseFlags.WheeledDown;
+						break;
+					case 68:
+					case 72:
+					case 80:
+						buttonState = MouseFlags.WheeledLeft;       // Shift/Ctrl+WheeledUp
+						break;
+					case 69:
+					case 73:
+					case 81:
+						buttonState = MouseFlags.WheeledRight;      // Shift/Ctrl+WheeledDown
+						break;
+					}
+					// Modifiers.
+					switch (buttonCode) {
+					case 8:
+					case 9:
+					case 10:
+					case 43:
+						buttonState |= MouseFlags.ButtonAlt;
+						break;
+					case 14:
+					case 47:
+						buttonState |= MouseFlags.ButtonAlt | MouseFlags.ButtonShift;
+						break;
+					case 16:
+					case 17:
+					case 18:
+					case 51:
+						buttonState |= MouseFlags.ButtonCtrl;
+						break;
+					case 22:
+					case 55:
+						buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonShift;
+						break;
+					case 24:
+					case 25:
+					case 26:
+					case 59:
+						buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonAlt;
+						break;
+					case 30:
+					case 63:
+						buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonShift | MouseFlags.ButtonAlt;
+						break;
+					case 32:
+					case 33:
+					case 34:
+						buttonState |= MouseFlags.ReportMousePosition;
+						break;
+					case 36:
+					case 37:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonShift;
+						break;
+					case 39:
+					case 68:
+					case 69:
+						buttonState |= MouseFlags.ButtonShift;
+						break;
+					case 40:
+					case 41:
+					case 42:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonAlt;
+						break;
+					case 45:
+					case 46:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonAlt | MouseFlags.ButtonShift;
+						break;
+					case 48:
+					case 49:
+					case 50:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl;
+						break;
+					case 53:
+					case 54:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonShift;
+						break;
+					case 56:
+					case 57:
+					case 58:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonAlt;
+						break;
+					case 61:
+					case 62:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonShift | MouseFlags.ButtonAlt;
+						break;
+					}
+				}
+			}
+
+			mouseFlags = new List<MouseFlags> () { MouseFlags.AllEvents };
+
+			if (lastMouseButtonPressed != null && !isButtonPressed && !buttonState.HasFlag (MouseFlags.ReportMousePosition)
+				&& !buttonState.HasFlag (MouseFlags.Button1Released)
+				&& !buttonState.HasFlag (MouseFlags.Button2Released)
+				&& !buttonState.HasFlag (MouseFlags.Button3Released)
+				&& !buttonState.HasFlag (MouseFlags.Button4Released)) {
+
+				lastMouseButtonPressed = null;
+				isButtonPressed = false;
+			}
+
+			if (!isButtonClicked && !isButtonDoubleClicked && ((buttonState == MouseFlags.Button1Pressed || buttonState == MouseFlags.Button2Pressed ||
+				  buttonState == MouseFlags.Button3Pressed || buttonState == MouseFlags.Button4Pressed) && lastMouseButtonPressed == null) ||
+				  isButtonPressed && lastMouseButtonPressed != null && buttonState.HasFlag (MouseFlags.ReportMousePosition)) {
+
+				mouseFlags [0] = buttonState;
+				lastMouseButtonPressed = buttonState;
+				isButtonPressed = true;
+
+				if ((mouseFlags [0] & MouseFlags.ReportMousePosition) == 0) {
+					point = new Point () {
+						X = pos.X,
+						Y = pos.Y
+					};
+
+					Application.MainLoop.AddIdle (() => {
+						Task.Run (async () => await ProcessContinuousButtonPressedAsync (buttonState, continuousButtonPressedHandler));
+						return false;
+					});
+				} else if (mouseFlags [0] == MouseFlags.ReportMousePosition) {
+					isButtonPressed = false;
+				}
+
+			} else if (isButtonDoubleClicked && (buttonState == MouseFlags.Button1Pressed || buttonState == MouseFlags.Button2Pressed ||
+				buttonState == MouseFlags.Button3Pressed || buttonState == MouseFlags.Button4Pressed)) {
+
+				mouseFlags [0] = GetButtonTripleClicked (buttonState);
+				isButtonDoubleClicked = false;
+				isButtonTripleClicked = true;
+
+			} else if (isButtonClicked && (buttonState == MouseFlags.Button1Pressed || buttonState == MouseFlags.Button2Pressed ||
+				buttonState == MouseFlags.Button3Pressed || buttonState == MouseFlags.Button4Pressed)) {
+
+				mouseFlags [0] = GetButtonDoubleClicked (buttonState);
+				isButtonClicked = false;
+				isButtonDoubleClicked = true;
+				Application.MainLoop.AddIdle (() => {
+					Task.Run (async () => await ProcessButtonDoubleClickedAsync ());
+					return false;
+				});
+
+			}
+			//else if (isButtonReleased && !isButtonClicked && buttonState == MouseFlags.ReportMousePosition) {
+			//	mouseFlag [0] = GetButtonClicked ((MouseFlags)lastMouseButtonReleased);
+			//	lastMouseButtonReleased = null;
+			//	isButtonReleased = false;
+			//	isButtonClicked = true;
+			//	Application.MainLoop.AddIdle (() => {
+			//		Task.Run (async () => await ProcessButtonClickedAsync ());
+			//		return false;
+			//	});
+
+			//} 
+			else if (!isButtonClicked && !isButtonDoubleClicked && (buttonState == MouseFlags.Button1Released || buttonState == MouseFlags.Button2Released ||
+				  buttonState == MouseFlags.Button3Released || buttonState == MouseFlags.Button4Released)) {
+
+				mouseFlags [0] = buttonState;
+				isButtonPressed = false;
+
+				if (isButtonTripleClicked) {
+					isButtonTripleClicked = false;
+				} else if (pos.X == point.X && pos.Y == point.Y) {
+					mouseFlags.Add (GetButtonClicked (buttonState));
+					isButtonClicked = true;
+					Application.MainLoop.AddIdle (() => {
+						Task.Run (async () => await ProcessButtonClickedAsync ());
+						return false;
+					});
+				}
+
+				point = pos;
+
+				//if ((lastMouseButtonPressed & MouseFlags.ReportMousePosition) == 0) {
+				//	lastMouseButtonReleased = buttonState;
+				//	isButtonPressed = false;
+				//	isButtonReleased = true;
+				//} else {
+				//	lastMouseButtonPressed = null;
+				//	isButtonPressed = false;
+				//}
+
+			} else if (buttonState == MouseFlags.WheeledUp) {
+
+				mouseFlags [0] = MouseFlags.WheeledUp;
+
+			} else if (buttonState == MouseFlags.WheeledDown) {
+
+				mouseFlags [0] = MouseFlags.WheeledDown;
+
+			} else if (buttonState == MouseFlags.WheeledLeft) {
+
+				mouseFlags [0] = MouseFlags.WheeledLeft;
+
+			} else if (buttonState == MouseFlags.WheeledRight) {
+
+				mouseFlags [0] = MouseFlags.WheeledRight;
+
+			} else if (buttonState == MouseFlags.ReportMousePosition) {
+				mouseFlags [0] = MouseFlags.ReportMousePosition;
+
+			} else {
+				mouseFlags [0] = buttonState;
+				//foreach (var flag in buttonState.GetUniqueFlags()) {
+				//	mouseFlag [0] |= flag;
+				//}
+			}
+
+			mouseFlags [0] = SetControlKeyStates (buttonState, mouseFlags [0]);
+			//buttonState = mouseFlags;
+
+			//System.Diagnostics.Debug.WriteLine ($"buttonState: {buttonState} X: {pos.X} Y: {pos.Y}");
+			//foreach (var mf in mouseFlags) {
+			//	System.Diagnostics.Debug.WriteLine ($"mouseFlags: {mf} X: {pos.X} Y: {pos.Y}");
+			//}
+		}
+
+		private static async Task ProcessContinuousButtonPressedAsync (MouseFlags mouseFlag, Action<MouseFlags, Point> continuousButtonPressedHandler)
+		{
+			while (isButtonPressed) {
+				await Task.Delay (100);
+				//var me = new MouseEvent () {
+				//	X = point.X,
+				//	Y = point.Y,
+				//	Flags = mouseFlag
+				//};
+
+				var view = Application.WantContinuousButtonPressedView;
+				if (view == null)
+					break;
+				if (isButtonPressed && lastMouseButtonPressed != null && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
+					Application.MainLoop.Invoke (() => continuousButtonPressedHandler (mouseFlag, point));
+				}
+			}
+		}
+
+		private static async Task ProcessButtonClickedAsync ()
+		{
+			await Task.Delay (300);
+			isButtonClicked = false;
+		}
+
+		private static async Task ProcessButtonDoubleClickedAsync ()
+		{
+			await Task.Delay (300);
+			isButtonDoubleClicked = false;
+		}
+
+		private static MouseFlags GetButtonClicked (MouseFlags mouseFlag)
+		{
+			MouseFlags mf = default;
+			switch (mouseFlag) {
+			case MouseFlags.Button1Released:
+				mf = MouseFlags.Button1Clicked;
+				break;
+
+			case MouseFlags.Button2Released:
+				mf = MouseFlags.Button2Clicked;
+				break;
+
+			case MouseFlags.Button3Released:
+				mf = MouseFlags.Button3Clicked;
+				break;
+			}
+			return mf;
+		}
+
+		private static MouseFlags GetButtonDoubleClicked (MouseFlags mouseFlag)
+		{
+			MouseFlags mf = default;
+			switch (mouseFlag) {
+			case MouseFlags.Button1Pressed:
+				mf = MouseFlags.Button1DoubleClicked;
+				break;
+
+			case MouseFlags.Button2Pressed:
+				mf = MouseFlags.Button2DoubleClicked;
+				break;
+
+			case MouseFlags.Button3Pressed:
+				mf = MouseFlags.Button3DoubleClicked;
+				break;
+			}
+			return mf;
+		}
+
+		private static MouseFlags GetButtonTripleClicked (MouseFlags mouseFlag)
+		{
+			MouseFlags mf = default;
+			switch (mouseFlag) {
+			case MouseFlags.Button1Pressed:
+				mf = MouseFlags.Button1TripleClicked;
+				break;
+
+			case MouseFlags.Button2Pressed:
+				mf = MouseFlags.Button2TripleClicked;
+				break;
+
+			case MouseFlags.Button3Pressed:
+				mf = MouseFlags.Button3TripleClicked;
+				break;
+			}
+			return mf;
+		}
+
+		private static MouseFlags SetControlKeyStates (MouseFlags buttonState, MouseFlags mouseFlag)
+		{
+			if ((buttonState & MouseFlags.ButtonCtrl) != 0 && (mouseFlag & MouseFlags.ButtonCtrl) == 0)
+				mouseFlag |= MouseFlags.ButtonCtrl;
+
+			if ((buttonState & MouseFlags.ButtonShift) != 0 && (mouseFlag & MouseFlags.ButtonShift) == 0)
+				mouseFlag |= MouseFlags.ButtonShift;
+
+			if ((buttonState & MouseFlags.ButtonAlt) != 0 && (mouseFlag & MouseFlags.ButtonAlt) == 0)
+				mouseFlag |= MouseFlags.ButtonAlt;
+			return mouseFlag;
+		}
+
+		/// <summary>
+		/// Get the terminal that holds the console driver.
+		/// </summary>
+		/// <param name="process">The process.</param>
+		/// <returns>If supported the executable console process, null otherwise.</returns>
+		public static Process GetParentProcess (Process process)
+		{
+			if (!RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+				return null;
+			}
+
+			string query = "SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = " + process.Id;
+			using (ManagementObjectSearcher mos = new ManagementObjectSearcher (query)) {
+				foreach (ManagementObject mo in mos.Get ()) {
+					if (mo ["ParentProcessId"] != null) {
+						try {
+							var id = Convert.ToInt32 (mo ["ParentProcessId"]);
+							return Process.GetProcessById (id);
+						} catch {
+						}
+					}
+				}
+			}
+			return null;
+		}
+	}
+}

+ 1 - 1
Terminal.Gui/Core/Event.cs

@@ -749,7 +749,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		WheeledUp = unchecked((int)0x10000000),
 		/// <summary>
-		/// Vertical button wheeled up.
+		/// Vertical button wheeled down.
 		/// </summary>
 		WheeledDown = unchecked((int)0x20000000),
 		/// <summary>

+ 29 - 0
Terminal.Gui/Core/GrabMouseEventArgs.cs

@@ -0,0 +1,29 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Args for events that relate to specific <see cref="Application.MouseGrabView"/>
+	/// </summary>
+	public class GrabMouseEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="GrabMouseEventArgs"/> class.
+		/// </summary>
+		/// <param name="view">The view that the event is about.</param>
+		public GrabMouseEventArgs (View view)
+		{
+			View = view;
+		}
+
+		/// <summary>
+		/// The view that the event is about.
+		/// </summary>
+		public View View { get; }
+
+		/// <summary>
+		/// Flag that allows the cancellation of the event. If set to <see langword="true"/> in the
+		/// event handler, the event will be canceled.
+		/// </summary>
+		public bool Cancel { get; set; }
+	}
+}

+ 13 - 24
Terminal.Gui/Core/Graphs/LineCanvas.cs

@@ -199,8 +199,8 @@ namespace Terminal.Gui.Graphs {
 			}
 
 			// TODO: Remove these two once we have all of the below ported to IntersectionRuneResolvers
-			var useDouble = intersects.Any (i => i.Line.Style == BorderStyle.Double && i.Line.Length != 0);
-			var useRounded = intersects.Any (i => i.Line.Style == BorderStyle.Rounded && i.Line.Length != 0);
+			var useDouble = intersects.Any (i => i.Line.Style == BorderStyle.Double);
+			var useRounded = intersects.Any (i => i.Line.Style == BorderStyle.Rounded);
 
 			// TODO: maybe make these resolvers to for simplicity?
 			// or for dotted lines later on or that kind of thing?
@@ -220,13 +220,6 @@ namespace Terminal.Gui.Graphs {
 
 		private IntersectionRuneType GetRuneTypeForIntersects (IntersectionDefinition [] intersects)
 		{
-			if (intersects.All (i => i.Line.Length == 0)) {
-				return IntersectionRuneType.Dot;
-			}
-
-			// ignore dots
-			intersects = intersects.Where (i => i.Type != IntersectionType.Dot).ToArray ();
-
 			var set = new HashSet<IntersectionType> (intersects.Select (i => i.Type));
 
 			#region Crosshair Conditions
@@ -487,14 +480,6 @@ namespace Terminal.Gui.Graphs {
 
 			internal IntersectionDefinition Intersects (int x, int y)
 			{
-				if (IsDot ()) {
-					if (StartsAt (x, y)) {
-						return new IntersectionDefinition (Start, IntersectionType.Dot, this);
-					} else {
-						return null;
-					}
-				}
-
 				switch (Orientation) {
 				case Orientation.Horizontal: return IntersectsHorizontally (x, y);
 				case Orientation.Vertical: return IntersectsVertically (x, y);
@@ -512,7 +497,7 @@ namespace Terminal.Gui.Graphs {
 
 						return new IntersectionDefinition (
 							Start,
-							Length < 0 ? IntersectionType.StartLeft : IntersectionType.StartRight,
+							GetTypeByLength(IntersectionType.StartLeft, IntersectionType.PassOverHorizontal,IntersectionType.StartRight),
 							this
 							);
 
@@ -552,7 +537,7 @@ namespace Terminal.Gui.Graphs {
 
 						return new IntersectionDefinition (
 							Start,
-							Length < 0 ? IntersectionType.StartUp : IntersectionType.StartDown,
+							GetTypeByLength(IntersectionType.StartUp, IntersectionType.PassOverVertical, IntersectionType.StartDown),
 							this
 							);
 
@@ -583,6 +568,15 @@ namespace Terminal.Gui.Graphs {
 				}
 			}
 
+			private IntersectionType GetTypeByLength (IntersectionType typeWhenNegative, IntersectionType typeWhenZero, IntersectionType typeWhenPositive)
+			{
+				if (Length == 0) {
+					return typeWhenZero;
+				} 
+
+				return Length < 0 ? typeWhenNegative : typeWhenPositive;
+			}
+
 			private bool EndsAt (int x, int y)
 			{
 				if (Orientation == Orientation.Horizontal) {
@@ -596,11 +590,6 @@ namespace Terminal.Gui.Graphs {
 			{
 				return Start.X == x && Start.Y == y;
 			}
-
-			private bool IsDot ()
-			{
-				return Length == 0;
-			}
 		}
 	}
 }

+ 34 - 0
Terminal.Gui/Core/KeyChangedEventArgs.cs

@@ -0,0 +1,34 @@
+using System;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Event args for when a <see cref="Key"/> is changed from
+	/// one value to a new value (e.g. in <see cref="View.HotKeyChanged"/>)
+	/// </summary>
+	public class KeyChangedEventArgs : EventArgs {
+
+		/// <summary>
+		/// Gets the old <see cref="Key"/> that was set before the event.
+		/// Use <see cref="Key.Null"/> to check for empty.
+		/// </summary>
+		public Key OldKey { get; }
+
+		/// <summary>
+		/// Gets the new <see cref="Key"/> that is being used.
+		/// Use <see cref="Key.Null"/> to check for empty.
+		/// </summary>
+		public Key NewKey { get; }
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="KeyChangedEventArgs"/> class
+		/// </summary>
+		/// <param name="oldKey"></param>
+		/// <param name="newKey"></param>
+		public KeyChangedEventArgs (Key oldKey, Key newKey)
+		{
+			this.OldKey = oldKey;
+			this.NewKey = newKey;
+		}
+	}
+}

+ 24 - 0
Terminal.Gui/Core/KeyEventEventArgs.cs

@@ -0,0 +1,24 @@
+using System;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Defines the event arguments for <see cref="KeyEvent"/>
+	/// </summary>
+	public class KeyEventEventArgs : EventArgs {
+		/// <summary>
+		/// Constructs.
+		/// </summary>
+		/// <param name="ke"></param>
+		public KeyEventEventArgs (KeyEvent ke) => KeyEvent = ke;
+		/// <summary>
+		/// The <see cref="KeyEvent"/> for the event.
+		/// </summary>
+		public KeyEvent KeyEvent { get; set; }
+		/// <summary>
+		/// Indicates if the current Key event has already been processed and the driver should stop notifying any other event subscriber.
+		/// Its important to set this value to true specially when updating any View's layout from inside the subscriber method.
+		/// </summary>
+		public bool Handled { get; set; } = false;
+	}
+}

+ 22 - 0
Terminal.Gui/Core/KeystrokeNavigatorEventArgs.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Event arguments for the <see cref="CollectionNavigator.SearchStringChanged"/> event.
+	/// </summary>
+	public class KeystrokeNavigatorEventArgs : EventArgs {
+		/// <summary>
+		/// he current <see cref="SearchString"/>.
+		/// </summary>
+		public string SearchString { get; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="KeystrokeNavigatorEventArgs"/>
+		/// </summary>
+		/// <param name="searchString">The current <see cref="SearchString"/>.</param>
+		public KeystrokeNavigatorEventArgs (string searchString)
+		{
+			SearchString = searchString;
+		}
+	}
+}

+ 2 - 2
Terminal.Gui/Core/MainLoop.cs

@@ -97,7 +97,7 @@ namespace Terminal.Gui {
 		/// Invoked when a new timeout is added. To be used in the case
 		/// when <see cref="Application.ExitRunLoopAfterFirstIteration"/> is <see langword="true"/>.
 		/// </summary>
-		public event Action<long> TimeoutAdded;
+		public event EventHandler<TimeoutEventArgs> TimeoutAdded;
 
 		/// <summary>
 		///  Creates a new Mainloop. 
@@ -161,7 +161,7 @@ namespace Terminal.Gui {
 			lock (timeoutsLockToken) {
 				var k = (DateTime.UtcNow + time).Ticks;
 				timeouts.Add (NudgeToUniqueKey (k), timeout);
-				TimeoutAdded?.Invoke (k);
+				TimeoutAdded?.Invoke (this, new TimeoutEventArgs(timeout, k));
 			}
 		}
 

+ 31 - 0
Terminal.Gui/Core/MouseEventEventArgs.cs

@@ -0,0 +1,31 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Specifies the event arguments for <see cref="Terminal.Gui.MouseEvent"/>. This is a higher-level construct
+	/// than the wrapped <see cref="MouseEvent"/> class and is used for the events defined on <see cref="View"/>
+	/// and subclasses of View (e.g. <see cref="View.MouseEnter"/> and <see cref="View.MouseClick"/>).
+	/// </summary>
+	public class MouseEventEventArgs : EventArgs {
+		/// <summary>
+		/// Constructs.
+		/// </summary>
+		/// <param name="me">The mouse event.</param>
+		public MouseEventEventArgs (MouseEvent me) => MouseEvent = me;
+		/// <summary>
+		/// The <see cref="Terminal.Gui.MouseEvent"/> for the event.
+		/// </summary>
+		public MouseEvent MouseEvent { get; set; }
+
+		/// <summary>
+		/// Indicates if the current mouse event has already been processed and the driver should stop notifying any other event subscriber.
+		/// Its important to set this value to true specially when updating any View's layout from inside the subscriber method.
+		/// </summary>
+		/// <remarks>This property forwards to the <see cref="MouseEvent.Handled"/> property and is provided as a convenience and for
+		/// backwards compatibility</remarks>
+		public bool Handled {
+			get => MouseEvent.Handled;
+			set => MouseEvent.Handled = value;
+		}
+	}
+}

+ 30 - 0
Terminal.Gui/Core/MouseFlagsChangedEventArgs.cs

@@ -0,0 +1,30 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Args for events that describe a change in <see cref="MouseFlags"/>
+	/// </summary>
+	public class MouseFlagsChangedEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="MouseFlagsChangedEventArgs"/> class.
+		/// </summary>
+		/// <param name="oldValue"></param>
+		/// <param name="newValue"></param>
+		public MouseFlagsChangedEventArgs (MouseFlags oldValue, MouseFlags newValue)
+		{
+			OldValue = oldValue;
+			NewValue = newValue;
+		}
+
+		/// <summary>
+		/// The old value before event
+		/// </summary>
+		public MouseFlags OldValue { get; }
+
+		/// <summary>
+		/// The new value
+		/// </summary>
+		public MouseFlags NewValue { get; }
+	}
+}

+ 23 - 0
Terminal.Gui/Core/PointEventArgs.cs

@@ -0,0 +1,23 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Event args for events which relate to a single <see cref="Point"/>
+	/// </summary>
+	public class PointEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="PointEventArgs"/> class
+		/// </summary>
+		/// <param name="p"></param>
+		public PointEventArgs (Point p)
+		{
+			this.Point = p;
+		}
+
+		/// <summary>
+		/// The point the event happened at
+		/// </summary>
+		public Point Point { get; }
+	}
+}

+ 2 - 2
Terminal.Gui/Core/PosDim.cs

@@ -345,7 +345,7 @@ namespace Terminal.Gui {
 				case 3: tside = "bottom"; break;
 				default: tside = "unknown"; break;
 				}
-				return $"View({tside},{Target.ToString()})";
+				return $"View({tside},{Target.ToString ()})";
 			}
 
 			public override int GetHashCode () => Target.GetHashCode ();
@@ -691,7 +691,7 @@ namespace Terminal.Gui {
 				case 1: tside = "Width"; break;
 				default: tside = "unknown"; break;
 				}
-				return $"DimView({tside},{Target.ToString ()})";
+				return $"View({tside},{Target.ToString ()})";
 			}
 
 			public override int GetHashCode () => Target.GetHashCode ();

+ 32 - 0
Terminal.Gui/Core/ResizedEventArgs.cs

@@ -0,0 +1,32 @@
+//
+// Core.cs: The core engine for gui.cs
+//
+// Authors:
+//   Miguel de Icaza ([email protected])
+//
+// Pending:
+//   - Check for NeedDisplay on the hierarchy and repaint
+//   - Layout support
+//   - "Colors" type or "Attributes" type?
+//   - What to surface as "BackgroundCOlor" when clearing a window, an attribute or colors?
+//
+// Optimizations
+//   - Add rendering limitation to the exposed area
+using System;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Event arguments for the <see cref="Application.Resized"/> event.
+	/// </summary>
+	public class ResizedEventArgs : EventArgs {
+		/// <summary>
+		/// The number of rows in the resized terminal.
+		/// </summary>
+		public int Rows { get; set; }
+		/// <summary>
+		/// The number of columns in the resized terminal.
+		/// </summary>
+		public int Cols { get; set; }
+	}
+}

+ 24 - 0
Terminal.Gui/Core/RunStateEventArgs.cs

@@ -0,0 +1,24 @@
+using System;
+using static Terminal.Gui.Application;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Event arguments for events about <see cref="RunState"/>
+	/// </summary>
+	public class RunStateEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="RunStateEventArgs"/> class
+		/// </summary>
+		/// <param name="state"></param>
+		public RunStateEventArgs (RunState state)
+		{
+			State = state;
+		}
+
+		/// <summary>
+		/// The state being reported on by the event
+		/// </summary>
+		public RunState State { get; }
+	}
+}

+ 26 - 0
Terminal.Gui/Core/SizeChangedEventArgs.cs

@@ -0,0 +1,26 @@
+using System;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Args for events about Size (e.g. Resized)
+	/// </summary>
+	public class SizeChangedEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="SizeChangedEventArgs"/> class.
+		/// </summary>
+		/// <param name="size"></param>
+		public SizeChangedEventArgs (Size size)
+		{
+			Size = size;
+		}
+
+		/// <summary>
+		/// Gets the size the event describes.  This should
+		/// reflect the new/current size after the event
+		/// resolved.
+		/// </summary>
+		public Size Size { get; }
+	}
+}

+ 33 - 0
Terminal.Gui/Core/SuperViewChangedEventArgs.cs

@@ -0,0 +1,33 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Args for events where the <see cref="View.SuperView"/> of a <see cref="View"/> is changed
+	/// (e.g. <see cref="View.Removed"/> / <see cref="View.Added"/> events).
+	/// </summary>
+	public class SuperViewChangedEventArgs : EventArgs
+	{
+		/// <summary>
+		/// Creates a new instance of the <see cref="SuperViewChangedEventArgs"/> class.
+		/// </summary>
+		/// <param name="parent"></param>
+		/// <param name="child"></param>
+		public SuperViewChangedEventArgs (View parent, View child)
+		{
+			Parent = parent;
+			Child = child;
+		}
+
+		/// <summary>
+		/// The parent.  For <see cref="View.Removed"/> this is the old
+		/// parent (new parent now being null).  For <see cref="View.Added"/>
+		/// it is the new parent to whom view now belongs.
+		/// </summary>
+		public View Parent { get; }
+
+		/// <summary>
+		/// The view that is having it's <see cref="View.SuperView"/> changed
+		/// </summary>
+		public View Child { get; }
+	}
+}

+ 22 - 11
Terminal.Gui/Core/TextFormatter.cs

@@ -126,7 +126,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Event invoked when the <see cref="HotKey"/> is changed.
 		/// </summary>
-		public event Action<Key> HotKeyChanged;
+		public event EventHandler<KeyChangedEventArgs> HotKeyChanged;
 
 		/// <summary>
 		///   The text to be displayed. This text is never modified.
@@ -288,7 +288,7 @@ namespace Terminal.Gui {
 				if (hotKey != value) {
 					var oldKey = hotKey;
 					hotKey = value;
-					HotKeyChanged?.Invoke (oldKey);
+					HotKeyChanged?.Invoke (this, new KeyChangedEventArgs(oldKey,value));
 				}
 			}
 		}
@@ -1176,22 +1176,29 @@ namespace Terminal.Gui {
 			}
 
 			var isVertical = IsVerticalDirection (textDirection);
-			var savedClip = Application.Driver?.Clip;
 			var maxBounds = bounds;
 			if (Application.Driver != null) {
-				Application.Driver.Clip = maxBounds = containerBounds == default
+				maxBounds = containerBounds == default
 					? bounds
 					: new Rect (Math.Max (containerBounds.X, bounds.X),
 					Math.Max (containerBounds.Y, bounds.Y),
 					Math.Max (Math.Min (containerBounds.Width, containerBounds.Right - bounds.Left), 0),
 					Math.Max (Math.Min (containerBounds.Height, containerBounds.Bottom - bounds.Top), 0));
 			}
+			if (maxBounds.Width == 0 || maxBounds.Height == 0) {
+				return;
+			}
+			var savedClip = Application.Driver?.Clip;
+			if (Application.Driver != null) {
+				Application.Driver.Clip = maxBounds;
+			}
+			var lineOffset = !isVertical && bounds.Y < 0 ? Math.Abs (bounds.Y) : 0;
 
-			for (int line = 0; line < linesFormated.Count; line++) {
+			for (int line = lineOffset; line < linesFormated.Count; line++) {
 				if ((isVertical && line > bounds.Width) || (!isVertical && line > bounds.Height))
 					continue;
 				if ((isVertical && line >= maxBounds.Left + maxBounds.Width)
-					|| (!isVertical && line >= maxBounds.Top + maxBounds.Height))
+					|| (!isVertical && line >= maxBounds.Top + maxBounds.Height + lineOffset))
 
 					break;
 
@@ -1267,18 +1274,21 @@ namespace Terminal.Gui {
 					throw new ArgumentOutOfRangeException ();
 				}
 
+				var colOffset = bounds.X < 0 ? Math.Abs (bounds.X) : 0;
 				var start = isVertical ? bounds.Top : bounds.Left;
 				var size = isVertical ? bounds.Height : bounds.Width;
-				var current = start;
+				var current = start + colOffset;
 
-				for (var idx = (isVertical ? start - y : start - x); current < start + size; idx++) {
-					if (!fillRemaining && idx < 0) {
+				for (var idx = (isVertical ? start - y : start - x) + colOffset; current < start + size; idx++) {
+					if (idx < 0 || x + current + colOffset < 0) {
 						current++;
 						continue;
 					} else if (!fillRemaining && idx > runes.Length - 1) {
 						break;
 					}
-					if ((!isVertical && idx > maxBounds.Left + maxBounds.Width - bounds.X) || (isVertical && idx > maxBounds.Top + maxBounds.Height - bounds.Y))
+					if ((!isVertical && idx > maxBounds.Left + maxBounds.Width - bounds.X + colOffset)
+						|| (isVertical && idx > maxBounds.Top + maxBounds.Height - bounds.Y))
+
 						break;
 
 					var rune = (Rune)' ';
@@ -1316,8 +1326,9 @@ namespace Terminal.Gui {
 					}
 				}
 			}
-			if (Application.Driver != null)
+			if (Application.Driver != null) {
 				Application.Driver.Clip = (Rect)savedClip;
+			}
 		}
 	}
 }

+ 32 - 0
Terminal.Gui/Core/TimeoutEventArgs.cs

@@ -0,0 +1,32 @@
+using System;
+using static Terminal.Gui.MainLoop;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// <see cref="EventArgs"/> for timeout events (e.g. <see cref="MainLoop.TimeoutAdded"/>)
+	/// </summary>
+	public class TimeoutEventArgs : EventArgs {
+		/// <summary>
+		/// Gets the timeout callback handler
+		/// </summary>
+		public Timeout Timeout { get; }
+
+		/// <summary>
+		/// Gets the <see cref="DateTime.Ticks"/> in UTC time when the 
+		/// <see cref="Timeout"/> will next execute after.
+		/// </summary>
+		public long Ticks { get; }
+
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="TimeoutEventArgs"/> class.
+		/// </summary>
+		/// <param name="timeout"></param>
+		/// <param name="ticks"></param>
+		public TimeoutEventArgs (Timeout timeout, long ticks)
+		{
+			Timeout = timeout;
+			Ticks = ticks;
+		}
+	}
+}

+ 46 - 0
Terminal.Gui/Core/TitleEventArgs.cs

@@ -0,0 +1,46 @@
+//
+// Authors:
+//   Miguel de Icaza ([email protected])
+//
+// NOTE: Window is functionally identical to FrameView with the following exceptions. 
+//  - Window is a Toplevel
+//  - FrameView Does not support padding (but should)
+//  - FrameView Does not support mouse dragging
+//  - FrameView Does not support IEnumerable
+// Any updates done here should probably be done in FrameView as well; TODO: Merge these classes
+
+using System;
+using NStack;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Event arguments for Title change events.
+	/// </summary>
+	public class TitleEventArgs : EventArgs {
+		/// <summary>
+		/// The new Window Title.
+		/// </summary>
+		public ustring NewTitle { get; set; }
+
+		/// <summary>
+		/// The old Window Title.
+		/// </summary>
+		public ustring OldTitle { get; set; }
+
+		/// <summary>
+		/// Flag which allows canceling the Title change.
+		/// </summary>
+		public bool Cancel { get; set; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="TitleEventArgs"/>
+		/// </summary>
+		/// <param name="oldTitle">The <see cref="Window.Title"/> that is/has been replaced.</param>
+		/// <param name="newTitle">The new <see cref="Window.Title"/> to be replaced.</param>
+		public TitleEventArgs (ustring oldTitle, ustring newTitle)
+		{
+			OldTitle = oldTitle;
+			NewTitle = newTitle;
+		}
+	}
+}

+ 30 - 0
Terminal.Gui/Core/ToggleEventArgs.cs

@@ -0,0 +1,30 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// <see cref="EventArgs"/> for the <see cref="CheckBox.Toggled"/> event
+	/// </summary>
+	public class ToggleEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="ToggleEventArgs"/> class.
+		/// </summary>
+		/// <param name="oldValue"></param>
+		/// <param name="newValue"></param>
+		public ToggleEventArgs (bool? oldValue, bool? newValue)
+		{
+			OldValue = oldValue;
+			NewValue = newValue;
+		}
+
+		/// <summary>
+		/// The previous checked state
+		/// </summary>
+		public bool? OldValue { get; }
+
+		/// <summary>
+		/// The new checked state
+		/// </summary>
+		public bool? NewValue { get; }
+	}
+}

+ 101 - 97
Terminal.Gui/Core/Toplevel.cs

@@ -20,19 +20,6 @@ namespace Terminal.Gui {
 	///     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>
-	///   <para>
-	///     Toplevels can also opt-in to more sophisticated initialization
-	///     by implementing <see cref="ISupportInitialize"/>. When they do
-	///     so, the <see cref="ISupportInitialize.BeginInit"/> and
-	///     <see cref="ISupportInitialize.EndInit"/> methods will be called
-	///     before running the view.
-	///     If first-run-only initialization is preferred, the <see cref="ISupportInitializeNotification"/>
-	///     can be implemented too, in which case the <see cref="ISupportInitialize"/>
-	///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
-	///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
-	///     to override base class layout code optimally by doing so only on first run,
-	///     instead of on every run.
-	///   </para>
 	/// </remarks>
 	public class Toplevel : View {
 		/// <summary>
@@ -48,7 +35,7 @@ namespace Terminal.Gui {
 		/// A Loaded event handler is a good place to finalize initialization before calling 
 		/// <see cref="Application.RunLoop(Application.RunState, bool)"/>.
 		/// </summary>
-		public event Action Loaded;
+		public event EventHandler Loaded;
 
 		/// <summary>
 		/// Invoked when the Toplevel <see cref="MainLoop"/> has started it's first iteration.
@@ -57,109 +44,109 @@ namespace Terminal.Gui {
 		/// <para>A Ready event handler is a good place to finalize initialization after calling 
 		/// <see cref="Application.Run(Func{Exception, bool})"/> on this Toplevel.</para>
 		/// </summary>
-		public event Action Ready;
+		public event EventHandler Ready;
 
 		/// <summary>
 		/// Invoked when the Toplevel <see cref="Application.RunState"/> has been unloaded.
 		/// A Unloaded event handler is a good place to dispose objects after calling <see cref="Application.End(Application.RunState)"/>.
 		/// </summary>
-		public event Action Unloaded;
+		public event EventHandler Unloaded;
 
 		/// <summary>
 		/// Invoked when the Toplevel <see cref="Application.RunState"/> becomes the <see cref="Application.Current"/> Toplevel.
 		/// </summary>
-		public event Action<Toplevel> Activate;
+		public event EventHandler<ToplevelEventArgs> Activate;
 
 		/// <summary>
 		/// Invoked when the Toplevel<see cref="Application.RunState"/> ceases to be the <see cref="Application.Current"/> Toplevel.
 		/// </summary>
-		public event Action<Toplevel> Deactivate;
+		public event EventHandler<ToplevelEventArgs> Deactivate;
 
 		/// <summary>
 		/// Invoked when a child of the Toplevel <see cref="Application.RunState"/> is closed by  
 		/// <see cref="Application.End(Application.RunState)"/>.
 		/// </summary>
-		public event Action<Toplevel> ChildClosed;
+		public event EventHandler<ToplevelEventArgs> ChildClosed;
 
 		/// <summary>
 		/// Invoked when the last child of the Toplevel <see cref="Application.RunState"/> is closed from 
 		/// by <see cref="Application.End(Application.RunState)"/>.
 		/// </summary>
-		public event Action AllChildClosed;
+		public event EventHandler AllChildClosed;
 
 		/// <summary>
 		/// Invoked when the Toplevel's <see cref="Application.RunState"/> is being closed by  
 		/// <see cref="Application.RequestStop(Toplevel)"/>.
 		/// </summary>
-		public event Action<ToplevelClosingEventArgs> Closing;
+		public event EventHandler<ToplevelClosingEventArgs> Closing;
 
 		/// <summary>
 		/// Invoked when the Toplevel's <see cref="Application.RunState"/> is closed by <see cref="Application.End(Application.RunState)"/>.
 		/// </summary>
-		public event Action<Toplevel> Closed;
+		public event EventHandler<ToplevelEventArgs> Closed;
 
 		/// <summary>
 		/// Invoked when a child Toplevel's <see cref="Application.RunState"/> has been loaded.
 		/// </summary>
-		public event Action<Toplevel> ChildLoaded;
+		public event EventHandler<ToplevelEventArgs> ChildLoaded;
 
 		/// <summary>
 		/// Invoked when a cjhild Toplevel's <see cref="Application.RunState"/> has been unloaded.
 		/// </summary>
-		public event Action<Toplevel> ChildUnloaded;
+		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 Action<Size> Resized;
+		public event EventHandler<SizeChangedEventArgs> Resized;
 
-		internal virtual void OnResized (Size size)
+		internal virtual void OnResized (SizeChangedEventArgs size)
 		{
-			Resized?.Invoke (size);
+			Resized?.Invoke (this, size);
 		}
 
 		internal virtual void OnChildUnloaded (Toplevel top)
 		{
-			ChildUnloaded?.Invoke (top);
+			ChildUnloaded?.Invoke (this, new ToplevelEventArgs (top));
 		}
 
 		internal virtual void OnChildLoaded (Toplevel top)
 		{
-			ChildLoaded?.Invoke (top);
+			ChildLoaded?.Invoke (this, new ToplevelEventArgs (top));
 		}
 
 		internal virtual void OnClosed (Toplevel top)
 		{
-			Closed?.Invoke (top);
+			Closed?.Invoke (this, new ToplevelEventArgs (top));
 		}
 
 		internal virtual bool OnClosing (ToplevelClosingEventArgs ev)
 		{
-			Closing?.Invoke (ev);
+			Closing?.Invoke (this, ev);
 			return ev.Cancel;
 		}
 
 		internal virtual void OnAllChildClosed ()
 		{
-			AllChildClosed?.Invoke ();
+			AllChildClosed?.Invoke (this, EventArgs.Empty);
 		}
 
 		internal virtual void OnChildClosed (Toplevel top)
 		{
 			if (IsMdiContainer) {
-				SetChildNeedsDisplay ();
+				SetSubViewNeedsDisplay ();
 			}
-			ChildClosed?.Invoke (top);
+			ChildClosed?.Invoke (this, new ToplevelEventArgs (top));
 		}
 
 		internal virtual void OnDeactivate (Toplevel activated)
 		{
-			Deactivate?.Invoke (activated);
+			Deactivate?.Invoke (this, new ToplevelEventArgs (activated));
 		}
 
 		internal virtual void OnActivate (Toplevel deactivated)
 		{
-			Activate?.Invoke (deactivated);
+			Activate?.Invoke (this, new ToplevelEventArgs (deactivated));
 		}
 
 		/// <summary>
@@ -167,10 +154,11 @@ namespace Terminal.Gui {
 		/// </summary>
 		virtual public void OnLoaded ()
 		{
+			IsLoaded = true;
 			foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
 				tl.OnLoaded ();
 			}
-			Loaded?.Invoke ();
+			Loaded?.Invoke (this, EventArgs.Empty);
 		}
 
 		/// <summary>
@@ -182,7 +170,7 @@ namespace Terminal.Gui {
 			foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
 				tl.OnReady ();
 			}
-			Ready?.Invoke ();
+			Ready?.Invoke (this, EventArgs.Empty);
 		}
 
 		/// <summary>
@@ -193,7 +181,7 @@ namespace Terminal.Gui {
 			foreach (Toplevel tl in Subviews.Where (v => v is Toplevel)) {
 				tl.OnUnloaded ();
 			}
-			Unloaded?.Invoke ();
+			Unloaded?.Invoke (this, EventArgs.Empty);
 		}
 
 		/// <summary>
@@ -220,6 +208,13 @@ namespace Terminal.Gui {
 		{
 			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; });
@@ -255,49 +250,63 @@ namespace Terminal.Gui {
 			AddKeyBinding (Key.L | Key.CtrlMask, Command.Refresh);
 		}
 
+		private 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;
+			}
+		}
+
 		/// <summary>
 		/// Invoked when the <see cref="Application.AlternateForwardKey"/> is changed.
 		/// </summary>
-		public event Action<Key> AlternateForwardKeyChanged;
+		public event EventHandler<KeyChangedEventArgs> AlternateForwardKeyChanged;
 
 		/// <summary>
 		/// Virtual method to invoke the <see cref="AlternateForwardKeyChanged"/> event.
 		/// </summary>
-		/// <param name="oldKey"></param>
-		public virtual void OnAlternateForwardKeyChanged (Key oldKey)
+		/// <param name="e"></param>
+		public virtual void OnAlternateForwardKeyChanged (KeyChangedEventArgs e)
 		{
-			ReplaceKeyBinding (oldKey, Application.AlternateForwardKey);
-			AlternateForwardKeyChanged?.Invoke (oldKey);
+			ReplaceKeyBinding (e.OldKey, e.NewKey);
+			AlternateForwardKeyChanged?.Invoke (this, e);
 		}
 
 		/// <summary>
 		/// Invoked when the <see cref="Application.AlternateBackwardKey"/> is changed.
 		/// </summary>
-		public event Action<Key> AlternateBackwardKeyChanged;
+		public event EventHandler<KeyChangedEventArgs> AlternateBackwardKeyChanged;
 
 		/// <summary>
 		/// Virtual method to invoke the <see cref="AlternateBackwardKeyChanged"/> event.
 		/// </summary>
-		/// <param name="oldKey"></param>
-		public virtual void OnAlternateBackwardKeyChanged (Key oldKey)
+		/// <param name="e"></param>
+		public virtual void OnAlternateBackwardKeyChanged (KeyChangedEventArgs e)
 		{
-			ReplaceKeyBinding (oldKey, Application.AlternateBackwardKey);
-			AlternateBackwardKeyChanged?.Invoke (oldKey);
+			ReplaceKeyBinding (e.OldKey, e.NewKey);
+			AlternateBackwardKeyChanged?.Invoke (this, e);
 		}
 
 		/// <summary>
 		/// Invoked when the <see cref="Application.QuitKey"/> is changed.
 		/// </summary>
-		public event Action<Key> QuitKeyChanged;
+		public event EventHandler<KeyChangedEventArgs> QuitKeyChanged;
 
 		/// <summary>
 		/// Virtual method to invoke the <see cref="QuitKeyChanged"/> event.
 		/// </summary>
-		/// <param name="oldKey"></param>
-		public virtual void OnQuitKeyChanged (Key oldKey)
+		/// <param name="e"></param>
+		public virtual void OnQuitKeyChanged (KeyChangedEventArgs e)
 		{
-			ReplaceKeyBinding (oldKey, Application.QuitKey);
-			QuitKeyChanged?.Invoke (oldKey);
+			ReplaceKeyBinding (e.OldKey, e.NewKey);
+			QuitKeyChanged?.Invoke (this, e);
 		}
 
 		/// <summary>
@@ -367,6 +376,12 @@ namespace Terminal.Gui {
 			}
 		}
 
+		/// <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; }
+
 		///<inheritdoc/>
 		public override bool OnKeyDown (KeyEvent keyEvent)
 		{
@@ -600,7 +615,7 @@ namespace Terminal.Gui {
 		}
 
 		internal View EnsureVisibleBounds (Toplevel top, int x, int y,
-			out int nx, out int ny, out View mb, out View sb)
+			out int nx, out int ny, out MenuBar mb, out StatusBar sb)
 		{
 			int l;
 			View superView;
@@ -611,11 +626,15 @@ namespace Terminal.Gui {
 				l = top.SuperView.Frame.Width;
 				superView = top.SuperView;
 			}
-			nx = Math.Max (x, 0);
-			nx = nx + top.Frame.Width > l ? Math.Max (l - top.Frame.Width, 0) : nx;
 			var mfLength = top.Border?.DrawMarginFrame == true ? 2 : 1;
-			if (nx + mfLength > top.Frame.X + top.Frame.Width) {
-				nx = Math.Max (top.Frame.Right - mfLength, 0);
+			if (top.Frame.Width <= l) {
+				nx = Math.Max (x, 0);
+				nx = nx + top.Frame.Width > l ? Math.Max (l - top.Frame.Width, 0) : nx;
+				if (nx + mfLength > top.Frame.X + top.Frame.Width) {
+					nx = Math.Max (top.Frame.Right - mfLength, 0);
+				}
+			} else {
+				nx = x;
 			}
 			//System.Diagnostics.Debug.WriteLine ($"nx:{nx}, rWidth:{rWidth}");
 			bool m, s;
@@ -624,7 +643,7 @@ namespace Terminal.Gui {
 				mb = Application.Top.MenuBar;
 			} else {
 				var t = top.SuperView;
-				while (!(t is Toplevel)) {
+				while (t is not Toplevel) {
 					t = t.SuperView;
 				}
 				m = ((Toplevel)t).MenuBar?.Visible == true;
@@ -641,7 +660,7 @@ namespace Terminal.Gui {
 				sb = Application.Top.StatusBar;
 			} else {
 				var t = top.SuperView;
-				while (!(t is Toplevel)) {
+				while (t is not Toplevel) {
 					t = t.SuperView;
 				}
 				s = ((Toplevel)t).StatusBar?.Visible == true;
@@ -653,9 +672,11 @@ namespace Terminal.Gui {
 				l = s ? top.SuperView.Frame.Height - 1 : top.SuperView.Frame.Height;
 			}
 			ny = Math.Min (ny, l);
-			ny = ny + top.Frame.Height >= l ? Math.Max (l - top.Frame.Height, m ? 1 : 0) : ny;
-			if (ny + mfLength > top.Frame.Y + top.Frame.Height) {
-				ny = Math.Max (top.Frame.Bottom - mfLength, 0);
+			if (top.Frame.Height <= l) {
+				ny = ny + top.Frame.Height >= l ? Math.Max (l - top.Frame.Height, m ? 1 : 0) : ny;
+				if (ny + mfLength > top.Frame.Y + top.Frame.Height) {
+					ny = Math.Max (top.Frame.Bottom - mfLength, 0);
+				}
 			}
 			//System.Diagnostics.Debug.WriteLine ($"ny:{ny}, rHeight:{rHeight}");
 
@@ -673,28 +694,30 @@ namespace Terminal.Gui {
 		}
 
 		/// <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.</param>
+		/// <param name="top">The Toplevel to adjust.</param>
 		public virtual void PositionToplevel (Toplevel top)
 		{
 			var superView = EnsureVisibleBounds (top, top.Frame.X, top.Frame.Y,
-				out int nx, out int ny, out _, out View sb);
+				out int nx, out int ny, out _, out StatusBar sb);
 			bool layoutSubviews = false;
-			if ((top?.SuperView != null || (top != Application.Top && top.Modal)
+			if ((superView != top || top?.SuperView != null || (top != Application.Top && top.Modal)
 				|| (top?.SuperView == null && top.IsMdiChild))
-				&& (nx > top.Frame.X || ny > top.Frame.Y) && top.LayoutStyle == LayoutStyle.Computed) {
+				&& (top.Frame.X + top.Frame.Width > Driver.Cols || ny > top.Frame.Y) && top.LayoutStyle == LayoutStyle.Computed) {
 
-				if ((top.X == null || top.X is Pos.PosAbsolute) && top.Bounds.X != nx) {
+				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.Bounds.Y != ny) {
+				if ((top.Y == null || top.Y is Pos.PosAbsolute) && top.Frame.Y != ny) {
 					top.Y = ny;
 					layoutSubviews = true;
 				}
 			}
 
+			// TODO: v2 - This is a hack to get the StatusBar to be positioned correctly.
 			if (sb != null && ny + top.Frame.Height != superView.Frame.Height - (sb.Visible ? 1 : 0)
 				&& top.Height is Dim.DimFill && -top.Height.Anchor (0) < 1) {
 
@@ -741,12 +764,8 @@ namespace Terminal.Gui {
 					if (view.Frame.IntersectsWith (bounds) && !OutsideTopFrame (this)) {
 						view.SetNeedsLayout ();
 						view.SetNeedsDisplay (view.Bounds);
-						//view.Redraw (view.Bounds);
 					}
 				}
-
-				ClearLayoutNeeded ();
-				ClearNeedsDisplay ();
 			}
 
 			base.Redraw (Bounds);
@@ -820,8 +839,8 @@ namespace Terminal.Gui {
 			}
 
 			if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Released) && dragPosition.HasValue) {
-				Application.UngrabMouse ();
 				dragPosition = null;
+				Application.UngrabMouse ();
 			}
 
 			//System.Diagnostics.Debug.WriteLine ($"dragPosition after: {dragPosition.HasValue}");
@@ -980,6 +999,13 @@ namespace Terminal.Gui {
 		{
 			return MostFocused?.OnLeave (view) ?? base.OnLeave (view);
 		}
+
+		///<inheritdoc/>
+		protected override void Dispose (bool disposing)
+		{
+			dragPosition = null;
+			base.Dispose (disposing);
+		}
 	}
 
 	/// <summary>
@@ -1046,26 +1072,4 @@ namespace Terminal.Gui {
 				return string.Compare (x.Id.ToString (), y.Id.ToString ());
 		}
 	}
-	/// <summary>
-	/// <see cref="EventArgs"/> implementation for the <see cref="Toplevel.Closing"/> event.
-	/// </summary>
-	public class ToplevelClosingEventArgs : EventArgs {
-		/// <summary>
-		/// The toplevel requesting stop.
-		/// </summary>
-		public View RequestingTop { get; }
-		/// <summary>
-		/// Provides an event cancellation option.
-		/// </summary>
-		public bool Cancel { get; set; }
-
-		/// <summary>
-		/// Initializes the event arguments with the requesting toplevel.
-		/// </summary>
-		/// <param name="requestingTop">The <see cref="RequestingTop"/>.</param>
-		public ToplevelClosingEventArgs (Toplevel requestingTop)
-		{
-			RequestingTop = requestingTop;
-		}
-	}
 }

+ 51 - 0
Terminal.Gui/Core/ToplevelEventArgs.cs

@@ -0,0 +1,51 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Args for events that relate to a specific <see cref="Toplevel"/>.
+	/// </summary>
+	public class ToplevelEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="ToplevelClosingEventArgs"/> class.
+		/// </summary>
+		/// <param name="toplevel"></param>
+		public ToplevelEventArgs (Toplevel toplevel)
+		{
+			Toplevel = toplevel;
+		}
+
+		/// <summary>
+		/// Gets the <see cref="Toplevel"/> that the event is about.
+		/// </summary>
+		/// <remarks>This is usually but may not always be the same as the sender 
+		/// in <see cref="EventHandler"/>.  For example if the reported event
+		/// is about a different  <see cref="Toplevel"/> or the event is
+		/// raised by a separate class.
+		/// </remarks>
+		public Toplevel Toplevel { get; }
+	}
+
+	/// <summary>
+	/// <see cref="EventArgs"/> implementation for the <see cref="Toplevel.Closing"/> event.
+	/// </summary>
+	public class ToplevelClosingEventArgs : EventArgs {
+		/// <summary>
+		/// The toplevel requesting stop.
+		/// </summary>
+		public View RequestingTop { get; }
+		/// <summary>
+		/// Provides an event cancellation option.
+		/// </summary>
+		public bool Cancel { get; set; }
+
+		/// <summary>
+		/// Initializes the event arguments with the requesting toplevel.
+		/// </summary>
+		/// <param name="requestingTop">The <see cref="RequestingTop"/>.</param>
+		public ToplevelClosingEventArgs (Toplevel requestingTop)
+		{
+			RequestingTop = requestingTop;
+		}
+	}
+}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 218 - 215
Terminal.Gui/Core/View.cs


+ 0 - 27
Terminal.Gui/Core/View2.cs

@@ -1,27 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using System.Reflection;
-using NStack;
-
-namespace Terminal.Gui {
-
-	public class View2 : View, ISupportInitializeNotification {
-		public Thickness Margin { get; set; }
-
-		void DrawThickness (Thickness thickness)
-		{
-
-		}
-
-		public override void Redraw (Rect bounds)
-		{
-			base.Redraw (bounds);
-
-			DrawThickness (Margin);
-		}
-
-
-	}
-}

+ 80 - 0
Terminal.Gui/Core/ViewEventArgs.cs

@@ -0,0 +1,80 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Args for events that relate to specific <see cref="View"/>
+	/// </summary>
+	public class ViewEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="Terminal.Gui.View"/> class.
+		/// </summary>
+		/// <param name="view"></param>
+		public ViewEventArgs (View view)
+		{
+			View = view;
+		}
+
+		/// <summary>
+		/// The view that the event is about.
+		/// </summary>
+		/// <remarks>
+		/// Can be different from the sender of the <see cref="EventHandler"/>
+		/// for example if event describes the adding a child then sender may
+		/// be the parent while <see cref="View"/> is the child
+		/// being added.
+		/// </remarks>
+		public View View { get; }
+	}
+
+	/// <summary>
+	/// Event arguments for the <see cref="View.LayoutComplete"/> event.
+	/// </summary>
+	public class LayoutEventArgs : EventArgs {
+		/// <summary>
+		/// The view-relative bounds of the <see cref="View"/> before it was laid out.
+		/// </summary>
+		public Rect OldBounds { get; set; }
+	}
+
+	/// <summary>
+	/// Event args for draw events
+	/// </summary>
+	public class DrawEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="DrawEventArgs"/> class.
+		/// </summary>
+		/// <param name="rect">Gets the view-relative rectangle describing the currently visible viewport into the <see cref="View"/>.</param>
+		public DrawEventArgs (Rect rect)
+		{
+			Rect = rect;
+		}
+
+		/// <summary>
+		/// Gets the view-relative rectangle describing the currently visible viewport into the <see cref="View"/>.
+		/// </summary>
+		public Rect Rect { get; }
+	}
+
+	/// <summary>
+	/// Defines the event arguments for <see cref="View.SetFocus(View)"/>
+	/// </summary>
+	public class FocusEventArgs : EventArgs {
+		/// <summary>
+		/// Constructs.
+		/// </summary>
+		/// <param name="view">The view that gets or loses focus.</param>
+		public FocusEventArgs (View view) { View = view; }
+		/// <summary>
+		/// Indicates if the current focus event has already been processed and the driver should stop notifying any other event subscriber.
+		/// Its important to set this value to true specially when updating any View's layout from inside the subscriber method.
+		/// </summary>
+		public bool Handled { get; set; }
+		/// <summary>
+		/// Indicates the current view that gets or loses focus.
+		/// </summary>
+		public View View { get; set; }
+	}
+
+}

+ 27 - 54
Terminal.Gui/Core/Window.cs

@@ -7,7 +7,7 @@
 //  - FrameView Does not support padding (but should)
 //  - FrameView Does not support mouse dragging
 //  - FrameView Does not support IEnumerable
-// Any udpates done here should probably be done in FrameView as well; TODO: Merge these classes
+// Any updates done here should probably be done in FrameView as well; TODO: Merge these classes
 
 using System;
 using System.Collections;
@@ -24,7 +24,7 @@ namespace Terminal.Gui {
 	/// The 'client area' of a <see cref="Window"/> is a rectangle deflated by one or more rows/columns from <see cref="View.Bounds"/>. A this time there is no
 	/// API to determine this rectangle.
 	/// </remarks>
-	public class Window : Toplevel {
+	public partial class Window : Toplevel {
 		View contentView;
 		ustring title = ustring.Empty;
 
@@ -38,6 +38,9 @@ namespace Terminal.Gui {
 				if (!OnTitleChanging (title, value)) {
 					var old = title;
 					title = value;
+					if (Border != null) {
+						Border.Title = title;
+					}
 					OnTitleChanged (old, title);
 				}
 				SetNeedsDisplay ();
@@ -67,7 +70,7 @@ namespace Terminal.Gui {
 			}
 		}
 
-		void Border_BorderChanged (Border border)
+		void Border_BorderChanged (object sender, EventArgs e)
 		{
 			Rect frame;
 			if (contentView != null && (contentView.Width is Dim || contentView.Height is Dim)) {
@@ -192,10 +195,13 @@ namespace Terminal.Gui {
 				Border = new Border () {
 					BorderStyle = DefaultBorderStyle,
 					Padding = new Thickness (padding),
-					BorderBrush = ColorScheme.Normal.Background
+					Title = title
 				};
 			} else {
 				Border = border;
+				if (ustring.IsNullOrEmpty (border.Title)) {
+					border.Title = title;
+				}
 			}
 			AdjustContentView (frame);
 		}
@@ -234,9 +240,12 @@ namespace Terminal.Gui {
 					contentView.Frame = cFrame;
 				}
 			}
-			if (Subviews?.Count == 0)
+			if (Subviews?.Count == 0) {
 				base.Add (contentView);
-			Border.Child = contentView;
+			}
+			if (Border.Child != contentView) {
+				Border.Child = contentView;
+			}
 		}
 
 		///// <summary>
@@ -267,7 +276,13 @@ namespace Terminal.Gui {
 			}
 
 			SetNeedsDisplay ();
-			contentView.Remove (view);
+			if (view == contentView) {
+				base.Remove (view);
+				contentView.Dispose ();
+				return;
+			} else {
+				contentView.Remove (view);
+			}
 
 			if (contentView.InternalSubviews.Count < 1) {
 				CanFocus = false;
@@ -287,9 +302,6 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		public override void Redraw (Rect bounds)
 		{
-			var padding = Border.GetSumThickness ();
-			var scrRect = ViewToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
-
 			if (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded) {
 				Driver.SetAttribute (GetNormalColor ());
 				Clear ();
@@ -298,7 +310,6 @@ namespace Terminal.Gui {
 			var savedClip = contentView.ClipToBounds ();
 
 			// Redraw our contentView
-			// DONE: smartly constrict contentView.Bounds to just be what intersects with the 'bounds' we were passed
 			contentView.Redraw (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded ? contentView.Bounds : bounds);
 			Driver.Clip = savedClip;
 
@@ -306,14 +317,7 @@ namespace Terminal.Gui {
 			ClearNeedsDisplay ();
 
 			Driver.SetAttribute (GetNormalColor ());
-			//Driver.DrawWindowFrame (scrRect, padding.Left + borderLength, padding.Top + borderLength, padding.Right + borderLength, padding.Bottom + borderLength,
-			//	Border.BorderStyle != BorderStyle.None, fill: true, Border.BorderStyle);
 			Border.DrawContent (this, false);
-			if (HasFocus)
-				Driver.SetAttribute (ColorScheme.HotNormal);
-			if (Border.DrawMarginFrame)
-				Driver.DrawWindowTitle (scrRect, Title, padding.Left, padding.Top, padding.Right, padding.Bottom);
-			Driver.SetAttribute (GetNormalColor ());
 		}
 
 		/// <inheritdoc/>
@@ -348,47 +352,16 @@ namespace Terminal.Gui {
 				base.TextAlignment = contentView.TextAlignment = value;
 			}
 		}
-
-		/// <summary>
-		/// Event arguments for <see cref="Title"/> chane events.
-		/// </summary>
-		public class TitleEventArgs : EventArgs {
-			/// <summary>
-			/// The new Window Title.
-			/// </summary>
-			public ustring NewTitle { get; set; }
-
-			/// <summary>
-			/// The old Window Title.
-			/// </summary>
-			public ustring OldTitle { get; set; }
-
-			/// <summary>
-			/// Flag which allows cancelling the Title change.
-			/// </summary>
-			public bool Cancel { get; set; }
-
-			/// <summary>
-			/// Initializes a new instance of <see cref="TitleEventArgs"/>
-			/// </summary>
-			/// <param name="oldTitle">The <see cref="Window.Title"/> that is/has been replaced.</param>
-			/// <param name="newTitle">The new <see cref="Window.Title"/> to be replaced.</param>
-			public TitleEventArgs (ustring oldTitle, ustring newTitle)
-			{
-				OldTitle = oldTitle;
-				NewTitle = newTitle;
-			}
-		}
 		/// <summary>
 		/// Called before the <see cref="Window.Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be cancelled.
 		/// </summary>
 		/// <param name="oldTitle">The <see cref="Window.Title"/> that is/has been replaced.</param>
 		/// <param name="newTitle">The new <see cref="Window.Title"/> to be replaced.</param>
-		/// <returns>`true` if an event handler cancelled the Title change.</returns>
+		/// <returns>`true` if an event handler canceled the Title change.</returns>
 		public virtual bool OnTitleChanging (ustring oldTitle, ustring newTitle)
 		{
 			var args = new TitleEventArgs (oldTitle, newTitle);
-			TitleChanging?.Invoke (args);
+			TitleChanging?.Invoke (this, args);
 			return args.Cancel;
 		}
 
@@ -396,7 +369,7 @@ namespace Terminal.Gui {
 		/// Event fired when the <see cref="Window.Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to 
 		/// `true` to cancel the Title change.
 		/// </summary>
-		public event Action<TitleEventArgs> TitleChanging;
+		public event EventHandler<TitleEventArgs> TitleChanging;
 
 		/// <summary>
 		/// Called when the <see cref="Window.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.
@@ -406,12 +379,12 @@ namespace Terminal.Gui {
 		public virtual void OnTitleChanged (ustring oldTitle, ustring newTitle)
 		{
 			var args = new TitleEventArgs (oldTitle, newTitle);
-			TitleChanged?.Invoke (args);
+			TitleChanged?.Invoke (this, args);
 		}
 
 		/// <summary>
 		/// Event fired after the <see cref="Window.Title"/> has been changed. 
 		/// </summary>
-		public event Action<TitleEventArgs> TitleChanged;
+		public event EventHandler<TitleEventArgs> TitleChanged;
 	}
 }

+ 1 - 1
Terminal.Gui/Resources/config.json

@@ -23,7 +23,7 @@
       "Ctrl"
     ]
   },
-  "Application.HeightAsBuffer": false,
+  "Application.EnableConsoleScrolling": false,
   "Application.QuitKey": {
     "Key": "Q",
     "Modifiers": [

+ 9 - 10
Terminal.Gui/Terminal.Gui.csproj

@@ -10,10 +10,10 @@
     <!-- Version numbers are automatically updated by gitversion when a release is released -->
     <!-- In the source tree the version will always be 1.0 for all projects. -->
     <!-- Do not modify these. Do NOT commit after manually running `dotnet-gitversion /updateprojectfiles` -->
-    <AssemblyVersion>1.0</AssemblyVersion>
-    <FileVersion>1.0</FileVersion>
-    <Version>1.0</Version>
-    <InformationalVersion>1.0</InformationalVersion>
+    <AssemblyVersion>2.0</AssemblyVersion>
+    <FileVersion>2.0</FileVersion>
+    <Version>2.0</Version>
+    <InformationalVersion>2.0</InformationalVersion>
   </PropertyGroup>
   <ItemGroup>
     <None Remove="Resources\config.json" />
@@ -22,11 +22,15 @@
     <EmbeddedResource Include="Resources\config.json" />
   </ItemGroup>
   <ItemGroup>
+    <!-- Enable Nuget Source Link for github -->
+    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
     <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
     <PackageReference Include="NStack.Core" Version="1.0.7" />
+    <PackageReference Include="System.Text.Json" Version="7.0.1" />
+    <PackageReference Include="System.Management" Version="7.0.0" />
     <InternalsVisibleTo Include="UnitTests" />
-  </ItemGroup>
+   </ItemGroup>
   <!-- Uncomment the RestoreSources element to have dotnet restore pull NStack from a local dir for testing -->
   <PropertyGroup>
     <!-- See https://stackoverflow.com/a/44463578/297526 -->
@@ -56,11 +60,6 @@
       <LastGenOutput>Strings.Designer.cs</LastGenOutput>
     </EmbeddedResource>
   </ItemGroup>
-  <!-- Enable Nuget Source Link for github -->
-  <ItemGroup>
-    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
-    <PackageReference Include="System.Text.Json" Version="7.0.1" />
-  </ItemGroup>
   <PropertyGroup>
     <TargetFrameworks>net472;netstandard2.0;net6.0</TargetFrameworks>
     <LangVersion>9</LangVersion>

+ 1 - 1
Terminal.Gui/Types/Rect.cs

@@ -130,7 +130,7 @@ namespace Terminal.Gui
 		///
 		/// <remarks>
 		///	Produces a new Rectangle by intersecting 2 existing 
-		///	Rectangles. Returns null if there is no	intersection.
+		///	Rectangles. Returns Empty if there is no intersection.
 		/// </remarks>
 
 		public static Rect Intersect (Rect a, Rect b)

+ 14 - 9
Terminal.Gui/Views/Button.cs

@@ -60,7 +60,7 @@ namespace Terminal.Gui {
 		/// </param>
 		public Button (ustring text, bool is_default = false) : base (text)
 		{
-			Initialize (text, is_default);
+			SetInitialProperties (text, is_default);
 		}
 
 		/// <summary>
@@ -92,10 +92,15 @@ namespace Terminal.Gui {
 		public Button (int x, int y, ustring text, bool is_default)
 		    : base (new Rect (x, y, text.RuneCount + 4 + (is_default ? 2 : 0), 1), text)
 		{
-			Initialize (text, is_default);
+			SetInitialProperties (text, is_default);
 		}
-
-		void Initialize (ustring text, bool is_default)
+		// TODO: v2 - Remove constructors with parameters
+		/// <summary>
+		/// Private helper to set the initial properties of the View that were provided via constructors.
+		/// </summary>
+		/// <param name="text"></param>
+		/// <param name="is_default"></param>
+		void SetInitialProperties (ustring text, bool is_default)
 		{
 			TextAlignment = TextAlignment.Centered;
 			VerticalTextAlignment = VerticalTextAlignment.Middle;
@@ -111,8 +116,8 @@ namespace Terminal.Gui {
 			AutoSize = true;
 			this.is_default = is_default;
 			Text = text ?? string.Empty;
-			UpdateTextFormatterText ();
-			ProcessResizeView ();
+
+			OnResizeNeeded ();
 
 			// Things this view knows how to do
 			AddCommand (Command.Accept, () => AcceptKey ());
@@ -134,7 +139,7 @@ namespace Terminal.Gui {
 			set {
 				is_default = value;
 				UpdateTextFormatterText ();
-				ProcessResizeView ();
+				OnResizeNeeded ();
 			}
 		}
 
@@ -231,7 +236,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnClicked ()
 		{
-			Clicked?.Invoke ();
+			Clicked?.Invoke (this, EventArgs.Empty);
 		}
 
 		/// <summary>
@@ -243,7 +248,7 @@ namespace Terminal.Gui {
 		///   raised when the button is activated either with
 		///   the mouse or the keyboard.
 		/// </remarks>
-		public event Action Clicked;
+		public event EventHandler Clicked;
 
 		///<inheritdoc/>
 		public override bool MouseEvent (MouseEvent me)

+ 43 - 0
Terminal.Gui/Views/CellActivatedEventArgs.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Data;
+
+namespace Terminal.Gui {
+
+
+	/// <summary>
+	///  Defines the event arguments for <see cref="TableView.CellActivated"/> event
+	/// </summary>
+	public class CellActivatedEventArgs : EventArgs {
+		/// <summary>
+		/// The current table to which the new indexes refer.  May be null e.g. if selection change is the result of clearing the table from the view
+		/// </summary>
+		/// <value></value>
+		public DataTable Table { get; }
+
+
+		/// <summary>
+		/// The column index of the <see cref="Table"/> cell that is being activated
+		/// </summary>
+		/// <value></value>
+		public int Col { get; }
+
+		/// <summary>
+		/// The row index of the <see cref="Table"/> cell that is being activated
+		/// </summary>
+		/// <value></value>
+		public int Row { get; }
+
+		/// <summary>
+		/// Creates a new instance of arguments describing a cell being activated in <see cref="TableView"/>
+		/// </summary>
+		/// <param name="t"></param>
+		/// <param name="col"></param>
+		/// <param name="row"></param>
+		public CellActivatedEventArgs (DataTable t, int col, int row)
+		{
+			Table = t;
+			Col = col;
+			Row = row;
+		}
+	}
+}

+ 17 - 10
Terminal.Gui/Views/CheckBox.cs

@@ -27,14 +27,14 @@ namespace Terminal.Gui {
 		///   raised when the <see cref="CheckBox"/> is activated either with
 		///   the mouse or the keyboard. The passed <c>bool</c> contains the previous state. 
 		/// </remarks>
-		public event Action<bool?> Toggled;
+		public event EventHandler<ToggleEventArgs> Toggled;
 
 		/// <summary>
 		/// Called when the <see cref="Checked"/> property changes. Invokes the <see cref="Toggled"/> event.
 		/// </summary>
-		public virtual void OnToggled (bool? previousChecked)
+		public virtual void OnToggled (ToggleEventArgs e)
 		{
-			Toggled?.Invoke (previousChecked);
+			Toggled?.Invoke (this, e);
 		}
 
 		/// <summary>
@@ -49,7 +49,7 @@ namespace Terminal.Gui {
 		/// <param name="is_checked">If set to <c>true</c> is checked.</param>
 		public CheckBox (ustring s, bool is_checked = false) : base ()
 		{
-			Initialize (s, is_checked);
+			SetInitialProperties (s, is_checked);
 		}
 
 		/// <summary>
@@ -72,10 +72,16 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public CheckBox (int x, int y, ustring s, bool is_checked) : base (new Rect (x, y, s.Length, 1))
 		{
-			Initialize (s, is_checked);
+			SetInitialProperties (s, is_checked);
 		}
 
-		void Initialize (ustring s, bool is_checked)
+		// TODO: v2 - Remove constructors with parameters
+		/// <summary>
+		/// Private helper to set the initial properties of the View that were provided via constructors.
+		/// </summary>
+		/// <param name="s"></param>
+		/// <param name="is_checked"></param>
+		void SetInitialProperties (ustring s, bool is_checked)
 		{
 			charNullChecked = new Rune (Driver != null ? Driver.NullChecked : '?');
 			charChecked = new Rune (Driver != null ? Driver.Checked : '√');
@@ -85,8 +91,8 @@ namespace Terminal.Gui {
 			CanFocus = true;
 			AutoSize = true;
 			Text = s;
-			UpdateTextFormatterText ();
-			ProcessResizeView ();
+			
+			OnResizeNeeded ();
 
 			// Things this view knows how to do
 			AddCommand (Command.ToggleChecked, () => ToggleChecked ());
@@ -139,7 +145,7 @@ namespace Terminal.Gui {
 				}
 				@checked = value;
 				UpdateTextFormatterText ();
-				ProcessResizeView ();
+				OnResizeNeeded ();
 			}
 		}
 
@@ -203,7 +209,8 @@ namespace Terminal.Gui {
 			} else {
 				Checked = !Checked;
 			}
-			OnToggled (previousChecked);
+			
+			OnToggled (new ToggleEventArgs (previousChecked, Checked));
 			SetNeedsDisplay ();
 			return true;
 		}

+ 2 - 2
Terminal.Gui/Views/ColorPicker.cs

@@ -51,7 +51,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Fired when a color is picked.
 		/// </summary>
-		public event Action ColorChanged;
+		public event EventHandler ColorChanged;
 
 		private int selectColorIndex = (int)Color.Black;
 
@@ -65,7 +65,7 @@ namespace Terminal.Gui {
 
 			set {
 				selectColorIndex = (int)value;
-				ColorChanged?.Invoke ();
+				ColorChanged?.Invoke (this, EventArgs.Empty);
 				SetNeedsDisplay ();
 			}
 		}

+ 21 - 19
Terminal.Gui/Views/ComboBox.cs

@@ -188,7 +188,7 @@ namespace Terminal.Gui {
 				if (SuperView != null && SuperView.Subviews.Contains (this)) {
 					SelectedItem = -1;
 					search.Text = "";
-					Search_Changed ("");
+					Search_Changed (this, new TextChangedEventArgs (""));
 					SetNeedsDisplay ();
 				}
 			}
@@ -214,22 +214,22 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// This event is raised when the selected item in the <see cref="ComboBox"/> has changed.
 		/// </summary>
-		public event Action<ListViewItemEventArgs> SelectedItemChanged;
+		public event EventHandler<ListViewItemEventArgs> SelectedItemChanged;
 
 		/// <summary>
 		/// This event is raised when the drop-down list is expanded.
 		/// </summary>
-		public event Action Expanded;
+		public event EventHandler Expanded;
 
 		/// <summary>
 		/// This event is raised when the drop-down list is collapsed.
 		/// </summary>
-		public event Action Collapsed;
+		public event EventHandler Collapsed;
 
 		/// <summary>
 		/// This event is raised when the user Double Clicks on an item or presses ENTER to open the selected item.
 		/// </summary>
-		public event Action<ListViewItemEventArgs> OpenSelectedItem;
+		public event EventHandler<ListViewItemEventArgs> OpenSelectedItem;
 
 		readonly IList searchset = new List<object> ();
 		ustring text = "";
@@ -294,12 +294,12 @@ namespace Terminal.Gui {
 			search.TextChanged += Search_Changed;
 
 			listview.Y = Pos.Bottom (search);
-			listview.OpenSelectedItem += (ListViewItemEventArgs a) => Selected ();
+			listview.OpenSelectedItem += (object sender, ListViewItemEventArgs a) => Selected ();
 
 			this.Add (search, listview);
 
 			// On resize
-			LayoutComplete += (LayoutEventArgs a) => {
+			LayoutComplete += (object sender, LayoutEventArgs a) => {
 				if ((!autoHide && Bounds.Width > 0 && search.Frame.Width != Bounds.Width) ||
 					(autoHide && Bounds.Width > 0 && search.Frame.Width != Bounds.Width - 1)) {
 					search.Width = listview.Width = autoHide ? Bounds.Width - 1 : Bounds.Width;
@@ -309,14 +309,14 @@ namespace Terminal.Gui {
 				}
 			};
 
-			listview.SelectedItemChanged += (ListViewItemEventArgs e) => {
+			listview.SelectedItemChanged += (object sender, ListViewItemEventArgs e) => {
 
 				if (!HideDropdownListOnClick && searchset.Count > 0) {
 					SetValue (searchset [listview.SelectedItem]);
 				}
 			};
 
-			Added += (View v) => {
+			Added += (s, e) => {
 
 				// Determine if this view is hosted inside a dialog and is the only control
 				for (View view = this.SuperView; view != null; view = view.SuperView) {
@@ -328,7 +328,7 @@ namespace Terminal.Gui {
 
 				SetNeedsLayout ();
 				SetNeedsDisplay ();
-				Search_Changed (Text);
+				Search_Changed (this, new TextChangedEventArgs (Text));
 			};
 
 			// Things this view knows how to do
@@ -466,7 +466,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnExpanded ()
 		{
-			Expanded?.Invoke ();
+			Expanded?.Invoke (this, EventArgs.Empty);
 		}
 
 		/// <summary>
@@ -474,7 +474,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnCollapsed ()
 		{
-			Collapsed?.Invoke ();
+			Collapsed?.Invoke (this, EventArgs.Empty);
 		}
 
 		///<inheritdoc/>
@@ -515,7 +515,7 @@ namespace Terminal.Gui {
 		{
 			// Note: Cannot rely on "listview.SelectedItem != lastSelectedItem" because the list is dynamic. 
 			// So we cannot optimize. Ie: Don't call if not changed
-			SelectedItemChanged?.Invoke (new ListViewItemEventArgs (SelectedItem, search.Text));
+			SelectedItemChanged?.Invoke (this, new ListViewItemEventArgs (SelectedItem, search.Text));
 
 			return true;
 		}
@@ -528,7 +528,7 @@ namespace Terminal.Gui {
 		{
 			var value = search.Text;
 			lastSelectedItem = SelectedItem;
-			OpenSelectedItem?.Invoke (new ListViewItemEventArgs (SelectedItem, value));
+			OpenSelectedItem?.Invoke (this, new ListViewItemEventArgs (SelectedItem, value));
 
 			return true;
 		}
@@ -745,15 +745,17 @@ namespace Terminal.Gui {
 			if (listview.Source.Count == 0 || (searchset?.Count ?? 0) == 0) {
 				text = "";
 				HideList ();
+				isShow = false;
 				return;
 			}
 
-			SetValue (searchset [listview.SelectedItem]);
+			SetValue (listview.SelectedItem > -1 ? searchset [listview.SelectedItem] : text);
 			search.CursorPosition = search.Text.ConsoleWidth;
-			Search_Changed (search.Text);
+			Search_Changed (this, new TextChangedEventArgs (search.Text));
 			OnOpenSelectedItem ();
 			Reset (keepSearchText: true);
 			HideList ();
+			isShow = false;
 		}
 
 		private int GetSelectedItemFromSource (ustring value)
@@ -806,15 +808,15 @@ namespace Terminal.Gui {
 			}
 		}
 
-		private void Search_Changed (ustring text)
+		private void Search_Changed (object sender, TextChangedEventArgs e)
 		{
 			if (source == null) { // Object initialization		
 				return;
 			}
 
-			if (ustring.IsNullOrEmpty (search.Text) && ustring.IsNullOrEmpty (text)) {
+			if (ustring.IsNullOrEmpty (search.Text) && ustring.IsNullOrEmpty (e.OldValue)) {
 				ResetSearchSet ();
-			} else if (search.Text != text) {
+			} else if (search.Text != e.OldValue) {
 				isShow = true;
 				ResetSearchSet (noCopy: true);
 

+ 32 - 0
Terminal.Gui/Views/ContentsChangedEventArgs.cs

@@ -0,0 +1,32 @@
+// TextView.cs: multi-line text editing
+using System;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Event arguments for events for when the contents of the TextView change. E.g. the <see cref="TextView.ContentsChanged"/> event.
+	/// </summary>
+	public class ContentsChangedEventArgs : EventArgs {
+		/// <summary>
+		/// Creates a new <see cref="TextView.ContentsChanged"/> instance.
+		/// </summary>
+		/// <param name="currentRow">Contains the row where the change occurred.</param>
+		/// <param name="currentColumn">Contains the column where the change occured.</param>
+		public ContentsChangedEventArgs (int currentRow, int currentColumn)
+		{
+			Row = currentRow;
+			Col = currentColumn;
+		}
+
+		/// <summary>
+		/// 
+		/// Contains the row where the change occurred.
+		/// </summary>
+		public int Row { get; private set; }
+
+		/// <summary>
+		/// Contains the column where the change occurred.
+		/// </summary>
+		public int Col { get; private set; }
+	}
+}

+ 7 - 7
Terminal.Gui/Views/ContextMenu.cs

@@ -61,7 +61,7 @@ namespace Terminal.Gui {
 			Position = new Point (x, y);
 		}
 
-		private void MenuBar_MenuAllClosed ()
+		private void MenuBar_MenuAllClosed (object sender, EventArgs e)
 		{
 			Dispose ();
 		}
@@ -145,14 +145,14 @@ namespace Terminal.Gui {
 			menuBar.OpenMenu ();
 		}
 
-		private void Container_Resized (Size obj)
+		private void Container_Resized (object sender, SizeChangedEventArgs e)
 		{
 			if (IsShow) {
 				Show ();
 			}
 		}
 
-		private void Container_Closing (ToplevelClosingEventArgs obj)
+		private void Container_Closing (object sender, ToplevelClosingEventArgs obj)
 		{
 			Hide ();
 		}
@@ -169,12 +169,12 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Event invoked when the <see cref="ContextMenu.Key"/> is changed.
 		/// </summary>
-		public event Action<Key> KeyChanged;
+		public event EventHandler<KeyChangedEventArgs> KeyChanged;
 
 		/// <summary>
 		/// Event invoked when the <see cref="ContextMenu.MouseFlags"/> is changed.
 		/// </summary>
-		public event Action<MouseFlags> MouseFlagsChanged;
+		public event EventHandler<MouseFlagsChangedEventArgs> MouseFlagsChanged;
 
 		/// <summary>
 		/// Gets or sets the menu position.
@@ -194,7 +194,7 @@ namespace Terminal.Gui {
 			set {
 				var oldKey = key;
 				key = value;
-				KeyChanged?.Invoke (oldKey);
+				KeyChanged?.Invoke (this, new KeyChangedEventArgs(oldKey,key));
 			}
 		}
 
@@ -206,7 +206,7 @@ namespace Terminal.Gui {
 			set {
 				var oldFlags = mouseFlags;
 				mouseFlags = value;
-				MouseFlagsChanged?.Invoke (oldFlags);
+				MouseFlagsChanged?.Invoke (this, new MouseFlagsChangedEventArgs(oldFlags,value));
 			}
 		}
 

+ 5 - 38
Terminal.Gui/Views/DateField.cs

@@ -38,7 +38,7 @@ namespace Terminal.Gui {
 		/// <remarks>
 		///   The passed event arguments containing the old value, new value, and format string.
 		/// </remarks>
-		public event Action<DateTimeEventArgs<DateTime>> DateChanged;
+		public event EventHandler<DateTimeEventArgs<DateTime>> DateChanged;
 
 		/// <summary>
 		///    Initializes a new instance of <see cref="DateField"/> using <see cref="LayoutStyle.Absolute"/> layout.
@@ -106,13 +106,13 @@ namespace Terminal.Gui {
 			AddKeyBinding (Key.F | Key.CtrlMask, Command.Right);
 		}
 
-		void DateField_Changed (ustring e)
+		void DateField_Changed (object sender, TextChangedEventArgs e)
 		{
 			try {
 				if (!DateTime.TryParseExact (GetDate (Text).ToString (), GetInvarianteFormat (), CultureInfo.CurrentCulture, DateTimeStyles.None, out DateTime result))
-					Text = e;
+					Text = e.OldValue;
 			} catch (Exception) {
-				Text = e;
+				Text = e.OldValue;
 			}
 		}
 
@@ -418,40 +418,7 @@ namespace Terminal.Gui {
 		/// <param name="args">Event arguments</param>
 		public virtual void OnDateChanged (DateTimeEventArgs<DateTime> args)
 		{
-			DateChanged?.Invoke (args);
-		}
-	}
-
-	/// <summary>
-	/// Defines the event arguments for <see cref="DateField.DateChanged"/> and <see cref="TimeField.TimeChanged"/> events.
-	/// </summary>
-	public class DateTimeEventArgs<T> : EventArgs {
-		/// <summary>
-		/// The old <see cref="DateField"/> or <see cref="TimeField"/> value.
-		/// </summary>
-		public T OldValue { get; }
-
-		/// <summary>
-		/// The new <see cref="DateField"/> or <see cref="TimeField"/> value.
-		/// </summary>
-		public T NewValue { get; }
-
-		/// <summary>
-		/// The <see cref="DateField"/> or <see cref="TimeField"/> format.
-		/// </summary>
-		public string Format { get; }
-
-		/// <summary>
-		/// Initializes a new instance of <see cref="DateTimeEventArgs{T}"/>
-		/// </summary>
-		/// <param name="oldValue">The old <see cref="DateField"/> or <see cref="TimeField"/> value.</param>
-		/// <param name="newValue">The new <see cref="DateField"/> or <see cref="TimeField"/> value.</param>
-		/// <param name="format">The <see cref="DateField"/> or <see cref="TimeField"/> format string.</param>
-		public DateTimeEventArgs (T oldValue, T newValue, string format)
-		{
-			OldValue = oldValue;
-			NewValue = newValue;
-			Format = format;
+			DateChanged?.Invoke (this,args);
 		}
 	}
 }

+ 43 - 0
Terminal.Gui/Views/DateTimeEventArgs.cs

@@ -0,0 +1,43 @@
+//
+// DateField.cs: text entry for date
+//
+// Author: Barry Nolte
+//
+// Licensed under the MIT license
+//
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Defines the event arguments for <see cref="DateField.DateChanged"/> and <see cref="TimeField.TimeChanged"/> events.
+	/// </summary>
+	public class DateTimeEventArgs<T> : EventArgs {
+		/// <summary>
+		/// The old <see cref="DateField"/> or <see cref="TimeField"/> value.
+		/// </summary>
+		public T OldValue { get; }
+
+		/// <summary>
+		/// The new <see cref="DateField"/> or <see cref="TimeField"/> value.
+		/// </summary>
+		public T NewValue { get; }
+
+		/// <summary>
+		/// The <see cref="DateField"/> or <see cref="TimeField"/> format.
+		/// </summary>
+		public string Format { get; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="DateTimeEventArgs{T}"/>
+		/// </summary>
+		/// <param name="oldValue">The old <see cref="DateField"/> or <see cref="TimeField"/> value.</param>
+		/// <param name="newValue">The new <see cref="DateField"/> or <see cref="TimeField"/> value.</param>
+		/// <param name="format">The <see cref="DateField"/> or <see cref="TimeField"/> format string.</param>
+		public DateTimeEventArgs (T oldValue, T newValue, string format)
+		{
+			OldValue = oldValue;
+			NewValue = newValue;
+			Format = format;
+		}
+	}
+}

+ 30 - 45
Terminal.Gui/Views/FrameView.cs

@@ -1,15 +1,4 @@
-//
-// Authors:
-//   Miguel de Icaza ([email protected])
-//
-// NOTE: FrameView is functionally identical to Window with the following exceptions. 
-//  - Is not a Toplevel
-//  - Does not support mouse dragging
-//  - Does not support padding (but should)
-//  - Does not support IEnumerable
-// Any udpates done here should probably be done in Window as well; TODO: Merge these classes
-
-using System;
+using System;
 using System.Linq;
 using System.Text.Json.Serialization;
 using NStack;
@@ -67,6 +56,9 @@ namespace Terminal.Gui {
 			get => title;
 			set {
 				title = value;
+				if (Border != null) {
+					Border.Title = title;
+				}
 				SetNeedsDisplay ();
 			}
 		}
@@ -94,7 +86,7 @@ namespace Terminal.Gui {
 			}
 		}
 
-		void Border_BorderChanged (Border border)
+		void Border_BorderChanged (object sender, EventArgs e)
 		{
 			Rect frame;
 			if (contentView != null && (contentView.Width is Dim || contentView.Height is Dim)) {
@@ -124,8 +116,6 @@ namespace Terminal.Gui {
 		/// <param name="border">The <see cref="Border"/>.</param>
 		public FrameView (Rect frame, ustring title = null, View [] views = null, Border border = null) : base (frame)
 		{
-			//var cFrame = new Rect (1, 1, Math.Max (frame.Width - 2, 0), Math.Max (frame.Height - 2, 0));
-
 			Initialize (frame, title, views, border);
 		}
 
@@ -159,10 +149,14 @@ namespace Terminal.Gui {
 			this.Title = title;
 			if (border == null) {
 				Border = new Border () {
-					BorderStyle = DefaultBorderStyle
+					BorderStyle = DefaultBorderStyle,
+					Title = title
 				};
 			} else {
 				Border = border;
+				if (ustring.IsNullOrEmpty (border.Title)) {
+					border.Title = title;
+				}
 			}
 			AdjustContentView (frame, views);
 		}
@@ -261,12 +255,8 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		public override void Redraw (Rect bounds)
 		{
-			var padding = Border.GetSumThickness ();
-			var scrRect = ViewToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
-
 			if (!NeedDisplay.IsEmpty) {
 				Driver.SetAttribute (GetNormalColor ());
-				//Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: true);
 				Clear ();
 			}
 
@@ -274,17 +264,12 @@ namespace Terminal.Gui {
 			contentView.Redraw (!NeedDisplay.IsEmpty ? contentView.Bounds : bounds);
 			Driver.Clip = savedClip;
 
+			ClearLayoutNeeded ();
 			ClearNeedsDisplay ();
 
 			if (!IgnoreBorderPropertyOnRedraw) {
 				Driver.SetAttribute (GetNormalColor ());
-				//Driver.DrawWindowFrame (scrRect, padding + 1, padding + 1, padding + 1, padding + 1, border: true, fill: false);
 				Border.DrawContent (this, false);
-				if (HasFocus)
-					Driver.SetAttribute (ColorScheme.HotNormal);
-				if (Border.DrawMarginFrame)
-					Driver.DrawWindowTitle (scrRect, Title, padding.Left, padding.Top, padding.Right, padding.Bottom);
-				Driver.SetAttribute (GetNormalColor ());
 			} else {
 				var lc = new LineCanvas ();
 
@@ -306,28 +291,28 @@ namespace Terminal.Gui {
 
 				//}
 
-				Driver.SetAttribute (ColorScheme.Normal);
-				foreach (var p in lc.GenerateImage (bounds)) {
-					this.AddRune (p.Key.X, p.Key.Y, p.Value);
-				}
+				//Driver.SetAttribute (ColorScheme.Normal);
+				//foreach (var p in lc.GenerateImage (bounds)) {
+				//	this.AddRune (p.Key.X, p.Key.Y, p.Value);
+				//}
 
-				// Redraw the lines so that focus/drag symbol renders
-				foreach (var subview in contentView.Subviews) {
-					//	line.DrawSplitterSymbol ();
-				}
+				//// Redraw the lines so that focus/drag symbol renders
+				//foreach (var subview in contentView.Subviews) {
+				//	//	line.DrawSplitterSymbol ();
+				//}
 
 
-				// Draw Titles over Border
-				foreach (var subview in contentView.Subviews) {
-					// TODO: Use reflection to see if subview has a Title property
-					if (subview is FrameView viewWithTite) {
-						var rect = viewWithTite.Frame;
-						rect.X = rect.X + 1;
-						rect.Y = rect.Y + 2;
-						// TODO: Do focus color correctly
-						Driver.DrawWindowTitle (rect, viewWithTite.Title, padding.Left, padding.Top, padding.Right, padding.Bottom);
-					}
-				}
+				//// Draw Titles over Border
+				//foreach (var subview in contentView.Subviews) {
+				//	// TODO: Use reflection to see if subview has a Title property
+				//	if (subview is FrameView viewWithTite) {
+				//		var rect = viewWithTite.Frame;
+				//		rect.X = rect.X + 1;
+				//		rect.Y = rect.Y + 2;
+				//		// TODO: Do focus color correctly
+				//		Driver.DrawWindowTitle (rect, viewWithTite.Title, padding.Left, padding.Top, padding.Right, padding.Bottom);
+				//	}
+				//}
 			}
 		}
 

+ 9 - 41
Terminal.Gui/Views/HexView.cs

@@ -34,7 +34,7 @@ namespace Terminal.Gui {
 	/// to an offset in the stream.
 	/// </para>
 	/// </remarks>
-	public class HexView : View {
+	public partial class HexView : View {
 		SortedDictionary<long, byte> edits = new SortedDictionary<long, byte> ();
 		Stream source;
 		long displayStart, pos;
@@ -103,12 +103,12 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Event to be invoked when an edit is made on the <see cref="Stream"/>.
 		/// </summary>
-		public event Action<KeyValuePair<long, byte>> Edited;
+		public event EventHandler<HexViewEditEventArgs> Edited;
 
 		/// <summary>
 		/// Event to be invoked when the position and cursor position changes.
 		/// </summary>
-		public event Action<HexViewEventArgs> PositionChanged;
+		public event EventHandler<HexViewEventArgs> PositionChanged;
 
 		/// <summary>
 		/// Sets or gets the <see cref="Stream"/> the <see cref="HexView"/> is operating on; the stream must support seeking (<see cref="Stream.CanSeek"/> == true).
@@ -458,11 +458,11 @@ namespace Terminal.Gui {
 					firstNibble = false;
 					b = (byte)(b & 0xf | (value << bsize));
 					edits [position] = b;
-					OnEdited (new KeyValuePair<long, byte> (position, edits [position]));
+					OnEdited (new HexViewEditEventArgs (position, edits [position]));
 				} else {
 					b = (byte)(b & 0xf0 | value);
 					edits [position] = b;
-					OnEdited (new KeyValuePair<long, byte> (position, edits [position]));
+					OnEdited (new HexViewEditEventArgs (position, edits [position]));
 					MoveRight ();
 				}
 				return true;
@@ -473,10 +473,10 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Method used to invoke the <see cref="Edited"/> event passing the <see cref="KeyValuePair{TKey, TValue}"/>.
 		/// </summary>
-		/// <param name="keyValuePair">The key value pair.</param>
-		public virtual void OnEdited (KeyValuePair<long, byte> keyValuePair)
+		/// <param name="e">The key value pair.</param>
+		public virtual void OnEdited (HexViewEditEventArgs e)
 		{
-			Edited?.Invoke (keyValuePair);
+			Edited?.Invoke (this, e);
 		}
 
 		/// <summary>
@@ -484,7 +484,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnPositionChanged ()
 		{
-			PositionChanged?.Invoke (new HexViewEventArgs (Position, CursorPosition, BytesPerLine));
+			PositionChanged?.Invoke (this, new HexViewEventArgs (Position, CursorPosition, BytesPerLine));
 		}
 
 		/// <inheritdoc/>
@@ -631,37 +631,5 @@ namespace Terminal.Gui {
 
 			return base.OnEnter (view);
 		}
-
-		/// <summary>
-		/// Defines the event arguments for <see cref="PositionChanged"/> event.
-		/// </summary>
-		public class HexViewEventArgs : EventArgs {
-			/// <summary>
-			/// Gets the current character position starting at one, related to the <see cref="Stream"/>.
-			/// </summary>
-			public long Position { get; private set; }
-			/// <summary>
-			/// Gets the current cursor position starting at one for both, line and column.
-			/// </summary>
-			public Point CursorPosition { get; private set; }
-
-			/// <summary>
-			/// The bytes length per line.
-			/// </summary>
-			public int BytesPerLine { get; private set; }
-
-			/// <summary>
-			/// Initializes a new instance of <see cref="HexViewEventArgs"/>
-			/// </summary>
-			/// <param name="pos">The character position.</param>
-			/// <param name="cursor">The cursor position.</param>
-			/// <param name="lineLength">Line bytes length.</param>
-			public HexViewEventArgs (long pos, Point cursor, int lineLength)
-			{
-				Position = pos;
-				CursorPosition = cursor;
-				BytesPerLine = lineLength;
-			}
-		}
 	}
 }

+ 70 - 0
Terminal.Gui/Views/HexViewEventArgs.cs

@@ -0,0 +1,70 @@
+//
+// HexView.cs: A hexadecimal viewer
+//
+// TODO:
+// - Support searching and highlighting of the search result
+// - Bug showing the last line
+// 
+using System;
+using System.IO;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Defines the event arguments for <see cref="HexView.PositionChanged"/> event.
+	/// </summary>
+	public class HexViewEventArgs : EventArgs {
+		/// <summary>
+		/// Gets the current character position starting at one, related to the <see cref="Stream"/>.
+		/// </summary>
+		public long Position { get; private set; }
+		/// <summary>
+		/// Gets the current cursor position starting at one for both, line and column.
+		/// </summary>
+		public Point CursorPosition { get; private set; }
+
+		/// <summary>
+		/// The bytes length per line.
+		/// </summary>
+		public int BytesPerLine { get; private set; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="HexViewEventArgs"/>
+		/// </summary>
+		/// <param name="pos">The character position.</param>
+		/// <param name="cursor">The cursor position.</param>
+		/// <param name="lineLength">Line bytes length.</param>
+		public HexViewEventArgs (long pos, Point cursor, int lineLength)
+		{
+			Position = pos;
+			CursorPosition = cursor;
+			BytesPerLine = lineLength;
+		}
+	}
+
+	/// <summary>
+	/// Defines the event arguments for <see cref="HexView.Edited"/> event.
+	/// </summary>
+	public class HexViewEditEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="HexViewEditEventArgs"/> class.
+		/// </summary>
+		/// <param name="position"></param>
+		/// <param name="newValue"></param>
+		public HexViewEditEventArgs (long position, byte newValue)
+		{
+			Position = position;
+			NewValue = newValue;
+		}
+
+		/// <summary>
+		/// Gets the location of the edit.
+		/// </summary>
+		public long Position { get; }
+
+		/// <summary>
+		/// Gets the new value for that <see cref="Position"/>.
+		/// </summary>
+		public byte NewValue { get; }
+	}
+}

+ 36 - 0
Terminal.Gui/Views/HistoryTextItem.cs

@@ -0,0 +1,36 @@
+// TextView.cs: multi-line text editing
+using System;
+using System.Collections.Generic;
+using Rune = System.Rune;
+
+namespace Terminal.Gui {
+	partial class HistoryText {
+		public class HistoryTextItem : EventArgs {
+			public List<List<Rune>> Lines;
+			public Point CursorPosition;
+			public LineStatus LineStatus;
+			public bool IsUndoing;
+			public Point FinalCursorPosition;
+			public HistoryTextItem RemovedOnAdded;
+
+			public HistoryTextItem (List<List<Rune>> lines, Point curPos, LineStatus linesStatus)
+			{
+				Lines = lines;
+				CursorPosition = curPos;
+				LineStatus = linesStatus;
+			}
+
+			public HistoryTextItem (HistoryTextItem historyTextItem)
+			{
+				Lines = new List<List<Rune>> (historyTextItem.Lines);
+				CursorPosition = new Point (historyTextItem.CursorPosition.X, historyTextItem.CursorPosition.Y);
+				LineStatus = historyTextItem.LineStatus;
+			}
+
+			public override string ToString ()
+			{
+				return $"(Count: {Lines.Count}, Cursor: {CursorPosition}, Status: {LineStatus})";
+			}
+		}
+	}
+}

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

@@ -68,7 +68,7 @@ namespace Terminal.Gui {
 		///   raised when the button is activated either with
 		///   the mouse or the keyboard.
 		/// </remarks>
-		public event Action Clicked;
+		public event EventHandler Clicked;
 
 		///// <inheritdoc/>
 		//public new ustring Text {
@@ -92,7 +92,7 @@ namespace Terminal.Gui {
 		/// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
 		public override bool OnMouseEvent (MouseEvent mouseEvent)
 		{
-			MouseEventArgs args = new MouseEventArgs (mouseEvent);
+			MouseEventEventArgs args = new MouseEventEventArgs (mouseEvent);
 			if (OnMouseClick (args))
 				return true;
 			if (MouseEvent (mouseEvent))
@@ -139,7 +139,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnClicked ()
 		{
-			Clicked?.Invoke ();
+			Clicked?.Invoke (this, EventArgs.Empty);
 		}
 	}
 }

+ 25 - 86
Terminal.Gui/Views/ListView.cs

@@ -96,7 +96,7 @@ namespace Terminal.Gui {
 	/// </remarks>
 	public class ListView : View {
 		int top, left;
-		int selected;
+		int selected = -1;
 
 		IListDataSource source;
 		/// <summary>
@@ -112,7 +112,7 @@ namespace Terminal.Gui {
 				source = value;
 				KeystrokeNavigator.Collection = source?.ToList ()?.Cast<object> ();
 				top = 0;
-				selected = 0;
+				selected = -1;
 				lastSelectedItem = -1;
 				SetNeedsDisplay ();
 			}
@@ -207,7 +207,7 @@ namespace Terminal.Gui {
 
 				if (value < 0 || (source.Count > 0 && value >= source.Count))
 					throw new ArgumentException ("value");
-				top = value;
+				top = Math.Max (value, 0);
 				SetNeedsDisplay ();
 			}
 		}
@@ -244,7 +244,7 @@ namespace Terminal.Gui {
 				if (source == null || source.Count == 0) {
 					return;
 				}
-				if (value < 0 || value >= source.Count) {
+				if (value < -1 || value >= source.Count) {
 					throw new ArgumentException ("value");
 				}
 				selected = value;
@@ -395,17 +395,17 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// This event is raised when the selected item in the <see cref="ListView"/> has changed.
 		/// </summary>
-		public event Action<ListViewItemEventArgs> SelectedItemChanged;
+		public event EventHandler<ListViewItemEventArgs> SelectedItemChanged;
 
 		/// <summary>
 		/// This event is raised when the user Double Clicks on an item or presses ENTER to open the selected item.
 		/// </summary>
-		public event Action<ListViewItemEventArgs> OpenSelectedItem;
+		public event EventHandler<ListViewItemEventArgs> OpenSelectedItem;
 
 		/// <summary>
 		/// This event is invoked when this <see cref="ListView"/> is being drawn before rendering.
 		/// </summary>
-		public event Action<ListViewRowEventArgs> RowRender;
+		public event EventHandler<ListViewRowEventArgs> RowRender;
 
 		/// <summary>
 		/// Gets the <see cref="CollectionNavigator"/> that searches the <see cref="ListView.Source"/> collection as
@@ -485,7 +485,7 @@ namespace Terminal.Gui {
 				n = 0;
 			if (n != selected) {
 				selected = n;
-				top = selected;
+				top = Math.Max (selected, 0);
 				OnSelectedChanged ();
 				SetNeedsDisplay ();
 			}
@@ -506,7 +506,7 @@ namespace Terminal.Gui {
 			if (n != selected) {
 				selected = n;
 				if (source.Count >= Frame.Height)
-					top = selected;
+					top = Math.Max (selected, 0);
 				else
 					top = 0;
 				OnSelectedChanged ();
@@ -540,9 +540,7 @@ namespace Terminal.Gui {
 				if (selected >= top + Frame.Height) {
 					top++;
 				} else if (selected < top) {
-					top = selected;
-				} else if (selected < top) {
-					top = selected;
+					top = Math.Max (selected, 0);
 				}
 				OnSelectedChanged ();
 				SetNeedsDisplay ();
@@ -550,7 +548,7 @@ namespace Terminal.Gui {
 				OnSelectedChanged ();
 				SetNeedsDisplay ();
 			} else if (selected >= top + Frame.Height) {
-				top = source.Count - Frame.Height;
+				top = Math.Max (source.Count - Frame.Height, 0);
 				SetNeedsDisplay ();
 			}
 
@@ -581,14 +579,14 @@ namespace Terminal.Gui {
 					selected = Source.Count - 1;
 				}
 				if (selected < top) {
-					top = selected;
+					top = Math.Max (selected, 0);
 				} else if (selected > top + Frame.Height) {
 					top = Math.Max (selected - Frame.Height + 1, 0);
 				}
 				OnSelectedChanged ();
 				SetNeedsDisplay ();
 			} else if (selected < top) {
-				top = selected;
+				top = Math.Max (selected, 0);
 				SetNeedsDisplay ();
 			}
 			return true;
@@ -604,7 +602,7 @@ namespace Terminal.Gui {
 			if (source.Count > 0 && selected != source.Count - 1) {
 				selected = source.Count - 1;
 				if (top + selected > Frame.Height - 1) {
-					top = selected;
+					top = Math.Max (selected, 0);
 				}
 				OnSelectedChanged ();
 				SetNeedsDisplay ();
@@ -622,7 +620,7 @@ namespace Terminal.Gui {
 		{
 			if (selected != 0) {
 				selected = 0;
-				top = selected;
+				top = Math.Max (selected, 0);
 				OnSelectedChanged ();
 				SetNeedsDisplay ();
 			}
@@ -685,10 +683,9 @@ namespace Terminal.Gui {
 		{
 			if (selected != lastSelectedItem) {
 				var value = source?.Count > 0 ? source.ToList () [selected] : null;
-				SelectedItemChanged?.Invoke (new ListViewItemEventArgs (selected, value));
-				if (HasFocus) {
-					lastSelectedItem = selected;
-				}
+				SelectedItemChanged?.Invoke (this, new ListViewItemEventArgs (selected, value));
+				lastSelectedItem = selected;
+				EnsureSelectedItemVisible ();
 				return true;
 			}
 
@@ -707,7 +704,7 @@ namespace Terminal.Gui {
 
 			var value = source.ToList () [selected];
 
-			OpenSelectedItem?.Invoke (new ListViewItemEventArgs (selected, value));
+			OpenSelectedItem?.Invoke (this, new ListViewItemEventArgs (selected, value));
 
 			return true;
 		}
@@ -718,31 +715,22 @@ namespace Terminal.Gui {
 		/// <param name="rowEventArgs"></param>
 		public virtual void OnRowRender (ListViewRowEventArgs rowEventArgs)
 		{
-			RowRender?.Invoke (rowEventArgs);
+			RowRender?.Invoke (this, rowEventArgs);
 		}
 
 		///<inheritdoc/>
 		public override bool OnEnter (View view)
 		{
-			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-			if (lastSelectedItem == -1) {
+			if (IsInitialized) {
+				Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+			}
+			if (lastSelectedItem != selected) {
 				EnsureSelectedItemVisible ();
 			}
 
 			return base.OnEnter (view);
 		}
 
-		///<inheritdoc/>
-		public override bool OnLeave (View view)
-		{
-			if (lastSelectedItem > -1) {
-				lastSelectedItem = -1;
-			}
-
-			return base.OnLeave (view);
-		}
-
 		/// <summary>
 		/// Ensures the selected item is always visible on the screen.
 		/// </summary>
@@ -750,7 +738,7 @@ namespace Terminal.Gui {
 		{
 			SuperView?.LayoutSubviews ();
 			if (selected < top) {
-				top = selected;
+				top = Math.Max (selected, 0);
 			} else if (Frame.Height > 0 && selected >= top + Frame.Height) {
 				top = Math.Max (selected - Frame.Height + 1, 0);
 			}
@@ -938,53 +926,4 @@ namespace Terminal.Gui {
 			return -1;
 		}
 	}
-
-	/// <summary>
-	/// <see cref="EventArgs"/> for <see cref="ListView"/> events.
-	/// </summary>
-	public class ListViewItemEventArgs : EventArgs {
-		/// <summary>
-		/// The index of the <see cref="ListView"/> item.
-		/// </summary>
-		public int Item { get; }
-		/// <summary>
-		/// The <see cref="ListView"/> item.
-		/// </summary>
-		public object Value { get; }
-
-		/// <summary>
-		/// Initializes a new instance of <see cref="ListViewItemEventArgs"/>
-		/// </summary>
-		/// <param name="item">The index of the <see cref="ListView"/> item.</param>
-		/// <param name="value">The <see cref="ListView"/> item</param>
-		public ListViewItemEventArgs (int item, object value)
-		{
-			Item = item;
-			Value = value;
-		}
-	}
-
-	/// <summary>
-	/// <see cref="EventArgs"/> used by the <see cref="ListView.RowRender"/> event.
-	/// </summary>
-	public class ListViewRowEventArgs : EventArgs {
-		/// <summary>
-		/// The current row being rendered.
-		/// </summary>
-		public int Row { get; }
-		/// <summary>
-		/// The <see cref="Attribute"/> used by current row or
-		/// null to maintain the current attribute.
-		/// </summary>
-		public Attribute? RowAttribute { get; set; }
-
-		/// <summary>
-		/// Initializes with the current row.
-		/// </summary>
-		/// <param name="row"></param>
-		public ListViewRowEventArgs (int row)
-		{
-			Row = row;
-		}
-	}
 }

+ 52 - 0
Terminal.Gui/Views/ListViewEventArgs.cs

@@ -0,0 +1,52 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// <see cref="EventArgs"/> for <see cref="ListView"/> events.
+	/// </summary>
+	public class ListViewItemEventArgs : EventArgs {
+		/// <summary>
+		/// The index of the <see cref="ListView"/> item.
+		/// </summary>
+		public int Item { get; }
+		/// <summary>
+		/// The <see cref="ListView"/> item.
+		/// </summary>
+		public object Value { get; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="ListViewItemEventArgs"/>
+		/// </summary>
+		/// <param name="item">The index of the <see cref="ListView"/> item.</param>
+		/// <param name="value">The <see cref="ListView"/> item</param>
+		public ListViewItemEventArgs (int item, object value)
+		{
+			Item = item;
+			Value = value;
+		}
+	}
+
+	/// <summary>
+	/// <see cref="EventArgs"/> used by the <see cref="ListView.RowRender"/> event.
+	/// </summary>
+	public class ListViewRowEventArgs : EventArgs {
+		/// <summary>
+		/// The current row being rendered.
+		/// </summary>
+		public int Row { get; }
+		/// <summary>
+		/// The <see cref="Attribute"/> used by current row or
+		/// null to maintain the current attribute.
+		/// </summary>
+		public Attribute? RowAttribute { get; set; }
+
+		/// <summary>
+		/// Initializes with the current row.
+		/// </summary>
+		/// <param name="row"></param>
+		public ListViewRowEventArgs (int row)
+		{
+			Row = row;
+		}
+	}
+}

+ 30 - 83
Terminal.Gui/Views/Menu.cs

@@ -808,7 +808,7 @@ namespace Terminal.Gui {
 				}
 			}
 
-			host?.openMenu.SetNeedsDisplay ();
+			host?.openMenu?.SetNeedsDisplay ();
 			host.SetNeedsDisplay ();
 		}
 
@@ -1025,6 +1025,8 @@ namespace Terminal.Gui {
 			WantMousePositionReports = true;
 			IsMenuOpen = false;
 
+			Added += MenuBar_Added;
+
 			// Things this view knows how to do
 			AddCommand (Command.Left, () => { MoveLeft (); return true; });
 			AddCommand (Command.Right, () => { MoveRight (); return true; });
@@ -1040,6 +1042,14 @@ namespace Terminal.Gui {
 			AddKeyBinding (Key.Enter, Command.Accept);
 		}
 
+		bool _initialCanFocus;
+
+		private void MenuBar_Added (object sender, SuperViewChangedEventArgs e)
+		{
+			_initialCanFocus = CanFocus;
+			Added -= MenuBar_Added;
+		}
+
 		bool openedByAltKey;
 
 		bool isCleaning;
@@ -1049,9 +1059,8 @@ namespace Terminal.Gui {
 		{
 			if ((!(view is MenuBar) && !(view is Menu) || !(view is MenuBar) && !(view is Menu) && openMenu != null) && !isCleaning && !reopen) {
 				CleanUp ();
-				return true;
 			}
-			return false;
+			return base.OnLeave (view);
 		}
 
 		///<inheritdoc/>
@@ -1112,7 +1121,7 @@ namespace Terminal.Gui {
 			openedByAltKey = false;
 			IsMenuOpen = false;
 			selected = -1;
-			CanFocus = false;
+			CanFocus = _initialCanFocus;
 			if (lastFocused != null) {
 				lastFocused.SetFocus ();
 			}
@@ -1196,22 +1205,22 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Raised as a menu is opening.
 		/// </summary>
-		public event Action<MenuOpeningEventArgs> MenuOpening;
+		public event EventHandler<MenuOpeningEventArgs> MenuOpening;
 
 		/// <summary>
 		/// Raised when a menu is opened.
 		/// </summary>
-		public event Action<MenuItem> MenuOpened;
+		public event EventHandler<MenuOpenedEventArgs> MenuOpened;
 
 		/// <summary>
 		/// Raised when a menu is closing passing <see cref="MenuClosingEventArgs"/>.
 		/// </summary>
-		public event Action<MenuClosingEventArgs> MenuClosing;
+		public event EventHandler<MenuClosingEventArgs> MenuClosing;
 
 		/// <summary>
 		/// Raised when all the menu is closed.
 		/// </summary>
-		public event Action MenuAllClosed;
+		public event EventHandler MenuAllClosed;
 
 		internal Menu openMenu;
 		Menu ocm;
@@ -1244,7 +1253,7 @@ namespace Terminal.Gui {
 		public virtual MenuOpeningEventArgs OnMenuOpening (MenuBarItem currentMenu)
 		{
 			var ev = new MenuOpeningEventArgs (currentMenu);
-			MenuOpening?.Invoke (ev);
+			MenuOpening?.Invoke (this, ev);
 			return ev;
 		}
 
@@ -1254,16 +1263,20 @@ namespace Terminal.Gui {
 		public virtual void OnMenuOpened ()
 		{
 			MenuItem mi = null;
+			MenuBarItem parent;
+
 			if (openCurrentMenu.barItems.Children != null && openCurrentMenu.barItems.Children.Length > 0
 				&& openCurrentMenu?.current > -1) {
-
-				mi = openCurrentMenu.barItems.Children [openCurrentMenu.current];
+				parent = openCurrentMenu.barItems;
+				mi = parent.Children [openCurrentMenu.current];
 			} else if (openCurrentMenu.barItems.IsTopLevel) {
+				parent = null;
 				mi = openCurrentMenu.barItems;
 			} else {
-				mi = openMenu.barItems.Children [openMenu.current];
+				parent = openMenu.barItems;
+				mi = parent.Children [openMenu.current];
 			}
-			MenuOpened?.Invoke (mi);
+			MenuOpened?.Invoke (this, new MenuOpenedEventArgs (parent, mi));
 		}
 
 		/// <summary>
@@ -1275,7 +1288,7 @@ namespace Terminal.Gui {
 		public virtual MenuClosingEventArgs OnMenuClosing (MenuBarItem currentMenu, bool reopen, bool isSubMenu)
 		{
 			var ev = new MenuClosingEventArgs (currentMenu, reopen, isSubMenu);
-			MenuClosing?.Invoke (ev);
+			MenuClosing?.Invoke (this, ev);
 			return ev;
 		}
 
@@ -1284,7 +1297,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnMenuAllClosed ()
 		{
-			MenuAllClosed?.Invoke ();
+			MenuAllClosed?.Invoke (this, EventArgs.Empty);
 		}
 
 		View lastFocused;
@@ -1509,6 +1522,8 @@ namespace Terminal.Gui {
 						selected = -1;
 					}
 					LastFocused.SetFocus ();
+				} else if (openSubMenu == null || openSubMenu.Count == 0) {
+					CloseAllMenus ();
 				} else {
 					SetFocus ();
 					PositionCursor ();
@@ -2000,72 +2015,4 @@ namespace Terminal.Gui {
 			return base.OnEnter (view);
 		}
 	}
-
-	/// <summary>
-	/// An <see cref="EventArgs"/> which allows passing a cancelable menu opening event or replacing with a new <see cref="MenuBarItem"/>.
-	/// </summary>
-	public class MenuOpeningEventArgs : EventArgs {
-		/// <summary>
-		/// The current <see cref="MenuBarItem"/> parent.
-		/// </summary>
-		public MenuBarItem CurrentMenu { get; }
-
-		/// <summary>
-		/// The new <see cref="MenuBarItem"/> to be replaced.
-		/// </summary>
-		public MenuBarItem NewMenuBarItem { get; set; }
-		/// <summary>
-		/// Flag that allows the cancellation of the event. If set to <see langword="true"/> in the
-		/// event handler, the event will be canceled. 
-		/// </summary>
-		public bool Cancel { get; set; }
-
-		/// <summary>
-		/// Initializes a new instance of <see cref="MenuOpeningEventArgs"/>.
-		/// </summary>
-		/// <param name="currentMenu">The current <see cref="MenuBarItem"/> parent.</param>
-		public MenuOpeningEventArgs (MenuBarItem currentMenu)
-		{
-			CurrentMenu = currentMenu;
-		}
-	}
-
-	/// <summary>
-	/// An <see cref="EventArgs"/> which allows passing a cancelable menu closing event.
-	/// </summary>
-	public class MenuClosingEventArgs : EventArgs {
-		/// <summary>
-		/// The current <see cref="MenuBarItem"/> parent.
-		/// </summary>
-		public MenuBarItem CurrentMenu { get; }
-
-		/// <summary>
-		/// Indicates whether the current menu will reopen.
-		/// </summary>
-		public bool Reopen { get; }
-
-		/// <summary>
-		/// Indicates whether the current menu is a sub-menu.
-		/// </summary>
-		public bool IsSubMenu { get; }
-
-		/// <summary>
-		/// Flag that allows the cancellation of the event. If set to <see langword="true"/> in the
-		/// event handler, the event will be canceled. 
-		/// </summary>
-		public bool Cancel { get; set; }
-
-		/// <summary>
-		/// Initializes a new instance of <see cref="MenuClosingEventArgs"/>.
-		/// </summary>
-		/// <param name="currentMenu">The current <see cref="MenuBarItem"/> parent.</param>
-		/// <param name="reopen">Whether the current menu will reopen.</param>
-		/// <param name="isSubMenu">Indicates whether it is a sub-menu.</param>
-		public MenuClosingEventArgs (MenuBarItem currentMenu, bool reopen, bool isSubMenu)
-		{
-			CurrentMenu = currentMenu;
-			Reopen = reopen;
-			IsSubMenu = isSubMenu;
-		}
-	}
 }

+ 98 - 0
Terminal.Gui/Views/MenuEventArgs.cs

@@ -0,0 +1,98 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// An <see cref="EventArgs"/> which allows passing a cancelable menu opening event or replacing with a new <see cref="MenuBarItem"/>.
+	/// </summary>
+	public class MenuOpeningEventArgs : EventArgs {
+		/// <summary>
+		/// The current <see cref="MenuBarItem"/> parent.
+		/// </summary>
+		public MenuBarItem CurrentMenu { get; }
+
+		/// <summary>
+		/// The new <see cref="MenuBarItem"/> to be replaced.
+		/// </summary>
+		public MenuBarItem NewMenuBarItem { get; set; }
+		/// <summary>
+		/// Flag that allows the cancellation of the event. If set to <see langword="true"/> in the
+		/// event handler, the event will be canceled. 
+		/// </summary>
+		public bool Cancel { get; set; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="MenuOpeningEventArgs"/>.
+		/// </summary>
+		/// <param name="currentMenu">The current <see cref="MenuBarItem"/> parent.</param>
+		public MenuOpeningEventArgs (MenuBarItem currentMenu)
+		{
+			CurrentMenu = currentMenu;
+		}
+	}
+
+	/// <summary>
+	/// Defines arguments for the <see cref="MenuBar.MenuOpened"/> event
+	/// </summary>
+	public class MenuOpenedEventArgs : EventArgs {
+		/// <summary>
+		/// Creates a new instance of the <see cref="MenuOpenedEventArgs"/> class
+		/// </summary>
+		/// <param name="parent"></param>
+		/// <param name="menuItem"></param>
+		public MenuOpenedEventArgs (MenuBarItem parent, MenuItem menuItem)
+		{
+			Parent = parent;
+			MenuItem = menuItem;
+		}
+
+		/// <summary>
+		/// The parent of <see cref="MenuItem"/>.  Will be null if menu opening
+		/// is the root (see <see cref="MenuBarItem.IsTopLevel"/>).
+		/// </summary>
+		public MenuBarItem Parent { get; }
+
+		/// <summary>
+		/// Gets the <see cref="MenuItem"/> being opened.
+		/// </summary>
+		public MenuItem MenuItem { get; }
+	}
+
+	/// <summary>
+	/// An <see cref="EventArgs"/> which allows passing a cancelable menu closing event.
+	/// </summary>
+	public class MenuClosingEventArgs : EventArgs {
+		/// <summary>
+		/// The current <see cref="MenuBarItem"/> parent.
+		/// </summary>
+		public MenuBarItem CurrentMenu { get; }
+
+		/// <summary>
+		/// Indicates whether the current menu will reopen.
+		/// </summary>
+		public bool Reopen { get; }
+
+		/// <summary>
+		/// Indicates whether the current menu is a sub-menu.
+		/// </summary>
+		public bool IsSubMenu { get; }
+
+		/// <summary>
+		/// Flag that allows the cancellation of the event. If set to <see langword="true"/> in the
+		/// event handler, the event will be canceled. 
+		/// </summary>
+		public bool Cancel { get; set; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="MenuClosingEventArgs"/>.
+		/// </summary>
+		/// <param name="currentMenu">The current <see cref="MenuBarItem"/> parent.</param>
+		/// <param name="reopen">Whether the current menu will reopen.</param>
+		/// <param name="isSubMenu">Indicates whether it is a sub-menu.</param>
+		public MenuClosingEventArgs (MenuBarItem currentMenu, bool reopen, bool isSubMenu)
+		{
+			CurrentMenu = currentMenu;
+			Reopen = reopen;
+			IsSubMenu = isSubMenu;
+		}
+	}
+}

+ 1 - 1
Terminal.Gui/Views/PanelView.cs

@@ -128,7 +128,7 @@ namespace Terminal.Gui {
 			Child.Initialized -= Child_Initialized;
 		}
 
-		private void Border_BorderChanged (Border obj)
+		private void Border_BorderChanged (object sender, EventArgs e)
 		{
 			AdjustContainer ();
 		}

+ 2 - 28
Terminal.Gui/Views/RadioGroup.cs

@@ -265,7 +265,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Invoked when the selected radio label has changed.
 		/// </summary>
-		public event Action<SelectedItemChangedArgs> SelectedItemChanged;
+		public event EventHandler<SelectedItemChangedArgs> SelectedItemChanged;
 
 		/// <summary>
 		/// The currently selected item from the list of radio labels
@@ -296,7 +296,7 @@ namespace Terminal.Gui {
 		public virtual void OnSelectedItemChanged (int selectedItem, int previousSelectedItem)
 		{
 			selected = selectedItem;
-			SelectedItemChanged?.Invoke (new SelectedItemChangedArgs (selectedItem, previousSelectedItem));
+			SelectedItemChanged?.Invoke (this, new SelectedItemChangedArgs (selectedItem, previousSelectedItem));
 		}
 
 		///<inheritdoc/>
@@ -422,30 +422,4 @@ namespace Terminal.Gui {
 		/// </summary>
 		Horizontal
 	}
-
-	/// <summary>
-	/// Event arguments for the SelectedItemChagned event.
-	/// </summary>
-	public class SelectedItemChangedArgs : EventArgs {
-		/// <summary>
-		/// Gets the index of the item that was previously selected. -1 if there was no previous selection.
-		/// </summary>
-		public int PreviousSelectedItem { get; }
-
-		/// <summary>
-		/// Gets the index of the item that is now selected. -1 if there is no selection.
-		/// </summary>
-		public int SelectedItem { get; }
-
-		/// <summary>
-		/// Initializes a new <see cref="SelectedItemChangedArgs"/> class.
-		/// </summary>
-		/// <param name="selectedItem"></param>
-		/// <param name="previousSelectedItem"></param>
-		public SelectedItemChangedArgs (int selectedItem, int previousSelectedItem)
-		{
-			PreviousSelectedItem = previousSelectedItem;
-			SelectedItem = selectedItem;
-		}
-	}
 }

+ 5 - 5
Terminal.Gui/Views/ScrollBarView.cs

@@ -119,7 +119,7 @@ namespace Terminal.Gui {
 			ClearOnVisibleFalse = false;
 		}
 
-		private void Host_VisibleChanged ()
+		private void Host_VisibleChanged (object sender, EventArgs e)
 		{
 			if (!Host.Visible) {
 				Visible = Host.Visible;
@@ -132,7 +132,7 @@ namespace Terminal.Gui {
 			}
 		}
 
-		private void Host_EnabledChanged ()
+		private void Host_EnabledChanged (object sender, EventArgs e)
 		{
 			Enabled = Host.Enabled;
 			if (otherScrollBarView != null) {
@@ -149,7 +149,7 @@ namespace Terminal.Gui {
 		//	}
 		//}
 
-		void ContentBottomRightCorner_MouseClick (MouseEventArgs me)
+		void ContentBottomRightCorner_MouseClick (object sender, MouseEventEventArgs me)
 		{
 			if (me.MouseEvent.Flags == MouseFlags.WheeledDown || me.MouseEvent.Flags == MouseFlags.WheeledUp
 				|| me.MouseEvent.Flags == MouseFlags.WheeledRight || me.MouseEvent.Flags == MouseFlags.WheeledLeft) {
@@ -199,7 +199,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// This event is raised when the position on the scrollbar has changed.
 		/// </summary>
-		public event Action ChangedPosition;
+		public event EventHandler ChangedPosition;
 
 		/// <summary>
 		/// The position, relative to <see cref="Size"/>, to set the scrollbar at.
@@ -312,7 +312,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public virtual void OnChangedPosition ()
 		{
-			ChangedPosition?.Invoke ();
+			ChangedPosition?.Invoke (this, EventArgs.Empty);
 		}
 
 		/// <summary>

+ 5 - 5
Terminal.Gui/Views/ScrollView.cs

@@ -45,7 +45,7 @@ namespace Terminal.Gui {
 		/// <param name="frame"></param>
 		public ScrollView (Rect frame) : base (frame)
 		{
-			Initialize (frame);
+			SetInitialProperties (frame);
 		}
 
 
@@ -54,10 +54,10 @@ namespace Terminal.Gui {
 		/// </summary>
 		public ScrollView () : base ()
 		{
-			Initialize (Rect.Empty);
+			SetInitialProperties (Rect.Empty);
 		}
 
-		void Initialize (Rect frame)
+		void SetInitialProperties (Rect frame)
 		{
 			contentView = new ContentView (frame);
 			vertical = new ScrollBarView (1, 0, isVertical: true) {
@@ -237,14 +237,14 @@ namespace Terminal.Gui {
 			SetNeedsLayout ();
 		}
 
-		void View_MouseLeave (MouseEventArgs e)
+		void View_MouseLeave (object sender, MouseEventEventArgs e)
 		{
 			if (Application.MouseGrabView != null && Application.MouseGrabView != vertical && Application.MouseGrabView != horizontal) {
 				Application.UngrabMouse ();
 			}
 		}
 
-		void View_MouseEnter (MouseEventArgs e)
+		void View_MouseEnter (object sender, MouseEventEventArgs e)
 		{
 			Application.GrabMouse (this);
 		}

+ 63 - 0
Terminal.Gui/Views/SelectedCellChangedEventArgs.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Data;
+
+namespace Terminal.Gui {
+
+
+	/// <summary>
+	/// Defines the event arguments for <see cref="TableView.SelectedCellChanged"/> 
+	/// </summary>
+	public class SelectedCellChangedEventArgs : EventArgs {
+		/// <summary>
+		/// The current table to which the new indexes refer.  May be null e.g. if selection change is the result of clearing the table from the view
+		/// </summary>
+		/// <value></value>
+		public DataTable Table { get; }
+
+
+		/// <summary>
+		/// The previous selected column index.  May be invalid e.g. when the selection has been changed as a result of replacing the existing Table with a smaller one
+		/// </summary>
+		/// <value></value>
+		public int OldCol { get; }
+
+
+		/// <summary>
+		/// The newly selected column index.
+		/// </summary>
+		/// <value></value>
+		public int NewCol { get; }
+
+
+		/// <summary>
+		/// The previous selected row index.  May be invalid e.g. when the selection has been changed as a result of deleting rows from the table
+		/// </summary>
+		/// <value></value>
+		public int OldRow { get; }
+
+
+		/// <summary>
+		/// The newly selected row index.
+		/// </summary>
+		/// <value></value>
+		public int NewRow { get; }
+
+		/// <summary>
+		/// Creates a new instance of arguments describing a change in selected cell in a <see cref="TableView"/>
+		/// </summary>
+		/// <param name="t"></param>
+		/// <param name="oldCol"></param>
+		/// <param name="newCol"></param>
+		/// <param name="oldRow"></param>
+		/// <param name="newRow"></param>
+		public SelectedCellChangedEventArgs (DataTable t, int oldCol, int newCol, int oldRow, int newRow)
+		{
+			Table = t;
+			OldCol = oldCol;
+			NewCol = newCol;
+			OldRow = oldRow;
+			NewRow = newRow;
+		}
+	}
+
+}

+ 29 - 0
Terminal.Gui/Views/SelectedItemChangedArgs.cs

@@ -0,0 +1,29 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Event arguments for the SelectedItemChagned event.
+	/// </summary>
+	public class SelectedItemChangedArgs : EventArgs {
+		/// <summary>
+		/// Gets the index of the item that was previously selected. -1 if there was no previous selection.
+		/// </summary>
+		public int PreviousSelectedItem { get; }
+
+		/// <summary>
+		/// Gets the index of the item that is now selected. -1 if there is no selection.
+		/// </summary>
+		public int SelectedItem { get; }
+
+		/// <summary>
+		/// Initializes a new <see cref="SelectedItemChangedArgs"/> class.
+		/// </summary>
+		/// <param name="selectedItem"></param>
+		/// <param name="previousSelectedItem"></param>
+		public SelectedItemChangedArgs (int selectedItem, int previousSelectedItem)
+		{
+			PreviousSelectedItem = previousSelectedItem;
+			SelectedItem = selectedItem;
+		}
+	}
+}

+ 38 - 0
Terminal.Gui/Views/SplitterEventArgs.cs

@@ -0,0 +1,38 @@
+using System;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Provides data for <see cref="TileView"/> events.
+	/// </summary>
+	public class SplitterEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="SplitterEventArgs"/> class.
+		/// </summary>
+		/// <param name="tileView"><see cref="TileView"/> in which splitter is being moved.</param>
+		/// <param name="idx">Index of the splitter being moved in <see cref="TileView.SplitterDistances"/>.</param>
+		/// <param name="splitterDistance">The new <see cref="Pos"/> of the splitter line.</param>
+		public SplitterEventArgs (TileView tileView, int idx, Pos splitterDistance)
+		{
+			SplitterDistance = splitterDistance;
+			TileView = tileView;
+			Idx = idx;
+		}
+
+		/// <summary>
+		/// New position of the splitter line (see <see cref="TileView.SplitterDistances"/>).
+		/// </summary>
+		public Pos SplitterDistance { get; }
+
+		/// <summary>
+		/// Container (sender) of the event.
+		/// </summary>
+		public TileView TileView { get; }
+
+		/// <summary>
+		/// Gets the index of the splitter that is being moved. This can be
+		/// used to index <see cref="TileView.SplitterDistances"/>
+		/// </summary>
+		public int Idx { get; }
+	}
+}

+ 31 - 0
Terminal.Gui/Views/TabChangedEventArgs.cs

@@ -0,0 +1,31 @@
+using System;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Describes a change in <see cref="TabView.SelectedTab"/>
+	/// </summary>
+	public class TabChangedEventArgs : EventArgs {
+
+		/// <summary>
+		/// The previously selected tab. May be null
+		/// </summary>
+		public TabView.Tab OldTab { get; }
+
+		/// <summary>
+		/// The currently selected tab. May be null
+		/// </summary>
+		public TabView.Tab NewTab { get; }
+
+		/// <summary>
+		/// Documents a tab change
+		/// </summary>
+		/// <param name="oldTab"></param>
+		/// <param name="newTab"></param>
+		public TabChangedEventArgs (TabView.Tab oldTab, TabView.Tab newTab)
+		{
+			OldTab = oldTab;
+			NewTab = newTab;
+		}
+	}
+}

+ 35 - 0
Terminal.Gui/Views/TabMouseEventArgs.cs

@@ -0,0 +1,35 @@
+using System;
+
+namespace Terminal.Gui {
+
+	/// <summary>
+	/// Describes a mouse event over a specific <see cref="TabView.Tab"/> in a <see cref="TabView"/>.
+	/// </summary>
+	public class TabMouseEventArgs : EventArgs {
+
+		/// <summary>
+		/// Gets the <see cref="TabView.Tab"/> (if any) that the mouse
+		/// was over when the <see cref="MouseEvent"/> occurred.
+		/// </summary>
+		/// <remarks>This will be null if the click is after last tab
+		/// or before first.</remarks>
+		public TabView.Tab Tab { get; }
+
+		/// <summary>
+		/// Gets the actual mouse event.  Use <see cref="MouseEvent.Handled"/> to cancel this event
+		/// and perform custom behavior (e.g. show a context menu).
+		/// </summary>
+		public MouseEvent MouseEvent { get; }
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="TabMouseEventArgs"/> class.
+		/// </summary>
+		/// <param name="tab"><see cref="TabView.Tab"/> that the mouse was over when the event occurred.</param>
+		/// <param name="mouseEvent">The mouse activity being reported</param>
+		public TabMouseEventArgs (TabView.Tab tab, MouseEvent mouseEvent)
+		{
+			Tab = tab;
+			MouseEvent = mouseEvent;
+		}
+	}
+}

+ 1 - 59
Terminal.Gui/Views/TabView.cs

@@ -9,7 +9,7 @@ namespace Terminal.Gui {
 	/// <summary>
 	/// Control that hosts multiple sub views, presenting a single one at once
 	/// </summary>
-	public class TabView : View {
+	public partial class TabView : View {
 		private Tab selectedTab;
 
 		/// <summary>
@@ -771,37 +771,6 @@ namespace Terminal.Gui {
 			TabClicked?.Invoke (this, tabMouseEventArgs);
 		}
 
-		/// <summary>
-		/// Describes a mouse event over a specific <see cref="TabView.Tab"/> in a <see cref="TabView"/>.
-		/// </summary>
-		public class TabMouseEventArgs : EventArgs {
-
-			/// <summary>
-			/// Gets the <see cref="TabView.Tab"/> (if any) that the mouse
-			/// was over when the <see cref="MouseEvent"/> occurred.
-			/// </summary>
-			/// <remarks>This will be null if the click is after last tab
-			/// or before first.</remarks>
-			public Tab Tab { get; }
-
-			/// <summary>
-			/// Gets the actual mouse event.  Use <see cref="MouseEvent.Handled"/> to cancel this event
-			/// and perform custom behavior (e.g. show a context menu).
-			/// </summary>
-			public MouseEvent MouseEvent { get; }
-
-			/// <summary>
-			/// Creates a new instance of the <see cref="TabMouseEventArgs"/> class.
-			/// </summary>
-			/// <param name="tab"><see cref="TabView.Tab"/> that the mouse was over when the event occurred.</param>
-			/// <param name="mouseEvent">The mouse activity being reported</param>
-			public TabMouseEventArgs (Tab tab, MouseEvent mouseEvent)
-			{
-				Tab = tab;
-				MouseEvent = mouseEvent;
-			}
-		}
-
 		/// <summary>
 		/// A single tab in a <see cref="TabView"/>
 		/// </summary>
@@ -867,33 +836,6 @@ namespace Terminal.Gui {
 			public bool TabsOnBottom { get; set; } = false;
 
 		}
-
-		/// <summary>
-		/// Describes a change in <see cref="TabView.SelectedTab"/>
-		/// </summary>
-		public class TabChangedEventArgs : EventArgs {
-
-			/// <summary>
-			/// The previously selected tab. May be null
-			/// </summary>
-			public Tab OldTab { get; }
-
-			/// <summary>
-			/// The currently selected tab. May be null
-			/// </summary>
-			public Tab NewTab { get; }
-
-			/// <summary>
-			/// Documents a tab change
-			/// </summary>
-			/// <param name="oldTab"></param>
-			/// <param name="newTab"></param>
-			public TabChangedEventArgs (Tab oldTab, Tab newTab)
-			{
-				OldTab = oldTab;
-				NewTab = newTab;
-			}
-		}
 		#endregion
 	}
 }

+ 5 - 98
Terminal.Gui/Views/TableView.cs

@@ -13,44 +13,7 @@ namespace Terminal.Gui {
 	/// 
 	/// <a href="https://gui-cs.github.io/Terminal.Gui/articles/tableview.html">See TableView Deep Dive for more information</a>.
 	/// </summary>
-	public class TableView : View {
-
-		/// <summary>
-		///  Defines the event arguments for <see cref="TableView.CellActivated"/> event
-		/// </summary>
-		public class CellActivatedEventArgs : EventArgs {
-			/// <summary>
-			/// The current table to which the new indexes refer.  May be null e.g. if selection change is the result of clearing the table from the view
-			/// </summary>
-			/// <value></value>
-			public DataTable Table { get; }
-
-
-			/// <summary>
-			/// The column index of the <see cref="Table"/> cell that is being activated
-			/// </summary>
-			/// <value></value>
-			public int Col { get; }
-
-			/// <summary>
-			/// The row index of the <see cref="Table"/> cell that is being activated
-			/// </summary>
-			/// <value></value>
-			public int Row { get; }
-
-			/// <summary>
-			/// Creates a new instance of arguments describing a cell being activated in <see cref="TableView"/>
-			/// </summary>
-			/// <param name="t"></param>
-			/// <param name="col"></param>
-			/// <param name="row"></param>
-			public CellActivatedEventArgs (DataTable t, int col, int row)
-			{
-				Table = t;
-				Col = col;
-				Row = row;
-			}
-		}
+	public partial class TableView : View {
 
 		private int columnOffset;
 		private int rowOffset;
@@ -171,12 +134,12 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// This event is raised when the selected cell in the table changes.
 		/// </summary>
-		public event Action<SelectedCellChangedEventArgs> SelectedCellChanged;
+		public event EventHandler<SelectedCellChangedEventArgs> SelectedCellChanged;
 
 		/// <summary>
 		/// This event is raised when a cell is activated e.g. by double clicking or pressing <see cref="CellActivationKey"/>
 		/// </summary>
-		public event Action<CellActivatedEventArgs> CellActivated;
+		public event EventHandler<CellActivatedEventArgs> CellActivated;
 
 		/// <summary>
 		/// The key which when pressed should trigger <see cref="CellActivated"/> event.  Defaults to Enter.
@@ -1510,7 +1473,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		protected virtual void OnSelectedCellChanged (SelectedCellChangedEventArgs args)
 		{
-			SelectedCellChanged?.Invoke (args);
+			SelectedCellChanged?.Invoke (this,args);
 		}
 
 		/// <summary>
@@ -1519,7 +1482,7 @@ namespace Terminal.Gui {
 		/// <param name="args"></param>
 		protected virtual void OnCellActivated (CellActivatedEventArgs args)
 		{
-			CellActivated?.Invoke (args);
+			CellActivated?.Invoke (this, args);
 		}
 
 		/// <summary>
@@ -2001,62 +1964,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-		/// <summary>
-		/// Defines the event arguments for <see cref="TableView.SelectedCellChanged"/> 
-		/// </summary>
-		public class SelectedCellChangedEventArgs : EventArgs {
-			/// <summary>
-			/// The current table to which the new indexes refer.  May be null e.g. if selection change is the result of clearing the table from the view
-			/// </summary>
-			/// <value></value>
-			public DataTable Table { get; }
-
-
-			/// <summary>
-			/// The previous selected column index.  May be invalid e.g. when the selection has been changed as a result of replacing the existing Table with a smaller one
-			/// </summary>
-			/// <value></value>
-			public int OldCol { get; }
-
-
-			/// <summary>
-			/// The newly selected column index.
-			/// </summary>
-			/// <value></value>
-			public int NewCol { get; }
-
-
-			/// <summary>
-			/// The previous selected row index.  May be invalid e.g. when the selection has been changed as a result of deleting rows from the table
-			/// </summary>
-			/// <value></value>
-			public int OldRow { get; }
-
-
-			/// <summary>
-			/// The newly selected row index.
-			/// </summary>
-			/// <value></value>
-			public int NewRow { get; }
-
-			/// <summary>
-			/// Creates a new instance of arguments describing a change in selected cell in a <see cref="TableView"/>
-			/// </summary>
-			/// <param name="t"></param>
-			/// <param name="oldCol"></param>
-			/// <param name="newCol"></param>
-			/// <param name="oldRow"></param>
-			/// <param name="newRow"></param>
-			public SelectedCellChangedEventArgs (DataTable t, int oldCol, int newCol, int oldRow, int newRow)
-			{
-				Table = t;
-				OldCol = oldCol;
-				NewCol = newCol;
-				OldRow = oldRow;
-				NewRow = newRow;
-			}
-		}
-
 		/// <summary>
 		/// Describes a selected region of the table
 		/// </summary>

+ 31 - 0
Terminal.Gui/Views/TextChangedEventArgs.cs

@@ -0,0 +1,31 @@
+//
+// TextField.cs: single-line text editor with Emacs keybindings
+//
+// Authors:
+//   Miguel de Icaza ([email protected])
+//
+
+using System;
+using NStack;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Event args for the <see cref="TextField.TextChanged"/> event
+	/// </summary>
+	public class TextChangedEventArgs : EventArgs {
+
+		/// <summary>
+		/// Creates a new instance of the <see cref="TextChangedEventArgs"/> class
+		/// </summary>
+		/// <param name="oldValue"></param>
+		public TextChangedEventArgs (ustring oldValue)
+		{
+			OldValue = oldValue;
+		}
+
+		/// <summary>
+		/// The old value before the text changed
+		/// </summary>
+		public ustring OldValue { get; }
+	}
+}

+ 34 - 0
Terminal.Gui/Views/TextChangingEventArgs.cs

@@ -0,0 +1,34 @@
+//
+// TextField.cs: single-line text editor with Emacs keybindings
+//
+// Authors:
+//   Miguel de Icaza ([email protected])
+//
+
+using System;
+using NStack;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// An <see cref="EventArgs"/> which allows passing a cancelable new text value event.
+	/// </summary>
+	public class TextChangingEventArgs : EventArgs {
+		/// <summary>
+		/// The new text to be replaced.
+		/// </summary>
+		public ustring NewText { get; set; }
+		/// <summary>
+		/// Flag which allows to cancel the new text value.
+		/// </summary>
+		public bool Cancel { get; set; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="TextChangingEventArgs"/>
+		/// </summary>
+		/// <param name="newText">The new <see cref="TextField.Text"/> to be replaced.</param>
+		public TextChangingEventArgs (ustring newText)
+		{
+			NewText = newText;
+		}
+	}
+}

+ 17 - 39
Terminal.Gui/Views/TextField.cs

@@ -55,7 +55,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Changing event, raised before the <see cref="Text"/> changes and can be canceled or changing the new text.
 		/// </summary>
-		public event Action<TextChangingEventArgs> TextChanging;
+		public event EventHandler<TextChangingEventArgs> TextChanging;
 
 		/// <summary>
 		///   Changed event, raised when the text has changed.
@@ -66,7 +66,7 @@ namespace Terminal.Gui {
 		/// <remarks>
 		///   The passed <see cref="EventArgs"/> is a <see cref="NStack.ustring"/> containing the old value. 
 		/// </remarks>
-		public event Action<ustring> TextChanged;
+		public event EventHandler<TextChangedEventArgs> TextChanged;
 
 		/// <summary>
 		/// Initializes a new instance of the <see cref="TextField"/> class using <see cref="LayoutStyle.Computed"/> positioning.
@@ -241,12 +241,12 @@ namespace Terminal.Gui {
 				});
 		}
 
-		private void ContextMenu_KeyChanged (Key obj)
+		private void ContextMenu_KeyChanged (object sender, KeyChangedEventArgs e)
 		{
-			ReplaceKeyBinding (obj, ContextMenu.Key);
+			ReplaceKeyBinding (e.OldKey, e.NewKey);
 		}
 
-		private void HistoryText_ChangeText (HistoryText.HistoryTextItem obj)
+		private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
 		{
 			if (obj == null)
 				return;
@@ -262,6 +262,16 @@ namespace Terminal.Gui {
 			Autocomplete.PopupInsideContainer = false;
 		}
 
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			if (IsInitialized) {
+				Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
+			}
+
+			return base.OnEnter (view);
+		}
+
 		///<inheritdoc/>
 		public override bool OnLeave (View view)
 		{
@@ -321,7 +331,7 @@ namespace Terminal.Gui {
 						, HistoryText.LineStatus.Replaced);
 				}
 
-				TextChanged?.Invoke (oldText);
+				TextChanged?.Invoke (this, new TextChangedEventArgs (oldText));
 
 				if (point > text.Count) {
 					point = Math.Max (TextModel.DisplaySize (text, 0).size - 1, 0);
@@ -1285,7 +1295,7 @@ namespace Terminal.Gui {
 		public virtual TextChangingEventArgs OnTextChanging (ustring newText)
 		{
 			var ev = new TextChangingEventArgs (newText);
-			TextChanging?.Invoke (ev);
+			TextChanging?.Invoke (this, ev);
 			return ev;
 		}
 
@@ -1305,14 +1315,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-		///<inheritdoc/>
-		public override bool OnEnter (View view)
-		{
-			Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-
-			return base.OnEnter (view);
-		}
-
 		/// <summary>
 		/// Inserts the given <paramref name="toAdd"/> text at the current cursor position
 		/// exactly as if the user had just typed it
@@ -1344,30 +1346,6 @@ namespace Terminal.Gui {
 			historyText.Clear (Text);
 		}
 	}
-
-	/// <summary>
-	/// An <see cref="EventArgs"/> which allows passing a cancelable new text value event.
-	/// </summary>
-	public class TextChangingEventArgs : EventArgs {
-		/// <summary>
-		/// The new text to be replaced.
-		/// </summary>
-		public ustring NewText { get; set; }
-		/// <summary>
-		/// Flag which allows to cancel the new text value.
-		/// </summary>
-		public bool Cancel { get; set; }
-
-		/// <summary>
-		/// Initializes a new instance of <see cref="TextChangingEventArgs"/>
-		/// </summary>
-		/// <param name="newText">The new <see cref="TextField.Text"/> to be replaced.</param>
-		public TextChangingEventArgs (ustring newText)
-		{
-			NewText = newText;
-		}
-	}
-
 	/// <summary>
 	/// Renders an overlay on another view at a given point that allows selecting
 	/// from a range of 'autocomplete' options.

+ 21 - 76
Terminal.Gui/Views/TextView.cs

@@ -16,7 +16,7 @@ namespace Terminal.Gui {
 	class TextModel {
 		List<List<Rune>> lines = new List<List<Rune>> ();
 
-		public event Action LinesLoaded;
+		public event EventHandler LinesLoaded;
 
 		public bool LoadFile (string file)
 		{
@@ -120,7 +120,7 @@ namespace Terminal.Gui {
 
 		void OnLinesLoaded ()
 		{
-			LinesLoaded?.Invoke ();
+			LinesLoaded?.Invoke (this, EventArgs.Empty);
 		}
 
 		public override string ToString ()
@@ -387,7 +387,7 @@ namespace Terminal.Gui {
 						pos = new Point (col, i);
 						col += (textToReplace.Length - matchText.Length);
 					}
-					if (col + 1 > txt.Length) {
+					if (col < 0 || col + 1 > txt.Length) {
 						break;
 					}
 					col = txt.IndexOf (matchText, col + 1);
@@ -515,7 +515,7 @@ namespace Terminal.Gui {
 		}
 	}
 
-	class HistoryText {
+	partial class HistoryText {
 		public enum LineStatus {
 			Original,
 			Replaced,
@@ -523,34 +523,6 @@ namespace Terminal.Gui {
 			Added
 		}
 
-		public class HistoryTextItem {
-			public List<List<Rune>> Lines;
-			public Point CursorPosition;
-			public LineStatus LineStatus;
-			public bool IsUndoing;
-			public Point FinalCursorPosition;
-			public HistoryTextItem RemovedOnAdded;
-
-			public HistoryTextItem (List<List<Rune>> lines, Point curPos, LineStatus linesStatus)
-			{
-				Lines = lines;
-				CursorPosition = curPos;
-				LineStatus = linesStatus;
-			}
-
-			public HistoryTextItem (HistoryTextItem historyTextItem)
-			{
-				Lines = new List<List<Rune>> (historyTextItem.Lines);
-				CursorPosition = new Point (historyTextItem.CursorPosition.X, historyTextItem.CursorPosition.Y);
-				LineStatus = historyTextItem.LineStatus;
-			}
-
-			public override string ToString ()
-			{
-				return $"(Count: {Lines.Count}, Cursor: {CursorPosition}, Status: {LineStatus})";
-			}
-		}
-
 		List<HistoryTextItem> historyTextItems = new List<HistoryTextItem> ();
 		int idxHistoryText = -1;
 		ustring originalText;
@@ -559,7 +531,7 @@ namespace Terminal.Gui {
 
 		public bool HasHistoryChanges => idxHistoryText > -1;
 
-		public event Action<HistoryTextItem> ChangeText;
+		public event EventHandler<HistoryTextItem> ChangeText;
 
 		public void Add (List<List<Rune>> lines, Point curPos, LineStatus lineStatus = LineStatus.Original)
 		{
@@ -711,7 +683,7 @@ namespace Terminal.Gui {
 
 		void OnChangeText (HistoryTextItem lines)
 		{
-			ChangeText?.Invoke (lines);
+			ChangeText?.Invoke (this, lines);
 		}
 
 		public void Clear (ustring text)
@@ -1129,7 +1101,7 @@ namespace Terminal.Gui {
 	///   </item>
 	///  </list>
 	/// </remarks>
-	public class TextView : View {
+	public partial class TextView : View {
 		TextModel model = new TextModel ();
 		int topRow;
 		int leftColumn;
@@ -1156,7 +1128,7 @@ namespace Terminal.Gui {
 		/// set, not as the user types. To be notified as the user changes the contents of the TextView
 		/// see <see cref="IsDirty"/>.
 		/// </remarks>
-		public event Action TextChanged;
+		public event EventHandler TextChanged;
 
 		/// <summary>
 		///  Raised when the contents of the <see cref="TextView"/> are changed. 
@@ -1165,12 +1137,12 @@ namespace Terminal.Gui {
 		/// Unlike the <see cref="TextChanged"/> event, this event is raised whenever the user types or
 		/// otherwise changes the contents of the <see cref="TextView"/>.
 		/// </remarks>
-		public event Action<ContentsChangedEventArgs> ContentsChanged;
+		public event EventHandler<ContentsChangedEventArgs> ContentsChanged;
 
 		/// <summary>
 		/// Invoked with the unwrapped <see cref="CursorPosition"/>.
 		/// </summary>
-		public event Action<Point> UnwrappedCursorPosition;
+		public event EventHandler<PointEventArgs> UnwrappedCursorPosition;
 
 		/// <summary>
 		/// Provides autocomplete context menu based on suggestions at the current cursor
@@ -1378,12 +1350,12 @@ namespace Terminal.Gui {
 				});
 		}
 
-		private void ContextMenu_KeyChanged (Key obj)
+		private void ContextMenu_KeyChanged (object sender, KeyChangedEventArgs e)
 		{
-			ReplaceKeyBinding (obj, ContextMenu.Key);
+			ReplaceKeyBinding (e.OldKey, e.NewKey);
 		}
 
-		private void Model_LinesLoaded ()
+		private void Model_LinesLoaded (object sender, EventArgs e)
 		{
 			// This call is not needed. Model_LinesLoaded gets invoked when
 			// model.LoadString (value) is called. LoadString is called from one place
@@ -1393,7 +1365,7 @@ namespace Terminal.Gui {
 			//historyText.Clear (Text);
 		}
 
-		private void HistoryText_ChangeText (HistoryText.HistoryTextItem obj)
+		private void HistoryText_ChangeText (object sender, HistoryText.HistoryTextItem obj)
 		{
 			SetWrapModel ();
 
@@ -1446,14 +1418,14 @@ namespace Terminal.Gui {
 			OnContentsChanged ();
 		}
 
-		void Top_AlternateBackwardKeyChanged (Key obj)
+		void Top_AlternateBackwardKeyChanged (object sender, KeyChangedEventArgs e)
 		{
-			ReplaceKeyBinding (obj, Application.AlternateBackwardKey);
+			ReplaceKeyBinding (e.OldKey, e.NewKey);
 		}
 
-		void Top_AlternateForwardKeyChanged (Key obj)
+		void Top_AlternateForwardKeyChanged (object sender, KeyChangedEventArgs e)
 		{
-			ReplaceKeyBinding (obj, Application.AlternateForwardKey);
+			ReplaceKeyBinding (e.OldKey, e.NewKey);
 		}
 
 		/// <summary>
@@ -1492,7 +1464,7 @@ namespace Terminal.Gui {
 					wrapManager = new WordWrapManager (model);
 					model = wrapManager.WrapModel (frameWidth, out _, out _, out _, out _);
 				}
-				TextChanged?.Invoke ();
+				TextChanged?.Invoke (this, EventArgs.Empty);
 				SetNeedsDisplay ();
 
 				historyText.Clear (Text);
@@ -2364,7 +2336,7 @@ namespace Terminal.Gui {
 				row = wrapManager.GetModelLineFromWrappedLines (currentRow);
 				col = wrapManager.GetModelColFromWrappedLines (currentRow, currentColumn);
 			}
-			UnwrappedCursorPosition?.Invoke (new Point ((int)col, (int)row));
+			UnwrappedCursorPosition?.Invoke (this, new PointEventArgs (new Point ((int)col, (int)row)));
 		}
 
 		ustring GetSelectedRegion ()
@@ -2709,40 +2681,13 @@ namespace Terminal.Gui {
 			OnUnwrappedCursorPosition ();
 		}
 
-		/// <summary>
-		/// Event arguments for events for when the contents of the TextView change. E.g. the <see cref="ContentsChanged"/> event.
-		/// </summary>
-		public class ContentsChangedEventArgs : EventArgs {
-			/// <summary>
-			/// Creates a new <see cref="ContentsChanged"/> instance.
-			/// </summary>
-			/// <param name="currentRow">Contains the row where the change occurred.</param>
-			/// <param name="currentColumn">Contains the column where the change occured.</param>
-			public ContentsChangedEventArgs (int currentRow, int currentColumn)
-			{
-				Row = currentRow;
-				Col = currentColumn;
-			}
-
-			/// <summary>
-			/// 
-			/// Contains the row where the change occurred.
-			/// </summary>
-			public int Row { get; private set; }
-
-			/// <summary>
-			/// Contains the column where the change occurred.
-			/// </summary>
-			public int Col { get; private set; }
-		}
-
 		/// <summary>
 		/// Called when the contents of the TextView change. E.g. when the user types text or deletes text. Raises
 		/// the <see cref="ContentsChanged"/> event.
 		/// </summary>
 		public virtual void OnContentsChanged ()
 		{
-			ContentsChanged?.Invoke (new ContentsChangedEventArgs (CurrentRow, CurrentColumn));
+			ContentsChanged?.Invoke (this, new ContentsChangedEventArgs (CurrentRow, CurrentColumn));
 		}
 
 		(int width, int height) OffSetBackground ()

+ 7 - 73
Terminal.Gui/Views/TileView.cs

@@ -10,7 +10,7 @@ namespace Terminal.Gui {
 	/// A <see cref="View"/> consisting of a moveable bar that divides
 	/// the display area into resizeable <see cref="Tiles"/>.
 	/// </summary>
-	public class TileView : View {
+	public partial class TileView : View {
 		TileView parentTileView;
 
 		/// <summary>
@@ -24,7 +24,7 @@ namespace Terminal.Gui {
 		/// new instances use <see cref="TileView.RebuildForTileCount(int)"/> 
 		/// or <see cref="TileView.InsertTile(int)"/>.
 		/// </summary>
-		public class Tile {
+		public partial class Tile {
 			/// <summary>
 			/// The <see cref="ContentView"/> that is contained in this <see cref="TileView"/>.
 			/// Add new child views to this member for multiple 
@@ -61,37 +61,6 @@ namespace Terminal.Gui {
 
 			private string _title = string.Empty;
 
-			/// <summary>
-			/// An <see cref="EventArgs"/> which allows passing a cancelable new <see cref="Title"/> value event.
-			/// </summary>
-			public class TitleEventArgs : EventArgs {
-				/// <summary>
-				/// The new Window Title.
-				/// </summary>
-				public ustring NewTitle { get; set; }
-
-				/// <summary>
-				/// The old Window Title.
-				/// </summary>
-				public ustring OldTitle { get; set; }
-
-				/// <summary>
-				/// Flag which allows cancelling the Title change.
-				/// </summary>
-				public bool Cancel { get; set; }
-
-				/// <summary>
-				/// Initializes a new instance of <see cref="TitleEventArgs"/>
-				/// </summary>
-				/// <param name="oldTitle">The <see cref="Title"/> that is/has been replaced.</param>
-				/// <param name="newTitle">The new <see cref="Title"/> to be replaced.</param>
-				public TitleEventArgs (ustring oldTitle, ustring newTitle)
-				{
-					OldTitle = oldTitle;
-					NewTitle = newTitle;
-				}
-			}
-
 			/// <summary>
 			/// Called before the <see cref="Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be cancelled.
 			/// </summary>
@@ -101,7 +70,7 @@ namespace Terminal.Gui {
 			public virtual bool OnTitleChanging (ustring oldTitle, ustring newTitle)
 			{
 				var args = new TitleEventArgs (oldTitle, newTitle);
-				TitleChanging?.Invoke (args);
+				TitleChanging?.Invoke (this, args);
 				return args.Cancel;
 			}
 
@@ -109,7 +78,7 @@ namespace Terminal.Gui {
 			/// Event fired when the <see cref="Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to 
 			/// <c>true</c> to cancel the Title change.
 			/// </summary>
-			public event Action<TitleEventArgs> TitleChanging;
+			public event EventHandler<TitleEventArgs> TitleChanging;
 
 			/// <summary>
 			/// Called when the <see cref="Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.
@@ -119,13 +88,13 @@ namespace Terminal.Gui {
 			public virtual void OnTitleChanged (ustring oldTitle, ustring newTitle)
 			{
 				var args = new TitleEventArgs (oldTitle, newTitle);
-				TitleChanged?.Invoke (args);
+				TitleChanged?.Invoke (this, args);
 			}
 
 			/// <summary>
 			/// Event fired after the <see cref="Title"/> has been changed. 
 			/// </summary>
-			public event Action<TitleEventArgs> TitleChanged;
+			public event EventHandler<TitleEventArgs> TitleChanged;
 
 			/// <summary>
 			/// Creates a new instance of the <see cref="Tile"/> class.
@@ -233,7 +202,7 @@ namespace Terminal.Gui {
 				var tile = new Tile ();
 				tiles.Add (tile);
 				Add (tile.ContentView);
-				tile.TitleChanged += (e) => SetNeedsDisplay ();
+				tile.TitleChanged += (s,e) => SetNeedsDisplay ();
 			}
 
 			LayoutSubviews ();
@@ -1107,41 +1076,6 @@ namespace Terminal.Gui {
 
 	}
 
-	/// <summary>
-	/// Provides data for <see cref="TileView"/> events.
-	/// </summary>
-	public class SplitterEventArgs : EventArgs {
-
-		/// <summary>
-		/// Creates a new instance of the <see cref="SplitterEventArgs"/> class.
-		/// </summary>
-		/// <param name="tileView"><see cref="TileView"/> in which splitter is being moved.</param>
-		/// <param name="idx">Index of the splitter being moved in <see cref="TileView.SplitterDistances"/>.</param>
-		/// <param name="splitterDistance">The new <see cref="Pos"/> of the splitter line.</param>
-		public SplitterEventArgs (TileView tileView, int idx, Pos splitterDistance)
-		{
-			SplitterDistance = splitterDistance;
-			TileView = tileView;
-			Idx = idx;
-		}
-
-		/// <summary>
-		/// New position of the splitter line (see <see cref="TileView.SplitterDistances"/>).
-		/// </summary>
-		public Pos SplitterDistance { get; }
-
-		/// <summary>
-		/// Container (sender) of the event.
-		/// </summary>
-		public TileView TileView { get; }
-
-		/// <summary>
-		/// Gets the index of the splitter that is being moved. This can be
-		/// used to index <see cref="TileView.SplitterDistances"/>
-		/// </summary>
-		public int Idx { get; }
-	}
-
 	/// <summary>
 	/// Represents a method that will handle splitter events.
 	/// </summary>

+ 5 - 5
Terminal.Gui/Views/TimeField.cs

@@ -38,7 +38,7 @@ namespace Terminal.Gui {
 		/// <remarks>
 		///   The passed <see cref="EventArgs"/> is a <see cref="DateTimeEventArgs{T}"/> containing the old value, new value, and format string.
 		/// </remarks>
-		public event Action<DateTimeEventArgs<TimeSpan>> TimeChanged;
+		public event EventHandler<DateTimeEventArgs<TimeSpan>> TimeChanged;
 
 		/// <summary>
 		///    Initializes a new instance of <see cref="TimeField"/> using <see cref="LayoutStyle.Absolute"/> positioning.
@@ -106,13 +106,13 @@ namespace Terminal.Gui {
 			AddKeyBinding (Key.F | Key.CtrlMask, Command.Right);
 		}
 
-		void TextField_TextChanged (ustring e)
+		void TextField_TextChanged (object sender, TextChangedEventArgs e)
 		{
 			try {
 				if (!TimeSpan.TryParseExact (Text.ToString ().Trim (), format.Trim (), CultureInfo.CurrentCulture, TimeSpanStyles.None, out TimeSpan result))
-					Text = e;
+					Text = e.OldValue;
 			} catch (Exception) {
-				Text = e;
+				Text = e.OldValue;
 			}
 		}
 
@@ -336,7 +336,7 @@ namespace Terminal.Gui {
 		/// <param name="args">The event arguments</param>
 		public virtual void OnTimeChanged (DateTimeEventArgs<TimeSpan> args)
 		{
-			TimeChanged?.Invoke (args);
+			TimeChanged?.Invoke (this,args);
 		}
 	}
 }

+ 42 - 0
Terminal.Gui/Views/TitleEventArgs.cs

@@ -0,0 +1,42 @@
+using NStack;
+using System;
+
+namespace Terminal.Gui {
+
+	public partial class TileView {
+
+		public partial class Tile {
+			/// <summary>
+			/// An <see cref="EventArgs"/> which allows passing a cancelable new <see cref="Title"/> value event.
+			/// </summary>
+			public class TitleEventArgs : EventArgs {
+				/// <summary>
+				/// The new Window Title.
+				/// </summary>
+				public ustring NewTitle { get; set; }
+
+				/// <summary>
+				/// The old Window Title.
+				/// </summary>
+				public ustring OldTitle { get; set; }
+
+				/// <summary>
+				/// Flag which allows cancelling the Title change.
+				/// </summary>
+				public bool Cancel { get; set; }
+
+				/// <summary>
+				/// Initializes a new instance of <see cref="TitleEventArgs"/>
+				/// </summary>
+				/// <param name="oldTitle">The <see cref="Title"/> that is/has been replaced.</param>
+				/// <param name="newTitle">The new <see cref="Title"/> to be replaced.</param>
+				public TitleEventArgs (ustring oldTitle, ustring newTitle)
+				{
+					OldTitle = oldTitle;
+					NewTitle = newTitle;
+				}
+			}
+		}
+
+	}
+}

+ 2 - 2
Terminal.Gui/Views/TreeView.cs

@@ -112,7 +112,7 @@ namespace Terminal.Gui {
 		/// This event is raised when an object is activated e.g. by double clicking or 
 		/// pressing <see cref="ObjectActivationKey"/>.
 		/// </summary>
-		public event Action<ObjectActivatedEventArgs<T>> ObjectActivated;
+		public event EventHandler<ObjectActivatedEventArgs<T>> ObjectActivated;
 
 		/// <summary>
 		/// Key which when pressed triggers <see cref="TreeView{T}.ObjectActivated"/>.
@@ -712,7 +712,7 @@ namespace Terminal.Gui {
 		/// <param name="e"></param>
 		protected virtual void OnObjectActivated (ObjectActivatedEventArgs<T> e)
 		{
-			ObjectActivated?.Invoke (e);
+			ObjectActivated?.Invoke (this,e);
 		}
 
 		/// <summary>

+ 42 - 3
Terminal.Gui/Windows/Dialog.cs

@@ -62,7 +62,7 @@ namespace Terminal.Gui {
 		/// <remarks>
 		/// Use the constructor that does not take a <c>width</c> and <c>height</c> instead.
 		/// </remarks>
-		public Dialog (ustring title, int width, int height, params Button [] buttons) : base (title, padding: padding)
+		public Dialog (ustring title, int width, int height, params Button [] buttons) : base (title: title, padding: padding)
 		{
 			X = Pos.Center ();
 			Y = Pos.Center ();
@@ -78,7 +78,10 @@ namespace Terminal.Gui {
 			ColorScheme = Colors.Dialog;
 			Modal = true;
 			ButtonAlignment = DefaultButtonAlignment;
-			Border = DefaultBorder;
+			if (Border == null) {
+				Border = DefaultBorder;
+				Border.Title = title;
+			}
 
 			if (buttons != null) {
 				foreach (var b in buttons) {
@@ -87,7 +90,7 @@ namespace Terminal.Gui {
 				}
 			}
 
-			LayoutStarted += (args) => {
+			LayoutStarted += (s, args) => {
 				LayoutStartedHandler ();
 			};
 		}
@@ -118,6 +121,42 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public Dialog (ustring title, params Button [] buttons) : this (title: title, width: 0, height: 0, buttons: buttons) { }
 
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Dialog"/> class using <see cref="LayoutStyle.Computed"/> positioning, 
+		/// with a <see cref="Border"/> and with an optional set of <see cref="Button"/>s to display
+		/// </summary>
+		/// <param name="title">Title for the dialog.</param>
+		/// <param name="border">The border.</param>
+		/// <param name="buttons">Optional buttons to lay out at the bottom of the dialog.</param>
+		public Dialog (ustring title, Border border, params Button [] buttons)
+			: this (title: title, width: 0, height: 0, buttons: buttons)
+		{
+			Initialize (title, border);
+		}
+
+		/// <summary>
+		/// Initializes a new instance of the <see cref="Dialog"/> class using <see cref="LayoutStyle.Computed"/> positioning, 
+		/// with a <see cref="Border"/> and with an optional set of <see cref="Button"/>s to display
+		/// </summary>
+		/// <param name="title">Title for the dialog.</param>
+		/// <param name="width">Width for the dialog.</param>
+		/// <param name="height">Height for the dialog.</param>
+		/// <param name="border">The border.</param>
+		/// <param name="buttons">Optional buttons to lay out at the bottom of the dialog.</param>
+		public Dialog (ustring title, int width, int height, Border border, params Button [] buttons)
+			: this (title: title, width: width, height: height, buttons: buttons)
+		{
+			Initialize (title, border);
+		}
+
+		void Initialize (ustring title, Border border)
+		{
+			if (border != null) {
+				Border = border;
+				Border.Title = title;
+			}
+		}
+
 		/// <summary>
 		/// Adds a <see cref="Button"/> to the <see cref="Dialog"/>, its layout will be controlled by the <see cref="Dialog"/>
 		/// </summary>

+ 6 - 6
Terminal.Gui/Windows/FileDialog.cs

@@ -649,7 +649,7 @@ namespace Terminal.Gui {
 				Y = 1 + msgLines,
 				Width = Dim.Fill () - 1,
 			};
-			dirEntry.TextChanged += (e) => {
+			dirEntry.TextChanged += (s, e) => {
 				DirectoryPath = dirEntry.Text;
 				nameEntry.Text = ustring.Empty;
 			};
@@ -678,7 +678,7 @@ namespace Terminal.Gui {
 				HideDropdownListOnClick = true
 			};
 			cmbAllowedTypes.SetSource (allowedTypes ?? new List<string> ());
-			cmbAllowedTypes.OpenSelectedItem += (e) => {
+			cmbAllowedTypes.OpenSelectedItem += (s, e) => {
 				dirListView.AllowedFileTypes = cmbAllowedTypes.Text.ToString ().Split (';');
 				dirListView.Reload ();
 			};
@@ -698,7 +698,7 @@ namespace Terminal.Gui {
 			dirListView.FileChanged = (file) => nameEntry.Text = file == ".." ? "" : file;
 			dirListView.SelectedChanged = (file) => nameEntry.Text = file.Item1 == ".." ? "" : file.Item1;
 			this.cancel = new Button ("Cancel");
-			this.cancel.Clicked += () => {
+			this.cancel.Clicked += (s,e) => {
 				Cancel ();
 			};
 			AddButton (cancel);
@@ -707,7 +707,7 @@ namespace Terminal.Gui {
 				IsDefault = true,
 				Enabled = nameEntry.Text.IsEmpty ? false : true
 			};
-			this.prompt.Clicked += () => {
+			this.prompt.Clicked += (s,e) => {
 				if (this is OpenDialog) {
 					if (!dirListView.GetValidFilesName (nameEntry.Text.ToString (), out string res)) {
 						nameEntry.Text = res;
@@ -731,7 +731,7 @@ namespace Terminal.Gui {
 			};
 			AddButton (this.prompt);
 
-			nameEntry.TextChanged += (e) => {
+			nameEntry.TextChanged += (s,e) => {
 				if (nameEntry.Text.IsEmpty) {
 					this.prompt.Enabled = false;
 				} else {
@@ -745,7 +745,7 @@ namespace Terminal.Gui {
 			// On success, we will set this to false.
 			canceled = true;
 
-			KeyPress += (e) => {
+			KeyPress += (s, e) => {
 				if (e.KeyEvent.Key == Key.Esc) {
 					Cancel ();
 					e.Handled = true;

+ 61 - 30
Terminal.Gui/Windows/MessageBox.cs

@@ -1,6 +1,8 @@
 using NStack;
 using System;
 using System.Collections.Generic;
+using Terminal.Gui.Configuration;
+using static Terminal.Gui.Configuration.ConfigurationManager;
 
 namespace Terminal.Gui {
 	/// <summary>
@@ -38,7 +40,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int Query (int width, int height, ustring title, ustring message, params ustring [] buttons)
 		{
-			return QueryFull (false, width, height, title, message, 0, null, buttons);
+			return QueryFull (false, width, height, title, message, 0, null, true, buttons);
 		}
 
 		/// <summary>
@@ -54,7 +56,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int Query (ustring title, ustring message, params ustring [] buttons)
 		{
-			return QueryFull (false, 0, 0, title, message, 0, null, buttons);
+			return QueryFull (false, 0, 0, title, message, 0, null, true, buttons);
 		}
 
 		/// <summary>
@@ -71,7 +73,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int ErrorQuery (int width, int height, ustring title, ustring message, params ustring [] buttons)
 		{
-			return QueryFull (true, width, height, title, message, 0, null, buttons);
+			return QueryFull (true, width, height, title, message, 0, null, true, buttons);
 		}
 
 		/// <summary>
@@ -87,7 +89,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int ErrorQuery (ustring title, ustring message, params ustring [] buttons)
 		{
-			return QueryFull (true, 0, 0, title, message, 0, null, buttons);
+			return QueryFull (true, 0, 0, title, message, 0, null, true, buttons);
 		}
 
 		/// <summary>
@@ -105,7 +107,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int Query (int width, int height, ustring title, ustring message, int defaultButton = 0, params ustring [] buttons)
 		{
-			return QueryFull (false, width, height, title, message, defaultButton, null, buttons);
+			return QueryFull (false, width, height, title, message, defaultButton, null, true, buttons);
 		}
 
 		/// <summary>
@@ -122,7 +124,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int Query (ustring title, ustring message, int defaultButton = 0, params ustring [] buttons)
 		{
-			return QueryFull (false, 0, 0, title, message, defaultButton, null, buttons);
+			return QueryFull (false, 0, 0, title, message, defaultButton, null, true, buttons);
 		}
 
 		/// <summary>
@@ -135,13 +137,14 @@ namespace Terminal.Gui {
 		/// <param name="message">Message to display, might contain multiple lines.</param>
 		/// <param name="defaultButton">Index of the default button.</param>
 		/// <param name="border">The border settings.</param>
+		/// <param name="wrapMessagge">If wrap the message or not.</param>
 		/// <param name="buttons">Array of buttons to add.</param>
 		/// <remarks>
 		/// Use <see cref="Query(ustring, ustring, ustring[])"/> instead; it automatically sizes the MessageBox based on the contents.
 		/// </remarks>
-		public static int Query (int width, int height, ustring title, ustring message, int defaultButton = 0, Border border = null, params ustring [] buttons)
+		public static int Query (int width, int height, ustring title, ustring message, int defaultButton = 0, Border border = null, bool wrapMessagge = true, params ustring [] buttons)
 		{
-			return QueryFull (false, width, height, title, message, defaultButton, border, buttons);
+			return QueryFull (false, width, height, title, message, defaultButton, border, wrapMessagge, buttons);
 		}
 
 		/// <summary>
@@ -152,14 +155,15 @@ namespace Terminal.Gui {
 		/// <param name="message">Message to display, might contain multiple lines.</param>
 		/// <param name="defaultButton">Index of the default button.</param>
 		/// <param name="border">The border settings.</param>
+		/// <param name="wrapMessagge">If wrap the message or not.</param>
 		/// <param name="buttons">Array of buttons to add.</param>
 		/// <remarks>
 		/// The message box will be vertically and horizontally centered in the container and the size will be automatically determined
 		/// from the size of the message and buttons.
 		/// </remarks>
-		public static int Query (ustring title, ustring message, int defaultButton = 0, Border border = null, params ustring [] buttons)
+		public static int Query (ustring title, ustring message, int defaultButton = 0, Border border = null, bool wrapMessagge = true, params ustring [] buttons)
 		{
-			return QueryFull (false, 0, 0, title, message, defaultButton, border, buttons);
+			return QueryFull (false, 0, 0, title, message, defaultButton, border, wrapMessagge, buttons);
 		}
 
 
@@ -178,7 +182,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int ErrorQuery (int width, int height, ustring title, ustring message, int defaultButton = 0, params ustring [] buttons)
 		{
-			return QueryFull (true, width, height, title, message, defaultButton, null, buttons);
+			return QueryFull (true, width, height, title, message, defaultButton, null, true, buttons);
 		}
 
 		/// <summary>
@@ -195,7 +199,7 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public static int ErrorQuery (ustring title, ustring message, int defaultButton = 0, params ustring [] buttons)
 		{
-			return QueryFull (true, 0, 0, title, message, defaultButton, null, buttons);
+			return QueryFull (true, 0, 0, title, message, defaultButton, null, true, buttons);
 		}
 
 		/// <summary>
@@ -208,13 +212,14 @@ namespace Terminal.Gui {
 		/// <param name="message">Message to display, might contain multiple lines.</param>
 		/// <param name="defaultButton">Index of the default button.</param>
 		/// <param name="border">The border settings.</param>
+		/// <param name="wrapMessagge">If wrap the message or not.</param>
 		/// <param name="buttons">Array of buttons to add.</param>
 		/// <remarks>
 		/// Use <see cref="ErrorQuery(ustring, ustring, ustring[])"/> instead; it automatically sizes the MessageBox based on the contents.
 		/// </remarks>
-		public static int ErrorQuery (int width, int height, ustring title, ustring message, int defaultButton = 0, Border border = null, params ustring [] buttons)
+		public static int ErrorQuery (int width, int height, ustring title, ustring message, int defaultButton = 0, Border border = null, bool wrapMessagge = true, params ustring [] buttons)
 		{
-			return QueryFull (true, width, height, title, message, defaultButton, border, buttons);
+			return QueryFull (true, width, height, title, message, defaultButton, border, wrapMessagge, buttons);
 		}
 
 		/// <summary>
@@ -225,25 +230,37 @@ namespace Terminal.Gui {
 		/// <param name="message">Message to display, might contain multiple lines.</param>
 		/// <param name="defaultButton">Index of the default button.</param>
 		/// <param name="border">The border settings.</param>
+		/// <param name="wrapMessagge">If wrap the message or not.</param>
 		/// <param name="buttons">Array of buttons to add.</param>
 		/// <remarks>
 		/// The message box will be vertically and horizontally centered in the container and the size will be automatically determined
 		/// from the size of the title, message. and buttons.
 		/// </remarks>
-		public static int ErrorQuery (ustring title, ustring message, int defaultButton = 0, Border border = null, params ustring [] buttons)
+		public static int ErrorQuery (ustring title, ustring message, int defaultButton = 0, Border border = null, bool wrapMessagge = true, params ustring [] buttons)
 		{
-			return QueryFull (true, 0, 0, title, message, defaultButton, border, buttons);
+			return QueryFull (true, 0, 0, title, message, defaultButton, border, wrapMessagge, buttons);
 		}
 
+		/// <summary>
+		/// Defines the default border styling for <see cref="Dialog"/>. Can be configured via <see cref="ConfigurationManager"/>.
+		/// </summary>
+		[SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
+		public static Border DefaultBorder { get; set; } = new Border () {
+			BorderStyle = BorderStyle.Single,
+			DrawMarginFrame = false,
+			Effect3D = true,
+			Effect3DOffset = new Point (1, 1),
+		};
+
 		static int QueryFull (bool useErrorColors, int width, int height, ustring title, ustring message,
-			int defaultButton = 0, Border border = null, params ustring [] buttons)
+			int defaultButton = 0, Border border = null, bool wrapMessagge = true, params ustring [] buttons)
 		{
 			int defaultWidth = 50;
 			if (defaultWidth > Application.Driver.Cols / 2) {
 				defaultWidth = (int)(Application.Driver.Cols * 0.60f);
 			}
 			int maxWidthLine = TextFormatter.MaxWidthLine (message);
-			if (maxWidthLine > Application.Driver.Cols) {
+			if (wrapMessagge && maxWidthLine > Application.Driver.Cols) {
 				maxWidthLine = Application.Driver.Cols;
 			}
 			if (width == 0) {
@@ -251,10 +268,14 @@ namespace Terminal.Gui {
 			} else {
 				maxWidthLine = width;
 			}
-			int textWidth = Math.Min (TextFormatter.MaxWidth (message, maxWidthLine), Application.Driver.Cols);
+			int textWidth = TextFormatter.MaxWidth (message, maxWidthLine);
 			int textHeight = TextFormatter.MaxLines (message, textWidth); // message.Count (ustring.Make ('\n')) + 1;
-			int msgboxHeight = Math.Min (Math.Max (1, textHeight) + 4, Application.Driver.Rows); // textHeight + (top + top padding + buttons + bottom)
+			int msgboxHeight = Math.Max (1, textHeight) + 4; // textHeight + (top + top padding + buttons + bottom)
 
+			if (wrapMessagge) {
+				textWidth = Math.Min (textWidth, Application.Driver.Cols);
+				msgboxHeight = Math.Min (msgboxHeight, Application.Driver.Rows);
+			}
 			// Create button array for Dialog
 			int count = 0;
 			List<Button> buttonList = new List<Button> ();
@@ -269,26 +290,31 @@ namespace Terminal.Gui {
 				buttonList.Add (b);
 				count++;
 			}
-
+			if (border == null) {
+				border = DefaultBorder;
+				border.Title = title;
+			}
 			// Create Dialog (retain backwards compat by supporting specifying height/width)
 			Dialog d;
 			if (width == 0 & height == 0) {
-				d = new Dialog (title, buttonList.ToArray ()) {
+				d = new Dialog (title, border, buttonList.ToArray ()) {
 					Height = msgboxHeight
 				};
 			} else {
-				d = new Dialog (title, width, Math.Max (height, 4), buttonList.ToArray ());
-			}
-
-			if (border != null) {
-				d.Border = border;
+				d = new Dialog (title, width, Math.Max (height, 4), border, buttonList.ToArray ());
 			}
 
 			if (useErrorColors) {
 				d.ColorScheme = Colors.Error;
+				d.Border.BorderBrush = Colors.Error.Normal.Foreground;
+				d.Border.Background = Colors.Error.Normal.Background;
+			} else {
+				d.ColorScheme = Colors.Dialog;
+				d.Border.BorderBrush = Colors.Dialog.Normal.Foreground;
+				d.Border.Background = Colors.Dialog.Normal.Background;
 			}
 
-			if (message != null) {
+			if (!ustring.IsNullOrEmpty (message)) {
 				var l = new Label (message) {
 					LayoutStyle = LayoutStyle.Computed,
 					TextAlignment = TextAlignment.Centered,
@@ -303,7 +329,12 @@ namespace Terminal.Gui {
 
 			if (width == 0 & height == 0) {
 				// Dynamically size Width
-				d.Width = Math.Min (Math.Max (maxWidthLine, Math.Max (title.ConsoleWidth, Math.Max (textWidth + 2, d.GetButtonsWidth () + d.buttons.Count + 2))), Application.Driver.Cols); // textWidth + (left + padding + padding + right)
+				var dWidth = Math.Max (maxWidthLine, Math.Max (title.ConsoleWidth, Math.Max (textWidth + 2, d.GetButtonsWidth () + d.buttons.Count + 2))); // textWidth + (left + padding + padding + right)
+				if (wrapMessagge) {
+					d.Width = Math.Min (dWidth, Application.Driver.Cols);
+				} else {
+					d.Width = dWidth;
+				}
 			}
 
 			// Setup actions
@@ -311,7 +342,7 @@ namespace Terminal.Gui {
 			for (int n = 0; n < buttonList.Count; n++) {
 				int buttonId = n;
 				var b = buttonList [n];
-				b.Clicked += () => {
+				b.Clicked += (s, e) => {
 					Clicked = buttonId;
 					Application.RequestStop ();
 				};

+ 28 - 78
Terminal.Gui/Windows/Wizard.cs

@@ -132,7 +132,7 @@ namespace Terminal.Gui {
 			public virtual bool OnTitleChanging (ustring oldTitle, ustring newTitle)
 			{
 				var args = new TitleEventArgs (oldTitle, newTitle);
-				TitleChanging?.Invoke (args);
+				TitleChanging?.Invoke (this, args);
 				return args.Cancel;
 			}
 
@@ -140,7 +140,7 @@ namespace Terminal.Gui {
 			/// Event fired when the <see cref="Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to 
 			/// <c>true</c> to cancel the Title change.
 			/// </summary>
-			public event Action<TitleEventArgs> TitleChanging;
+			public event EventHandler<TitleEventArgs> TitleChanging;
 
 			/// <summary>
 			/// Called when the <see cref="Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.
@@ -150,13 +150,13 @@ namespace Terminal.Gui {
 			public virtual void OnTitleChanged (ustring oldTitle, ustring newTitle)
 			{
 				var args = new TitleEventArgs (oldTitle, newTitle);
-				TitleChanged?.Invoke (args);
+				TitleChanged?.Invoke (this, args);
 			}
 
 			/// <summary>
 			/// Event fired after the <see cref="Title"/> has been changed. 
 			/// </summary>
-			public event Action<TitleEventArgs> TitleChanged;
+			public event EventHandler<TitleEventArgs> TitleChanged;
 
 			// The contentView works like the ContentView in FrameView.
 			private View contentView = new View () { Data = "WizardContentView" };
@@ -211,7 +211,7 @@ namespace Terminal.Gui {
 
 				var scrollBar = new ScrollBarView (helpTextView, true);
 
-				scrollBar.ChangedPosition += () => {
+				scrollBar.ChangedPosition += (s,e) => {
 					helpTextView.TopRow = scrollBar.Position;
 					if (helpTextView.TopRow != scrollBar.Position) {
 						scrollBar.Position = helpTextView.TopRow;
@@ -219,7 +219,7 @@ namespace Terminal.Gui {
 					helpTextView.SetNeedsDisplay ();
 				};
 
-				scrollBar.OtherScrollBarView.ChangedPosition += () => {
+				scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => {
 					helpTextView.LeftColumn = scrollBar.OtherScrollBarView.Position;
 					if (helpTextView.LeftColumn != scrollBar.OtherScrollBarView.Position) {
 						scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn;
@@ -227,7 +227,7 @@ namespace Terminal.Gui {
 					helpTextView.SetNeedsDisplay ();
 				};
 
-				scrollBar.VisibleChanged += () => {
+				scrollBar.VisibleChanged += (s,e) => {
 					if (scrollBar.Visible && helpTextView.RightOffset == 0) {
 						helpTextView.RightOffset = 1;
 					} else if (!scrollBar.Visible && helpTextView.RightOffset == 1) {
@@ -235,7 +235,7 @@ namespace Terminal.Gui {
 					}
 				};
 
-				scrollBar.OtherScrollBarView.VisibleChanged += () => {
+				scrollBar.OtherScrollBarView.VisibleChanged += (s,e) => {
 					if (scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 0) {
 						helpTextView.BottomOffset = 1;
 					} else if (!scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 1) {
@@ -243,7 +243,7 @@ namespace Terminal.Gui {
 					}
 				};
 
-				helpTextView.DrawContent += (e) => {
+				helpTextView.DrawContent += (s,e) => {
 					scrollBar.Size = helpTextView.Lines;
 					scrollBar.Position = helpTextView.TopRow;
 					if (scrollBar.OtherScrollBarView != null) {
@@ -385,26 +385,26 @@ namespace Terminal.Gui {
 
 		}
 
-		private void Wizard_Loaded ()
+		private void Wizard_Loaded (object sender, EventArgs args)
 		{
 			CurrentStep = GetFirstStep (); // gets the first step if CurrentStep == null
 		}
 
 		private bool finishedPressed = false;
 
-		private void Wizard_Closing (ToplevelClosingEventArgs obj)
+		private void Wizard_Closing (object sender, ToplevelClosingEventArgs obj)
 		{
 			if (!finishedPressed) {
 				var args = new WizardButtonEventArgs ();
-				Cancelled?.Invoke (args);
+				Cancelled?.Invoke (this, args);
 			}
 		}
 
-		private void NextfinishBtn_Clicked ()
+		private void NextfinishBtn_Clicked (object sender, EventArgs e)
 		{
 			if (CurrentStep == GetLastStep ()) {
 				var args = new WizardButtonEventArgs ();
-				Finished?.Invoke (args);
+				Finished?.Invoke (this, args);
 				if (!args.Cancel) {
 					finishedPressed = true;
 					if (IsCurrentTop) {
@@ -416,7 +416,7 @@ namespace Terminal.Gui {
 				}
 			} else {
 				var args = new WizardButtonEventArgs ();
-				MovingNext?.Invoke (args);
+				MovingNext?.Invoke (this, args);
 				if (!args.Cancel) {
 					GoNext ();
 				}
@@ -437,7 +437,7 @@ namespace Terminal.Gui {
 				switch (kb.Key) {
 				case Key.Esc:
 					var args = new WizardButtonEventArgs ();
-					Cancelled?.Invoke (args);
+					Cancelled?.Invoke (this, args);
 					return false;
 				}
 			}
@@ -486,10 +486,10 @@ namespace Terminal.Gui {
 			return null;
 		}
 
-		private void BackBtn_Clicked ()
+		private void BackBtn_Clicked (object sender, EventArgs e)
 		{
 			var args = new WizardButtonEventArgs ();
-			MovingBack?.Invoke (args);
+			MovingBack?.Invoke (this, args);
 			if (!args.Cancel) {
 				GoBack ();
 			}
@@ -590,8 +590,8 @@ namespace Terminal.Gui {
 		{
 			SizeStep (newStep);
 
-			newStep.EnabledChanged += UpdateButtonsAndTitle;
-			newStep.TitleChanged += (args) => UpdateButtonsAndTitle ();
+			newStep.EnabledChanged += (s,e)=> UpdateButtonsAndTitle();
+			newStep.TitleChanged += (s,e) => UpdateButtonsAndTitle ();
 			steps.AddLast (newStep);
 			this.Add (newStep);
 			UpdateButtonsAndTitle ();
@@ -615,29 +615,11 @@ namespace Terminal.Gui {
 		}
 		private ustring wizardTitle = ustring.Empty;
 
-		/// <summary>	
-		/// <see cref="EventArgs"/> for <see cref="WizardStep"/> transition events.
-		/// </summary>
-		public class WizardButtonEventArgs : EventArgs {
-			/// <summary>
-			/// Set to true to cancel the transition to the next step.
-			/// </summary>
-			public bool Cancel { get; set; }
-
-			/// <summary>
-			/// Initializes a new instance of <see cref="WizardButtonEventArgs"/>
-			/// </summary>
-			public WizardButtonEventArgs ()
-			{
-				Cancel = false;
-			}
-		}
-
 		/// <summary>
 		/// Raised when the Back button in the <see cref="Wizard"/> is clicked. The Back button is always
 		/// the first button in the array of Buttons passed to the <see cref="Wizard"/> constructor, if any.
 		/// </summary>
-		public event Action<WizardButtonEventArgs> MovingBack;
+		public event EventHandler<WizardButtonEventArgs> MovingBack;
 
 		/// <summary>
 		/// Raised when the Next/Finish button in the <see cref="Wizard"/> is clicked (or the user presses Enter). 
@@ -645,7 +627,7 @@ namespace Terminal.Gui {
 		/// if any. This event is only raised if the <see cref="CurrentStep"/> is the last Step in the Wizard flow 
 		/// (otherwise the <see cref="Finished"/> event is raised).
 		/// </summary>
-		public event Action<WizardButtonEventArgs> MovingNext;
+		public event EventHandler<WizardButtonEventArgs> MovingNext;
 
 		/// <summary>
 		/// Raised when the Next/Finish button in the <see cref="Wizard"/> is clicked. The Next/Finish button is always
@@ -653,7 +635,7 @@ namespace Terminal.Gui {
 		/// raised if the <see cref="CurrentStep"/> is the last Step in the Wizard flow 
 		/// (otherwise the <see cref="Finished"/> event is raised).
 		/// </summary>
-		public event Action<WizardButtonEventArgs> Finished;
+		public event EventHandler<WizardButtonEventArgs> Finished;
 
 		/// <summary>
 		/// Raised when the user has cancelled the <see cref="Wizard"/> by pressin the Esc key. 
@@ -661,50 +643,18 @@ namespace Terminal.Gui {
 		/// closing, cancel the event by setting <see cref="WizardButtonEventArgs.Cancel"/> to 
 		/// <c>true</c> before returning from the event handler.
 		/// </summary>
-		public event Action<WizardButtonEventArgs> Cancelled;
-
-		/// <summary>
-		/// <see cref="EventArgs"/> for <see cref="WizardStep"/> events.
-		/// </summary>
-		public class StepChangeEventArgs : EventArgs {
-			/// <summary>
-			/// The current (or previous) <see cref="WizardStep"/>.
-			/// </summary>
-			public WizardStep OldStep { get; }
-
-			/// <summary>
-			/// The <see cref="WizardStep"/> the <see cref="Wizard"/> is changing to or has changed to.
-			/// </summary>
-			public WizardStep NewStep { get; }
-
-			/// <summary>
-			/// Event handlers can set to true before returning to cancel the step transition.
-			/// </summary>
-			public bool Cancel { get; set; }
-
-			/// <summary>
-			/// Initializes a new instance of <see cref="StepChangeEventArgs"/>
-			/// </summary>
-			/// <param name="oldStep">The current <see cref="WizardStep"/>.</param>
-			/// <param name="newStep">The new <see cref="WizardStep"/>.</param>
-			public StepChangeEventArgs (WizardStep oldStep, WizardStep newStep)
-			{
-				OldStep = oldStep;
-				NewStep = newStep;
-				Cancel = false;
-			}
-		}
+		public event EventHandler<WizardButtonEventArgs> Cancelled;
 
 		/// <summary>
 		/// This event is raised when the current <see cref="CurrentStep"/>) is about to change. Use <see cref="StepChangeEventArgs.Cancel"/> 
 		/// to abort the transition.
 		/// </summary>
-		public event Action<StepChangeEventArgs> StepChanging;
+		public event EventHandler<StepChangeEventArgs> StepChanging;
 
 		/// <summary>
 		/// This event is raised after the <see cref="Wizard"/> has changed the <see cref="CurrentStep"/>. 
 		/// </summary>
-		public event Action<StepChangeEventArgs> StepChanged;
+		public event EventHandler<StepChangeEventArgs> StepChanged;
 
 		/// <summary>
 		/// Gets or sets the currently active <see cref="WizardStep"/>.
@@ -725,7 +675,7 @@ namespace Terminal.Gui {
 		public virtual bool OnStepChanging (WizardStep oldStep, WizardStep newStep)
 		{
 			var args = new StepChangeEventArgs (oldStep, newStep);
-			StepChanging?.Invoke (args);
+			StepChanging?.Invoke (this, args);
 			return args.Cancel;
 		}
 
@@ -738,7 +688,7 @@ namespace Terminal.Gui {
 		public virtual bool OnStepChanged (WizardStep oldStep, WizardStep newStep)
 		{
 			var args = new StepChangeEventArgs (oldStep, newStep);
-			StepChanged?.Invoke (args);
+			StepChanged?.Invoke (this, args);
 			return args.Cancel;
 		}
 

+ 54 - 0
Terminal.Gui/Windows/WizardEventArgs.cs

@@ -0,0 +1,54 @@
+using System;
+using static Terminal.Gui.Wizard;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// <see cref="EventArgs"/> for <see cref="WizardStep"/> transition events.
+	/// </summary>
+	public class WizardButtonEventArgs : EventArgs {
+		/// <summary>
+		/// Set to true to cancel the transition to the next step.
+		/// </summary>
+		public bool Cancel { get; set; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="WizardButtonEventArgs"/>
+		/// </summary>
+		public WizardButtonEventArgs ()
+		{
+			Cancel = false;
+		}
+	}
+
+	/// <summary>
+	/// <see cref="EventArgs"/> for <see cref="WizardStep"/> events.
+	/// </summary>
+	public class StepChangeEventArgs : EventArgs {
+		/// <summary>
+		/// The current (or previous) <see cref="WizardStep"/>.
+		/// </summary>
+		public WizardStep OldStep { get; }
+
+		/// <summary>
+		/// The <see cref="WizardStep"/> the <see cref="Wizard"/> is changing to or has changed to.
+		/// </summary>
+		public WizardStep NewStep { get; }
+
+		/// <summary>
+		/// Event handlers can set to true before returning to cancel the step transition.
+		/// </summary>
+		public bool Cancel { get; set; }
+
+		/// <summary>
+		/// Initializes a new instance of <see cref="StepChangeEventArgs"/>
+		/// </summary>
+		/// <param name="oldStep">The current <see cref="WizardStep"/>.</param>
+		/// <param name="newStep">The new <see cref="WizardStep"/>.</param>
+		public StepChangeEventArgs (WizardStep oldStep, WizardStep newStep)
+		{
+			OldStep = oldStep;
+			NewStep = newStep;
+			Cancel = false;
+		}
+	}
+}

+ 9 - 6
UICatalog/KeyBindingsDialog.cs

@@ -60,8 +60,11 @@ namespace UICatalog {
 				foreach (var sub in view.Subviews) {
 					RecordView (sub);
 				}
+				// TODO: BUG: Based on my new understanding of Added event I think this is wrong
+				// (and always was wrong). Parents don't get to be told when new views are added
+				// to them
 
-				view.Added += RecordView;
+				view.Added += (s,e)=>RecordView(e.Child);
 			}
 
 			internal static void Initialize ()
@@ -151,14 +154,14 @@ namespace UICatalog {
 			btnChange.Clicked += RemapKey;
 
 			var close = new Button ("Ok");
-			close.Clicked += () => {
+			close.Clicked += (s,e) => {
 				Application.RequestStop ();
 				ViewTracker.Instance.StartUsingNewKeyMap (CurrentBindings);
 			};
 			AddButton (close);
 
 			var cancel = new Button ("Cancel");
-			cancel.Clicked += ()=>Application.RequestStop();
+			cancel.Clicked += (s,e)=>Application.RequestStop();
 			AddButton (cancel);
 
 			// Register event handler as the last thing in constructor to prevent early calls
@@ -169,14 +172,14 @@ namespace UICatalog {
 			SetTextBoxToShowBinding (commands.First());
 		}
 
-		private void RemapKey ()
+		private void RemapKey (object sender, EventArgs e)
 		{
 			var cmd = commands [commandsListView.SelectedItem];
 			Key? key = null;
 
 			// prompt user to hit a key
 			var dlg = new Dialog ("Enter Key");
-			dlg.KeyPress += (k) => {
+			dlg.KeyPress += (s, k) => {
 				key = k.KeyEvent.Key;
 				Application.RequestStop ();
 			};
@@ -198,7 +201,7 @@ namespace UICatalog {
 			SetNeedsDisplay ();
 		}
 
-		private void CommandsListView_SelectedItemChanged (ListViewItemEventArgs obj)
+		private void CommandsListView_SelectedItemChanged (object sender, ListViewItemEventArgs obj)
 		{
 			SetTextBoxToShowBinding ((Command)obj.Value);
 		}

+ 6 - 14
UICatalog/Properties/launchSettings.json

@@ -3,6 +3,12 @@
     "UICatalog": {
       "commandName": "Project"
     },
+    "WSL : UICatalog": {
+      "commandName": "Executable",
+      "executablePath": "wsl",
+      "commandLineArgs": "dotnet UICatalog.dll",
+      "distributionName": ""
+    },
     "UICatalog -usc": {
       "commandName": "Project",
       "commandLineArgs": "-usc"
@@ -29,10 +35,6 @@
       "commandName": "Project",
       "commandLineArgs": "WizardAsView"
     },
-    "VkeyPacketSimulator": {
-      "commandName": "Project",
-      "commandLineArgs": "VkeyPacketSimulator"
-    },
     "CollectionNavigatorTester": {
       "commandName": "Project",
       "commandLineArgs": "\"Search Collection Nav\""
@@ -48,16 +50,6 @@
     "Windows & FrameViews": {
       "commandName": "Project",
       "commandLineArgs": "\"Windows & FrameViews\""
-    },
-    "WSL : UICatalog": {
-      "commandName": "Executable",
-      "executablePath": "wsl",
-      "commandLineArgs": "dotnet UICatalog.dll",
-      "distributionName": ""
-    },
-    "Tile View Experiments": {
-      "commandName": "Project",
-      "commandLineArgs": "\"Tile View Experiments\""
     }
   }
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно