diff --git a/ReactiveExample/ReactiveExample.csproj b/ReactiveExample/ReactiveExample.csproj index 0c174f748b..c2ce6640cc 100644 --- a/ReactiveExample/ReactiveExample.csproj +++ b/ReactiveExample/ReactiveExample.csproj @@ -3,7 +3,7 @@ Exe net6.0 - + 1.0 1.0 diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 4a8858abf0..c915db6e44 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -74,14 +74,14 @@ public override void AddRune (Rune rune) var c = sn [0]; Curses.mvaddch (crow, ccol - 1, (int)(uint)c); contents [crow, ccol - 1, 0] = c; - contents [crow, ccol - 1, 1] = currentAttribute; + contents [crow, ccol - 1, 1] = CurrentAttribute; contents [crow, ccol - 1, 2] = 1; } else { if (runeWidth < 2 && ccol > 0 && Rune.ColumnWidth ((char)contents [crow, ccol - 1, 0]) > 1) { - var curAtttib = currentAttribute; + var curAtttib = CurrentAttribute; Curses.attrset (contents [crow, ccol - 1, 1]); Curses.mvaddch (crow, ccol - 1, (int)(uint)' '); contents [crow, ccol - 1, 0] = (int)(uint)' '; @@ -91,7 +91,7 @@ public override void AddRune (Rune rune) } else if (runeWidth < 2 && ccol <= Clip.Right - 1 && Rune.ColumnWidth ((char)contents [crow, ccol, 0]) > 1) { - var curAtttib = currentAttribute; + var curAtttib = CurrentAttribute; Curses.attrset (contents [crow, ccol + 1, 1]); Curses.mvaddch (crow, ccol + 1, (int)(uint)' '); contents [crow, ccol + 1, 0] = (int)(uint)' '; @@ -106,25 +106,28 @@ public override void AddRune (Rune rune) Curses.addch ((int)(uint)rune); contents [crow, ccol, 0] = (int)(uint)rune; } - contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 1; } - } else + } else { needMove = true; + } if (runeWidth < 0 || runeWidth > 0) { ccol++; } + if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { - contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 0; } ccol++; } - if (sync) + if (sync) { UpdateScreen (); + } } public override void AddStr (ustring str) @@ -179,13 +182,10 @@ public override void End () public override void UpdateScreen () => window.redrawwin (); - Attribute currentAttribute = new Attribute (Color.White, Color.Black); - public override void SetAttribute (Attribute c) { base.SetAttribute (c); - currentAttribute = c; - Curses.attrset (currentAttribute); + Curses.attrset (CurrentAttribute); } public Curses.Window window; @@ -897,34 +897,18 @@ public override void Init (Action terminalResized) 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; @@ -951,6 +935,10 @@ public override void Init (Action terminalResized) Colors.Error.HotFocus = Curses.A_REVERSE; Colors.Error.Disabled = Curses.A_BOLD | Curses.COLOR_GRAY; } + + ResizeScreen (); + UpdateOffScreen (); + } public override void ResizeScreen () @@ -1025,6 +1013,8 @@ static int MapColor (Color color) 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"); } @@ -1115,11 +1105,6 @@ public override void CookMouse () //Curses.mouseinterval (lastMouseInterval); } - public override Attribute GetAttribute () - { - return currentAttribute; - } - /// public override bool GetCursorVisibility (out CursorVisibility visibility) { diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs index e9ae11a425..661daaca47 100644 --- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs @@ -142,7 +142,7 @@ public override void AddRune (Rune rune) } var c = sn [0]; contents [crow, ccol - 1, 0] = c; - contents [crow, ccol - 1, 1] = currentAttribute; + contents [crow, ccol - 1, 1] = CurrentAttribute; contents [crow, ccol - 1, 2] = 1; } else { @@ -163,20 +163,22 @@ public override void AddRune (Rune rune) } else { contents [crow, ccol, 0] = (int)(uint)rune; } - contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 1; dirtyLine [crow] = true; } - } else + } else { needMove = true; + } if (runeWidth < 0 || runeWidth > 0) { ccol++; } + if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { - contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 0; } ccol++; @@ -187,8 +189,9 @@ public override void AddRune (Rune rune) // if (crow + 1 < Rows) // crow++; //} - if (sync) + if (sync) { UpdateScreen (); + } } public override void AddStr (ustring str) @@ -226,8 +229,9 @@ public override void Init (Action terminalResized) rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT; FakeConsole.Clear (); ResizeScreen (); - // Call CreateColors before UpdateOffScreen as it references Colors - CreateColors (); + // Call InitalizeColorSchemes before UpdateOffScreen as it references Colors + CurrentAttribute = MakeColor (Color.White, Color.Black); + InitalizeColorSchemes (); UpdateOffScreen (); } @@ -299,11 +303,9 @@ public override void Refresh () UpdateCursor (); } - Attribute currentAttribute = new Attribute (Color.White, Color.Black); public override void SetAttribute (Attribute c) { base.SetAttribute (c); - currentAttribute = c; } public ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo) @@ -492,11 +494,6 @@ void ProcessInput (ConsoleKeyInfo consoleKey) 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 5f3e560ec6..9ae4eb20e5 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1252,7 +1252,7 @@ public override void AddRune (Rune rune) } var c = sn [0]; contents [crow, ccol - 1, 0] = c; - contents [crow, ccol - 1, 1] = currentAttribute; + contents [crow, ccol - 1, 1] = CurrentAttribute; contents [crow, ccol - 1, 2] = 1; } else { @@ -1273,7 +1273,7 @@ public override void AddRune (Rune rune) } else { contents [crow, ccol, 0] = (int)(uint)rune; } - contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 1; } @@ -1283,9 +1283,10 @@ public override void AddRune (Rune rune) if (runeWidth < 0 || runeWidth > 0) { ccol++; } + if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { - contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 0; } ccol++; @@ -1358,12 +1359,14 @@ public override void Init (Action terminalResized) cols = Console.WindowWidth; rows = Console.WindowHeight; + CurrentAttribute = MakeColor (Color.White, Color.Black); + InitalizeColorSchemes (); + ResizeScreen (); UpdateOffScreen (); StartReportingMouseMoves (); - CreateColors (); Clear (); } @@ -1631,12 +1634,10 @@ public override void Suspend () { } - Attribute currentAttribute = new Attribute (Color.White, Color.Black); public override void SetAttribute (Attribute c) { base.SetAttribute (c); - currentAttribute = c; } public ConsoleKeyInfo FromVKPacketToKConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo) @@ -1954,11 +1955,6 @@ MouseEvent ToDriverMouse (NetEvents.MouseEvent me) }; } - 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 e03ff1b9ce..8a7502c265 100644 --- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs @@ -1455,13 +1455,13 @@ public override void Init (Action terminalResized) var winSize = WinConsole.GetConsoleOutputWindow (out Point pos); cols = winSize.Width; rows = winSize.Height; - WindowsConsole.SmallRect.MakeEmpty (ref damageRegion); + CurrentAttribute = MakeColor (Color.White, Color.Black); + InitalizeColorSchemes (); + ResizeScreen (); UpdateOffScreen (); - - CreateColors (); } catch (Win32Exception e) { throw new InvalidOperationException ("The Windows Console output window is not available.", e); } @@ -1530,8 +1530,8 @@ public override void AddRune (Rune rune) var prevPosition = crow * Cols + (ccol - 1); OutputBuffer [prevPosition].Char.UnicodeChar = c; contents [crow, ccol - 1, 0] = c; - OutputBuffer [prevPosition].Attributes = (ushort)currentAttribute; - contents [crow, ccol - 1, 1] = currentAttribute; + OutputBuffer [prevPosition].Attributes = (ushort)CurrentAttribute; + contents [crow, ccol - 1, 1] = CurrentAttribute; contents [crow, ccol - 1, 2] = 1; WindowsConsole.SmallRect.Update (ref damageRegion, (short)(ccol - 1), (short)crow); } else { @@ -1557,8 +1557,8 @@ public override void AddRune (Rune rune) OutputBuffer [position].Char.UnicodeChar = (char)rune; contents [crow, ccol, 0] = (int)(uint)rune; } - OutputBuffer [position].Attributes = (ushort)currentAttribute; - contents [crow, ccol, 1] = currentAttribute; + OutputBuffer [position].Attributes = (ushort)CurrentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 1; WindowsConsole.SmallRect.Update (ref damageRegion, (short)ccol, (short)crow); } @@ -1567,20 +1567,22 @@ public override void AddRune (Rune rune) if (runeWidth < 0 || runeWidth > 0) { ccol++; } + if (runeWidth > 1) { if (validClip && ccol < Clip.Right) { position = GetOutputBufferPosition (); - OutputBuffer [position].Attributes = (ushort)currentAttribute; + OutputBuffer [position].Attributes = (ushort)CurrentAttribute; OutputBuffer [position].Char.UnicodeChar = (char)0x00; contents [crow, ccol, 0] = (int)(uint)0x00; - contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 1] = CurrentAttribute; contents [crow, ccol, 2] = 0; } ccol++; } - if (sync) + if (sync) { UpdateScreen (); + } } public override void AddStr (ustring str) @@ -1589,12 +1591,9 @@ public override void AddStr (ustring str) AddRune (rune); } - Attribute currentAttribute = new Attribute (Color.White, Color.Black); - public override void SetAttribute (Attribute c) { base.SetAttribute (c); - currentAttribute = c; } public override Attribute MakeColor (Color foreground, Color background) @@ -1696,11 +1695,6 @@ public override void End () WinConsole = null; } - public override Attribute GetAttribute () - { - return currentAttribute; - } - /// public override bool GetCursorVisibility (out CursorVisibility visibility) { diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index b5f6e5984d..681a4733af 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 @@ public static Toplevel MdiTop { /// 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 @@ public static Key AlternateForwardKey { static void OnAlternateForwardKeyChanged (Key oldKey) { - foreach (var top in toplevels) { + foreach (var top in toplevels.ToArray()) { top.OnAlternateForwardKeyChanged (oldKey); } } @@ -155,7 +160,7 @@ static void OnAlternateForwardKeyChanged (Key oldKey) 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 @@ public static Key AlternateBackwardKey { static void OnAlternateBackwardKeyChanged (Key oldKey) { - foreach (var top in toplevels) { + foreach (var top in toplevels.ToArray()) { top.OnAlternateBackwardKeyChanged (oldKey); } } @@ -200,7 +205,8 @@ public static Key QuitKey { 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 @@ static void OnQuitKeyChanged (Key oldKey) 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 @@ public static Rect MakeCenteredRect (Size size) // users use async/await on their code // class MainLoopSyncContext : SynchronizationContext { - MainLoop mainLoop; + readonly MainLoop mainLoop; public MainLoopSyncContext (MainLoop mainLoop) { @@ -305,9 +311,9 @@ public override void Send (SendOrPostCallback d, object state) } /// - /// 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 @@ internal static void InternalInit (Func topLevelFactory, ConsoleDriver 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. @@ -986,9 +993,7 @@ public static RunState Begin (Toplevel toplevel) toplevel.PositionToplevels (); toplevel.WillPresent (); if (refreshDriver) { - if (MdiTop != null) { - MdiTop.OnChildLoaded (toplevel); - } + MdiTop?.OnChildLoaded (toplevel); toplevel.OnLoaded (); Redraw (toplevel); toplevel.PositionCursor (); @@ -1111,12 +1116,6 @@ static void Redraw (View view) 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 4fd2dd6f95..bc3856289a 100644 --- a/Terminal.Gui/Core/ConsoleDriver.cs +++ b/Terminal.Gui/Core/ConsoleDriver.cs @@ -17,7 +17,6 @@ namespace Terminal.Gui { /// /// The value indicates either no-color has been set or the color is invalid. /// - [DefaultValue(Invalid)] public enum Color { /// /// The black color. @@ -82,13 +81,91 @@ public enum Color { /// /// 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. /// @@ -123,7 +200,7 @@ public struct Attribute { public Attribute (int value) { Color foreground = Color.Invalid; - Color background = Color.Invalid; + Color background = Color.Invalid; Initialized = false; if (Application.Driver != null) { @@ -156,8 +233,9 @@ public Attribute (int value, Color foreground, Color background) /// Background public Attribute (Color foreground = new Color (), Color background = new Color ()) { - Initialized = false; - Value = Make (foreground, background).Value; + var make = Make (foreground, background); + Initialized = make.Initialized; + Value = make.Value; Foreground = foreground; Background = background; } @@ -175,10 +253,10 @@ public Attribute (Color color) : this (color, color) { } /// /// The driver-specific color value stored in the attribute. /// The attribute to convert - public static implicit operator int (Attribute c) { - 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; + 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; } /// @@ -251,11 +329,11 @@ public bool HasValidColors { /// See also: . /// public class ColorScheme : IEquatable { - Attribute _normal; - Attribute _focus; - Attribute _hotNormal; - Attribute _hotFocus; - Attribute _disabled; + 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); /// /// Used by and to track which ColorScheme @@ -269,7 +347,6 @@ public class ColorScheme : IEquatable { public Attribute Normal { get { return _normal; } set { - if (!value.HasValidColors) { return; } @@ -390,20 +467,67 @@ public override int GetHashCode () { 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 ()); } /// @@ -470,7 +594,7 @@ static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string s /// /// Provides the defined s. /// - public static Dictionary ColorSchemes { get; } + public static Dictionary ColorSchemes { get; private set; } } /// @@ -753,6 +877,22 @@ public bool IsValidContent (int col, int row, Rect clip) => /// public abstract void UpdateScreen (); + /// + /// The current attribute the driver is using. + /// + 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; + } + } + /// /// Selects the specified attribute as the attribute to use for future calls to AddRune and AddString. /// @@ -762,7 +902,7 @@ public bool IsValidContent (int col, int row, Rect clip) => /// C. public virtual void SetAttribute (Attribute c) { - Debug.WriteLineIf(!c.Initialized, "ConsoleDriver.SetAttribute: Attributes must be initialized before use."); + CurrentAttribute = c; } /// @@ -1298,6 +1438,7 @@ public Rect Clip { /// Lower right rounded corner /// public Rune LRRCorner = '\u256f'; + private Attribute currentAttribute; /// /// Make the attribute for the foreground and background colors. @@ -1311,7 +1452,7 @@ public Rect Clip { /// Gets the current . /// /// The current attribute. - public abstract Attribute GetAttribute (); + public Attribute GetAttribute () => CurrentAttribute; /// /// Make the for the . @@ -1322,17 +1463,16 @@ public Rect Clip { 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 supportsColors = true) + /// Flag indicating if colors are supported (not used). + public void InitalizeColorSchemes (bool supportsColors = true) { - // 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 (); + // Ensure all Attributes are initlaized by the driver + foreach (var s in Colors.ColorSchemes) { + s.Value.Initialize (); + } if (!supportsColors) { return; diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index fddabb692e..1346244a0c 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -821,7 +821,6 @@ public override bool MouseEvent (MouseEvent mouseEvent) if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Released) && dragPosition.HasValue) { Application.UngrabMouse (); - Driver.UncookMouse (); dragPosition = null; } diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 8734261c0b..36ce60d5ee 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -1447,8 +1447,9 @@ public View MostFocused { /// public virtual ColorScheme ColorScheme { get { - if (colorScheme == null) + if (colorScheme == null) { return SuperView?.ColorScheme; + } return colorScheme; } set { diff --git a/Terminal.Gui/Terminal.Gui.csproj b/Terminal.Gui/Terminal.Gui.csproj index ce22fd3cd0..e92806346d 100644 --- a/Terminal.Gui/Terminal.Gui.csproj +++ b/Terminal.Gui/Terminal.Gui.csproj @@ -10,9 +10,10 @@ - 1.9 - 1.9 - 1.9 + 1.0 + 1.0 + 1.0 + 1.0 diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index 14cd47ecec..4c8f19eee8 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -164,7 +164,7 @@ class UICatalogTopLevel : Toplevel { public UICatalogTopLevel () { - ColorScheme = _colorScheme; + ColorScheme = _colorScheme = Colors.Base; MenuBar = new MenuBar (new MenuBarItem [] { new MenuBarItem ("_File", new MenuItem [] { new MenuItem ("_Quit", "Quit UI Catalog", () => RequestStop(), null, null, Key.Q | Key.CtrlMask) diff --git a/UICatalog/UICatalog.csproj b/UICatalog/UICatalog.csproj index 40d346438f..6320c1e996 100644 --- a/UICatalog/UICatalog.csproj +++ b/UICatalog/UICatalog.csproj @@ -5,7 +5,7 @@ 8.0 UICatalog.UICatalogApp - + 1.0 1.0 diff --git a/UnitTests/Application/ApplicationTests.cs b/UnitTests/Application/ApplicationTests.cs index b7ef1d8dbd..7228d8ad6e 100644 --- a/UnitTests/Application/ApplicationTests.cs +++ b/UnitTests/Application/ApplicationTests.cs @@ -24,7 +24,6 @@ void Pre_Init_State () Assert.Null (Application.Driver); Assert.Null (Application.Top); Assert.Null (Application.Current); - Assert.Throws (() => Application.HeightAsBuffer == true); Assert.Null (Application.MainLoop); Assert.Null (Application.Iteration); Assert.Null (Application.RootMouseEvent); diff --git a/UnitTests/Drivers/ConsoleDriverTests.cs b/UnitTests/Drivers/ConsoleDriverTests.cs index a77d5f5a67..8289e9737a 100644 --- a/UnitTests/Drivers/ConsoleDriverTests.cs +++ b/UnitTests/Drivers/ConsoleDriverTests.cs @@ -319,7 +319,7 @@ public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_BufferHeight_Minus Application.Shutdown (); } - + [Fact, AutoInitShutdown] public void AddRune_On_Clip_Left_Or_Right_Replace_Previous_Or_Next_Wide_Rune_With_Space () { @@ -441,7 +441,7 @@ public void MakePrintable_Does_Not_Convert_Ansi_Chars_To_Unicode (uint code) } private static object packetLock = new object (); - + /// /// Sometimes when using remote tools EventKeyRecord sends 'virtual keystrokes'. /// These are indicated with the wVirtualKeyCode of 231. When we see this code @@ -487,6 +487,7 @@ public void TestVKPacket (uint unicodeCharacter, bool shift, bool alt, bool cont if (iterations == 0) Application.Driver.SendKeys ((char)mappedConsoleKey, ConsoleKey.Packet, shift, alt, control); }; + lock (packetLock) { Application.Run (); Application.Shutdown (); diff --git a/UnitTests/Drivers/KeyTests.cs b/UnitTests/Drivers/KeyTests.cs index 3d4d8606e3..3116c86285 100644 --- a/UnitTests/Drivers/KeyTests.cs +++ b/UnitTests/Drivers/KeyTests.cs @@ -1,4 +1,5 @@ using System; +using Terminal.Gui; using Xunit; namespace Terminal.Gui.DriverTests { diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj index 68da4e1d00..ae37662441 100644 --- a/UnitTests/UnitTests.csproj +++ b/UnitTests/UnitTests.csproj @@ -7,12 +7,12 @@ false - + - 1.0 - 1.0 - 1.0 - 1.0 + 2.0 + 2.0 + 2.0 + 2.0 TRACE