diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index f854f34f1..5ca55ca34 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,25 +1,29 @@
{
"name": "Terminal.Gui Codespace",
- "image": "mcr.microsoft.com/vscode/devcontainers/dotnet:6.0",
- "settings": {
- "terminal.integrated.defaultProfile.linux": "pwsh"
- },
- "extensions": [
- "eamodio.gitlens",
- "ms-dotnettools.csharp",
- "VisualStudioExptTeam.vscodeintellicode",
- "ms-vscode.powershell",
- "cschleiden.vscode-github-actions",
- "redhat.vscode-yaml",
- "bierner.markdown-preview-github-styles",
- "ban.spellright",
- "jmrog.vscode-nuget-package-manager",
- "coenraads.bracket-pair-colorizer",
- "vscode-icons-team.vscode-icons",
- "editorconfig.editorconfig",
- "formulahendry.dotnet-test-explorer"
- ],
- "postCreateCommand": "dotnet restore && dotnet clean && dotnet build --configuration Release --no-restore && dotnet test --configuration Debug --no-restore --verbosity normal --collect:'XPlat Code Coverage' --settings UnitTests/coverlet.runsettings"
+ "image": "mcr.microsoft.com/vscode/devcontainers/dotnet:7.0",
+ "customizations": {
+ "vscode": {
+ "settings": {
+ "terminal.integrated.defaultProfile.linux": "pwsh"
+ },
+ "extensions": [
+ "eamodio.gitlens",
+ "ms-dotnettools.csharp",
+ "VisualStudioExptTeam.vscodeintellicode",
+ "ms-vscode.powershell",
+ "cschleiden.vscode-github-actions",
+ "redhat.vscode-yaml",
+ "bierner.markdown-preview-github-styles",
+ "ban.spellright",
+ "jmrog.vscode-nuget-package-manager",
+ "coenraads.bracket-pair-colorizer",
+ "vscode-icons-team.vscode-icons",
+ "editorconfig.editorconfig",
+ "formulahendry.dotnet-test-explorer"
+ ],
+ "postCreateCommand": "dotnet restore && dotnet clean && dotnet build --configuration Release --no-restore && dotnet test --configuration Debug --no-restore --verbosity normal --collect:'XPlat Code Coverage' --settings UnitTests/coverlet.runsettings"
+ }
+ }
}
// Built with ❤ by [Pipeline Foundation](https://pipeline.foundation)
diff --git a/ReactiveExample/ReactiveExample.csproj b/ReactiveExample/ReactiveExample.csproj
index 0c174f748..c2ce6640c 100644
--- a/ReactiveExample/ReactiveExample.csproj
+++ b/ReactiveExample/ReactiveExample.csproj
@@ -3,7 +3,7 @@
Exe
net6.0
-
+
1.0
1.0
diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
index 0a61f3bbb..c915db6e4 100644
--- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
@@ -74,14 +74,14 @@ namespace Terminal.Gui {
var c = sn [0];
Curses.mvaddch (crow, ccol - 1, (int)(uint)c);
contents [crow, ccol - 1, 0] = c;
- contents [crow, ccol - 1, 1] = currentAttribute;
+ contents [crow, ccol - 1, 1] = CurrentAttribute;
contents [crow, ccol - 1, 2] = 1;
} else {
if (runeWidth < 2 && ccol > 0
&& Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) {
- var curAtttib = currentAttribute;
+ var curAtttib = CurrentAttribute;
Curses.attrset (contents [crow, ccol - 1, 1]);
Curses.mvaddch (crow, ccol - 1, (int)(uint)' ');
contents [crow, ccol - 1, 0] = (int)(uint)' ';
@@ -91,7 +91,7 @@ namespace Terminal.Gui {
} else if (runeWidth < 2 && ccol <= Clip.Right - 1
&& Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) {
- var curAtttib = currentAttribute;
+ var curAtttib = CurrentAttribute;
Curses.attrset (contents [crow, ccol + 1, 1]);
Curses.mvaddch (crow, ccol + 1, (int)(uint)' ');
contents [crow, ccol + 1, 0] = (int)(uint)' ';
@@ -106,25 +106,28 @@ namespace Terminal.Gui {
Curses.addch ((int)(uint)rune);
contents [crow, ccol, 0] = (int)(uint)rune;
}
- contents [crow, ccol, 1] = currentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 1;
}
- } else
+ } else {
needMove = true;
+ }
if (runeWidth < 0 || runeWidth > 0) {
ccol++;
}
+
if (runeWidth > 1) {
if (validClip && ccol < Clip.Right) {
- contents [crow, ccol, 1] = currentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 0;
}
ccol++;
}
- if (sync)
+ if (sync) {
UpdateScreen ();
+ }
}
public override void AddStr (ustring str)
@@ -179,12 +182,10 @@ namespace Terminal.Gui {
public override void UpdateScreen () => window.redrawwin ();
- Attribute currentAttribute;
-
public override void SetAttribute (Attribute c)
{
- currentAttribute = c;
- Curses.attrset (currentAttribute);
+ base.SetAttribute (c);
+ Curses.attrset (CurrentAttribute);
}
public Curses.Window window;
@@ -220,6 +221,7 @@ namespace Terminal.Gui {
public override void SetColors (ConsoleColor foreground, ConsoleColor background)
{
+ // BUGBUG: This code is never called ?? See Issue #2300
int f = (short)foreground;
int b = (short)background;
var v = colorPairs [f, b];
@@ -237,6 +239,7 @@ namespace Terminal.Gui {
Dictionary rawPairs = new Dictionary ();
public override void SetColors (short foreColorId, short backgroundColorId)
{
+ // BUGBUG: This code is never called ?? See Issue #2300
int key = ((ushort)foreColorId << 16) | (ushort)backgroundColorId;
if (!rawPairs.TryGetValue (key, out var v)) {
v = MakeColor (foreColorId, backgroundColorId);
@@ -894,34 +897,18 @@ namespace Terminal.Gui {
if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition))
StartReportingMouseMoves ();
- ResizeScreen ();
- UpdateOffScreen ();
-
- //HLine = Curses.ACS_HLINE;
- //VLine = Curses.ACS_VLINE;
- //Stipple = Curses.ACS_CKBOARD;
- //Diamond = Curses.ACS_DIAMOND;
- //ULCorner = Curses.ACS_ULCORNER;
- //LLCorner = Curses.ACS_LLCORNER;
- //URCorner = Curses.ACS_URCORNER;
- //LRCorner = Curses.ACS_LRCORNER;
- //LeftTee = Curses.ACS_LTEE;
- //RightTee = Curses.ACS_RTEE;
- //TopTee = Curses.ACS_TTEE;
- //BottomTee = Curses.ACS_BTEE;
- //RightArrow = Curses.ACS_RARROW;
- //LeftArrow = Curses.ACS_LARROW;
- //UpArrow = Curses.ACS_UARROW;
- //DownArrow = Curses.ACS_DARROW;
+ CurrentAttribute = MakeColor (Color.White, Color.Black);
if (Curses.HasColors) {
Curses.StartColor ();
Curses.UseDefaultColors ();
- CreateColors ();
+ InitalizeColorSchemes ();
} else {
- CreateColors (false);
+ InitalizeColorSchemes (false);
+ // BUGBUG: This is a hack to make the colors work on the Mac?
+ // The new Theme support overwrites these colors, so this is not needed?
Colors.TopLevel.Normal = Curses.COLOR_GREEN;
Colors.TopLevel.Focus = Curses.COLOR_WHITE;
Colors.TopLevel.HotNormal = Curses.COLOR_YELLOW;
@@ -948,6 +935,10 @@ namespace Terminal.Gui {
Colors.Error.HotFocus = Curses.A_REVERSE;
Colors.Error.Disabled = Curses.A_BOLD | Curses.COLOR_GRAY;
}
+
+ ResizeScreen ();
+ UpdateOffScreen ();
+
}
public override void ResizeScreen ()
@@ -1022,6 +1013,8 @@ namespace Terminal.Gui {
return Curses.COLOR_YELLOW | Curses.A_BOLD | Curses.COLOR_GRAY;
case Color.White:
return Curses.COLOR_WHITE | Curses.A_BOLD | Curses.COLOR_GRAY;
+ case Color.Invalid:
+ return Curses.COLOR_BLACK;
}
throw new ArgumentException ("Invalid color code");
}
@@ -1112,11 +1105,6 @@ namespace Terminal.Gui {
//Curses.mouseinterval (lastMouseInterval);
}
- public override Attribute GetAttribute ()
- {
- return currentAttribute;
- }
-
///
public override bool GetCursorVisibility (out CursorVisibility visibility)
{
diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
index 84ced2be2..661daaca4 100644
--- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
@@ -142,7 +142,7 @@ namespace Terminal.Gui {
}
var c = sn [0];
contents [crow, ccol - 1, 0] = c;
- contents [crow, ccol - 1, 1] = currentAttribute;
+ contents [crow, ccol - 1, 1] = CurrentAttribute;
contents [crow, ccol - 1, 2] = 1;
} else {
@@ -163,20 +163,22 @@ namespace Terminal.Gui {
} else {
contents [crow, ccol, 0] = (int)(uint)rune;
}
- contents [crow, ccol, 1] = currentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 1;
dirtyLine [crow] = true;
}
- } else
+ } else {
needMove = true;
+ }
if (runeWidth < 0 || runeWidth > 0) {
ccol++;
}
+
if (runeWidth > 1) {
if (validClip && ccol < Clip.Right) {
- contents [crow, ccol, 1] = currentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 0;
}
ccol++;
@@ -187,8 +189,9 @@ namespace Terminal.Gui {
// if (crow + 1 < Rows)
// crow++;
//}
- if (sync)
+ if (sync) {
UpdateScreen ();
+ }
}
public override void AddStr (ustring str)
@@ -226,11 +229,10 @@ namespace Terminal.Gui {
rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
FakeConsole.Clear ();
ResizeScreen ();
+ // Call InitalizeColorSchemes before UpdateOffScreen as it references Colors
+ CurrentAttribute = MakeColor (Color.White, Color.Black);
+ InitalizeColorSchemes ();
UpdateOffScreen ();
-
- CreateColors ();
-
- //MockConsole.Clear ();
}
public override Attribute MakeAttribute (Color fore, Color back)
@@ -301,10 +303,9 @@ namespace Terminal.Gui {
UpdateCursor ();
}
- Attribute currentAttribute;
public override void SetAttribute (Attribute c)
{
- currentAttribute = c;
+ base.SetAttribute (c);
}
public ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
@@ -493,11 +494,6 @@ namespace Terminal.Gui {
keyUpHandler (new KeyEvent (map, keyModifiers));
}
- public override Attribute GetAttribute ()
- {
- return currentAttribute;
- }
-
///
public override bool GetCursorVisibility (out CursorVisibility visibility)
{
diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
index 0b1da2d2a..9ae4eb20e 100644
--- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
@@ -1252,7 +1252,7 @@ namespace Terminal.Gui {
}
var c = sn [0];
contents [crow, ccol - 1, 0] = c;
- contents [crow, ccol - 1, 1] = currentAttribute;
+ contents [crow, ccol - 1, 1] = CurrentAttribute;
contents [crow, ccol - 1, 2] = 1;
} else {
@@ -1273,7 +1273,7 @@ namespace Terminal.Gui {
} else {
contents [crow, ccol, 0] = (int)(uint)rune;
}
- contents [crow, ccol, 1] = currentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 1;
}
@@ -1283,9 +1283,10 @@ namespace Terminal.Gui {
if (runeWidth < 0 || runeWidth > 0) {
ccol++;
}
+
if (runeWidth > 1) {
if (validClip && ccol < Clip.Right) {
- contents [crow, ccol, 1] = currentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 0;
}
ccol++;
@@ -1358,12 +1359,14 @@ namespace Terminal.Gui {
cols = Console.WindowWidth;
rows = Console.WindowHeight;
+ CurrentAttribute = MakeColor (Color.White, Color.Black);
+ InitalizeColorSchemes ();
+
ResizeScreen ();
UpdateOffScreen ();
StartReportingMouseMoves ();
- CreateColors ();
Clear ();
}
@@ -1631,10 +1634,10 @@ namespace Terminal.Gui {
{
}
- Attribute currentAttribute;
+
public override void SetAttribute (Attribute c)
{
- currentAttribute = c;
+ base.SetAttribute (c);
}
public ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
@@ -1952,11 +1955,6 @@ namespace Terminal.Gui {
};
}
- public override Attribute GetAttribute ()
- {
- return currentAttribute;
- }
-
///
public override bool GetCursorVisibility (out CursorVisibility visibility)
{
diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
index 8d1b71646..21ea48300 100644
--- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
@@ -116,6 +116,10 @@ namespace Terminal.Gui {
public bool GetCursorVisibility (out CursorVisibility visibility)
{
+ if (ScreenBuffer == IntPtr.Zero) {
+ visibility = CursorVisibility.Invisible;
+ return false;
+ }
if (!GetConsoleCursorInfo (ScreenBuffer, out ConsoleCursorInfo info)) {
var err = Marshal.GetLastWin32Error ();
if (err != 0) {
@@ -1455,13 +1459,13 @@ namespace Terminal.Gui {
var winSize = WinConsole.GetConsoleOutputWindow (out Point pos);
cols = winSize.Width;
rows = winSize.Height;
-
WindowsConsole.SmallRect.MakeEmpty (ref damageRegion);
+ CurrentAttribute = MakeColor (Color.White, Color.Black);
+ InitalizeColorSchemes ();
+
ResizeScreen ();
UpdateOffScreen ();
-
- CreateColors ();
} catch (Win32Exception e) {
throw new InvalidOperationException ("The Windows Console output window is not available.", e);
}
@@ -1530,8 +1534,8 @@ namespace Terminal.Gui {
var prevPosition = crow * Cols + (ccol - 1);
OutputBuffer [prevPosition].Char.UnicodeChar = c;
contents [crow, ccol - 1, 0] = c;
- OutputBuffer [prevPosition].Attributes = (ushort)currentAttribute;
- contents [crow, ccol - 1, 1] = currentAttribute;
+ OutputBuffer [prevPosition].Attributes = (ushort)CurrentAttribute;
+ contents [crow, ccol - 1, 1] = CurrentAttribute;
contents [crow, ccol - 1, 2] = 1;
WindowsConsole.SmallRect.Update (ref damageRegion, (short)(ccol - 1), (short)crow);
} else {
@@ -1557,8 +1561,8 @@ namespace Terminal.Gui {
OutputBuffer [position].Char.UnicodeChar = (char)rune;
contents [crow, ccol, 0] = (int)(uint)rune;
}
- OutputBuffer [position].Attributes = (ushort)currentAttribute;
- contents [crow, ccol, 1] = currentAttribute;
+ OutputBuffer [position].Attributes = (ushort)CurrentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 1;
WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow);
}
@@ -1567,20 +1571,22 @@ namespace Terminal.Gui {
if (runeWidth < 0 || runeWidth > 0) {
ccol++;
}
+
if (runeWidth > 1) {
if (validClip && ccol < Clip.Right) {
position = GetOutputBufferPosition ();
- OutputBuffer [position].Attributes = (ushort)currentAttribute;
+ OutputBuffer [position].Attributes = (ushort)CurrentAttribute;
OutputBuffer [position].Char.UnicodeChar = (char)0x00;
contents [crow, ccol, 0] = (int)(uint)0x00;
- contents [crow, ccol, 1] = currentAttribute;
+ contents [crow, ccol, 1] = CurrentAttribute;
contents [crow, ccol, 2] = 0;
}
ccol++;
}
- if (sync)
+ if (sync) {
UpdateScreen ();
+ }
}
public override void AddStr (ustring str)
@@ -1589,11 +1595,9 @@ namespace Terminal.Gui {
AddRune (rune);
}
- Attribute currentAttribute;
-
public override void SetAttribute (Attribute c)
{
- currentAttribute = c;
+ base.SetAttribute (c);
}
public override Attribute MakeColor (Color foreground, Color background)
@@ -1695,11 +1699,6 @@ namespace Terminal.Gui {
WinConsole = null;
}
- public override Attribute GetAttribute ()
- {
- return currentAttribute;
- }
-
///
public override bool GetCursorVisibility (out CursorVisibility visibility)
{
diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs
index b5f6e5984..eb609e609 100644
--- a/Terminal.Gui/Core/Application.cs
+++ b/Terminal.Gui/Core/Application.cs
@@ -57,7 +57,7 @@ namespace Terminal.Gui {
///
///
public static class Application {
- static Stack toplevels = new Stack ();
+ static readonly Stack toplevels = new Stack ();
///
/// The current in use.
@@ -111,28 +111,33 @@ namespace Terminal.Gui {
///
public static View WantContinuousButtonPressedView { get; private set; }
+ private static bool? _heightAsBuffer;
+
///
/// The current used in the terminal.
///
+ ///
public static bool HeightAsBuffer {
get {
if (Driver == null) {
- throw new ArgumentNullException ("The driver must be initialized first.");
+ return _heightAsBuffer.HasValue && _heightAsBuffer.Value;
}
return Driver.HeightAsBuffer;
}
set {
+ _heightAsBuffer = value;
if (Driver == null) {
- throw new ArgumentNullException ("The driver must be initialized first.");
+ return;
}
- Driver.HeightAsBuffer = value;
+
+ Driver.HeightAsBuffer = _heightAsBuffer.Value;
}
}
static Key alternateForwardKey = Key.PageDown | Key.CtrlMask;
///
- /// Alternative key to navigate forwards through all views. Ctrl+Tab is always used.
+ /// Alternative key to navigate forwards through views. Ctrl+Tab is the primary key.
///
public static Key AlternateForwardKey {
get => alternateForwardKey;
@@ -147,7 +152,7 @@ namespace Terminal.Gui {
static void OnAlternateForwardKeyChanged (Key oldKey)
{
- foreach (var top in toplevels) {
+ foreach (var top in toplevels.ToArray()) {
top.OnAlternateForwardKeyChanged (oldKey);
}
}
@@ -155,7 +160,7 @@ namespace Terminal.Gui {
static Key alternateBackwardKey = Key.PageUp | Key.CtrlMask;
///
- /// Alternative key to navigate backwards through all views. Shift+Ctrl+Tab is always used.
+ /// Alternative key to navigate backwards through views. Shift+Ctrl+Tab is the primary key.
///
public static Key AlternateBackwardKey {
get => alternateBackwardKey;
@@ -170,7 +175,7 @@ namespace Terminal.Gui {
static void OnAlternateBackwardKeyChanged (Key oldKey)
{
- foreach (var top in toplevels) {
+ foreach (var top in toplevels.ToArray()) {
top.OnAlternateBackwardKeyChanged (oldKey);
}
}
@@ -200,7 +205,8 @@ namespace Terminal.Gui {
static void OnQuitKeyChanged (Key oldKey)
{
- foreach (var top in toplevels) {
+ // Duplicate the list so if it changes during enumeration we're safe
+ foreach (var top in toplevels.ToArray()) {
top.OnQuitKeyChanged (oldKey);
}
}
@@ -212,7 +218,7 @@ namespace Terminal.Gui {
public static MainLoop MainLoop { get; private set; }
///
- /// Disable or enable the mouse in this
+ /// Disable or enable the mouse. The mouse is enabled by default.
///
public static bool IsMouseDisabled { get; set; }
@@ -266,7 +272,7 @@ namespace Terminal.Gui {
// users use async/await on their code
//
class MainLoopSyncContext : SynchronizationContext {
- MainLoop mainLoop;
+ readonly MainLoop mainLoop;
public MainLoopSyncContext (MainLoop mainLoop)
{
@@ -305,9 +311,9 @@ namespace Terminal.Gui {
}
///
- /// If set, it forces the use of the System.Console-based driver.
+ /// If , forces the use of the System.Console-based (see ) driver. The default is .
///
- public static bool UseSystemConsole;
+ public static bool UseSystemConsole { get; set; } = false;
// For Unit testing - ignores UseSystemConsole
internal static bool ForceFakeConsole;
@@ -422,6 +428,7 @@ namespace Terminal.Gui {
MainLoop = new MainLoop (mainLoopDriver);
try {
+ Driver.HeightAsBuffer = HeightAsBuffer;
Driver.Init (TerminalResized);
} catch (InvalidOperationException ex) {
// This is a case where the driver is unable to initialize the console.
@@ -933,6 +940,8 @@ namespace Terminal.Gui {
if (Top != null && toplevel != Top && !toplevels.Contains (Top)) {
Top.Dispose ();
Top = null;
+ } else if (Top != null && toplevel != Top && toplevels.Contains (Top)) {
+ Top.OnLeave (toplevel);
}
if (string.IsNullOrEmpty (toplevel.Id.ToString ())) {
var count = 1;
@@ -986,9 +995,7 @@ namespace Terminal.Gui {
toplevel.PositionToplevels ();
toplevel.WillPresent ();
if (refreshDriver) {
- if (MdiTop != null) {
- MdiTop.OnChildLoaded (toplevel);
- }
+ MdiTop?.OnChildLoaded (toplevel);
toplevel.OnLoaded ();
Redraw (toplevel);
toplevel.PositionCursor ();
@@ -1043,6 +1050,7 @@ namespace Terminal.Gui {
MdiTop.OnAllChildClosed ();
} else {
SetCurrentAsTop ();
+ Current.OnEnter (Current);
}
Refresh ();
}
@@ -1111,12 +1119,6 @@ namespace Terminal.Gui {
Driver.Refresh ();
}
- static void Refresh (View view)
- {
- view.Redraw (view.Bounds);
- Driver.Refresh ();
- }
-
///
/// Triggers a refresh of the entire display.
///
diff --git a/Terminal.Gui/Core/Autocomplete/Autocomplete.cs b/Terminal.Gui/Core/Autocomplete/Autocomplete.cs
index f351b8424..61ccc01ea 100644
--- a/Terminal.Gui/Core/Autocomplete/Autocomplete.cs
+++ b/Terminal.Gui/Core/Autocomplete/Autocomplete.cs
@@ -324,6 +324,7 @@ namespace Terminal.Gui {
if (IsWordChar ((char)kb.Key)) {
Visible = true;
closed = false;
+ return false;
}
if (kb.Key == Reopen) {
@@ -332,6 +333,9 @@ namespace Terminal.Gui {
if (closed || Suggestions.Count == 0) {
Visible = false;
+ if (!closed) {
+ Close ();
+ }
return false;
}
@@ -345,6 +349,17 @@ namespace Terminal.Gui {
return true;
}
+ if (kb.Key == Key.CursorLeft || kb.Key == Key.CursorRight) {
+ GenerateSuggestions (kb.Key == Key.CursorLeft ? -1 : 1);
+ if (Suggestions.Count == 0) {
+ Visible = false;
+ if (!closed) {
+ Close ();
+ }
+ }
+ return false;
+ }
+
if (kb.Key == SelectionKey) {
return Select ();
}
@@ -368,6 +383,9 @@ namespace Terminal.Gui {
public virtual bool MouseEvent (MouseEvent me, bool fromHost = false)
{
if (fromHost) {
+ if (!Visible) {
+ return false;
+ }
GenerateSuggestions ();
if (Visible && Suggestions.Count == 0) {
Visible = false;
@@ -444,7 +462,8 @@ namespace Terminal.Gui {
/// Populates with all strings in that
/// match with the current cursor position/text in the
///
- public virtual void GenerateSuggestions ()
+ /// The column offset.
+ public virtual void GenerateSuggestions (int columnOffset = 0)
{
// if there is nothing to pick from
if (AllSuggestions.Count == 0) {
@@ -452,7 +471,7 @@ namespace Terminal.Gui {
return;
}
- var currentWord = GetCurrentWord ();
+ var currentWord = GetCurrentWord (columnOffset);
if (string.IsNullOrWhiteSpace (currentWord)) {
ClearSuggestions ();
@@ -524,11 +543,12 @@ namespace Terminal.Gui {
///
/// Returns the currently selected word from the .
///
- /// When overriding this method views can make use of
+ /// When overriding this method views can make use of
///
///
+ /// The column offset.
///
- protected abstract string GetCurrentWord ();
+ protected abstract string GetCurrentWord (int columnOffset = 0);
///
///
@@ -536,37 +556,40 @@ namespace Terminal.Gui {
/// or null. Also returns null if the is positioned in the middle of a word.
///
///
- /// Use this method to determine whether autocomplete should be shown when the cursor is at
- /// a given point in a line and to get the word from which suggestions should be generated.
+ ///
+ /// Use this method to determine whether autocomplete should be shown when the cursor is at
+ /// a given point in a line and to get the word from which suggestions should be generated.
+ /// Use the to indicate if search the word at left (negative),
+ /// at right (positive) or at the current column (zero) which is the default.
+ ///
///
///
///
+ ///
///
- protected virtual string IdxToWord (List line, int idx)
+ protected virtual string IdxToWord (List line, int idx, int columnOffset = 0)
{
StringBuilder sb = new StringBuilder ();
+ var endIdx = idx;
- // do not generate suggestions if the cursor is positioned in the middle of a word
- bool areMidWord;
-
- if (idx == line.Count) {
- // the cursor positioned at the very end of the line
- areMidWord = false;
- } else {
- // we are in the middle of a word if the cursor is over a letter/number
- areMidWord = IsWordChar (line [idx]);
+ // get the ending word index
+ while (endIdx < line.Count) {
+ if (IsWordChar (line [endIdx])) {
+ endIdx++;
+ } else {
+ break;
+ }
}
- // if we are in the middle of a word then there is no way to autocomplete that word
- if (areMidWord) {
+ // It isn't a word char then there is no way to autocomplete that word
+ if (endIdx == idx && columnOffset != 0) {
return null;
}
// we are at the end of a word. Work out what has been typed so far
- while (idx-- > 0) {
-
- if (IsWordChar (line [idx])) {
- sb.Insert (0, (char)line [idx]);
+ while (endIdx-- > 0) {
+ if (IsWordChar (line [endIdx])) {
+ sb.Insert (0, (char)line [endIdx]);
} else {
break;
}
diff --git a/Terminal.Gui/Core/Autocomplete/IAutocomplete.cs b/Terminal.Gui/Core/Autocomplete/IAutocomplete.cs
index 32e7046e7..2e3194eb3 100644
--- a/Terminal.Gui/Core/Autocomplete/IAutocomplete.cs
+++ b/Terminal.Gui/Core/Autocomplete/IAutocomplete.cs
@@ -109,6 +109,7 @@ namespace Terminal.Gui {
/// Populates with all strings in that
/// match with the current cursor position/text in the .
///
- void GenerateSuggestions ();
+ /// The column offset. Current (zero - default), left (negative), right (positive).
+ void GenerateSuggestions (int columnOffset = 0);
}
}
diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs
index 42d32ebfa..bc3856289 100644
--- a/Terminal.Gui/Core/ConsoleDriver.cs
+++ b/Terminal.Gui/Core/ConsoleDriver.cs
@@ -1,23 +1,22 @@
//
-// ConsoleDriver.cs: Definition for the Console Driver API
+// ConsoleDriver.cs: Base class for Terminal.Gui ConsoleDriver implementations.
//
-// Authors:
-// Miguel de Icaza (miguel@gnome.org)
-//
-// Define this to enable diagnostics drawing for Window Frames
using NStack;
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
-using Unix.Terminal;
namespace Terminal.Gui {
///
- /// Basic colors that can be used to set the foreground and background colors in console applications.
+ /// Colors that can be used to set the foreground and background colors in console applications.
///
+ ///
+ /// The value indicates either no-color has been set or the color is invalid.
+ ///
public enum Color {
///
/// The black color.
@@ -82,26 +81,112 @@ namespace Terminal.Gui {
///
/// The White color.
///
- White
+ White,
+ ///
+ /// Indicates an invalid or un-set color value.
+ ///
+ Invalid = -1
}
///
- /// Attributes are used as elements that contain both a foreground and a background or platform specific features
+ ///
+ ///
+ public class TrueColor {
+ ///
+ /// Red color component.
+ ///
+ public int Red { get; }
+ ///
+ /// Green color component.
+ ///
+ public int Green { get; }
+ ///
+ /// Blue color component.
+ ///
+ public int Blue { get; }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ ///
+ ///
+ ///
+ public TrueColor (int red, int green, int blue)
+ {
+ Red = red;
+ Green = green;
+ Blue = blue;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public Color ToConsoleColor ()
+ {
+ var trueColorMap = new Dictionary () {
+ { new TrueColor (0,0,0),Color.Black},
+ { new TrueColor (0, 0, 0x80),Color.Blue},
+ { new TrueColor (0, 0x80, 0),Color.Green},
+ { new TrueColor (0, 0x80, 0x80),Color.Cyan},
+ { new TrueColor (0x80, 0, 0),Color.Red},
+ { new TrueColor (0x80, 0, 0x80),Color.Magenta},
+ { new TrueColor (0xC1, 0x9C, 0x00),Color.Brown}, // TODO confirm this
+ { new TrueColor (0xC0, 0xC0, 0xC0),Color.Gray},
+ { new TrueColor (0x80, 0x80, 0x80),Color.DarkGray},
+ { new TrueColor (0, 0, 0xFF),Color.BrightBlue},
+ { new TrueColor (0, 0xFF, 0),Color.BrightGreen},
+ { new TrueColor (0, 0xFF, 0xFF),Color.BrightCyan},
+ { new TrueColor (0xFF, 0, 0),Color.BrightRed},
+ { new TrueColor (0xFF, 0, 0xFF),Color.BrightMagenta },
+ { new TrueColor (0xFF, 0xFF, 0),Color.BrightYellow},
+ { new TrueColor (0xFF, 0xFF, 0xFF),Color.White},
+ };
+ // Iterate over all colors in the map
+ var distances = trueColorMap.Select (
+ k => Tuple.Create (
+ // the candidate we are considering matching against (RGB)
+ k.Key,
+
+ CalculateDistance (k.Key, this)
+ ));
+
+ // get the closest
+ var match = distances.OrderBy (t => t.Item2).First ();
+ return trueColorMap [match.Item1];
+ }
+
+ private float CalculateDistance (TrueColor color1, TrueColor color2)
+ {
+ // use RGB distance
+ return
+ Math.Abs (color1.Red - color2.Red) +
+ Math.Abs (color1.Green - color2.Green) +
+ Math.Abs (color1.Blue - color2.Blue);
+ }
+ }
+
+ ///
+ /// Attributes are used as elements that contain both a foreground and a background or platform specific features.
///
///
- /// s are needed to map colors to terminal capabilities that might lack colors, on color
- /// scenarios, they encode both the foreground and the background color and are used in the
- /// class to define color schemes that can be used in your application.
+ /// s are needed to map colors to terminal capabilities that might lack colors.
+ /// They encode both the foreground and the background color and are used in the
+ /// class to define color schemes that can be used in an application.
///
public struct Attribute {
///
- /// The color attribute value.
+ /// The -specific color attribute value. If is
+ /// the value of this property is invalid (typcially because the Attribute was created before a driver was loaded)
+ /// and the attribute should be re-made (see ) before it is used.
///
public int Value { get; }
+
///
/// The foreground color.
///
public Color Foreground { get; }
+
///
/// The background color.
///
@@ -114,11 +199,13 @@ namespace Terminal.Gui {
/// Value.
public Attribute (int value)
{
- Color foreground = default;
- Color background = default;
+ Color foreground = Color.Invalid;
+ Color background = Color.Invalid;
+ Initialized = false;
if (Application.Driver != null) {
Application.Driver.GetColors (value, out foreground, out background);
+ Initialized = true;
}
Value = value;
Foreground = foreground;
@@ -136,6 +223,7 @@ namespace Terminal.Gui {
Value = value;
Foreground = foreground;
Background = background;
+ Initialized = true;
}
///
@@ -145,7 +233,9 @@ namespace Terminal.Gui {
/// Background
public Attribute (Color foreground = new Color (), Color background = new Color ())
{
- Value = Make (foreground, background).Value;
+ var make = Make (foreground, background);
+ Initialized = make.Initialized;
+ Value = make.Value;
Foreground = foreground;
Background = background;
}
@@ -158,29 +248,42 @@ namespace Terminal.Gui {
public Attribute (Color color) : this (color, color) { }
///
- /// Implicit conversion from an to the underlying Int32 representation
+ /// Implicit conversion from an to the underlying, driver-specific, Int32 representation
+ /// of the color.
///
- /// The integer value stored in the attribute.
+ /// The driver-specific color value stored in the attribute.
/// The attribute to convert
- public static implicit operator int (Attribute c) => c.Value;
+ public static implicit operator int (Attribute c)
+ {
+ if (!c.Initialized) throw new InvalidOperationException ("Attribute: Attributes must be initialized by a driver before use.");
+ return c.Value;
+ }
///
- /// Implicitly convert an integer value into an
+ /// Implicitly convert an driver-specific color value into an
///
- /// An attribute with the specified integer value.
+ /// An attribute with the specified driver-specific color value.
/// value
public static implicit operator Attribute (int v) => new Attribute (v);
///
- /// Creates an from the specified foreground and background.
+ /// Creates an from the specified foreground and background colors.
///
- /// The make.
+ ///
+ /// If a has not been loaded (Application.Driver == null) this
+ /// method will return an attribute with set to .
+ ///
+ /// The new attribute.
/// Foreground color to use.
/// Background color to use.
public static Attribute Make (Color foreground, Color background)
{
- if (Application.Driver == null)
- throw new InvalidOperationException ("The Application has not been initialized");
+ if (Application.Driver == null) {
+ // Create the attribute, but show it's not been initialized
+ var a = new Attribute (-1, foreground, background);
+ a.Initialized = false;
+ return a;
+ }
return Application.Driver.MakeAttribute (foreground, background);
}
@@ -194,45 +297,114 @@ namespace Terminal.Gui {
throw new InvalidOperationException ("The Application has not been initialized");
return Application.Driver.GetAttribute ();
}
+
+ ///
+ /// If the attribute has been initialzed by a and
+ /// thus has that is valid for that driver. If the
+ /// and colors may have been set (see ) but
+ /// the attribute has not been mapped to a specific color value.
+ ///
+ ///
+ /// Attributes that have not been initialized must eventually be initialized before being passed to a driver.
+ ///
+ public bool Initialized { get; internal set; }
+
+ ///
+ /// Returns if the Atrribute is valid (both foreground and background have valid color values).
+ ///
+ ///
+ public bool HasValidColors {
+ get {
+ return Foreground != Color.Invalid && Background != Color.Invalid;
+ }
+ }
}
///
- /// Color scheme definitions, they cover some common scenarios and are used
- /// typically in containers such as and to set the scheme that is used by all the
- /// views contained inside.
+ /// Defines the color s for common visible elements in a .
+ /// Containers such as and use to determine
+ /// the colors used by sub-views.
///
+ ///
+ /// See also: .
+ ///
public class ColorScheme : IEquatable {
- Attribute _normal;
- Attribute _focus;
- Attribute _hotNormal;
- Attribute _hotFocus;
- Attribute _disabled;
- internal string caller = "";
+ Attribute _normal = new Attribute(Color.White, Color.Black);
+ Attribute _focus = new Attribute (Color.White, Color.Black);
+ Attribute _hotNormal = new Attribute (Color.White, Color.Black);
+ Attribute _hotFocus = new Attribute (Color.White, Color.Black);
+ Attribute _disabled = new Attribute (Color.White, Color.Black);
///
- /// The default color for text, when the view is not focused.
+ /// Used by and to track which ColorScheme
+ /// is being accessed.
///
- public Attribute Normal { get { return _normal; } set { _normal = value; } }
+ internal string schemeBeingSet = "";
///
- /// The color for text when the view has the focus.
+ /// The foreground and background color for text when the view is not focused, hot, or disabled.
///
- public Attribute Focus { get { return _focus; } set { _focus = value; } }
+ public Attribute Normal {
+ get { return _normal; }
+ set {
+ if (!value.HasValidColors) {
+ return;
+ }
+ _normal = value;
+ }
+ }
///
- /// The color for the hotkey when a view is not focused
+ /// The foreground and background color for text when the view has the focus.
///
- public Attribute HotNormal { get { return _hotNormal; } set { _hotNormal = value; } }
+ public Attribute Focus {
+ get { return _focus; }
+ set {
+ if (!value.HasValidColors) {
+ return;
+ }
+ _focus = value;
+ }
+ }
///
- /// The color for the hotkey when the view is focused.
+ /// The foreground and background color for text when the view is highlighted (hot).
///
- public Attribute HotFocus { get { return _hotFocus; } set { _hotFocus = value; } }
+ public Attribute HotNormal {
+ get { return _hotNormal; }
+ set {
+ if (!value.HasValidColors) {
+ return;
+ }
+ _hotNormal = value;
+ }
+ }
///
- /// The default color for text, when the view is disabled.
+ /// The foreground and background color for text when the view is highlighted (hot) and has focus.
///
- public Attribute Disabled { get { return _disabled; } set { _disabled = value; } }
+ public Attribute HotFocus {
+ get { return _hotFocus; }
+ set {
+ if (!value.HasValidColors) {
+ return;
+ }
+ _hotFocus = value;
+ }
+ }
+
+ ///
+ /// The default foreground and background color for text, when the view is disabled.
+ ///
+ public Attribute Disabled {
+ get { return _disabled; }
+ set {
+ if (!value.HasValidColors) {
+ return;
+ }
+ _disabled = value;
+ }
+ }
///
/// Compares two objects for equality.
@@ -295,20 +467,67 @@ namespace Terminal.Gui {
{
return !(left == right);
}
+
+ internal void Initialize ()
+ {
+ // If the new scheme was created before a driver was loaded, we need to re-make
+ // the attributes
+ if (!_normal.Initialized) {
+ _normal = new Attribute (_normal.Foreground, _normal.Background);
+ }
+ if (!_focus.Initialized) {
+ _focus = new Attribute (_focus.Foreground, _focus.Background);
+ }
+ if (!_hotNormal.Initialized) {
+ _hotNormal = new Attribute (_hotNormal.Foreground, _hotNormal.Background);
+ }
+ if (!_hotFocus.Initialized) {
+ _hotFocus = new Attribute (_hotFocus.Foreground, _hotFocus.Background);
+ }
+ if (!_disabled.Initialized) {
+ _disabled = new Attribute (_disabled.Foreground, _disabled.Background);
+ }
+ }
}
///
/// The default s for the application.
///
+ ///
+ /// This property can be set in a Theme to change the default for the application.
+ ///
public static class Colors {
+ private class SchemeNameComparerIgnoreCase : IEqualityComparer {
+ public bool Equals (string x, string y)
+ {
+ if (x != null && y != null) {
+ return x.ToLowerInvariant () == y.ToLowerInvariant ();
+ }
+ return false;
+ }
+
+ public int GetHashCode (string obj)
+ {
+ return obj.ToLowerInvariant ().GetHashCode ();
+ }
+ }
+
static Colors ()
+ {
+ ColorSchemes = Create ();
+ }
+
+ ///
+ /// Creates a new dictionary of new objects.
+ ///
+ public static Dictionary Create ()
{
// Use reflection to dynamically create the default set of ColorSchemes from the list defined
// by the class.
- ColorSchemes = typeof (Colors).GetProperties ()
+ return typeof (Colors).GetProperties ()
.Where (p => p.PropertyType == typeof (ColorScheme))
- .Select (p => new KeyValuePair (p.Name, new ColorScheme ())) // (ColorScheme)p.GetValue (p)))
- .ToDictionary (t => t.Key, t => t.Value);
+ .Select (p => new KeyValuePair (p.Name, new ColorScheme()))
+ .ToDictionary (t => t.Key, t => t.Value, comparer: new SchemeNameComparerIgnoreCase ());
}
///
@@ -361,21 +580,21 @@ namespace Terminal.Gui {
///
public static ColorScheme Error { get => GetColorScheme (); set => SetColorScheme (value); }
- static ColorScheme GetColorScheme ([CallerMemberName] string callerMemberName = null)
+ static ColorScheme GetColorScheme ([CallerMemberName] string schemeBeingSet = null)
{
- return ColorSchemes [callerMemberName];
+ return ColorSchemes [schemeBeingSet];
}
- static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string callerMemberName = null)
+ static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string schemeBeingSet = null)
{
- ColorSchemes [callerMemberName] = colorScheme;
- colorScheme.caller = callerMemberName;
+ ColorSchemes [schemeBeingSet] = colorScheme;
+ colorScheme.schemeBeingSet = schemeBeingSet;
}
///
/// Provides the defined s.
///
- public static Dictionary ColorSchemes { get; }
+ public static Dictionary ColorSchemes { get; private set; }
}
///
@@ -659,13 +878,35 @@ namespace Terminal.Gui {
public abstract void UpdateScreen ();
///
- /// Selects the specified attribute as the attribute to use for future calls to AddRune, AddString.
+ /// The current attribute the driver is using.
///
- /// C.
- public abstract void SetAttribute (Attribute c);
+ public virtual Attribute CurrentAttribute {
+ get => currentAttribute;
+ set {
+ if (!value.Initialized && value.HasValidColors && Application.Driver != null) {
+ CurrentAttribute = Application.Driver.MakeAttribute (value.Foreground, value.Background);
+ return;
+ }
+ if (!value.Initialized) Debug.WriteLine ("ConsoleDriver.CurrentAttribute: Attributes must be initialized before use.");
+
+ currentAttribute = value;
+ }
+ }
///
- /// Set Colors from limit sets of colors.
+ /// Selects the specified attribute as the attribute to use for future calls to AddRune and AddString.
+ ///
+ ///
+ /// Implementations should call base.SetAttribute(c).
+ ///
+ /// C.
+ public virtual void SetAttribute (Attribute c)
+ {
+ CurrentAttribute = c;
+ }
+
+ ///
+ /// Set Colors from limit sets of colors. Not implemented by any driver: See Issue #2300.
///
/// Foreground.
/// Background.
@@ -675,7 +916,7 @@ namespace Terminal.Gui {
// that independently with the R, G, B values.
///
/// Advanced uses - set colors to any pre-set pairs, you would need to init_color
- /// that independently with the R, G, B values.
+ /// that independently with the R, G, B values. Not implemented by any driver: See Issue #2300.
///
/// Foreground color identifier.
/// Background color identifier.
@@ -998,12 +1239,13 @@ namespace Terminal.Gui {
public abstract void StopReportingMouseMoves ();
///
- /// Disables the cooked event processing from the mouse driver. At startup, it is assumed mouse events are cooked.
+ /// Disables the cooked event processing from the mouse driver.
+ /// At startup, it is assumed mouse events are cooked. Not implemented by any driver: See Issue #2300.
///
public abstract void UncookMouse ();
///
- /// Enables the cooked event processing from the mouse driver
+ /// Enables the cooked event processing from the mouse driver. Not implemented by any driver: See Issue #2300.
///
public abstract void CookMouse ();
@@ -1196,6 +1438,7 @@ namespace Terminal.Gui {
/// Lower right rounded corner
///
public Rune LRRCorner = '\u256f';
+ private Attribute currentAttribute;
///
/// Make the attribute for the foreground and background colors.
@@ -1209,7 +1452,7 @@ namespace Terminal.Gui {
/// Gets the current .
///
/// The current attribute.
- public abstract Attribute GetAttribute ();
+ public Attribute GetAttribute () => CurrentAttribute;
///
/// Make the for the .
@@ -1220,21 +1463,24 @@ namespace Terminal.Gui {
public abstract Attribute MakeColor (Color foreground, Color background);
///
- /// Create all with the for the console driver.
+ /// Ensures all s in are correclty
+ /// initalized by the driver.
///
- /// Flag indicating if colors are supported.
- public void CreateColors (bool hasColors = true)
+ /// Flag indicating if colors are supported (not used).
+ public void InitalizeColorSchemes (bool supportsColors = true)
{
- Colors.TopLevel = new ColorScheme ();
- Colors.Base = new ColorScheme ();
- Colors.Dialog = new ColorScheme ();
- Colors.Menu = new ColorScheme ();
- Colors.Error = new ColorScheme ();
+ // Ensure all Attributes are initlaized by the driver
+ foreach (var s in Colors.ColorSchemes) {
+ s.Value.Initialize ();
+ }
- if (!hasColors) {
+ if (!supportsColors) {
return;
}
+
+ // Define the default color theme only if the user has not defined one.
+
Colors.TopLevel.Normal = MakeColor (Color.BrightGreen, Color.Black);
Colors.TopLevel.Focus = MakeColor (Color.White, Color.Cyan);
Colors.TopLevel.HotNormal = MakeColor (Color.Brown, Color.Black);
diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs
index fddabb692..881b97426 100644
--- a/Terminal.Gui/Core/Toplevel.cs
+++ b/Terminal.Gui/Core/Toplevel.cs
@@ -821,7 +821,6 @@ namespace Terminal.Gui {
if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Released) && dragPosition.HasValue) {
Application.UngrabMouse ();
- Driver.UncookMouse ();
dragPosition = null;
}
@@ -960,6 +959,18 @@ namespace Terminal.Gui {
}
return false;
}
+
+ ///
+ public override bool OnEnter (View view)
+ {
+ return MostFocused?.OnEnter (view) ?? base.OnEnter (view);
+ }
+
+ ///
+ public override bool OnLeave (View view)
+ {
+ return MostFocused?.OnLeave (view) ?? base.OnLeave (view);
+ }
}
///
diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs
index 2a02bf118..09d8ca3a1 100644
--- a/Terminal.Gui/Core/View.cs
+++ b/Terminal.Gui/Core/View.cs
@@ -1447,8 +1447,9 @@ namespace Terminal.Gui {
///
public virtual ColorScheme ColorScheme {
get {
- if (colorScheme == null)
+ if (colorScheme == null) {
return SuperView?.ColorScheme;
+ }
return colorScheme;
}
set {
diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj
index ce22fd3cd..e92806346 100644
--- a/Terminal.Gui/Terminal.Gui.csproj
+++ b/Terminal.Gui/Terminal.Gui.csproj
@@ -10,9 +10,10 @@
- 1.9
- 1.9
- 1.9
+ 1.0
+ 1.0
+ 1.0
+ 1.0
diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs
index 14fc56394..07389fb4f 100644
--- a/Terminal.Gui/Views/TextField.cs
+++ b/Terminal.Gui/Views/TextField.cs
@@ -1346,12 +1346,12 @@ namespace Terminal.Gui {
}
///
- protected override string GetCurrentWord ()
+ protected override string GetCurrentWord (int columnOffset = 0)
{
var host = (TextField)HostControl;
var currentLine = host.Text.ToRuneList ();
- var cursorPosition = Math.Min (host.CursorPosition, currentLine.Count);
- return IdxToWord (currentLine, cursorPosition);
+ var cursorPosition = Math.Min (host.CursorPosition + columnOffset, currentLine.Count);
+ return IdxToWord (currentLine, cursorPosition, columnOffset);
}
///
diff --git a/Terminal.Gui/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs
index 3c9e54b09..7cb797b11 100644
--- a/Terminal.Gui/Views/TextView.cs
+++ b/Terminal.Gui/Views/TextView.cs
@@ -2035,6 +2035,16 @@ namespace Terminal.Gui {
return base.OnEnter (view);
}
+ ///
+ public override bool OnLeave (View view)
+ {
+ if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
+ Application.UngrabMouse ();
+ }
+
+ return base.OnLeave (view);
+ }
+
// Returns an encoded region start..end (top 32 bits are the row, low32 the column)
void GetEncodedRegionBounds (out long start, out long end,
int? startRow = null, int? startCol = null, int? cRow = null, int? cCol = null)
@@ -2437,6 +2447,10 @@ namespace Terminal.Gui {
PositionCursor ();
+ if (clickWithSelecting) {
+ clickWithSelecting = false;
+ return;
+ }
if (SelectedLength > 0)
return;
@@ -2667,8 +2681,10 @@ namespace Terminal.Gui {
need = true;
} else if ((wordWrap && leftColumn > 0) || (dSize.size + RightOffset < Frame.Width + offB.width
&& tSize.size + RightOffset < Frame.Width + offB.width)) {
- leftColumn = 0;
- need = true;
+ if (leftColumn > 0) {
+ leftColumn = 0;
+ need = true;
+ }
}
if (currentRow < topRow) {
@@ -4269,6 +4285,7 @@ namespace Terminal.Gui {
}
bool isButtonShift;
+ bool clickWithSelecting;
///
public override bool MouseEvent (MouseEvent ev)
@@ -4362,6 +4379,7 @@ namespace Terminal.Gui {
columnTrack = currentColumn;
} else if (ev.Flags.HasFlag (MouseFlags.Button1Pressed)) {
if (shiftSelecting) {
+ clickWithSelecting = true;
StopSelecting ();
}
ProcessMouseClick (ev, out _);
@@ -4447,16 +4465,6 @@ namespace Terminal.Gui {
line = r;
}
- ///
- public override bool OnLeave (View view)
- {
- if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
- Application.UngrabMouse ();
- }
-
- return base.OnLeave (view);
- }
-
///
/// Allows clearing the items updating the original text.
///
@@ -4475,12 +4483,12 @@ namespace Terminal.Gui {
public class TextViewAutocomplete : Autocomplete {
///
- protected override string GetCurrentWord ()
+ protected override string GetCurrentWord (int columnOffset = 0)
{
var host = (TextView)HostControl;
var currentLine = host.GetCurrentLine ();
- var cursorPosition = Math.Min (host.CurrentColumn, currentLine.Count);
- return IdxToWord (currentLine, cursorPosition);
+ var cursorPosition = Math.Min (host.CurrentColumn + columnOffset, currentLine.Count);
+ return IdxToWord (currentLine, cursorPosition, columnOffset);
}
///
diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs
index 65d6eda20..6d49d9e06 100644
--- a/UICatalog/UICatalog.cs
+++ b/UICatalog/UICatalog.cs
@@ -163,7 +163,7 @@ namespace UICatalog {
public UICatalogTopLevel ()
{
- ColorScheme = _colorScheme;
+ ColorScheme = _colorScheme = Colors.Base;
MenuBar = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_File", new MenuItem [] {
new MenuItem ("_Quit", "Quit UI Catalog", () => RequestStop(), null, null, Key.Q | Key.CtrlMask)
diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj
index 40d346438..6320c1e99 100644
--- a/UICatalog/UICatalog.csproj
+++ b/UICatalog/UICatalog.csproj
@@ -5,7 +5,7 @@
8.0
UICatalog.UICatalogApp
-
+
1.0
1.0
diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs
index b7ef1d8db..7228d8ad6 100644
--- a/UnitTests/Application/ApplicationTests.cs
+++ b/UnitTests/Application/ApplicationTests.cs
@@ -24,7 +24,6 @@ namespace Terminal.Gui.ApplicationTests {
Assert.Null (Application.Driver);
Assert.Null (Application.Top);
Assert.Null (Application.Current);
- Assert.Throws (() => Application.HeightAsBuffer == true);
Assert.Null (Application.MainLoop);
Assert.Null (Application.Iteration);
Assert.Null (Application.RootMouseEvent);
diff --git a/UnitTests/Drivers/AttributeTests.cs b/UnitTests/Drivers/AttributeTests.cs
index ddc7b4695..fd563c051 100644
--- a/UnitTests/Drivers/AttributeTests.cs
+++ b/UnitTests/Drivers/AttributeTests.cs
@@ -85,7 +85,34 @@ namespace Terminal.Gui.DriverTests {
}
[Fact]
- public void Make_Asserts_IfNotInit ()
+ public void Implicit_Assign_NoDriver ()
+ {
+
+ var attr = new Attribute ();
+
+ var fg = new Color ();
+ fg = Color.Red;
+
+ var bg = new Color ();
+ bg = Color.Blue;
+
+ // Test conversion to int
+ attr = new Attribute (fg, bg);
+ int value_implicit = (int)attr.Value;
+ Assert.False (attr.Initialized);
+
+ Assert.Equal (-1, value_implicit);
+ Assert.False (attr.Initialized);
+
+ // Test conversion from int
+ attr = -1;
+ Assert.Equal (-1, attr.Value);
+ Assert.False (attr.Initialized);
+
+ }
+
+ [Fact]
+ public void Make_SetsNotInitialized_NoDriver ()
{
var fg = new Color ();
fg = Color.Red;
@@ -93,7 +120,9 @@ namespace Terminal.Gui.DriverTests {
var bg = new Color ();
bg = Color.Blue;
- Assert.Throws (() => Attribute.Make (fg, bg));
+ var a = Attribute.Make (fg, bg);
+
+ Assert.False (a.Initialized);
}
[Fact]
@@ -109,8 +138,8 @@ namespace Terminal.Gui.DriverTests {
var bg = new Color ();
bg = Color.Blue;
- var attr = Attribute.Make (fg, bg);
-
+ var attr = Attribute.Make (fg, bg);
+ Assert.True (attr.Initialized);
Assert.Equal (fg, attr.Foreground);
Assert.Equal (bg, attr.Background);
@@ -119,7 +148,23 @@ namespace Terminal.Gui.DriverTests {
}
[Fact]
- public void Get_Asserts_IfNotInit ()
+ public void Make_Creates_NoDriver ()
+ {
+
+ var fg = new Color ();
+ fg = Color.Red;
+
+ var bg = new Color ();
+ bg = Color.Blue;
+
+ var attr = Attribute.Make (fg, bg);
+ Assert.False (attr.Initialized);
+ Assert.Equal (fg, attr.Foreground);
+ Assert.Equal (bg, attr.Background);
+ }
+
+ [Fact]
+ public void Get_Asserts_NoDriver ()
{
Assert.Throws (() => Attribute.Get ());
}
@@ -163,5 +208,24 @@ namespace Terminal.Gui.DriverTests {
Assert.Equal (Color.Red, fg);
Assert.Equal (Color.Green, bg);
}
+
+ [Fact]
+ public void IsValid_Tests ()
+ {
+ var attr = new Attribute ();
+ Assert.True (attr.HasValidColors);
+
+ attr = new Attribute (Color.Red, Color.Green);
+ Assert.True (attr.HasValidColors);
+
+ attr = new Attribute (Color.Red, Color.Invalid);
+ Assert.False (attr.HasValidColors);
+
+ attr = new Attribute (Color.Invalid, Color.Green);
+ Assert.False (attr.HasValidColors);
+
+ attr = new Attribute (Color.Invalid, Color.Invalid);
+ Assert.False (attr.HasValidColors);
+ }
}
}
diff --git a/UnitTests/Drivers/ColorTests.cs b/UnitTests/Drivers/ColorTests.cs
index f42463c81..3e8266e27 100644
--- a/UnitTests/Drivers/ColorTests.cs
+++ b/UnitTests/Drivers/ColorTests.cs
@@ -35,5 +35,14 @@ namespace Terminal.Gui.DriverTests {
Application.Shutdown ();
}
+ [Fact, AutoInitShutdown]
+ public void ColorScheme_New ()
+ {
+ var scheme = new ColorScheme ();
+ var lbl = new Label ();
+ lbl.ColorScheme = scheme;
+ lbl.Redraw (lbl.Bounds);
+ }
+
}
}
\ No newline at end of file
diff --git a/UnitTests/Drivers/ConsoleDriverTests.cs b/UnitTests/Drivers/ConsoleDriverTests.cs
index a77d5f5a6..8289e9737 100644
--- a/UnitTests/Drivers/ConsoleDriverTests.cs
+++ b/UnitTests/Drivers/ConsoleDriverTests.cs
@@ -319,7 +319,7 @@ namespace Terminal.Gui.DriverTests {
Application.Shutdown ();
}
-
+
[Fact, AutoInitShutdown]
public void AddRune_On_Clip_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space ()
{
@@ -441,7 +441,7 @@ namespace Terminal.Gui.DriverTests {
}
private static object packetLock = new object ();
-
+
///
/// Sometimes when using remote tools EventKeyRecord sends 'virtual keystrokes'.
/// These are indicated with the wVirtualKeyCode of 231. When we see this code
@@ -487,6 +487,7 @@ namespace Terminal.Gui.DriverTests {
if (iterations == 0) Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control);
};
+
lock (packetLock) {
Application.Run ();
Application.Shutdown ();
diff --git a/UnitTests/Drivers/KeyTests.cs b/UnitTests/Drivers/KeyTests.cs
index 3d4d8606e..3116c8628 100644
--- a/UnitTests/Drivers/KeyTests.cs
+++ b/UnitTests/Drivers/KeyTests.cs
@@ -1,4 +1,5 @@
using System;
+using Terminal.Gui;
using Xunit;
namespace Terminal.Gui.DriverTests {
diff --git a/UnitTests/TopLevels/ToplevelTests.cs b/UnitTests/TopLevels/ToplevelTests.cs
index 7cd2b1d06..88f9181dd 100644
--- a/UnitTests/TopLevels/ToplevelTests.cs
+++ b/UnitTests/TopLevels/ToplevelTests.cs
@@ -696,7 +696,7 @@ namespace Terminal.Gui.TopLevelTests {
((FakeDriver)Application.Driver).SetBufferSize (40, 15);
MessageBox.Query ("About", "Hello Word", "Ok");
- } else if (iterations == 1) TestHelpers.AssertDriverContentsWithFrameAre (@"
+ } else if (iterations == 1) TestHelpers.AssertDriverContentsWithFrameAre (@"
File
┌ Window ──────────────────────────────┐
│ │
@@ -712,7 +712,7 @@ namespace Terminal.Gui.TopLevelTests {
│ │
└──────────────────────────────────────┘
CTRL-N New ", output);
-else if (iterations == 2) {
+ else if (iterations == 2) {
Assert.Null (Application.MouseGrabView);
// Grab the mouse
ReflectionTools.InvokePrivate (
@@ -815,8 +815,8 @@ else if (iterations == 2) {
Assert.Null (Application.MouseGrabView);
- } else if (iterations == 8) Application.RequestStop ();
-else if (iterations == 9) Application.RequestStop ();
+ } else if (iterations == 8) Application.RequestStop ();
+ else if (iterations == 9) Application.RequestStop ();
};
Application.Run ();
@@ -956,7 +956,7 @@ else if (iterations == 9) Application.RequestStop ();
Assert.Null (Application.MouseGrabView);
- } else if (iterations == 8) Application.RequestStop ();
+ } else if (iterations == 8) Application.RequestStop ();
};
Application.Run ();
@@ -974,5 +974,42 @@ else if (iterations == 9) Application.RequestStop ();
exception = Record.Exception (() => ((FakeDriver)Application.Driver).SetBufferSize (10, 0));
Assert.Null (exception);
}
+
+ [Fact, AutoInitShutdown]
+ public void OnEnter_OnLeave_Triggered_On_Application_Begin_End ()
+ {
+ var isEnter = false;
+ var isLeave = false;
+ var v = new View ();
+ v.Enter += (_) => isEnter = true;
+ v.Leave += (_) => isLeave = true;
+ var top = Application.Top;
+ top.Add (v);
+
+ Assert.False (v.CanFocus);
+ var exception = Record.Exception (() => top.OnEnter (top));
+ Assert.Null (exception);
+ exception = Record.Exception (() => top.OnLeave (top));
+ Assert.Null (exception);
+
+ v.CanFocus = true;
+ Application.Begin (top);
+
+ Assert.True (isEnter);
+ Assert.False (isLeave);
+
+ isEnter = false;
+ var d = new Dialog ();
+ var rs = Application.Begin (d);
+
+ Assert.False (isEnter);
+ Assert.True (isLeave);
+
+ isLeave = false;
+ Application.End (rs);
+
+ Assert.True (isEnter);
+ Assert.False (isLeave);
+ }
}
}
\ No newline at end of file
diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj
index 68da4e1d0..ae3766244 100644
--- a/UnitTests/UnitTests.csproj
+++ b/UnitTests/UnitTests.csproj
@@ -7,12 +7,12 @@
false
-
+
- 1.0
- 1.0
- 1.0
- 1.0
+ 2.0
+ 2.0
+ 2.0
+ 2.0
TRACE
diff --git a/UnitTests/Views/AutocompleteTests.cs b/UnitTests/Views/AutocompleteTests.cs
index 51dd0076c..dca1fd81c 100644
--- a/UnitTests/Views/AutocompleteTests.cs
+++ b/UnitTests/Views/AutocompleteTests.cs
@@ -6,9 +6,16 @@ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Terminal.Gui;
using Xunit;
+using Xunit.Abstractions;
namespace Terminal.Gui.ViewTests {
public class AutocompleteTests {
+ readonly ITestOutputHelper output;
+
+ public AutocompleteTests (ITestOutputHelper output)
+ {
+ this.output = output;
+ }
[Fact]
public void Test_GenerateSuggestions_Simple ()
@@ -151,5 +158,84 @@ namespace Terminal.Gui.ViewTests {
Assert.Empty (tv.Autocomplete.Suggestions);
Assert.Equal (3, tv.Autocomplete.AllSuggestions.Count);
}
+
+ [Fact, AutoInitShutdown]
+ public void CursorLeft_CursorRight_Mouse_Button_Pressed_Does_Not_Show_Popup ()
+ {
+ var tv = new TextView () {
+ Width = 50,
+ Height = 5,
+ Text = "This a long line and against TextView."
+ };
+ tv.Autocomplete.AllSuggestions = Regex.Matches (tv.Text.ToString (), "\\w+")
+ .Select (s => s.Value)
+ .Distinct ().ToList ();
+ var top = Application.Top;
+ top.Add (tv);
+ Application.Begin (top);
+
+
+ for (int i = 0; i < 7; i++) {
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This a long line and against TextView.", output);
+ }
+
+ Assert.True (tv.MouseEvent (new MouseEvent () {
+ X = 6,
+ Y = 0,
+ Flags = MouseFlags.Button1Pressed
+ }));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This a long line and against TextView.", output);
+
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.g, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This ag long line and against TextView.
+ against ", output);
+
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This ag long line and against TextView.
+ against ", output);
+
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This ag long line and against TextView.
+ against ", output);
+
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This ag long line and against TextView.", output);
+
+ for (int i = 0; i < 3; i++) {
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This ag long line and against TextView.", output);
+ }
+
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.Backspace, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This a long line and against TextView.", output);
+
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.n, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This an long line and against TextView.
+ and ", output);
+
+ Assert.True (tv.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ())));
+ Application.Refresh ();
+ TestHelpers.AssertDriverContentsWithFrameAre (@"
+This an long line and against TextView.", output);
+ }
}
}
\ No newline at end of file
diff --git a/UnitTests/Views/ViewTests.cs b/UnitTests/Views/ViewTests.cs
index 3d93e7d6c..01c1f19ad 100644
--- a/UnitTests/Views/ViewTests.cs
+++ b/UnitTests/Views/ViewTests.cs
@@ -1602,8 +1602,8 @@ Y
// Calling the Text constructor.
lbl = new Label (text);
}
- lbl.ColorScheme = new ColorScheme ();
- lbl.Redraw (lbl.Bounds);
+ Application.Top.Add (lbl);
+ Application.Top.Redraw (Application.Top.Bounds);
// should have the initial text
Assert.Equal ('t', driver.Contents [0, 0, 0]);