mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-02 01:03:29 +01:00
Merge branch 'master' of https://github.com/migueldeicaza/gui.cs into feature/TextFieldAutoComplete
This commit is contained in:
26
.github/workflows/dotnetcore.yml
vendored
26
.github/workflows/dotnetcore.yml
vendored
@@ -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
|
||||
@@ -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);
|
||||
|
||||
172
README.md
172
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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
48
TODO.md
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.
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
|
||||
/// <returns>true if the event was handled</returns>
|
||||
public virtual bool KeyDown (KeyEvent keyEvent)
|
||||
public virtual bool OnKeyDown (KeyEvent keyEvent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
/// <param name="keyEvent">Contains the details about the key that produced the event.</param>
|
||||
/// <returns>true if the event was handled</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Invoked when a character key is pressed and occurs after the key up event.
|
||||
/// </summary>
|
||||
public Action<KeyEvent> OnKeyPress;
|
||||
public event EventHandler<KeyEventEventArgs> KeyPress;
|
||||
|
||||
/// <inheritdoc cref="ProcessKey"/>
|
||||
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 {
|
||||
/// <inheritdoc cref="ProcessHotKey"/>
|
||||
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 {
|
||||
/// <inheritdoc cref="ProcessColdKey"/>
|
||||
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 {
|
||||
/// <summary>
|
||||
/// Invoked when a key is pressed
|
||||
/// </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)
|
||||
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 {
|
||||
/// <summary>
|
||||
/// Invoked when a key is released
|
||||
/// </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)
|
||||
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 {
|
||||
/// <summary>
|
||||
/// Check id current toplevel has menu bar
|
||||
/// </summary>
|
||||
public bool HasMenuBar { get; set; }
|
||||
public MenuBar MenuBar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Check id current toplevel has status bar
|
||||
/// </summary>
|
||||
public bool HasStatusBar { get; set; }
|
||||
public StatusBar StatusBar { get; set; }
|
||||
|
||||
///<inheritdoc cref="ProcessKey"/>
|
||||
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 {
|
||||
/// <remarks>
|
||||
/// See also <see cref="Timeout"/>
|
||||
/// </remarks>
|
||||
static public event EventHandler Iteration;
|
||||
public static event EventHandler Iteration;
|
||||
|
||||
/// <summary>
|
||||
/// 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 {
|
||||
/// <summary>
|
||||
/// Merely a debugging aid to see the raw mouse events
|
||||
/// </summary>
|
||||
static public Action<MouseEvent> RootMouseEvent;
|
||||
public static Action<MouseEvent> 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;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
static public Action OnLoad;
|
||||
public static event EventHandler<ResizedEventArgs> Loaded;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// undo these changes.
|
||||
/// </remarks>
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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)
|
||||
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 {
|
||||
/// </summary>
|
||||
public static void Run<T> () where T : Toplevel, new()
|
||||
{
|
||||
Init (() => new T());
|
||||
Init (() => new T ());
|
||||
Run (Top);
|
||||
}
|
||||
|
||||
@@ -2525,14 +2557,28 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the terminal was resized.
|
||||
/// Event arguments for the <see cref="T:Terminal.Gui.Application.Resized"/> event.
|
||||
/// </summary>
|
||||
static public Action OnResized;
|
||||
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>
|
||||
public static event EventHandler<ResizedEventArgs> 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 ();
|
||||
|
||||
@@ -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<MouseEvent> mouseHandler;
|
||||
MainLoop mainLoop;
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -63,6 +63,12 @@ namespace Terminal.Gui {
|
||||
/// <param name="item">Item index.</param>
|
||||
/// <param name="value">If set to <c>true</c> value.</param>
|
||||
void SetMark (int item, bool value);
|
||||
|
||||
/// <summary>
|
||||
/// Return the source as IList.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IList ToList ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -257,7 +263,7 @@ namespace Terminal.Gui {
|
||||
/// Redraws the ListView
|
||||
/// </summary>
|
||||
/// <param name="region">Region.</param>
|
||||
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 {
|
||||
/// <summary>
|
||||
/// This event is raised when the cursor selection has changed.
|
||||
/// </summary>
|
||||
public event Action SelectedChanged;
|
||||
public event EventHandler<ListViewItemEventArgs> SelectedChanged;
|
||||
|
||||
/// <summary>
|
||||
/// This event is raised on Enter key or Double Click to open the selected item.
|
||||
/// </summary>
|
||||
public event EventHandler OpenSelectedItem;
|
||||
public event EventHandler<ListViewItemEventArgs> OpenSelectedItem;
|
||||
|
||||
/// <summary>
|
||||
/// 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 {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Prevents marking if it's not allowed mark and if it's not allows multiple selection.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool AllowsAll ()
|
||||
@@ -359,13 +365,14 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Marks an unmarked row.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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 {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Moves to the next page.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Moves to the previous page.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Moves to the next row.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Moves to the previous row.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
|
||||
/// <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>
|
||||
/// Positions the cursor in this view
|
||||
/// </summary>
|
||||
public override void PositionCursor()
|
||||
public override void PositionCursor ()
|
||||
{
|
||||
if (allowsMarking)
|
||||
Move (1, selected - top);
|
||||
@@ -461,7 +498,8 @@ namespace Terminal.Gui {
|
||||
///<inheritdoc cref="MouseEvent(Gui.MouseEvent)"/>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// constructor
|
||||
/// Constructor based on a source.
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
public ListWrapper (IList source)
|
||||
@@ -508,7 +554,7 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count of items.
|
||||
/// Returns the amount of items in the source.
|
||||
/// </summary>
|
||||
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 {
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <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)
|
||||
{
|
||||
container.Move (col, line);
|
||||
@@ -553,10 +599,10 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true of the item is marked. false if not.
|
||||
/// Returns true if the item is marked, false otherwise.
|
||||
/// </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)
|
||||
{
|
||||
if (item >= 0 && item < count)
|
||||
@@ -565,14 +611,48 @@ namespace Terminal.Gui {
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <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)
|
||||
{
|
||||
if (item >= 0 && item < count)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<61>t detect an alone special key down was pressed.
|
||||
// it can<61>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;
|
||||
|
||||
///<inheritdoc cref="KeyDown"/>
|
||||
public override bool KeyDown (KeyEvent keyEvent)
|
||||
///<inheritdoc cref="OnKeyDown"/>
|
||||
public override bool OnKeyDown (KeyEvent keyEvent)
|
||||
{
|
||||
if (keyEvent.IsAlt) {
|
||||
openedByAltKey = true;
|
||||
@@ -574,13 +574,8 @@ namespace Terminal.Gui {
|
||||
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) {
|
||||
// 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<61>t detect an alone special key down was pressed.
|
||||
// it can<61>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;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// - Perhaps allow an option to not display the scrollbar arrow indicators?
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Terminal.Gui {
|
||||
/// <summary>
|
||||
/// 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="size">The size that this scrollbar represents.</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)
|
||||
{
|
||||
vertical = isVertical;
|
||||
@@ -314,9 +316,35 @@ namespace Terminal.Gui {
|
||||
/// <param name="view">The view to add to the scrollview.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visibility for the horizontal scroll indicator.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
///<inheritdoc cref="Redraw"/>
|
||||
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);
|
||||
|
||||
@@ -28,6 +28,11 @@ namespace Terminal.Gui {
|
||||
/// </summary>
|
||||
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>
|
||||
/// Changed event, raised when the text has clicked.
|
||||
/// </summary>
|
||||
@@ -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 {
|
||||
/// <summary>
|
||||
/// Copy the selected text to the clipboard.
|
||||
/// </summary>
|
||||
public void Copy ()
|
||||
public virtual void Copy ()
|
||||
{
|
||||
if (Secret)
|
||||
return;
|
||||
|
||||
if (SelectedLength != 0) {
|
||||
Clipboard.Contents = SelectedText;
|
||||
}
|
||||
@@ -692,7 +727,7 @@ namespace Terminal.Gui {
|
||||
/// <summary>
|
||||
/// Cut the selected text to the clipboard.
|
||||
/// </summary>
|
||||
public void Cut ()
|
||||
public virtual void Cut ()
|
||||
{
|
||||
if (SelectedLength != 0) {
|
||||
Clipboard.Contents = SelectedText;
|
||||
@@ -715,8 +750,11 @@ namespace Terminal.Gui {
|
||||
/// <summary>
|
||||
/// Paste the selected text from the clipboard.
|
||||
/// </summary>
|
||||
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 () ?? "";
|
||||
|
||||
@@ -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<List<Rune>> ();
|
||||
} 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<Rune> ToRunes (ustring str)
|
||||
@@ -120,6 +134,8 @@ namespace Terminal.Gui {
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of text lines in the model
|
||||
/// </summary>
|
||||
@@ -351,6 +367,18 @@ namespace Terminal.Gui {
|
||||
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>
|
||||
/// The current cursor row.
|
||||
/// </summary>
|
||||
|
||||
19
Terminal.sln
19
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -235,7 +244,7 @@ namespace UICatalog {
|
||||
/// to not be impacted. Same as for tabs.
|
||||
/// </summary>
|
||||
/// <param name="ke"></param>
|
||||
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<Type> newlist;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"profiles": {
|
||||
"UICatalog": {
|
||||
"commandName": "Project"
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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: ".
|
||||
- Tag bugs or suggestions for `UI Catalog` as [`Terminal.Gui` Github Issues](https://github.com/migueldeicaza/gui.cs/issues) with "UICatalog: ".
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
public class Scenario {
|
||||
public class Scenario : IDisposable {
|
||||
private bool _disposedValue;
|
||||
|
||||
/// <summary>
|
||||
/// The Top level for the Scenario. This should be set to `Application.Top` in most cases.
|
||||
/// </summary>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
155
UICatalog/Scenarios/ComputedLayout.cs
Normal file
155
UICatalog/Scenarios/ComputedLayout.cs
Normal file
@@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,8 @@ namespace UICatalog {
|
||||
public override bool ProcessColdKey (KeyEvent keyEvent)
|
||||
{
|
||||
_processColdKeyList.Add (keyEvent.ToString ());
|
||||
return base.ProcessHotKey (keyEvent);
|
||||
|
||||
return base.ProcessColdKey (keyEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace UICatalog {
|
||||
};
|
||||
Win.Add (labelKeypress);
|
||||
|
||||
Win.OnKeyPress += (KeyEvent keyEvent) => labelKeypress.Text = keyEvent.ToString ();
|
||||
Win.KeyPress += (sender, a) => labelKeypress.Text = a.KeyEvent.ToString ();
|
||||
|
||||
// Key stroke log:
|
||||
var keyLogLabel = new Label ("Key stroke log:") {
|
||||
@@ -119,9 +119,9 @@ namespace UICatalog {
|
||||
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:
|
||||
// BUGBUG: Label is not positioning right with Pos, so using TextField instead
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace UICatalog {
|
||||
@@ -9,39 +10,93 @@ namespace UICatalog {
|
||||
[ScenarioCategory ("Controls")]
|
||||
class Progress : Scenario {
|
||||
|
||||
private ProgressBar _progressBar;
|
||||
private ProgressBar _activityProgressBar;
|
||||
private ProgressBar _pulseProgressBar;
|
||||
private Timer _timer;
|
||||
private object _timeoutToken;
|
||||
|
||||
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,
|
||||
Clicked = () => Start ()
|
||||
}); ;
|
||||
Clicked = () => Pulse ()
|
||||
};
|
||||
|
||||
Win.Add (new Button ("Stop") {
|
||||
X = Pos.Center () + 10,
|
||||
Y = Pos.Center () - 5,
|
||||
Win.Add (new Button ("Start Timer") {
|
||||
X = Pos.Left(pulseButton) - 20,
|
||||
Y = Pos.Y(pulseButton),
|
||||
Clicked = () => Start ()
|
||||
});
|
||||
|
||||
Win.Add (new Button ("Stop Timer") {
|
||||
X = Pos.Right (pulseButton) + 20, // BUGBUG: Right is somehow adding additional width
|
||||
Y = Pos.Y (pulseButton),
|
||||
Clicked = () => Stop()
|
||||
});
|
||||
|
||||
_progressBar = new ProgressBar () {
|
||||
Win.Add (pulseButton);
|
||||
|
||||
_activityProgressBar = new ProgressBar () {
|
||||
X = Pos.Center (),
|
||||
// BUGBUG: If you remove the +1 below the control is drawn at top?!?!
|
||||
Y = Pos.Center ()+1,
|
||||
Width = 30,
|
||||
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 ()
|
||||
{
|
||||
_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 ()
|
||||
{
|
||||
_progressBar.Fraction = 1F;
|
||||
_timer?.Dispose ();
|
||||
_timer = null;
|
||||
Application.MainLoop.RemoveTimeout (_timeoutToken);
|
||||
|
||||
_activityProgressBar.Fraction = 1F;
|
||||
_pulseProgressBar.Fraction = 1F;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,22 +8,56 @@ namespace UICatalog {
|
||||
class TimeAndDate : Scenario {
|
||||
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
|
||||
//X = Pos.Center (),
|
||||
//Y = Pos.Center () - 1,
|
||||
X = 10,
|
||||
X = Pos.Center (),
|
||||
Y = 2,
|
||||
});
|
||||
ReadOnly = false,
|
||||
};
|
||||
Win.Add (longTime);
|
||||
|
||||
Win.Add (new TimeField (0, 2, DateTime.Now, isShort: true) {
|
||||
var shortTime = new TimeField (0, 2, DateTime.Now, isShort: true) {
|
||||
// BUGBUG: TimeField does not support Computed Layout
|
||||
//X = Pos.Center (),
|
||||
//Y = Pos.Center () + 1,
|
||||
X = 10,
|
||||
Y = 3,
|
||||
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);
|
||||
|
||||
var longDate = new TimeField (0, 2, DateTime.Now, isShort: true) {
|
||||
// BUGBUG: TimeField does not support Computed Layout
|
||||
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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 22 KiB |
@@ -1,5 +1,5 @@
|
||||
# Conceptual Documentation
|
||||
|
||||
* [Gui.cs Overview](overview.html)
|
||||
* [Terminal.Gui Overview](overview.html)
|
||||
* [Keyboard Event Processing](keyboard.html)
|
||||
* [Event Processing and the Application Main Loop](mainloop.md)
|
||||
@@ -12,7 +12,7 @@ class.
|
||||
|
||||
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
|
||||
toolkits before.
|
||||
toolkits before.
|
||||
|
||||
This class provides the following capabilities:
|
||||
|
||||
|
||||
BIN
docfx/sample.gif
Normal file
BIN
docfx/sample.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
docfx/sample.png
BIN
docfx/sample.png
Binary file not shown.
|
Before Width: | Height: | Size: 249 KiB After Width: | Height: | Size: 20 KiB |
Reference in New Issue
Block a user