瀏覽代碼

Merge branch 'master' of https://github.com/migueldeicaza/gui.cs into feature/TextFieldAutoComplete

Ross Ferguson 5 年之前
父節點
當前提交
6228bffcbf

+ 0 - 26
.github/workflows/dotnetcore.yml

@@ -1,26 +0,0 @@
-name: .NET Core
-
-on:
-  push:
-    branches: [ master ]
-  pull_request:
-    branches: [ master ]
-
-jobs:
-  build:
-
-    runs-on: ubuntu-latest
-
-# Commented out until we resolve how to build the project with just netstandard2.1
-#    steps:
-#    - uses: actions/checkout@v2
-#   - name: Setup .NET Core
-#      uses: actions/setup-dotnet@v1
-#      with:
-#        dotnet-version: 3.1.101
-#    - name: Install dependencies
-#      run: dotnet restore
-#    - name: Build
-#      run: dotnet build --configuration Release --no-restore
-#    - name: Test
-#      run: dotnet test --no-restore --verbosity normal

+ 8 - 8
Example/demo.cs

@@ -92,8 +92,8 @@ static class Demo {
 			Width = Dim.Fill (),
 			Width = Dim.Fill (),
 			Height = Dim.Fill ()
 			Height = Dim.Fill ()
 		};
 		};
-		container.OnKeyUp += (KeyEvent ke) => {
-			if (ke.Key == Key.Esc)
+		container.KeyUp += (sender, e) => {
+			if (e.KeyEvent.Key == Key.Esc)
 				container.Running = false;
 				container.Running = false;
 		};
 		};
 
 
