From ed7cb3d4293bb158e756fde815e4eb06cfcd783b Mon Sep 17 00:00:00 2001 From: Tig Kindel Date: Mon, 6 Feb 2023 11:25:29 +0900 Subject: [PATCH] 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); } }