From 0ddf097820c9b88c0a6f9da774f286a1f4d6875f Mon Sep 17 00:00:00 2001 From: Charlie Kindel Date: Sun, 16 Oct 2022 07:29:31 -0600 Subject: [PATCH 01/19] setting up v2.0 branch --- Example/Example.csproj | 10 +++++----- README.md | 2 ++ ReactiveExample/ReactiveExample.csproj | 10 +++++----- Terminal.Gui/Terminal.Gui.csproj | 10 +++++----- UICatalog/UICatalog.csproj | 10 +++++----- UnitTests/UnitTests.csproj | 10 +++++----- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/Example/Example.csproj b/Example/Example.csproj index fc1498ca1..046a97db0 100644 --- a/Example/Example.csproj +++ b/Example/Example.csproj @@ -3,12 +3,12 @@ Exe net6.0 - + - 1.0 - 1.0 - 1.0 - 1.0 + 2.0 + 2.0 + 2.0 + 2.0 diff --git a/README.md b/README.md index 5269552cb..0de4e1acc 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ [![License](https://img.shields.io/github/license/gui-cs/gui.cs.svg)](LICENSE) ![Bugs](https://img.shields.io/github/issues/gui-cs/gui.cs/bug) +# This is the v2.0 Branch - Under Development + # Terminal.Gui - Cross Platform Terminal UI toolkit for .NET A toolkit for building rich console apps for .NET, .NET Core, and Mono that works on Windows, the Mac, and Linux/Unix. diff --git a/ReactiveExample/ReactiveExample.csproj b/ReactiveExample/ReactiveExample.csproj index 274cbde40..afbdd701e 100644 --- a/ReactiveExample/ReactiveExample.csproj +++ b/ReactiveExample/ReactiveExample.csproj @@ -3,12 +3,12 @@ Exe net6.0 - + - 1.0 - 1.0 - 1.0 - 1.0 + 2.0 + 2.0 + 2.0 + 2.0 diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index 39d2e1ff2..1ca5e9f92 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -8,12 +8,12 @@ - + - 1.0 - 1.0 - 1.0 - 1.0 + 2.0 + 2.0 + 2.0 + 2.0 diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj index 234474a26..8302da79d 100644 --- a/UICatalog/UICatalog.csproj +++ b/UICatalog/UICatalog.csproj @@ -5,12 +5,12 @@ 8.0 UICatalog.UICatalogApp - + - 1.0 - 1.0 - 1.0 - 1.0 + 2.0 + 2.0 + 2.0 + 2.0 TRACE diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index 5cc67ac22..56684104b 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -4,12 +4,12 @@ false - + - 1.0 - 1.0 - 1.0 - 1.0 + 2.0 + 2.0 + 2.0 + 2.0 TRACE From 8a9e7af2a581d531ce4a2b8c688312391f3096c8 Mon Sep 17 00:00:00 2001 From: Charlie Kindel Date: Sun, 16 Oct 2022 08:09:47 -0600 Subject: [PATCH 02/19] updated readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0de4e1acc..cbd0ab92a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ # This is the v2.0 Branch - Under Development +See the v2 Discussion here: https://github.com/gui-cs/Terminal.Gui/discussions/1940 + # Terminal.Gui - Cross Platform Terminal UI toolkit for .NET A toolkit for building rich console apps for .NET, .NET Core, and Mono that works on Windows, the Mac, and Linux/Unix. From 7f563244eb8f1f1c7d1e926bbe5307fc99a8f466 Mon Sep 17 00:00:00 2001 From: Charlie Kindel Date: Fri, 20 Jan 2023 15:50:11 -0700 Subject: [PATCH 03/19] Made Attribute Make more robust --- .../CursesDriver/CursesDriver.cs | 5 +- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 9 +- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 4 +- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 3 +- Terminal.Gui/Core/ConsoleDriver.cs | 214 +++++++++++++----- UnitTests/Drivers/AttributeTests.cs | 8 +- UnitTests/Drivers/ColorTests.cs | 9 + UnitTests/Views/ViewTests.cs | 4 +- 8 files changed, 188 insertions(+), 68 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index d8d38392f..8b8c2219c 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -160,10 +160,11 @@ namespace Terminal.Gui { public override void UpdateScreen () => window.redrawwin (); - Attribute currentAttribute; + Attribute currentAttribute = new Attribute (Color.White, Color.Black); public override void SetAttribute (Attribute c) { + base.SetAttribute (c); currentAttribute = c; Curses.attrset (currentAttribute); } @@ -201,6 +202,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]; @@ -218,6 +220,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); diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 77526629b..f34b141b3 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -208,11 +208,9 @@ namespace Terminal.Gui { rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT; FakeConsole.Clear (); ResizeScreen (); - UpdateOffScreen (); - + // Call CreateColors before UpdateOffScreen as it references Colors CreateColors (); - - //MockConsole.Clear (); + UpdateOffScreen (); } public override Attribute MakeAttribute (Color fore, Color back) @@ -283,9 +281,10 @@ namespace Terminal.Gui { UpdateCursor (); } - Attribute currentAttribute; + Attribute currentAttribute = new Attribute (Color.White, Color.Black); public override void SetAttribute (Attribute c) { + base.SetAttribute (c); currentAttribute = c; } diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 37b43244b..1273742fd 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1613,9 +1613,11 @@ namespace Terminal.Gui { { } - Attribute currentAttribute; + Attribute currentAttribute = new Attribute (Color.White, Color.Black); + public override void SetAttribute (Attribute c) { + base.SetAttribute (c); currentAttribute = c; } diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 28013fe71..fecbccb92 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1568,10 +1568,11 @@ namespace Terminal.Gui { AddRune (rune); } - Attribute currentAttribute; + Attribute currentAttribute = new Attribute (Color.White, Color.Black); public override void SetAttribute (Attribute c) { + base.SetAttribute (c); currentAttribute = c; } diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 42d32ebfa..e84f7df0e 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -1,23 +1,23 @@ // -// 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. + /// + [DefaultValue(Invalid)] public enum Color { /// /// The black color. @@ -82,31 +82,50 @@ 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 + /// 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. /// public Color Background { get; } + /// + /// 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 IsInitialized { get; internal set; } + /// /// Initializes a new instance of the struct with only the value passed to /// and trying to get the colors if defined. @@ -123,6 +142,7 @@ namespace Terminal.Gui { Value = value; Foreground = foreground; Background = background; + IsInitialized = true; } /// @@ -136,6 +156,7 @@ namespace Terminal.Gui { Value = value; Foreground = foreground; Background = background; + IsInitialized = true; } /// @@ -145,6 +166,7 @@ namespace Terminal.Gui { /// Background public Attribute (Color foreground = new Color (), Color background = new Color ()) { + IsInitialized = true; Value = Make (foreground, background).Value; Foreground = foreground; Background = background; @@ -158,29 +180,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) { + Debug.WriteLineIf (!c.IsInitialized, "ConsoleDriver.SetAttribute: Attributes must be initialized by a driver before use."); + //if (!c.IsInitialized) throw new InvalidOperationException ("Attributes must be initialized by 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.IsInitialized = false; + return a; + } return Application.Driver.MakeAttribute (foreground, background); } @@ -194,45 +229,103 @@ namespace Terminal.Gui { throw new InvalidOperationException ("The Application has not been initialized"); return Application.Driver.GetAttribute (); } + + /// + /// Returns if the Atrribute is valid (both foreground and background have valid color values). + /// + /// + public bool IsValid () + { + 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 = ""; /// - /// 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.IsValid ()) { + 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.IsValid ()) { + 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.IsValid ()) { + 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.IsValid ()) { + 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.IsValid ()) { + return; + } + _disabled = value; + } + } /// /// Compares two objects for equality. @@ -361,15 +454,15 @@ 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; } /// @@ -659,13 +752,19 @@ namespace Terminal.Gui { public abstract void UpdateScreen (); /// - /// Selects the specified attribute as the attribute to use for future calls to AddRune, AddString. + /// Selects the specified attribute as the attribute to use for future calls to AddRune and AddString. /// + /// + /// Implementations should call base.SetAttribute(c). + /// /// C. - public abstract void SetAttribute (Attribute c); + public virtual void SetAttribute (Attribute c) + { + Debug.WriteLineIf(!c.IsInitialized, "ConsoleDriver.SetAttribute: Attributes must be initialized before use."); + } /// - /// Set Colors from limit sets of colors. + /// Set Colors from limit sets of colors. Not implemented by any driver: See Issue #2300. /// /// Foreground. /// Background. @@ -675,7 +774,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 +1097,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 (); @@ -1222,19 +1322,23 @@ namespace Terminal.Gui { /// /// Create all with the for the console driver. /// - /// Flag indicating if colors are supported. - public void CreateColors (bool hasColors = true) + /// Flag indicating if colors are supported. + public void CreateColors (bool supportsColors = true) { - Colors.TopLevel = new ColorScheme (); - Colors.Base = new ColorScheme (); - Colors.Dialog = new ColorScheme (); - Colors.Menu = new ColorScheme (); - Colors.Error = new ColorScheme (); + // BUGBUG: No need to create these instances here as they are created in constructor + //Colors.TopLevel = new ColorScheme (); + //Colors.Base = new ColorScheme (); + //Colors.Dialog = new ColorScheme (); + //Colors.Menu = new ColorScheme (); + //Colors.Error = new ColorScheme (); - 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/UnitTests/Drivers/AttributeTests.cs b/UnitTests/Drivers/AttributeTests.cs index ddc7b4695..3cae7b8b5 100644 --- a/UnitTests/Drivers/AttributeTests.cs +++ b/UnitTests/Drivers/AttributeTests.cs @@ -85,7 +85,7 @@ namespace Terminal.Gui.DriverTests { } [Fact] - public void Make_Asserts_IfNotInit () + public void Make_SetsNotInitialized_IfNotInit () { var fg = new Color (); fg = Color.Red; @@ -93,7 +93,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.IsInitialized); } [Fact] @@ -110,7 +112,7 @@ namespace Terminal.Gui.DriverTests { bg = Color.Blue; var attr = Attribute.Make (fg, bg); - + Assert.True (attr.IsInitialized); Assert.Equal (fg, attr.Foreground); Assert.Equal (bg, attr.Background); 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/Views/ViewTests.cs b/UnitTests/Views/ViewTests.cs index b1a22046c..0733c9698 100644 --- a/UnitTests/Views/ViewTests.cs +++ b/UnitTests/Views/ViewTests.cs @@ -1601,8 +1601,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]); From 6cabb20f89a61a686312d489a0726bc4b8720ffd Mon Sep 17 00:00:00 2001 From: Charlie Kindel Date: Fri, 20 Jan 2023 16:31:32 -0700 Subject: [PATCH 04/19] Tweaks to make code more clear --- Terminal.Gui/Core/ConsoleDriver.cs | 60 ++++++++++++------------ UnitTests/Drivers/AttributeTests.cs | 72 +++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 34 deletions(-) diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index e84f7df0e..4fd2dd6f9 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -99,7 +99,7 @@ namespace Terminal.Gui { /// public struct Attribute { /// - /// The -specific color attribute value. If is + /// 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. /// @@ -115,17 +115,6 @@ namespace Terminal.Gui { /// public Color Background { get; } - /// - /// 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 IsInitialized { get; internal set; } - /// /// Initializes a new instance of the struct with only the value passed to /// and trying to get the colors if defined. @@ -133,16 +122,17 @@ 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; Background = background; - IsInitialized = true; } /// @@ -156,7 +146,7 @@ namespace Terminal.Gui { Value = value; Foreground = foreground; Background = background; - IsInitialized = true; + Initialized = true; } /// @@ -166,7 +156,7 @@ namespace Terminal.Gui { /// Background public Attribute (Color foreground = new Color (), Color background = new Color ()) { - IsInitialized = true; + Initialized = false; Value = Make (foreground, background).Value; Foreground = foreground; Background = background; @@ -186,7 +176,7 @@ namespace Terminal.Gui { /// The driver-specific color value stored in the attribute. /// The attribute to convert public static implicit operator int (Attribute c) { - Debug.WriteLineIf (!c.IsInitialized, "ConsoleDriver.SetAttribute: Attributes must be initialized by a driver before use."); + Debug.WriteLineIf (!c.Initialized, "ConsoleDriver.SetAttribute: Attributes must be initialized by a driver before use."); //if (!c.IsInitialized) throw new InvalidOperationException ("Attributes must be initialized by driver before use."); return c.Value; } @@ -203,7 +193,7 @@ namespace Terminal.Gui { /// /// /// If a has not been loaded (Application.Driver == null) this - /// method will return an attribute with set to . + /// method will return an attribute with set to . /// /// The new attribute. /// Foreground color to use. @@ -213,7 +203,7 @@ namespace Terminal.Gui { if (Application.Driver == null) { // Create the attribute, but show it's not been initialized var a = new Attribute (-1, foreground, background); - a.IsInitialized = false; + a.Initialized = false; return a; } return Application.Driver.MakeAttribute (foreground, background); @@ -230,13 +220,25 @@ namespace Terminal.Gui { 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 IsValid () - { - return Foreground != Color.Invalid && Background != Color.Invalid; + public bool HasValidColors { + get { + return Foreground != Color.Invalid && Background != Color.Invalid; + } } } @@ -268,7 +270,7 @@ namespace Terminal.Gui { get { return _normal; } set { - if (!value.IsValid ()) { + if (!value.HasValidColors) { return; } _normal = value; @@ -281,7 +283,7 @@ namespace Terminal.Gui { public Attribute Focus { get { return _focus; } set { - if (!value.IsValid ()) { + if (!value.HasValidColors) { return; } _focus = value; @@ -294,7 +296,7 @@ namespace Terminal.Gui { public Attribute HotNormal { get { return _hotNormal; } set { - if (!value.IsValid ()) { + if (!value.HasValidColors) { return; } _hotNormal = value; @@ -307,7 +309,7 @@ namespace Terminal.Gui { public Attribute HotFocus { get { return _hotFocus; } set { - if (!value.IsValid ()) { + if (!value.HasValidColors) { return; } _hotFocus = value; @@ -320,7 +322,7 @@ namespace Terminal.Gui { public Attribute Disabled { get { return _disabled; } set { - if (!value.IsValid ()) { + if (!value.HasValidColors) { return; } _disabled = value; @@ -760,7 +762,7 @@ namespace Terminal.Gui { /// C. public virtual void SetAttribute (Attribute c) { - Debug.WriteLineIf(!c.IsInitialized, "ConsoleDriver.SetAttribute: Attributes must be initialized before use."); + Debug.WriteLineIf(!c.Initialized, "ConsoleDriver.SetAttribute: Attributes must be initialized before use."); } /// diff --git a/UnitTests/Drivers/AttributeTests.cs b/UnitTests/Drivers/AttributeTests.cs index 3cae7b8b5..fd563c051 100644 --- a/UnitTests/Drivers/AttributeTests.cs +++ b/UnitTests/Drivers/AttributeTests.cs @@ -85,7 +85,34 @@ namespace Terminal.Gui.DriverTests { } [Fact] - public void Make_SetsNotInitialized_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; @@ -95,7 +122,7 @@ namespace Terminal.Gui.DriverTests { var a = Attribute.Make (fg, bg); - Assert.False (a.IsInitialized); + Assert.False (a.Initialized); } [Fact] @@ -111,8 +138,8 @@ namespace Terminal.Gui.DriverTests { var bg = new Color (); bg = Color.Blue; - var attr = Attribute.Make (fg, bg); - Assert.True (attr.IsInitialized); + var attr = Attribute.Make (fg, bg); + Assert.True (attr.Initialized); Assert.Equal (fg, attr.Foreground); Assert.Equal (bg, attr.Background); @@ -121,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 ()); } @@ -165,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); + } } } From ed7cb3d4293bb158e756fde815e4eb06cfcd783b Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 11:25:29 +0900 Subject: [PATCH 05/19] removed unused GetColors api --- .../CursesDriver/CursesDriver.cs | 132 ++---- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 70 +-- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 67 +-- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 84 ++-- Terminal.Gui/Core/ConsoleDriver.cs | 410 +++++++++++++----- 5 files changed, 428 insertions(+), 335 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 0a61f3bbb..7c828afd5 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -62,62 +62,43 @@ namespace Terminal.Gui { Curses.move (crow, ccol); needMove = false; } - if (runeWidth == 0 && ccol > 0) { - var r = contents [crow, ccol - 1, 0]; - var s = new string (new char [] { (char)r, (char)rune }); - string sn; - if (!s.IsNormalized ()) { - sn = s.Normalize (); - } else { - sn = s; - } - 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, 2] = 1; + if (runeWidth < 2 && ccol > 0 + && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { - } else { - if (runeWidth < 2 && ccol > 0 - && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + var curAtttib = CurrentAttribute; + Curses.attrset (contents [crow, ccol - 1, 1]); + Curses.mvaddch (crow, ccol - 1, (int)(uint)' '); + contents [crow, ccol - 1, 0] = (int)(uint)' '; + Curses.move (crow, ccol); + Curses.attrset (curAtttib); - var curAtttib = currentAttribute; - Curses.attrset (contents [crow, ccol - 1, 1]); - Curses.mvaddch (crow, ccol - 1, (int)(uint)' '); - contents [crow, ccol - 1, 0] = (int)(uint)' '; - Curses.move (crow, ccol); - Curses.attrset (curAtttib); + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { + var curAtttib = CurrentAttribute; + Curses.attrset (contents [crow, ccol + 1, 1]); + Curses.mvaddch (crow, ccol + 1, (int)(uint)' '); + contents [crow, ccol + 1, 0] = (int)(uint)' '; + Curses.move (crow, ccol); + Curses.attrset (curAtttib); - var curAtttib = currentAttribute; - Curses.attrset (contents [crow, ccol + 1, 1]); - Curses.mvaddch (crow, ccol + 1, (int)(uint)' '); - contents [crow, ccol + 1, 0] = (int)(uint)' '; - Curses.move (crow, ccol); - Curses.attrset (curAtttib); - - } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - Curses.addch ((int)(uint)' '); - contents [crow, ccol, 0] = (int)(uint)' '; - } else { - Curses.addch ((int)(uint)rune); - contents [crow, ccol, 0] = (int)(uint)rune; - } - contents [crow, ccol, 1] = currentAttribute; - contents [crow, ccol, 2] = 1; } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + Curses.addch ((int)(uint)' '); + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + Curses.addch ((int)(uint)rune); + contents [crow, ccol, 0] = (int)(uint)rune; + } + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; } else needMove = true; - if (runeWidth < 0 || runeWidth > 0) { - ccol++; - } + 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++; @@ -179,12 +160,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; @@ -216,27 +195,10 @@ namespace Terminal.Gui { return MakeColor ((short)MapColor (fore), (short)MapColor (back)); } - int [,] colorPairs = new int [16, 16]; - - public override void SetColors (ConsoleColor foreground, ConsoleColor background) - { - int f = (short)foreground; - int b = (short)background; - var v = colorPairs [f, b]; - if ((v & 0x10000) == 0) { - b &= 0x7; - bool bold = (f & 0x8) != 0; - f &= 0x7; - - v = MakeColor ((short)f, (short)b) | (bold ? Curses.A_BOLD : 0); - colorPairs [(int)foreground, (int)background] = v | 0x1000; - } - SetAttribute (v & 0xffff); - } - 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 +856,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 +894,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 +972,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"); } @@ -1114,7 +1066,7 @@ namespace Terminal.Gui { public override Attribute GetAttribute () { - return currentAttribute; + return CurrentAttribute; } /// diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 84ced2be2..0b22e30e8 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -33,7 +33,7 @@ namespace Terminal.Gui { UseFakeClipboard = useFakeClipboard; FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException; FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue; - + // double check usage is correct Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false); Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false); @@ -131,52 +131,34 @@ namespace Terminal.Gui { //MockConsole.CursorTop = crow; needMove = false; } - if (runeWidth == 0 && ccol > 0) { - var r = contents [crow, ccol - 1, 0]; - var s = new string (new char [] { (char)r, (char)rune }); - string sn; - if (!s.IsNormalized ()) { - sn = s.Normalize (); - } else { - sn = s; - } - var c = sn [0]; - contents [crow, ccol - 1, 0] = c; - contents [crow, ccol - 1, 1] = currentAttribute; - contents [crow, ccol - 1, 2] = 1; - - } else { - if (runeWidth < 2 && ccol > 0 + if (runeWidth < 2 && ccol > 0 && Rune.ColumnWidth ((Rune)contents [crow, ccol - 1, 0]) > 1) { - contents [crow, ccol - 1, 0] = (int)(uint)' '; + contents [crow, ccol - 1, 0] = (int)(uint)' '; - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((Rune)contents [crow, ccol, 0]) > 1) { + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((Rune)contents [crow, ccol, 0]) > 1) { - contents [crow, ccol + 1, 0] = (int)(uint)' '; - contents [crow, ccol + 1, 2] = 1; + contents [crow, ccol + 1, 0] = (int)(uint)' '; + contents [crow, ccol + 1, 2] = 1; - } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - contents [crow, ccol, 0] = (int)(uint)' '; - } else { - contents [crow, ccol, 0] = (int)(uint)rune; - } - contents [crow, ccol, 1] = currentAttribute; - contents [crow, ccol, 2] = 1; - - dirtyLine [crow] = true; } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + contents [crow, ccol, 0] = (int)(uint)rune; + } + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; + + dirtyLine [crow] = true; } else needMove = true; - if (runeWidth < 0 || runeWidth > 0) { - ccol++; - } + 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++; @@ -226,11 +208,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 +282,9 @@ namespace Terminal.Gui { UpdateCursor (); } - Attribute currentAttribute; public override void SetAttribute (Attribute c) { - currentAttribute = c; + base.SetAttribute (c); } public ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo) @@ -495,7 +475,7 @@ namespace Terminal.Gui { public override Attribute GetAttribute () { - return currentAttribute; + return CurrentAttribute; } /// @@ -674,10 +654,6 @@ namespace Terminal.Gui { { } - public override void SetColors (ConsoleColor foreground, ConsoleColor background) - { - } - public override void SetColors (short foregroundColorId, short backgroundColorId) { throw new NotImplementedException (); diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 0b1da2d2a..2726d38da 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1241,51 +1241,33 @@ namespace Terminal.Gui { var validClip = IsValidContent (ccol, crow, Clip); if (validClip) { - if (runeWidth == 0 && ccol > 0) { - var r = contents [crow, ccol - 1, 0]; - var s = new string (new char [] { (char)r, (char)rune }); - string sn; - if (!s.IsNormalized ()) { - sn = s.Normalize (); - } else { - sn = s; - } - var c = sn [0]; - contents [crow, ccol - 1, 0] = c; - contents [crow, ccol - 1, 1] = currentAttribute; - contents [crow, ccol - 1, 2] = 1; + if (runeWidth < 2 && ccol > 0 + && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { - } else { - if (runeWidth < 2 && ccol > 0 - && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + contents [crow, ccol - 1, 0] = (int)(uint)' '; - contents [crow, ccol - 1, 0] = (int)(uint)' '; + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - - contents [crow, ccol + 1, 0] = (int)(uint)' '; - contents [crow, ccol + 1, 2] = 1; - - } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - contents [crow, ccol, 0] = (int)(uint)' '; - } else { - contents [crow, ccol, 0] = (int)(uint)rune; - } - contents [crow, ccol, 1] = currentAttribute; - contents [crow, ccol, 2] = 1; + contents [crow, ccol + 1, 0] = (int)(uint)' '; + contents [crow, ccol + 1, 2] = 1; } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + contents [crow, ccol, 0] = (int)(uint)rune; + } + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; + dirtyLine [crow] = true; } - if (runeWidth < 0 || runeWidth > 0) { - ccol++; - } + 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 +1340,14 @@ namespace Terminal.Gui { cols = Console.WindowWidth; rows = Console.WindowHeight; + CurrentAttribute = MakeColor (Color.White, Color.Black); + InitalizeColorSchemes (); + ResizeScreen (); UpdateOffScreen (); StartReportingMouseMoves (); - CreateColors (); Clear (); } @@ -1503,7 +1487,7 @@ namespace Terminal.Gui { outputWidth++; var rune = contents [row, col, 0]; char [] spair; - if (Rune.DecodeSurrogatePair ((uint)rune, out spair)) { + if (Rune.DecodeSurrogatePair((uint) rune, out spair)) { output.Append (spair); } else { output.Append ((char)rune); @@ -1631,10 +1615,10 @@ namespace Terminal.Gui { { } - Attribute currentAttribute; + public override void SetAttribute (Attribute c) { - currentAttribute = c; + base.SetAttribute (c); } public ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo) @@ -1954,7 +1938,7 @@ namespace Terminal.Gui { public override Attribute GetAttribute () { - return currentAttribute; + return CurrentAttribute; } /// @@ -2017,9 +2001,6 @@ namespace Terminal.Gui { } #region Unused - public override void SetColors (ConsoleColor foreground, ConsoleColor background) - { - } public override void SetColors (short foregroundColorId, short backgroundColorId) { diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 8d1b71646..fcb128e28 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1455,13 +1455,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); } @@ -1517,63 +1517,42 @@ namespace Terminal.Gui { var validClip = IsValidContent (ccol, crow, Clip); if (validClip) { - if (runeWidth == 0 && ccol > 0) { - var r = contents [crow, ccol - 1, 0]; - var s = new string (new char [] { (char)r, (char)rune }); - string sn; - if (!s.IsNormalized ()) { - sn = s.Normalize (); - } else { - sn = s; - } - var c = sn [0]; + if (runeWidth < 2 && ccol > 0 + && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + 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; - contents [crow, ccol - 1, 2] = 1; - WindowsConsole.SmallRect.Update (ref damageRegion, (short)(ccol - 1), (short)crow); - } else { - if (runeWidth < 2 && ccol > 0 - && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + OutputBuffer [prevPosition].Char.UnicodeChar = ' '; + contents [crow, ccol - 1, 0] = (int)(uint)' '; - var prevPosition = crow * Cols + (ccol - 1); - OutputBuffer [prevPosition].Char.UnicodeChar = ' '; - contents [crow, ccol - 1, 0] = (int)(uint)' '; + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { + var prevPosition = GetOutputBufferPosition () + 1; + OutputBuffer [prevPosition].Char.UnicodeChar = (char)' '; + contents [crow, ccol + 1, 0] = (int)(uint)' '; - var prevPosition = GetOutputBufferPosition () + 1; - OutputBuffer [prevPosition].Char.UnicodeChar = (char)' '; - contents [crow, ccol + 1, 0] = (int)(uint)' '; - - } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - OutputBuffer [position].Char.UnicodeChar = (char)' '; - contents [crow, ccol, 0] = (int)(uint)' '; - } else { - OutputBuffer [position].Char.UnicodeChar = (char)rune; - contents [crow, ccol, 0] = (int)(uint)rune; - } - OutputBuffer [position].Attributes = (ushort)currentAttribute; - contents [crow, ccol, 1] = currentAttribute; - contents [crow, ccol, 2] = 1; - WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + OutputBuffer [position].Char.UnicodeChar = (char)' '; + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + OutputBuffer [position].Char.UnicodeChar = (char)rune; + contents [crow, ccol, 0] = (int)(uint)rune; + } + OutputBuffer [position].Attributes = (ushort)CurrentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; + WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } - if (runeWidth < 0 || runeWidth > 0) { - ccol++; - } + 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++; @@ -1589,11 +1568,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) @@ -1697,7 +1674,7 @@ namespace Terminal.Gui { public override Attribute GetAttribute () { - return currentAttribute; + return CurrentAttribute; } /// @@ -1792,9 +1769,6 @@ namespace Terminal.Gui { } #region Unused - public override void SetColors (ConsoleColor foreground, ConsoleColor background) - { - } public override void SetColors (short foregroundColorId, short backgroundColorId) { diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 42d32ebfa..518771801 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 + } + + /// + /// + /// + 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,23 +878,38 @@ 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. /// - /// Foreground. - /// Background. - public abstract void SetColors (ConsoleColor foreground, ConsoleColor background); + /// + /// Implementations should call base.SetAttribute(c). + /// + /// C. + public virtual void SetAttribute (Attribute c) + { + CurrentAttribute = c; + } // Advanced uses - set colors to any pre-set pairs, you would need to init_color // 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 +1232,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 +1431,8 @@ namespace Terminal.Gui { /// Lower right rounded corner /// public Rune LRRCorner = '\u256f'; + + private Attribute _currentAttribute; /// /// Make the attribute for the foreground and background colors. @@ -1220,50 +1457,23 @@ 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; } - Colors.TopLevel.Normal = MakeColor (Color.BrightGreen, Color.Black); - Colors.TopLevel.Focus = MakeColor (Color.White, Color.Cyan); - Colors.TopLevel.HotNormal = MakeColor (Color.Brown, Color.Black); - Colors.TopLevel.HotFocus = MakeColor (Color.Blue, Color.Cyan); - Colors.TopLevel.Disabled = MakeColor (Color.DarkGray, Color.Black); - - Colors.Base.Normal = MakeColor (Color.White, Color.Blue); - Colors.Base.Focus = MakeColor (Color.Black, Color.Gray); - Colors.Base.HotNormal = MakeColor (Color.BrightCyan, Color.Blue); - Colors.Base.HotFocus = MakeColor (Color.BrightBlue, Color.Gray); - Colors.Base.Disabled = MakeColor (Color.DarkGray, Color.Blue); - - Colors.Dialog.Normal = MakeColor (Color.Black, Color.Gray); - Colors.Dialog.Focus = MakeColor (Color.White, Color.DarkGray); - Colors.Dialog.HotNormal = MakeColor (Color.Blue, Color.Gray); - Colors.Dialog.HotFocus = MakeColor (Color.BrightYellow, Color.DarkGray); - Colors.Dialog.Disabled = MakeColor (Color.Gray, Color.DarkGray); - - Colors.Menu.Normal = MakeColor (Color.White, Color.DarkGray); - Colors.Menu.Focus = MakeColor (Color.White, Color.Black); - Colors.Menu.HotNormal = MakeColor (Color.BrightYellow, Color.DarkGray); - Colors.Menu.HotFocus = MakeColor (Color.BrightYellow, Color.Black); - Colors.Menu.Disabled = MakeColor (Color.Gray, Color.DarkGray); - - Colors.Error.Normal = MakeColor (Color.Red, Color.White); - Colors.Error.Focus = MakeColor (Color.Black, Color.BrightRed); - Colors.Error.HotNormal = MakeColor (Color.Black, Color.White); - Colors.Error.HotFocus = MakeColor (Color.White, Color.BrightRed); - Colors.Error.Disabled = MakeColor (Color.DarkGray, Color.White); } } From 0dcc69023e0fda605e1e684df302a5051af58ce5 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 11:26:36 +0900 Subject: [PATCH 06/19] removed unused GetColors api --- .../ConsoleDrivers/CursesDriver/CursesDriver.cs | 12 ------------ Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs | 5 ----- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 5 ----- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 5 ----- Terminal.Gui/Core/ConsoleDriver.cs | 10 ---------- 5 files changed, 37 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 7c828afd5..e7ebc03f8 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -195,18 +195,6 @@ namespace Terminal.Gui { return MakeColor ((short)MapColor (fore), (short)MapColor (back)); } - 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); - rawPairs [key] = v; - } - SetAttribute (v); - } - static Key MapCursesKey (int cursesKey) { switch (cursesKey) { diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 0b22e30e8..27d038982 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -654,11 +654,6 @@ namespace Terminal.Gui { { } - public override void SetColors (short foregroundColorId, short backgroundColorId) - { - throw new NotImplementedException (); - } - public override void CookMouse () { } diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 2726d38da..bad3d940e 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -2001,11 +2001,6 @@ namespace Terminal.Gui { } #region Unused - - public override void SetColors (short foregroundColorId, short backgroundColorId) - { - } - public override void CookMouse () { } diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index fcb128e28..59a3d9674 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1769,11 +1769,6 @@ namespace Terminal.Gui { } #region Unused - - public override void SetColors (short foregroundColorId, short backgroundColorId) - { - } - public override void Suspend () { } diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 518771801..7e6eb0953 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -905,16 +905,6 @@ namespace Terminal.Gui { CurrentAttribute = c; } - // Advanced uses - set colors to any pre-set pairs, you would need to init_color - // 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. Not implemented by any driver: See Issue #2300. - /// - /// Foreground color identifier. - /// Background color identifier. - public abstract void SetColors (short foregroundColorId, short backgroundColorId); - /// /// Gets the foreground and background colors based on the value. /// From de5af990df4deb19c5d61116da0799f668f75624 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 11:28:33 +0900 Subject: [PATCH 07/19] removed unused Cook/UncookMouse APIs --- .../ConsoleDrivers/CursesDriver/CursesDriver.cs | 17 ----------------- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 9 --------- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 10 ---------- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 8 -------- Terminal.Gui/Core/ConsoleDriver.cs | 11 ----------- Terminal.Gui/Core/Toplevel.cs | 1 - 6 files changed, 56 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index e7ebc03f8..5702f6ba5 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -1035,23 +1035,6 @@ namespace Terminal.Gui { Console.Out.Flush (); } - //int lastMouseInterval; - //bool mouseGrabbed; - - public override void UncookMouse () - { - //if (mouseGrabbed) - // return; - //lastMouseInterval = Curses.mouseinterval (0); - //mouseGrabbed = true; - } - - public override void CookMouse () - { - //mouseGrabbed = false; - //Curses.mouseinterval (lastMouseInterval); - } - public override Attribute GetAttribute () { return CurrentAttribute; diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 27d038982..39257fcb5 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -653,15 +653,6 @@ namespace Terminal.Gui { public override void Suspend () { } - - public override void CookMouse () - { - } - - public override void UncookMouse () - { - } - #endregion public class FakeClipboard : ClipboardBase { diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index bad3d940e..c9236de22 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -2000,16 +2000,6 @@ namespace Terminal.Gui { return hasColor; } - #region Unused - public override void CookMouse () - { - } - - public override void UncookMouse () - { - } - #endregion - // // These are for the .NET driver, but running natively on Windows, wont run // on the Mono emulation diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 59a3d9674..29439e8c4 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1780,14 +1780,6 @@ namespace Terminal.Gui { public override void StopReportingMouseMoves () { } - - public override void UncookMouse () - { - } - - public override void CookMouse () - { - } #endregion } diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 7e6eb0953..122c7e69c 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -1221,17 +1221,6 @@ 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. Not implemented by any driver: See Issue #2300. - /// - public abstract void UncookMouse (); - - /// - /// Enables the cooked event processing from the mouse driver. Not implemented by any driver: See Issue #2300. - /// - public abstract void CookMouse (); - /// /// Horizontal line character. /// diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index fddabb692..1346244a0 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; } From 84a4bb69d430082c9ce90bf6cf5257700f20ebb2 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 11:31:02 +0900 Subject: [PATCH 08/19] removed unused Cook/UncookMouse APIs --- Terminal.Gui/Core/Application.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index b5f6e5984..327c9e2c4 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -705,7 +705,6 @@ namespace Terminal.Gui { return; OnGrabbedMouse (view); mouseGrabView = view; - Driver.UncookMouse (); } /// @@ -717,7 +716,6 @@ namespace Terminal.Gui { return; OnUnGrabbedMouse (mouseGrabView); mouseGrabView = null; - Driver.CookMouse (); } static void OnGrabbedMouse (View view) From 9e58ed9963e4a2a371f09eaf237432bec1f650a6 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 11:41:09 +0900 Subject: [PATCH 09/19] cleanup --- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 16 +--- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 14 +--- Terminal.Gui/Core/ConsoleDriver.cs | 84 ++++--------------- 3 files changed, 21 insertions(+), 93 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 39257fcb5..fcfa18c0b 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -626,7 +626,6 @@ namespace Terminal.Gui { return hasColor; } - #region Unused public override void UpdateCursor () { if (!EnsureCursorVisibility ()) @@ -642,17 +641,10 @@ namespace Terminal.Gui { } } - public override void StartReportingMouseMoves () - { - } - - public override void StopReportingMouseMoves () - { - } - - public override void Suspend () - { - } + #region Unused + public override void StartReportingMouseMoves () {} + public override void StopReportingMouseMoves () {} + public override void Suspend () {} #endregion public class FakeClipboard : ClipboardBase { diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 29439e8c4..16692f966 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1769,17 +1769,9 @@ namespace Terminal.Gui { } #region Unused - public override void Suspend () - { - } - - public override void StartReportingMouseMoves () - { - } - - public override void StopReportingMouseMoves () - { - } + public override void StartReportingMouseMoves () { } + public override void StopReportingMouseMoves () { } + public override void Suspend () { } #endregion } diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 122c7e69c..9b7adf001 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -170,9 +170,18 @@ namespace Terminal.Gui { /// 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. /// 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. + /// + /// + /// s are driver-specific and, as a result, are only valid if initialized by a . + /// If an is created before a driver is initialized + /// and attempts to use the will result in an exception. To use an that is not + /// initilzied, after a driver is initialized, recreate the by calling the constructor + /// or . + /// /// public struct Attribute { /// @@ -424,11 +433,11 @@ namespace Terminal.Gui { public bool Equals (ColorScheme other) { return other != null && - EqualityComparer.Default.Equals (_normal, other._normal) && - EqualityComparer.Default.Equals (_focus, other._focus) && - EqualityComparer.Default.Equals (_hotNormal, other._hotNormal) && - EqualityComparer.Default.Equals (_hotFocus, other._hotFocus) && - EqualityComparer.Default.Equals (_disabled, other._disabled); + EqualityComparer.Default.Equals (_normal, other._normal) && + EqualityComparer.Default.Equals (_focus, other._focus) && + EqualityComparer.Default.Equals (_hotNormal, other._hotNormal) && + EqualityComparer.Default.Equals (_hotFocus, other._hotFocus) && + EqualityComparer.Default.Equals (_disabled, other._disabled); } /// @@ -655,71 +664,6 @@ namespace Terminal.Gui { BoxFix = 0x02020164, } - ///// - ///// Special characters that can be drawn with - ///// - //public enum SpecialChar { - // /// - // /// Horizontal line character. - // /// - // HLine, - - // /// - // /// Vertical line character. - // /// - // VLine, - - // /// - // /// Stipple pattern - // /// - // Stipple, - - // /// - // /// Diamond character - // /// - // Diamond, - - // /// - // /// Upper left corner - // /// - // ULCorner, - - // /// - // /// Lower left corner - // /// - // LLCorner, - - // /// - // /// Upper right corner - // /// - // URCorner, - - // /// - // /// Lower right corner - // /// - // LRCorner, - - // /// - // /// Left tee - // /// - // LeftTee, - - // /// - // /// Right tee - // /// - // RightTee, - - // /// - // /// Top tee - // /// - // TopTee, - - // /// - // /// The bottom tee. - // /// - // BottomTee, - //} - /// /// ConsoleDriver is an abstract class that defines the requirements for a console driver. /// There are currently three implementations: (for Unix and Mac), , and that uses the .NET Console API. From 4531eb00d20f5617291145559e9ed30dfbc9af21 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 11:56:53 +0900 Subject: [PATCH 10/19] more cleanup --- .../CursesDriver/CursesDriver.cs | 26 +++---------------- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 5 ---- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 5 ---- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 5 ---- Terminal.Gui/Core/ConsoleDriver.cs | 6 ++--- 5 files changed, 6 insertions(+), 41 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 5702f6ba5..7d2b0b422 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -143,19 +143,6 @@ namespace Terminal.Gui { SetCursorVisibility (CursorVisibility.Default); Curses.endwin (); - - // I'm commenting this because was used in a trying to fix the Linux hanging and forgot to exclude it. - // Clear and reset entire screen. - //Console.Out.Write ("\x1b[2J"); - //Console.Out.Flush (); - - // Set top and bottom lines of a window. - //Console.Out.Write ("\x1b[1;25r"); - //Console.Out.Flush (); - - //Set cursor key to cursor. - //Console.Out.Write ("\x1b[?1l"); - //Console.Out.Flush (); } public override void UpdateScreen () => window.redrawwin (); @@ -168,8 +155,6 @@ namespace Terminal.Gui { public Curses.Window window; - //static short last_color_pair = 16; - /// /// Creates a curses color from the provided foreground and background colors /// @@ -782,7 +767,7 @@ namespace Terminal.Gui { }; } - Curses.Event oldMouseEvents, reportableMouseEvents; + Curses.Event reportableMouseEvents; public override void Init (Action terminalResized) { if (window != null) @@ -839,7 +824,7 @@ namespace Terminal.Gui { Curses.noecho (); Curses.Window.Standard.keypad (true); - reportableMouseEvents = Curses.mousemask (Curses.Event.AllEvents | Curses.Event.ReportMousePosition, out oldMouseEvents); + reportableMouseEvents = Curses.mousemask (Curses.Event.AllEvents | Curses.Event.ReportMousePosition, out _); TerminalResized = terminalResized; if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition)) StartReportingMouseMoves (); @@ -961,7 +946,7 @@ namespace Terminal.Gui { case Color.White: return Curses.COLOR_WHITE | Curses.A_BOLD | Curses.COLOR_GRAY; case Color.Invalid: - return Curses.COLOR_BLACK; + return Curses.COLOR_BLACK; } throw new ArgumentException ("Invalid color code"); } @@ -1035,11 +1020,6 @@ namespace Terminal.Gui { Console.Out.Flush (); } - 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 fcfa18c0b..3adbb7a23 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -473,11 +473,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 c9236de22..485a06f6e 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1936,11 +1936,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 16692f966..9b0568a62 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1672,11 +1672,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/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index 9b7adf001..e0f52ccc6 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -177,7 +177,7 @@ namespace Terminal.Gui { /// /// /// s are driver-specific and, as a result, are only valid if initialized by a . - /// If an is created before a driver is initialized + /// If an is created before a driver is initialized will be /// and attempts to use the will result in an exception. To use an that is not /// initilzied, after a driver is initialized, recreate the by calling the constructor /// or . @@ -824,7 +824,7 @@ namespace Terminal.Gui { /// /// The current attribute the driver is using. /// - public virtual Attribute CurrentAttribute { + internal virtual Attribute CurrentAttribute { get => _currentAttribute; set { if (!value.Initialized && value.HasValidColors && Application.Driver != null) { @@ -1369,7 +1369,7 @@ namespace Terminal.Gui { /// Gets the current . /// /// The current attribute. - public abstract Attribute GetAttribute (); + public Attribute GetAttribute () => CurrentAttribute; /// /// Make the for the . From a0c2369a848becdbd7d5eb38a20d9fb6691340e3 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 12:01:58 +0900 Subject: [PATCH 11/19] forgot to merge unit tests --- UnitTests/Drivers/AttributeTests.cs | 12 -- UnitTests/Drivers/ColorTests.cs | 9 + UnitTests/Drivers/ConsoleDriverTests.cs | 230 ++++++++++++------------ UnitTests/Drivers/KeyTests.cs | 1 + 4 files changed, 122 insertions(+), 130 deletions(-) diff --git a/UnitTests/Drivers/AttributeTests.cs b/UnitTests/Drivers/AttributeTests.cs index ddc7b4695..33deb8ac7 100644 --- a/UnitTests/Drivers/AttributeTests.cs +++ b/UnitTests/Drivers/AttributeTests.cs @@ -84,18 +84,6 @@ namespace Terminal.Gui.DriverTests { Application.Shutdown (); } - [Fact] - public void Make_Asserts_IfNotInit () - { - var fg = new Color (); - fg = Color.Red; - - var bg = new Color (); - bg = Color.Blue; - - Assert.Throws (() => Attribute.Make (fg, bg)); - } - [Fact] public void Make_Creates () { 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..cdc8edfc6 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 () { @@ -440,8 +440,6 @@ namespace Terminal.Gui.DriverTests { Assert.Equal (code, actual.Value); } - 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,126 +485,122 @@ namespace Terminal.Gui.DriverTests { if (iterations == 0) Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control); }; - lock (packetLock) { - Application.Run (); - Application.Shutdown (); - } + Application.Run (); + Application.Shutdown (); } public class PacketTest : IEnumerable, IEnumerable { public IEnumerator GetEnumerator () { - lock (packetLock) { - yield return new object [] { 'a', false, false, false, 'A', 30, Key.a, 'A', 30 }; - yield return new object [] { 'A', true, false, false, 'A', 30, Key.A | Key.ShiftMask, 'A', 30 }; - yield return new object [] { 'A', true, true, false, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask, 'A', 30 }; - yield return new object [] { 'A', true, true, true, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'A', 30 }; - yield return new object [] { 'z', false, false, false, 'Z', 44, Key.z, 'Z', 44 }; - yield return new object [] { 'Z', true, false, false, 'Z', 44, Key.Z | Key.ShiftMask, 'Z', 44 }; - yield return new object [] { 'Z', true, true, false, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask, 'Z', 44 }; - yield return new object [] { 'Z', true, true, true, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'Z', 44 }; - yield return new object [] { '英', false, false, false, '\0', 0, (Key)'英', '\0', 0 }; - yield return new object [] { '英', true, false, false, '\0', 0, (Key)'英' | Key.ShiftMask, '\0', 0 }; - yield return new object [] { '英', true, true, false, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask, '\0', 0 }; - yield return new object [] { '英', true, true, true, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '\0', 0 }; - yield return new object [] { '+', false, false, false, 187, 26, (Key)'+', 187, 26 }; - yield return new object [] { '*', true, false, false, 187, 26, (Key)'*' | Key.ShiftMask, 187, 26 }; - yield return new object [] { '+', true, true, false, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask, 187, 26 }; - yield return new object [] { '+', true, true, true, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 187, 26 }; - yield return new object [] { '1', false, false, false, '1', 2, Key.D1, '1', 2 }; - yield return new object [] { '!', true, false, false, '1', 2, (Key)'!' | Key.ShiftMask, '1', 2 }; - yield return new object [] { '1', true, true, false, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask, '1', 2 }; - yield return new object [] { '1', true, true, true, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '1', 2 }; - yield return new object [] { '1', false, true, true, '1', 2, Key.D1 | Key.AltMask | Key.CtrlMask, '1', 2 }; - yield return new object [] { '2', false, false, false, '2', 3, Key.D2, '2', 3 }; - yield return new object [] { '"', true, false, false, '2', 3, (Key)'"' | Key.ShiftMask, '2', 3 }; - yield return new object [] { '2', true, true, false, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask, '2', 3 }; - yield return new object [] { '2', true, true, true, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '2', 3 }; - yield return new object [] { '@', false, true, true, '2', 3, (Key)'@' | Key.AltMask | Key.CtrlMask, '2', 3 }; - yield return new object [] { '3', false, false, false, '3', 4, Key.D3, '3', 4 }; - yield return new object [] { '#', true, false, false, '3', 4, (Key)'#' | Key.ShiftMask, '3', 4 }; - yield return new object [] { '3', true, true, false, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask, '3', 4 }; - yield return new object [] { '3', true, true, true, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '3', 4 }; - yield return new object [] { '£', false, true, true, '3', 4, (Key)'£' | Key.AltMask | Key.CtrlMask, '3', 4 }; - yield return new object [] { '4', false, false, false, '4', 5, Key.D4, '4', 5 }; - yield return new object [] { '$', true, false, false, '4', 5, (Key)'$' | Key.ShiftMask, '4', 5 }; - yield return new object [] { '4', true, true, false, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask, '4', 5 }; - yield return new object [] { '4', true, true, true, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '4', 5 }; - yield return new object [] { '§', false, true, true, '4', 5, (Key)'§' | Key.AltMask | Key.CtrlMask, '4', 5 }; - yield return new object [] { '5', false, false, false, '5', 6, Key.D5, '5', 6 }; - yield return new object [] { '%', true, false, false, '5', 6, (Key)'%' | Key.ShiftMask, '5', 6 }; - yield return new object [] { '5', true, true, false, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask, '5', 6 }; - yield return new object [] { '5', true, true, true, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '5', 6 }; - yield return new object [] { '€', false, true, true, '5', 6, (Key)'€' | Key.AltMask | Key.CtrlMask, '5', 6 }; - yield return new object [] { '6', false, false, false, '6', 7, Key.D6, '6', 7 }; - yield return new object [] { '&', true, false, false, '6', 7, (Key)'&' | Key.ShiftMask, '6', 7 }; - yield return new object [] { '6', true, true, false, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask, '6', 7 }; - yield return new object [] { '6', true, true, true, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '6', 7 }; - yield return new object [] { '6', false, true, true, '6', 7, Key.D6 | Key.AltMask | Key.CtrlMask, '6', 7 }; - yield return new object [] { '7', false, false, false, '7', 8, Key.D7, '7', 8 }; - yield return new object [] { '/', true, false, false, '7', 8, (Key)'/' | Key.ShiftMask, '7', 8 }; - yield return new object [] { '7', true, true, false, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask, '7', 8 }; - yield return new object [] { '7', true, true, true, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '7', 8 }; - yield return new object [] { '{', false, true, true, '7', 8, (Key)'{' | Key.AltMask | Key.CtrlMask, '7', 8 }; - yield return new object [] { '8', false, false, false, '8', 9, Key.D8, '8', 9 }; - yield return new object [] { '(', true, false, false, '8', 9, (Key)'(' | Key.ShiftMask, '8', 9 }; - yield return new object [] { '8', true, true, false, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask, '8', 9 }; - yield return new object [] { '8', true, true, true, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '8', 9 }; - yield return new object [] { '[', false, true, true, '8', 9, (Key)'[' | Key.AltMask | Key.CtrlMask, '8', 9 }; - yield return new object [] { '9', false, false, false, '9', 10, Key.D9, '9', 10 }; - yield return new object [] { ')', true, false, false, '9', 10, (Key)')' | Key.ShiftMask, '9', 10 }; - yield return new object [] { '9', true, true, false, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask, '9', 10 }; - yield return new object [] { '9', true, true, true, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '9', 10 }; - yield return new object [] { ']', false, true, true, '9', 10, (Key)']' | Key.AltMask | Key.CtrlMask, '9', 10 }; - yield return new object [] { '0', false, false, false, '0', 11, Key.D0, '0', 11 }; - yield return new object [] { '=', true, false, false, '0', 11, (Key)'=' | Key.ShiftMask, '0', 11 }; - yield return new object [] { '0', true, true, false, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask, '0', 11 }; - yield return new object [] { '0', true, true, true, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '0', 11 }; - yield return new object [] { '}', false, true, true, '0', 11, (Key)'}' | Key.AltMask | Key.CtrlMask, '0', 11 }; - yield return new object [] { '\'', false, false, false, 219, 12, (Key)'\'', 219, 12 }; - yield return new object [] { '?', true, false, false, 219, 12, (Key)'?' | Key.ShiftMask, 219, 12 }; - yield return new object [] { '\'', true, true, false, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask, 219, 12 }; - yield return new object [] { '\'', true, true, true, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 219, 12 }; - yield return new object [] { '«', false, false, false, 221, 13, (Key)'«', 221, 13 }; - yield return new object [] { '»', true, false, false, 221, 13, (Key)'»' | Key.ShiftMask, 221, 13 }; - yield return new object [] { '«', true, true, false, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask, 221, 13 }; - yield return new object [] { '«', true, true, true, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 221, 13 }; - yield return new object [] { 'á', false, false, false, 'á', 0, (Key)'á', 'A', 30 }; - yield return new object [] { 'Á', true, false, false, 'Á', 0, (Key)'Á' | Key.ShiftMask, 'A', 30 }; - yield return new object [] { 'à', false, false, false, 'à', 0, (Key)'à', 'A', 30 }; - yield return new object [] { 'À', true, false, false, 'À', 0, (Key)'À' | Key.ShiftMask, 'A', 30 }; - yield return new object [] { 'é', false, false, false, 'é', 0, (Key)'é', 'E', 18 }; - yield return new object [] { 'É', true, false, false, 'É', 0, (Key)'É' | Key.ShiftMask, 'E', 18 }; - yield return new object [] { 'è', false, false, false, 'è', 0, (Key)'è', 'E', 18 }; - yield return new object [] { 'È', true, false, false, 'È', 0, (Key)'È' | Key.ShiftMask, 'E', 18 }; - yield return new object [] { 'í', false, false, false, 'í', 0, (Key)'í', 'I', 23 }; - yield return new object [] { 'Í', true, false, false, 'Í', 0, (Key)'Í' | Key.ShiftMask, 'I', 23 }; - yield return new object [] { 'ì', false, false, false, 'ì', 0, (Key)'ì', 'I', 23 }; - yield return new object [] { 'Ì', true, false, false, 'Ì', 0, (Key)'Ì' | Key.ShiftMask, 'I', 23 }; - yield return new object [] { 'ó', false, false, false, 'ó', 0, (Key)'ó', 'O', 24 }; - yield return new object [] { 'Ó', true, false, false, 'Ó', 0, (Key)'Ó' | Key.ShiftMask, 'O', 24 }; - yield return new object [] { 'ò', false, false, false, 'Ó', 0, (Key)'ò', 'O', 24 }; - yield return new object [] { 'Ò', true, false, false, 'Ò', 0, (Key)'Ò' | Key.ShiftMask, 'O', 24 }; - yield return new object [] { 'ú', false, false, false, 'ú', 0, (Key)'ú', 'U', 22 }; - yield return new object [] { 'Ú', true, false, false, 'Ú', 0, (Key)'Ú' | Key.ShiftMask, 'U', 22 }; - yield return new object [] { 'ù', false, false, false, 'ù', 0, (Key)'ù', 'U', 22 }; - yield return new object [] { 'Ù', true, false, false, 'Ù', 0, (Key)'Ù' | Key.ShiftMask, 'U', 22 }; - yield return new object [] { 'ö', false, false, false, 'ó', 0, (Key)'ö', 'O', 24 }; - yield return new object [] { 'Ö', true, false, false, 'Ó', 0, (Key)'Ö' | Key.ShiftMask, 'O', 24 }; - yield return new object [] { '<', false, false, false, 226, 86, (Key)'<', 226, 86 }; - yield return new object [] { '>', true, false, false, 226, 86, (Key)'>' | Key.ShiftMask, 226, 86 }; - yield return new object [] { '<', true, true, false, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask, 226, 86 }; - yield return new object [] { '<', true, true, true, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 226, 86 }; - yield return new object [] { 'ç', false, false, false, 192, 39, (Key)'ç', 192, 39 }; - yield return new object [] { 'Ç', true, false, false, 192, 39, (Key)'Ç' | Key.ShiftMask, 192, 39 }; - yield return new object [] { 'ç', true, true, false, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask, 192, 39 }; - yield return new object [] { 'ç', true, true, true, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 192, 39 }; - yield return new object [] { '¨', false, true, true, 187, 26, (Key)'¨' | Key.AltMask | Key.CtrlMask, 187, 26 }; - yield return new object [] { (uint)Key.PageUp, false, false, false, 33, 73, Key.PageUp, 33, 73 }; - yield return new object [] { (uint)Key.PageUp, true, false, false, 33, 73, Key.PageUp | Key.ShiftMask, 33, 73 }; - yield return new object [] { (uint)Key.PageUp, true, true, false, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask, 33, 73 }; - yield return new object [] { (uint)Key.PageUp, true, true, true, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 33, 73 }; - } + yield return new object [] { 'a', false, false, false, 'A', 30, Key.a, 'A', 30 }; + yield return new object [] { 'A', true, false, false, 'A', 30, Key.A | Key.ShiftMask, 'A', 30 }; + yield return new object [] { 'A', true, true, false, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask, 'A', 30 }; + yield return new object [] { 'A', true, true, true, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'A', 30 }; + yield return new object [] { 'z', false, false, false, 'Z', 44, Key.z, 'Z', 44 }; + yield return new object [] { 'Z', true, false, false, 'Z', 44, Key.Z | Key.ShiftMask, 'Z', 44 }; + yield return new object [] { 'Z', true, true, false, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask, 'Z', 44 }; + yield return new object [] { 'Z', true, true, true, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'Z', 44 }; + yield return new object [] { '英', false, false, false, '\0', 0, (Key)'英', '\0', 0 }; + yield return new object [] { '英', true, false, false, '\0', 0, (Key)'英' | Key.ShiftMask, '\0', 0 }; + yield return new object [] { '英', true, true, false, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask, '\0', 0 }; + yield return new object [] { '英', true, true, true, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '\0', 0 }; + yield return new object [] { '+', false, false, false, 187, 26, (Key)'+', 187, 26 }; + yield return new object [] { '*', true, false, false, 187, 26, (Key)'*' | Key.ShiftMask, 187, 26 }; + yield return new object [] { '+', true, true, false, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask, 187, 26 }; + yield return new object [] { '+', true, true, true, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 187, 26 }; + yield return new object [] { '1', false, false, false, '1', 2, Key.D1, '1', 2 }; + yield return new object [] { '!', true, false, false, '1', 2, (Key)'!' | Key.ShiftMask, '1', 2 }; + yield return new object [] { '1', true, true, false, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask, '1', 2 }; + yield return new object [] { '1', true, true, true, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '1', 2 }; + yield return new object [] { '1', false, true, true, '1', 2, Key.D1 | Key.AltMask | Key.CtrlMask, '1', 2 }; + yield return new object [] { '2', false, false, false, '2', 3, Key.D2, '2', 3 }; + yield return new object [] { '"', true, false, false, '2', 3, (Key)'"' | Key.ShiftMask, '2', 3 }; + yield return new object [] { '2', true, true, false, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask, '2', 3 }; + yield return new object [] { '2', true, true, true, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '2', 3 }; + yield return new object [] { '@', false, true, true, '2', 3, (Key)'@' | Key.AltMask | Key.CtrlMask, '2', 3 }; + yield return new object [] { '3', false, false, false, '3', 4, Key.D3, '3', 4 }; + yield return new object [] { '#', true, false, false, '3', 4, (Key)'#' | Key.ShiftMask, '3', 4 }; + yield return new object [] { '3', true, true, false, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask, '3', 4 }; + yield return new object [] { '3', true, true, true, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '3', 4 }; + yield return new object [] { '£', false, true, true, '3', 4, (Key)'£' | Key.AltMask | Key.CtrlMask, '3', 4 }; + yield return new object [] { '4', false, false, false, '4', 5, Key.D4, '4', 5 }; + yield return new object [] { '$', true, false, false, '4', 5, (Key)'$' | Key.ShiftMask, '4', 5 }; + yield return new object [] { '4', true, true, false, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask, '4', 5 }; + yield return new object [] { '4', true, true, true, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '4', 5 }; + yield return new object [] { '§', false, true, true, '4', 5, (Key)'§' | Key.AltMask | Key.CtrlMask, '4', 5 }; + yield return new object [] { '5', false, false, false, '5', 6, Key.D5, '5', 6 }; + yield return new object [] { '%', true, false, false, '5', 6, (Key)'%' | Key.ShiftMask, '5', 6 }; + yield return new object [] { '5', true, true, false, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask, '5', 6 }; + yield return new object [] { '5', true, true, true, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '5', 6 }; + yield return new object [] { '€', false, true, true, '5', 6, (Key)'€' | Key.AltMask | Key.CtrlMask, '5', 6 }; + yield return new object [] { '6', false, false, false, '6', 7, Key.D6, '6', 7 }; + yield return new object [] { '&', true, false, false, '6', 7, (Key)'&' | Key.ShiftMask, '6', 7 }; + yield return new object [] { '6', true, true, false, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask, '6', 7 }; + yield return new object [] { '6', true, true, true, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '6', 7 }; + yield return new object [] { '6', false, true, true, '6', 7, Key.D6 | Key.AltMask | Key.CtrlMask, '6', 7 }; + yield return new object [] { '7', false, false, false, '7', 8, Key.D7, '7', 8 }; + yield return new object [] { '/', true, false, false, '7', 8, (Key)'/' | Key.ShiftMask, '7', 8 }; + yield return new object [] { '7', true, true, false, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask, '7', 8 }; + yield return new object [] { '7', true, true, true, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '7', 8 }; + yield return new object [] { '{', false, true, true, '7', 8, (Key)'{' | Key.AltMask | Key.CtrlMask, '7', 8 }; + yield return new object [] { '8', false, false, false, '8', 9, Key.D8, '8', 9 }; + yield return new object [] { '(', true, false, false, '8', 9, (Key)'(' | Key.ShiftMask, '8', 9 }; + yield return new object [] { '8', true, true, false, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask, '8', 9 }; + yield return new object [] { '8', true, true, true, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '8', 9 }; + yield return new object [] { '[', false, true, true, '8', 9, (Key)'[' | Key.AltMask | Key.CtrlMask, '8', 9 }; + yield return new object [] { '9', false, false, false, '9', 10, Key.D9, '9', 10 }; + yield return new object [] { ')', true, false, false, '9', 10, (Key)')' | Key.ShiftMask, '9', 10 }; + yield return new object [] { '9', true, true, false, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask, '9', 10 }; + yield return new object [] { '9', true, true, true, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '9', 10 }; + yield return new object [] { ']', false, true, true, '9', 10, (Key)']' | Key.AltMask | Key.CtrlMask, '9', 10 }; + yield return new object [] { '0', false, false, false, '0', 11, Key.D0, '0', 11 }; + yield return new object [] { '=', true, false, false, '0', 11, (Key)'=' | Key.ShiftMask, '0', 11 }; + yield return new object [] { '0', true, true, false, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask, '0', 11 }; + yield return new object [] { '0', true, true, true, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '0', 11 }; + yield return new object [] { '}', false, true, true, '0', 11, (Key)'}' | Key.AltMask | Key.CtrlMask, '0', 11 }; + yield return new object [] { '\'', false, false, false, 219, 12, (Key)'\'', 219, 12 }; + yield return new object [] { '?', true, false, false, 219, 12, (Key)'?' | Key.ShiftMask, 219, 12 }; + yield return new object [] { '\'', true, true, false, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask, 219, 12 }; + yield return new object [] { '\'', true, true, true, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 219, 12 }; + yield return new object [] { '«', false, false, false, 221, 13, (Key)'«', 221, 13 }; + yield return new object [] { '»', true, false, false, 221, 13, (Key)'»' | Key.ShiftMask, 221, 13 }; + yield return new object [] { '«', true, true, false, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask, 221, 13 }; + yield return new object [] { '«', true, true, true, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 221, 13 }; + yield return new object [] { 'á', false, false, false, 'á', 0, (Key)'á', 'A', 30 }; + yield return new object [] { 'Á', true, false, false, 'Á', 0, (Key)'Á' | Key.ShiftMask, 'A', 30 }; + yield return new object [] { 'à', false, false, false, 'à', 0, (Key)'à', 'A', 30 }; + yield return new object [] { 'À', true, false, false, 'À', 0, (Key)'À' | Key.ShiftMask, 'A', 30 }; + yield return new object [] { 'é', false, false, false, 'é', 0, (Key)'é', 'E', 18 }; + yield return new object [] { 'É', true, false, false, 'É', 0, (Key)'É' | Key.ShiftMask, 'E', 18 }; + yield return new object [] { 'è', false, false, false, 'è', 0, (Key)'è', 'E', 18 }; + yield return new object [] { 'È', true, false, false, 'È', 0, (Key)'È' | Key.ShiftMask, 'E', 18 }; + yield return new object [] { 'í', false, false, false, 'í', 0, (Key)'í', 'I', 23 }; + yield return new object [] { 'Í', true, false, false, 'Í', 0, (Key)'Í' | Key.ShiftMask, 'I', 23 }; + yield return new object [] { 'ì', false, false, false, 'ì', 0, (Key)'ì', 'I', 23 }; + yield return new object [] { 'Ì', true, false, false, 'Ì', 0, (Key)'Ì' | Key.ShiftMask, 'I', 23 }; + yield return new object [] { 'ó', false, false, false, 'ó', 0, (Key)'ó', 'O', 24 }; + yield return new object [] { 'Ó', true, false, false, 'Ó', 0, (Key)'Ó' | Key.ShiftMask, 'O', 24 }; + yield return new object [] { 'ò', false, false, false, 'Ó', 0, (Key)'ò', 'O', 24 }; + yield return new object [] { 'Ò', true, false, false, 'Ò', 0, (Key)'Ò' | Key.ShiftMask, 'O', 24 }; + yield return new object [] { 'ú', false, false, false, 'ú', 0, (Key)'ú', 'U', 22 }; + yield return new object [] { 'Ú', true, false, false, 'Ú', 0, (Key)'Ú' | Key.ShiftMask, 'U', 22 }; + yield return new object [] { 'ù', false, false, false, 'ù', 0, (Key)'ù', 'U', 22 }; + yield return new object [] { 'Ù', true, false, false, 'Ù', 0, (Key)'Ù' | Key.ShiftMask, 'U', 22 }; + yield return new object [] { 'ö', false, false, false, 'ó', 0, (Key)'ö', 'O', 24 }; + yield return new object [] { 'Ö', true, false, false, 'Ó', 0, (Key)'Ö' | Key.ShiftMask, 'O', 24 }; + yield return new object [] { '<', false, false, false, 226, 86, (Key)'<', 226, 86 }; + yield return new object [] { '>', true, false, false, 226, 86, (Key)'>' | Key.ShiftMask, 226, 86 }; + yield return new object [] { '<', true, true, false, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask, 226, 86 }; + yield return new object [] { '<', true, true, true, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 226, 86 }; + yield return new object [] { 'ç', false, false, false, 192, 39, (Key)'ç', 192, 39 }; + yield return new object [] { 'Ç', true, false, false, 192, 39, (Key)'Ç' | Key.ShiftMask, 192, 39 }; + yield return new object [] { 'ç', true, true, false, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask, 192, 39 }; + yield return new object [] { 'ç', true, true, true, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 192, 39 }; + yield return new object [] { '¨', false, true, true, 187, 26, (Key)'¨' | Key.AltMask | Key.CtrlMask, 187, 26 }; + yield return new object [] { (uint)Key.PageUp, false, false, false, 33, 73, Key.PageUp, 33, 73 }; + yield return new object [] { (uint)Key.PageUp, true, false, false, 33, 73, Key.PageUp | Key.ShiftMask, 33, 73 }; + yield return new object [] { (uint)Key.PageUp, true, true, false, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask, 33, 73 }; + yield return new object [] { (uint)Key.PageUp, true, true, true, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 33, 73 }; } IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); 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 { From 651ee21ba53c96f79883823779498b82f3b23543 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 6 Feb 2023 18:24:48 +0000 Subject: [PATCH 12/19] Fixes #2323. The devcontainer.json settings isn't work with the current develop branch. --- .devcontainer/devcontainer.json | 44 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 20 deletions(-) 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) From 057bbcaea85269db8b277a8348fbe19dfbacc60b Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 6 Feb 2023 23:47:09 +0000 Subject: [PATCH 13/19] Fixes #2326. Invisible cursor after modal dialog. --- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 4 ++ Terminal.Gui/Core/Application.cs | 3 ++ Terminal.Gui/Core/Toplevel.cs | 12 +++++ Terminal.Gui/Views/TextView.cs | 20 ++++----- UnitTests/TopLevels/ToplevelTests.cs | 47 +++++++++++++++++--- 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 8d1b71646..0d7722090 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) { diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index b5f6e5984..27c51eee5 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -933,6 +933,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; @@ -1043,6 +1045,7 @@ namespace Terminal.Gui { MdiTop.OnAllChildClosed (); } else { SetCurrentAsTop (); + Current.OnEnter (Current); } Refresh (); } diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index fddabb692..1df0278bb 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -960,6 +960,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/Views/TextView.cs b/Terminal.Gui/Views/TextView.cs index 3c9e54b09..dd609f12c 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) @@ -4447,16 +4457,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. /// 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 From 2b26ec7bfb39bff4fbc4741333e726e8608032f1 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Tue, 7 Feb 2023 16:33:22 +0900 Subject: [PATCH 14/19] merge fixes --- .../CursesDriver/CursesDriver.cs | 155 ++++++++++++++---- .../ConsoleDrivers/FakeDriver/FakeDriver.cs | 93 ++++++++--- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 75 ++++++--- Terminal.Gui/ConsoleDrivers/WindowsDriver.cs | 103 ++++++++---- Terminal.Gui/Core/Application.cs | 45 ++--- Terminal.Gui/Core/ConsoleDriver.cs | 152 ++++++++++++++--- Terminal.Gui/Core/View.cs | 5 +- UICatalog/UICatalog.cs | 2 +- UnitTests/Application/ApplicationTests.cs | 1 - 9 files changed, 479 insertions(+), 152 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 7d2b0b422..c915db6e4 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -62,40 +62,61 @@ namespace Terminal.Gui { Curses.move (crow, ccol); needMove = false; } - if (runeWidth < 2 && ccol > 0 - && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + if (runeWidth == 0 && ccol > 0) { + var r = contents [crow, ccol - 1, 0]; + var s = new string (new char [] { (char)r, (char)rune }); + string sn; + if (!s.IsNormalized ()) { + sn = s.Normalize (); + } else { + sn = s; + } + 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, 2] = 1; - var curAtttib = CurrentAttribute; - Curses.attrset (contents [crow, ccol - 1, 1]); - Curses.mvaddch (crow, ccol - 1, (int)(uint)' '); - contents [crow, ccol - 1, 0] = (int)(uint)' '; - Curses.move (crow, ccol); - Curses.attrset (curAtttib); - - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - - var curAtttib = CurrentAttribute; - Curses.attrset (contents [crow, ccol + 1, 1]); - Curses.mvaddch (crow, ccol + 1, (int)(uint)' '); - contents [crow, ccol + 1, 0] = (int)(uint)' '; - Curses.move (crow, ccol); - Curses.attrset (curAtttib); - - } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - Curses.addch ((int)(uint)' '); - contents [crow, ccol, 0] = (int)(uint)' '; } else { - Curses.addch ((int)(uint)rune); - contents [crow, ccol, 0] = (int)(uint)rune; - } - contents [crow, ccol, 1] = CurrentAttribute; - contents [crow, ccol, 2] = 1; - } else - needMove = true; + if (runeWidth < 2 && ccol > 0 + && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { - ccol++; + var curAtttib = CurrentAttribute; + Curses.attrset (contents [crow, ccol - 1, 1]); + Curses.mvaddch (crow, ccol - 1, (int)(uint)' '); + contents [crow, ccol - 1, 0] = (int)(uint)' '; + Curses.move (crow, ccol); + Curses.attrset (curAtttib); + + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { + + var curAtttib = CurrentAttribute; + Curses.attrset (contents [crow, ccol + 1, 1]); + Curses.mvaddch (crow, ccol + 1, (int)(uint)' '); + contents [crow, ccol + 1, 0] = (int)(uint)' '; + Curses.move (crow, ccol); + Curses.attrset (curAtttib); + + } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + Curses.addch ((int)(uint)' '); + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + Curses.addch ((int)(uint)rune); + contents [crow, ccol, 0] = (int)(uint)rune; + } + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; + } + } else { + needMove = true; + } + + if (runeWidth < 0 || runeWidth > 0) { + ccol++; + } + if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { contents [crow, ccol, 1] = CurrentAttribute; @@ -104,8 +125,9 @@ namespace Terminal.Gui { ccol++; } - if (sync) + if (sync) { UpdateScreen (); + } } public override void AddStr (ustring str) @@ -143,6 +165,19 @@ namespace Terminal.Gui { SetCursorVisibility (CursorVisibility.Default); Curses.endwin (); + + // I'm commenting this because was used in a trying to fix the Linux hanging and forgot to exclude it. + // Clear and reset entire screen. + //Console.Out.Write ("\x1b[2J"); + //Console.Out.Flush (); + + // Set top and bottom lines of a window. + //Console.Out.Write ("\x1b[1;25r"); + //Console.Out.Flush (); + + //Set cursor key to cursor. + //Console.Out.Write ("\x1b[?1l"); + //Console.Out.Flush (); } public override void UpdateScreen () => window.redrawwin (); @@ -155,6 +190,8 @@ namespace Terminal.Gui { public Curses.Window window; + //static short last_color_pair = 16; + /// /// Creates a curses color from the provided foreground and background colors /// @@ -180,6 +217,37 @@ namespace Terminal.Gui { return MakeColor ((short)MapColor (fore), (short)MapColor (back)); } + int [,] colorPairs = new int [16, 16]; + + 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]; + if ((v & 0x10000) == 0) { + b &= 0x7; + bool bold = (f & 0x8) != 0; + f &= 0x7; + + v = MakeColor ((short)f, (short)b) | (bold ? Curses.A_BOLD : 0); + colorPairs [(int)foreground, (int)background] = v | 0x1000; + } + SetAttribute (v & 0xffff); + } + + 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); + rawPairs [key] = v; + } + SetAttribute (v); + } + static Key MapCursesKey (int cursesKey) { switch (cursesKey) { @@ -767,7 +835,7 @@ namespace Terminal.Gui { }; } - Curses.Event reportableMouseEvents; + Curses.Event oldMouseEvents, reportableMouseEvents; public override void Init (Action terminalResized) { if (window != null) @@ -824,7 +892,7 @@ namespace Terminal.Gui { Curses.noecho (); Curses.Window.Standard.keypad (true); - reportableMouseEvents = Curses.mousemask (Curses.Event.AllEvents | Curses.Event.ReportMousePosition, out _); + reportableMouseEvents = Curses.mousemask (Curses.Event.AllEvents | Curses.Event.ReportMousePosition, out oldMouseEvents); TerminalResized = terminalResized; if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition)) StartReportingMouseMoves (); @@ -946,7 +1014,7 @@ namespace Terminal.Gui { case Color.White: return Curses.COLOR_WHITE | Curses.A_BOLD | Curses.COLOR_GRAY; case Color.Invalid: - return Curses.COLOR_BLACK; + return Curses.COLOR_BLACK; } throw new ArgumentException ("Invalid color code"); } @@ -1020,6 +1088,23 @@ namespace Terminal.Gui { Console.Out.Flush (); } + //int lastMouseInterval; + //bool mouseGrabbed; + + public override void UncookMouse () + { + //if (mouseGrabbed) + // return; + //lastMouseInterval = Curses.mouseinterval (0); + //mouseGrabbed = true; + } + + public override void CookMouse () + { + //mouseGrabbed = false; + //Curses.mouseinterval (lastMouseInterval); + } + /// public override bool GetCursorVisibility (out CursorVisibility visibility) { diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index 3adbb7a23..661daaca4 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -33,7 +33,7 @@ namespace Terminal.Gui { UseFakeClipboard = useFakeClipboard; FakeClipboardAlwaysThrowsNotSupportedException = fakeClipboardAlwaysThrowsNotSupportedException; FakeClipboardIsSupportedAlwaysFalse = fakeClipboardIsSupportedAlwaysTrue; - + // double check usage is correct Debug.Assert (useFakeClipboard == false && fakeClipboardAlwaysThrowsNotSupportedException == false); Debug.Assert (useFakeClipboard == false && fakeClipboardIsSupportedAlwaysTrue == false); @@ -131,31 +131,51 @@ namespace Terminal.Gui { //MockConsole.CursorTop = crow; needMove = false; } - if (runeWidth < 2 && ccol > 0 + if (runeWidth == 0 && ccol > 0) { + var r = contents [crow, ccol - 1, 0]; + var s = new string (new char [] { (char)r, (char)rune }); + string sn; + if (!s.IsNormalized ()) { + sn = s.Normalize (); + } else { + sn = s; + } + var c = sn [0]; + contents [crow, ccol - 1, 0] = c; + contents [crow, ccol - 1, 1] = CurrentAttribute; + contents [crow, ccol - 1, 2] = 1; + + } else { + if (runeWidth < 2 && ccol > 0 && Rune.ColumnWidth ((Rune)contents [crow, ccol - 1, 0]) > 1) { - contents [crow, ccol - 1, 0] = (int)(uint)' '; + contents [crow, ccol - 1, 0] = (int)(uint)' '; - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((Rune)contents [crow, ccol, 0]) > 1) { + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((Rune)contents [crow, ccol, 0]) > 1) { - contents [crow, ccol + 1, 0] = (int)(uint)' '; - contents [crow, ccol + 1, 2] = 1; + contents [crow, ccol + 1, 0] = (int)(uint)' '; + contents [crow, ccol + 1, 2] = 1; + } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + contents [crow, ccol, 0] = (int)(uint)rune; + } + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; + + dirtyLine [crow] = true; } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - contents [crow, ccol, 0] = (int)(uint)' '; - } else { - contents [crow, ccol, 0] = (int)(uint)rune; - } - contents [crow, ccol, 1] = CurrentAttribute; - contents [crow, ccol, 2] = 1; - - dirtyLine [crow] = true; - } else + } else { needMove = true; + } + + if (runeWidth < 0 || runeWidth > 0) { + ccol++; + } - ccol++; if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { contents [crow, ccol, 1] = CurrentAttribute; @@ -169,8 +189,9 @@ namespace Terminal.Gui { // if (crow + 1 < Rows) // crow++; //} - if (sync) + if (sync) { UpdateScreen (); + } } public override void AddStr (ustring str) @@ -621,6 +642,7 @@ namespace Terminal.Gui { return hasColor; } + #region Unused public override void UpdateCursor () { if (!EnsureCursorVisibility ()) @@ -636,10 +658,35 @@ namespace Terminal.Gui { } } - #region Unused - public override void StartReportingMouseMoves () {} - public override void StopReportingMouseMoves () {} - public override void Suspend () {} + public override void StartReportingMouseMoves () + { + } + + public override void StopReportingMouseMoves () + { + } + + public override void Suspend () + { + } + + public override void SetColors (ConsoleColor foreground, ConsoleColor background) + { + } + + public override void SetColors (short foregroundColorId, short backgroundColorId) + { + throw new NotImplementedException (); + } + + public override void CookMouse () + { + } + + public override void UncookMouse () + { + } + #endregion public class FakeClipboard : ClipboardBase { diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 485a06f6e..9ae4eb20e 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1241,30 +1241,49 @@ namespace Terminal.Gui { var validClip = IsValidContent (ccol, crow, Clip); if (validClip) { - if (runeWidth < 2 && ccol > 0 - && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + if (runeWidth == 0 && ccol > 0) { + var r = contents [crow, ccol - 1, 0]; + var s = new string (new char [] { (char)r, (char)rune }); + string sn; + if (!s.IsNormalized ()) { + sn = s.Normalize (); + } else { + sn = s; + } + var c = sn [0]; + contents [crow, ccol - 1, 0] = c; + contents [crow, ccol - 1, 1] = CurrentAttribute; + contents [crow, ccol - 1, 2] = 1; - contents [crow, ccol - 1, 0] = (int)(uint)' '; - - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - - contents [crow, ccol + 1, 0] = (int)(uint)' '; - contents [crow, ccol + 1, 2] = 1; - - } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - contents [crow, ccol, 0] = (int)(uint)' '; } else { - contents [crow, ccol, 0] = (int)(uint)rune; - } - contents [crow, ccol, 1] = CurrentAttribute; - contents [crow, ccol, 2] = 1; + if (runeWidth < 2 && ccol > 0 + && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + contents [crow, ccol - 1, 0] = (int)(uint)' '; + + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { + + contents [crow, ccol + 1, 0] = (int)(uint)' '; + contents [crow, ccol + 1, 2] = 1; + + } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + contents [crow, ccol, 0] = (int)(uint)rune; + } + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; + + } dirtyLine [crow] = true; } - ccol++; + if (runeWidth < 0 || runeWidth > 0) { + ccol++; + } + if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { contents [crow, ccol, 1] = CurrentAttribute; @@ -1487,7 +1506,7 @@ namespace Terminal.Gui { outputWidth++; var rune = contents [row, col, 0]; char [] spair; - if (Rune.DecodeSurrogatePair((uint) rune, out spair)) { + if (Rune.DecodeSurrogatePair ((uint)rune, out spair)) { output.Append (spair); } else { output.Append ((char)rune); @@ -1995,6 +2014,24 @@ namespace Terminal.Gui { return hasColor; } + #region Unused + public override void SetColors (ConsoleColor foreground, ConsoleColor background) + { + } + + public override void SetColors (short foregroundColorId, short backgroundColorId) + { + } + + public override void CookMouse () + { + } + + public override void UncookMouse () + { + } + #endregion + // // These are for the .NET driver, but running natively on Windows, wont run // on the Mono emulation diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs index 9b0568a62..8a7502c26 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1517,35 +1517,57 @@ namespace Terminal.Gui { var validClip = IsValidContent (ccol, crow, Clip); if (validClip) { - if (runeWidth < 2 && ccol > 0 - && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { - + if (runeWidth == 0 && ccol > 0) { + var r = contents [crow, ccol - 1, 0]; + var s = new string (new char [] { (char)r, (char)rune }); + string sn; + if (!s.IsNormalized ()) { + sn = s.Normalize (); + } else { + sn = s; + } + var c = sn [0]; var prevPosition = crow * Cols + (ccol - 1); - OutputBuffer [prevPosition].Char.UnicodeChar = ' '; - contents [crow, ccol - 1, 0] = (int)(uint)' '; - - } else if (runeWidth < 2 && ccol <= Clip.Right - 1 - && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - - var prevPosition = GetOutputBufferPosition () + 1; - OutputBuffer [prevPosition].Char.UnicodeChar = (char)' '; - contents [crow, ccol + 1, 0] = (int)(uint)' '; - - } - if (runeWidth > 1 && ccol == Clip.Right - 1) { - OutputBuffer [position].Char.UnicodeChar = (char)' '; - contents [crow, ccol, 0] = (int)(uint)' '; + OutputBuffer [prevPosition].Char.UnicodeChar = c; + contents [crow, ccol - 1, 0] = c; + 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 { - OutputBuffer [position].Char.UnicodeChar = (char)rune; - contents [crow, ccol, 0] = (int)(uint)rune; + if (runeWidth < 2 && ccol > 0 + && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { + + var prevPosition = crow * Cols + (ccol - 1); + OutputBuffer [prevPosition].Char.UnicodeChar = ' '; + contents [crow, ccol - 1, 0] = (int)(uint)' '; + + } else if (runeWidth < 2 && ccol <= Clip.Right - 1 + && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { + + var prevPosition = GetOutputBufferPosition () + 1; + OutputBuffer [prevPosition].Char.UnicodeChar = (char)' '; + contents [crow, ccol + 1, 0] = (int)(uint)' '; + + } + if (runeWidth > 1 && ccol == Clip.Right - 1) { + OutputBuffer [position].Char.UnicodeChar = (char)' '; + contents [crow, ccol, 0] = (int)(uint)' '; + } else { + OutputBuffer [position].Char.UnicodeChar = (char)rune; + contents [crow, ccol, 0] = (int)(uint)rune; + } + OutputBuffer [position].Attributes = (ushort)CurrentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; + contents [crow, ccol, 2] = 1; + WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } - OutputBuffer [position].Attributes = (ushort)CurrentAttribute; - contents [crow, ccol, 1] = CurrentAttribute; - contents [crow, ccol, 2] = 1; - WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } - ccol++; + if (runeWidth < 0 || runeWidth > 0) { + ccol++; + } + if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { position = GetOutputBufferPosition (); @@ -1558,8 +1580,9 @@ namespace Terminal.Gui { ccol++; } - if (sync) + if (sync) { UpdateScreen (); + } } public override void AddStr (ustring str) @@ -1764,9 +1787,33 @@ namespace Terminal.Gui { } #region Unused - public override void StartReportingMouseMoves () { } - public override void StopReportingMouseMoves () { } - public override void Suspend () { } + public override void SetColors (ConsoleColor foreground, ConsoleColor background) + { + } + + public override void SetColors (short foregroundColorId, short backgroundColorId) + { + } + + public override void Suspend () + { + } + + public override void StartReportingMouseMoves () + { + } + + public override void StopReportingMouseMoves () + { + } + + public override void UncookMouse () + { + } + + public override void CookMouse () + { + } #endregion } diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 327c9e2c4..681a4733a 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. @@ -705,6 +712,7 @@ namespace Terminal.Gui { return; OnGrabbedMouse (view); mouseGrabView = view; + Driver.UncookMouse (); } /// @@ -716,6 +724,7 @@ namespace Terminal.Gui { return; OnUnGrabbedMouse (mouseGrabView); mouseGrabView = null; + Driver.CookMouse (); } static void OnGrabbedMouse (View view) @@ -984,9 +993,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 (); @@ -1109,12 +1116,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/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs index e0f52ccc6..49a50695f 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -170,18 +170,9 @@ namespace Terminal.Gui { /// 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. /// 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. - /// - /// - /// s are driver-specific and, as a result, are only valid if initialized by a . - /// If an is created before a driver is initialized will be - /// and attempts to use the will result in an exception. To use an that is not - /// initilzied, after a driver is initialized, recreate the by calling the constructor - /// or . - /// /// public struct Attribute { /// @@ -433,11 +424,11 @@ namespace Terminal.Gui { public bool Equals (ColorScheme other) { return other != null && - EqualityComparer.Default.Equals (_normal, other._normal) && - EqualityComparer.Default.Equals (_focus, other._focus) && - EqualityComparer.Default.Equals (_hotNormal, other._hotNormal) && - EqualityComparer.Default.Equals (_hotFocus, other._hotFocus) && - EqualityComparer.Default.Equals (_disabled, other._disabled); + EqualityComparer.Default.Equals (_normal, other._normal) && + EqualityComparer.Default.Equals (_focus, other._focus) && + EqualityComparer.Default.Equals (_hotNormal, other._hotNormal) && + EqualityComparer.Default.Equals (_hotFocus, other._hotFocus) && + EqualityComparer.Default.Equals (_disabled, other._disabled); } /// @@ -664,6 +655,71 @@ namespace Terminal.Gui { BoxFix = 0x02020164, } + ///// + ///// Special characters that can be drawn with + ///// + //public enum SpecialChar { + // /// + // /// Horizontal line character. + // /// + // HLine, + + // /// + // /// Vertical line character. + // /// + // VLine, + + // /// + // /// Stipple pattern + // /// + // Stipple, + + // /// + // /// Diamond character + // /// + // Diamond, + + // /// + // /// Upper left corner + // /// + // ULCorner, + + // /// + // /// Lower left corner + // /// + // LLCorner, + + // /// + // /// Upper right corner + // /// + // URCorner, + + // /// + // /// Lower right corner + // /// + // LRCorner, + + // /// + // /// Left tee + // /// + // LeftTee, + + // /// + // /// Right tee + // /// + // RightTee, + + // /// + // /// Top tee + // /// + // TopTee, + + // /// + // /// The bottom tee. + // /// + // BottomTee, + //} + /// /// ConsoleDriver is an abstract class that defines the requirements for a console driver. /// There are currently three implementations: (for Unix and Mac), , and that uses the .NET Console API. @@ -824,8 +880,8 @@ namespace Terminal.Gui { /// /// The current attribute the driver is using. /// - internal virtual Attribute CurrentAttribute { - get => _currentAttribute; + public virtual Attribute CurrentAttribute { + get => currentAttribute; set { if (!value.Initialized && value.HasValidColors && Application.Driver != null) { CurrentAttribute = Application.Driver.MakeAttribute (value.Foreground, value.Background); @@ -833,7 +889,7 @@ namespace Terminal.Gui { } if (!value.Initialized) Debug.WriteLine ("ConsoleDriver.CurrentAttribute: Attributes must be initialized before use."); - _currentAttribute = value; + currentAttribute = value; } } @@ -849,6 +905,23 @@ namespace Terminal.Gui { CurrentAttribute = c; } + /// + /// Set Colors from limit sets of colors. Not implemented by any driver: See Issue #2300. + /// + /// Foreground. + /// Background. + public abstract void SetColors (ConsoleColor foreground, ConsoleColor background); + + // Advanced uses - set colors to any pre-set pairs, you would need to init_color + // 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. Not implemented by any driver: See Issue #2300. + /// + /// Foreground color identifier. + /// Background color identifier. + public abstract void SetColors (short foregroundColorId, short backgroundColorId); + /// /// Gets the foreground and background colors based on the value. /// @@ -1165,6 +1238,17 @@ 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. Not implemented by any driver: See Issue #2300. + /// + public abstract void UncookMouse (); + + /// + /// Enables the cooked event processing from the mouse driver. Not implemented by any driver: See Issue #2300. + /// + public abstract void CookMouse (); + /// /// Horizontal line character. /// @@ -1354,8 +1438,7 @@ namespace Terminal.Gui { /// Lower right rounded corner /// public Rune LRRCorner = '\u256f'; - - private Attribute _currentAttribute; + private Attribute currentAttribute; /// /// Make the attribute for the foreground and background colors. @@ -1383,8 +1466,6 @@ namespace Terminal.Gui { /// Ensures all s in are correclty /// initalized by the driver. /// - /// - /// /// Flag indicating if colors are supported (not used). public void InitalizeColorSchemes (bool supportsColors = true) { @@ -1397,6 +1478,35 @@ namespace Terminal.Gui { return; } + Colors.TopLevel.Normal = MakeColor (Color.BrightGreen, Color.Black); + Colors.TopLevel.Focus = MakeColor (Color.White, Color.Cyan); + Colors.TopLevel.HotNormal = MakeColor (Color.Brown, Color.Black); + Colors.TopLevel.HotFocus = MakeColor (Color.Blue, Color.Cyan); + Colors.TopLevel.Disabled = MakeColor (Color.DarkGray, Color.Black); + + Colors.Base.Normal = MakeColor (Color.White, Color.Blue); + Colors.Base.Focus = MakeColor (Color.Black, Color.Gray); + Colors.Base.HotNormal = MakeColor (Color.BrightCyan, Color.Blue); + Colors.Base.HotFocus = MakeColor (Color.BrightBlue, Color.Gray); + Colors.Base.Disabled = MakeColor (Color.DarkGray, Color.Blue); + + Colors.Dialog.Normal = MakeColor (Color.Black, Color.Gray); + Colors.Dialog.Focus = MakeColor (Color.White, Color.DarkGray); + Colors.Dialog.HotNormal = MakeColor (Color.Blue, Color.Gray); + Colors.Dialog.HotFocus = MakeColor (Color.BrightYellow, Color.DarkGray); + Colors.Dialog.Disabled = MakeColor (Color.Gray, Color.DarkGray); + + Colors.Menu.Normal = MakeColor (Color.White, Color.DarkGray); + Colors.Menu.Focus = MakeColor (Color.White, Color.Black); + Colors.Menu.HotNormal = MakeColor (Color.BrightYellow, Color.DarkGray); + Colors.Menu.HotFocus = MakeColor (Color.BrightYellow, Color.Black); + Colors.Menu.Disabled = MakeColor (Color.Gray, Color.DarkGray); + + Colors.Error.Normal = MakeColor (Color.Red, Color.White); + Colors.Error.Focus = MakeColor (Color.Black, Color.BrightRed); + Colors.Error.HotNormal = MakeColor (Color.Black, Color.White); + Colors.Error.HotFocus = MakeColor (Color.White, Color.BrightRed); + Colors.Error.Disabled = MakeColor (Color.DarkGray, Color.White); } } diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 8734261c0..454a64dd1 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -769,7 +769,7 @@ namespace Terminal.Gui { void Initialize (ustring text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed, TextDirection direction = TextDirection.LeftRight_TopBottom, Border border = null) { - TextFormatter = new TextFormatter (); + TextFormatter = new TextFormatter (); TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged; TextDirection = direction; Border = border; @@ -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/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index 14cd47ece..4c8f19eee 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -164,7 +164,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/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); From 44e734ae0421b53400ea06b5e7e4ac6cddef9c3d Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Tue, 7 Feb 2023 16:56:59 +0900 Subject: [PATCH 15/19] fixing merge screwups --- Terminal.Gui/Terminal.Gui.csproj | 10 +- UnitTests/Drivers/ConsoleDriverTests.cs | 227 ++++++++++++------------ 2 files changed, 123 insertions(+), 114 deletions(-) diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index b7ee4c523..e92806346 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -8,12 +8,12 @@ - + - 2.0 - 2.0 - 2.0 - 2.0 + 1.0 + 1.0 + 1.0 + 1.0 diff --git a/UnitTests/Drivers/ConsoleDriverTests.cs b/UnitTests/Drivers/ConsoleDriverTests.cs index cdc8edfc6..f63244c1c 100644 --- a/UnitTests/Drivers/ConsoleDriverTests.cs +++ b/UnitTests/Drivers/ConsoleDriverTests.cs @@ -440,6 +440,8 @@ namespace Terminal.Gui.DriverTests { Assert.Equal (code, actual.Value); } + 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 @@ -485,6 +487,11 @@ namespace Terminal.Gui.DriverTests { if (iterations == 0) Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control); }; + + lock (packetLock) { + Application.Run (); + Application.Shutdown (); + } Application.Run (); Application.Shutdown (); } @@ -492,115 +499,117 @@ namespace Terminal.Gui.DriverTests { public class PacketTest : IEnumerable, IEnumerable { public IEnumerator GetEnumerator () { - yield return new object [] { 'a', false, false, false, 'A', 30, Key.a, 'A', 30 }; - yield return new object [] { 'A', true, false, false, 'A', 30, Key.A | Key.ShiftMask, 'A', 30 }; - yield return new object [] { 'A', true, true, false, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask, 'A', 30 }; - yield return new object [] { 'A', true, true, true, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'A', 30 }; - yield return new object [] { 'z', false, false, false, 'Z', 44, Key.z, 'Z', 44 }; - yield return new object [] { 'Z', true, false, false, 'Z', 44, Key.Z | Key.ShiftMask, 'Z', 44 }; - yield return new object [] { 'Z', true, true, false, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask, 'Z', 44 }; - yield return new object [] { 'Z', true, true, true, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'Z', 44 }; - yield return new object [] { '英', false, false, false, '\0', 0, (Key)'英', '\0', 0 }; - yield return new object [] { '英', true, false, false, '\0', 0, (Key)'英' | Key.ShiftMask, '\0', 0 }; - yield return new object [] { '英', true, true, false, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask, '\0', 0 }; - yield return new object [] { '英', true, true, true, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '\0', 0 }; - yield return new object [] { '+', false, false, false, 187, 26, (Key)'+', 187, 26 }; - yield return new object [] { '*', true, false, false, 187, 26, (Key)'*' | Key.ShiftMask, 187, 26 }; - yield return new object [] { '+', true, true, false, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask, 187, 26 }; - yield return new object [] { '+', true, true, true, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 187, 26 }; - yield return new object [] { '1', false, false, false, '1', 2, Key.D1, '1', 2 }; - yield return new object [] { '!', true, false, false, '1', 2, (Key)'!' | Key.ShiftMask, '1', 2 }; - yield return new object [] { '1', true, true, false, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask, '1', 2 }; - yield return new object [] { '1', true, true, true, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '1', 2 }; - yield return new object [] { '1', false, true, true, '1', 2, Key.D1 | Key.AltMask | Key.CtrlMask, '1', 2 }; - yield return new object [] { '2', false, false, false, '2', 3, Key.D2, '2', 3 }; - yield return new object [] { '"', true, false, false, '2', 3, (Key)'"' | Key.ShiftMask, '2', 3 }; - yield return new object [] { '2', true, true, false, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask, '2', 3 }; - yield return new object [] { '2', true, true, true, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '2', 3 }; - yield return new object [] { '@', false, true, true, '2', 3, (Key)'@' | Key.AltMask | Key.CtrlMask, '2', 3 }; - yield return new object [] { '3', false, false, false, '3', 4, Key.D3, '3', 4 }; - yield return new object [] { '#', true, false, false, '3', 4, (Key)'#' | Key.ShiftMask, '3', 4 }; - yield return new object [] { '3', true, true, false, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask, '3', 4 }; - yield return new object [] { '3', true, true, true, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '3', 4 }; - yield return new object [] { '£', false, true, true, '3', 4, (Key)'£' | Key.AltMask | Key.CtrlMask, '3', 4 }; - yield return new object [] { '4', false, false, false, '4', 5, Key.D4, '4', 5 }; - yield return new object [] { '$', true, false, false, '4', 5, (Key)'$' | Key.ShiftMask, '4', 5 }; - yield return new object [] { '4', true, true, false, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask, '4', 5 }; - yield return new object [] { '4', true, true, true, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '4', 5 }; - yield return new object [] { '§', false, true, true, '4', 5, (Key)'§' | Key.AltMask | Key.CtrlMask, '4', 5 }; - yield return new object [] { '5', false, false, false, '5', 6, Key.D5, '5', 6 }; - yield return new object [] { '%', true, false, false, '5', 6, (Key)'%' | Key.ShiftMask, '5', 6 }; - yield return new object [] { '5', true, true, false, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask, '5', 6 }; - yield return new object [] { '5', true, true, true, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '5', 6 }; - yield return new object [] { '€', false, true, true, '5', 6, (Key)'€' | Key.AltMask | Key.CtrlMask, '5', 6 }; - yield return new object [] { '6', false, false, false, '6', 7, Key.D6, '6', 7 }; - yield return new object [] { '&', true, false, false, '6', 7, (Key)'&' | Key.ShiftMask, '6', 7 }; - yield return new object [] { '6', true, true, false, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask, '6', 7 }; - yield return new object [] { '6', true, true, true, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '6', 7 }; - yield return new object [] { '6', false, true, true, '6', 7, Key.D6 | Key.AltMask | Key.CtrlMask, '6', 7 }; - yield return new object [] { '7', false, false, false, '7', 8, Key.D7, '7', 8 }; - yield return new object [] { '/', true, false, false, '7', 8, (Key)'/' | Key.ShiftMask, '7', 8 }; - yield return new object [] { '7', true, true, false, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask, '7', 8 }; - yield return new object [] { '7', true, true, true, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '7', 8 }; - yield return new object [] { '{', false, true, true, '7', 8, (Key)'{' | Key.AltMask | Key.CtrlMask, '7', 8 }; - yield return new object [] { '8', false, false, false, '8', 9, Key.D8, '8', 9 }; - yield return new object [] { '(', true, false, false, '8', 9, (Key)'(' | Key.ShiftMask, '8', 9 }; - yield return new object [] { '8', true, true, false, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask, '8', 9 }; - yield return new object [] { '8', true, true, true, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '8', 9 }; - yield return new object [] { '[', false, true, true, '8', 9, (Key)'[' | Key.AltMask | Key.CtrlMask, '8', 9 }; - yield return new object [] { '9', false, false, false, '9', 10, Key.D9, '9', 10 }; - yield return new object [] { ')', true, false, false, '9', 10, (Key)')' | Key.ShiftMask, '9', 10 }; - yield return new object [] { '9', true, true, false, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask, '9', 10 }; - yield return new object [] { '9', true, true, true, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '9', 10 }; - yield return new object [] { ']', false, true, true, '9', 10, (Key)']' | Key.AltMask | Key.CtrlMask, '9', 10 }; - yield return new object [] { '0', false, false, false, '0', 11, Key.D0, '0', 11 }; - yield return new object [] { '=', true, false, false, '0', 11, (Key)'=' | Key.ShiftMask, '0', 11 }; - yield return new object [] { '0', true, true, false, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask, '0', 11 }; - yield return new object [] { '0', true, true, true, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '0', 11 }; - yield return new object [] { '}', false, true, true, '0', 11, (Key)'}' | Key.AltMask | Key.CtrlMask, '0', 11 }; - yield return new object [] { '\'', false, false, false, 219, 12, (Key)'\'', 219, 12 }; - yield return new object [] { '?', true, false, false, 219, 12, (Key)'?' | Key.ShiftMask, 219, 12 }; - yield return new object [] { '\'', true, true, false, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask, 219, 12 }; - yield return new object [] { '\'', true, true, true, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 219, 12 }; - yield return new object [] { '«', false, false, false, 221, 13, (Key)'«', 221, 13 }; - yield return new object [] { '»', true, false, false, 221, 13, (Key)'»' | Key.ShiftMask, 221, 13 }; - yield return new object [] { '«', true, true, false, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask, 221, 13 }; - yield return new object [] { '«', true, true, true, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 221, 13 }; - yield return new object [] { 'á', false, false, false, 'á', 0, (Key)'á', 'A', 30 }; - yield return new object [] { 'Á', true, false, false, 'Á', 0, (Key)'Á' | Key.ShiftMask, 'A', 30 }; - yield return new object [] { 'à', false, false, false, 'à', 0, (Key)'à', 'A', 30 }; - yield return new object [] { 'À', true, false, false, 'À', 0, (Key)'À' | Key.ShiftMask, 'A', 30 }; - yield return new object [] { 'é', false, false, false, 'é', 0, (Key)'é', 'E', 18 }; - yield return new object [] { 'É', true, false, false, 'É', 0, (Key)'É' | Key.ShiftMask, 'E', 18 }; - yield return new object [] { 'è', false, false, false, 'è', 0, (Key)'è', 'E', 18 }; - yield return new object [] { 'È', true, false, false, 'È', 0, (Key)'È' | Key.ShiftMask, 'E', 18 }; - yield return new object [] { 'í', false, false, false, 'í', 0, (Key)'í', 'I', 23 }; - yield return new object [] { 'Í', true, false, false, 'Í', 0, (Key)'Í' | Key.ShiftMask, 'I', 23 }; - yield return new object [] { 'ì', false, false, false, 'ì', 0, (Key)'ì', 'I', 23 }; - yield return new object [] { 'Ì', true, false, false, 'Ì', 0, (Key)'Ì' | Key.ShiftMask, 'I', 23 }; - yield return new object [] { 'ó', false, false, false, 'ó', 0, (Key)'ó', 'O', 24 }; - yield return new object [] { 'Ó', true, false, false, 'Ó', 0, (Key)'Ó' | Key.ShiftMask, 'O', 24 }; - yield return new object [] { 'ò', false, false, false, 'Ó', 0, (Key)'ò', 'O', 24 }; - yield return new object [] { 'Ò', true, false, false, 'Ò', 0, (Key)'Ò' | Key.ShiftMask, 'O', 24 }; - yield return new object [] { 'ú', false, false, false, 'ú', 0, (Key)'ú', 'U', 22 }; - yield return new object [] { 'Ú', true, false, false, 'Ú', 0, (Key)'Ú' | Key.ShiftMask, 'U', 22 }; - yield return new object [] { 'ù', false, false, false, 'ù', 0, (Key)'ù', 'U', 22 }; - yield return new object [] { 'Ù', true, false, false, 'Ù', 0, (Key)'Ù' | Key.ShiftMask, 'U', 22 }; - yield return new object [] { 'ö', false, false, false, 'ó', 0, (Key)'ö', 'O', 24 }; - yield return new object [] { 'Ö', true, false, false, 'Ó', 0, (Key)'Ö' | Key.ShiftMask, 'O', 24 }; - yield return new object [] { '<', false, false, false, 226, 86, (Key)'<', 226, 86 }; - yield return new object [] { '>', true, false, false, 226, 86, (Key)'>' | Key.ShiftMask, 226, 86 }; - yield return new object [] { '<', true, true, false, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask, 226, 86 }; - yield return new object [] { '<', true, true, true, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 226, 86 }; - yield return new object [] { 'ç', false, false, false, 192, 39, (Key)'ç', 192, 39 }; - yield return new object [] { 'Ç', true, false, false, 192, 39, (Key)'Ç' | Key.ShiftMask, 192, 39 }; - yield return new object [] { 'ç', true, true, false, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask, 192, 39 }; - yield return new object [] { 'ç', true, true, true, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 192, 39 }; - yield return new object [] { '¨', false, true, true, 187, 26, (Key)'¨' | Key.AltMask | Key.CtrlMask, 187, 26 }; - yield return new object [] { (uint)Key.PageUp, false, false, false, 33, 73, Key.PageUp, 33, 73 }; - yield return new object [] { (uint)Key.PageUp, true, false, false, 33, 73, Key.PageUp | Key.ShiftMask, 33, 73 }; - yield return new object [] { (uint)Key.PageUp, true, true, false, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask, 33, 73 }; - yield return new object [] { (uint)Key.PageUp, true, true, true, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 33, 73 }; + lock (packetLock) { + yield return new object [] { 'a', false, false, false, 'A', 30, Key.a, 'A', 30 }; + yield return new object [] { 'A', true, false, false, 'A', 30, Key.A | Key.ShiftMask, 'A', 30 }; + yield return new object [] { 'A', true, true, false, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask, 'A', 30 }; + yield return new object [] { 'A', true, true, true, 'A', 30, Key.A | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'A', 30 }; + yield return new object [] { 'z', false, false, false, 'Z', 44, Key.z, 'Z', 44 }; + yield return new object [] { 'Z', true, false, false, 'Z', 44, Key.Z | Key.ShiftMask, 'Z', 44 }; + yield return new object [] { 'Z', true, true, false, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask, 'Z', 44 }; + yield return new object [] { 'Z', true, true, true, 'Z', 44, Key.Z | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 'Z', 44 }; + yield return new object [] { '英', false, false, false, '\0', 0, (Key)'英', '\0', 0 }; + yield return new object [] { '英', true, false, false, '\0', 0, (Key)'英' | Key.ShiftMask, '\0', 0 }; + yield return new object [] { '英', true, true, false, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask, '\0', 0 }; + yield return new object [] { '英', true, true, true, '\0', 0, (Key)'英' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '\0', 0 }; + yield return new object [] { '+', false, false, false, 187, 26, (Key)'+', 187, 26 }; + yield return new object [] { '*', true, false, false, 187, 26, (Key)'*' | Key.ShiftMask, 187, 26 }; + yield return new object [] { '+', true, true, false, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask, 187, 26 }; + yield return new object [] { '+', true, true, true, 187, 26, (Key)'+' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 187, 26 }; + yield return new object [] { '1', false, false, false, '1', 2, Key.D1, '1', 2 }; + yield return new object [] { '!', true, false, false, '1', 2, (Key)'!' | Key.ShiftMask, '1', 2 }; + yield return new object [] { '1', true, true, false, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask, '1', 2 }; + yield return new object [] { '1', true, true, true, '1', 2, Key.D1 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '1', 2 }; + yield return new object [] { '1', false, true, true, '1', 2, Key.D1 | Key.AltMask | Key.CtrlMask, '1', 2 }; + yield return new object [] { '2', false, false, false, '2', 3, Key.D2, '2', 3 }; + yield return new object [] { '"', true, false, false, '2', 3, (Key)'"' | Key.ShiftMask, '2', 3 }; + yield return new object [] { '2', true, true, false, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask, '2', 3 }; + yield return new object [] { '2', true, true, true, '2', 3, Key.D2 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '2', 3 }; + yield return new object [] { '@', false, true, true, '2', 3, (Key)'@' | Key.AltMask | Key.CtrlMask, '2', 3 }; + yield return new object [] { '3', false, false, false, '3', 4, Key.D3, '3', 4 }; + yield return new object [] { '#', true, false, false, '3', 4, (Key)'#' | Key.ShiftMask, '3', 4 }; + yield return new object [] { '3', true, true, false, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask, '3', 4 }; + yield return new object [] { '3', true, true, true, '3', 4, Key.D3 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '3', 4 }; + yield return new object [] { '£', false, true, true, '3', 4, (Key)'£' | Key.AltMask | Key.CtrlMask, '3', 4 }; + yield return new object [] { '4', false, false, false, '4', 5, Key.D4, '4', 5 }; + yield return new object [] { '$', true, false, false, '4', 5, (Key)'$' | Key.ShiftMask, '4', 5 }; + yield return new object [] { '4', true, true, false, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask, '4', 5 }; + yield return new object [] { '4', true, true, true, '4', 5, Key.D4 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '4', 5 }; + yield return new object [] { '§', false, true, true, '4', 5, (Key)'§' | Key.AltMask | Key.CtrlMask, '4', 5 }; + yield return new object [] { '5', false, false, false, '5', 6, Key.D5, '5', 6 }; + yield return new object [] { '%', true, false, false, '5', 6, (Key)'%' | Key.ShiftMask, '5', 6 }; + yield return new object [] { '5', true, true, false, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask, '5', 6 }; + yield return new object [] { '5', true, true, true, '5', 6, Key.D5 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '5', 6 }; + yield return new object [] { '€', false, true, true, '5', 6, (Key)'€' | Key.AltMask | Key.CtrlMask, '5', 6 }; + yield return new object [] { '6', false, false, false, '6', 7, Key.D6, '6', 7 }; + yield return new object [] { '&', true, false, false, '6', 7, (Key)'&' | Key.ShiftMask, '6', 7 }; + yield return new object [] { '6', true, true, false, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask, '6', 7 }; + yield return new object [] { '6', true, true, true, '6', 7, Key.D6 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '6', 7 }; + yield return new object [] { '6', false, true, true, '6', 7, Key.D6 | Key.AltMask | Key.CtrlMask, '6', 7 }; + yield return new object [] { '7', false, false, false, '7', 8, Key.D7, '7', 8 }; + yield return new object [] { '/', true, false, false, '7', 8, (Key)'/' | Key.ShiftMask, '7', 8 }; + yield return new object [] { '7', true, true, false, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask, '7', 8 }; + yield return new object [] { '7', true, true, true, '7', 8, Key.D7 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '7', 8 }; + yield return new object [] { '{', false, true, true, '7', 8, (Key)'{' | Key.AltMask | Key.CtrlMask, '7', 8 }; + yield return new object [] { '8', false, false, false, '8', 9, Key.D8, '8', 9 }; + yield return new object [] { '(', true, false, false, '8', 9, (Key)'(' | Key.ShiftMask, '8', 9 }; + yield return new object [] { '8', true, true, false, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask, '8', 9 }; + yield return new object [] { '8', true, true, true, '8', 9, Key.D8 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '8', 9 }; + yield return new object [] { '[', false, true, true, '8', 9, (Key)'[' | Key.AltMask | Key.CtrlMask, '8', 9 }; + yield return new object [] { '9', false, false, false, '9', 10, Key.D9, '9', 10 }; + yield return new object [] { ')', true, false, false, '9', 10, (Key)')' | Key.ShiftMask, '9', 10 }; + yield return new object [] { '9', true, true, false, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask, '9', 10 }; + yield return new object [] { '9', true, true, true, '9', 10, Key.D9 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '9', 10 }; + yield return new object [] { ']', false, true, true, '9', 10, (Key)']' | Key.AltMask | Key.CtrlMask, '9', 10 }; + yield return new object [] { '0', false, false, false, '0', 11, Key.D0, '0', 11 }; + yield return new object [] { '=', true, false, false, '0', 11, (Key)'=' | Key.ShiftMask, '0', 11 }; + yield return new object [] { '0', true, true, false, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask, '0', 11 }; + yield return new object [] { '0', true, true, true, '0', 11, Key.D0 | Key.ShiftMask | Key.AltMask | Key.CtrlMask, '0', 11 }; + yield return new object [] { '}', false, true, true, '0', 11, (Key)'}' | Key.AltMask | Key.CtrlMask, '0', 11 }; + yield return new object [] { '\'', false, false, false, 219, 12, (Key)'\'', 219, 12 }; + yield return new object [] { '?', true, false, false, 219, 12, (Key)'?' | Key.ShiftMask, 219, 12 }; + yield return new object [] { '\'', true, true, false, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask, 219, 12 }; + yield return new object [] { '\'', true, true, true, 219, 12, (Key)'\'' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 219, 12 }; + yield return new object [] { '«', false, false, false, 221, 13, (Key)'«', 221, 13 }; + yield return new object [] { '»', true, false, false, 221, 13, (Key)'»' | Key.ShiftMask, 221, 13 }; + yield return new object [] { '«', true, true, false, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask, 221, 13 }; + yield return new object [] { '«', true, true, true, 221, 13, (Key)'«' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 221, 13 }; + yield return new object [] { 'á', false, false, false, 'á', 0, (Key)'á', 'A', 30 }; + yield return new object [] { 'Á', true, false, false, 'Á', 0, (Key)'Á' | Key.ShiftMask, 'A', 30 }; + yield return new object [] { 'à', false, false, false, 'à', 0, (Key)'à', 'A', 30 }; + yield return new object [] { 'À', true, false, false, 'À', 0, (Key)'À' | Key.ShiftMask, 'A', 30 }; + yield return new object [] { 'é', false, false, false, 'é', 0, (Key)'é', 'E', 18 }; + yield return new object [] { 'É', true, false, false, 'É', 0, (Key)'É' | Key.ShiftMask, 'E', 18 }; + yield return new object [] { 'è', false, false, false, 'è', 0, (Key)'è', 'E', 18 }; + yield return new object [] { 'È', true, false, false, 'È', 0, (Key)'È' | Key.ShiftMask, 'E', 18 }; + yield return new object [] { 'í', false, false, false, 'í', 0, (Key)'í', 'I', 23 }; + yield return new object [] { 'Í', true, false, false, 'Í', 0, (Key)'Í' | Key.ShiftMask, 'I', 23 }; + yield return new object [] { 'ì', false, false, false, 'ì', 0, (Key)'ì', 'I', 23 }; + yield return new object [] { 'Ì', true, false, false, 'Ì', 0, (Key)'Ì' | Key.ShiftMask, 'I', 23 }; + yield return new object [] { 'ó', false, false, false, 'ó', 0, (Key)'ó', 'O', 24 }; + yield return new object [] { 'Ó', true, false, false, 'Ó', 0, (Key)'Ó' | Key.ShiftMask, 'O', 24 }; + yield return new object [] { 'ò', false, false, false, 'Ó', 0, (Key)'ò', 'O', 24 }; + yield return new object [] { 'Ò', true, false, false, 'Ò', 0, (Key)'Ò' | Key.ShiftMask, 'O', 24 }; + yield return new object [] { 'ú', false, false, false, 'ú', 0, (Key)'ú', 'U', 22 }; + yield return new object [] { 'Ú', true, false, false, 'Ú', 0, (Key)'Ú' | Key.ShiftMask, 'U', 22 }; + yield return new object [] { 'ù', false, false, false, 'ù', 0, (Key)'ù', 'U', 22 }; + yield return new object [] { 'Ù', true, false, false, 'Ù', 0, (Key)'Ù' | Key.ShiftMask, 'U', 22 }; + yield return new object [] { 'ö', false, false, false, 'ó', 0, (Key)'ö', 'O', 24 }; + yield return new object [] { 'Ö', true, false, false, 'Ó', 0, (Key)'Ö' | Key.ShiftMask, 'O', 24 }; + yield return new object [] { '<', false, false, false, 226, 86, (Key)'<', 226, 86 }; + yield return new object [] { '>', true, false, false, 226, 86, (Key)'>' | Key.ShiftMask, 226, 86 }; + yield return new object [] { '<', true, true, false, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask, 226, 86 }; + yield return new object [] { '<', true, true, true, 226, 86, (Key)'<' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 226, 86 }; + yield return new object [] { 'ç', false, false, false, 192, 39, (Key)'ç', 192, 39 }; + yield return new object [] { 'Ç', true, false, false, 192, 39, (Key)'Ç' | Key.ShiftMask, 192, 39 }; + yield return new object [] { 'ç', true, true, false, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask, 192, 39 }; + yield return new object [] { 'ç', true, true, true, 192, 39, (Key)'ç' | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 192, 39 }; + yield return new object [] { '¨', false, true, true, 187, 26, (Key)'¨' | Key.AltMask | Key.CtrlMask, 187, 26 }; + yield return new object [] { (uint)Key.PageUp, false, false, false, 33, 73, Key.PageUp, 33, 73 }; + yield return new object [] { (uint)Key.PageUp, true, false, false, 33, 73, Key.PageUp | Key.ShiftMask, 33, 73 }; + yield return new object [] { (uint)Key.PageUp, true, true, false, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask, 33, 73 }; + yield return new object [] { (uint)Key.PageUp, true, true, true, 33, 73, Key.PageUp | Key.ShiftMask | Key.AltMask | Key.CtrlMask, 33, 73 }; + } } IEnumerator IEnumerable.GetEnumerator () => GetEnumerator (); From d6e308966bbec95d81bb054530068bd0c6f4f1c7 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Tue, 7 Feb 2023 17:03:10 +0900 Subject: [PATCH 16/19] fixing merge screwups --- Example/Example.csproj | 8 ++++---- ReactiveExample/ReactiveExample.csproj | 8 ++++---- Terminal.Gui/Core/View.cs | 2 +- UICatalog/UICatalog.csproj | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Example/Example.csproj b/Example/Example.csproj index aebe02889..7922c0635 100644 --- a/Example/Example.csproj +++ b/Example/Example.csproj @@ -5,10 +5,10 @@ - 2.0 - 2.0 - 2.0 - 2.0 + 1.0 + 1.0 + 1.0 + 1.0 diff --git a/ReactiveExample/ReactiveExample.csproj b/ReactiveExample/ReactiveExample.csproj index b0dbfe464..c2ce6640c 100644 --- a/ReactiveExample/ReactiveExample.csproj +++ b/ReactiveExample/ReactiveExample.csproj @@ -5,10 +5,10 @@ - 2.0 - 2.0 - 2.0 - 2.0 + 1.0 + 1.0 + 1.0 + 1.0 diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 454a64dd1..36ce60d5e 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -769,7 +769,7 @@ namespace Terminal.Gui { void Initialize (ustring text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed, TextDirection direction = TextDirection.LeftRight_TopBottom, Border border = null) { - TextFormatter = new TextFormatter (); + TextFormatter = new TextFormatter (); TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged; TextDirection = direction; Border = border; diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj index 74ed065a3..6320c1e99 100644 --- a/UICatalog/UICatalog.csproj +++ b/UICatalog/UICatalog.csproj @@ -7,10 +7,10 @@ - 2.0 - 2.0 - 2.0 - 2.0 + 1.0 + 1.0 + 1.0 + 1.0 TRACE From e325052feb35aa3341ab0e67df37881316b52ba8 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Tue, 7 Feb 2023 17:04:52 +0900 Subject: [PATCH 17/19] fixing merge screwups --- Example/Example.csproj | 2 +- README.md | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Example/Example.csproj b/Example/Example.csproj index 7922c0635..2ebf163bc 100644 --- a/Example/Example.csproj +++ b/Example/Example.csproj @@ -3,7 +3,7 @@ Exe net6.0 - + 1.0 1.0 diff --git a/README.md b/README.md index 3b7633dd2..d62088a11 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,6 @@ [![License](https://img.shields.io/github/license/gui-cs/gui.cs.svg)](LICENSE) ![Bugs](https://img.shields.io/github/issues/gui-cs/gui.cs/bug) -# This is the v2.0 Branch - Under Development - -See the v2 Discussion here: https://github.com/gui-cs/Terminal.Gui/discussions/1940 - # Terminal.Gui - Cross Platform Terminal UI toolkit for .NET A toolkit for building rich console apps for .NET, .NET Core, and Mono that works on Windows, the Mac, and Linux/Unix. From ea663ae1130939e62e72624448c9a37de2110ad7 Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Tue, 7 Feb 2023 17:06:30 +0900 Subject: [PATCH 18/19] fixing more merge screwups --- UnitTests/Drivers/ConsoleDriverTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/UnitTests/Drivers/ConsoleDriverTests.cs b/UnitTests/Drivers/ConsoleDriverTests.cs index f63244c1c..8289e9737 100644 --- a/UnitTests/Drivers/ConsoleDriverTests.cs +++ b/UnitTests/Drivers/ConsoleDriverTests.cs @@ -492,8 +492,6 @@ namespace Terminal.Gui.DriverTests { Application.Run (); Application.Shutdown (); } - Application.Run (); - Application.Shutdown (); } public class PacketTest : IEnumerable, IEnumerable { From 5da7665e921691405b305d367a22f9d5b678c75e Mon Sep 17 00:00:00 2001 From: BDisp Date: Wed, 8 Feb 2023 00:12:52 +0000 Subject: [PATCH 19/19] Fixes #2328. TextView Autocomplete triggered by cursor move. --- .../Core/Autocomplete/Autocomplete.cs | 67 ++++++++++----- .../Core/Autocomplete/IAutocomplete.cs | 3 +- Terminal.Gui/Views/TextField.cs | 6 +- Terminal.Gui/Views/TextView.cs | 18 ++-- UnitTests/Views/AutocompleteTests.cs | 86 +++++++++++++++++++ 5 files changed, 149 insertions(+), 31 deletions(-) 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/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 dd609f12c..7cb797b11 100644 --- a/Terminal.Gui/Views/TextView.cs +++ b/Terminal.Gui/Views/TextView.cs @@ -2447,6 +2447,10 @@ namespace Terminal.Gui { PositionCursor (); + if (clickWithSelecting) { + clickWithSelecting = false; + return; + } if (SelectedLength > 0) return; @@ -2677,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) { @@ -4279,6 +4285,7 @@ namespace Terminal.Gui { } bool isButtonShift; + bool clickWithSelecting; /// public override bool MouseEvent (MouseEvent ev) @@ -4372,6 +4379,7 @@ namespace Terminal.Gui { columnTrack = currentColumn; } else if (ev.Flags.HasFlag (MouseFlags.Button1Pressed)) { if (shiftSelecting) { + clickWithSelecting = true; StopSelecting (); } ProcessMouseClick (ev, out _); @@ -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/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