@@ -436,11 +436,11 @@ static class Demo {
 	#endregion
 	#endregion
 
 
 
 
-	#region OnKeyDown / OnKeyPress / OnKeyUp Demo
+	#region KeyDown / KeyPress / KeyUp Demo
 	private static void OnKeyDownPressUpDemo ()
 	private static void OnKeyDownPressUpDemo ()
 	{
 	{
 		var container = new Dialog (
 		var container = new Dialog (
-			"OnKeyDown & OnKeyPress & OnKeyUp demo", 80, 20,
+			"KeyDown & KeyPress & KeyUp demo", 80, 20,
 			new Button ("Close") { Clicked = () => { Application.RequestStop (); } }) {
 			new Button ("Close") { Clicked = () => { Application.RequestStop (); } }) {
 			Width = Dim.Fill (),
 			Width = Dim.Fill (),
 			Height = Dim.Fill (),
 			Height = Dim.Fill (),
@@ -492,9 +492,9 @@ static class Demo {
 		}
 		}
 
 
 
 
-		container.OnKeyDown += (KeyEvent keyEvent) => KeyDownPressUp (keyEvent, "Down");
-		container.OnKeyPress += (KeyEvent keyEvent) => KeyDownPressUp (keyEvent, "Press");
-		container.OnKeyUp += (KeyEvent keyEvent) => KeyDownPressUp (keyEvent, "Up");
+		container.KeyDown += (o, e) => KeyDownPressUp (e.KeyEvent, "Down");
+		container.KeyPress += (o, e) => KeyDownPressUp (e.KeyEvent, "Press");
+		container.KeyUp += (o, e) => KeyDownPressUp (e.KeyEvent, "Up");
 		Application.Run (container);
 		Application.Run (container);
 	}
 	}
 	#endregion
 	#endregion
@@ -628,7 +628,7 @@ static class Demo {
 		var bottom2 = new Label ("This should go on the bottom of another top-level!");
 		var bottom2 = new Label ("This should go on the bottom of another top-level!");
 		top.Add (bottom2);
 		top.Add (bottom2);
 
 
-		Application.OnLoad = () => {
+		Application.Loaded += (sender, e) => {
 			bottom.X = win.X;
 			bottom.X = win.X;
 			bottom.Y = Pos.Bottom (win) - Pos.Top (win) - margin;
 			bottom.Y = Pos.Bottom (win) - Pos.Top (win) - margin;
 			bottom2.X = Pos.Left (win);
 			bottom2.X = Pos.Left (win);

+ 71 - 99
README.md

@@ -2,59 +2,84 @@
 [![Version](https://img.shields.io/nuget/v/Terminal.Gui.svg)](https://www.nuget.org/packages/Terminal.Gui)
 [![Version](https://img.shields.io/nuget/v/Terminal.Gui.svg)](https://www.nuget.org/packages/Terminal.Gui)
 [![Downloads](https://img.shields.io/nuget/dt/Terminal.Gui)](https://www.nuget.org/packages/Terminal.Gui)
 [![Downloads](https://img.shields.io/nuget/dt/Terminal.Gui)](https://www.nuget.org/packages/Terminal.Gui)
 [![License](https://img.shields.io/github/license/migueldeicaza/gui.cs.svg)](LICENSE)
 [![License](https://img.shields.io/github/license/migueldeicaza/gui.cs.svg)](LICENSE)
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mono/mono?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - The Mono Channel room
 
 
-[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mono/mono?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - This is the Mono Channel room
+# Terminal.Gui - Terminal UI toolkit for .NET
 
 
-# Gui.cs - Terminal UI toolkit for .NET
+A simple UI toolkit for .NET, .NET Core, and Mono that works on Windows, the Mac, and Linux/Unix.
 
 
-This is a simple UI toolkit for .NET, .NET Core and Mono and works on
-both Windows and Linux/Unix.
+![Sample app](https://raw.githubusercontent.com/migueldeicaza/gui.cs/master/docfx/sample.gif)
 
 
-![Sample app](https://raw.githubusercontent.com/migueldeicaza/gui.cs/master/docfx/sample.png)
+## Controls & Features
 
 
-A presentation of this was part of the [Retro.NET](https://channel9.msdn.com/Events/dotnetConf/2018/S313) talk at .NET Conf 2018 [Slides](https://tirania.org/Retro.pdf)
-
-The toolkit contains various controls for building text user interfaces:
+The *Terminal.Gui* toolkit contains various controls for building text user interfaces:
 
 
 * [Buttons](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Button.html) 
 * [Buttons](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Button.html) 
+* [Checkboxes](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.CheckBox.html)
+* [Dialog boxes](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Dialog.html)
+* [Frames](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.FrameView.html)
+* [Hex viewer/editor](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.HexView.html)
 * [Labels](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Label.html)
 * [Labels](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Label.html)
+* [ListViews](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ListView.html)
+* [Menus](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.MenuBar.html)
+* [Message boxes](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.MessageBox.html)
+* [ProgressBars](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ProgressBar.html)
+* [Time editing field](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TimeField.html)
 * [Text entry](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TextField.html)
 * [Text entry](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TextField.html)
 * [Text view](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TextView.html)
 * [Text view](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TextView.html)
-* [Time editing field](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TimeField.html)
+* [Scroll views](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ScrollView.html)
+* [Scrollbars](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ScrollBarView.html)
+* [Status bars]()
 * [Radio buttons](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.RadioGroup.html)
 * [Radio buttons](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.RadioGroup.html)
-* [Checkboxes](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.CheckBox.html)
-* [Dialog boxes](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Dialog.html)
-  * [Message boxes](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.MessageBox.html)
 * [Windows](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Window.html)
 * [Windows](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Window.html)
-* [Menus](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.MenuBar.html)
-* [ListViews](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ListView.html)
-* [Frames](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.FrameView.html)
-* [ProgressBars](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ProgressBar.html)
-* [Scroll views](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ScrollView.html) and [Scrollbars](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.ScrollBarView.html)
-* Hexadecimal viewer/editor (HexView)
-* Terminal Emulator - a complete Xterm/Vt100 terminal emulator that you can embed is now part of [XtermSharp](https://github.com/migueldeicaza/XtermSharp/blob/master/GuiCsHost/TerminalView.cs) - you just need to pull the `TerminalView` linked here into your project.
 
 
-All visible UI elements are subclasses of the
-[View](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.View.html),
-and these in turn can contain an arbitrary number of subviews.   
+In addition, a complete Xterm/Vt100 terminal emulator that you can embed is now part of [XtermSharp](https://github.com/migueldeicaza/XtermSharp/blob/master/GuiCsHost/TerminalView.cs) - you just need to pull the `TerminalView` linked here into your project.
 
 
-It comes with a
-[mainloop](https://migueldeicaza.github.io/gui.cs/api/Mono.Terminal/Mono.Terminal.MainLoop.html)
-to process events, process idle handlers, timers and monitoring file
+### Features
+
+* **Cross Platform** - Terminal drivers for Curses, [Windows Console](https://github.com/migueldeicaza/gui.cs/issues/27), and the .NET Console mean **Terminal.Gui** works well on both color and monochrome terminals and has mouse support on terminal emulators that support it.
+* **Keyboard and Mouse Input** - Both keyboard and mouse input are supported, including limited support for drag & drop.
+* **[Flexible Layout](https://migueldeicaza.github.io/gui.cs/articles/overview.html#layout)** - **Terminal.Gui** supports both *Absolute layout* and an innovative UI layout system referred to as *Computed Layout*. *Computed Layout* makes it easy to layout controls relative to each other and enables dynamic console GUIs.
+* **Clipboard support** - Cut, Copy, and Paste of text provided through the [`Clipboard`](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Clipboard.html) class.
+* **[Arbitrary Views](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.View.html)** - All visible UI elements are subclasses of the `View` class, and these in turn can contain an arbitrary number of sub-views.
+* **Advanced App Features** - The [Mainloop](https://migueldeicaza.github.io/gui.cs/api/Mono.Terminal/Mono.Terminal.MainLoop.html) supports processing events, idle handlers, timers, and monitoring file
 descriptors.
 descriptors.
 
 
-It is designed to work on Curses and the [Windows Console](https://github.com/migueldeicaza/gui.cs/issues/27), 
-works well on both color and monochrome terminals and has mouse support on
-terminal emulators that support it.
+### Keyboard Input Handling
+
+The input handling of **Terminal.Gui** is similar in some ways to Emacs and the Midnight Commander, so you can expect some of the special key combinations to be active.
+
+The key `ESC` can act as an Alt modifier (or Meta in Emacs parlance), to allow input on terminals that do not have an alt key.  So to produce the sequence `Alt-F`, you can press either `Alt-F`, or `ESC` followed by the key `F`.
+
+To enter the key `ESC`, you can either press `ESC` and wait 100 milliseconds, or you can press `ESC` twice.
+
+`ESC-0`, and `ESC-1` through `ESC-9` have a special meaning, they map to `F10`, and `F1` to `F9` respectively.
 
 
-# Documentation
+**Terminal.Gui** respects common Mac and Windows keyboard idoms as well. For example, clipboard operations use the familiar `Control/Command-C, X, V` model.
 
 
-* [API documentation](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui.html) for details.
+`CTRL-Q` is used for exiting views (and apps).
 
 
-* [Overview](https://migueldeicaza.github.io/gui.cs/articles/overview.html) contains the conceptual
-  documentation and a walkthrough of the core concepts of `gui.cs`
+### Driver model
 
 
-# Sample Usage
+Currently **Terminal.Gui** has support for [ncurses](https://github.com/migueldeicaza/gui.cs/blob/master/Terminal.Gui/Drivers/CursesDriver.cs), [`System.Console`](https://github.com/migueldeicaza/gui.cs/blob/master/Terminal.Gui/Drivers/NetDriver.cs), and a full [Win32 Console](https://github.com/migueldeicaza/gui.cs/blob/master/Terminal.Gui/Drivers/WindowsDriver.cs) front-end.
+
+`ncurses` is used on Mac/Linux/Unix with color support based on what your library is compiled with; the Windows driver supports full color and mouse, and an easy-to-debug `System.Console` can be used on Windows and Unix, but lacks mouse support.
+
+You can force the use of `System.Console` on Unix as well; see `Core.cs`.
+
+## Showcase & Examples
+
+* **UI Catalog** - The [UI Catalog project](https://github.com/migueldeicaza/gui.cs/tree/master/UICatalog) provides an easy to use and extend sample illustrating the capabilities of **Terminal.Gui**. Run `dotnet run` in the `UICatalog` directory to run the UI Catalog.
+* **Example (aka `demo.cs`)** - Run `dotnet run` in the `Example` directory to run the simple demo.
+* **Standalone Example** - A trivial .NET core sample application can be found in the `StandaloneExample` directory. Run `dotnet run` in directory to test.
+
+## Documentation
+
+* [API documentation](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui.html)
+
+* [Overview](https://migueldeicaza.github.io/gui.cs/articles/overview.html) contains the conceptual documentation and a walkthrough of the core concepts of **Terminal.Gui**.
+
+### Sample Usage
 
 
 ```csharp
 ```csharp
 using Terminal.Gui;
 using Terminal.Gui;
@@ -125,8 +150,7 @@ class Demo {
 }
 }
 ```
 ```
 
 
-Alternatively, you can encapsulate the app behavior in a new `Window`-derived class, 
-say `App.cs` containing the code above, and simplify your `Main` method to:
+Alternatively, you can encapsulate the app behavior in a new `Window`-derived class, say `App.cs` containing the code above, and simplify your `Main` method to:
 
 
 ```csharp
 ```csharp
 using Terminal.Gui;
 using Terminal.Gui;
@@ -139,78 +163,26 @@ class Demo {
 }
 }
 ```
 ```
 
 
-The example above shows how to add views, two styles are used, a very
-nice layout system that I have no name for, but that [is
-documented](https://migueldeicaza.github.io/gui.cs/articles/overview.html#layout),
-and the absolute positioning.
-
-# Installing it
-
-If you want to try Gui.cs, use NuGet to install the `Terminal.Gui` NuGet package:
-
-https://www.nuget.org/packages/Terminal.Gui
+The example above shows how to add views using both styles of layout supported by **Terminal.Gui**: **Absolute layout** and **[Computed layout](https://migueldeicaza.github.io/gui.cs/articles/overview.html#layout)**.
 
 
-# Running and Building
+## Installing
 
 
-You can find a trivial .NET core sample application in the
-"StandaloneExample" directory.   You can execute it by running
-`dotnet run` in that directory.
+Use NuGet to install the `Terminal.Gui` NuGet package: https://www.nuget.org/packages/Terminal.Gui
 
 
-That sample relies on the distributed NuGet package, if you want to
-to use the code on GitHub, you can open the Example program which 
-references the library built out of this tree.
+## Running and Building
 
 
-# Input Handling
+* *`Terminal.Gui`* - Build and run using the .NET SDK command line tools (`doetnet build` in the root directory) or with Visual Studio 2019.
 
 
-The input handling of gui.cs is similar in some ways to Emacs and the
-Midnight Commander, so you can expect some of the special key
-combinations to be active.
+## Contributing
 
 
-The key `ESC` can act as an Alt modifier (or Meta in Emacs parlance), to
-allow input on terminals that do not have an alt key.  So to produce
-the sequence `Alt-F`, you can press either `Alt-F`, or `ESC` followed by the key `F`.
+See [Issues](https://github.com/migueldeicaza/gui.cs/issues) for a list of open bugs and enhancements.
 
 
-To enter the key `ESC`, you can either press `ESC` and wait 100
-milliseconds, or you can press `ESC` twice.
+## History
 
 
-`ESC-0`, and `ESC-1` through `ESC-9` have a special meaning, they map to
-`F10`, and `F1` to `F9` respectively.
+This is an updated version of [gui.cs](http://tirania.org/blog/archive/2007/Apr-16.html) that Miguel wrote for [mono-curses](https://github.com/mono/mono-curses) in 2007.
 
 
-# Driver model
+The original **gui.cs** was a UI toolkit in a single file and tied to curses. This version tries to be console-agnostic and instead of having a container/widget model, only uses Views (which can contain subviews) and changes the rendering model to rely on damage regions instead of burdening each view with the details.
 
 
-Currently gui.cs has support for ncurses, `System.Console` and a full
-Win32 console front-end.
-
-ncurses is used on Unix with color support based on what your library
-is compiled with;   The windows driver supports full color and mouse, and
-an easy-to-debug `System.Console` can be used on Windows and Unix, but
-lacks mouse support.
-
-You can force the use of `System.Console` on Unix as
-well, see `Core.cs`.   
-
-# Tasks
-
-There are some tasks in the github issues, and some others are being
-tracked in the TODO.md file.
-
-# History
-
-This is an updated version of
-[gui.cs](http://tirania.org/blog/archive/2007/Apr-16.html) that
-I wrote for [mono-curses](https://github.com/mono/mono-curses) in 2007.
-
-The original gui.cs was a UI toolkit in a single file and tied to
-curses.  This version tries to be console-agnostic and instead of
-having a container/widget model, only uses Views (which can contain
-subviews) and changes the rendering model to rely on damage regions
-instead of burderning each view with the details.
-
-# Releases
-
-Recently, I setup VSTS to do the releases, for now, this requires a
-branch to be pushed with the name release/XXX, do this after the NuGet
-package version has been updated on the
-Terminal.Gui/Terminal.Gui.csproj, and push.
+A presentation of this was part of the [Retro.NET](https://channel9.msdn.com/Events/dotnetConf/2018/S313) talk at .NET Conf 2018 [Slides](https://tirania.org/Retro.pdf)
 
 
-Then once the package is built, VSTS will request an approval.
+Release history can be found in the [Terminal.Gui.csproj](https://github.com/migueldeicaza/gui.cs/blob/master/Terminal.Gui/Terminal.Gui.csproj) file.

+ 2 - 5
StandaloneExample/README.md

@@ -1,5 +1,4 @@
-This is just a simple standalone sample that shows how to consume
-the gui.cs from a NuGet package and .NET Core project.
+This is just a simple standalone sample that shows how to consume Terinal.Gui from a NuGet package and .NET Core project.
 
 
 Simply run:
 Simply run:
 
 
@@ -7,6 +6,4 @@ Simply run:
 $ dotnet run
 $ dotnet run
 ```
 ```
 
 
-To launch the application.   
-
-Or use Visual Studio, open the solution and run.
+To launch the application. Or use Visual Studio, open the solution and run.

+ 0 - 48
TODO.md

@@ -1,48 +0,0 @@
-
-# Things missing
-
-## Color System
-
-Topics to debate.
-
-Given that we need pairs of foreground/background to be set when
-operating on a view, should we surface the values independently, or
-should we surface the attribute?
-
-Currently views hardcode the colors to Colors.Base.SOmething for
-example, perhaps these should be set with styles instead, or even
-inheriting them.
-
-The reason why the Colors definition is useful is because it comes with
-defaults that work for both color and black and white and other limited
-terminals.  Setting foreground/background independently tends to break
-the black and white scenarios.
-
-## Color and Dialogs
-
-Replaces `Colors.Base.Normal` with `Attributes.Normal`, and perhaps attributes
-points to the container.
-
-## Views
-
-Wanted:
-- HotLabels (should be labelsw ith a hotkey that take a focus view as an argument)
-- Shell/Process?
-- Submenus in menus.
-- Make windows draggable
-- View + Attribute for SolidFills?
-
-Should Views support Padding/Margin/Border?   Would make it simpler for Forms backend and perhaps
-adopt the Forms CSS as-is
-
-## Layout manager
-
-Unclear what to do about that right now.  Perhaps use Flex?
-
-Will at least need the protocol for sizing 
-
-# Merge Responder into View
-
-For now it is split, in case we want to introduce formal view
-controllers.  But the design becomes very ugly.
-

+ 115 - 69
Terminal.Gui/Core.cs

@@ -126,7 +126,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
 		/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
 		/// <returns>true if the event was handled</returns>
 		/// <returns>true if the event was handled</returns>
-		public virtual bool KeyDown (KeyEvent keyEvent)
+		public virtual bool OnKeyDown (KeyEvent keyEvent)
 		{
 		{
 			return false;
 			return false;
 		}
 		}
@@ -136,7 +136,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
 		/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
 		/// <returns>true if the event was handled</returns>
 		/// <returns>true if the event was handled</returns>
-		public virtual bool KeyUp (KeyEvent keyEvent)
+		public virtual bool OnKeyUp (KeyEvent keyEvent)
 		{
 		{
 			return false;
 			return false;
 		}
 		}
@@ -607,7 +607,7 @@ namespace Terminal.Gui {
 				return;
 				return;
 
 
 			while (subviews.Count > 0) {
 			while (subviews.Count > 0) {
-				Remove (subviews[0]);
+				Remove (subviews [0]);
 			}
 			}
 		}
 		}
 
 
@@ -705,9 +705,9 @@ namespace Terminal.Gui {
 		{
 		{
 			PerformActionForSubview (subview, x => {
 			PerformActionForSubview (subview, x => {
 				var idx = subviews.IndexOf (x);
 				var idx = subviews.IndexOf (x);
-				if (idx+1 < subviews.Count) {
+				if (idx + 1 < subviews.Count) {
 					subviews.Remove (x);
 					subviews.Remove (x);
-					subviews.Insert (idx+1, x);
+					subviews.Insert (idx + 1, x);
 				}
 				}
 			});
 			});
 		}
 		}
@@ -910,7 +910,7 @@ namespace Terminal.Gui {
 						OnEnter ();
 						OnEnter ();
 					else
 					else
 						OnLeave ();
 						OnLeave ();
-					SetNeedsDisplay ();
+				SetNeedsDisplay ();
 				base.HasFocus = value;
 				base.HasFocus = value;
 
 
 				// Remove focus down the chain of subviews if focus is removed
 				// Remove focus down the chain of subviews if focus is removed
@@ -1062,18 +1062,33 @@ namespace Terminal.Gui {
 			focused.EnsureFocus ();
 			focused.EnsureFocus ();
 
 
 			// Send focus upwards
 			// Send focus upwards
-			SuperView?.SetFocus(this);
+			SuperView?.SetFocus (this);
+		}
+
+		/// <summary>
+		/// Specifies 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>
 		/// <summary>
 		/// Invoked when a character key is pressed and occurs after the key up event.
 		/// Invoked when a character key is pressed and occurs after the key up event.
 		/// </summary>
 		/// </summary>
-		public Action<KeyEvent> OnKeyPress;
+		public event EventHandler<KeyEventEventArgs> KeyPress;
 
 
 		/// <inheritdoc cref="ProcessKey"/>
 		/// <inheritdoc cref="ProcessKey"/>
 		public override bool ProcessKey (KeyEvent keyEvent)
 		public override bool ProcessKey (KeyEvent keyEvent)
 		{
 		{
-			OnKeyPress?.Invoke (keyEvent);
+			KeyPress?.Invoke (this, new KeyEventEventArgs(keyEvent));
 			if (Focused?.ProcessKey (keyEvent) == true)
 			if (Focused?.ProcessKey (keyEvent) == true)
 				return true;
 				return true;
 
 
@@ -1083,6 +1098,7 @@ namespace Terminal.Gui {
 		/// <inheritdoc cref="ProcessHotKey"/>
 		/// <inheritdoc cref="ProcessHotKey"/>
 		public override bool ProcessHotKey (KeyEvent keyEvent)
 		public override bool ProcessHotKey (KeyEvent keyEvent)
 		{
 		{
+			KeyPress?.Invoke (this, new KeyEventEventArgs (keyEvent));
 			if (subviews == null || subviews.Count == 0)
 			if (subviews == null || subviews.Count == 0)
 				return false;
 				return false;
 			foreach (var view in subviews)
 			foreach (var view in subviews)
@@ -1094,6 +1110,7 @@ namespace Terminal.Gui {
 		/// <inheritdoc cref="ProcessColdKey"/>
 		/// <inheritdoc cref="ProcessColdKey"/>
 		public override bool ProcessColdKey (KeyEvent keyEvent)
 		public override bool ProcessColdKey (KeyEvent keyEvent)
 		{
 		{
+			KeyPress?.Invoke (this, new KeyEventEventArgs(keyEvent));
 			if (subviews == null || subviews.Count == 0)
 			if (subviews == null || subviews.Count == 0)
 				return false;
 				return false;
 			foreach (var view in subviews)
 			foreach (var view in subviews)
@@ -1105,16 +1122,16 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Invoked when a key is pressed
 		/// Invoked when a key is pressed
 		/// </summary>
 		/// </summary>
-		public Action<KeyEvent> OnKeyDown;
+		public event EventHandler<KeyEventEventArgs> KeyDown;
 
 
-		/// <inheritdoc cref="KeyDown"/>
-		public override bool KeyDown (KeyEvent keyEvent)
+		/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
+		public override bool OnKeyDown (KeyEvent keyEvent)
 		{
 		{
-			OnKeyDown?.Invoke (keyEvent);
+			KeyDown?.Invoke (this, new KeyEventEventArgs (keyEvent));
 			if (subviews == null || subviews.Count == 0)
 			if (subviews == null || subviews.Count == 0)
 				return false;
 				return false;
 			foreach (var view in subviews)
 			foreach (var view in subviews)
-				if (view.KeyDown (keyEvent))
+				if (view.OnKeyDown (keyEvent))
 					return true;
 					return true;
 
 
 			return false;
 			return false;
@@ -1123,16 +1140,16 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Invoked when a key is released
 		/// Invoked when a key is released
 		/// </summary>
 		/// </summary>
-		public Action<KeyEvent> OnKeyUp;
+		public event EventHandler<KeyEventEventArgs> KeyUp;
 
 
-		/// <inheritdoc cref="KeyUp"/>
-		public override bool KeyUp (KeyEvent keyEvent)
+		/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
+		public override bool OnKeyUp (KeyEvent keyEvent)
 		{
 		{
-			OnKeyUp?.Invoke (keyEvent);
+			KeyUp?.Invoke (this, new KeyEventEventArgs (keyEvent));
 			if (subviews == null || subviews.Count == 0)
 			if (subviews == null || subviews.Count == 0)
 				return false;
 				return false;
 			foreach (var view in subviews)
 			foreach (var view in subviews)
-				if (view.KeyUp (keyEvent))
+				if (view.OnKeyUp (keyEvent))
 					return true;
 					return true;
 
 
 			return false;
 			return false;
@@ -1174,7 +1191,7 @@ namespace Terminal.Gui {
 		public void FocusLast ()
 		public void FocusLast ()
 		{
 		{
 			if (subviews == null) {
 			if (subviews == null) {
-				SuperView?.SetFocus(this);
+				SuperView?.SetFocus (this);
 				return;
 				return;
 			}
 			}
 
 
@@ -1221,7 +1238,7 @@ namespace Terminal.Gui {
 						w.FocusLast ();
 						w.FocusLast ();
 
 
 					SetFocus (w);
 					SetFocus (w);
-				return true;
+					return true;
 				}
 				}
 			}
 			}
 			if (focused != null) {
 			if (focused != null) {
@@ -1538,12 +1555,12 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Check id current toplevel has menu bar
 		/// Check id current toplevel has menu bar
 		/// </summary>
 		/// </summary>
-		public bool HasMenuBar { get; set; }
+		public MenuBar MenuBar { get; set; }
 
 
 		/// <summary>
 		/// <summary>
 		/// Check id current toplevel has status bar
 		/// Check id current toplevel has status bar
 		/// </summary>
 		/// </summary>
-		public bool HasStatusBar { get; set; }
+		public StatusBar StatusBar { get; set; }
 
 
 		///<inheritdoc cref="ProcessKey"/>
 		///<inheritdoc cref="ProcessKey"/>
 		public override bool ProcessKey (KeyEvent keyEvent)
 		public override bool ProcessKey (KeyEvent keyEvent)
@@ -1602,9 +1619,9 @@ namespace Terminal.Gui {
 		{
 		{
 			if (this == Application.Top) {
 			if (this == Application.Top) {
 				if (view is MenuBar)
 				if (view is MenuBar)
-					HasMenuBar = true;
+					MenuBar = view as MenuBar;
 				if (view is StatusBar)
 				if (view is StatusBar)
-					HasStatusBar = true;
+					StatusBar = view as StatusBar;
 			}
 			}
 			base.Add (view);
 			base.Add (view);
 		}
 		}
@@ -1614,9 +1631,9 @@ namespace Terminal.Gui {
 		{
 		{
 			if (this == Application.Top) {
 			if (this == Application.Top) {
 				if (view is MenuBar)
 				if (view is MenuBar)
-					HasMenuBar = true;
+					MenuBar = null;
 				if (view is StatusBar)
 				if (view is StatusBar)
-					HasStatusBar = true;
+					StatusBar = null;
 			}
 			}
 			base.Remove (view);
 			base.Remove (view);
 		}
 		}
@@ -1625,8 +1642,8 @@ namespace Terminal.Gui {
 		public override void RemoveAll ()
 		public override void RemoveAll ()
 		{
 		{
 			if (this == Application.Top) {
 			if (this == Application.Top) {
-				HasMenuBar = false;
-				HasStatusBar = false;
+				MenuBar = null;
+				StatusBar = null;
 			}
 			}
 			base.RemoveAll ();
 			base.RemoveAll ();
 		}
 		}
@@ -1634,21 +1651,21 @@ namespace Terminal.Gui {
 		internal void EnsureVisibleBounds (Toplevel top, int x, int y, out int nx, out int ny)
 		internal void EnsureVisibleBounds (Toplevel top, int x, int y, out int nx, out int ny)
 		{
 		{
 			nx = Math.Max (x, 0);
 			nx = Math.Max (x, 0);
-			nx = nx + top.Frame.Width > Driver.Cols ? Math.Max(Driver.Cols - top.Frame.Width, 0) : nx;
+			nx = nx + top.Frame.Width > Driver.Cols ? Math.Max (Driver.Cols - top.Frame.Width, 0) : nx;
 			bool m, s;
 			bool m, s;
-			if (SuperView == null)
-				m = Application.Top.HasMenuBar;
+			if (SuperView == null || SuperView.GetType() != typeof(Toplevel))
+				m = Application.Top.MenuBar != null;
 			else
 			else
-				m = ((Toplevel)SuperView).HasMenuBar;
+				m = ((Toplevel)SuperView).MenuBar != null;
 			int l = m ? 1 : 0;
 			int l = m ? 1 : 0;
 			ny = Math.Max (y, l);
 			ny = Math.Max (y, l);
-			if (SuperView == null)
-				s = Application.Top.HasStatusBar;
+			if (SuperView == null || SuperView.GetType() != typeof(Toplevel))
+				s = Application.Top.StatusBar != null;
 			else
 			else
-				s = ((Toplevel)SuperView).HasStatusBar;
+				s = ((Toplevel)SuperView).StatusBar != null;
 			l = s ? Driver.Rows - 1 : Driver.Rows;
 			l = s ? Driver.Rows - 1 : Driver.Rows;
 			ny = Math.Min (ny, l);
 			ny = Math.Min (ny, l);
-			ny = ny + top.Frame.Height > l ? Math.Max(l - top.Frame.Height, m ? 1 : 0) : ny;
+			ny = ny + top.Frame.Height > l ? Math.Max (l - top.Frame.Height, m ? 1 : 0) : ny;
 		}
 		}
 
 
 		internal void PositionToplevels ()
 		internal void PositionToplevels ()
@@ -1667,9 +1684,15 @@ namespace Terminal.Gui {
 							top.X = nx;
 							top.X = nx;
 							top.Y = ny;
 							top.Y = ny;
 						}
 						}
-						if (HasStatusBar && ny + top.Frame.Height > Driver.Rows - 1) {
-							if (top.Height is Dim.DimFill)
-								top.Height = Dim.Fill () - 1;
+						if (StatusBar != null) {
+							if (ny + top.Frame.Height > Driver.Rows - 1) {
+								if (top.Height is Dim.DimFill)
+									top.Height = Dim.Fill () - 1;
+							}
+							if (StatusBar.Frame.Y != Driver.Rows - 1) {
+								StatusBar.Y = Driver.Rows - 1;
+								SetNeedsDisplay ();
+							}
 						}
 						}
 					}
 					}
 				}
 				}
@@ -1681,7 +1704,7 @@ namespace Terminal.Gui {
 		{
 		{
 			Application.CurrentView = this;
 			Application.CurrentView = this;
 
 
-			if (this == Application.Top) {
+			if (this == Application.Top || this == Application.Current) {
 				if (!NeedDisplay.IsEmpty) {
 				if (!NeedDisplay.IsEmpty) {
 					Driver.SetAttribute (Colors.TopLevel.Normal);
 					Driver.SetAttribute (Colors.TopLevel.Normal);
 					Clear (region);
 					Clear (region);
@@ -1796,7 +1819,7 @@ namespace Terminal.Gui {
 			this.Title = title;
 			this.Title = title;
 			int wb = 1 + padding;
 			int wb = 1 + padding;
 			this.padding = padding;
 			this.padding = padding;
- 			contentView = new ContentView () {
+			contentView = new ContentView () {
 				X = wb,
 				X = wb,
 				Y = wb,
 				Y = wb,
 				Width = Dim.Fill (wb),
 				Width = Dim.Fill (wb),
@@ -2008,7 +2031,7 @@ namespace Terminal.Gui {
 		/// <remarks>
 		/// <remarks>
 		///   See also <see cref="Timeout"/>
 		///   See also <see cref="Timeout"/>
 		/// </remarks>
 		/// </remarks>
-		static public event EventHandler Iteration;
+		public static event EventHandler Iteration;
 
 
 		/// <summary>
 		/// <summary>
 		/// Returns a rectangle that is centered in the screen for the provided size.
 		/// Returns a rectangle that is centered in the screen for the provided size.
@@ -2079,7 +2102,7 @@ namespace Terminal.Gui {
 			if (UseSystemConsole) {
 			if (UseSystemConsole) {
 				mainLoopDriver = new Mono.Terminal.NetMainLoop ();
 				mainLoopDriver = new Mono.Terminal.NetMainLoop ();
 				Driver = new NetDriver ();
 				Driver = new NetDriver ();
-			} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows){
+			} else if (p == PlatformID.Win32NT || p == PlatformID.Win32S || p == PlatformID.Win32Windows) {
 				var windowsDriver = new WindowsDriver ();
 				var windowsDriver = new WindowsDriver ();
 				mainLoopDriver = windowsDriver;
 				mainLoopDriver = windowsDriver;
 				Driver = windowsDriver;
 				Driver = windowsDriver;
@@ -2137,7 +2160,7 @@ namespace Terminal.Gui {
 		static void ProcessKeyEvent (KeyEvent ke)
 		static void ProcessKeyEvent (KeyEvent ke)
 		{
 		{
 
 
-			var chain = toplevels.ToList();
+			var chain = toplevels.ToList ();
 			foreach (var topLevel in chain) {
 			foreach (var topLevel in chain) {
 				if (topLevel.ProcessHotKey (ke))
 				if (topLevel.ProcessHotKey (ke))
 					return;
 					return;
@@ -2165,7 +2188,7 @@ namespace Terminal.Gui {
 		{
 		{
 			var chain = toplevels.ToList ();
 			var chain = toplevels.ToList ();
 			foreach (var topLevel in chain) {
 			foreach (var topLevel in chain) {
-				if (topLevel.KeyDown (ke))
+				if (topLevel.OnKeyDown (ke))
 					return;
 					return;
 				if (topLevel.Modal)
 				if (topLevel.Modal)
 					break;
 					break;
@@ -2177,7 +2200,7 @@ namespace Terminal.Gui {
 		{
 		{
 			var chain = toplevels.ToList ();
 			var chain = toplevels.ToList ();
 			foreach (var topLevel in chain) {
 			foreach (var topLevel in chain) {
-				if (topLevel.KeyUp (ke))
+				if (topLevel.OnKeyUp (ke))
 					return;
 					return;
 				if (topLevel.Modal)
 				if (topLevel.Modal)
 					break;
 					break;
@@ -2194,7 +2217,7 @@ namespace Terminal.Gui {
 				return null;
 				return null;
 			}
 			}
 
 
-			if (start.InternalSubviews != null){
+			if (start.InternalSubviews != null) {
 				int count = start.InternalSubviews.Count;
 				int count = start.InternalSubviews.Count;
 				if (count > 0) {
 				if (count > 0) {
 					var rx = x - startFrame.X;
 					var rx = x - startFrame.X;
@@ -2210,8 +2233,8 @@ namespace Terminal.Gui {
 					}
 					}
 				}
 				}
 			}
 			}
-			resx = x-startFrame.X;
-			resy = y-startFrame.Y;
+			resx = x - startFrame.X;
+			resy = y - startFrame.Y;
 			return start;
 			return start;
 		}
 		}
 
 
@@ -2242,7 +2265,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Merely a debugging aid to see the raw mouse events
 		/// Merely a debugging aid to see the raw mouse events
 		/// </summary>
 		/// </summary>
-		static public Action<MouseEvent> RootMouseEvent;
+		public static Action<MouseEvent> RootMouseEvent;
 
 
 		internal static View wantContinuousButtonPressedView;
 		internal static View wantContinuousButtonPressedView;
 		static View lastMouseOwnerView;
 		static View lastMouseOwnerView;
@@ -2267,8 +2290,12 @@ namespace Terminal.Gui {
 					OfY = me.Y - newxy.Y,
 					OfY = me.Y - newxy.Y,
 					View = view
 					View = view
 				};
 				};
-				mouseGrabView.MouseEvent (nme);
-				return;
+				if (OutsideFrame (new Point (nme.X, nme.Y), mouseGrabView.Frame))
+					lastMouseOwnerView.OnMouseLeave (me);
+				if (mouseGrabView != null) {
+					mouseGrabView.MouseEvent (nme);
+					return;
+				}
 			}
 			}
 
 
 			if (view != null) {
 			if (view != null) {
@@ -2303,10 +2330,16 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
+		static bool OutsideFrame (Point p, Rect r)
+		{
+			return p.X < 0 || p.X > r.Width - 1 || p.Y < 0 || p.Y > r.Height - 1;
+		}
+
 		/// <summary>
 		/// <summary>
-		/// Action that is invoked once at beginning.
+		/// This event is fired once when the application is first loaded. The dimensions of the
+		/// terminal are provided.
 		/// </summary>
 		/// </summary>
-		static public Action OnLoad;
+		public static event EventHandler<ResizedEventArgs> Loaded;
 
 
 		/// <summary>
 		/// <summary>
 		/// Building block API: Prepares the provided toplevel for execution.
 		/// Building block API: Prepares the provided toplevel for execution.
@@ -2321,7 +2354,7 @@ namespace Terminal.Gui {
 		///  the <see cref="RunLoop"/> method, and then the <see cref="End(RunState)"/> method upon termination which will
 		///  the <see cref="RunLoop"/> method, and then the <see cref="End(RunState)"/> method upon termination which will
 		///   undo these changes.
 		///   undo these changes.
 		/// </remarks>
 		/// </remarks>
-		static public RunState Begin (Toplevel toplevel)
+		public static RunState Begin (Toplevel toplevel)
 		{
 		{
 			if (toplevel == null)
 			if (toplevel == null)
 				throw new ArgumentNullException (nameof (toplevel));
 				throw new ArgumentNullException (nameof (toplevel));
@@ -2330,11 +2363,11 @@ namespace Terminal.Gui {
 			Init ();
 			Init ();
 			if (toplevel is ISupportInitializeNotification initializableNotification &&
 			if (toplevel is ISupportInitializeNotification initializableNotification &&
 			    !initializableNotification.IsInitialized) {
 			    !initializableNotification.IsInitialized) {
-				initializableNotification.BeginInit();
-				initializableNotification.EndInit();
+				initializableNotification.BeginInit ();
+				initializableNotification.EndInit ();
 			} else if (toplevel is ISupportInitialize initializable) {
 			} else if (toplevel is ISupportInitialize initializable) {
-				initializable.BeginInit();
-				initializable.EndInit();
+				initializable.BeginInit ();
+				initializable.EndInit ();
 			}
 			}
 			toplevels.Push (toplevel);
 			toplevels.Push (toplevel);
 			Current = toplevel;
 			Current = toplevel;
@@ -2342,7 +2375,7 @@ namespace Terminal.Gui {
 			if (toplevel.LayoutStyle == LayoutStyle.Computed)
 			if (toplevel.LayoutStyle == LayoutStyle.Computed)
 				toplevel.RelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
 				toplevel.RelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
 			toplevel.LayoutSubviews ();
 			toplevel.LayoutSubviews ();
-			OnLoad?.Invoke ();
+			Loaded?.Invoke (null, new ResizedEventArgs () { Rows = Driver.Rows, Cols = Driver.Cols } );
 			toplevel.WillPresent ();
 			toplevel.WillPresent ();
 			Redraw (toplevel);
 			Redraw (toplevel);
 			toplevel.PositionCursor ();
 			toplevel.PositionCursor ();
@@ -2355,7 +2388,7 @@ namespace Terminal.Gui {
 		/// Building block API: completes the execution of a Toplevel that was started with Begin.
 		/// Building block API: completes the execution of a Toplevel that was started with Begin.
 		/// </summary>
 		/// </summary>
 		/// <param name="runState">The runstate returned by the <see cref="Begin(Toplevel)"/> method.</param>
 		/// <param name="runState">The runstate returned by the <see cref="Begin(Toplevel)"/> method.</param>
-		static public void End (RunState runState)
+		public static void End (RunState runState)
 		{
 		{
 			if (runState == null)
 			if (runState == null)
 				throw new ArgumentNullException (nameof (runState));
 				throw new ArgumentNullException (nameof (runState));
@@ -2409,9 +2442,8 @@ namespace Terminal.Gui {
 			toplevels.Pop ();
 			toplevels.Pop ();
 			if (toplevels.Count == 0)
 			if (toplevels.Count == 0)
 				Shutdown ();
 				Shutdown ();
-			else
-			{
-				Current = toplevels.Peek();
+			else {
+				Current = toplevels.Peek ();
 				Refresh ();
 				Refresh ();
 			}
 			}
 		}
 		}
@@ -2480,7 +2512,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public static void Run<T> () where T : Toplevel, new()
 		public static void Run<T> () where T : Toplevel, new()
 		{
 		{
-			Init (() => new T());
+			Init (() => new T ());
 			Run (Top);
 			Run (Top);
 		}
 		}
 
 
@@ -2525,14 +2557,28 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Invoked when the terminal was resized.
+		/// Event arguments for the <see cref="T:Terminal.Gui.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>
 		/// </summary>
-		static public Action OnResized;
+		public static event EventHandler<ResizedEventArgs> Resized;
 
 
 		static void TerminalResized ()
 		static void TerminalResized ()
 		{
 		{
-			OnResized?.Invoke ();
 			var full = new Rect (0, 0, Driver.Cols, Driver.Rows);
 			var full = new Rect (0, 0, Driver.Cols, Driver.Rows);
+			Resized?.Invoke (null, new ResizedEventArgs () { Cols = full.Width, Rows = full.Height });
 			Driver.Clip = full;
 			Driver.Clip = full;
 			foreach (var t in toplevels) {
 			foreach (var t in toplevels) {
 				t.PositionToplevels ();
 				t.PositionToplevels ();

+ 190 - 11
Terminal.Gui/Drivers/CursesDriver.cs

@@ -7,6 +7,7 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
+using System.Threading.Tasks;
 using Mono.Terminal;
 using Mono.Terminal;
 using NStack;
 using NStack;
 using Unix.Terminal;
 using Unix.Terminal;
@@ -183,12 +184,185 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
-		static MouseEvent ToDriverMouse (Curses.MouseEvent cev)
+		Curses.Event? LastMouseButtonPressed = null;
+		bool IsButtonPressed = false;
+		bool cancelButtonClicked = false;
+		Point point;
+
+		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.Button1Clicked || cev.ButtonState == Curses.Event.Button2Clicked ||
+				cev.ButtonState == Curses.Event.Button3Clicked) &&
+				LastMouseButtonPressed == null) {
+
+				IsButtonPressed = false;
+				mouseFlag = ProcessButtonClickedEvent (cev, mouseFlag);
+
+			} else if (((cev.ButtonState == Curses.Event.Button1Pressed || cev.ButtonState == Curses.Event.Button2Pressed ||
+				cev.ButtonState == Curses.Event.Button3Pressed) && LastMouseButtonPressed == null) ||
+				IsButtonPressed && cev.ButtonState == Curses.Event.ReportMousePosition) {
+
+				mouseFlag = (MouseFlags)cev.ButtonState;
+				if (cev.ButtonState != Curses.Event.ReportMousePosition)
+					LastMouseButtonPressed = cev.ButtonState;
+				IsButtonPressed = true;
+
+				if (cev.ButtonState == Curses.Event.ReportMousePosition) {
+					mouseFlag = (MouseFlags)LastMouseButtonPressed | MouseFlags.ReportMousePosition;
+					point = new Point ();
+					cancelButtonClicked = true;
+				} else {
+					point = new Point () {
+						X = cev.X,
+						Y = cev.Y
+					};
+				}
+
+				if ((mouseFlag & MouseFlags.ReportMousePosition) == 0) {
+					Task.Run (async () => {
+						while (IsButtonPressed && LastMouseButtonPressed != null) {
+							await Task.Delay (200);
+							var me = new MouseEvent () {
+								X = cev.X,
+								Y = cev.Y,
+								Flags = mouseFlag
+							};
+
+							var view = Application.wantContinuousButtonPressedView;
+							if (view == null)
+								break;
+							if (IsButtonPressed && LastMouseButtonPressed != null && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
+								mouseHandler (me);
+								mainLoop.Driver.Wakeup ();
+							}
+						}
+					});
+				}
+
+
+			} else if ((cev.ButtonState == Curses.Event.Button1Released || cev.ButtonState == Curses.Event.Button2Released ||
+				cev.ButtonState == Curses.Event.Button3Released)) {
+
+				mouseFlag = ProcessButtonReleasedEvent (cev, mouseFlag);
+				IsButtonPressed = false;
+
+			} else if (cev.ButtonState == Curses.Event.Button4Pressed) {
+
+				mouseFlag = MouseFlags.WheeledUp;
+
+			} else if (cev.ButtonState == Curses.Event.ReportMousePosition && cev.X == point.X && cev.Y == point.Y) {
+
+				mouseFlag = MouseFlags.WheeledDown;
+
+			}
+			else if (cev.ButtonState == Curses.Event.ReportMousePosition) {
+
+				mouseFlag = MouseFlags.ReportMousePosition;
+			} else {
+				mouseFlag = (MouseFlags)cev.ButtonState;
+			}
+
+			point = new Point () {
+				X = cev.X,
+				Y = cev.Y
+			};
+
+
+
+			if (cev.ID != 0)
+				mouseFlag = MouseFlags.WheeledDown;
+
+			return new MouseEvent () {
+				X = cev.X,
+				Y = cev.Y,
+				//Flags = (MouseFlags)cev.ButtonState
+				Flags = mouseFlag
+			};
+		}
+
+		private MouseFlags ProcessButtonClickedEvent (Curses.MouseEvent cev, MouseFlags mf)
+		{
+			LastMouseButtonPressed = cev.ButtonState;
+			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 = (MouseFlags)cev.ButtonState;
+				}
+			}
+			LastMouseButtonPressed = null;
+			return mf;
+		}
+
+		private MouseFlags ProcessButtonReleasedEvent (Curses.MouseEvent cev, MouseFlags mf)
+		{			
+			mf = (MouseFlags)cev.ButtonState;
+			mouseHandler (ProcessButtonState (cev, mf));
+			if (!cancelButtonClicked && LastMouseButtonPressed == null)
+				mf = GetButtonState (cev);
+			else
+				cancelButtonClicked = false;
+			return mf;
+		}
+
+		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 () {
 			return new MouseEvent () {
 				X = cev.X,
 				X = cev.X,
 				Y = cev.Y,
 				Y = cev.Y,
-				Flags = (MouseFlags)cev.ButtonState
+				Flags = mf
 			};
 			};
 		}
 		}
 
 
@@ -252,10 +426,15 @@ namespace Terminal.Gui {
 			keyUpHandler (new KeyEvent ((Key)wch));
 			keyUpHandler (new KeyEvent ((Key)wch));
 		}
 		}
 
 
+		Action<MouseEvent> mouseHandler;
+		MainLoop mainLoop;
+
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
 		public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
 		{
 		{
 			// Note: Curses doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
 			// Note: Curses doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
-			Curses.timeout (-1);
+			Curses.timeout (0);
+			this.mouseHandler = mouseHandler;
+			this.mainLoop = mainLoop;
 
 
 			(mainLoop.Driver as Mono.Terminal.UnixMainLoop).AddWatch (0, Mono.Terminal.UnixMainLoop.Condition.PollIn, x => {
 			(mainLoop.Driver as Mono.Terminal.UnixMainLoop).AddWatch (0, Mono.Terminal.UnixMainLoop.Condition.PollIn, x => {
 				ProcessInput (keyHandler, keyUpHandler, mouseHandler);
 				ProcessInput (keyHandler, keyUpHandler, mouseHandler);
@@ -425,21 +604,21 @@ namespace Terminal.Gui {
 			Console.Out.Flush ();
 			Console.Out.Flush ();
 		}
 		}
 
 
-		int lastMouseInterval;
-		bool mouseGrabbed;
+		//int lastMouseInterval;
+		//bool mouseGrabbed;
 
 
 		public override void UncookMouse ()
 		public override void UncookMouse ()
 		{
 		{
-			if (mouseGrabbed)
-				return;
-			lastMouseInterval = Curses.mouseinterval (0);
-			mouseGrabbed = true;
+			//if (mouseGrabbed)
+			//	return;
+			//lastMouseInterval = Curses.mouseinterval (0);
+			//mouseGrabbed = true;
 		}
 		}
 
 
 		public override void CookMouse ()
 		public override void CookMouse ()
 		{
 		{
-			mouseGrabbed = false;
-			Curses.mouseinterval (lastMouseInterval);
+			//mouseGrabbed = false;
+			//Curses.mouseinterval (lastMouseInterval);
 		}
 		}
 	}
 	}
 
 

+ 2 - 2
Terminal.Gui/Drivers/WindowsDriver.cs

@@ -673,10 +673,10 @@ namespace Terminal.Gui {
 						keyUpHandler (key);
 						keyUpHandler (key);
 				} else {
 				} else {
 					if (inputEvent.KeyEvent.bKeyDown) {
 					if (inputEvent.KeyEvent.bKeyDown) {
+						// Key Down - Fire KeyDown Event and KeyStroke (ProcessKey) Event
+						keyHandler (new KeyEvent (map));
 						keyDownHandler (new KeyEvent (map));
 						keyDownHandler (new KeyEvent (map));
 					} else {
 					} else {
-						// Key Up - Fire KeyDown Event and KeyStroke (ProcessKey) Event
-						keyHandler (new KeyEvent (map));
 						keyUpHandler (new KeyEvent (map));
 						keyUpHandler (new KeyEvent (map));
 					}
 					}
 				}
 				}

+ 35 - 24
Terminal.Gui/MonoCurses/constants.cs

@@ -2,6 +2,8 @@
  * This file is autogenerated by the attrib.c program, do not edit
  * This file is autogenerated by the attrib.c program, do not edit
  */
  */
 
 
+#define XTERM1006
+
 using System;
 using System;
 
 
 namespace Unix.Terminal {
 namespace Unix.Terminal {
@@ -77,6 +79,15 @@ namespace Unix.Terminal {
 			ReportMousePosition = unchecked((int)0x8000000),
 			ReportMousePosition = unchecked((int)0x8000000),
 			AllEvents = unchecked((int)0x7ffffff),
 			AllEvents = unchecked((int)0x7ffffff),
 		}
 		}
+#if XTERM1006
+		public const int LeftRightUpNPagePPage= unchecked((int)0x8);
+		public const int DownEnd = unchecked((int)0x6);
+		public const int Home = unchecked((int)0x7);
+#else
+		public const int LeftRightUpNPagePPage= unchecked((int)0x0);
+		public const int DownEnd = unchecked((int)0x0);
+		public const int Home = unchecked((int)0x0);
+#endif
 		public const int ERR = unchecked((int)0xffffffff);
 		public const int ERR = unchecked((int)0xffffffff);
 		public const int KeyBackspace = unchecked((int)0x107);
 		public const int KeyBackspace = unchecked((int)0x107);
 		public const int KeyUp = unchecked((int)0x103);
 		public const int KeyUp = unchecked((int)0x103);
@@ -110,30 +121,30 @@ namespace Unix.Terminal {
 		public const int ShiftKeyPPage = unchecked((int)0x18e);
 		public const int ShiftKeyPPage = unchecked((int)0x18e);
 		public const int ShiftKeyHome = unchecked((int)0x187);
 		public const int ShiftKeyHome = unchecked((int)0x187);
 		public const int ShiftKeyEnd = unchecked((int)0x182);
 		public const int ShiftKeyEnd = unchecked((int)0x182);
-		public const int AltKeyUp = unchecked((int)0x234);
-		public const int AltKeyDown = unchecked((int)0x20b);
-		public const int AltKeyLeft = unchecked((int)0x21f);
-		public const int AltKeyRight = unchecked((int)0x22e);
-		public const int AltKeyNPage = unchecked((int)0x224);
-		public const int AltKeyPPage = unchecked((int)0x229);
-		public const int AltKeyHome = unchecked((int)0x215);
-		public const int AltKeyEnd = unchecked((int)0x210);
-		public const int CtrlKeyUp = unchecked((int)0x236);
-		public const int CtrlKeyDown = unchecked((int)0x20d);
-		public const int CtrlKeyLeft = unchecked((int)0x221);
-		public const int CtrlKeyRight = unchecked((int)0x230);
-		public const int CtrlKeyNPage = unchecked((int)0x226);
-		public const int CtrlKeyPPage = unchecked((int)0x22b);
-		public const int CtrlKeyHome = unchecked((int)0x217);
-		public const int CtrlKeyEnd = unchecked((int)0x212);
-		public const int ShiftCtrlKeyUp = unchecked((int)0x237);
-		public const int ShiftCtrlKeyDown = unchecked((int)0x20e);
-		public const int ShiftCtrlKeyLeft = unchecked((int)0x222);
-		public const int ShiftCtrlKeyRight = unchecked((int)0x231);
-		public const int ShiftCtrlKeyNPage = unchecked((int)0x227);
-		public const int ShiftCtrlKeyPPage = unchecked((int)0x22c);
-		public const int ShiftCtrlKeyHome = unchecked((int)0x218);
-		public const int ShiftCtrlKeyEnd = unchecked((int)0x213);
+		public const int AltKeyUp = unchecked((int)0x234 + LeftRightUpNPagePPage);
+		public const int AltKeyDown = unchecked((int)0x20b + DownEnd);
+		public const int AltKeyLeft = unchecked((int)0x21f + LeftRightUpNPagePPage);
+		public const int AltKeyRight = unchecked((int)0x22e + LeftRightUpNPagePPage);
+		public const int AltKeyNPage = unchecked((int)0x224 + LeftRightUpNPagePPage);
+		public const int AltKeyPPage = unchecked((int)0x229 + LeftRightUpNPagePPage);
+		public const int AltKeyHome = unchecked((int)0x215 + Home);
+		public const int AltKeyEnd = unchecked((int)0x210 + DownEnd);
+		public const int CtrlKeyUp = unchecked((int)0x236 + LeftRightUpNPagePPage);
+		public const int CtrlKeyDown = unchecked((int)0x20d + DownEnd);
+		public const int CtrlKeyLeft = unchecked((int)0x221 + LeftRightUpNPagePPage);
+		public const int CtrlKeyRight = unchecked((int)0x230 + LeftRightUpNPagePPage);
+		public const int CtrlKeyNPage = unchecked((int)0x226 + LeftRightUpNPagePPage);
+		public const int CtrlKeyPPage = unchecked((int)0x22b + LeftRightUpNPagePPage);
+		public const int CtrlKeyHome = unchecked((int)0x217 + Home);
+		public const int CtrlKeyEnd = unchecked((int)0x212 + DownEnd);
+		public const int ShiftCtrlKeyUp = unchecked((int)0x237 + LeftRightUpNPagePPage);
+		public const int ShiftCtrlKeyDown = unchecked((int)0x20e + DownEnd);
+		public const int ShiftCtrlKeyLeft = unchecked((int)0x222 + LeftRightUpNPagePPage);
+		public const int ShiftCtrlKeyRight = unchecked((int)0x231 + LeftRightUpNPagePPage);
+		public const int ShiftCtrlKeyNPage = unchecked((int)0x227 + LeftRightUpNPagePPage);
+		public const int ShiftCtrlKeyPPage = unchecked((int)0x22c + LeftRightUpNPagePPage);
+		public const int ShiftCtrlKeyHome = unchecked((int)0x218 + Home);
+		public const int ShiftCtrlKeyEnd = unchecked((int)0x213 + DownEnd);
 
 
 		public const int LC_ALL = 6;
 		public const int LC_ALL = 6;
 		static public int ColorPair(int n){
 		static public int ColorPair(int n){

+ 141 - 61
Terminal.Gui/Views/ListView.cs

@@ -63,6 +63,12 @@ namespace Terminal.Gui {
 		/// <param name="item">Item index.</param>
 		/// <param name="item">Item index.</param>
 		/// <param name="value">If set to <c>true</c> value.</param>
 		/// <param name="value">If set to <c>true</c> value.</param>
 		void SetMark (int item, bool value);
 		void SetMark (int item, bool value);
+
+		/// <summary>
+		/// Return the source as IList.
+		/// </summary>
+		/// <returns></returns>
+		IList ToList ();
 	}
 	}
 
 
 	/// <summary>
 	/// <summary>
@@ -257,7 +263,7 @@ namespace Terminal.Gui {
 		/// Redraws the ListView
 		/// Redraws the ListView
 		/// </summary>
 		/// </summary>
 		/// <param name="region">Region.</param>
 		/// <param name="region">Region.</param>
-		public override void Redraw(Rect region)
+		public override void Redraw (Rect region)
 		{
 		{
 			var current = ColorScheme.Focus;
 			var current = ColorScheme.Focus;
 			Driver.SetAttribute (current);
 			Driver.SetAttribute (current);
@@ -279,12 +285,12 @@ namespace Terminal.Gui {
 				Move (0, row);
 				Move (0, row);
 				if (source == null || item >= source.Count) {
 				if (source == null || item >= source.Count) {
 					for (int c = 0; c < f.Width; c++)
 					for (int c = 0; c < f.Width; c++)
-						Driver.AddRune(' ');
+						Driver.AddRune (' ');
 				} else {
 				} else {
 					if (allowsMarking) {
 					if (allowsMarking) {
 						Driver.AddStr (source.IsMarked (item) ? (AllowsMultipleSelection ? "[x] " : "(o)") : (AllowsMultipleSelection ? "[ ] " : "( )"));
 						Driver.AddStr (source.IsMarked (item) ? (AllowsMultipleSelection ? "[x] " : "(o)") : (AllowsMultipleSelection ? "[ ] " : "( )"));
 					}
 					}
-					Source.Render(this, Driver, isSelected, item, col, row, f.Width-col);
+					Source.Render (this, Driver, isSelected, item, col, row, f.Width - col);
 				}
 				}
 			}
 			}
 		}
 		}
@@ -292,12 +298,12 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// This event is raised when the cursor selection has changed.
 		/// This event is raised when the cursor selection has changed.
 		/// </summary>
 		/// </summary>
-		public event Action SelectedChanged;
+		public event EventHandler<ListViewItemEventArgs> SelectedChanged;
 
 
 		/// <summary>
 		/// <summary>
 		/// This event is raised on Enter key or Double Click to open the selected item.
 		/// This event is raised on Enter key or Double Click to open the selected item.
 		/// </summary>
 		/// </summary>
-		public event EventHandler OpenSelectedItem;
+		public event EventHandler<ListViewItemEventArgs> OpenSelectedItem;
 
 
 		/// <summary>
 		/// <summary>
 		/// Handles cursor movement for this view, passes all other events.
 		/// Handles cursor movement for this view, passes all other events.
@@ -312,27 +318,27 @@ namespace Terminal.Gui {
 			switch (kb.Key) {
 			switch (kb.Key) {
 			case Key.CursorUp:
 			case Key.CursorUp:
 			case Key.ControlP:
 			case Key.ControlP:
-				return MoveUp();
+				return MoveUp ();
 
 
 			case Key.CursorDown:
 			case Key.CursorDown:
 			case Key.ControlN:
 			case Key.ControlN:
-				return MoveDown();
+				return MoveDown ();
 
 
 			case Key.ControlV:
 			case Key.ControlV:
 			case Key.PageDown:
 			case Key.PageDown:
-				return MovePageDown();
+				return MovePageDown ();
 
 
 			case Key.PageUp:
 			case Key.PageUp:
-				return MovePageUp();
+				return MovePageUp ();
 
 
 			case Key.Space:
 			case Key.Space:
-				if (MarkUnmarkRow())
+				if (MarkUnmarkRow ())
 					return true;
 					return true;
 				else
 				else
 					break;
 					break;
 
 
 			case Key.Enter:
 			case Key.Enter:
-				OpenSelectedItem?.Invoke (this, new EventArgs ());
+				OnOpenSelectedItem ();
 				break;
 				break;
 
 
 			}
 			}
@@ -340,7 +346,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// 
+		/// Prevents marking if it's not allowed mark and if it's not allows multiple selection.
 		/// </summary>
 		/// </summary>
 		/// <returns></returns>
 		/// <returns></returns>
 		public virtual bool AllowsAll ()
 		public virtual bool AllowsAll ()
@@ -359,13 +365,14 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// 
+		/// Marks an unmarked row.
 		/// </summary>
 		/// </summary>
 		/// <returns></returns>
 		/// <returns></returns>
-		public virtual bool MarkUnmarkRow(){
+		public virtual bool MarkUnmarkRow ()
+		{
 			if (AllowsAll ()) {
 			if (AllowsAll ()) {
-				Source.SetMark(SelectedItem, !Source.IsMarked(SelectedItem));
-				SetNeedsDisplay();
+				Source.SetMark (SelectedItem, !Source.IsMarked (SelectedItem));
+				SetNeedsDisplay ();
 				return true;
 				return true;
 			}
 			}
 
 
@@ -373,84 +380,114 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// 
+		/// Moves to the next page.
 		/// </summary>
 		/// </summary>
 		/// <returns></returns>
 		/// <returns></returns>
-		public virtual bool MovePageUp(){
+		public virtual bool MovePageUp ()
+		{
 			int n = (selected - Frame.Height);
 			int n = (selected - Frame.Height);
 			if (n < 0)
 			if (n < 0)
 				n = 0;
 				n = 0;
-			if (n != selected){
+			if (n != selected) {
 				selected = n;
 				selected = n;
 				top = selected;
 				top = selected;
-				if (SelectedChanged != null)
-					SelectedChanged();
-				SetNeedsDisplay();
+				OnSelectedChanged ();
+				SetNeedsDisplay ();
 			}
 			}
 
 
 			return true;
 			return true;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// 
+		/// Moves to the previous page.
 		/// </summary>
 		/// </summary>
 		/// <returns></returns>
 		/// <returns></returns>
-		public virtual bool MovePageDown(){
+		public virtual bool MovePageDown ()
+		{
 			var n = (selected + Frame.Height);
 			var n = (selected + Frame.Height);
 			if (n > source.Count)
 			if (n > source.Count)
 				n = source.Count - 1;
 				n = source.Count - 1;
-			if (n != selected){
+			if (n != selected) {
 				selected = n;
 				selected = n;
 				if (source.Count >= Frame.Height)
 				if (source.Count >= Frame.Height)
 					top = selected;
 					top = selected;
 				else
 				else
 					top = 0;
 					top = 0;
-				if (SelectedChanged != null)
-					SelectedChanged();
-				SetNeedsDisplay();
+				OnSelectedChanged ();
+				SetNeedsDisplay ();
 			}
 			}
 
 
 			return true;
 			return true;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// 
+		/// Moves to the next row.
 		/// </summary>
 		/// </summary>
 		/// <returns></returns>
 		/// <returns></returns>
-		public virtual bool MoveDown(){
-			if (selected + 1 < source.Count){
+		public virtual bool MoveDown ()
+		{
+			if (selected + 1 < source.Count) {
 				selected++;
 				selected++;
 				if (selected >= top + Frame.Height)
 				if (selected >= top + Frame.Height)
 					top++;
 					top++;
-				if (SelectedChanged != null)
-					SelectedChanged();
-				SetNeedsDisplay();
+				OnSelectedChanged ();
+				SetNeedsDisplay ();
 			}
 			}
 
 
 			return true;
 			return true;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// 
+		/// Moves to the previous row.
 		/// </summary>
 		/// </summary>
 		/// <returns></returns>
 		/// <returns></returns>
-		public virtual bool MoveUp(){
-			if (selected > 0){
+		public virtual bool MoveUp ()
+		{
+			if (selected > 0) {
 				selected--;
 				selected--;
 				if (selected < top)
 				if (selected < top)
 					top = selected;
 					top = selected;
-				if (SelectedChanged != null)
-					SelectedChanged();
-				SetNeedsDisplay();
+				OnSelectedChanged ();
+				SetNeedsDisplay ();
 			}
 			}
 
 
 			return true;
 			return true;
 		}
 		}
 
 
+		int lastSelectedItem = -1;
+
+		/// <summary>
+		/// Invokes the SelectedChanged event if it is defined.
+		/// </summary>
+		/// <returns></returns>
+		public virtual bool OnSelectedChanged ()
+		{
+			if (selected != lastSelectedItem) {
+				var value = source.ToList () [selected];
+				SelectedChanged?.Invoke (this, new ListViewItemEventArgs (selected, value));
+				lastSelectedItem = selected;
+				return true;
+			}
+
+			return false;
+		}
+
+		/// <summary>
+		/// Invokes the OnOpenSelectedItem event if it is defined.
+		/// </summary>
+		/// <returns></returns>
+		public virtual bool OnOpenSelectedItem ()
+		{
+			var value = source.ToList () [selected];
+			OpenSelectedItem?.Invoke (this, new ListViewItemEventArgs (selected, value));
+
+			return true;
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Positions the cursor in this view
 		/// Positions the cursor in this view
 		/// </summary>
 		/// </summary>
-		public override void PositionCursor()
+		public override void PositionCursor ()
 		{
 		{
 			if (allowsMarking)
 			if (allowsMarking)
 				Move (1, selected - top);
 				Move (1, selected - top);
@@ -461,7 +498,8 @@ namespace Terminal.Gui {
 		///<inheritdoc cref="MouseEvent(Gui.MouseEvent)"/>
 		///<inheritdoc cref="MouseEvent(Gui.MouseEvent)"/>
 		public override bool MouseEvent(MouseEvent me)
 		public override bool MouseEvent(MouseEvent me)
 		{
 		{
-			if (!me.Flags.HasFlag (MouseFlags.Button1Clicked) && !me.Flags.HasFlag (MouseFlags.Button1DoubleClicked))
+			if (!me.Flags.HasFlag (MouseFlags.Button1Clicked) && !me.Flags.HasFlag (MouseFlags.Button1DoubleClicked) &&
+				me.Flags != MouseFlags.WheeledDown && me.Flags != MouseFlags.WheeledUp)
 				return false;
 				return false;
 
 
 			if (!HasFocus)
 			if (!HasFocus)
@@ -470,6 +508,14 @@ namespace Terminal.Gui {
 			if (source == null)
 			if (source == null)
 				return false;
 				return false;
 
 
+			if (me.Flags == MouseFlags.WheeledDown) {
+				MoveDown ();
+				return true;
+			} else if (me.Flags == MouseFlags.WheeledUp) {
+				MoveUp ();
+				return true;
+			}
+
 			if (me.Y + top >= source.Count)
 			if (me.Y + top >= source.Count)
 				return true;
 				return true;
 
 
@@ -479,10 +525,10 @@ namespace Terminal.Gui {
 				SetNeedsDisplay ();
 				SetNeedsDisplay ();
 				return true;
 				return true;
 			}
 			}
-			SelectedChanged?.Invoke ();
+			OnSelectedChanged ();
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 			if (me.Flags == MouseFlags.Button1DoubleClicked)
 			if (me.Flags == MouseFlags.Button1DoubleClicked)
-				OpenSelectedItem?.Invoke (this, new EventArgs ());
+				OnOpenSelectedItem ();
 			return true;
 			return true;
 		}
 		}
 	}
 	}
@@ -497,7 +543,7 @@ namespace Terminal.Gui {
 		int count;
 		int count;
 
 
 		/// <summary>
 		/// <summary>
-		/// constructor
+		/// Constructor based on a source.
 		/// </summary>
 		/// </summary>
 		/// <param name="source"></param>
 		/// <param name="source"></param>
 		public ListWrapper (IList source)
 		public ListWrapper (IList source)
@@ -508,7 +554,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Count of items.
+		/// Returns the amount of items in the source.
 		/// </summary>
 		/// </summary>
 		public int Count => src.Count;
 		public int Count => src.Count;
 
 
@@ -519,7 +565,7 @@ namespace Terminal.Gui {
 			for (int i = 0; i < byteLen;) {
 			for (int i = 0; i < byteLen;) {
 				(var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
 				(var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
 				var count = Rune.ColumnWidth (rune);
 				var count = Rune.ColumnWidth (rune);
-				if (used+count >= width)
+				if (used + count >= width)
 					break;
 					break;
 				driver.AddRune (rune);
 				driver.AddRune (rune);
 				used += count;
 				used += count;
@@ -531,15 +577,15 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Renders an item in the the list.
+		/// Method that render to the appropriate type based on the type of the item passed to it.
 		/// </summary>
 		/// </summary>
-		/// <param name="container"></param>
-		/// <param name="driver"></param>
-		/// <param name="marked"></param>
-		/// <param name="item"></param>
-		/// <param name="col"></param>
-		/// <param name="line"></param>
-		/// <param name="width"></param>
+		/// <param name="container">The ListView.</param>
+		/// <param name="driver">The driver used by the caller.</param>
+		/// <param name="marked">Informs if it's marked or not.</param>
+		/// <param name="item">The item.</param>
+		/// <param name="col">The col where to move.</param>
+		/// <param name="line">The line where to move.</param>
+		/// <param name="width">The item width.</param>
 		public void Render (ListView container, ConsoleDriver driver, bool marked, int item, int col, int line, int width)
 		public void Render (ListView container, ConsoleDriver driver, bool marked, int item, int col, int line, int width)
 		{
 		{
 			container.Move (col, line);
 			container.Move (col, line);
@@ -553,10 +599,10 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Returns true of the item is marked. false if not.
+		/// Returns true if the item is marked, false otherwise.
 		/// </summary>
 		/// </summary>
-		/// <param name="item"></param>
-		/// <returns></returns>
+		/// <param name="item">The item.</param>
+		/// <returns><c>true</c>If is marked.<c>false</c>otherwise.</returns>
 		public bool IsMarked (int item)
 		public bool IsMarked (int item)
 		{
 		{
 			if (item >= 0 && item < count)
 			if (item >= 0 && item < count)
@@ -565,14 +611,48 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Sets the marked state of an item.
+		/// Sets the item as marked or unmarked based on the value is true or false, respectively.
 		/// </summary>
 		/// </summary>
-		/// <param name="item"></param>
-		/// <param name="value"></param>
+		/// <param name="item">The item</param>
+		/// <param name="value"><true>Marks the item.</true><false>Unmarked the item.</false>The value.</param>
 		public void SetMark (int item, bool value)
 		public void SetMark (int item, bool value)
 		{
 		{
 			if (item >= 0 && item < count)
 			if (item >= 0 && item < count)
 				marks [item] = value;
 				marks [item] = value;
 		}
 		}
+
+		/// <summary>
+		/// Returns the source as IList.
+		/// </summary>
+		/// <returns></returns>
+		public IList ToList ()
+		{
+			return src;
+		}
+	}
+
+	/// <summary>
+	/// Gets the item and value to use in an event handler.
+	/// </summary>
+	public class ListViewItemEventArgs : EventArgs {
+		/// <summary>
+		/// The item.
+		/// </summary>
+		public int Item { get; }
+		/// <summary>
+		/// The item value.
+		/// </summary>
+		public object Value { get; }
+
+		/// <summary>
+		/// Constructor to sets the item and value passed from.
+		/// </summary>
+		/// <param name="item">The item.</param>
+		/// <param name="value">The item value</param>
+		public ListViewItemEventArgs (int item, object value)
+		{
+			Item = item;
+			Value = value;
+		}
 	}
 	}
 }
 }

+ 10 - 15
Terminal.Gui/Views/Menu.cs

@@ -347,7 +347,7 @@ namespace Terminal.Gui {
 			});
 			});
 		}
 		}
 
 
-		public override bool KeyDown (KeyEvent keyEvent)
+		public override bool OnKeyDown (KeyEvent keyEvent)
 		{
 		{
 			if (keyEvent.IsAlt) {
 			if (keyEvent.IsAlt) {
 				host.CloseAllMenus ();
 				host.CloseAllMenus ();
@@ -360,9 +360,9 @@ namespace Terminal.Gui {
 		public override bool ProcessHotKey (KeyEvent keyEvent)
 		public override bool ProcessHotKey (KeyEvent keyEvent)
 		{
 		{
 			// To ncurses simulate a AltMask key pressing Alt+Space because
 			// To ncurses simulate a AltMask key pressing Alt+Space because
-			// it can´t detect an alone special key down was pressed.
+			// it can�t detect an alone special key down was pressed.
 			if (keyEvent.IsAlt && keyEvent.Key == Key.AltMask) {
 			if (keyEvent.IsAlt && keyEvent.Key == Key.AltMask) {
-				KeyDown (keyEvent);
+				OnKeyDown (keyEvent);
 				return true;
 				return true;
 			}
 			}
 
 
@@ -563,8 +563,8 @@ namespace Terminal.Gui {
 
 
 		bool openedByAltKey;
 		bool openedByAltKey;
 
 
-		///<inheritdoc cref="KeyDown"/>
-		public override bool KeyDown (KeyEvent keyEvent)
+		///<inheritdoc cref="OnKeyDown"/>
+		public override bool OnKeyDown (KeyEvent keyEvent)
 		{
 		{
 			if (keyEvent.IsAlt) {
 			if (keyEvent.IsAlt) {
 				openedByAltKey = true;
 				openedByAltKey = true;
@@ -574,13 +574,8 @@ namespace Terminal.Gui {
 			return false;
 			return false;
 		}
 		}
 
 
-		/// <summary>
-		/// Track Alt key-up events. On Windows, when a user releases Alt (without another key), the menu gets focus but doesn't open.
-		/// We mimic that behavior here.
-		/// </summary>
-		/// <param name="keyEvent"></param>
-		/// <returns></returns>
-		public override bool KeyUp (KeyEvent keyEvent)
+		///<inheritdoc cref="OnKeyUp"/>
+		public override bool OnKeyUp (KeyEvent keyEvent)
 		{
 		{
 			if (keyEvent.IsAlt) {
 			if (keyEvent.IsAlt) {
 				// User pressed Alt - this may be a precursor to a menu accelerator (e.g. Alt-F)
 				// User pressed Alt - this may be a precursor to a menu accelerator (e.g. Alt-F)
@@ -1001,10 +996,10 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			// To ncurses simulate a AltMask key pressing Alt+Space because
 			// To ncurses simulate a AltMask key pressing Alt+Space because
-			// it can´t detect an alone special key down was pressed.
+			// it can�t detect an alone special key down was pressed.
 			if (kb.IsAlt && kb.Key == Key.AltMask && openMenu == null) {
 			if (kb.IsAlt && kb.Key == Key.AltMask && openMenu == null) {
-				KeyDown (kb);
-				KeyUp (kb);
+				OnKeyDown (kb);
+				OnKeyUp (kb);
 				return true;
 				return true;
 			} else if (kb.IsAlt) {
 			} else if (kb.IsAlt) {
 				if (FindAndOpenMenuByHotkey (kb)) return true;
 				if (FindAndOpenMenuByHotkey (kb)) return true;

+ 43 - 2
Terminal.Gui/Views/ScrollView.cs

@@ -14,6 +14,8 @@
 // - Perhaps allow an option to not display the scrollbar arrow indicators?
 // - Perhaps allow an option to not display the scrollbar arrow indicators?
 
 
 using System;
 using System;
+using System.Reflection;
+
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 	/// <summary>
 	/// <summary>
 	/// ScrollBarViews are views that display a 1-character scrollbar, either horizontal or vertical
 	/// ScrollBarViews are views that display a 1-character scrollbar, either horizontal or vertical
@@ -73,7 +75,7 @@ namespace Terminal.Gui {
 		/// <param name="rect">Frame for the scrollbar.</param>
 		/// <param name="rect">Frame for the scrollbar.</param>
 		/// <param name="size">The size that this scrollbar represents.</param>
 		/// <param name="size">The size that this scrollbar represents.</param>
 		/// <param name="position">The position within this scrollbar.</param>
 		/// <param name="position">The position within this scrollbar.</param>
-		/// <param name="isVertical">If set to <c>true</c> this is a vertical scrollbar, otherwize, the scrollbar is horizontal.</param>
+		/// <param name="isVertical">If set to <c>true</c> this is a vertical scrollbar, otherwise, the scrollbar is horizontal.</param>
 		public ScrollBarView (Rect rect, int size, int position, bool isVertical) : base (rect)
 		public ScrollBarView (Rect rect, int size, int position, bool isVertical) : base (rect)
 		{
 		{
 			vertical = isVertical;
 			vertical = isVertical;
@@ -314,9 +316,35 @@ namespace Terminal.Gui {
 		/// <param name="view">The view to add to the scrollview.</param>
 		/// <param name="view">The view to add to the scrollview.</param>
 		public override void Add (View view)
 		public override void Add (View view)
 		{
 		{
+			if (!IsOverridden (view)) {
+				view.MouseEnter += View_MouseEnter;
+				view.MouseLeave += View_MouseLeave;
+				vertical.MouseEnter += View_MouseEnter;
+				vertical.MouseLeave += View_MouseLeave;
+				horizontal.MouseEnter += View_MouseEnter;
+				horizontal.MouseLeave += View_MouseLeave;
+			}
 			contentView.Add (view);
 			contentView.Add (view);
 		}
 		}
 
 
+		void View_MouseLeave (object sender, MouseEvent e)
+		{
+			Application.UngrabMouse ();
+		}
+
+		void View_MouseEnter (object sender, MouseEvent e)
+		{
+			Application.GrabMouse (this);
+		}
+
+		bool IsOverridden (View view)
+		{
+			Type t = view.GetType ();
+			MethodInfo m = t.GetMethod ("MouseEvent");
+
+			return m.DeclaringType == t && m.GetBaseDefinition ().DeclaringType == typeof (Responder);
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Gets or sets the visibility for the horizontal scroll indicator.
 		/// Gets or sets the visibility for the horizontal scroll indicator.
 		/// </summary>
 		/// </summary>
@@ -463,7 +491,7 @@ namespace Terminal.Gui {
 			switch (kb.Key) {
 			switch (kb.Key) {
 			case Key.CursorUp:
 			case Key.CursorUp:
 				return ScrollUp (1);
 				return ScrollUp (1);
-			case (Key) 'v' | Key.AltMask:
+			case (Key)'v' | Key.AltMask:
 			case Key.PageUp:
 			case Key.PageUp:
 				return ScrollUp (Bounds.Height);
 				return ScrollUp (Bounds.Height);
 
 
@@ -489,5 +517,18 @@ namespace Terminal.Gui {
 			}
 			}
 			return false;
 			return false;
 		}
 		}
+
+		public override bool MouseEvent (MouseEvent me)
+		{
+			if (me.Flags != MouseFlags.WheeledDown && me.Flags != MouseFlags.WheeledUp)
+				return false;
+
+			if (me.Flags == MouseFlags.WheeledDown)
+				ScrollDown (1);
+			else if (me.Flags == MouseFlags.WheeledUp)
+				ScrollUp (1);
+
+			return true;
+		}
 	}
 	}
 }
 }

+ 11 - 7
Terminal.Gui/Views/StatusBar.cs

@@ -107,8 +107,12 @@ namespace Terminal.Gui {
 			Items = items;
 			Items = items;
 			CanFocus = false;
 			CanFocus = false;
 			ColorScheme = Colors.Menu;
 			ColorScheme = Colors.Menu;
+			X = 0;
+			Y = Driver.Rows - 1;
+			Width = Dim.Fill ();
+			Height = 1;
 
 
-			Application.OnLoad += () => {
+			Application.Loaded += (sender, e) => {
 				X = 0;
 				X = 0;
 				Height = 1;
 				Height = 1;
 #if SNAP_TO_TOP
 #if SNAP_TO_TOP
@@ -120,7 +124,7 @@ namespace Terminal.Gui {
 				case StatusBarStyle.SnapToBottom:
 				case StatusBarStyle.SnapToBottom:
 #endif
 #endif
 					if (Parent == null) {
 					if (Parent == null) {
-						Y = Application.Driver.Rows - 1; // TODO: using internals of Application
+						Y = e.Rows - 1; 
 					} else {
 					} else {
 						Y = Pos.Bottom (Parent);
 						Y = Pos.Bottom (Parent);
 					}
 					}
@@ -141,11 +145,11 @@ namespace Terminal.Gui {
 		///<inheritdoc cref="Redraw"/>
 		///<inheritdoc cref="Redraw"/>
 		public override void Redraw (Rect region)
 		public override void Redraw (Rect region)
 		{
 		{
-			if (Frame.Y != Driver.Rows - 1) {
-				Frame = new Rect (Frame.X, Driver.Rows - 1, Frame.Width, Frame.Height);
-				Y = Driver.Rows - 1;
-				SetNeedsDisplay ();
-			}
+			//if (Frame.Y != Driver.Rows - 1) {
+			//	Frame = new Rect (Frame.X, Driver.Rows - 1, Frame.Width, Frame.Height);
+			//	Y = Driver.Rows - 1;
+			//	SetNeedsDisplay ();
+			//}
 
 
 			Move (0, 0);
 			Move (0, 0);
 			Driver.SetAttribute (ColorScheme.Normal);
 			Driver.SetAttribute (ColorScheme.Normal);

+ 44 - 6
Terminal.Gui/Views/TextField.cs

@@ -28,6 +28,11 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public bool Used { get => used; set { used = value; } }
 		public bool Used { get => used; set { used = value; } }
 
 
+		/// <summary>
+		/// If set to true its not allow any changes in the text.
+		/// </summary>
+		public bool ReadOnly { get; set; } = false;
+
 		/// <summary>
 		/// <summary>
 		///   Changed event, raised when the text has clicked.
 		///   Changed event, raised when the text has clicked.
 		/// </summary>
 		/// </summary>
@@ -95,7 +100,7 @@ namespace Terminal.Gui {
 			set {
 			set {
 				base.Frame = value;
 				base.Frame = value;
 				var w = base.Frame.Width;
 				var w = base.Frame.Width;
-				//first = point > w ? point - w : 0;
+				first = point > w ? point - w : 0;
 				Adjust ();
 				Adjust ();
 			}
 			}
 		}
 		}
@@ -115,6 +120,9 @@ namespace Terminal.Gui {
 			}
 			}
 
 
 			set {
 			set {
+				if (ReadOnly)
+					return;
+
 				var oldText = ustring.Make (text);
 				var oldText = ustring.Make (text);
 				text = TextModel.ToRunes (value);
 				text = TextModel.ToRunes (value);
 				if (!Secret && !isFromHistory) {
 				if (!Secret && !isFromHistory) {
@@ -184,13 +192,16 @@ namespace Terminal.Gui {
 			int col = 0;
 			int col = 0;
 			int width = Frame.Width;
 			int width = Frame.Width;
 			var tcount = text.Count;
 			var tcount = text.Count;
+			var roc = new Attribute (Color.DarkGray, Color.Gray);
 			for (int idx = 0; idx < tcount; idx++){
 			for (int idx = 0; idx < tcount; idx++){
 				var rune = text [idx];
 				var rune = text [idx];
 				if (idx < p)
 				if (idx < p)
 					continue;
 					continue;
 				var cols = Rune.ColumnWidth (rune);
 				var cols = Rune.ColumnWidth (rune);
-				if (col == point && HasFocus && !Used && SelectedLength == 0)
+				if (col == point && HasFocus && !Used && SelectedLength == 0 && !ReadOnly)
 					Driver.SetAttribute (Colors.Menu.HotFocus);
 					Driver.SetAttribute (Colors.Menu.HotFocus);
+				else if (ReadOnly)
+					Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : roc);
 				else
 				else
 					Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : ColorScheme.Focus);
 					Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : ColorScheme.Focus);
 				if (col + cols <= width)
 				if (col + cols <= width)
@@ -261,6 +272,9 @@ namespace Terminal.Gui {
 			switch (kb.Key) {
 			switch (kb.Key) {
 			case Key.DeleteChar:
 			case Key.DeleteChar:
 			case Key.ControlD:
 			case Key.ControlD:
+				if (ReadOnly)
+					return true;
+
 				if (SelectedLength == 0) {
 				if (SelectedLength == 0) {
 					if (text.Count == 0 || text.Count == point)
 					if (text.Count == 0 || text.Count == point)
 						return true;
 						return true;
@@ -275,6 +289,9 @@ namespace Terminal.Gui {
 
 
 			case Key.Delete:
 			case Key.Delete:
 			case Key.Backspace:
 			case Key.Backspace:
+				if (ReadOnly)
+					return true;
+
 				if (SelectedLength == 0) {
 				if (SelectedLength == 0) {
 					if (point == 0)
 					if (point == 0)
 						return true;
 						return true;
@@ -373,6 +390,9 @@ namespace Terminal.Gui {
 				break;
 				break;
 
 
 			case Key.ControlK: // kill-to-end
 			case Key.ControlK: // kill-to-end
+				if (ReadOnly)
+					return true;
+
 				ClearAllSelection ();
 				ClearAllSelection ();
 				if (point >= text.Count)
 				if (point >= text.Count)
 					return true;
 					return true;
@@ -383,6 +403,9 @@ namespace Terminal.Gui {
 
 
 			// Undo
 			// Undo
 			case Key.ControlZ:
 			case Key.ControlZ:
+				if (ReadOnly)
+					return true;
+
 				if (historyText != null && historyText.Count > 0) {
 				if (historyText != null && historyText.Count > 0) {
 					isFromHistory = true;
 					isFromHistory = true;
 					if (idxhistoryText > 0)
 					if (idxhistoryText > 0)
@@ -396,6 +419,9 @@ namespace Terminal.Gui {
 
 
 			//Redo
 			//Redo
 			case Key.ControlY: // Control-y, yank
 			case Key.ControlY: // Control-y, yank
+				if (ReadOnly)
+					return true;
+
 				if (historyText != null && historyText.Count > 0) {
 				if (historyText != null && historyText.Count > 0) {
 					isFromHistory = true;
 					isFromHistory = true;
 					if (idxhistoryText < historyText.Count - 1) {
 					if (idxhistoryText < historyText.Count - 1) {
@@ -455,6 +481,9 @@ namespace Terminal.Gui {
 				break;
 				break;
 
 
 			case Key.ControlX:
 			case Key.ControlX:
+				if (ReadOnly)
+					return true;
+
 				Cut ();
 				Cut ();
 				break;
 				break;
 
 
@@ -472,6 +501,9 @@ namespace Terminal.Gui {
 				if (kb.Key < Key.Space || kb.Key > Key.CharMask)
 				if (kb.Key < Key.Space || kb.Key > Key.CharMask)
 					return false;
 					return false;
 
 
+				if (ReadOnly)
+					return true;
+
 				if (SelectedLength != 0) {
 				if (SelectedLength != 0) {
 					DeleteSelectedText ();
 					DeleteSelectedText ();
 					oldCursorPos = point;
 					oldCursorPos = point;
@@ -639,7 +671,7 @@ namespace Terminal.Gui {
 				point = text.Count;
 				point = text.Count;
 			if (point < first)
 			if (point < first)
 				point = 0;
 				point = 0;
-			return x;
+			return point;
 		}
 		}
 
 
 		void PrepareSelection (int x, int direction = 0)
 		void PrepareSelection (int x, int direction = 0)
@@ -682,8 +714,11 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Copy the selected text to the clipboard.
 		/// Copy the selected text to the clipboard.
 		/// </summary>
 		/// </summary>
-		public void Copy ()
+		public virtual void Copy ()
 		{
 		{
+			if (Secret)
+				return;
+
 			if (SelectedLength != 0) {
 			if (SelectedLength != 0) {
 				Clipboard.Contents = SelectedText;
 				Clipboard.Contents = SelectedText;
 			}
 			}
@@ -692,7 +727,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Cut the selected text to the clipboard.
 		/// Cut the selected text to the clipboard.
 		/// </summary>
 		/// </summary>
-		public void Cut ()
+		public virtual void Cut ()
 		{
 		{
 			if (SelectedLength != 0) {
 			if (SelectedLength != 0) {
 				Clipboard.Contents = SelectedText;
 				Clipboard.Contents = SelectedText;
@@ -715,8 +750,11 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// <summary>
 		/// Paste the selected text from the clipboard.
 		/// Paste the selected text from the clipboard.
 		/// </summary>
 		/// </summary>
-		public void Paste ()
+		public virtual void Paste ()
 		{
 		{
+			if (ReadOnly)
+				return;
+
 			string actualText = Text.ToString ();
 			string actualText = Text.ToString ();
 			int start = SelectedStart == -1 ? CursorPosition : SelectedStart;
 			int start = SelectedStart == -1 ? CursorPosition : SelectedStart;
 			ustring cbTxt = Clipboard.Contents?.ToString () ?? "";
 			ustring cbTxt = Clipboard.Contents?.ToString () ?? "";

+ 28 - 0
Terminal.Gui/Views/TextView.cs

@@ -39,6 +39,7 @@ namespace Terminal.Gui {
 			if (file == null)
 			if (file == null)
 				throw new ArgumentNullException (nameof (file));
 				throw new ArgumentNullException (nameof (file));
 			try {
 			try {
+				FilePath = file;
 				var stream = File.OpenRead (file);
 				var stream = File.OpenRead (file);
 			} catch {
 			} catch {
 				return false;
 				return false;
@@ -47,6 +48,19 @@ namespace Terminal.Gui {
 			return true;
 			return true;
 		}
 		}
 
 
+		public bool CloseFile ()
+		{
+			if (FilePath == null)
+				throw new ArgumentNullException (nameof (FilePath));
+			try {
+				FilePath = null;
+				lines = new List<List<Rune>> ();
+			} catch {
+				return false;
+			}
+			return true;
+		}
+
 		// Turns the ustring into runes, this does not split the 
 		// Turns the ustring into runes, this does not split the 
 		// contents on a newline if it is present.
 		// contents on a newline if it is present.
 		internal static List<Rune> ToRunes (ustring str)
 		internal static List<Rune> ToRunes (ustring str)
@@ -120,6 +134,8 @@ namespace Terminal.Gui {
 			return sb.ToString ();
 			return sb.ToString ();
 		}
 		}
 
 
+		public string FilePath { get; set; }
+
 		/// <summary>
 		/// <summary>
 		/// The number of text lines in the model
 		/// The number of text lines in the model
 		/// </summary>
 		/// </summary>
@@ -351,6 +367,18 @@ namespace Terminal.Gui {
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 		}
 		}
 
 
+		/// <summary>
+		/// Closes the contents of the stream into the TextView.
+		/// </summary>
+		/// <returns><c>true</c>, if stream was closed, <c>false</c> otherwise.</returns>
+		public bool CloseFile()
+		{
+			ResetPosition ();
+			var res = model.CloseFile ();
+			SetNeedsDisplay ();
+			return res;
+		}
+
 		/// <summary>
 		/// <summary>
 		///    The current cursor row.
 		///    The current cursor row.
 		/// </summary>
 		/// </summary>

+ 11 - 8
Terminal.sln

@@ -1,13 +1,14 @@
-
 Microsoft Visual Studio Solution File, Format Version 12.00
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.128
+MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{B0A602CD-E176-449D-8663-64238D54F857}"
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example", "Example\Example.csproj", "{B0A602CD-E176-449D-8663-64238D54F857}"
 EndProject
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}"
 EndProject
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}"
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}"
 EndProject
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UICatalog", "UICatalog\UICatalog.csproj", "{88979F89-9A42-448F-AE3E-3060145F6375}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UICatalog", "UICatalog\UICatalog.csproj", "{88979F89-9A42-448F-AE3E-3060145F6375}"
 EndProject
 EndProject
 Global
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,15 +28,17 @@ Global
 		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.Build.0 = Debug|x86
 		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Debug|x86.Build.0 = Debug|x86
 		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.ActiveCfg = Release|x86
 		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.ActiveCfg = Release|x86
 		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.Build.0 = Release|x86
 		{1228D992-C801-49BB-839A-7BD28A3FFF0A}.Release|x86.Build.0 = Release|x86
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.ActiveCfg = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.ActiveCfg = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.Build.0 = Debug|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Debug|x86.Build.0 = Debug|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.Build.0 = Release|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.ActiveCfg = Release|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.ActiveCfg = Release|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.Build.0 = Release|Any CPU
 		{88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {9F8F8A4D-7B8D-4C2A-AC5E-CD7117F74C03}
+	EndGlobalSection
 	GlobalSection(MonoDevelopProperties) = preSolution
 	GlobalSection(MonoDevelopProperties) = preSolution
 		Policies = $0
 		Policies = $0
 		$0.TextStylePolicy = $1
 		$0.TextStylePolicy = $1

+ 16 - 7
UICatalog/Program.cs

@@ -1,5 +1,6 @@
 using NStack;
 using NStack;
 using System;
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Globalization;
 using System.Globalization;
@@ -62,7 +63,7 @@ namespace UICatalog {
 				new MenuBarItem ("_File", new MenuItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {
 					new MenuItem ("_Quit", "", () => Application.RequestStop() )
 					new MenuItem ("_Quit", "", () => Application.RequestStop() )
 				}),
 				}),
-				new MenuBarItem ("_About...", "About this app", () =>  MessageBox.Query (0, 6, "About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok")),
+				new MenuBarItem ("_About...", "About this app", () =>  MessageBox.Query (0, 10, "About UI Catalog", "UI Catalog is a comprehensive sample library for Terminal.Gui", "Ok")),
 			});
 			});
 
 
 			_leftPane = new Window ("Categories") {
 			_leftPane = new Window ("Categories") {
@@ -119,7 +120,7 @@ namespace UICatalog {
 			_rightPane.Add (_scenarioListView);
 			_rightPane.Add (_scenarioListView);
 
 
 			_categoryListView.SelectedItem = 0;
 			_categoryListView.SelectedItem = 0;
-			CategoryListView_SelectedChanged ();
+			_categoryListView.OnSelectedChanged ();
 
 
 			_statusBar = new StatusBar (new StatusItem [] {
 			_statusBar = new StatusBar (new StatusItem [] {
 				//new StatusItem(Key.F1, "~F1~ Help", () => Help()),
 				//new StatusItem(Key.F1, "~F1~ Help", () => Help()),
@@ -148,7 +149,9 @@ namespace UICatalog {
 			}
 			}
 
 
 			_top = Application.Top;
 			_top = Application.Top;
-			_top.OnKeyUp += KeyUpHandler;
+
+			_top.KeyUp += KeyUpHandler;
+
 			_top.Add (_menu);
 			_top.Add (_menu);
 			_top.Add (_leftPane);
 			_top.Add (_leftPane);
 			_top.Add (_rightPane);
 			_top.Add (_rightPane);
@@ -227,6 +230,12 @@ namespace UICatalog {
 					used++;
 					used++;
 				}
 				}
 			}
 			}
+
+			public IList ToList ()
+			{
+				return Scenarios;
+			}
+
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -235,7 +244,7 @@ namespace UICatalog {
 		/// to not be impacted. Same as for tabs.
 		/// to not be impacted. Same as for tabs.
 		/// </summary>
 		/// </summary>
 		/// <param name="ke"></param>
 		/// <param name="ke"></param>
-		private static void KeyUpHandler (KeyEvent ke)
+		private static void KeyUpHandler (object sender, View.KeyEventEventArgs a)
 		{
 		{
 			if (_runningScenario != null) {
 			if (_runningScenario != null) {
 				//switch (ke.Key) {
 				//switch (ke.Key) {
@@ -244,8 +253,8 @@ namespace UICatalog {
 				//	break;
 				//	break;
 				//case Key.Enter:
 				//case Key.Enter:
 				//	break;
 				//	break;
-				//}
-			} else if (ke.Key == Key.Tab || ke.Key == Key.BackTab) {
+				//}<
+			} else if (a.KeyEvent.Key == Key.Tab || a.KeyEvent.Key == Key.BackTab) {
 				// BUGBUG: Work around Issue #434 by implementing our own TAB navigation
 				// BUGBUG: Work around Issue #434 by implementing our own TAB navigation
 				if (_top.MostFocused == _categoryListView)
 				if (_top.MostFocused == _categoryListView)
 					_top.SetFocus (_rightPane);
 					_top.SetFocus (_rightPane);
@@ -254,7 +263,7 @@ namespace UICatalog {
 			}
 			}
 		}
 		}
 
 
-		private static void CategoryListView_SelectedChanged ()
+		private static void CategoryListView_SelectedChanged (object sender, ListViewItemEventArgs e)
 		{
 		{
 			var item = _categories [_categoryListView.SelectedItem];
 			var item = _categories [_categoryListView.SelectedItem];
 			List<Type> newlist;
 			List<Type> newlist;

+ 0 - 1
UICatalog/Properties/launchSettings.json

@@ -2,7 +2,6 @@
   "profiles": {
   "profiles": {
     "UICatalog": {
     "UICatalog": {
       "commandName": "Project"
       "commandName": "Project"
-
     }
     }
   }
   }
 }
 }

+ 1 - 1
UICatalog/README.md

@@ -119,4 +119,4 @@ For complete control, the `Init` and `Run` overrides can be implemented. The `ba
 - Use the `Bug Rero` Category for `Scnarios` that reproduce bugs. 
 - Use the `Bug Rero` Category for `Scnarios` that reproduce bugs. 
 	- Include the Github Issue # in the Description.
 	- Include the Github Issue # in the Description.
 	- Once the bug has been fixed in `master` submit another PR to remove the `Scenario` (or modify it to provide a good regression test).
 	- Once the bug has been fixed in `master` submit another PR to remove the `Scenario` (or modify it to provide a good regression test).
-- Tag bugs or suggestions for `UI Catalog` in the main `Terminal.Gui` Github Issues with "UICatalog: ".
+- Tag bugs or suggestions for `UI Catalog` as [`Terminal.Gui` Github Issues](https://github.com/migueldeicaza/gui.cs/issues) with "UICatalog: ".

+ 23 - 1
UICatalog/Scenario.cs

@@ -17,7 +17,9 @@ namespace UICatalog {
 	/// The Main program uses reflection to find all sceanarios and adds them to the
 	/// The Main program uses reflection to find all sceanarios and adds them to the
 	/// ListViews. Press ENTER to run the selected sceanrio. Press CTRL-Q to exit it.
 	/// ListViews. Press ENTER to run the selected sceanrio. Press CTRL-Q to exit it.
 	/// </summary>
 	/// </summary>
-	public class Scenario {
+	public class Scenario : IDisposable {
+		private bool _disposedValue;
+
 		/// <summary>
 		/// <summary>
 		/// The Top level for the Scenario. This should be set to `Application.Top` in most cases.
 		/// The Top level for the Scenario. This should be set to `Application.Top` in most cases.
 		/// </summary>
 		/// </summary>
@@ -177,5 +179,25 @@ namespace UICatalog {
 			}
 			}
 			return objects;
 			return objects;
 		}
 		}
+
+		protected virtual void Dispose (bool disposing)
+		{
+			if (!_disposedValue) {
+				if (disposing) {
+					// TODO: dispose managed state (managed objects)
+				}
+
+				// TODO: free unmanaged resources (unmanaged objects) and override finalizer
+				// TODO: set large fields to null
+				_disposedValue = true;
+			}
+		}
+
+		public void Dispose ()
+		{
+			// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+			Dispose (disposing: true);
+			GC.SuppressFinalize (this);
+		}
 	}
 	}
 }
 }

+ 155 - 0
UICatalog/Scenarios/ComputedLayout.cs

@@ -0,0 +1,155 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Terminal.Gui;
+
+namespace UICatalog {
+	/// <summary>
+	/// This Scenario demonstrates how to use Termina.gui's Dim and Pos Layout System. 
+	/// [x] - Using Dim.Fill to fill a window
+	/// [x] - Using Dim.Fill and Dim.Pos to automatically align controls based on an initial control
+	/// [ ] - ...
+	/// </summary>
+	[ScenarioMetadata (Name: "Computed Layout", Description: "Demonstrates using the Computed (Dim and Pos) Layout System")]
+	[ScenarioCategory ("Layout")]
+	class ComputedLayout : Scenario {
+
+		public override void Setup ()
+		{
+			//Top.LayoutStyle = LayoutStyle.Computed;
+			// Demonstrate using Dim to create a horizontal ruler that always measures the parent window's width
+			// BUGBUG: Dim.Fill returns too big a value sometimes.
+			const string rule = "|123456789";
+			var horizontalRuler = new Label ("") {
+				X = 0,
+				Y = 0,
+				Width = Dim.Fill (1),  // BUGBUG: I don't think this should be needed; DimFill() should respect container's frame. X does.
+				ColorScheme = Colors.Error
+			};
+
+			Application.Resized += (sender, a) => {
+				horizontalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(horizontalRuler.Bounds.Width) / (double)rule.Length)) [0..(horizontalRuler.Bounds.Width)];
+			};
+
+			Win.Add (horizontalRuler);
+
+			// Demonstrate using Dim to create a vertical ruler that always measures the parent window's height
+			// TODO: Either build a custom control for this or implement linewrap in Label #352
+			//var verticalRuler = new Label ("") {
+			//	X = 0,
+			//	Y = 0,
+			//	Width = 1,
+			//	Height = Dim.Fill (),
+			//	ColorScheme = Colors.Error
+			//};
+
+			//Application.OnResized += () => {
+			//	verticalRuler.Text = rule.Repeat ((int)Math.Ceiling ((double)(verticalRuler.Bounds.Height) / (double)rule.Length)) [0..(verticalRuler.Bounds.Height)];
+			//};
+
+			//Win.Add (verticalRuler);
+
+
+			// Demonstrate using Dim to create a window that fills the parent with a margin
+			int margin = 10;
+			var subWin = new Window ($"Centered Sub Window with {margin} character margin") {
+				X = Pos.Center(),
+				Y = 2,
+				Width = Dim.Fill (margin),
+				Height = 7
+			};
+			Win.Add (subWin);
+
+			int i = 1;
+			string txt = "Resize the terminal to see computed layout in action.";
+			var labelList = new List<Label> ();
+			labelList.Add (new Label ($"The lines below show different TextAlignments"));
+			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Left, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
+			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Right, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
+			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Centered, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
+			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Justified, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()), ColorScheme = Colors.Dialog });
+
+			subWin.Add (labelList.ToArray ());
+
+			// Demonstrate Dim & Pos using percentages - a TextField that is 20% height and 80% wide
+			var textView= new TextView () {
+				X = Pos.Center (),
+				Y = Pos.Percent (50),
+				Width = Dim.Percent (80),
+				Height = Dim.Percent (20),
+				ColorScheme = Colors.TopLevel,
+			};
+			textView.Text = "This text view should be half-way down the terminal,\n20% of its height, and 80% of its width.";
+			Win.Add (textView);
+
+			//// Demonstrate AnchorEnd - Button anchored to bottom of textView
+			//var clearButton = new Button ("Clear") {
+			//	X = Pos.AnchorEnd (),
+			//	Y = Pos.AnchorEnd (),
+			//	Width = 15,
+			//	Height = 1
+			//};
+			//Win.Add (clearButton);
+
+			// Demonstrate At - Absolute Layout using Pos
+			var absoluteButton = new Button ("At(10,10)") {
+				X = Pos.At(10),
+				Y = Pos.At(10)
+			};
+			Win.Add (absoluteButton);
+
+			// Centering multiple controls horizontally. 
+			// This is intentionally convoluted to illustrate potential bugs.
+			var bottomLabel = new Label ("This should be the last line (Bug #xxx).") {
+				TextAlignment = Terminal.Gui.TextAlignment.Centered,
+				ColorScheme = Colors.TopLevel,
+				Width = Dim.Fill (),
+				X = Pos.Center (),
+				Y = Pos.Bottom (Win) - 3  // BUGBUG: -1 should be just above border; but it has to be -3
+			};
+
+			var centerButton = new Button ("Center") {
+				X = Pos.Center (),
+				Y = Pos.Top(bottomLabel) - 1
+			};
+			var leftButton = new Button ("Left") {
+				Y = Pos.Top (bottomLabel) - 1
+			};
+			var rightButton = new Button ("Right") {
+				Y = Pos.Top (bottomLabel) - 1
+			};
+
+			leftButton.X = Pos.Left (centerButton) - leftButton.Frame.Width - 5;
+			rightButton.X = Pos.Right (centerButton) + 5;
+
+			Win.Add (bottomLabel);
+			Win.Add (leftButton);
+			Win.Add (centerButton);
+			Win.Add (rightButton);
+
+		}
+
+		public override void Run ()
+		{
+			base.Run ();
+		}
+	}
+
+	public static class StringExtensions {
+		public static string Repeat (this string instr, int n)
+		{
+			if (n <= 0) {
+				return null;
+			}
+
+			if (string.IsNullOrEmpty (instr) || n == 1) {
+				return instr;
+			}
+
+			return new StringBuilder (instr.Length * n)
+				.Insert (0, instr, n)
+				.ToString ();
+		}
+	}
+}

+ 0 - 82
UICatalog/Scenarios/DimAndPosLayout.cs

@@ -1,82 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Terminal.Gui;
-
-namespace UICatalog {
-	/// <summary>
-	/// This Scenario demonstrates how to use Termina.gui's Dim and Pos Layout System. 
-	/// [x] - Using Dim.Fill to fill a window
-	/// [x] - Using Dim.Fill and Dim.Pos to automatically align controls based on an initial control
-	/// [ ] - ...
-	/// </summary>
-	[ScenarioMetadata (Name: "DimAndPosLayout", Description: "Demonstrates using the Dim and Pos Layout System")]
-	[ScenarioCategory ("Layout")]
-	class DimAndPosLayout : Scenario {
-
-		public override void Setup ()
-		{
-			Top.LayoutStyle = LayoutStyle.Computed;
-			// Demonstrate using Dim to create a ruler that always measures the top-level window's width
-			// BUGBUG: Dim.Fill returns too big a value sometimes.
-			//const string rule = "|123456789";
-			//var labelRuler = new Label ("ruler") {
-			//	X = 0,
-			//	Y = 0,
-			//	Width = Dim.Fill (1),  // BUGBUG: I don't think this should be needed; DimFill() should respect container's frame. X does.
-			//	ColorScheme = Colors.Error
-			//};
-
-			//Application.OnResized += () => {
-			//	labelRuler.Text = rule.Repeat ((int)Math.Ceiling((double)(labelRuler.Bounds.Width) / (double)rule.Length))[0..(labelRuler.Bounds.Width)];
-			//};
-
-			//win.Add (labelRuler);
-
-			// Demonstrate using Dim to create a window that fills the parent with a margin
-			int margin = 20;
-			var subWin = new Window ($"Sub Windoww with {margin} character margin") {
-				X = margin,
-				Y = 2,
-				Width = Dim.Fill (margin),
-				Height = Dim.Fill ()
-			};
-			Win.Add (subWin);
-
-			int i = 1;
-			string txt = "Hello world, how are you doing today";
-			var labelList = new List<Label> ();
-			labelList.Add (new Label ($"Label:"));
-			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Left, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()) + 1, ColorScheme = Colors.Dialog });
-			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Right, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()) + 1, ColorScheme = Colors.Dialog });
-			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Centered, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()) + 1, ColorScheme = Colors.Dialog });
-			labelList.Add (new Label ($"{i++}-{txt}") { TextAlignment = Terminal.Gui.TextAlignment.Justified, Width = Dim.Fill (1), X = 0, Y = Pos.Bottom (labelList.LastOrDefault ()) + 1, ColorScheme = Colors.Dialog });
-
-			subWin.Add (labelList.ToArray ());
-			//subWin.LayoutSubviews ();
-		}
-
-		public override void Run ()
-		{
-			base.Run ();
-		}
-	}
-
-	public static class StringExtensions {
-		public static string Repeat (this string instr, int n)
-		{
-			if (n <= 0) {
-				return null;
-			}
-
-			if (string.IsNullOrEmpty (instr) || n == 1) {
-				return instr;
-			}
-
-			return new StringBuilder (instr.Length * n)
-				.Insert (0, instr, n)
-				.ToString ();
-		}
-	}
-}

+ 5 - 5
UICatalog/Scenarios/Keys.cs

@@ -43,8 +43,8 @@ namespace UICatalog {
 			public override bool ProcessColdKey (KeyEvent keyEvent)
 			public override bool ProcessColdKey (KeyEvent keyEvent)
 			{
 			{
 				_processColdKeyList.Add (keyEvent.ToString ());
 				_processColdKeyList.Add (keyEvent.ToString ());
-				return base.ProcessHotKey (keyEvent);
 
 
+				return base.ProcessColdKey (keyEvent);
 			}
 			}
 		}
 		}
 
 
@@ -92,7 +92,7 @@ namespace UICatalog {
 			};
 			};
 			Win.Add (labelKeypress);
 			Win.Add (labelKeypress);
 
 
-			Win.OnKeyPress += (KeyEvent keyEvent) => labelKeypress.Text = keyEvent.ToString ();
+			Win.KeyPress += (sender, a) => labelKeypress.Text = a.KeyEvent.ToString ();
 
 
 			// Key stroke log:
 			// Key stroke log:
 			var keyLogLabel = new Label ("Key stroke log:") {
 			var keyLogLabel = new Label ("Key stroke log:") {
@@ -119,9 +119,9 @@ namespace UICatalog {
 				keyStrokeListView.MoveDown ();
 				keyStrokeListView.MoveDown ();
 			}
 			}
 
 
-			Win.OnKeyDown += (KeyEvent keyEvent) => KeyDownPressUp (keyEvent, "Down");
-			Win.OnKeyPress += (KeyEvent keyEvent) => KeyDownPressUp (keyEvent, "Press");
-			Win.OnKeyUp += (KeyEvent keyEvent) => KeyDownPressUp (keyEvent, "Up");
+			Win.KeyDown += (sender, a) => KeyDownPressUp (a.KeyEvent, "Down");
+			Win.KeyPress += (sender, a) => KeyDownPressUp (a.KeyEvent, "Press");
+			Win.KeyUp += (sender, a) => KeyDownPressUp (a.KeyEvent, "Up");
 
 
 			// ProcessKey log:
 			// ProcessKey log:
 			// BUGBUG: Label is not positioning right with Pos, so using TextField instead
 			// BUGBUG: Label is not positioning right with Pos, so using TextField instead

+ 66 - 11
UICatalog/Scenarios/Progress.cs

@@ -1,4 +1,5 @@
 using System;
 using System;
+using System.Threading;
 using Terminal.Gui;
 using Terminal.Gui;
 
 
 namespace UICatalog {
 namespace UICatalog {
@@ -9,39 +10,93 @@ namespace UICatalog {
 	[ScenarioCategory ("Controls")]
 	[ScenarioCategory ("Controls")]
 	class Progress : Scenario {
 	class Progress : Scenario {
 
 
-		private ProgressBar _progressBar;
+		private ProgressBar _activityProgressBar;
+		private ProgressBar _pulseProgressBar;
+		private Timer _timer;
+		private object _timeoutToken;
+
 		public override void Setup ()
 		public override void Setup ()
 		{
 		{
-			Win.Add (new Button ("Start") {
-				X = Pos.Center () - 20,
+			var pulseButton = new Button ("Pulse") {
+				X = Pos.Center (),
 				Y = Pos.Center () - 5,
 				Y = Pos.Center () - 5,
+				Clicked = () => Pulse ()
+			};
+
+			Win.Add (new Button ("Start Timer") {
+				X = Pos.Left(pulseButton) - 20,
+				Y = Pos.Y(pulseButton),
 				Clicked = () => Start ()
 				Clicked = () => Start ()
-			}); ;
+			});
 
 
-			Win.Add (new Button ("Stop") {
-				X = Pos.Center () + 10,
-				Y = Pos.Center () - 5,
+			Win.Add (new Button ("Stop Timer") {
+				X = Pos.Right (pulseButton) + 20, // BUGBUG: Right is somehow adding additional width
+				Y = Pos.Y (pulseButton),
 				Clicked = () => Stop()
 				Clicked = () => Stop()
 			});
 			});
 
 
-			_progressBar = new ProgressBar () {
+			Win.Add (pulseButton);
+
+			_activityProgressBar = new ProgressBar () {
 				X = Pos.Center (),
 				X = Pos.Center (),
 				// BUGBUG: If you remove the +1 below the control is drawn at top?!?!
 				// BUGBUG: If you remove the +1 below the control is drawn at top?!?!
 				Y = Pos.Center ()+1,
 				Y = Pos.Center ()+1,
 				Width = 30,
 				Width = 30,
 				Fraction = 0.25F,
 				Fraction = 0.25F,
 			};
 			};
-			Win.Add (_progressBar);
+			Win.Add (_activityProgressBar);
+
+			_pulseProgressBar = new ProgressBar () {
+				X = Pos.Center (),
+				// BUGBUG: If you remove the +1 below the control is drawn at top?!?!
+				Y = Pos.Center () + 3,
+				Width = 30,
+			};
+			Win.Add (_pulseProgressBar);
+		}
+
+		protected override void Dispose (bool disposing)
+		{
+			_timer?.Dispose ();
+			_timer = null;
+			Application.MainLoop.RemoveTimeout (_timeoutToken);
+			base.Dispose (disposing);
+		}
+
+		private void Pulse ()
+		{
+			if (_activityProgressBar.Fraction + 0.01F >= 1) {
+				_activityProgressBar.Fraction = 0F;
+			} else {
+				_activityProgressBar.Fraction += 0.01F;
+			}
+			_pulseProgressBar.Pulse ();
 		}
 		}
 
 
 		private void Start ()
 		private void Start ()
 		{
 		{
-			_progressBar.Fraction = 0F;
+			_timer?.Dispose ();
+			_timer = null;
+
+			_activityProgressBar.Fraction = 0F;
+			_pulseProgressBar.Fraction = 0F;
+
+			_timer = new Timer ((o) => Application.MainLoop.Invoke (() => Pulse ()), null, 0, 10);
+
+			// BUGBUG: This timeout does nothing but return true, however it trigger the Application.MainLoop
+			// to run the Action. Without this timeout, the display updates are random, 
+			// or triggered by user interaction with the UI. See #155
+			_timeoutToken = Application.MainLoop.AddTimeout (TimeSpan.FromMilliseconds (10), loop => true);
 		}
 		}
 
 
 		private void Stop ()
 		private void Stop ()
 		{
 		{
-			_progressBar.Fraction = 1F;
+			_timer?.Dispose ();
+			_timer = null;
+			Application.MainLoop.RemoveTimeout (_timeoutToken);
+
+			_activityProgressBar.Fraction = 1F;
+			_pulseProgressBar.Fraction = 1F;
 		}
 		}
 	}
 	}
 }
 }

+ 45 - 11
UICatalog/Scenarios/TimeAndDate.cs

@@ -8,22 +8,56 @@ namespace UICatalog {
 	class TimeAndDate : Scenario {
 	class TimeAndDate : Scenario {
 		public override void Setup ()
 		public override void Setup ()
 		{
 		{
-			// NOTE: The TimeField control is not ready for prime-time.
+			// NOTE: The TimeField control is not ready for prime-time. See #246
 
 
-			Win.Add (new TimeField (0, 0, DateTime.Now, isShort: false) {
+			var longTime = new TimeField (0, 0, DateTime.Now, isShort: false) {
 				// BUGBUG: TimeField does not support Computed Layout
 				// BUGBUG: TimeField does not support Computed Layout
-				//X = Pos.Center (),
-				//Y = Pos.Center () - 1,
-				X = 10,
+				X = Pos.Center (),
 				Y = 2,
 				Y = 2,
-			});
+				ReadOnly = false,
+			};
+			Win.Add (longTime);
+
+			var shortTime = new TimeField (0, 2, DateTime.Now, isShort: true) {
+				// BUGBUG: TimeField does not support Computed Layout
+				X = Pos.Center (),
+				Y = Pos.Bottom(longTime) + 1,
+				ReadOnly = true,
+			};
+			Win.Add (shortTime);
+
+			var shortDate = new DateField (0, 2, DateTime.Now, isShort: true) {
+				// BUGBUG: TimeField does not support Computed Layout
+				X = Pos.Center (),
+				Y = Pos.Bottom (shortTime) + 1,
+				ReadOnly = true,
+			};
+			Win.Add (shortDate);
 
 
-			Win.Add (new TimeField (0, 2, DateTime.Now, isShort: true) {
+			var longDate = new TimeField (0, 2, DateTime.Now, isShort: true) {
 				// BUGBUG: TimeField does not support Computed Layout
 				// BUGBUG: TimeField does not support Computed Layout
-				//X = Pos.Center (),
-				//Y = Pos.Center () + 1,
-				X = 10,
-				Y = 3,
+				X = Pos.Center (),
+				Y = Pos.Bottom (shortDate) + 1,
+				ReadOnly = true,
+			};
+			Win.Add (longDate);
+
+			Win.Add (new Button ("Swap Long/Short & Read/Read Only") {
+				X = Pos.Center (),
+				Y = Pos.Bottom (Win) - 5,
+				Clicked = () => {
+					longTime.ReadOnly = !longTime.ReadOnly;
+					shortTime.ReadOnly = !shortTime.ReadOnly;
+
+					//longTime.IsShortFormat = !longTime.IsShortFormat;
+					//shortTime.IsShortFormat = !shortTime.IsShortFormat;
+
+					longDate.ReadOnly = !longDate.ReadOnly;
+					shortDate.ReadOnly = !shortDate.ReadOnly;
+
+					//longDate.IsShortFormat = !longDate.IsShortFormat;
+					//shortDate.IsShortFormat = !shortDate.IsShortFormat;
+				}
 			});
 			});
 		}
 		}
 	}
 	}

二進制
UICatalog/screenshot.png


+ 1 - 1
docfx/articles/index.md

@@ -1,5 +1,5 @@
 # Conceptual Documentation
 # Conceptual Documentation
 
 
-* [Gui.cs Overview](overview.html)
+* [Terminal.Gui Overview](overview.html)
 * [Keyboard Event Processing](keyboard.html)
 * [Keyboard Event Processing](keyboard.html)
 * [Event Processing and the Application Main Loop](mainloop.md)
 * [Event Processing and the Application Main Loop](mainloop.md)

+ 1 - 1
docfx/articles/mainloop.md

@@ -12,7 +12,7 @@ class.
 
 
 Mainloops are a common idiom in many user interface toolkits so many
 Mainloops are a common idiom in many user interface toolkits so many
 of the concepts will be familiar to you if you have used other
 of the concepts will be familiar to you if you have used other
-toolkits before.   
+toolkits before.
 
 
 This class provides the following capabilities:
 This class provides the following capabilities:
 
 

二進制
docfx/sample.gif


二進制
docfx/sample.png