diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
deleted file mode 100644
index fe44e5fb5..000000000
--- a/.github/workflows/dotnetcore.yml
+++ /dev/null
@@ -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
diff --git a/Example/demo.cs b/Example/demo.cs
index 98dd80af7..53974b3c0 100644
--- a/Example/demo.cs
+++ b/Example/demo.cs
@@ -92,8 +92,8 @@ static class Demo {
Width = 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;
};
@@ -436,11 +436,11 @@ static class Demo {
#endregion
- #region OnKeyDown / OnKeyPress / OnKeyUp Demo
+ #region KeyDown / KeyPress / KeyUp Demo
private static void OnKeyDownPressUpDemo ()
{
var container = new Dialog (
- "OnKeyDown & OnKeyPress & OnKeyUp demo", 80, 20,
+ "KeyDown & KeyPress & KeyUp demo", 80, 20,
new Button ("Close") { Clicked = () => { Application.RequestStop (); } }) {
Width = 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);
}
#endregion
@@ -628,7 +628,7 @@ static class Demo {
var bottom2 = new Label ("This should go on the bottom of another top-level!");
top.Add (bottom2);
- Application.OnLoad = () => {
+ Application.Loaded += (sender, e) => {
bottom.X = win.X;
bottom.Y = Pos.Bottom (win) - Pos.Top (win) - margin;
bottom2.X = Pos.Left (win);
diff --git a/README.md b/README.md
index 303368499..2b42b3659 100644
--- a/README.md
+++ b/README.md
@@ -2,59 +2,84 @@
[](https://www.nuget.org/packages/Terminal.Gui)
[](https://www.nuget.org/packages/Terminal.Gui)
[](LICENSE)
+[](https://gitter.im/mono/mono?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - The Mono Channel room
-[](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.
+
-
+## 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)
-* [Labels](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Label.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)
-* [Time editing field](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TimeField.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)
-* [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)
+* [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)
+* [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)
-* [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.
+* [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 view](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.TextView.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)
+* [Windows](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui/Terminal.Gui.Window.html)
-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.
-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
-# Documentation
+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.
-* [API documentation](https://migueldeicaza.github.io/gui.cs/api/Terminal.Gui.html) for details.
+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`.
-* [Overview](https://migueldeicaza.github.io/gui.cs/articles/overview.html) contains the conceptual
- documentation and a walkthrough of the core concepts of `gui.cs`
+To enter the key `ESC`, you can either press `ESC` and wait 100 milliseconds, or you can press `ESC` twice.
-# Sample Usage
+`ESC-0`, and `ESC-1` through `ESC-9` have a special meaning, they map to `F10`, and `F1` to `F9` respectively.
+
+**Terminal.Gui** respects common Mac and Windows keyboard idoms as well. For example, clipboard operations use the familiar `Control/Command-C, X, V` model.
+
+`CTRL-Q` is used for exiting views (and apps).
+
+### Driver model
+
+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
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
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.
+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)**.
-# Installing it
+## Installing
-If you want to try Gui.cs, use NuGet to install the `Terminal.Gui` NuGet package:
+Use NuGet to install the `Terminal.Gui` NuGet package: https://www.nuget.org/packages/Terminal.Gui
-https://www.nuget.org/packages/Terminal.Gui
+## Running and Building
-# Running and Building
+* *`Terminal.Gui`* - Build and run using the .NET SDK command line tools (`doetnet build` in the root directory) or with Visual Studio 2019.
-You can find a trivial .NET core sample application in the
-"StandaloneExample" directory. You can execute it by running
-`dotnet run` in that directory.
+## Contributing
-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.
+See [Issues](https://github.com/migueldeicaza/gui.cs/issues) for a list of open bugs and enhancements.
-# Input Handling
+## History
-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.
+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.
-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`.
+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.
-To enter the key `ESC`, you can either press `ESC` and wait 100
-milliseconds, or you can press `ESC` twice.
+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)
-`ESC-0`, and `ESC-1` through `ESC-9` have a special meaning, they map to
-`F10`, and `F1` to `F9` respectively.
-
-# Driver model
-
-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.
-
-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.
diff --git a/StandaloneExample/README.md b/StandaloneExample/README.md
index c959ff9f8..d04ad1153 100644
--- a/StandaloneExample/README.md
+++ b/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:
@@ -7,6 +6,4 @@ Simply 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.
diff --git a/TODO.md b/TODO.md
deleted file mode 100644
index 166936357..000000000
--- a/TODO.md
+++ /dev/null
@@ -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.
-
diff --git a/Terminal.Gui/Core.cs b/Terminal.Gui/Core.cs
index 4bed3fbf6..2bf0d78f7 100644
--- a/Terminal.Gui/Core.cs
+++ b/Terminal.Gui/Core.cs
@@ -126,7 +126,7 @@ namespace Terminal.Gui {
///
/// Contains the details about the key that produced the event.
/// true if the event was handled
- public virtual bool KeyDown (KeyEvent keyEvent)
+ public virtual bool OnKeyDown (KeyEvent keyEvent)
{
return false;
}
@@ -136,7 +136,7 @@ namespace Terminal.Gui {
///
/// Contains the details about the key that produced the event.
/// true if the event was handled
- public virtual bool KeyUp (KeyEvent keyEvent)
+ public virtual bool OnKeyUp (KeyEvent keyEvent)
{
return false;
}
@@ -607,7 +607,7 @@ namespace Terminal.Gui {
return;
while (subviews.Count > 0) {
- Remove (subviews[0]);
+ Remove (subviews [0]);
}
}
@@ -705,9 +705,9 @@ namespace Terminal.Gui {
{
PerformActionForSubview (subview, x => {
var idx = subviews.IndexOf (x);
- if (idx+1 < subviews.Count) {
+ if (idx + 1 < subviews.Count) {
subviews.Remove (x);
- subviews.Insert (idx+1, x);
+ subviews.Insert (idx + 1, x);
}
});
}
@@ -910,7 +910,7 @@ namespace Terminal.Gui {
OnEnter ();
else
OnLeave ();
- SetNeedsDisplay ();
+ SetNeedsDisplay ();
base.HasFocus = value;
// Remove focus down the chain of subviews if focus is removed
@@ -1062,18 +1062,33 @@ namespace Terminal.Gui {
focused.EnsureFocus ();
// Send focus upwards
- SuperView?.SetFocus(this);
+ SuperView?.SetFocus (this);
+ }
+
+ ///
+ /// Specifies the event arguments for
+ ///
+ public class KeyEventEventArgs : EventArgs {
+ ///
+ /// Constructs.
+ ///
+ ///
+ public KeyEventEventArgs(KeyEvent ke) => KeyEvent = ke;
+ ///
+ /// The for the event.
+ ///
+ public KeyEvent KeyEvent { get; set; }
}
///
/// Invoked when a character key is pressed and occurs after the key up event.
///
- public Action OnKeyPress;
+ public event EventHandler KeyPress;
///
public override bool ProcessKey (KeyEvent keyEvent)
{
- OnKeyPress?.Invoke (keyEvent);
+ KeyPress?.Invoke (this, new KeyEventEventArgs(keyEvent));
if (Focused?.ProcessKey (keyEvent) == true)
return true;
@@ -1083,6 +1098,7 @@ namespace Terminal.Gui {
///
public override bool ProcessHotKey (KeyEvent keyEvent)
{
+ KeyPress?.Invoke (this, new KeyEventEventArgs (keyEvent));
if (subviews == null || subviews.Count == 0)
return false;
foreach (var view in subviews)
@@ -1094,6 +1110,7 @@ namespace Terminal.Gui {
///
public override bool ProcessColdKey (KeyEvent keyEvent)
{
+ KeyPress?.Invoke (this, new KeyEventEventArgs(keyEvent));
if (subviews == null || subviews.Count == 0)
return false;
foreach (var view in subviews)
@@ -1105,16 +1122,16 @@ namespace Terminal.Gui {
///
/// Invoked when a key is pressed
///
- public Action OnKeyDown;
+ public event EventHandler KeyDown;
- ///
- public override bool KeyDown (KeyEvent keyEvent)
+ /// Contains the details about the key that produced the event.
+ public override bool OnKeyDown (KeyEvent keyEvent)
{
- OnKeyDown?.Invoke (keyEvent);
+ KeyDown?.Invoke (this, new KeyEventEventArgs (keyEvent));
if (subviews == null || subviews.Count == 0)
return false;
foreach (var view in subviews)
- if (view.KeyDown (keyEvent))
+ if (view.OnKeyDown (keyEvent))
return true;
return false;
@@ -1123,16 +1140,16 @@ namespace Terminal.Gui {
///
/// Invoked when a key is released
///
- public Action OnKeyUp;
+ public event EventHandler KeyUp;
- ///
- public override bool KeyUp (KeyEvent keyEvent)
+ /// Contains the details about the key that produced the event.
+ public override bool OnKeyUp (KeyEvent keyEvent)
{
- OnKeyUp?.Invoke (keyEvent);
+ KeyUp?.Invoke (this, new KeyEventEventArgs (keyEvent));
if (subviews == null || subviews.Count == 0)
return false;
foreach (var view in subviews)
- if (view.KeyUp (keyEvent))
+ if (view.OnKeyUp (keyEvent))
return true;
return false;
@@ -1174,7 +1191,7 @@ namespace Terminal.Gui {
public void FocusLast ()
{
if (subviews == null) {
- SuperView?.SetFocus(this);
+ SuperView?.SetFocus (this);
return;
}
@@ -1221,7 +1238,7 @@ namespace Terminal.Gui {
w.FocusLast ();
SetFocus (w);
- return true;
+ return true;
}
}
if (focused != null) {
@@ -1538,12 +1555,12 @@ namespace Terminal.Gui {
///
/// Check id current toplevel has menu bar
///
- public bool HasMenuBar { get; set; }
+ public MenuBar MenuBar { get; set; }
///
/// Check id current toplevel has status bar
///
- public bool HasStatusBar { get; set; }
+ public StatusBar StatusBar { get; set; }
///
public override bool ProcessKey (KeyEvent keyEvent)
@@ -1602,9 +1619,9 @@ namespace Terminal.Gui {
{
if (this == Application.Top) {
if (view is MenuBar)
- HasMenuBar = true;
+ MenuBar = view as MenuBar;
if (view is StatusBar)
- HasStatusBar = true;
+ StatusBar = view as StatusBar;
}
base.Add (view);
}
@@ -1614,9 +1631,9 @@ namespace Terminal.Gui {
{
if (this == Application.Top) {
if (view is MenuBar)
- HasMenuBar = true;
+ MenuBar = null;
if (view is StatusBar)
- HasStatusBar = true;
+ StatusBar = null;
}
base.Remove (view);
}
@@ -1625,8 +1642,8 @@ namespace Terminal.Gui {
public override void RemoveAll ()
{
if (this == Application.Top) {
- HasMenuBar = false;
- HasStatusBar = false;
+ MenuBar = null;
+ StatusBar = null;
}
base.RemoveAll ();
}
@@ -1634,21 +1651,21 @@ namespace Terminal.Gui {
internal void EnsureVisibleBounds (Toplevel top, int x, int y, out int nx, out int ny)
{
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;
- if (SuperView == null)
- m = Application.Top.HasMenuBar;
+ if (SuperView == null || SuperView.GetType() != typeof(Toplevel))
+ m = Application.Top.MenuBar != null;
else
- m = ((Toplevel)SuperView).HasMenuBar;
+ m = ((Toplevel)SuperView).MenuBar != null;
int l = m ? 1 : 0;
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
- s = ((Toplevel)SuperView).HasStatusBar;
+ s = ((Toplevel)SuperView).StatusBar != null;
l = s ? Driver.Rows - 1 : Driver.Rows;
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 ()
@@ -1667,9 +1684,15 @@ namespace Terminal.Gui {
top.X = nx;
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;
- if (this == Application.Top) {
+ if (this == Application.Top || this == Application.Current) {
if (!NeedDisplay.IsEmpty) {
Driver.SetAttribute (Colors.TopLevel.Normal);
Clear (region);
@@ -1796,7 +1819,7 @@ namespace Terminal.Gui {
this.Title = title;
int wb = 1 + padding;
this.padding = padding;
- contentView = new ContentView () {
+ contentView = new ContentView () {
X = wb,
Y = wb,
Width = Dim.Fill (wb),
@@ -2008,7 +2031,7 @@ namespace Terminal.Gui {
///
/// See also
///
- static public event EventHandler Iteration;
+ public static event EventHandler Iteration;
///
/// Returns a rectangle that is centered in the screen for the provided size.
@@ -2079,7 +2102,7 @@ namespace Terminal.Gui {
if (UseSystemConsole) {
mainLoopDriver = new Mono.Terminal.NetMainLoop ();
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 ();
mainLoopDriver = windowsDriver;
Driver = windowsDriver;
@@ -2137,7 +2160,7 @@ namespace Terminal.Gui {
static void ProcessKeyEvent (KeyEvent ke)
{
- var chain = toplevels.ToList();
+ var chain = toplevels.ToList ();
foreach (var topLevel in chain) {
if (topLevel.ProcessHotKey (ke))
return;
@@ -2165,7 +2188,7 @@ namespace Terminal.Gui {
{
var chain = toplevels.ToList ();
foreach (var topLevel in chain) {
- if (topLevel.KeyDown (ke))
+ if (topLevel.OnKeyDown (ke))
return;
if (topLevel.Modal)
break;
@@ -2177,7 +2200,7 @@ namespace Terminal.Gui {
{
var chain = toplevels.ToList ();
foreach (var topLevel in chain) {
- if (topLevel.KeyUp (ke))
+ if (topLevel.OnKeyUp (ke))
return;
if (topLevel.Modal)
break;
@@ -2194,7 +2217,7 @@ namespace Terminal.Gui {
return null;
}
- if (start.InternalSubviews != null){
+ if (start.InternalSubviews != null) {
int count = start.InternalSubviews.Count;
if (count > 0) {
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;
}
@@ -2242,7 +2265,7 @@ namespace Terminal.Gui {
///
/// Merely a debugging aid to see the raw mouse events
///
- static public Action RootMouseEvent;
+ public static Action RootMouseEvent;
internal static View wantContinuousButtonPressedView;
static View lastMouseOwnerView;
@@ -2267,8 +2290,12 @@ namespace Terminal.Gui {
OfY = me.Y - newxy.Y,
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) {
@@ -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;
+ }
+
///
- /// 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.
///
- static public Action OnLoad;
+ public static event EventHandler Loaded;
///
/// Building block API: Prepares the provided toplevel for execution.
@@ -2321,7 +2354,7 @@ namespace Terminal.Gui {
/// the method, and then the method upon termination which will
/// undo these changes.
///
- static public RunState Begin (Toplevel toplevel)
+ public static RunState Begin (Toplevel toplevel)
{
if (toplevel == null)
throw new ArgumentNullException (nameof (toplevel));
@@ -2330,11 +2363,11 @@ namespace Terminal.Gui {
Init ();
if (toplevel is ISupportInitializeNotification initializableNotification &&
!initializableNotification.IsInitialized) {
- initializableNotification.BeginInit();
- initializableNotification.EndInit();
+ initializableNotification.BeginInit ();
+ initializableNotification.EndInit ();
} else if (toplevel is ISupportInitialize initializable) {
- initializable.BeginInit();
- initializable.EndInit();
+ initializable.BeginInit ();
+ initializable.EndInit ();
}
toplevels.Push (toplevel);
Current = toplevel;
@@ -2342,7 +2375,7 @@ namespace Terminal.Gui {
if (toplevel.LayoutStyle == LayoutStyle.Computed)
toplevel.RelativeLayout (new Rect (0, 0, Driver.Cols, Driver.Rows));
toplevel.LayoutSubviews ();
- OnLoad?.Invoke ();
+ Loaded?.Invoke (null, new ResizedEventArgs () { Rows = Driver.Rows, Cols = Driver.Cols } );
toplevel.WillPresent ();
Redraw (toplevel);
toplevel.PositionCursor ();
@@ -2355,7 +2388,7 @@ namespace Terminal.Gui {
/// Building block API: completes the execution of a Toplevel that was started with Begin.
///
/// The runstate returned by the method.
- static public void End (RunState runState)
+ public static void End (RunState runState)
{
if (runState == null)
throw new ArgumentNullException (nameof (runState));
@@ -2409,9 +2442,8 @@ namespace Terminal.Gui {
toplevels.Pop ();
if (toplevels.Count == 0)
Shutdown ();
- else
- {
- Current = toplevels.Peek();
+ else {
+ Current = toplevels.Peek ();
Refresh ();
}
}
@@ -2480,7 +2512,7 @@ namespace Terminal.Gui {
///
public static void Run () where T : Toplevel, new()
{
- Init (() => new T());
+ Init (() => new T ());
Run (Top);
}
@@ -2525,14 +2557,28 @@ namespace Terminal.Gui {
}
///
- /// Invoked when the terminal was resized.
+ /// Event arguments for the event.
///
- static public Action OnResized;
+ public class ResizedEventArgs : EventArgs {
+ ///
+ /// The number of rows in the resized terminal.
+ ///
+ public int Rows { get; set; }
+ ///
+ /// The number of columns in the resized terminal.
+ ///
+ public int Cols { get; set; }
+ }
+
+ ///
+ /// Invoked when the terminal was resized. The new size of the terminal is provided.
+ ///
+ public static event EventHandler Resized;
static void TerminalResized ()
{
- OnResized?.Invoke ();
var full = new Rect (0, 0, Driver.Cols, Driver.Rows);
+ Resized?.Invoke (null, new ResizedEventArgs () { Cols = full.Width, Rows = full.Height });
Driver.Clip = full;
foreach (var t in toplevels) {
t.PositionToplevels ();
diff --git a/Terminal.Gui/Drivers/CursesDriver.cs b/Terminal.Gui/Drivers/CursesDriver.cs
index 95a658108..2e8e7059a 100644
--- a/Terminal.Gui/Drivers/CursesDriver.cs
+++ b/Terminal.Gui/Drivers/CursesDriver.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
+using System.Threading.Tasks;
using Mono.Terminal;
using NStack;
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 () {
X = cev.X,
Y = cev.Y,
- Flags = (MouseFlags)cev.ButtonState
+ Flags = mf
};
}
@@ -252,10 +426,15 @@ namespace Terminal.Gui {
keyUpHandler (new KeyEvent ((Key)wch));
}
+ Action mouseHandler;
+ MainLoop mainLoop;
+
public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler)
{
// 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 => {
ProcessInput (keyHandler, keyUpHandler, mouseHandler);
@@ -425,21 +604,21 @@ namespace Terminal.Gui {
Console.Out.Flush ();
}
- int lastMouseInterval;
- bool mouseGrabbed;
+ //int lastMouseInterval;
+ //bool mouseGrabbed;
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 ()
{
- mouseGrabbed = false;
- Curses.mouseinterval (lastMouseInterval);
+ //mouseGrabbed = false;
+ //Curses.mouseinterval (lastMouseInterval);
}
}
diff --git a/Terminal.Gui/Drivers/WindowsDriver.cs b/Terminal.Gui/Drivers/WindowsDriver.cs
index 343182dc0..0576071e3 100644
--- a/Terminal.Gui/Drivers/WindowsDriver.cs
+++ b/Terminal.Gui/Drivers/WindowsDriver.cs
@@ -673,10 +673,10 @@ namespace Terminal.Gui {
keyUpHandler (key);
} else {
if (inputEvent.KeyEvent.bKeyDown) {
+ // Key Down - Fire KeyDown Event and KeyStroke (ProcessKey) Event
+ keyHandler (new KeyEvent (map));
keyDownHandler (new KeyEvent (map));
} else {
- // Key Up - Fire KeyDown Event and KeyStroke (ProcessKey) Event
- keyHandler (new KeyEvent (map));
keyUpHandler (new KeyEvent (map));
}
}
diff --git a/Terminal.Gui/MonoCurses/constants.cs b/Terminal.Gui/MonoCurses/constants.cs
index df19c30e2..8eed47967 100644
--- a/Terminal.Gui/MonoCurses/constants.cs
+++ b/Terminal.Gui/MonoCurses/constants.cs
@@ -2,6 +2,8 @@
* This file is autogenerated by the attrib.c program, do not edit
*/
+#define XTERM1006
+
using System;
namespace Unix.Terminal {
@@ -77,6 +79,15 @@ namespace Unix.Terminal {
ReportMousePosition = unchecked((int)0x8000000),
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 KeyBackspace = unchecked((int)0x107);
public const int KeyUp = unchecked((int)0x103);
@@ -110,30 +121,30 @@ namespace Unix.Terminal {
public const int ShiftKeyPPage = unchecked((int)0x18e);
public const int ShiftKeyHome = unchecked((int)0x187);
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;
static public int ColorPair(int n){
diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs
index 309c408e0..7262fa478 100644
--- a/Terminal.Gui/Views/ListView.cs
+++ b/Terminal.Gui/Views/ListView.cs
@@ -63,6 +63,12 @@ namespace Terminal.Gui {
/// Item index.
/// If set to true value.
void SetMark (int item, bool value);
+
+ ///
+ /// Return the source as IList.
+ ///
+ ///
+ IList ToList ();
}
///
@@ -257,7 +263,7 @@ namespace Terminal.Gui {
/// Redraws the ListView
///
/// Region.
- public override void Redraw(Rect region)
+ public override void Redraw (Rect region)
{
var current = ColorScheme.Focus;
Driver.SetAttribute (current);
@@ -279,12 +285,12 @@ namespace Terminal.Gui {
Move (0, row);
if (source == null || item >= source.Count) {
for (int c = 0; c < f.Width; c++)
- Driver.AddRune(' ');
+ Driver.AddRune (' ');
} else {
if (allowsMarking) {
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 {
///
/// This event is raised when the cursor selection has changed.
///
- public event Action SelectedChanged;
+ public event EventHandler SelectedChanged;
///
/// This event is raised on Enter key or Double Click to open the selected item.
///
- public event EventHandler OpenSelectedItem;
+ public event EventHandler OpenSelectedItem;
///
/// Handles cursor movement for this view, passes all other events.
@@ -312,27 +318,27 @@ namespace Terminal.Gui {
switch (kb.Key) {
case Key.CursorUp:
case Key.ControlP:
- return MoveUp();
+ return MoveUp ();
case Key.CursorDown:
case Key.ControlN:
- return MoveDown();
+ return MoveDown ();
case Key.ControlV:
case Key.PageDown:
- return MovePageDown();
+ return MovePageDown ();
case Key.PageUp:
- return MovePageUp();
+ return MovePageUp ();
case Key.Space:
- if (MarkUnmarkRow())
+ if (MarkUnmarkRow ())
return true;
else
break;
case Key.Enter:
- OpenSelectedItem?.Invoke (this, new EventArgs ());
+ OnOpenSelectedItem ();
break;
}
@@ -340,7 +346,7 @@ namespace Terminal.Gui {
}
///
- ///
+ /// Prevents marking if it's not allowed mark and if it's not allows multiple selection.
///
///
public virtual bool AllowsAll ()
@@ -359,13 +365,14 @@ namespace Terminal.Gui {
}
///
- ///
+ /// Marks an unmarked row.
///
///
- public virtual bool MarkUnmarkRow(){
+ public virtual bool MarkUnmarkRow ()
+ {
if (AllowsAll ()) {
- Source.SetMark(SelectedItem, !Source.IsMarked(SelectedItem));
- SetNeedsDisplay();
+ Source.SetMark (SelectedItem, !Source.IsMarked (SelectedItem));
+ SetNeedsDisplay ();
return true;
}
@@ -373,84 +380,114 @@ namespace Terminal.Gui {
}
///
- ///
+ /// Moves to the next page.
///
///
- public virtual bool MovePageUp(){
+ public virtual bool MovePageUp ()
+ {
int n = (selected - Frame.Height);
if (n < 0)
n = 0;
- if (n != selected){
+ if (n != selected) {
selected = n;
top = selected;
- if (SelectedChanged != null)
- SelectedChanged();
- SetNeedsDisplay();
+ OnSelectedChanged ();
+ SetNeedsDisplay ();
}
return true;
}
///
- ///
+ /// Moves to the previous page.
///
///
- public virtual bool MovePageDown(){
+ public virtual bool MovePageDown ()
+ {
var n = (selected + Frame.Height);
if (n > source.Count)
n = source.Count - 1;
- if (n != selected){
+ if (n != selected) {
selected = n;
if (source.Count >= Frame.Height)
top = selected;
else
top = 0;
- if (SelectedChanged != null)
- SelectedChanged();
- SetNeedsDisplay();
+ OnSelectedChanged ();
+ SetNeedsDisplay ();
}
return true;
}
///
- ///
+ /// Moves to the next row.
///
///
- public virtual bool MoveDown(){
- if (selected + 1 < source.Count){
+ public virtual bool MoveDown ()
+ {
+ if (selected + 1 < source.Count) {
selected++;
if (selected >= top + Frame.Height)
top++;
- if (SelectedChanged != null)
- SelectedChanged();
- SetNeedsDisplay();
+ OnSelectedChanged ();
+ SetNeedsDisplay ();
}
return true;
}
///
- ///
+ /// Moves to the previous row.
///
///
- public virtual bool MoveUp(){
- if (selected > 0){
+ public virtual bool MoveUp ()
+ {
+ if (selected > 0) {
selected--;
if (selected < top)
top = selected;
- if (SelectedChanged != null)
- SelectedChanged();
- SetNeedsDisplay();
+ OnSelectedChanged ();
+ SetNeedsDisplay ();
}
return true;
}
+ int lastSelectedItem = -1;
+
+ ///
+ /// Invokes the SelectedChanged event if it is defined.
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ /// Invokes the OnOpenSelectedItem event if it is defined.
+ ///
+ ///
+ public virtual bool OnOpenSelectedItem ()
+ {
+ var value = source.ToList () [selected];
+ OpenSelectedItem?.Invoke (this, new ListViewItemEventArgs (selected, value));
+
+ return true;
+ }
+
///
/// Positions the cursor in this view
///
- public override void PositionCursor()
+ public override void PositionCursor ()
{
if (allowsMarking)
Move (1, selected - top);
@@ -461,7 +498,8 @@ namespace Terminal.Gui {
///
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;
if (!HasFocus)
@@ -470,6 +508,14 @@ namespace Terminal.Gui {
if (source == null)
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)
return true;
@@ -479,10 +525,10 @@ namespace Terminal.Gui {
SetNeedsDisplay ();
return true;
}
- SelectedChanged?.Invoke ();
+ OnSelectedChanged ();
SetNeedsDisplay ();
if (me.Flags == MouseFlags.Button1DoubleClicked)
- OpenSelectedItem?.Invoke (this, new EventArgs ());
+ OnOpenSelectedItem ();
return true;
}
}
@@ -497,7 +543,7 @@ namespace Terminal.Gui {
int count;
///
- /// constructor
+ /// Constructor based on a source.
///
///
public ListWrapper (IList source)
@@ -508,7 +554,7 @@ namespace Terminal.Gui {
}
///
- /// Count of items.
+ /// Returns the amount of items in the source.
///
public int Count => src.Count;
@@ -519,7 +565,7 @@ namespace Terminal.Gui {
for (int i = 0; i < byteLen;) {
(var rune, var size) = Utf8.DecodeRune (ustr, i, i - byteLen);
var count = Rune.ColumnWidth (rune);
- if (used+count >= width)
+ if (used + count >= width)
break;
driver.AddRune (rune);
used += count;
@@ -531,15 +577,15 @@ namespace Terminal.Gui {
}
///
- /// Renders an item in the the list.
+ /// Method that render to the appropriate type based on the type of the item passed to it.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// The ListView.
+ /// The driver used by the caller.
+ /// Informs if it's marked or not.
+ /// The item.
+ /// The col where to move.
+ /// The line where to move.
+ /// The item width.
public void Render (ListView container, ConsoleDriver driver, bool marked, int item, int col, int line, int width)
{
container.Move (col, line);
@@ -553,10 +599,10 @@ namespace Terminal.Gui {
}
///
- /// Returns true of the item is marked. false if not.
+ /// Returns true if the item is marked, false otherwise.
///
- ///
- ///
+ /// The item.
+ /// trueIf is marked.falseotherwise.
public bool IsMarked (int item)
{
if (item >= 0 && item < count)
@@ -565,14 +611,48 @@ namespace Terminal.Gui {
}
///
- /// Sets the marked state of an item.
+ /// Sets the item as marked or unmarked based on the value is true or false, respectively.
///
- ///
- ///
+ /// The item
+ /// Marks the item.Unmarked the item.The value.
public void SetMark (int item, bool value)
{
if (item >= 0 && item < count)
marks [item] = value;
}
+
+ ///
+ /// Returns the source as IList.
+ ///
+ ///
+ public IList ToList ()
+ {
+ return src;
+ }
+ }
+
+ ///
+ /// Gets the item and value to use in an event handler.
+ ///
+ public class ListViewItemEventArgs : EventArgs {
+ ///
+ /// The item.
+ ///
+ public int Item { get; }
+ ///
+ /// The item value.
+ ///
+ public object Value { get; }
+
+ ///
+ /// Constructor to sets the item and value passed from.
+ ///
+ /// The item.
+ /// The item value
+ public ListViewItemEventArgs (int item, object value)
+ {
+ Item = item;
+ Value = value;
+ }
}
}
diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs
index 56eecf66c..d6438a8a4 100644
--- a/Terminal.Gui/Views/Menu.cs
+++ b/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) {
host.CloseAllMenus ();
@@ -360,9 +360,9 @@ namespace Terminal.Gui {
public override bool ProcessHotKey (KeyEvent keyEvent)
{
// 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) {
- KeyDown (keyEvent);
+ OnKeyDown (keyEvent);
return true;
}
@@ -563,8 +563,8 @@ namespace Terminal.Gui {
bool openedByAltKey;
- ///
- public override bool KeyDown (KeyEvent keyEvent)
+ ///
+ public override bool OnKeyDown (KeyEvent keyEvent)
{
if (keyEvent.IsAlt) {
openedByAltKey = true;
@@ -574,13 +574,8 @@ namespace Terminal.Gui {
return false;
}
- ///
- /// 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.
- ///
- ///
- ///
- public override bool KeyUp (KeyEvent keyEvent)
+ ///
+ public override bool OnKeyUp (KeyEvent keyEvent)
{
if (keyEvent.IsAlt) {
// 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
- // 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) {
- KeyDown (kb);
- KeyUp (kb);
+ OnKeyDown (kb);
+ OnKeyUp (kb);
return true;
} else if (kb.IsAlt) {
if (FindAndOpenMenuByHotkey (kb)) return true;
diff --git a/Terminal.Gui/Views/ScrollView.cs b/Terminal.Gui/Views/ScrollView.cs
index b10e567b2..e67f43eed 100644
--- a/Terminal.Gui/Views/ScrollView.cs
+++ b/Terminal.Gui/Views/ScrollView.cs
@@ -14,6 +14,8 @@
// - Perhaps allow an option to not display the scrollbar arrow indicators?
using System;
+using System.Reflection;
+
namespace Terminal.Gui {
///
/// ScrollBarViews are views that display a 1-character scrollbar, either horizontal or vertical
@@ -73,7 +75,7 @@ namespace Terminal.Gui {
/// Frame for the scrollbar.
/// The size that this scrollbar represents.
/// The position within this scrollbar.
- /// If set to true this is a vertical scrollbar, otherwize, the scrollbar is horizontal.
+ /// If set to true this is a vertical scrollbar, otherwise, the scrollbar is horizontal.
public ScrollBarView (Rect rect, int size, int position, bool isVertical) : base (rect)
{
vertical = isVertical;
@@ -314,9 +316,35 @@ namespace Terminal.Gui {
/// The view to add to the scrollview.
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);
}
+ 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);
+ }
+
///
/// Gets or sets the visibility for the horizontal scroll indicator.
///
@@ -463,7 +491,7 @@ namespace Terminal.Gui {
switch (kb.Key) {
case Key.CursorUp:
return ScrollUp (1);
- case (Key) 'v' | Key.AltMask:
+ case (Key)'v' | Key.AltMask:
case Key.PageUp:
return ScrollUp (Bounds.Height);
@@ -489,5 +517,18 @@ namespace Terminal.Gui {
}
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;
+ }
}
}
diff --git a/Terminal.Gui/Views/StatusBar.cs b/Terminal.Gui/Views/StatusBar.cs
index 1bb5f2b33..789781815 100644
--- a/Terminal.Gui/Views/StatusBar.cs
+++ b/Terminal.Gui/Views/StatusBar.cs
@@ -107,8 +107,12 @@ namespace Terminal.Gui {
Items = items;
CanFocus = false;
ColorScheme = Colors.Menu;
+ X = 0;
+ Y = Driver.Rows - 1;
+ Width = Dim.Fill ();
+ Height = 1;
- Application.OnLoad += () => {
+ Application.Loaded += (sender, e) => {
X = 0;
Height = 1;
#if SNAP_TO_TOP
@@ -120,7 +124,7 @@ namespace Terminal.Gui {
case StatusBarStyle.SnapToBottom:
#endif
if (Parent == null) {
- Y = Application.Driver.Rows - 1; // TODO: using internals of Application
+ Y = e.Rows - 1;
} else {
Y = Pos.Bottom (Parent);
}
@@ -141,11 +145,11 @@ namespace Terminal.Gui {
///
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);
Driver.SetAttribute (ColorScheme.Normal);
diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs
index 781866ef5..71a53ccd7 100644
--- a/Terminal.Gui/Views/TextField.cs
+++ b/Terminal.Gui/Views/TextField.cs
@@ -28,6 +28,11 @@ namespace Terminal.Gui {
///
public bool Used { get => used; set { used = value; } }
+ ///
+ /// If set to true its not allow any changes in the text.
+ ///
+ public bool ReadOnly { get; set; } = false;
+
///
/// Changed event, raised when the text has clicked.
///
@@ -95,7 +100,7 @@ namespace Terminal.Gui {
set {
base.Frame = value;
var w = base.Frame.Width;
- //first = point > w ? point - w : 0;
+ first = point > w ? point - w : 0;
Adjust ();
}
}
@@ -115,6 +120,9 @@ namespace Terminal.Gui {
}
set {
+ if (ReadOnly)
+ return;
+
var oldText = ustring.Make (text);
text = TextModel.ToRunes (value);
if (!Secret && !isFromHistory) {
@@ -184,13 +192,16 @@ namespace Terminal.Gui {
int col = 0;
int width = Frame.Width;
var tcount = text.Count;
+ var roc = new Attribute (Color.DarkGray, Color.Gray);
for (int idx = 0; idx < tcount; idx++){
var rune = text [idx];
if (idx < p)
continue;
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);
+ else if (ReadOnly)
+ Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : roc);
else
Driver.SetAttribute (idx >= start && length > 0 && idx < start + length ? color.Focus : ColorScheme.Focus);
if (col + cols <= width)
@@ -261,6 +272,9 @@ namespace Terminal.Gui {
switch (kb.Key) {
case Key.DeleteChar:
case Key.ControlD:
+ if (ReadOnly)
+ return true;
+
if (SelectedLength == 0) {
if (text.Count == 0 || text.Count == point)
return true;
@@ -275,6 +289,9 @@ namespace Terminal.Gui {
case Key.Delete:
case Key.Backspace:
+ if (ReadOnly)
+ return true;
+
if (SelectedLength == 0) {
if (point == 0)
return true;
@@ -373,6 +390,9 @@ namespace Terminal.Gui {
break;
case Key.ControlK: // kill-to-end
+ if (ReadOnly)
+ return true;
+
ClearAllSelection ();
if (point >= text.Count)
return true;
@@ -383,6 +403,9 @@ namespace Terminal.Gui {
// Undo
case Key.ControlZ:
+ if (ReadOnly)
+ return true;
+
if (historyText != null && historyText.Count > 0) {
isFromHistory = true;
if (idxhistoryText > 0)
@@ -396,6 +419,9 @@ namespace Terminal.Gui {
//Redo
case Key.ControlY: // Control-y, yank
+ if (ReadOnly)
+ return true;
+
if (historyText != null && historyText.Count > 0) {
isFromHistory = true;
if (idxhistoryText < historyText.Count - 1) {
@@ -455,6 +481,9 @@ namespace Terminal.Gui {
break;
case Key.ControlX:
+ if (ReadOnly)
+ return true;
+
Cut ();
break;
@@ -472,6 +501,9 @@ namespace Terminal.Gui {
if (kb.Key < Key.Space || kb.Key > Key.CharMask)
return false;
+ if (ReadOnly)
+ return true;
+
if (SelectedLength != 0) {
DeleteSelectedText ();
oldCursorPos = point;
@@ -639,7 +671,7 @@ namespace Terminal.Gui {
point = text.Count;
if (point < first)
point = 0;
- return x;
+ return point;
}
void PrepareSelection (int x, int direction = 0)
@@ -682,8 +714,11 @@ namespace Terminal.Gui {
///
/// Copy the selected text to the clipboard.
///
- public void Copy ()
+ public virtual void Copy ()
{
+ if (Secret)
+ return;
+
if (SelectedLength != 0) {
Clipboard.Contents = SelectedText;
}
@@ -692,7 +727,7 @@ namespace Terminal.Gui {
///
/// Cut the selected text to the clipboard.
///
- public void Cut ()
+ public virtual void Cut ()
{
if (SelectedLength != 0) {
Clipboard.Contents = SelectedText;
@@ -715,8 +750,11 @@ namespace Terminal.Gui {
///
/// Paste the selected text from the clipboard.
///
- public void Paste ()
+ public virtual void Paste ()
{
+ if (ReadOnly)
+ return;
+
string actualText = Text.ToString ();
int start = SelectedStart == -1 ? CursorPosition : SelectedStart;
ustring cbTxt = Clipboard.Contents?.ToString () ?? "";
diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs
index 0d6f35a5c..738a6f35f 100644
--- a/Terminal.Gui/Views/TextView.cs
+++ b/Terminal.Gui/Views/TextView.cs
@@ -39,6 +39,7 @@ namespace Terminal.Gui {
if (file == null)
throw new ArgumentNullException (nameof (file));
try {
+ FilePath = file;
var stream = File.OpenRead (file);
} catch {
return false;
@@ -47,6 +48,19 @@ namespace Terminal.Gui {
return true;
}
+ public bool CloseFile ()
+ {
+ if (FilePath == null)
+ throw new ArgumentNullException (nameof (FilePath));
+ try {
+ FilePath = null;
+ lines = new List> ();
+ } catch {
+ return false;
+ }
+ return true;
+ }
+
// Turns the ustring into runes, this does not split the
// contents on a newline if it is present.
internal static List ToRunes (ustring str)
@@ -120,6 +134,8 @@ namespace Terminal.Gui {
return sb.ToString ();
}
+ public string FilePath { get; set; }
+
///
/// The number of text lines in the model
///
@@ -351,6 +367,18 @@ namespace Terminal.Gui {
SetNeedsDisplay ();
}
+ ///
+ /// Closes the contents of the stream into the TextView.
+ ///
+ /// true, if stream was closed, false otherwise.
+ public bool CloseFile()
+ {
+ ResetPosition ();
+ var res = model.CloseFile ();
+ SetNeedsDisplay ();
+ return res;
+ }
+
///
/// The current cursor row.
///
diff --git a/Terminal.sln b/Terminal.sln
index 77680ffd0..3b1fc187e 100644
--- a/Terminal.sln
+++ b/Terminal.sln
@@ -1,13 +1,14 @@
-
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}"
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
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}"
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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,15 +28,17 @@ Global
{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.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.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.Build.0 = Release|Any CPU
EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {9F8F8A4D-7B8D-4C2A-AC5E-CD7117F74C03}
+ EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.TextStylePolicy = $1
diff --git a/UICatalog/Program.cs b/UICatalog/Program.cs
index 14a7956db..a571f99c2 100644
--- a/UICatalog/Program.cs
+++ b/UICatalog/Program.cs
@@ -1,5 +1,6 @@
using NStack;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
@@ -62,7 +63,7 @@ namespace UICatalog {
new MenuBarItem ("_File", new MenuItem [] {
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") {
@@ -119,7 +120,7 @@ namespace UICatalog {
_rightPane.Add (_scenarioListView);
_categoryListView.SelectedItem = 0;
- CategoryListView_SelectedChanged ();
+ _categoryListView.OnSelectedChanged ();
_statusBar = new StatusBar (new StatusItem [] {
//new StatusItem(Key.F1, "~F1~ Help", () => Help()),
@@ -148,7 +149,9 @@ namespace UICatalog {
}
_top = Application.Top;
- _top.OnKeyUp += KeyUpHandler;
+
+ _top.KeyUp += KeyUpHandler;
+
_top.Add (_menu);
_top.Add (_leftPane);
_top.Add (_rightPane);
@@ -227,6 +230,12 @@ namespace UICatalog {
used++;
}
}
+
+ public IList ToList ()
+ {
+ return Scenarios;
+ }
+
}
///
@@ -235,7 +244,7 @@ namespace UICatalog {
/// to not be impacted. Same as for tabs.
///
///
- private static void KeyUpHandler (KeyEvent ke)
+ private static void KeyUpHandler (object sender, View.KeyEventEventArgs a)
{
if (_runningScenario != null) {
//switch (ke.Key) {
@@ -244,8 +253,8 @@ namespace UICatalog {
// break;
//case Key.Enter:
// 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
if (_top.MostFocused == _categoryListView)
_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];
List newlist;
diff --git a/UICatalog/Properties/launchSettings.json b/UICatalog/Properties/launchSettings.json
index 3941ffe72..68c82f53f 100644
--- a/UICatalog/Properties/launchSettings.json
+++ b/UICatalog/Properties/launchSettings.json
@@ -2,7 +2,6 @@
"profiles": {
"UICatalog": {
"commandName": "Project"
-
}
}
}
\ No newline at end of file
diff --git a/UICatalog/README.md b/UICatalog/README.md
index 6f6b019f8..49eebf94c 100644
--- a/UICatalog/README.md
+++ b/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.
- 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).
-- Tag bugs or suggestions for `UI Catalog` in the main `Terminal.Gui` Github Issues with "UICatalog: ".
\ No newline at end of file
+- Tag bugs or suggestions for `UI Catalog` as [`Terminal.Gui` Github Issues](https://github.com/migueldeicaza/gui.cs/issues) with "UICatalog: ".
\ No newline at end of file
diff --git a/UICatalog/Scenario.cs b/UICatalog/Scenario.cs
index e491a4c8e..b43821a4e 100644
--- a/UICatalog/Scenario.cs
+++ b/UICatalog/Scenario.cs
@@ -17,7 +17,9 @@ namespace UICatalog {
/// 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.
///
- public class Scenario {
+ public class Scenario : IDisposable {
+ private bool _disposedValue;
+
///
/// The Top level for the Scenario. This should be set to `Application.Top` in most cases.
///
@@ -177,5 +179,25 @@ namespace UICatalog {
}
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);
+ }
}
}
diff --git a/UICatalog/Scenarios/ComputedLayout.cs b/UICatalog/Scenarios/ComputedLayout.cs
new file mode 100644
index 000000000..d66194f22
--- /dev/null
+++ b/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 {
+ ///
+ /// 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
+ /// [ ] - ...
+ ///
+ [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