diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs
index 5ea981b7b..5019058bf 100644
--- a/Terminal.Gui/Application.cs
+++ b/Terminal.Gui/Application.cs
@@ -54,7 +54,7 @@ namespace Terminal.Gui {
public static bool UseSystemConsole { get; set; } = false;
///
- /// Gets or sets whether will be forced to output only the 16 colors defined in .
+ /// Gets or sets whether will be forced to output only the 16 colors defined in .
/// The default is , meaning 24-bit (TrueColor) colors will be output as long as the selected
/// supports TrueColor.
///
diff --git a/Terminal.Gui/Configuration/ColorJsonConverter.cs b/Terminal.Gui/Configuration/ColorJsonConverter.cs
index 29624582c..48ddea113 100644
--- a/Terminal.Gui/Configuration/ColorJsonConverter.cs
+++ b/Terminal.Gui/Configuration/ColorJsonConverter.cs
@@ -31,7 +31,7 @@ namespace Terminal.Gui {
var colorString = reader.GetString ();
// Check if the color string is a color name
- if (Enum.TryParse (colorString, ignoreCase: true, out ColorNames color)) {
+ if (Enum.TryParse (colorString, ignoreCase: true, out ColorName color)) {
// Return the parsed color
return new Color(color);
}
diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
index f8c2ea792..b5fd61084 100644
--- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
@@ -88,7 +88,7 @@ internal class CursesDriver : ConsoleDriver {
/// and the background color is stored in the least significant 4 bits.
/// The Terminal.GUi Color values are converted to curses color encoding before being encoded.
///
- private Attribute MakeColor (ColorNames foregroundName, ColorNames backgroundName)
+ private Attribute MakeColor (ColorName foregroundName, ColorName backgroundName)
{
if (!RunningUnitTests) {
return MakeColor (ColorNameToCursesColorNumber (foregroundName), ColorNameToCursesColorNumber (backgroundName));
@@ -119,80 +119,80 @@ internal class CursesDriver : ConsoleDriver {
}
}
- static short ColorNameToCursesColorNumber (ColorNames color)
+ static short ColorNameToCursesColorNumber (ColorName color)
{
switch (color) {
- case ColorNames.Black:
+ case ColorName.Black:
return Curses.COLOR_BLACK;
- case ColorNames.Blue:
+ case ColorName.Blue:
return Curses.COLOR_BLUE;
- case ColorNames.Green:
+ case ColorName.Green:
return Curses.COLOR_GREEN;
- case ColorNames.Cyan:
+ case ColorName.Cyan:
return Curses.COLOR_CYAN;
- case ColorNames.Red:
+ case ColorName.Red:
return Curses.COLOR_RED;
- case ColorNames.Magenta:
+ case ColorName.Magenta:
return Curses.COLOR_MAGENTA;
- case ColorNames.Yellow:
+ case ColorName.Yellow:
return Curses.COLOR_YELLOW;
- case ColorNames.Gray:
+ case ColorName.Gray:
return Curses.COLOR_WHITE;
- case ColorNames.DarkGray:
+ case ColorName.DarkGray:
return Curses.COLOR_GRAY;
- case ColorNames.BrightBlue:
+ case ColorName.BrightBlue:
return Curses.COLOR_BLUE | Curses.COLOR_GRAY;
- case ColorNames.BrightGreen:
+ case ColorName.BrightGreen:
return Curses.COLOR_GREEN | Curses.COLOR_GRAY;
- case ColorNames.BrightCyan:
+ case ColorName.BrightCyan:
return Curses.COLOR_CYAN | Curses.COLOR_GRAY;
- case ColorNames.BrightRed:
+ case ColorName.BrightRed:
return Curses.COLOR_RED | Curses.COLOR_GRAY;
- case ColorNames.BrightMagenta:
+ case ColorName.BrightMagenta:
return Curses.COLOR_MAGENTA | Curses.COLOR_GRAY;
- case ColorNames.BrightYellow:
+ case ColorName.BrightYellow:
return Curses.COLOR_YELLOW | Curses.COLOR_GRAY;
- case ColorNames.White:
+ case ColorName.White:
return Curses.COLOR_WHITE | Curses.COLOR_GRAY;
}
throw new ArgumentException ("Invalid color code");
}
- static ColorNames CursesColorNumberToColorName (short color)
+ static ColorName CursesColorNumberToColorName (short color)
{
switch (color) {
case Curses.COLOR_BLACK:
- return ColorNames.Black;
+ return ColorName.Black;
case Curses.COLOR_BLUE:
- return ColorNames.Blue;
+ return ColorName.Blue;
case Curses.COLOR_GREEN:
- return ColorNames.Green;
+ return ColorName.Green;
case Curses.COLOR_CYAN:
- return ColorNames.Cyan;
+ return ColorName.Cyan;
case Curses.COLOR_RED:
- return ColorNames.Red;
+ return ColorName.Red;
case Curses.COLOR_MAGENTA:
- return ColorNames.Magenta;
+ return ColorName.Magenta;
case Curses.COLOR_YELLOW:
- return ColorNames.Yellow;
+ return ColorName.Yellow;
case Curses.COLOR_WHITE:
- return ColorNames.Gray;
+ return ColorName.Gray;
case Curses.COLOR_GRAY:
- return ColorNames.DarkGray;
+ return ColorName.DarkGray;
case Curses.COLOR_BLUE | Curses.COLOR_GRAY:
- return ColorNames.BrightBlue;
+ return ColorName.BrightBlue;
case Curses.COLOR_GREEN | Curses.COLOR_GRAY:
- return ColorNames.BrightGreen;
+ return ColorName.BrightGreen;
case Curses.COLOR_CYAN | Curses.COLOR_GRAY:
- return ColorNames.BrightCyan;
+ return ColorName.BrightCyan;
case Curses.COLOR_RED | Curses.COLOR_GRAY:
- return ColorNames.BrightRed;
+ return ColorName.BrightRed;
case Curses.COLOR_MAGENTA | Curses.COLOR_GRAY:
- return ColorNames.BrightMagenta;
+ return ColorName.BrightMagenta;
case Curses.COLOR_YELLOW | Curses.COLOR_GRAY:
- return ColorNames.BrightYellow;
+ return ColorName.BrightYellow;
case Curses.COLOR_WHITE | Curses.COLOR_GRAY:
- return ColorNames.White;
+ return ColorName.White;
}
throw new ArgumentException ("Invalid curses color code");
}
@@ -675,7 +675,7 @@ internal class CursesDriver : ConsoleDriver {
Curses.UseDefaultColors ();
}
- CurrentAttribute = MakeColor (ColorNames.White, ColorNames.Black);
+ CurrentAttribute = MakeColor (ColorName.White, ColorName.Black);
TerminalResized = terminalResized;
diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
index 65a830dca..b824663c4 100644
--- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
@@ -2,19 +2,12 @@
// FakeDriver.cs: A fake ConsoleDriver for unit tests.
//
using System;
-using System.Buffers;
-using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
using System.Runtime.InteropServices;
-using System.Threading;
using System.Text;
// Alias Console to MockConsole so we don't accidentally use Console
using Console = Terminal.Gui.FakeConsole;
-using Unix.Terminal;
-using static Terminal.Gui.WindowsConsole;
-using System.Drawing;
namespace Terminal.Gui;
///
@@ -80,9 +73,7 @@ public class FakeDriver : ConsoleDriver {
Rows = FakeConsole.WindowHeight = FakeConsole.BufferHeight = FakeConsole.HEIGHT;
FakeConsole.Clear ();
ResizeScreen ();
- // Call InitializeColorSchemes before UpdateOffScreen as it references Colors
CurrentAttribute = new Attribute (Color.White, Color.Black);
- //InitializeColorSchemes ();
ClearContents ();
}
diff --git a/Terminal.Gui/Drawing/Color.cs b/Terminal.Gui/Drawing/Color.cs
index 8d8a3a852..facac2a71 100644
--- a/Terminal.Gui/Drawing/Color.cs
+++ b/Terminal.Gui/Drawing/Color.cs
@@ -8,1054 +8,1054 @@ using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
-namespace Terminal.Gui {
+namespace Terminal.Gui;
+///
+/// Defines the 16 legacy color names and values that can be used to set the
+/// foreground and background colors in Terminal.Gui apps. Used with .
+///
+///
+///
+/// These colors match the 16 colors defined for ANSI escape sequences for 4-bit (16) colors.
+///
+///
+/// For terminals that support 24-bit color (TrueColor), the RGB values for each of these colors can be configured using the
+/// property.
+///
+///
+public enum ColorName {
///
- /// Defines the 16 legacy color names and values that can be used to set the
- /// foreground and background colors in Terminal.Gui apps. Used with .
+ /// The black color. ANSI escape sequence: \u001b[30m.
///
- ///
- ///
- /// These colors match the 16 colors defined for ANSI escape sequences for 4-bit (16) colors.
- ///
- ///
- /// For terminals that support 24-bit color (TrueColor), the RGB values for each of these colors can be configured using the
- /// property.
- ///
- ///
- public enum ColorNames {
- ///
- /// The black color. ANSI escape sequence: \u001b[30m.
- ///
- Black,
- ///
- /// The blue color. ANSI escape sequence: \u001b[34m.
- ///
- Blue,
- ///
- /// The green color. ANSI escape sequence: \u001b[32m.
- ///
- Green,
- ///
- /// The cyan color. ANSI escape sequence: \u001b[36m.
- ///
- Cyan,
- ///
- /// The red color. ANSI escape sequence: \u001b[31m.
- ///
- Red,
- ///
- /// The magenta color. ANSI escape sequence: \u001b[35m.
- ///
- Magenta,
- ///
- /// The yellow color (also known as Brown). ANSI escape sequence: \u001b[33m.
- ///
- Yellow,
- ///
- /// The gray color (also known as White). ANSI escape sequence: \u001b[37m.
- ///
- Gray,
- ///
- /// The dark gray color (also known as Bright Black). ANSI escape sequence: \u001b[30;1m.
- ///
- DarkGray,
- ///
- /// The bright blue color. ANSI escape sequence: \u001b[34;1m.
- ///
- BrightBlue,
- ///
- /// The bright green color. ANSI escape sequence: \u001b[32;1m.
- ///
- BrightGreen,
- ///
- /// The bright cyan color. ANSI escape sequence: \u001b[36;1m.
- ///
- BrightCyan,
- ///
- /// The bright red color. ANSI escape sequence: \u001b[31;1m.
- ///
- BrightRed,
- ///
- /// The bright magenta color. ANSI escape sequence: \u001b[35;1m.
- ///
- BrightMagenta,
- ///
- /// The bright yellow color. ANSI escape sequence: \u001b[33;1m.
- ///
- BrightYellow,
- ///
- /// The White color (also known as Bright White). ANSI escape sequence: \u001b[37;1m.
- ///
- White
+ Black,
+ ///
+ /// The blue color. ANSI escape sequence: \u001b[34m.
+ ///
+ Blue,
+ ///
+ /// The green color. ANSI escape sequence: \u001b[32m.
+ ///
+ Green,
+ ///
+ /// The cyan color. ANSI escape sequence: \u001b[36m.
+ ///
+ Cyan,
+ ///
+ /// The red color. ANSI escape sequence: \u001b[31m.
+ ///
+ Red,
+ ///
+ /// The magenta color. ANSI escape sequence: \u001b[35m.
+ ///
+ Magenta,
+ ///
+ /// The yellow color (also known as Brown). ANSI escape sequence: \u001b[33m.
+ ///
+ Yellow,
+ ///
+ /// The gray color (also known as White). ANSI escape sequence: \u001b[37m.
+ ///
+ Gray,
+ ///
+ /// The dark gray color (also known as Bright Black). ANSI escape sequence: \u001b[30;1m.
+ ///
+ DarkGray,
+ ///
+ /// The bright blue color. ANSI escape sequence: \u001b[34;1m.
+ ///
+ BrightBlue,
+ ///
+ /// The bright green color. ANSI escape sequence: \u001b[32;1m.
+ ///
+ BrightGreen,
+ ///
+ /// The bright cyan color. ANSI escape sequence: \u001b[36;1m.
+ ///
+ BrightCyan,
+ ///
+ /// The bright red color. ANSI escape sequence: \u001b[31;1m.
+ ///
+ BrightRed,
+ ///
+ /// The bright magenta color. ANSI escape sequence: \u001b[35;1m.
+ ///
+ BrightMagenta,
+ ///
+ /// The bright yellow color. ANSI escape sequence: \u001b[33;1m.
+ ///
+ BrightYellow,
+ ///
+ /// The White color (also known as Bright White). ANSI escape sequence: \u001b[37;1m.
+ ///
+ White
+}
+
+///
+/// Represents a 24-bit color. Provides automatic mapping between the legacy 4-bit (16 color) system and 24-bit colors (see ).
+/// Used with .
+///
+[JsonConverter (typeof (ColorJsonConverter))]
+public class Color : IEquatable {
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The red 8-bits.
+ /// The green 8-bits.
+ /// The blue 8-bits.
+ /// Optional; defaults to 0xFF. The Alpha channel is not supported by Terminal.Gui.
+ public Color (int red, int green, int blue, int alpha = 0xFF)
+ {
+ R = red;
+ G = green;
+ B = blue;
+ A = alpha;
}
///
- /// Represents a 24-bit color. Provides automatic mapping between the legacy 4-bit (16 color) system and 24-bit colors (see ).
- /// Used with .
+ /// Initializes a new instance of the class with an encoded 24-bit color value.
///
- [JsonConverter (typeof (ColorJsonConverter))]
- public class Color : IEquatable {
+ /// The encoded 24-bit color value (see ).
+ public Color (int rgba)
+ {
+ Rgba = rgba;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// The red 8-bits.
- /// The green 8-bits.
- /// The blue 8-bits.
- /// Optional; defaults to 0xFF. The Alpha channel is not supported by Terminal.Gui.
- public Color (int red, int green, int blue, int alpha = 0xFF)
- {
- R = red;
- G = green;
- B = blue;
- A = alpha;
+ ///
+ /// Initializes a new instance of the color from a legacy 16-color value.
+ ///
+ /// The 16-color value.
+ public Color (ColorName colorName)
+ {
+ var c = Color.FromColorName (colorName);
+ R = c.R;
+ G = c.G;
+ B = c.B;
+ A = c.A;
+ }
+
+ ///
+ /// Initializes a new instance of the color from string. See for details.
+ ///
+ ///
+ ///
+ public Color (string colorString)
+ {
+ if (!TryParse (colorString, out var c)) {
+ throw new ArgumentOutOfRangeException (nameof (colorString));
}
+ R = c.R;
+ G = c.G;
+ B = c.B;
+ A = c.A;
+ }
- ///
- /// Initializes a new instance of the class with an encoded 24-bit color value.
- ///
- /// The encoded 24-bit color value (see ).
- public Color (int rgba)
- {
- Rgba = rgba;
+ ///
+ /// Initializes a new instance of the .
+ ///
+ public Color ()
+ {
+ R = 0;
+ G = 0;
+ B = 0;
+ A = 0xFF;
+ }
+
+ ///
+ /// Red color component.
+ ///
+ public int R { get; set; }
+ ///
+ /// Green color component.
+ ///
+ public int G { get; set; }
+ ///
+ /// Blue color component.
+ ///
+ public int B { get; set; }
+
+ ///
+ /// Alpha color component.
+ ///
+ ///
+ /// The Alpha channel is not supported by Terminal.Gui.
+ ///
+ public int A { get; set; } = 0xFF; // Not currently supported; here for completeness.
+
+ ///
+ /// Gets or sets the color value encoded as ARGB32.
+ ///
+ /// (<see cref="A"/> << 24) | (<see cref="R"/> << 16) | (<see cref="G"/> << 8) | <see cref="B"/>
+ ///
+ ///
+ public int Rgba {
+ get => (A << 24) | (R << 16) | (G << 8) | B;
+ set {
+ A = (byte)((value >> 24) & 0xFF);
+ R = (byte)((value >> 16) & 0xFF);
+ G = (byte)((value >> 8) & 0xFF);
+ B = (byte)(value & 0xFF);
}
+ }
- ///
- /// Initializes a new instance of the color from a legacy 16-color value.
- ///
- /// The 16-color value.
- public Color (ColorNames colorName)
- {
- var c = Color.FromColorName (colorName);
- R = c.R;
- G = c.G;
- B = c.B;
- A = c.A;
- }
-
- ///
- /// Initializes a new instance of the color from string. See for details.
- ///
- ///
- ///
- public Color (string colorString)
- {
- if (!TryParse (colorString, out var c)) {
- throw new ArgumentOutOfRangeException (nameof (colorString));
- }
- R = c.R;
- G = c.G;
- B = c.B;
- A = c.A;
- }
-
- ///
- /// Initializes a new instance of the .
- ///
- public Color ()
- {
- R = 0;
- G = 0;
- B = 0;
- A = 0xFF;
- }
-
- ///
- /// Red color component.
- ///
- public int R { get; set; }
- ///
- /// Green color component.
- ///
- public int G { get; set; }
- ///
- /// Blue color component.
- ///
- public int B { get; set; }
-
- ///
- /// Alpha color component.
- ///
- ///
- /// The Alpha channel is not supported by Terminal.Gui.
- ///
- public int A { get; set; } = 0xFF; // Not currently supported; here for completeness.
-
- ///
- /// Gets or sets the color value encoded as ARGB32.
- ///
- /// (<see cref="A"/> << 24) | (<see cref="R"/> << 16) | (<see cref="G"/> << 8) | <see cref="B"/>
- ///
- ///
- public int Rgba {
- get => (A << 24) | (R << 16) | (G << 8) | B;
- set {
- A = (byte)((value >> 24) & 0xFF);
- R = (byte)((value >> 16) & 0xFF);
- G = (byte)((value >> 8) & 0xFF);
- B = (byte)(value & 0xFF);
- }
- }
-
- // TODO: Make this map configurable via ConfigurationManager
- // TODO: This does not need to be a Dictionary, but can be an 16 element array.
- ///
- /// Maps legacy 16-color values to the corresponding 24-bit RGB value.
- ///
- internal static ImmutableDictionary _colorToNameMap = new Dictionary () {
+ // TODO: Make this map configurable via ConfigurationManager
+ // TODO: This does not need to be a Dictionary, but can be an 16 element array.
+ ///
+ /// Maps legacy 16-color values to the corresponding 24-bit RGB value.
+ ///
+ internal static ImmutableDictionary _colorToNameMap = new Dictionary () {
// using "Windows 10 Console/PowerShell 6" here: https://i.stack.imgur.com/9UVnC.png
// See also: https://en.wikipedia.org/wiki/ANSI_escape_code
- { new Color (12, 12, 12),ColorNames.Black },
- { new Color (0, 55, 218),ColorNames.Blue },
- { new Color (19, 161, 14),ColorNames.Green},
- { new Color (58, 150, 221),ColorNames.Cyan},
- { new Color (197, 15, 31),ColorNames.Red},
- { new Color (136, 23, 152),ColorNames.Magenta},
- { new Color (128, 64, 32),ColorNames.Yellow},
- { new Color (204, 204, 204),ColorNames.Gray},
- { new Color (118, 118, 118),ColorNames.DarkGray},
- { new Color (59, 120, 255),ColorNames.BrightBlue},
- { new Color (22, 198, 12),ColorNames.BrightGreen},
- { new Color (97, 214, 214),ColorNames.BrightCyan},
- { new Color (231, 72, 86),ColorNames.BrightRed},
- { new Color (180, 0, 158),ColorNames.BrightMagenta },
- { new Color (249, 241, 165),ColorNames.BrightYellow},
- { new Color (242, 242, 242),ColorNames.White},
+ { new Color (12, 12, 12),Gui.ColorName.Black },
+ { new Color (0, 55, 218),Gui.ColorName.Blue },
+ { new Color (19, 161, 14),Gui.ColorName.Green},
+ { new Color (58, 150, 221),Gui.ColorName.Cyan},
+ { new Color (197, 15, 31),Gui.ColorName.Red},
+ { new Color (136, 23, 152),Gui.ColorName.Magenta},
+ { new Color (128, 64, 32),Gui.ColorName.Yellow},
+ { new Color (204, 204, 204),Gui.ColorName.Gray},
+ { new Color (118, 118, 118),Gui.ColorName.DarkGray},
+ { new Color (59, 120, 255),Gui.ColorName.BrightBlue},
+ { new Color (22, 198, 12),Gui.ColorName.BrightGreen},
+ { new Color (97, 214, 214),Gui.ColorName.BrightCyan},
+ { new Color (231, 72, 86),Gui.ColorName.BrightRed},
+ { new Color (180, 0, 158),Gui.ColorName.BrightMagenta },
+ { new Color (249, 241, 165),Gui.ColorName.BrightYellow},
+ { new Color (242, 242, 242),Gui.ColorName.White},
}.ToImmutableDictionary ();
- [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]
- //[JsonConverter (typeof (DictionaryJsonConverter))]
- public static Dictionary Colors {
- get {
- // Transform _colorToNameMap into a Dictionary
- return _colorToNameMap.ToDictionary (kvp => kvp.Value, kvp => $"#{kvp.Key.R:X2}{kvp.Key.G:X2}{kvp.Key.B:X2}");
- }
- set {
- // Transform Dictionary into _colorToNameMap
- var newMap = value.ToDictionary (kvp => new Color (kvp.Value), kvp => {
- if (Enum.TryParse (kvp.Key.ToString(), ignoreCase: true, out ColorNames colorName)) {
- return colorName;
- }
- throw new ArgumentException ($"Invalid color name: {kvp.Key}");
- });
- _colorToNameMap = newMap.ToImmutableDictionary ();
- }
+ ///
+ /// Gets or sets the 24-bit color value for each of the legacy 16-color values.
+ ///
+ [SerializableConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]
+ public static Dictionary Colors {
+ get {
+ // Transform _colorToNameMap into a Dictionary
+ return _colorToNameMap.ToDictionary (kvp => kvp.Value, kvp => $"#{kvp.Key.R:X2}{kvp.Key.G:X2}{kvp.Key.B:X2}");
}
-
- ///
- /// Converts a legacy to a 24-bit .
- ///
- /// The to convert.
- ///
- private static Color FromColorName (ColorNames consoleColor) => _colorToNameMap.FirstOrDefault (x => x.Value == consoleColor).Key;
-
- // Iterates through the entries in the _colorNames dictionary, calculates the
- // Euclidean distance between the input color and each dictionary color in RGB space,
- // and keeps track of the closest entry found so far. The function returns a KeyValuePair
- // representing the closest color entry and its associated color name.
- internal static ColorNames FindClosestColor (Color inputColor)
- {
- ColorNames closestColor = ColorNames.Black; // Default to Black
- double closestDistance = double.MaxValue;
-
- foreach (var colorEntry in _colorToNameMap) {
- var distance = CalculateColorDistance (inputColor, colorEntry.Key);
- if (distance < closestDistance) {
- closestDistance = distance;
- closestColor = colorEntry.Value;
+ set {
+ // Transform Dictionary into _colorToNameMap
+ var newMap = value.ToDictionary (kvp => new Color (kvp.Value), kvp => {
+ if (Enum.TryParse (kvp.Key.ToString (), ignoreCase: true, out ColorName colorName)) {
+ return colorName;
}
- }
-
- return closestColor;
+ throw new ArgumentException ($"Invalid color name: {kvp.Key}");
+ });
+ _colorToNameMap = newMap.ToImmutableDictionary ();
}
+ }
- private static double CalculateColorDistance (Color color1, Color color2)
- {
- // Calculate the Euclidean distance between two colors
- var deltaR = (double)color1.R - (double)color2.R;
- var deltaG = (double)color1.G - (double)color2.G;
- var deltaB = (double)color1.B - (double)color2.B;
+ ///
+ /// Converts a legacy to a 24-bit .
+ ///
+ /// The to convert.
+ ///
+ private static Color FromColorName (ColorName consoleColor) => _colorToNameMap.FirstOrDefault (x => x.Value == consoleColor).Key;
- return Math.Sqrt (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
- }
+ // Iterates through the entries in the _colorNames dictionary, calculates the
+ // Euclidean distance between the input color and each dictionary color in RGB space,
+ // and keeps track of the closest entry found so far. The function returns a KeyValuePair
+ // representing the closest color entry and its associated color name.
+ internal static ColorName FindClosestColor (Color inputColor)
+ {
+ ColorName closestColor = Gui.ColorName.Black; // Default to Black
+ double closestDistance = double.MaxValue;
- ///
- /// Gets or sets the using a legacy 16-color value.
- ///
- ///
- /// Get returns the of the closest 24-bit color value. Set sets the RGB value using a hard-coded map.
- ///
- public ColorNames ColorName {
- get => FindClosestColor (this);
- set {
-
- var c = FromColorName (value);
- R = c.R;
- G = c.G;
- B = c.B;
- A = c.A;
+ foreach (var colorEntry in _colorToNameMap) {
+ var distance = CalculateColorDistance (inputColor, colorEntry.Key);
+ if (distance < closestDistance) {
+ closestDistance = distance;
+ closestColor = colorEntry.Value;
}
}
- #region Legacy Color Names
- ///
- ///
- /// The black color.
- ///
- public const ColorNames Black = ColorNames.Black;
+ return closestColor;
+ }
- ///
- /// The blue color.
- ///
- public const ColorNames Blue = ColorNames.Blue;
- ///
- /// The green color.
- ///
- public const ColorNames Green = ColorNames.Green;
- ///
- /// The cyan color.
- ///
- public const ColorNames Cyan = ColorNames.Cyan;
- ///
- /// The red color.
- ///
- public const ColorNames Red = ColorNames.Red;
- ///
- /// The magenta color.
- ///
- public const ColorNames Magenta = ColorNames.Magenta;
- ///
- /// The yellow color.
- ///
- public const ColorNames Yellow = ColorNames.Yellow;
- ///
- /// The gray color.
- ///
- public const ColorNames Gray = ColorNames.Gray;
- ///
- /// The dark gray color.
- ///
- public const ColorNames DarkGray = ColorNames.DarkGray;
- ///
- /// The bright bBlue color.
- ///
- public const ColorNames BrightBlue = ColorNames.BrightBlue;
- ///
- /// The bright green color.
- ///
- public const ColorNames BrightGreen = ColorNames.BrightGreen;
- ///
- /// The bright cyan color.
- ///
- public const ColorNames BrightCyan = ColorNames.BrightCyan;
- ///
- /// The bright red color.
- ///
- public const ColorNames BrightRed = ColorNames.BrightRed;
- ///
- /// The bright magenta color.
- ///
- public const ColorNames BrightMagenta = ColorNames.BrightMagenta;
- ///
- /// The bright yellow color.
- ///
- public const ColorNames BrightYellow = ColorNames.BrightYellow;
- ///
- /// The White color.
- ///
- public const ColorNames White = ColorNames.White;
- #endregion
+ private static double CalculateColorDistance (Color color1, Color color2)
+ {
+ // Calculate the Euclidean distance between two colors
+ var deltaR = (double)color1.R - (double)color2.R;
+ var deltaG = (double)color1.G - (double)color2.G;
+ var deltaB = (double)color1.B - (double)color2.B;
- ///
- /// Converts the provided string to a new instance.
- ///
- /// The text to analyze. Formats supported are
- /// "#RGB", "#RRGGBB", "#RGBA", "#RRGGBBAA", "rgb(r,g,b)", "rgb(r,g,b,a)", and any of the
- /// .
- /// The parsed value.
- /// A boolean value indicating whether parsing was successful.
- ///
- /// While supports the alpha channel , Terminal.Gui does not.
- ///
- public static bool TryParse (string text, [NotNullWhen (true)] out Color color)
- {
- // empty color
- if ((text == null) || (text.Length == 0)) {
- color = null;
- return false;
- }
+ return Math.Sqrt (deltaR * deltaR + deltaG * deltaG + deltaB * deltaB);
+ }
- // #RRGGBB, #RGB
- if ((text [0] == '#') && text.Length is 7 or 4) {
- if (text.Length == 7) {
- var r = Convert.ToInt32 (text.Substring (1, 2), 16);
- var g = Convert.ToInt32 (text.Substring (3, 2), 16);
- var b = Convert.ToInt32 (text.Substring (5, 2), 16);
- color = new Color (r, g, b);
- } else {
- var rText = char.ToString (text [1]);
- var gText = char.ToString (text [2]);
- var bText = char.ToString (text [3]);
+ ///
+ /// Gets or sets the using a legacy 16-color value.
+ ///
+ ///
+ /// Get returns the of the closest 24-bit color value. Set sets the RGB value using a hard-coded map.
+ ///
+ public ColorName ColorName {
+ get => FindClosestColor (this);
+ set {
- var r = Convert.ToInt32 (rText + rText, 16);
- var g = Convert.ToInt32 (gText + gText, 16);
- var b = Convert.ToInt32 (bText + bText, 16);
- color = new Color (r, g, b);
- }
- return true;
- }
+ var c = FromColorName (value);
+ R = c.R;
+ G = c.G;
+ B = c.B;
+ A = c.A;
+ }
+ }
- // #RRGGBB, #RGBA
- if ((text [0] == '#') && text.Length is 8 or 5) {
- if (text.Length == 7) {
- var r = Convert.ToInt32 (text.Substring (1, 2), 16);
- var g = Convert.ToInt32 (text.Substring (3, 2), 16);
- var b = Convert.ToInt32 (text.Substring (5, 2), 16);
- var a = Convert.ToInt32 (text.Substring (7, 2), 16);
- color = new Color (a, r, g, b);
- } else {
- var rText = char.ToString (text [1]);
- var gText = char.ToString (text [2]);
- var bText = char.ToString (text [3]);
- var aText = char.ToString (text [4]);
+ #region Legacy Color Names
+ ///
+ ///
+ /// The black color.
+ ///
+ public const ColorName Black = ColorName.Black;
- var r = Convert.ToInt32 (aText + aText, 16);
- var g = Convert.ToInt32 (rText + rText, 16);
- var b = Convert.ToInt32 (gText + gText, 16);
- var a = Convert.ToInt32 (bText + bText, 16);
- color = new Color (r, g, b, a);
- }
- return true;
- }
-
- // rgb(r,g,b)
- var match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+)\)");
- if (match.Success) {
- var r = int.Parse (match.Groups [1].Value);
- var g = int.Parse (match.Groups [2].Value);
- var b = int.Parse (match.Groups [3].Value);
- color = new Color (r, g, b);
- return true;
- }
-
- // rgb(r,g,b,a)
- match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+),(\d+)\)");
- if (match.Success) {
- var r = int.Parse (match.Groups [1].Value);
- var g = int.Parse (match.Groups [2].Value);
- var b = int.Parse (match.Groups [3].Value);
- var a = int.Parse (match.Groups [4].Value);
- color = new Color (r, g, b, a);
- return true;
- }
-
- if (Enum.TryParse (text, ignoreCase: true, out ColorNames colorName)) {
- color = new Color (colorName);
- return true;
- }
+ ///
+ /// The blue color.
+ ///
+ public const ColorName Blue = ColorName.Blue;
+ ///
+ /// The green color.
+ ///
+ public const ColorName Green = ColorName.Green;
+ ///
+ /// The cyan color.
+ ///
+ public const ColorName Cyan = ColorName.Cyan;
+ ///
+ /// The red color.
+ ///
+ public const ColorName Red = ColorName.Red;
+ ///
+ /// The magenta color.
+ ///
+ public const ColorName Magenta = ColorName.Magenta;
+ ///
+ /// The yellow color.
+ ///
+ public const ColorName Yellow = ColorName.Yellow;
+ ///
+ /// The gray color.
+ ///
+ public const ColorName Gray = ColorName.Gray;
+ ///
+ /// The dark gray color.
+ ///
+ public const ColorName DarkGray = ColorName.DarkGray;
+ ///
+ /// The bright bBlue color.
+ ///
+ public const ColorName BrightBlue = ColorName.BrightBlue;
+ ///
+ /// The bright green color.
+ ///
+ public const ColorName BrightGreen = ColorName.BrightGreen;
+ ///
+ /// The bright cyan color.
+ ///
+ public const ColorName BrightCyan = ColorName.BrightCyan;
+ ///
+ /// The bright red color.
+ ///
+ public const ColorName BrightRed = ColorName.BrightRed;
+ ///
+ /// The bright magenta color.
+ ///
+ public const ColorName BrightMagenta = ColorName.BrightMagenta;
+ ///
+ /// The bright yellow color.
+ ///
+ public const ColorName BrightYellow = ColorName.BrightYellow;
+ ///
+ /// The White color.
+ ///
+ public const ColorName White = ColorName.White;
+ #endregion
+ ///
+ /// Converts the provided string to a new instance.
+ ///
+ /// The text to analyze. Formats supported are
+ /// "#RGB", "#RRGGBB", "#RGBA", "#RRGGBBAA", "rgb(r,g,b)", "rgb(r,g,b,a)", and any of the
+ /// .
+ /// The parsed value.
+ /// A boolean value indicating whether parsing was successful.
+ ///
+ /// While supports the alpha channel , Terminal.Gui does not.
+ ///
+ public static bool TryParse (string text, [NotNullWhen (true)] out Color color)
+ {
+ // empty color
+ if ((text == null) || (text.Length == 0)) {
color = null;
return false;
}
- #region Operators
- ///
- /// Cast from int.
- ///
- ///
- public static implicit operator Color (int rgba)
- {
- return new Color (rgba);
- }
+ // #RRGGBB, #RGB
+ if ((text [0] == '#') && text.Length is 7 or 4) {
+ if (text.Length == 7) {
+ var r = Convert.ToInt32 (text.Substring (1, 2), 16);
+ var g = Convert.ToInt32 (text.Substring (3, 2), 16);
+ var b = Convert.ToInt32 (text.Substring (5, 2), 16);
+ color = new Color (r, g, b);
+ } else {
+ var rText = char.ToString (text [1]);
+ var gText = char.ToString (text [2]);
+ var bText = char.ToString (text [3]);
- ///
- /// Cast to int.
- ///
- ///
- public static explicit operator int (Color color)
- {
- return color.Rgba;
- }
-
- ///
- /// Cast from .
- ///
- ///
- public static explicit operator Color (ColorNames colorName)
- {
- return new Color (colorName);
- }
-
- ///
- /// Cast to .
- ///
- ///
- public static explicit operator ColorNames (Color color)
- {
- return color.ColorName;
- }
-
-
- ///
- /// Equality operator for two objects..
- ///
- ///
- ///
- ///
- public static bool operator == (Color left, Color right)
- {
- if (left is null && right is null)
- return true;
-
- if (left is null || right is null)
- return false;
-
- return left.Equals (right);
- }
-
-
- ///
- /// Inequality operator for two objects.
- ///
- ///
- ///
- ///
- public static bool operator != (Color left, Color right)
- {
- if (left is null && right is null)
- return false;
-
- if (left is null || right is null)
- return true;
-
- return !left.Equals (right);
- }
-
- ///
- /// Equality operator for and objects.
- ///
- ///
- ///
- ///
- public static bool operator == (ColorNames left, Color right)
- {
- return left == right.ColorName;
- }
-
- ///
- /// Inequality operator for and objects.
- ///
- ///
- ///
- ///
- public static bool operator != (ColorNames left, Color right)
- {
- return left != right.ColorName;
- }
-
- ///
- /// Equality operator for and objects.
- ///
- ///
- ///
- ///
- public static bool operator == (Color left, ColorNames right)
- {
- return left.ColorName == right;
- }
-
- ///
- /// Inequality operator for and objects.
- ///
- ///
- ///
- ///
- public static bool operator != (Color left, ColorNames right)
- {
- return left.ColorName != right;
- }
-
-
- ///
- public override bool Equals (object obj)
- {
- return obj is Color other && Equals (other);
- }
-
- ///
- public bool Equals (Color other)
- {
- return
- R == other.R &&
- G == other.G &&
- B == other.B &&
- A == other.A;
- }
-
- ///
- public override int GetHashCode ()
- {
- return HashCode.Combine (R, G, B, A);
- }
- #endregion
-
- ///
- /// Converts the color to a string representation.
- ///
- ///
- ///
- /// If the color is a named color, the name is returned. Otherwise, the color is returned as a hex string.
- ///
- ///
- /// (Alpha channel) is ignored and the returned string will not include it.
- ///
- ///
- ///
- public override string ToString ()
- {
- // If Values has an exact match with a named color (in _colorNames), use that.
- if (_colorToNameMap.TryGetValue (this, out ColorNames colorName)) {
- return Enum.GetName (typeof (ColorNames), colorName);
+ var r = Convert.ToInt32 (rText + rText, 16);
+ var g = Convert.ToInt32 (gText + gText, 16);
+ var b = Convert.ToInt32 (bText + bText, 16);
+ color = new Color (r, g, b);
}
- // Otherwise return as an RGB hex value.
- return $"#{R:X2}{G:X2}{B:X2}";
+ return true;
}
+
+ // #RRGGBB, #RGBA
+ if ((text [0] == '#') && text.Length is 8 or 5) {
+ if (text.Length == 7) {
+ var r = Convert.ToInt32 (text.Substring (1, 2), 16);
+ var g = Convert.ToInt32 (text.Substring (3, 2), 16);
+ var b = Convert.ToInt32 (text.Substring (5, 2), 16);
+ var a = Convert.ToInt32 (text.Substring (7, 2), 16);
+ color = new Color (a, r, g, b);
+ } else {
+ var rText = char.ToString (text [1]);
+ var gText = char.ToString (text [2]);
+ var bText = char.ToString (text [3]);
+ var aText = char.ToString (text [4]);
+
+ var r = Convert.ToInt32 (aText + aText, 16);
+ var g = Convert.ToInt32 (rText + rText, 16);
+ var b = Convert.ToInt32 (gText + gText, 16);
+ var a = Convert.ToInt32 (bText + bText, 16);
+ color = new Color (r, g, b, a);
+ }
+ return true;
+ }
+
+ // rgb(r,g,b)
+ var match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+)\)");
+ if (match.Success) {
+ var r = int.Parse (match.Groups [1].Value);
+ var g = int.Parse (match.Groups [2].Value);
+ var b = int.Parse (match.Groups [3].Value);
+ color = new Color (r, g, b);
+ return true;
+ }
+
+ // rgb(r,g,b,a)
+ match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+),(\d+)\)");
+ if (match.Success) {
+ var r = int.Parse (match.Groups [1].Value);
+ var g = int.Parse (match.Groups [2].Value);
+ var b = int.Parse (match.Groups [3].Value);
+ var a = int.Parse (match.Groups [4].Value);
+ color = new Color (r, g, b, a);
+ return true;
+ }
+
+ if (Enum.TryParse (text, ignoreCase: true, out ColorName colorName)) {
+ color = new Color (colorName);
+ return true;
+ }
+
+ color = null;
+ return false;
+ }
+
+ #region Operators
+ ///
+ /// Cast from int.
+ ///
+ ///
+ public static implicit operator Color (int rgba)
+ {
+ return new Color (rgba);
}
///
- /// Attributes represent how text is styled when displayed in the terminal.
+ /// Cast to int.
///
- ///
- /// provides a platform independent representation of colors (and someday other forms of text styling).
- /// 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.
- ///
- [JsonConverter (typeof (AttributeJsonConverter))]
- public readonly struct Attribute : IEquatable {
-
- ///
- /// Default empty attribute.
- ///
- public static readonly Attribute Default = new Attribute (Color.White, Color.Black);
-
- ///
- /// The -specific color value.
- ///
- [JsonIgnore (Condition = JsonIgnoreCondition.Always)]
- internal int PlatformColor { get; }
-
- ///
- /// The foreground color.
- ///
- [JsonConverter (typeof (ColorJsonConverter))]
- public Color Foreground { get; private init; }
-
- ///
- /// The background color.
- ///
- [JsonConverter (typeof (ColorJsonConverter))]
- public Color Background { get; private init; }
-
- ///
- /// Initializes a new instance with default values.
- ///
- public Attribute ()
- {
- var d = Default;
- PlatformColor = -1;
- Foreground = d.Foreground;
- Background = d.Background;
- }
-
- ///
- /// Initializes a new instance with platform specific color value.
- ///
- /// Value.
- internal Attribute (int platformColor) : this (platformColor, Default.Foreground, Default.Background) { }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// platform-dependent color value.
- /// Foreground
- /// Background
- internal Attribute (int platformColor, Color foreground, Color background)
- {
- Foreground = foreground;
- Background = background;
- PlatformColor = platformColor;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// platform-dependent color value.
- /// Foreground
- /// Background
- internal Attribute (int platformColor, ColorNames foreground, ColorNames background) : this (platformColor, (Color)foreground, (Color)background) { }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// Foreground
- /// Background
- public Attribute (Color foreground, Color background)
- {
- Foreground = foreground;
- Background = background;
-
- if (Application.Driver == null) {
- PlatformColor = -1;
- return;
- }
-
- var make = Application.Driver.MakeAttribute (foreground, background);
- PlatformColor = make.PlatformColor;
- }
-
- ///
- /// Initializes a new instance with a value. Both and
- /// will be set to the specified color.
- ///
- /// Value.
- internal Attribute (ColorNames colorName) : this (colorName, colorName) { }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// Foreground
- /// Background
- public Attribute (ColorNames foregroundName, ColorNames backgroundName) : this (new Color (foregroundName), new Color (backgroundName)) { }
-
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// Foreground
- /// Background
- public Attribute (ColorNames foregroundName, Color background) : this (new Color (foregroundName), background) { }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// Foreground
- /// Background
- public Attribute (Color foreground, ColorNames backgroundName) : this (foreground, new Color (backgroundName)) { }
-
- ///
- /// Initializes a new instance of the struct
- /// with the same colors for the foreground and background.
- ///
- /// The color.
- public Attribute (Color color) : this (color, color) { }
-
-
- ///
- /// Compares two attributes for equality.
- ///
- ///
- ///
- ///
- public static bool operator == (Attribute left, Attribute right) => left.Equals (right);
-
- ///
- /// Compares two attributes for inequality.
- ///
- ///
- ///
- ///
- public static bool operator != (Attribute left, Attribute right) => !(left == right);
-
- ///
- public override bool Equals (object obj)
- {
- return obj is Attribute other && Equals (other);
- }
-
- ///
- public bool Equals (Attribute other)
- {
- return PlatformColor == other.PlatformColor &&
- Foreground == other.Foreground &&
- Background == other.Background;
- }
-
- ///
- public override int GetHashCode () => HashCode.Combine (PlatformColor, Foreground, Background);
-
- ///
- public override string ToString ()
- {
- // Note, Unit tests are dependent on this format
- return $"{Foreground},{Background}";
- }
+ ///
+ public static explicit operator int (Color color)
+ {
+ return color.Rgba;
}
///
- /// Defines the s for common visible elements in a .
- /// Containers such as and use to determine
- /// the colors used by sub-views.
+ /// Cast from .
///
- ///
- /// See also: .
- ///
- [JsonConverter (typeof (ColorSchemeJsonConverter))]
- public class ColorScheme : IEquatable {
- Attribute _normal = Attribute.Default;
- Attribute _focus = Attribute.Default;
- Attribute _hotNormal = Attribute.Default;
- Attribute _hotFocus = Attribute.Default;
- Attribute _disabled = Attribute.Default;
-
- ///
- /// Used by and to track which ColorScheme
- /// is being accessed.
- ///
- internal string _schemeBeingSet = "";
-
- ///
- /// Creates a new instance.
- ///
- public ColorScheme () : this (Attribute.Default) { }
-
- ///
- /// Creates a new instance, initialized with the values from .
- ///
- /// The scheme to initialize the new instance with.
- public ColorScheme (ColorScheme scheme) : base ()
- {
- if (scheme != null) {
- _normal = scheme.Normal;
- _focus = scheme.Focus;
- _hotNormal = scheme.HotNormal;
- _disabled = scheme.Disabled;
- _hotFocus = scheme.HotFocus;
- }
- }
-
- ///
- /// Creates a new instance, initialized with the values from .
- ///
- /// The attribute to initialize the new instance with.
- public ColorScheme (Attribute attribute)
- {
- _normal = attribute;
- _focus = attribute;
- _hotNormal = attribute;
- _disabled = attribute;
- _hotFocus = attribute;
- }
-
- ///
- /// The foreground and background color for text when the view is not focused, hot, or disabled.
- ///
- public Attribute Normal {
- get => _normal;
- set => _normal = value;
- }
-
- ///
- /// The foreground and background color for text when the view has the focus.
- ///
- public Attribute Focus {
- get => _focus;
- set => _focus = value;
- }
-
- ///
- /// The foreground and background color for text when the view is highlighted (hot).
- ///
- public Attribute HotNormal {
- get => _hotNormal;
- set => _hotNormal = value;
- }
-
- ///
- /// The foreground and background color for text when the view is highlighted (hot) and has focus.
- ///
- public Attribute HotFocus {
- get => _hotFocus;
- set => _hotFocus = value;
- }
-
- ///
- /// The default foreground and background color for text, when the view is disabled.
- ///
- public Attribute Disabled {
- get => _disabled;
- set => _disabled = value;
- }
-
- ///
- /// Compares two objects for equality.
- ///
- ///
- /// true if the two objects are equal
- public override bool Equals (object obj)
- {
- return Equals (obj as ColorScheme);
- }
-
- ///
- /// Compares two objects for equality.
- ///
- ///
- /// true if the two objects are equal
- 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);
- }
-
- ///
- /// Returns a hashcode for this instance.
- ///
- /// hashcode for this instance
- public override int GetHashCode ()
- {
- int hashCode = -1242460230;
- hashCode = hashCode * -1521134295 + _normal.GetHashCode ();
- hashCode = hashCode * -1521134295 + _focus.GetHashCode ();
- hashCode = hashCode * -1521134295 + _hotNormal.GetHashCode ();
- hashCode = hashCode * -1521134295 + _hotFocus.GetHashCode ();
- hashCode = hashCode * -1521134295 + _disabled.GetHashCode ();
- return hashCode;
- }
-
- ///
- /// Compares two objects for equality.
- ///
- ///
- ///
- /// true if the two objects are equivalent
- public static bool operator == (ColorScheme left, ColorScheme right)
- {
- return EqualityComparer.Default.Equals (left, right);
- }
-
- ///
- /// Compares two objects for inequality.
- ///
- ///
- ///
- /// true if the two objects are not equivalent
- public static bool operator != (ColorScheme left, ColorScheme right)
- {
- return !(left == right);
- }
+ ///
+ public static explicit operator Color (ColorName colorName)
+ {
+ return new Color (colorName);
}
///
- /// The default s for the application.
+ /// Cast to .
///
- ///
- /// 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 string.Equals (x, y, StringComparison.InvariantCultureIgnoreCase);
- }
- 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.
- return typeof (Colors).GetProperties ()
- .Where (p => p.PropertyType == typeof (ColorScheme))
- .Select (p => new KeyValuePair (p.Name, new ColorScheme ()))
- .ToDictionary (t => t.Key, t => t.Value, comparer: new SchemeNameComparerIgnoreCase ());
- }
-
- ///
- /// The application Toplevel color scheme, for the default Toplevel views.
- ///
- ///
- ///
- /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["TopLevel"];
- ///
- ///
- public static ColorScheme TopLevel { get => GetColorScheme (); set => SetColorScheme (value); }
-
- ///
- /// The base color scheme, for the default Toplevel views.
- ///
- ///
- ///
- /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Base"];
- ///
- ///
- public static ColorScheme Base { get => GetColorScheme (); set => SetColorScheme (value); }
-
- ///
- /// The dialog color scheme, for standard popup dialog boxes
- ///
- ///
- ///
- /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Dialog"];
- ///
- ///
- public static ColorScheme Dialog { get => GetColorScheme (); set => SetColorScheme (value); }
-
- ///
- /// The menu bar color
- ///
- ///
- ///
- /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Menu"];
- ///
- ///
- public static ColorScheme Menu { get => GetColorScheme (); set => SetColorScheme (value); }
-
- ///
- /// The color scheme for showing errors.
- ///
- ///
- ///
- /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Error"];
- ///
- ///
- public static ColorScheme Error { get => GetColorScheme (); set => SetColorScheme (value); }
-
- static ColorScheme GetColorScheme ([CallerMemberName] string schemeBeingSet = null)
- {
- return ColorSchemes [schemeBeingSet];
- }
-
- static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string schemeBeingSet = null)
- {
- ColorSchemes [schemeBeingSet] = colorScheme;
- colorScheme._schemeBeingSet = schemeBeingSet;
- }
-
- ///
- /// Provides the defined s.
- ///
- [SerializableConfigurationProperty (Scope = typeof (ThemeScope), OmitClassName = true)]
- [JsonConverter (typeof (DictionaryJsonConverter))]
- public static Dictionary ColorSchemes { get; private set; }
+ ///
+ public static explicit operator ColorName (Color color)
+ {
+ return color.ColorName;
}
+
+ ///
+ /// Equality operator for two objects..
+ ///
+ ///
+ ///
+ ///
+ public static bool operator == (Color left, Color right)
+ {
+ if (left is null && right is null)
+ return true;
+
+ if (left is null || right is null)
+ return false;
+
+ return left.Equals (right);
+ }
+
+
+ ///
+ /// Inequality operator for two objects.
+ ///
+ ///
+ ///
+ ///
+ public static bool operator != (Color left, Color right)
+ {
+ if (left is null && right is null)
+ return false;
+
+ if (left is null || right is null)
+ return true;
+
+ return !left.Equals (right);
+ }
+
+ ///
+ /// Equality operator for and objects.
+ ///
+ ///
+ ///
+ ///
+ public static bool operator == (ColorName left, Color right)
+ {
+ return left == right.ColorName;
+ }
+
+ ///
+ /// Inequality operator for and objects.
+ ///
+ ///
+ ///
+ ///
+ public static bool operator != (ColorName left, Color right)
+ {
+ return left != right.ColorName;
+ }
+
+ ///
+ /// Equality operator for and objects.
+ ///
+ ///
+ ///
+ ///
+ public static bool operator == (Color left, ColorName right)
+ {
+ return left.ColorName == right;
+ }
+
+ ///
+ /// Inequality operator for and objects.
+ ///
+ ///
+ ///
+ ///
+ public static bool operator != (Color left, ColorName right)
+ {
+ return left.ColorName != right;
+ }
+
+
+ ///
+ public override bool Equals (object obj)
+ {
+ return obj is Color other && Equals (other);
+ }
+
+ ///
+ public bool Equals (Color other)
+ {
+ return
+ R == other.R &&
+ G == other.G &&
+ B == other.B &&
+ A == other.A;
+ }
+
+ ///
+ public override int GetHashCode ()
+ {
+ return HashCode.Combine (R, G, B, A);
+ }
+ #endregion
+
+ ///
+ /// Converts the color to a string representation.
+ ///
+ ///
+ ///
+ /// If the color is a named color, the name is returned. Otherwise, the color is returned as a hex string.
+ ///
+ ///
+ /// (Alpha channel) is ignored and the returned string will not include it.
+ ///
+ ///
+ ///
+ public override string ToString ()
+ {
+ // If Values has an exact match with a named color (in _colorNames), use that.
+ if (_colorToNameMap.TryGetValue (this, out ColorName colorName)) {
+ return Enum.GetName (typeof (ColorName), colorName);
+ }
+ // Otherwise return as an RGB hex value.
+ return $"#{R:X2}{G:X2}{B:X2}";
+ }
+}
+
+///
+/// Attributes represent how text is styled when displayed in the terminal.
+///
+///
+/// provides a platform independent representation of colors (and someday other forms of text styling).
+/// 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.
+///
+[JsonConverter (typeof (AttributeJsonConverter))]
+public readonly struct Attribute : IEquatable {
+
+ ///
+ /// Default empty attribute.
+ ///
+ public static readonly Attribute Default = new Attribute (Color.White, Color.Black);
+
+ ///
+ /// The -specific color value.
+ ///
+ [JsonIgnore (Condition = JsonIgnoreCondition.Always)]
+ internal int PlatformColor { get; }
+
+ ///
+ /// The foreground color.
+ ///
+ [JsonConverter (typeof (ColorJsonConverter))]
+ public Color Foreground { get; private init; }
+
+ ///
+ /// The background color.
+ ///
+ [JsonConverter (typeof (ColorJsonConverter))]
+ public Color Background { get; private init; }
+
+ ///
+ /// Initializes a new instance with default values.
+ ///
+ public Attribute ()
+ {
+ var d = Default;
+ PlatformColor = -1;
+ Foreground = d.Foreground;
+ Background = d.Background;
+ }
+
+ ///
+ /// Initializes a new instance with platform specific color value.
+ ///
+ /// Value.
+ internal Attribute (int platformColor) : this (platformColor, Default.Foreground, Default.Background) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// platform-dependent color value.
+ /// Foreground
+ /// Background
+ internal Attribute (int platformColor, Color foreground, Color background)
+ {
+ Foreground = foreground;
+ Background = background;
+ PlatformColor = platformColor;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// platform-dependent color value.
+ /// Foreground
+ /// Background
+ internal Attribute (int platformColor, ColorName foreground, ColorName background) : this (platformColor, (Color)foreground, (Color)background) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Foreground
+ /// Background
+ public Attribute (Color foreground, Color background)
+ {
+ Foreground = foreground;
+ Background = background;
+
+ if (Application.Driver == null) {
+ PlatformColor = -1;
+ return;
+ }
+
+ var make = Application.Driver.MakeAttribute (foreground, background);
+ PlatformColor = make.PlatformColor;
+ }
+
+ ///
+ /// Initializes a new instance with a value. Both and
+ /// will be set to the specified color.
+ ///
+ /// Value.
+ internal Attribute (ColorName colorName) : this (colorName, colorName) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Foreground
+ /// Background
+ public Attribute (ColorName foregroundName, ColorName backgroundName) : this (new Color (foregroundName), new Color (backgroundName)) { }
+
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Foreground
+ /// Background
+ public Attribute (ColorName foregroundName, Color background) : this (new Color (foregroundName), background) { }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// Foreground
+ /// Background
+ public Attribute (Color foreground, ColorName backgroundName) : this (foreground, new Color (backgroundName)) { }
+
+ ///
+ /// Initializes a new instance of the struct
+ /// with the same colors for the foreground and background.
+ ///
+ /// The color.
+ public Attribute (Color color) : this (color, color) { }
+
+
+ ///
+ /// Compares two attributes for equality.
+ ///
+ ///
+ ///
+ ///
+ public static bool operator == (Attribute left, Attribute right) => left.Equals (right);
+
+ ///
+ /// Compares two attributes for inequality.
+ ///
+ ///
+ ///
+ ///
+ public static bool operator != (Attribute left, Attribute right) => !(left == right);
+
+ ///
+ public override bool Equals (object obj)
+ {
+ return obj is Attribute other && Equals (other);
+ }
+
+ ///
+ public bool Equals (Attribute other)
+ {
+ return PlatformColor == other.PlatformColor &&
+ Foreground == other.Foreground &&
+ Background == other.Background;
+ }
+
+ ///
+ public override int GetHashCode () => HashCode.Combine (PlatformColor, Foreground, Background);
+
+ ///
+ public override string ToString ()
+ {
+ // Note, Unit tests are dependent on this format
+ return $"{Foreground},{Background}";
+ }
+}
+
+///
+/// Defines the s for common visible elements in a .
+/// Containers such as and use to determine
+/// the colors used by sub-views.
+///
+///
+/// See also: .
+///
+[JsonConverter (typeof (ColorSchemeJsonConverter))]
+public class ColorScheme : IEquatable {
+ Attribute _normal = Attribute.Default;
+ Attribute _focus = Attribute.Default;
+ Attribute _hotNormal = Attribute.Default;
+ Attribute _hotFocus = Attribute.Default;
+ Attribute _disabled = Attribute.Default;
+
+ ///
+ /// Used by and to track which ColorScheme
+ /// is being accessed.
+ ///
+ internal string _schemeBeingSet = "";
+
+ ///
+ /// Creates a new instance.
+ ///
+ public ColorScheme () : this (Attribute.Default) { }
+
+ ///
+ /// Creates a new instance, initialized with the values from .
+ ///
+ /// The scheme to initialize the new instance with.
+ public ColorScheme (ColorScheme scheme) : base ()
+ {
+ if (scheme != null) {
+ _normal = scheme.Normal;
+ _focus = scheme.Focus;
+ _hotNormal = scheme.HotNormal;
+ _disabled = scheme.Disabled;
+ _hotFocus = scheme.HotFocus;
+ }
+ }
+
+ ///
+ /// Creates a new instance, initialized with the values from .
+ ///
+ /// The attribute to initialize the new instance with.
+ public ColorScheme (Attribute attribute)
+ {
+ _normal = attribute;
+ _focus = attribute;
+ _hotNormal = attribute;
+ _disabled = attribute;
+ _hotFocus = attribute;
+ }
+
+ ///
+ /// The foreground and background color for text when the view is not focused, hot, or disabled.
+ ///
+ public Attribute Normal {
+ get => _normal;
+ set => _normal = value;
+ }
+
+ ///
+ /// The foreground and background color for text when the view has the focus.
+ ///
+ public Attribute Focus {
+ get => _focus;
+ set => _focus = value;
+ }
+
+ ///
+ /// The foreground and background color for text when the view is highlighted (hot).
+ ///
+ public Attribute HotNormal {
+ get => _hotNormal;
+ set => _hotNormal = value;
+ }
+
+ ///
+ /// The foreground and background color for text when the view is highlighted (hot) and has focus.
+ ///
+ public Attribute HotFocus {
+ get => _hotFocus;
+ set => _hotFocus = value;
+ }
+
+ ///
+ /// The default foreground and background color for text, when the view is disabled.
+ ///
+ public Attribute Disabled {
+ get => _disabled;
+ set => _disabled = value;
+ }
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// true if the two objects are equal
+ public override bool Equals (object obj)
+ {
+ return Equals (obj as ColorScheme);
+ }
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// true if the two objects are equal
+ 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);
+ }
+
+ ///
+ /// Returns a hashcode for this instance.
+ ///
+ /// hashcode for this instance
+ public override int GetHashCode ()
+ {
+ int hashCode = -1242460230;
+ hashCode = hashCode * -1521134295 + _normal.GetHashCode ();
+ hashCode = hashCode * -1521134295 + _focus.GetHashCode ();
+ hashCode = hashCode * -1521134295 + _hotNormal.GetHashCode ();
+ hashCode = hashCode * -1521134295 + _hotFocus.GetHashCode ();
+ hashCode = hashCode * -1521134295 + _disabled.GetHashCode ();
+ return hashCode;
+ }
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ ///
+ /// true if the two objects are equivalent
+ public static bool operator == (ColorScheme left, ColorScheme right)
+ {
+ return EqualityComparer.Default.Equals (left, right);
+ }
+
+ ///
+ /// Compares two objects for inequality.
+ ///
+ ///
+ ///
+ /// true if the two objects are not equivalent
+ public static bool operator != (ColorScheme left, ColorScheme right)
+ {
+ return !(left == right);
+ }
+}
+
+///
+/// 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 string.Equals (x, y, StringComparison.InvariantCultureIgnoreCase);
+ }
+ 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.
+ return typeof (Colors).GetProperties ()
+ .Where (p => p.PropertyType == typeof (ColorScheme))
+ .Select (p => new KeyValuePair (p.Name, new ColorScheme ()))
+ .ToDictionary (t => t.Key, t => t.Value, comparer: new SchemeNameComparerIgnoreCase ());
+ }
+
+ ///
+ /// The application Toplevel color scheme, for the default Toplevel views.
+ ///
+ ///
+ ///
+ /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["TopLevel"];
+ ///
+ ///
+ public static ColorScheme TopLevel { get => GetColorScheme (); set => SetColorScheme (value); }
+
+ ///
+ /// The base color scheme, for the default Toplevel views.
+ ///
+ ///
+ ///
+ /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Base"];
+ ///
+ ///
+ public static ColorScheme Base { get => GetColorScheme (); set => SetColorScheme (value); }
+
+ ///
+ /// The dialog color scheme, for standard popup dialog boxes
+ ///
+ ///
+ ///
+ /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Dialog"];
+ ///
+ ///
+ public static ColorScheme Dialog { get => GetColorScheme (); set => SetColorScheme (value); }
+
+ ///
+ /// The menu bar color
+ ///
+ ///
+ ///
+ /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Menu"];
+ ///
+ ///
+ public static ColorScheme Menu { get => GetColorScheme (); set => SetColorScheme (value); }
+
+ ///
+ /// The color scheme for showing errors.
+ ///
+ ///
+ ///
+ /// This API will be deprecated in the future. Use instead (e.g. edit.ColorScheme = Colors.ColorSchemes["Error"];
+ ///
+ ///
+ public static ColorScheme Error { get => GetColorScheme (); set => SetColorScheme (value); }
+
+ static ColorScheme GetColorScheme ([CallerMemberName] string schemeBeingSet = null)
+ {
+ return ColorSchemes [schemeBeingSet];
+ }
+
+ static void SetColorScheme (ColorScheme colorScheme, [CallerMemberName] string schemeBeingSet = null)
+ {
+ ColorSchemes [schemeBeingSet] = colorScheme;
+ colorScheme._schemeBeingSet = schemeBeingSet;
+ }
+
+ ///
+ /// Provides the defined s.
+ ///
+ [SerializableConfigurationProperty (Scope = typeof (ThemeScope), OmitClassName = true)]
+ [JsonConverter (typeof (DictionaryJsonConverter))]
+ public static Dictionary ColorSchemes { get; private set; }
}
diff --git a/Terminal.Gui/Views/ColorPicker.cs b/Terminal.Gui/Views/ColorPicker.cs
index 71308543b..f41aa5b68 100644
--- a/Terminal.Gui/Views/ColorPicker.cs
+++ b/Terminal.Gui/Views/ColorPicker.cs
@@ -81,7 +81,7 @@ namespace Terminal.Gui {
set {
var colorIndex = value.Y * _cols + value.X;
- SelectedColor = (ColorNames)colorIndex;
+ SelectedColor = (ColorName)colorIndex;
}
}
@@ -93,13 +93,13 @@ namespace Terminal.Gui {
///
/// Selected color.
///
- public ColorNames SelectedColor {
+ public ColorName SelectedColor {
get {
- return (ColorNames)_selectColorIndex;
+ return (ColorName)_selectColorIndex;
}
set {
- ColorNames prev = (ColorNames)_selectColorIndex;
+ ColorName prev = (ColorName)_selectColorIndex;
_selectColorIndex = (int)value;
ColorChanged?.Invoke (this, new ColorEventArgs () {
PreviousColor = new Color (prev),
@@ -160,7 +160,7 @@ namespace Terminal.Gui {
for (var y = 0; y < (Bounds.Height / BoxHeight); y++) {
for (var x = 0; x < (Bounds.Width / BoxWidth); x++) {
var foregroundColorIndex = y == 0 ? colorIndex + _cols : colorIndex - _cols;
- Driver.SetAttribute (new Attribute ((ColorNames)foregroundColorIndex, (ColorNames)colorIndex));
+ Driver.SetAttribute (new Attribute ((ColorName)foregroundColorIndex, (ColorName)colorIndex));
var selected = x == Cursor.X && y == Cursor.Y;
DrawColorBox (x, y, selected);
colorIndex++;
diff --git a/UICatalog/Scenarios/BasicColors.cs b/UICatalog/Scenarios/BasicColors.cs
index 908e7cd7b..4ca1594a7 100644
--- a/UICatalog/Scenarios/BasicColors.cs
+++ b/UICatalog/Scenarios/BasicColors.cs
@@ -10,10 +10,10 @@ namespace UICatalog.Scenarios {
var vx = 30;
var x = 30;
var y = 14;
- var colors = System.Enum.GetValues (typeof (ColorNames));
+ var colors = System.Enum.GetValues (typeof (ColorName));
- foreach (ColorNames bg in colors) {
+ foreach (ColorName bg in colors) {
Attribute attr = new Attribute (bg, colors.Length - 1 - bg);
var vl = new Label (bg.ToString (), TextDirection.TopBottom_LeftRight) {
X = vx,
@@ -34,7 +34,7 @@ namespace UICatalog.Scenarios {
};
Win.Add (hl);
vx++;
- foreach (ColorNames fg in colors) {
+ foreach (ColorName fg in colors) {
var c = new Attribute (fg, bg);
var t = x.ToString ();
var l = new Label (x, y, t [t.Length - 1].ToString ()) {
diff --git a/UICatalog/Scenarios/GraphViewExample.cs b/UICatalog/Scenarios/GraphViewExample.cs
index 06e54232a..be945b7db 100644
--- a/UICatalog/Scenarios/GraphViewExample.cs
+++ b/UICatalog/Scenarios/GraphViewExample.cs
@@ -96,7 +96,7 @@ namespace UICatalog.Scenarios {
about.Text = "Housing Expenditures by income thirds 1996-2003";
- var fore = graphView.ColorScheme.Normal.Foreground == new Color(ColorNames.Black) ? new Color(ColorNames.White) : graphView.ColorScheme.Normal.Foreground;
+ var fore = graphView.ColorScheme.Normal.Foreground == new Color(ColorName.Black) ? new Color(ColorName.White) : graphView.ColorScheme.Normal.Foreground;
var black = new Attribute (fore, Color.Black);
var cyan = new Attribute (Color.BrightCyan, Color.Black);
var magenta = new Attribute (Color.BrightMagenta, Color.Black);
diff --git a/UICatalog/Scenarios/InvertColors.cs b/UICatalog/Scenarios/InvertColors.cs
index 01726fde0..8105f98eb 100644
--- a/UICatalog/Scenarios/InvertColors.cs
+++ b/UICatalog/Scenarios/InvertColors.cs
@@ -13,7 +13,7 @@ namespace UICatalog.Scenarios {
Win.ColorScheme = Colors.TopLevel;
List