mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2026-01-01 08:50:25 +01:00
* Add W3C color enum with the RGB as numeric value * Add transform helper class for W3cColor enum For the sake of backwards compatibility prioritize parsing 16 color mode color names over the W3C colors because the previous resource-based color names/values had a mix of W3C and 16 color mode RGB values. Mechanism for choosing/prioritizing one color scheme over the other is currently only available at higher application/driver/output level. * IColorNameResolver enable null analysis * Remove obsolete color name related ResourceManagerTests * Replace remains of W3CColors with direct W3C color name resolver Temporarily breaks backwards compatibility and tests even further. * Add ANSI 4-bit (ColorName16) color name resolver * Add multi-standard color name resolver Combined resolver for both ANSI 4-bit (ColorName16) and W3C colors while trying to maintain backwards compatibility for ColorPicker. * Split conditional name resolver test cases * Change W3C colors tests to be similar to name resolvers * Change W3cColorsTests to W3cColorNameResolverTests More consistent when all the tests refer to the color name resolver layer. * Make W3cColors internal Color name resolver is the public interface. * W3cColors: Use Color.Argb instead of individual RGB components * MultiStandardColorNameResolver: Substitute instead of blocking alternative W3C names Changes color picker behavior a bit, e.g. Aqua will match to Cyan instead of jumping to Aquamarine. * Remove leftover color string resources * Consistent position for IColorNameResolver #nullable enable directive * Add missing XML comments to ColorScheme.Colors.cs
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using ColorHelper;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
@@ -40,11 +39,9 @@ internal class ColorJsonConverter : JsonConverter<Color>
|
||||
// Get the color string
|
||||
ReadOnlySpan<char> colorString = reader.GetString ();
|
||||
|
||||
// Check if the color string is a color name
|
||||
if (ColorStrings.TryParseW3CColorName (colorString.ToString (), out Color color1))
|
||||
if (ColorStrings.TryParseNamedColor (colorString, out Color namedColor))
|
||||
{
|
||||
// Return the parsed color
|
||||
return new (color1);
|
||||
return namedColor;
|
||||
}
|
||||
|
||||
if (Color.TryParse (colorString, null, out Color parsedColor))
|
||||
|
||||
70
Terminal.Gui/Drawing/Color/AnsiColorNameResolver.cs
Normal file
70
Terminal.Gui/Drawing/Color/AnsiColorNameResolver.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Color name resolver for <see cref="ColorName16"/>.
|
||||
/// </summary>
|
||||
public class AnsiColorNameResolver : IColorNameResolver
|
||||
{
|
||||
private static readonly ImmutableArray<string> AnsiColorNames = ImmutableArray.Create(Enum.GetNames<ColorName16>());
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<string> GetColorNames ()
|
||||
{
|
||||
return AnsiColorNames;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryNameColor (Color color, [NotNullWhen (true)] out string? name)
|
||||
{
|
||||
if (Color.TryGetExactNamedColor16 (color, out ColorName16 colorName16))
|
||||
{
|
||||
name = Color16Name (colorName16);
|
||||
return true;
|
||||
}
|
||||
name = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryParseColor (ReadOnlySpan<char> name, out Color color)
|
||||
{
|
||||
if (Enum.TryParse (name, ignoreCase: true, out ColorName16 colorName16) &&
|
||||
// Any numerical value converts to undefined enum value.
|
||||
Enum.IsDefined (colorName16))
|
||||
{
|
||||
color = new Color (colorName16);
|
||||
return true;
|
||||
}
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string Color16Name (ColorName16 color16)
|
||||
{
|
||||
return color16 switch
|
||||
{
|
||||
ColorName16.Black => nameof (ColorName16.Black),
|
||||
ColorName16.Blue => nameof (ColorName16.Blue),
|
||||
ColorName16.Green => nameof (ColorName16.Green),
|
||||
ColorName16.Cyan => nameof (ColorName16.Cyan),
|
||||
ColorName16.Red => nameof (ColorName16.Red),
|
||||
ColorName16.Magenta => nameof (ColorName16.Magenta),
|
||||
ColorName16.Yellow => nameof (ColorName16.Yellow),
|
||||
ColorName16.Gray => nameof (ColorName16.Gray),
|
||||
ColorName16.DarkGray => nameof (ColorName16.DarkGray),
|
||||
ColorName16.BrightBlue => nameof (ColorName16.BrightBlue),
|
||||
ColorName16.BrightGreen => nameof (ColorName16.BrightGreen),
|
||||
ColorName16.BrightCyan => nameof (ColorName16.BrightCyan),
|
||||
ColorName16.BrightRed => nameof (ColorName16.BrightRed),
|
||||
ColorName16.BrightMagenta => nameof (ColorName16.BrightMagenta),
|
||||
ColorName16.BrightYellow => nameof (ColorName16.BrightYellow),
|
||||
ColorName16.White => nameof (ColorName16.White),
|
||||
_ => throw new NotSupportedException ($"ColorName16 '{color16}' is not supported.")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
#nullable enable
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@@ -267,90 +266,79 @@ public readonly partial record struct Color
|
||||
return text switch
|
||||
{
|
||||
// Null string or empty span provided
|
||||
{ IsEmpty: true } when formatProvider is null => throw new ColorParseException (
|
||||
in text,
|
||||
"The text provided was null or empty.",
|
||||
in text
|
||||
),
|
||||
{ IsEmpty: true } when formatProvider is null =>
|
||||
throw new ColorParseException (in text, "The text provided was null or empty.", in text),
|
||||
|
||||
// A valid ICustomColorFormatter was specified and the text wasn't null or empty
|
||||
{ IsEmpty: false } when formatProvider is ICustomColorFormatter f => f.Parse (text),
|
||||
|
||||
// Input string is only whitespace
|
||||
{ Length: > 0 } when text.IsWhiteSpace () => throw new ColorParseException (
|
||||
in text,
|
||||
"The text provided consisted of only whitespace characters.",
|
||||
in text
|
||||
),
|
||||
{ Length: > 0 } when text.IsWhiteSpace () =>
|
||||
throw new ColorParseException (in text, "The text provided consisted of only whitespace characters.", in text),
|
||||
|
||||
// Any string too short to possibly be any supported format.
|
||||
{ Length: > 0 and < 3 } => throw new ColorParseException (
|
||||
in text,
|
||||
"Text was too short to be any possible supported format.",
|
||||
in text
|
||||
),
|
||||
{ Length: > 0 and < 3 } =>
|
||||
throw new ColorParseException (in text, "Text was too short to be any possible supported format.", in text),
|
||||
|
||||
// The various hexadecimal cases
|
||||
['#', ..] hexString => hexString switch
|
||||
{
|
||||
// #RGB
|
||||
['#', var rChar, var gChar, var bChar] chars when chars [1..]
|
||||
.IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([rChar, rChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([gChar, gChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([bChar, bChar], NumberStyles.HexNumber)
|
||||
),
|
||||
// The various hexadecimal cases
|
||||
['#', ..] hexString => hexString switch
|
||||
{
|
||||
// #RGB
|
||||
['#', var rChar, var gChar, var bChar] chars when chars [1..]
|
||||
.IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([rChar, rChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([gChar, gChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([bChar, bChar], NumberStyles.HexNumber)
|
||||
),
|
||||
|
||||
// #ARGB
|
||||
['#', var aChar, var rChar, var gChar, var bChar] chars when chars [1..]
|
||||
.IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([rChar, rChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([gChar, gChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([bChar, bChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([aChar, aChar], NumberStyles.HexNumber)
|
||||
),
|
||||
// #ARGB
|
||||
['#', var aChar, var rChar, var gChar, var bChar] chars when chars [1..]
|
||||
.IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([rChar, rChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([gChar, gChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([bChar, bChar], NumberStyles.HexNumber),
|
||||
byte.Parse ([aChar, aChar], NumberStyles.HexNumber)
|
||||
),
|
||||
|
||||
// #RRGGBB
|
||||
[
|
||||
'#', var r1Char, var r2Char, var g1Char, var g2Char, var b1Char,
|
||||
var b2Char
|
||||
] chars when chars [1..].IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([r1Char, r2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([g1Char, g2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([b1Char, b2Char], NumberStyles.HexNumber)
|
||||
),
|
||||
// #RRGGBB
|
||||
[
|
||||
'#', var r1Char, var r2Char, var g1Char, var g2Char, var b1Char, var b2Char
|
||||
] chars when chars [1..].IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([r1Char, r2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([g1Char, g2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([b1Char, b2Char], NumberStyles.HexNumber)
|
||||
),
|
||||
|
||||
// #AARRGGBB
|
||||
[
|
||||
'#', var a1Char, var a2Char, var r1Char, var r2Char, var g1Char,
|
||||
var g2Char, var b1Char, var b2Char
|
||||
] chars when chars [1..].IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([r1Char, r2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([g1Char, g2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([b1Char, b2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([a1Char, a2Char], NumberStyles.HexNumber)
|
||||
),
|
||||
_ => throw new ColorParseException (
|
||||
in hexString,
|
||||
$"Color hex string {hexString} was not in a supported format",
|
||||
in hexString
|
||||
)
|
||||
},
|
||||
// #AARRGGBB
|
||||
[
|
||||
'#', var a1Char, var a2Char,
|
||||
var r1Char, var r2Char,
|
||||
var g1Char, var g2Char,
|
||||
var b1Char, var b2Char
|
||||
] chars when chars [1..].IsAllAsciiHexDigits () =>
|
||||
new Color (
|
||||
byte.Parse ([r1Char, r2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([g1Char, g2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([b1Char, b2Char], NumberStyles.HexNumber),
|
||||
byte.Parse ([a1Char, a2Char], NumberStyles.HexNumber)
|
||||
),
|
||||
_ => throw new ColorParseException (
|
||||
in hexString,
|
||||
$"Color hex string {hexString} was not in a supported format",
|
||||
in hexString
|
||||
)
|
||||
},
|
||||
|
||||
// rgb(r,g,b) or rgb(r,g,b,a)
|
||||
['r', 'g', 'b', '(', .., ')'] => ParseRgbaFormat (in text, 4),
|
||||
|
||||
// rgba(r,g,b,a) or rgba(r,g,b)
|
||||
['r', 'g', 'b', 'a', '(', .., ')'] => ParseRgbaFormat (in text, 5),
|
||||
|
||||
// Attempt to parse as a named color from the ColorStrings resources
|
||||
{ } when char.IsLetter (text [0]) && ColorStrings.TryParseW3CColorName (text.ToString (), out Color color) =>
|
||||
new Color (color),
|
||||
// rgb(r,g,b) or rgb(r,g,b,a)
|
||||
['r', 'g', 'b', '(', .., ')'] => ParseRgbaFormat (in text, 4),
|
||||
|
||||
// rgba(r,g,b,a) or rgba(r,g,b)
|
||||
['r', 'g', 'b', 'a', '(', .., ')'] => ParseRgbaFormat (in text, 5),
|
||||
// Attempt named colors
|
||||
{ } when char.IsLetter (text [0]) && ColorStrings.TryParseNamedColor (text, out Color color) => color,
|
||||
// Any other input
|
||||
_ => throw new ColorParseException (in text, "Text did not match any expected format.", in text, [])
|
||||
};
|
||||
@@ -585,11 +573,9 @@ public readonly partial record struct Color
|
||||
[SkipLocalsInit]
|
||||
public override string ToString ()
|
||||
{
|
||||
string? name = ColorStrings.GetW3CColorName (this);
|
||||
|
||||
if (name is { })
|
||||
if (ColorStrings.GetColorName (this) is string colorName)
|
||||
{
|
||||
return name;
|
||||
return colorName;
|
||||
}
|
||||
|
||||
return $"#{R:X2}{G:X2}{B:X2}";
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#nullable enable
|
||||
using System.Collections.Frozen;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -236,6 +234,15 @@ public readonly partial record struct Color : ISpanParsable<Color>, IUtf8SpanPar
|
||||
return ColorExtensions.ColorToName16Map.MinBy (pair => CalculateColorDistance (inputColor, pair.Key)).Value;
|
||||
}
|
||||
|
||||
/// <summary>Converts the given color value to exact named color represented by <see cref="ColorName16"/>.</summary>
|
||||
/// <param name="inputColor"></param>
|
||||
/// <param name="colorName16">Successfully converted named color.</param>
|
||||
/// <returns>True if conversion succeeded; otherwise false.</returns>
|
||||
internal static bool TryGetExactNamedColor16 (Color inputColor, out ColorName16 colorName16)
|
||||
{
|
||||
return ColorExtensions.ColorToName16Map.TryGetValue (inputColor, out colorName16);
|
||||
}
|
||||
|
||||
[SkipLocalsInit]
|
||||
private static float CalculateColorDistance (in Vector4 color1, in Vector4 color2) { return Vector4.Distance (color1, color2); }
|
||||
|
||||
|
||||
@@ -185,6 +185,11 @@ public sealed class Colors : INotifyCollectionChanged, IDictionary<string, Color
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="ColorSchemes"/> to an array, starting at a particular array index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional array that is the destination of the elements copied from <see cref="ColorSchemes"/>.</param>
|
||||
/// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
|
||||
public void CopyTo (KeyValuePair<string, ColorScheme?> [] array, int arrayIndex)
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -193,6 +198,10 @@ public sealed class Colors : INotifyCollectionChanged, IDictionary<string, Color
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the <see cref="ColorSchemes"/>.
|
||||
/// </summary>
|
||||
/// <returns>An enumerator for the <see cref="ColorSchemes"/>.</returns>
|
||||
public IEnumerator<KeyValuePair<string, ColorScheme?>> GetEnumerator ()
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -206,6 +215,7 @@ public sealed class Colors : INotifyCollectionChanged, IDictionary<string, Color
|
||||
return GetEnumerator ();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove (KeyValuePair<string, ColorScheme?> item)
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -219,6 +229,7 @@ public sealed class Colors : INotifyCollectionChanged, IDictionary<string, Color
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove (string key)
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -245,7 +256,7 @@ public sealed class Colors : INotifyCollectionChanged, IDictionary<string, Color
|
||||
/// <summary>
|
||||
/// Resets the <see cref="ColorSchemes"/> dictionary to its default values.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <returns>The reset <see cref="ColorSchemes"/> dictionary.</returns>
|
||||
public static Dictionary<string, ColorScheme?> Reset ()
|
||||
{
|
||||
lock (_lock)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#nullable enable
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
using System.Resources;
|
||||
using Terminal.Gui.Resources;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
@@ -11,7 +8,9 @@ namespace Terminal.Gui;
|
||||
/// </summary>
|
||||
public static class ColorStrings
|
||||
{
|
||||
// PERFORMANCE: See https://stackoverflow.com/a/15521524/297526 for why GlobalResources.GetString is fast.
|
||||
private static readonly AnsiColorNameResolver Ansi = new();
|
||||
private static readonly W3cColorNameResolver W3c = new();
|
||||
private static readonly MultiStandardColorNameResolver Multi = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the W3C standard string for <paramref name="color"/>.
|
||||
@@ -20,7 +19,39 @@ public static class ColorStrings
|
||||
/// <returns><see langword="null"/> if there is no standard color name for the specified color.</returns>
|
||||
public static string? GetW3CColorName (Color color)
|
||||
{
|
||||
return GlobalResources.GetString ($"#{color.R:X2}{color.G:X2}{color.B:X2}", CultureInfo.CurrentUICulture);
|
||||
if (W3c.TryNameColor (color, out string? name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ANSI 4-bit (16) color name for <paramref name="color"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <returns><see langword="null"/> if there is no standard color name for the specified color.</returns>
|
||||
public static string? GetANSIColor16Name (Color color)
|
||||
{
|
||||
if (Ansi.TryNameColor (color, out string? name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets backwards compatible color name for <paramref name="color"/>.
|
||||
/// </summary>
|
||||
/// <param name="color">The color.</param>
|
||||
/// <returns>Standard color name for the specified color; otherwise <see langword="null"/>.</returns>
|
||||
public static string? GetColorName (Color color)
|
||||
{
|
||||
if (Multi.TryNameColor (color, out string? name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -29,19 +60,7 @@ public static class ColorStrings
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<string> GetW3CColorNames ()
|
||||
{
|
||||
ResourceSet? resourceSet = GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true);
|
||||
if (resourceSet == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (DictionaryEntry entry in resourceSet)
|
||||
{
|
||||
if (entry is { Value: string colorName, Key: string key } && key.StartsWith ('#'))
|
||||
{
|
||||
yield return colorName;
|
||||
}
|
||||
}
|
||||
return W3c.GetColorNames ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,33 +69,68 @@ public static class ColorStrings
|
||||
/// <param name="name">The name to parse.</param>
|
||||
/// <param name="color">If successful, the color.</param>
|
||||
/// <returns><see langword="true"/> if <paramref name="name"/> was parsed successfully.</returns>
|
||||
public static bool TryParseW3CColorName (string name, out Color color)
|
||||
public static bool TryParseW3CColorName (ReadOnlySpan<char> name, out Color color)
|
||||
{
|
||||
foreach (DictionaryEntry entry in GlobalResources.GetResourceSet (CultureInfo.CurrentUICulture, true, true)!)
|
||||
if (W3c.TryParseColor (name, out color))
|
||||
{
|
||||
if (entry.Value is string colorName && colorName.Equals (name, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
}
|
||||
// Backwards compatibility: Also parse #RRGGBB.
|
||||
return TryParseHexColor (name, out color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses <paramref name="name"/> and returns <paramref name="color"/> if name is a ANSI 4-bit standard named color.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to parse.</param>
|
||||
/// <param name="color">If successful, the color.</param>
|
||||
/// <returns><see langword="true"/> if <paramref name="name"/> was parsed successfully.</returns>
|
||||
public static bool TryParseColor16 (ReadOnlySpan<char> name, out Color color)
|
||||
{
|
||||
if (Ansi.TryParseColor (name, out color))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses <paramref name="name"/> and returns <paramref name="color"/> if name is either ANSI 4-bit or W3C standard named color.
|
||||
/// </summary>
|
||||
/// <param name="name">The name to parse.</param>
|
||||
/// <param name="color">If successful, the color.</param>
|
||||
/// <returns><see langword="true"/> if <paramref name="name"/> was parsed successfully.</returns>
|
||||
public static bool TryParseNamedColor (ReadOnlySpan<char> name, out Color color)
|
||||
{
|
||||
if (Multi.TryParseColor (name, out color))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Backwards compatibility: Also parse #RRGGBB.
|
||||
if (TryParseHexColor (name, out color))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryParseHexColor (ReadOnlySpan<char> name, out Color color)
|
||||
{
|
||||
if (name.Length == 7 && name [0] == '#')
|
||||
{
|
||||
if (int.TryParse (name.Slice (1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int r) &&
|
||||
int.TryParse (name.Slice (3, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int g) &&
|
||||
int.TryParse (name.Slice (5, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int b))
|
||||
{
|
||||
return TryParseColorKey (entry.Key.ToString (), out color);
|
||||
color = new Color (r, g, b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return TryParseColorKey (name, out color);
|
||||
|
||||
bool TryParseColorKey (string? key, out Color color)
|
||||
{
|
||||
if (key != null && key.StartsWith ('#') && key.Length == 7)
|
||||
{
|
||||
if (int.TryParse (key.AsSpan (1, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int r) &&
|
||||
int.TryParse (key.AsSpan (3, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int g) &&
|
||||
int.TryParse (key.AsSpan (5, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int b))
|
||||
{
|
||||
color = new Color (r, g, b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
color = default (Color);
|
||||
return false;
|
||||
}
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
namespace Terminal.Gui;
|
||||
#nullable enable
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// When implemented by a class, allows mapping <see cref="Color"/> to
|
||||
@@ -20,7 +24,7 @@ public interface IColorNameResolver
|
||||
/// <param name="color"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
bool TryNameColor (Color color, out string name);
|
||||
bool TryNameColor (Color color, [NotNullWhen(true)]out string? name);
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> if <paramref name="name"/> is a recognized
|
||||
@@ -30,5 +34,5 @@ public interface IColorNameResolver
|
||||
/// <param name="name"></param>
|
||||
/// <param name="color"></param>
|
||||
/// <returns></returns>
|
||||
bool TryParseColor (string name, out Color color);
|
||||
bool TryParseColor (ReadOnlySpan<char> name, out Color color);
|
||||
}
|
||||
|
||||
188
Terminal.Gui/Drawing/Color/MultiStandardColorNameResolver.cs
Normal file
188
Terminal.Gui/Drawing/Color/MultiStandardColorNameResolver.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Backwards compatible(-ish) color name resolver prioritizing ANSI 4-bit (16) colors with fallback to W3C colors.
|
||||
/// </summary>
|
||||
public class MultiStandardColorNameResolver : IColorNameResolver
|
||||
{
|
||||
private static readonly AnsiColorNameResolver Ansi = new();
|
||||
private static readonly W3cColorNameResolver W3c = new();
|
||||
private static readonly FrozenSet<Color> W3cBlockedColors;
|
||||
private static readonly ImmutableArray<string> CombinedColorNames;
|
||||
private static readonly FrozenDictionary<int, (string Name, Color Color)> W3cSubstituteColors;
|
||||
|
||||
static MultiStandardColorNameResolver ()
|
||||
{
|
||||
HashSet<string> combinedNames = new(Ansi.GetColorNames());
|
||||
|
||||
HashSet<Color> w3cInconsistentColors = new();
|
||||
Dictionary<string, Color> w3cSubstituteColors = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
IEnumerable<string> enumerableW3cNames = W3c.GetColorNames ();
|
||||
IReadOnlyList<string> w3cNames = enumerableW3cNames is IReadOnlyList<string> alreadyReadOnlyList
|
||||
? alreadyReadOnlyList
|
||||
: [.. enumerableW3cNames];
|
||||
|
||||
Dictionary<Color, HashSet<string>> w3cColorsWithAlternativeNames = w3cNames
|
||||
.GroupBy(w3cName =>
|
||||
{
|
||||
if (!W3c.TryParseColor(w3cName, out Color w3cColor))
|
||||
{
|
||||
throw new InvalidOperationException ($"W3C color name '{w3cName}' does not resolve to any W3C color.");
|
||||
}
|
||||
return w3cColor;
|
||||
})
|
||||
.Where(g => g.Count() > 1)
|
||||
.ToDictionary(g => g.Key, g => g.ToHashSet());
|
||||
|
||||
// Gather inconsistencies between ANSI and W3C, filter out or substitute problematic W3C colors and names,
|
||||
// and create additional blocklist for W3C colors.
|
||||
// Blocking and filtering is only applied to W3C because this resolver prioritizes ANSI for backwards compatibility.
|
||||
// It would be a lot simpler to just prioritize W3C colors and names.
|
||||
foreach (string w3cName in w3cNames)
|
||||
{
|
||||
if (w3cSubstituteColors.ContainsKey (w3cName))
|
||||
{
|
||||
// Already dealt with alternative name.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!W3c.TryParseColor (w3cName, out Color w3cColor))
|
||||
{
|
||||
// This condition is just inverted to reduce indentation.
|
||||
// Also it should practically never happen if the W3C color name resolver is properly implemented.
|
||||
throw new InvalidOperationException ($"W3C color name '{w3cName}' does not resolve to any color.");
|
||||
}
|
||||
|
||||
if (w3cColorsWithAlternativeNames.TryGetValue (w3cColor, out var names))
|
||||
{
|
||||
bool substituted = false;
|
||||
// Alternative names cause issues with ColorPicker etc. when combined with ANSI and prioritizing ANSI resolver.
|
||||
// For example Aqua is not in ColorName16 but the actual color value resolves to ANSI Cyan
|
||||
// so autocomplete for Aqua suddenly changes to Cyan because they happen to have same color value in both color scheme.
|
||||
// Also DarkGrey would cause inconsistencies because the alternative DarkGray exists in ANSI and has different color value.
|
||||
foreach (string name in names)
|
||||
{
|
||||
if (Ansi.TryParseColor (name, out Color substituteColor))
|
||||
{
|
||||
// Block the W3C color when it is inconsistent with the substitute color
|
||||
// so there is no situation where W3C color -> color name -> ANSI color.
|
||||
if (w3cColor != substituteColor)
|
||||
{
|
||||
w3cInconsistentColors.Add (w3cColor);
|
||||
}
|
||||
|
||||
// Substitute all W3C alternatives to match with the ANSI color to keep colors consistent.
|
||||
foreach (string alternativeName in names)
|
||||
{
|
||||
w3cSubstituteColors.Add (alternativeName, substituteColor);
|
||||
combinedNames.Add (alternativeName);
|
||||
}
|
||||
substituted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (substituted)
|
||||
{
|
||||
// Already dealt with, continue to next W3C color name.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Same name, different ANSI value.
|
||||
// For example both #767676 (ColorName16) and #A9A9A9 (W3C) resolve to DarkGray,
|
||||
// although a bad example because it is already substituted due to also having alternative names.
|
||||
if (Ansi.TryParseColor (w3cName, out Color ansiColor) && w3cColor != ansiColor)
|
||||
{
|
||||
w3cInconsistentColors.Add (w3cColor);
|
||||
continue;
|
||||
}
|
||||
|
||||
combinedNames.Add (w3cName);
|
||||
}
|
||||
|
||||
// TODO: Utilize .NET 9 and later alternative lookup for matching ReadOnlySpan<char> with string.
|
||||
W3cSubstituteColors = w3cSubstituteColors.ToFrozenDictionary (
|
||||
// Workaround for alternative lookup not being available in .NET 8 by matching ReadOnlySpan<char> hash code to string hash code.
|
||||
keySelector: kvp => string.GetHashCode (kvp.Key, StringComparison.OrdinalIgnoreCase),
|
||||
// The string element is for detecting hash collision.
|
||||
elementSelector: kvp => (kvp.Key, kvp.Value));
|
||||
W3cBlockedColors = w3cInconsistentColors.ToFrozenSet ();
|
||||
CombinedColorNames = combinedNames.Order ().ToImmutableArray ();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<string> GetColorNames ()
|
||||
{
|
||||
return CombinedColorNames;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryNameColor (Color color, [NotNullWhen (true)] out string? name)
|
||||
{
|
||||
if (Ansi.TryNameColor (color, out string? ansiName))
|
||||
{
|
||||
name = ansiName;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IsBlockedW3cColor (color) &&
|
||||
W3c.TryNameColor (color, out string? w3cName))
|
||||
{
|
||||
name = w3cName;
|
||||
return true;
|
||||
}
|
||||
|
||||
name = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryParseColor (ReadOnlySpan<char> name, out Color color)
|
||||
{
|
||||
if (Ansi.TryParseColor (name, out color))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetSubstituteW3cColor (name, out color))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (W3c.TryParseColor (name, out color) &&
|
||||
!IsBlockedW3cColor (color))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool GetSubstituteW3cColor (ReadOnlySpan<char> name, out Color substituteColor)
|
||||
{
|
||||
int nameHashCode = string.GetHashCode(name, StringComparison.OrdinalIgnoreCase);
|
||||
if (W3cSubstituteColors.TryGetValue (nameHashCode, out var match) &&
|
||||
match is (string matchName, Color matchColor) &&
|
||||
name.Equals (matchName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
substituteColor = matchColor;
|
||||
return true;
|
||||
}
|
||||
substituteColor = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsBlockedW3cColor (Color color)
|
||||
{
|
||||
return W3cBlockedColors.Contains (color);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class that resolves w3c color names to their hex values
|
||||
/// Based on https://www.w3schools.com/colors/color_tryit.asp
|
||||
/// </summary>
|
||||
public class W3CColors : IColorNameResolver
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<string> GetColorNames () { return ColorStrings.GetW3CColorNames (); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryParseColor (string name, out Color color) { return ColorStrings.TryParseW3CColorName (name, out color); }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryNameColor (Color color, out string name)
|
||||
{
|
||||
string answer = ColorStrings.GetW3CColorName (color);
|
||||
|
||||
name = answer ?? string.Empty;
|
||||
|
||||
return answer != null;
|
||||
}
|
||||
}
|
||||
777
Terminal.Gui/Drawing/Color/W3cColor.cs
Normal file
777
Terminal.Gui/Drawing/Color/W3cColor.cs
Normal file
@@ -0,0 +1,777 @@
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the W3C color names with their RGB values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Based on https://www.w3schools.com/colors/color_tryit.asp page.
|
||||
/// </remarks>
|
||||
public enum W3cColor
|
||||
{
|
||||
/// <summary>
|
||||
/// Alice blue RGB(240, 248, 255).
|
||||
/// </summary>
|
||||
AliceBlue = 0xF0F8FF,
|
||||
|
||||
/// <summary>
|
||||
/// Antique white RGB(250, 235, 215).
|
||||
/// </summary>
|
||||
AntiqueWhite = 0xFAEBD7,
|
||||
|
||||
/// <summary>
|
||||
/// Aqua RGB(0, 255, 255).
|
||||
/// </summary>
|
||||
Aqua = 0x00FFFF,
|
||||
|
||||
/// <summary>
|
||||
/// Aquamarine RGB(127, 255, 212).
|
||||
/// </summary>
|
||||
Aquamarine = 0x7FFFD4,
|
||||
|
||||
/// <summary>
|
||||
/// Azure RGB(240, 255, 255).
|
||||
/// </summary>
|
||||
Azure = 0xF0FFFF,
|
||||
|
||||
/// <summary>
|
||||
/// Beige RGB(245, 245, 220).
|
||||
/// </summary>
|
||||
Beige = 0xF5F5DC,
|
||||
|
||||
/// <summary>
|
||||
/// Bisque RGB(255, 228, 196).
|
||||
/// </summary>
|
||||
Bisque = 0xFFE4C4,
|
||||
|
||||
/// <summary>
|
||||
/// Black RGB(0, 0, 0).
|
||||
/// </summary>
|
||||
Black = 0x000000,
|
||||
|
||||
/// <summary>
|
||||
/// Blanched almond RGB(255, 235, 205).
|
||||
/// </summary>
|
||||
BlanchedAlmond = 0xFFEBCD,
|
||||
|
||||
/// <summary>
|
||||
/// Blue RGB(0, 0, 255).
|
||||
/// </summary>
|
||||
Blue = 0x0000FF,
|
||||
|
||||
/// <summary>
|
||||
/// Blue violet RGB(138, 43, 226).
|
||||
/// </summary>
|
||||
BlueViolet = 0x8A2BE2,
|
||||
|
||||
/// <summary>
|
||||
/// Brown RGB(165, 42, 42).
|
||||
/// </summary>
|
||||
Brown = 0xA52A2A,
|
||||
|
||||
/// <summary>
|
||||
/// Burly wood RGB(222, 184, 135).
|
||||
/// </summary>
|
||||
BurlyWood = 0xDEB887,
|
||||
|
||||
/// <summary>
|
||||
/// Cadet blue RGB(95, 158, 160).
|
||||
/// </summary>
|
||||
CadetBlue = 0x5F9EA0,
|
||||
|
||||
/// <summary>
|
||||
/// Chartreuse RGB(127, 255, 0).
|
||||
/// </summary>
|
||||
Chartreuse = 0x7FFF00,
|
||||
|
||||
/// <summary>
|
||||
/// Chocolate RGB(210, 105, 30).
|
||||
/// </summary>
|
||||
Chocolate = 0xD2691E,
|
||||
|
||||
/// <summary>
|
||||
/// Coral RGB(255, 127, 80).
|
||||
/// </summary>
|
||||
Coral = 0xFF7F50,
|
||||
|
||||
/// <summary>
|
||||
/// Cornflower blue RGB(100, 149, 237).
|
||||
/// </summary>
|
||||
CornflowerBlue = 0x6495ED,
|
||||
|
||||
/// <summary>
|
||||
/// Cornsilk RGB(255, 248, 220).
|
||||
/// </summary>
|
||||
Cornsilk = 0xFFF8DC,
|
||||
|
||||
/// <summary>
|
||||
/// Crimson RGB(220, 20, 60).
|
||||
/// </summary>
|
||||
Crimson = 0xDC143C,
|
||||
|
||||
/// <summary>
|
||||
/// Cyan RGB(0, 255, 255).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="Aqua"/>.
|
||||
/// </remarks>
|
||||
Cyan = Aqua,
|
||||
|
||||
/// <summary>
|
||||
/// Dark blue RGB(0, 0, 139).
|
||||
/// </summary>
|
||||
DarkBlue = 0x00008B,
|
||||
|
||||
/// <summary>
|
||||
/// Dark cyan RGB(0, 139, 139).
|
||||
/// </summary>
|
||||
DarkCyan = 0x008B8B,
|
||||
|
||||
/// <summary>
|
||||
/// Dark goldenrod RGB(184, 134, 11).
|
||||
/// </summary>
|
||||
DarkGoldenrod = 0xB8860B,
|
||||
|
||||
/// <summary>
|
||||
/// Dark gray RGB(169, 169, 169).
|
||||
/// </summary>
|
||||
DarkGray = 0xA9A9A9,
|
||||
|
||||
/// <summary>
|
||||
/// Dark green RGB(0, 100, 0).
|
||||
/// </summary>
|
||||
DarkGreen = 0x006400,
|
||||
|
||||
/// <summary>
|
||||
/// Dark grey RGB(169, 169, 169).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="DarkGray"/>.
|
||||
/// </remarks>
|
||||
DarkGrey = DarkGray,
|
||||
|
||||
/// <summary>
|
||||
/// Dark khaki RGB(189, 183, 107).
|
||||
/// </summary>
|
||||
DarkKhaki = 0xBDB76B,
|
||||
|
||||
/// <summary>
|
||||
/// Dark magenta RGB(139, 0, 139).
|
||||
/// </summary>
|
||||
DarkMagenta = 0x8B008B,
|
||||
|
||||
/// <summary>
|
||||
/// Dark olive green RGB(85, 107, 47).
|
||||
/// </summary>
|
||||
DarkOliveGreen = 0x556B2F,
|
||||
|
||||
/// <summary>
|
||||
/// Dark orange RGB(255, 140, 0).
|
||||
/// </summary>
|
||||
DarkOrange = 0xFF8C00,
|
||||
|
||||
/// <summary>
|
||||
/// Dark orchid RGB(153, 50, 204).
|
||||
/// </summary>
|
||||
DarkOrchid = 0x9932CC,
|
||||
|
||||
/// <summary>
|
||||
/// Dark red RGB(139, 0, 0).
|
||||
/// </summary>
|
||||
DarkRed = 0x8B0000,
|
||||
|
||||
/// <summary>
|
||||
/// Dark salmon RGB(233, 150, 122).
|
||||
/// </summary>
|
||||
DarkSalmon = 0xE9967A,
|
||||
|
||||
/// <summary>
|
||||
/// Dark sea green RGB(143, 188, 143).
|
||||
/// </summary>
|
||||
DarkSeaGreen = 0x8FBC8F,
|
||||
|
||||
/// <summary>
|
||||
/// Dark slate blue RGB(72, 61, 139).
|
||||
/// </summary>
|
||||
DarkSlateBlue = 0x483D8B,
|
||||
|
||||
/// <summary>
|
||||
/// Dark slate gray RGB(47, 79, 79).
|
||||
/// </summary>
|
||||
DarkSlateGray = 0x2F4F4F,
|
||||
|
||||
/// <summary>
|
||||
/// Dark slate grey RGB(47, 79, 79).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="DarkSlateGray"/>.
|
||||
/// </remarks>
|
||||
DarkSlateGrey = DarkSlateGray,
|
||||
|
||||
/// <summary>
|
||||
/// Dark turquoise RGB(0, 206, 209).
|
||||
/// </summary>
|
||||
DarkTurquoise = 0x00CED1,
|
||||
|
||||
/// <summary>
|
||||
/// Dark violet RGB(148, 0, 211).
|
||||
/// </summary>
|
||||
DarkViolet = 0x9400D3,
|
||||
|
||||
/// <summary>
|
||||
/// Deep pink RGB(255, 20, 147).
|
||||
/// </summary>
|
||||
DeepPink = 0xFF1493,
|
||||
|
||||
/// <summary>
|
||||
/// Deep sky blue RGB(0, 191, 255).
|
||||
/// </summary>
|
||||
DeepSkyBlue = 0x00BFFF,
|
||||
|
||||
/// <summary>
|
||||
/// Dim gray RGB(105, 105, 105).
|
||||
/// </summary>
|
||||
DimGray = 0x696969,
|
||||
|
||||
/// <summary>
|
||||
/// Dim grey RGB(105, 105, 105).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="DimGray"/>.
|
||||
/// </remarks>
|
||||
DimGrey = DimGray,
|
||||
|
||||
/// <summary>
|
||||
/// Dodger blue RGB(30, 144, 255).
|
||||
/// </summary>
|
||||
DodgerBlue = 0x1E90FF,
|
||||
|
||||
/// <summary>
|
||||
/// Fire brick RGB(178, 34, 34).
|
||||
/// </summary>
|
||||
FireBrick = 0xB22222,
|
||||
|
||||
/// <summary>
|
||||
/// Floral white RGB(255, 250, 240).
|
||||
/// </summary>
|
||||
FloralWhite = 0xFFFAF0,
|
||||
|
||||
/// <summary>
|
||||
/// Forest green RGB(34, 139, 34).
|
||||
/// </summary>
|
||||
ForestGreen = 0x228B22,
|
||||
|
||||
/// <summary>
|
||||
/// Fuchsia RGB(255, 0, 255).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="Magenta"/>.
|
||||
/// </remarks>
|
||||
Fuchsia = Magenta,
|
||||
|
||||
/// <summary>
|
||||
/// Gainsboro RGB(220, 220, 220).
|
||||
/// </summary>
|
||||
Gainsboro = 0xDCDCDC,
|
||||
|
||||
/// <summary>
|
||||
/// Ghost white RGB(248, 248, 255).
|
||||
/// </summary>
|
||||
GhostWhite = 0xF8F8FF,
|
||||
|
||||
/// <summary>
|
||||
/// Gold RGB(255, 215, 0).
|
||||
/// </summary>
|
||||
Gold = 0xFFD700,
|
||||
|
||||
/// <summary>
|
||||
/// Goldenrod RGB(218, 165, 32).
|
||||
/// </summary>
|
||||
Goldenrod = 0xDAA520,
|
||||
|
||||
/// <summary>
|
||||
/// Gray RGB(128, 128, 128).
|
||||
/// </summary>
|
||||
Gray = 0x808080,
|
||||
|
||||
/// <summary>
|
||||
/// Green RGB(0, 128, 0).
|
||||
/// </summary>
|
||||
Green = 0x008000,
|
||||
|
||||
/// <summary>
|
||||
/// Green yellow RGB(173, 255, 47).
|
||||
/// </summary>
|
||||
GreenYellow = 0xADFF2F,
|
||||
|
||||
/// <summary>
|
||||
/// Grey RGB(128, 128, 128).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="Gray"/>.
|
||||
/// </remarks>
|
||||
Grey = Gray,
|
||||
|
||||
/// <summary>
|
||||
/// Honey dew RGB(240, 255, 240).
|
||||
/// </summary>
|
||||
HoneyDew = 0xF0FFF0,
|
||||
|
||||
/// <summary>
|
||||
/// Hot pink RGB(255, 105, 180).
|
||||
/// </summary>
|
||||
HotPink = 0xFF69B4,
|
||||
|
||||
/// <summary>
|
||||
/// Indian red RGB(205, 92, 92).
|
||||
/// </summary>
|
||||
IndianRed = 0xCD5C5C,
|
||||
|
||||
/// <summary>
|
||||
/// Indigo RGB(75, 0, 130).
|
||||
/// </summary>
|
||||
Indigo = 0x4B0082,
|
||||
|
||||
/// <summary>
|
||||
/// Ivory RGB(255, 255, 240).
|
||||
/// </summary>
|
||||
Ivory = 0xFFFFF0,
|
||||
|
||||
/// <summary>
|
||||
/// Khaki RGB(240, 230, 140).
|
||||
/// </summary>
|
||||
Khaki = 0xF0E68C,
|
||||
|
||||
/// <summary>
|
||||
/// Lavender RGB(230, 230, 250).
|
||||
/// </summary>
|
||||
Lavender = 0xE6E6FA,
|
||||
|
||||
/// <summary>
|
||||
/// Lavender blush RGB(255, 240, 245).
|
||||
/// </summary>
|
||||
LavenderBlush = 0xFFF0F5,
|
||||
|
||||
/// <summary>
|
||||
/// Lawn green RGB(124, 252, 0).
|
||||
/// </summary>
|
||||
LawnGreen = 0x7CFC00,
|
||||
|
||||
/// <summary>
|
||||
/// Lemon chiffon RGB(255, 250, 205).
|
||||
/// </summary>
|
||||
LemonChiffon = 0xFFFACD,
|
||||
|
||||
/// <summary>
|
||||
/// Light blue RGB(173, 216, 230).
|
||||
/// </summary>
|
||||
LightBlue = 0xADD8E6,
|
||||
|
||||
/// <summary>
|
||||
/// Light coral RGB(240, 128, 128).
|
||||
/// </summary>
|
||||
LightCoral = 0xF08080,
|
||||
|
||||
/// <summary>
|
||||
/// Light cyan RGB(224, 255, 255).
|
||||
/// </summary>
|
||||
LightCyan = 0xE0FFFF,
|
||||
|
||||
/// <summary>
|
||||
/// Light goldenrod yellow RGB(250, 250, 210).
|
||||
/// </summary>
|
||||
LightGoldenrodYellow = 0xFAFAD2,
|
||||
|
||||
/// <summary>
|
||||
/// Light gray RGB(211, 211, 211).
|
||||
/// </summary>
|
||||
LightGray = 0xD3D3D3,
|
||||
|
||||
/// <summary>
|
||||
/// Light green RGB(144, 238, 144).
|
||||
/// </summary>
|
||||
LightGreen = 0x90EE90,
|
||||
|
||||
/// <summary>
|
||||
/// Light grey RGB(211, 211, 211).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="LightGray"/>.
|
||||
/// </remarks>
|
||||
LightGrey = LightGray,
|
||||
|
||||
/// <summary>
|
||||
/// Light pink RGB(255, 182, 193).
|
||||
/// </summary>
|
||||
LightPink = 0xFFB6C1,
|
||||
|
||||
/// <summary>
|
||||
/// Light salmon RGB(255, 160, 122).
|
||||
/// </summary>
|
||||
LightSalmon = 0xFFA07A,
|
||||
|
||||
/// <summary>
|
||||
/// Light sea green RGB(32, 178, 170).
|
||||
/// </summary>
|
||||
LightSeaGreen = 0x20B2AA,
|
||||
|
||||
/// <summary>
|
||||
/// Light sky blue RGB(135, 206, 250).
|
||||
/// </summary>
|
||||
LightSkyBlue = 0x87CEFA,
|
||||
|
||||
/// <summary>
|
||||
/// Light slate gray RGB(119, 136, 153).
|
||||
/// </summary>
|
||||
LightSlateGray = 0x778899,
|
||||
|
||||
/// <summary>
|
||||
/// Light slate grey RGB(119, 136, 153).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="LightSlateGray"/>.
|
||||
/// </remarks>
|
||||
LightSlateGrey = LightSlateGray,
|
||||
|
||||
/// <summary>
|
||||
/// Light steel blue RGB(176, 196, 222).
|
||||
/// </summary>
|
||||
LightSteelBlue = 0xB0C4DE,
|
||||
|
||||
/// <summary>
|
||||
/// Light yellow RGB(255, 255, 224).
|
||||
/// </summary>
|
||||
LightYellow = 0xFFFFE0,
|
||||
|
||||
/// <summary>
|
||||
/// Lime RGB(0, 255, 0).
|
||||
/// </summary>
|
||||
Lime = 0x00FF00,
|
||||
|
||||
/// <summary>
|
||||
/// Lime green RGB(50, 205, 50).
|
||||
/// </summary>
|
||||
LimeGreen = 0x32CD32,
|
||||
|
||||
/// <summary>
|
||||
/// Linen RGB(250, 240, 230).
|
||||
/// </summary>
|
||||
Linen = 0xFAF0E6,
|
||||
|
||||
/// <summary>
|
||||
/// Magenta RGB(255, 0, 255).
|
||||
/// </summary>
|
||||
Magenta = 0xFF00FF,
|
||||
|
||||
/// <summary>
|
||||
/// Maroon RGB(128, 0, 0).
|
||||
/// </summary>
|
||||
Maroon = 0x800000,
|
||||
|
||||
/// <summary>
|
||||
/// Medium aqua marine RGB(102, 205, 170).
|
||||
/// </summary>
|
||||
MediumAquaMarine = 0x66CDAA,
|
||||
|
||||
/// <summary>
|
||||
/// Medium blue RGB(0, 0, 205).
|
||||
/// </summary>
|
||||
MediumBlue = 0x0000CD,
|
||||
|
||||
/// <summary>
|
||||
/// Medium orchid RGB(186, 85, 211).
|
||||
/// </summary>
|
||||
MediumOrchid = 0xBA55D3,
|
||||
|
||||
/// <summary>
|
||||
/// Medium purple RGB(147, 112, 219).
|
||||
/// </summary>
|
||||
MediumPurple = 0x9370DB,
|
||||
|
||||
/// <summary>
|
||||
/// Medium sea green RGB(60, 179, 113).
|
||||
/// </summary>
|
||||
MediumSeaGreen = 0x3CB371,
|
||||
|
||||
/// <summary>
|
||||
/// Medium slate blue RGB(123, 104, 238).
|
||||
/// </summary>
|
||||
MediumSlateBlue = 0x7B68EE,
|
||||
|
||||
/// <summary>
|
||||
/// Medium spring green RGB(0, 250, 154).
|
||||
/// </summary>
|
||||
MediumSpringGreen = 0x00FA9A,
|
||||
|
||||
/// <summary>
|
||||
/// Medium turquoise RGB(72, 209, 204).
|
||||
/// </summary>
|
||||
MediumTurquoise = 0x48D1CC,
|
||||
|
||||
/// <summary>
|
||||
/// Medium violet red RGB(199, 21, 133).
|
||||
/// </summary>
|
||||
MediumVioletRed = 0xC71585,
|
||||
|
||||
/// <summary>
|
||||
/// Midnight blue RGB(25, 25, 112).
|
||||
/// </summary>
|
||||
MidnightBlue = 0x191970,
|
||||
|
||||
/// <summary>
|
||||
/// Mint cream RGB(245, 255, 250).
|
||||
/// </summary>
|
||||
MintCream = 0xF5FFFA,
|
||||
|
||||
/// <summary>
|
||||
/// Misty rose RGB(255, 228, 225).
|
||||
/// </summary>
|
||||
MistyRose = 0xFFE4E1,
|
||||
|
||||
/// <summary>
|
||||
/// Moccasin RGB(255, 228, 181).
|
||||
/// </summary>
|
||||
Moccasin = 0xFFE4B5,
|
||||
|
||||
/// <summary>
|
||||
/// Navajo white RGB(255, 222, 173).
|
||||
/// </summary>
|
||||
NavajoWhite = 0xFFDEAD,
|
||||
|
||||
/// <summary>
|
||||
/// Navy RGB(0, 0, 128).
|
||||
/// </summary>
|
||||
Navy = 0x000080,
|
||||
|
||||
/// <summary>
|
||||
/// Old lace RGB(253, 245, 230).
|
||||
/// </summary>
|
||||
OldLace = 0xFDF5E6,
|
||||
|
||||
/// <summary>
|
||||
/// Olive RGB(128, 128, 0).
|
||||
/// </summary>
|
||||
Olive = 0x808000,
|
||||
|
||||
/// <summary>
|
||||
/// Olive drab RGB(107, 142, 35).
|
||||
/// </summary>
|
||||
OliveDrab = 0x6B8E23,
|
||||
|
||||
/// <summary>
|
||||
/// Orange RGB(255, 165, 0).
|
||||
/// </summary>
|
||||
Orange = 0xFFA500,
|
||||
|
||||
/// <summary>
|
||||
/// Orange red RGB(255, 69, 0).
|
||||
/// </summary>
|
||||
OrangeRed = 0xFF4500,
|
||||
|
||||
/// <summary>
|
||||
/// Orchid RGB(218, 112, 214).
|
||||
/// </summary>
|
||||
Orchid = 0xDA70D6,
|
||||
|
||||
/// <summary>
|
||||
/// Pale goldenrod RGB(238, 232, 170).
|
||||
/// </summary>
|
||||
PaleGoldenrod = 0xEEE8AA,
|
||||
|
||||
/// <summary>
|
||||
/// Pale green RGB(152, 251, 152).
|
||||
/// </summary>
|
||||
PaleGreen = 0x98FB98,
|
||||
|
||||
/// <summary>
|
||||
/// Pale turquoise RGB(175, 238, 238).
|
||||
/// </summary>
|
||||
PaleTurquoise = 0xAFEEEE,
|
||||
|
||||
/// <summary>
|
||||
/// Pale violet red RGB(219, 112, 147).
|
||||
/// </summary>
|
||||
PaleVioletRed = 0xDB7093,
|
||||
|
||||
/// <summary>
|
||||
/// Papaya whip RGB(255, 239, 213).
|
||||
/// </summary>
|
||||
PapayaWhip = 0xFFEFD5,
|
||||
|
||||
/// <summary>
|
||||
/// Peach puff RGB(255, 218, 185).
|
||||
/// </summary>
|
||||
PeachPuff = 0xFFDAB9,
|
||||
|
||||
/// <summary>
|
||||
/// Peru RGB(205, 133, 63).
|
||||
/// </summary>
|
||||
Peru = 0xCD853F,
|
||||
|
||||
/// <summary>
|
||||
/// Pink RGB(255, 192, 203).
|
||||
/// </summary>
|
||||
Pink = 0xFFC0CB,
|
||||
|
||||
/// <summary>
|
||||
/// Plum RGB(221, 160, 221).
|
||||
/// </summary>
|
||||
Plum = 0xDDA0DD,
|
||||
|
||||
/// <summary>
|
||||
/// Powder blue RGB(176, 224, 230).
|
||||
/// </summary>
|
||||
PowderBlue = 0xB0E0E6,
|
||||
|
||||
/// <summary>
|
||||
/// Purple RGB(128, 0, 128).
|
||||
/// </summary>
|
||||
Purple = 0x800080,
|
||||
|
||||
/// <summary>
|
||||
/// Rebecca purple RGB(102, 51, 153).
|
||||
/// </summary>
|
||||
RebeccaPurple = 0x663399,
|
||||
|
||||
/// <summary>
|
||||
/// Red RGB(255, 0, 0).
|
||||
/// </summary>
|
||||
Red = 0xFF0000,
|
||||
|
||||
/// <summary>
|
||||
/// Rosy brown RGB(188, 143, 143).
|
||||
/// </summary>
|
||||
RosyBrown = 0xBC8F8F,
|
||||
|
||||
/// <summary>
|
||||
/// Royal blue RGB(65, 105, 225).
|
||||
/// </summary>
|
||||
RoyalBlue = 0x4169E1,
|
||||
|
||||
/// <summary>
|
||||
/// Saddle brown RGB(139, 69, 19).
|
||||
/// </summary>
|
||||
SaddleBrown = 0x8B4513,
|
||||
|
||||
/// <summary>
|
||||
/// Salmon RGB(250, 128, 114).
|
||||
/// </summary>
|
||||
Salmon = 0xFA8072,
|
||||
|
||||
/// <summary>
|
||||
/// Sandy brown RGB(244, 164, 96).
|
||||
/// </summary>
|
||||
SandyBrown = 0xF4A460,
|
||||
|
||||
/// <summary>
|
||||
/// Sea green RGB(46, 139, 87).
|
||||
/// </summary>
|
||||
SeaGreen = 0x2E8B57,
|
||||
|
||||
/// <summary>
|
||||
/// Sea shell RGB(255, 245, 238).
|
||||
/// </summary>
|
||||
SeaShell = 0xFFF5EE,
|
||||
|
||||
/// <summary>
|
||||
/// Sienna RGB(160, 82, 45).
|
||||
/// </summary>
|
||||
Sienna = 0xA0522D,
|
||||
|
||||
/// <summary>
|
||||
/// Silver RGB(192, 192, 192).
|
||||
/// </summary>
|
||||
Silver = 0xC0C0C0,
|
||||
|
||||
/// <summary>
|
||||
/// Sky blue RGB(135, 206, 235).
|
||||
/// </summary>
|
||||
SkyBlue = 0x87CEEB,
|
||||
|
||||
/// <summary>
|
||||
/// Slate blue RGB(106, 90, 205).
|
||||
/// </summary>
|
||||
SlateBlue = 0x6A5ACD,
|
||||
|
||||
/// <summary>
|
||||
/// Slate gray RGB(112, 128, 144).
|
||||
/// </summary>
|
||||
SlateGray = 0x708090,
|
||||
|
||||
/// <summary>
|
||||
/// Slate grey RGB(112, 128, 144).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Same as <see cref="SlateGray"/>.
|
||||
/// </remarks>
|
||||
SlateGrey = SlateGray,
|
||||
|
||||
/// <summary>
|
||||
/// Snow RGB(255, 250, 250).
|
||||
/// </summary>
|
||||
Snow = 0xFFFAFA,
|
||||
|
||||
/// <summary>
|
||||
/// Spring green RGB(0, 255, 127).
|
||||
/// </summary>
|
||||
SpringGreen = 0x00FF7F,
|
||||
|
||||
/// <summary>
|
||||
/// Steel blue RGB(70, 130, 180).
|
||||
/// </summary>
|
||||
SteelBlue = 0x4682B4,
|
||||
|
||||
/// <summary>
|
||||
/// Tan RGB(210, 180, 140).
|
||||
/// </summary>
|
||||
Tan = 0xD2B48C,
|
||||
|
||||
/// <summary>
|
||||
/// Teal RGB(0, 128, 128).
|
||||
/// </summary>
|
||||
Teal = 0x008080,
|
||||
|
||||
/// <summary>
|
||||
/// Thistle RGB(216, 191, 216).
|
||||
/// </summary>
|
||||
Thistle = 0xD8BFD8,
|
||||
|
||||
/// <summary>
|
||||
/// Tomato RGB(255, 99, 71).
|
||||
/// </summary>
|
||||
Tomato = 0xFF6347,
|
||||
|
||||
/// <summary>
|
||||
/// Turquoise RGB(64, 224, 208).
|
||||
/// </summary>
|
||||
Turquoise = 0x40E0D0,
|
||||
|
||||
/// <summary>
|
||||
/// Violet RGB(238, 130, 238).
|
||||
/// </summary>
|
||||
Violet = 0xEE82EE,
|
||||
|
||||
/// <summary>
|
||||
/// Wheat RGB(245, 222, 179).
|
||||
/// </summary>
|
||||
Wheat = 0xF5DEB3,
|
||||
|
||||
/// <summary>
|
||||
/// White RGB(255, 255, 255).
|
||||
/// </summary>
|
||||
White = 0xFFFFFF,
|
||||
|
||||
/// <summary>
|
||||
/// White smoke RGB(245, 245, 245).
|
||||
/// </summary>
|
||||
WhiteSmoke = 0xF5F5F5,
|
||||
|
||||
/// <summary>
|
||||
/// Yellow RGB(255, 255, 0).
|
||||
/// </summary>
|
||||
Yellow = 0xFFFF00,
|
||||
|
||||
/// <summary>
|
||||
/// Yellow green RGB(154, 205, 50).
|
||||
/// </summary>
|
||||
YellowGreen = 0x9ACD32
|
||||
}
|
||||
110
Terminal.Gui/Drawing/Color/W3cColorNameResolver.cs
Normal file
110
Terminal.Gui/Drawing/Color/W3cColorNameResolver.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Frozen;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
/// W3C color name resolver.
|
||||
/// </summary>
|
||||
public class W3cColorNameResolver : IColorNameResolver
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<string> GetColorNames () =>
|
||||
W3cColors.GetColorNames ();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryParseColor (ReadOnlySpan<char> name, out Color color) =>
|
||||
W3cColors.TryParseColor (name, out color);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryNameColor (Color color, [NotNullWhen (true)] out string? name) =>
|
||||
W3cColors.TryNameColor (color, out name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for transforming to and from <see cref="W3cColor"/> enum.
|
||||
/// </summary>
|
||||
internal static class W3cColors
|
||||
{
|
||||
private static readonly ImmutableArray<string> Names;
|
||||
private static readonly FrozenDictionary<uint, string> ArgbNameMap;
|
||||
|
||||
static W3cColors ()
|
||||
{
|
||||
// Populate based on names because enums with same numerical value
|
||||
// are not otherwise distinguishable from each other.
|
||||
string[] w3cNames = Enum.GetNames<W3cColor> ().Order().ToArray();
|
||||
|
||||
Dictionary<uint, string> map = new(w3cNames.Length);
|
||||
foreach (string name in w3cNames)
|
||||
{
|
||||
W3cColor w3c = Enum.Parse<W3cColor>(name);
|
||||
uint argb = GetArgb(w3c);
|
||||
// TODO: Collect aliases?
|
||||
_ = map.TryAdd (argb, name);
|
||||
}
|
||||
|
||||
Names = ImmutableArray.Create (w3cNames);
|
||||
ArgbNameMap = map.ToFrozenDictionary ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets read-only list of the W3C colors in alphabetical order.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<string> GetColorNames ()
|
||||
{
|
||||
return Names;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given W3C color name to equivalent color value.
|
||||
/// </summary>
|
||||
/// <param name="name">W3C color name.</param>
|
||||
/// <param name="color">The successfully converted W3C color value.</param>
|
||||
/// <returns>True if the conversion succeeded; otherwise false.</returns>
|
||||
public static bool TryParseColor (ReadOnlySpan<char> name, out Color color)
|
||||
{
|
||||
if (!Enum.TryParse (name, ignoreCase: true, out W3cColor w3cColor) ||
|
||||
// Any numerical value converts to undefined enum value.
|
||||
!Enum.IsDefined (w3cColor))
|
||||
{
|
||||
color = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint argb = GetArgb (w3cColor);
|
||||
color = new Color (argb);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the given color value to a W3C color name.
|
||||
/// </summary>
|
||||
/// <param name="color">Color value to match W3C color.</param>
|
||||
/// <param name="name">The successfully converted W3C color name.</param>
|
||||
/// <returns>True if conversion succeeded; otherwise false.</returns>
|
||||
public static bool TryNameColor (Color color, [NotNullWhen (true)] out string? name)
|
||||
{
|
||||
if (ArgbNameMap.TryGetValue (color.Argb, out name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
name = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static uint GetArgb (W3cColor w3cColor)
|
||||
{
|
||||
const int alphaShift = 24;
|
||||
const uint alphaMask = 0xFFU << alphaShift;
|
||||
|
||||
int rgb = (int)w3cColor;
|
||||
|
||||
uint argb = (uint)rgb | alphaMask;
|
||||
return argb;
|
||||
}
|
||||
}
|
||||
1314
Terminal.Gui/Resources/Strings.Designer.cs
generated
1314
Terminal.Gui/Resources/Strings.Designer.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -280,444 +280,6 @@
|
||||
<data name="dpTitle" xml:space="preserve">
|
||||
<value>Date Picker</value>
|
||||
</data>
|
||||
<data name="#F0F8FF" xml:space="preserve">
|
||||
<value>AliceBlue</value>
|
||||
</data>
|
||||
<data name="#FAEBD7" xml:space="preserve">
|
||||
<value>AntiqueWhite</value>
|
||||
</data>
|
||||
<data name="#7FFFD4" xml:space="preserve">
|
||||
<value>Aquamarine</value>
|
||||
</data>
|
||||
<data name="#F0FFFF" xml:space="preserve">
|
||||
<value>Azure</value>
|
||||
</data>
|
||||
<data name="#F5F5DC" xml:space="preserve">
|
||||
<value>Beige</value>
|
||||
</data>
|
||||
<data name="#FFE4C4" xml:space="preserve">
|
||||
<value>Bisque</value>
|
||||
</data>
|
||||
<data name="#000000" xml:space="preserve">
|
||||
<value>Black</value>
|
||||
</data>
|
||||
<data name="#FFEBCD" xml:space="preserve">
|
||||
<value>BlanchedAlmond</value>
|
||||
</data>
|
||||
<data name="#0000FF" xml:space="preserve">
|
||||
<value>Blue</value>
|
||||
</data>
|
||||
<data name="#8A2BE2" xml:space="preserve">
|
||||
<value>BlueViolet</value>
|
||||
</data>
|
||||
<data name="#A52A2A" xml:space="preserve">
|
||||
<value>Brown</value>
|
||||
</data>
|
||||
<data name="#DEB887" xml:space="preserve">
|
||||
<value>BurlyWood</value>
|
||||
</data>
|
||||
<data name="#5F9EA0" xml:space="preserve">
|
||||
<value>CadetBlue</value>
|
||||
</data>
|
||||
<data name="#7FFF00" xml:space="preserve">
|
||||
<value>Chartreuse</value>
|
||||
</data>
|
||||
<data name="#D2691E" xml:space="preserve">
|
||||
<value>Chocolate</value>
|
||||
</data>
|
||||
<data name="#FF7F50" xml:space="preserve">
|
||||
<value>Coral</value>
|
||||
</data>
|
||||
<data name="#6495ED" xml:space="preserve">
|
||||
<value>CornflowerBlue</value>
|
||||
</data>
|
||||
<data name="#FFF8DC" xml:space="preserve">
|
||||
<value>Cornsilk</value>
|
||||
</data>
|
||||
<data name="#DC143C" xml:space="preserve">
|
||||
<value>Crimson</value>
|
||||
</data>
|
||||
<data name="#00FFFF" xml:space="preserve">
|
||||
<value>Cyan</value>
|
||||
</data>
|
||||
<data name="#00008B" xml:space="preserve">
|
||||
<value>DarkBlue</value>
|
||||
</data>
|
||||
<data name="#008B8B" xml:space="preserve">
|
||||
<value>DarkCyan</value>
|
||||
</data>
|
||||
<data name="#B8860B" xml:space="preserve">
|
||||
<value>DarkGoldenRod</value>
|
||||
</data>
|
||||
<data name="#A9A9A9" xml:space="preserve">
|
||||
<value>DarkGrey</value>
|
||||
</data>
|
||||
<data name="#006400" xml:space="preserve">
|
||||
<value>DarkGreen</value>
|
||||
</data>
|
||||
<data name="#BDB76B" xml:space="preserve">
|
||||
<value>DarkKhaki</value>
|
||||
</data>
|
||||
<data name="#8B008B" xml:space="preserve">
|
||||
<value>DarkMagenta</value>
|
||||
</data>
|
||||
<data name="#556B2F" xml:space="preserve">
|
||||
<value>DarkOliveGreen</value>
|
||||
</data>
|
||||
<data name="#FF8C00" xml:space="preserve">
|
||||
<value>DarkOrange</value>
|
||||
</data>
|
||||
<data name="#9932CC" xml:space="preserve">
|
||||
<value>DarkOrchid</value>
|
||||
</data>
|
||||
<data name="#8B0000" xml:space="preserve">
|
||||
<value>DarkRed</value>
|
||||
</data>
|
||||
<data name="#E9967A" xml:space="preserve">
|
||||
<value>DarkSalmon</value>
|
||||
</data>
|
||||
<data name="#8FBC8F" xml:space="preserve">
|
||||
<value>DarkSeaGreen</value>
|
||||
</data>
|
||||
<data name="#483D8B" xml:space="preserve">
|
||||
<value>DarkSlateBlue</value>
|
||||
</data>
|
||||
<data name="#2F4F4F" xml:space="preserve">
|
||||
<value>DarkSlateGrey</value>
|
||||
</data>
|
||||
<data name="#00CED1" xml:space="preserve">
|
||||
<value>DarkTurquoise</value>
|
||||
</data>
|
||||
<data name="#9400D3" xml:space="preserve">
|
||||
<value>DarkViolet</value>
|
||||
</data>
|
||||
<data name="#FF1493" xml:space="preserve">
|
||||
<value>DeepPink</value>
|
||||
</data>
|
||||
<data name="#00BFFF" xml:space="preserve">
|
||||
<value>DeepSkyBlue</value>
|
||||
</data>
|
||||
<data name="#696969" xml:space="preserve">
|
||||
<value>DimGray</value>
|
||||
</data>
|
||||
<data name="#1E90FF" xml:space="preserve">
|
||||
<value>DodgerBlue</value>
|
||||
</data>
|
||||
<data name="#B22222" xml:space="preserve">
|
||||
<value>FireBrick</value>
|
||||
</data>
|
||||
<data name="#FFFAF0" xml:space="preserve">
|
||||
<value>FloralWhite</value>
|
||||
</data>
|
||||
<data name="#228B22" xml:space="preserve">
|
||||
<value>ForestGreen</value>
|
||||
</data>
|
||||
<data name="#DCDCDC" xml:space="preserve">
|
||||
<value>Gainsboro</value>
|
||||
</data>
|
||||
<data name="#F8F8FF" xml:space="preserve">
|
||||
<value>GhostWhite</value>
|
||||
</data>
|
||||
<data name="#FFD700" xml:space="preserve">
|
||||
<value>Gold</value>
|
||||
</data>
|
||||
<data name="#DAA520" xml:space="preserve">
|
||||
<value>GoldenRod</value>
|
||||
</data>
|
||||
<data name="#808080" xml:space="preserve">
|
||||
<value>Gray</value>
|
||||
</data>
|
||||
<data name="#008000" xml:space="preserve">
|
||||
<value>Green</value>
|
||||
</data>
|
||||
<data name="#ADFF2F" xml:space="preserve">
|
||||
<value>GreenYellow</value>
|
||||
</data>
|
||||
<data name="#F0FFF0" xml:space="preserve">
|
||||
<value>HoneyDew</value>
|
||||
</data>
|
||||
<data name="#FF69B4" xml:space="preserve">
|
||||
<value>HotPink</value>
|
||||
</data>
|
||||
<data name="#CD5C5C" xml:space="preserve">
|
||||
<value>IndianRed</value>
|
||||
</data>
|
||||
<data name="#4B0082" xml:space="preserve">
|
||||
<value>Indigo</value>
|
||||
</data>
|
||||
<data name="#FFFFF0" xml:space="preserve">
|
||||
<value>Ivory</value>
|
||||
</data>
|
||||
<data name="#F0E68C" xml:space="preserve">
|
||||
<value>Khaki</value>
|
||||
</data>
|
||||
<data name="#E6E6FA" xml:space="preserve">
|
||||
<value>Lavender</value>
|
||||
</data>
|
||||
<data name="#FFF0F5" xml:space="preserve">
|
||||
<value>LavenderBlush</value>
|
||||
</data>
|
||||
<data name="#7CFC00" xml:space="preserve">
|
||||
<value>LawnGreen</value>
|
||||
</data>
|
||||
<data name="#FFFACD" xml:space="preserve">
|
||||
<value>LemonChiffon</value>
|
||||
</data>
|
||||
<data name="#ADD8E6" xml:space="preserve">
|
||||
<value>LightBlue</value>
|
||||
</data>
|
||||
<data name="#F08080" xml:space="preserve">
|
||||
<value>LightCoral</value>
|
||||
</data>
|
||||
<data name="#E0FFFF" xml:space="preserve">
|
||||
<value>LightCyan</value>
|
||||
</data>
|
||||
<data name="#FAFAD2" xml:space="preserve">
|
||||
<value>LightGoldenRodYellow</value>
|
||||
</data>
|
||||
<data name="#D3D3D3" xml:space="preserve">
|
||||
<value>LightGray</value>
|
||||
</data>
|
||||
<data name="#90EE90" xml:space="preserve">
|
||||
<value>LightGreen</value>
|
||||
</data>
|
||||
<data name="#FFB6C1" xml:space="preserve">
|
||||
<value>LightPink</value>
|
||||
</data>
|
||||
<data name="#FFA07A" xml:space="preserve">
|
||||
<value>LightSalmon</value>
|
||||
</data>
|
||||
<data name="#20B2AA" xml:space="preserve">
|
||||
<value>LightSeaGreen</value>
|
||||
</data>
|
||||
<data name="#87CEFA" xml:space="preserve">
|
||||
<value>LightSkyBlue</value>
|
||||
</data>
|
||||
<data name="#778899" xml:space="preserve">
|
||||
<value>LightSlateGrey</value>
|
||||
</data>
|
||||
<data name="#B0C4DE" xml:space="preserve">
|
||||
<value>LightSteelBlue</value>
|
||||
</data>
|
||||
<data name="#FFFFE0" xml:space="preserve">
|
||||
<value>LightYellow</value>
|
||||
</data>
|
||||
<data name="#00FF00" xml:space="preserve">
|
||||
<value>Lime</value>
|
||||
</data>
|
||||
<data name="#32CD32" xml:space="preserve">
|
||||
<value>LimeGreen</value>
|
||||
</data>
|
||||
<data name="#FAF0E6" xml:space="preserve">
|
||||
<value>Linen</value>
|
||||
</data>
|
||||
<data name="#FF00FF" xml:space="preserve">
|
||||
<value>Magenta</value>
|
||||
</data>
|
||||
<data name="#800000" xml:space="preserve">
|
||||
<value>Maroon</value>
|
||||
</data>
|
||||
<data name="#66CDAA" xml:space="preserve">
|
||||
<value>MediumAquaMarine</value>
|
||||
</data>
|
||||
<data name="#0000CD" xml:space="preserve">
|
||||
<value>MediumBlue</value>
|
||||
</data>
|
||||
<data name="#BA55D3" xml:space="preserve">
|
||||
<value>MediumOrchid</value>
|
||||
</data>
|
||||
<data name="#9370DB" xml:space="preserve">
|
||||
<value>MediumPurple</value>
|
||||
</data>
|
||||
<data name="#3CB371" xml:space="preserve">
|
||||
<value>MediumSeaGreen</value>
|
||||
</data>
|
||||
<data name="#7B68EE" xml:space="preserve">
|
||||
<value>MediumSlateBlue</value>
|
||||
</data>
|
||||
<data name="#00FA9A" xml:space="preserve">
|
||||
<value>MediumSpringGreen</value>
|
||||
</data>
|
||||
<data name="#48D1CC" xml:space="preserve">
|
||||
<value>MediumTurquoise</value>
|
||||
</data>
|
||||
<data name="#C71585" xml:space="preserve">
|
||||
<value>MediumVioletRed</value>
|
||||
</data>
|
||||
<data name="#191970" xml:space="preserve">
|
||||
<value>MidnightBlue</value>
|
||||
</data>
|
||||
<data name="#F5FFFA" xml:space="preserve">
|
||||
<value>MintCream</value>
|
||||
</data>
|
||||
<data name="#FFE4E1" xml:space="preserve">
|
||||
<value>MistyRose</value>
|
||||
</data>
|
||||
<data name="#FFE4B5" xml:space="preserve">
|
||||
<value>Moccasin</value>
|
||||
</data>
|
||||
<data name="#FFDEAD" xml:space="preserve">
|
||||
<value>NavajoWhite</value>
|
||||
</data>
|
||||
<data name="#000080" xml:space="preserve">
|
||||
<value>Navy</value>
|
||||
</data>
|
||||
<data name="#FDF5E6" xml:space="preserve">
|
||||
<value>OldLace</value>
|
||||
</data>
|
||||
<data name="#808000" xml:space="preserve">
|
||||
<value>Olive</value>
|
||||
</data>
|
||||
<data name="#6B8E23" xml:space="preserve">
|
||||
<value>OliveDrab</value>
|
||||
</data>
|
||||
<data name="#FFA500" xml:space="preserve">
|
||||
<value>Orange</value>
|
||||
</data>
|
||||
<data name="#FF4500" xml:space="preserve">
|
||||
<value>OrangeRed</value>
|
||||
</data>
|
||||
<data name="#DA70D6" xml:space="preserve">
|
||||
<value>Orchid</value>
|
||||
</data>
|
||||
<data name="#EEE8AA" xml:space="preserve">
|
||||
<value>PaleGoldenRod</value>
|
||||
</data>
|
||||
<data name="#98FB98" xml:space="preserve">
|
||||
<value>PaleGreen</value>
|
||||
</data>
|
||||
<data name="#AFEEEE" xml:space="preserve">
|
||||
<value>PaleTurquoise</value>
|
||||
</data>
|
||||
<data name="#DB7093" xml:space="preserve">
|
||||
<value>PaleVioletRed</value>
|
||||
</data>
|
||||
<data name="#FFEFD5" xml:space="preserve">
|
||||
<value>PapayaWhip</value>
|
||||
</data>
|
||||
<data name="#FFDAB9" xml:space="preserve">
|
||||
<value>PeachPuff</value>
|
||||
</data>
|
||||
<data name="#CD853F" xml:space="preserve">
|
||||
<value>Peru</value>
|
||||
</data>
|
||||
<data name="#FFC0CB" xml:space="preserve">
|
||||
<value>Pink</value>
|
||||
</data>
|
||||
<data name="#DDA0DD" xml:space="preserve">
|
||||
<value>Plum</value>
|
||||
</data>
|
||||
<data name="#B0E0E6" xml:space="preserve">
|
||||
<value>PowderBlue</value>
|
||||
</data>
|
||||
<data name="#800080" xml:space="preserve">
|
||||
<value>Purple</value>
|
||||
</data>
|
||||
<data name="#663399" xml:space="preserve">
|
||||
<value>RebeccaPurple</value>
|
||||
</data>
|
||||
<data name="#FF0000" xml:space="preserve">
|
||||
<value>Red</value>
|
||||
</data>
|
||||
<data name="#BC8F8F" xml:space="preserve">
|
||||
<value>RosyBrown</value>
|
||||
</data>
|
||||
<data name="#4169E1" xml:space="preserve">
|
||||
<value>RoyalBlue</value>
|
||||
</data>
|
||||
<data name="#8B4513" xml:space="preserve">
|
||||
<value>SaddleBrown</value>
|
||||
</data>
|
||||
<data name="#FA8072" xml:space="preserve">
|
||||
<value>Salmon</value>
|
||||
</data>
|
||||
<data name="#F4A460" xml:space="preserve">
|
||||
<value>SandyBrown</value>
|
||||
</data>
|
||||
<data name="#2E8B57" xml:space="preserve">
|
||||
<value>SeaGreen</value>
|
||||
</data>
|
||||
<data name="#FFF5EE" xml:space="preserve">
|
||||
<value>SeaShell</value>
|
||||
</data>
|
||||
<data name="#A0522D" xml:space="preserve">
|
||||
<value>Sienna</value>
|
||||
</data>
|
||||
<data name="#C0C0C0" xml:space="preserve">
|
||||
<value>Silver</value>
|
||||
</data>
|
||||
<data name="#87CEEB" xml:space="preserve">
|
||||
<value>SkyBlue</value>
|
||||
</data>
|
||||
<data name="#6A5ACD" xml:space="preserve">
|
||||
<value>SlateBlue</value>
|
||||
</data>
|
||||
<data name="#708090" xml:space="preserve">
|
||||
<value>SlateGray</value>
|
||||
</data>
|
||||
<data name="#FFFAFA" xml:space="preserve">
|
||||
<value>Snow</value>
|
||||
</data>
|
||||
<data name="#00FF7F" xml:space="preserve">
|
||||
<value>SpringGreen</value>
|
||||
</data>
|
||||
<data name="#4682B4" xml:space="preserve">
|
||||
<value>SteelBlue</value>
|
||||
</data>
|
||||
<data name="#D2B48C" xml:space="preserve">
|
||||
<value>Tan</value>
|
||||
</data>
|
||||
<data name="#008080" xml:space="preserve">
|
||||
<value>Teal</value>
|
||||
</data>
|
||||
<data name="#D8BFD8" xml:space="preserve">
|
||||
<value>Thistle</value>
|
||||
</data>
|
||||
<data name="#FF6347" xml:space="preserve">
|
||||
<value>Tomato</value>
|
||||
</data>
|
||||
<data name="#40E0D0" xml:space="preserve">
|
||||
<value>Turquoise</value>
|
||||
</data>
|
||||
<data name="#EE82EE" xml:space="preserve">
|
||||
<value>Violet</value>
|
||||
</data>
|
||||
<data name="#F5DEB3" xml:space="preserve">
|
||||
<value>Wheat</value>
|
||||
</data>
|
||||
<data name="#FFFFFF" xml:space="preserve">
|
||||
<value>White</value>
|
||||
</data>
|
||||
<data name="#F5F5F5" xml:space="preserve">
|
||||
<value>WhiteSmoke</value>
|
||||
</data>
|
||||
<data name="#FFFF00" xml:space="preserve">
|
||||
<value>Yellow</value>
|
||||
</data>
|
||||
<data name="#9ACD32" xml:space="preserve">
|
||||
<value>YellowGreen</value>
|
||||
</data>
|
||||
<data name="#3B78FF" xml:space="preserve">
|
||||
<value>BrightBlue</value>
|
||||
</data>
|
||||
<data name="#61D6D6" xml:space="preserve">
|
||||
<value>BrightCyan</value>
|
||||
</data>
|
||||
<data name="#E74856" xml:space="preserve">
|
||||
<value>BrightRed</value>
|
||||
</data>
|
||||
<data name="#16C60C" xml:space="preserve">
|
||||
<value>BrightGreen</value>
|
||||
</data>
|
||||
<data name="#B4009E" xml:space="preserve">
|
||||
<value>BrightMagenta</value>
|
||||
</data>
|
||||
<data name="#F9F1A5" xml:space="preserve">
|
||||
<value>BrightYellow</value>
|
||||
</data>
|
||||
<data name="#767676" xml:space="preserve">
|
||||
<value>DarkGray</value>
|
||||
</data>
|
||||
<data name="ctxColors" xml:space="preserve">
|
||||
<value>Co_lors</value>
|
||||
</data>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
|
||||
namespace Terminal.Gui;
|
||||
|
||||
/// <summary>
|
||||
@@ -34,7 +32,7 @@ public partial class ColorPicker : View
|
||||
private Color _selectedColor = Color.Black;
|
||||
|
||||
// TODO: Add interface
|
||||
private readonly IColorNameResolver _colorNameResolver = new W3CColors ();
|
||||
private readonly IColorNameResolver _colorNameResolver = new MultiStandardColorNameResolver ();
|
||||
|
||||
private List<IColorBar> _bars = new ();
|
||||
|
||||
@@ -64,7 +62,7 @@ public partial class ColorPicker : View
|
||||
Width = textFieldWidth
|
||||
};
|
||||
tfValue.HasFocusChanged += UpdateSingleBarValueFromTextField;
|
||||
tfValue.Accepting += (s, _)=>UpdateSingleBarValueFromTextField(s);
|
||||
tfValue.Accepting += (s, _) => UpdateSingleBarValueFromTextField (s);
|
||||
_textFields.Add (bar, tfValue);
|
||||
}
|
||||
|
||||
@@ -182,7 +180,7 @@ public partial class ColorPicker : View
|
||||
Add (_tfHex);
|
||||
|
||||
_tfHex.HasFocusChanged += UpdateValueFromTextField;
|
||||
_tfHex.Accepting += (_,_)=> UpdateValueFromTextField();
|
||||
_tfHex.Accepting += (_, _) => UpdateValueFromTextField ();
|
||||
}
|
||||
|
||||
private void DisposeOldViews ()
|
||||
@@ -266,7 +264,7 @@ public partial class ColorPicker : View
|
||||
|
||||
if (_tfName != null)
|
||||
{
|
||||
_tfName.Text = _colorNameResolver.TryNameColor (_selectedColor, out string name) ? name : string.Empty;
|
||||
_tfName.Text = _colorNameResolver.TryNameColor (_selectedColor, out string? name) ? name : string.Empty;
|
||||
}
|
||||
|
||||
if (_tfHex != null)
|
||||
@@ -312,7 +310,7 @@ public partial class ColorPicker : View
|
||||
}
|
||||
|
||||
// it is a leave event so update
|
||||
UpdateValueFromName();
|
||||
UpdateValueFromName ();
|
||||
}
|
||||
private void UpdateValueFromName ()
|
||||
{
|
||||
|
||||
@@ -9,10 +9,6 @@ namespace Terminal.Gui.ResourcesTests;
|
||||
|
||||
public class ResourceManagerTests
|
||||
{
|
||||
private const string DODGER_BLUE_COLOR_KEY = "DodgerBlue";
|
||||
private const string DODGER_BLUE_COLOR_NAME = "DodgerBlue";
|
||||
private const string NO_NAMED_COLOR_KEY = "#1E80FF";
|
||||
private const string NO_NAMED_COLOR_NAME = "#1E80FF";
|
||||
private const string EXISTENT_CULTURE = "pt-PT";
|
||||
private const string NO_EXISTENT_CULTURE = "de-DE";
|
||||
private const string NO_EXISTENT_KEY = "blabla";
|
||||
@@ -50,51 +46,6 @@ public class ResourceManagerTests
|
||||
RestoreCurrentCultures ();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetResourceSet_FallBack_To_Default_For_No_Existent_Culture_File ()
|
||||
{
|
||||
CultureInfo.CurrentCulture = new (NO_EXISTENT_CULTURE);
|
||||
CultureInfo.CurrentUICulture = new (NO_EXISTENT_CULTURE);
|
||||
|
||||
// W3CColors.GetColorNames also calls ColorStrings.GetW3CColorNames
|
||||
string [] colorNames = new W3CColors ().GetColorNames ().ToArray ();
|
||||
Assert.Contains (DODGER_BLUE_COLOR_NAME, colorNames);
|
||||
Assert.DoesNotContain (NO_TRANSLATED_VALUE, colorNames);
|
||||
|
||||
RestoreCurrentCultures ();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetResourceSet_FallBack_To_Default_For_Not_Translated_Existent_Culture_File ()
|
||||
{
|
||||
CultureInfo.CurrentCulture = new (EXISTENT_CULTURE);
|
||||
CultureInfo.CurrentUICulture = new (EXISTENT_CULTURE);
|
||||
|
||||
// These aren't already translated
|
||||
// ColorStrings.GetW3CColorNames method uses GetResourceSet method to retrieve color names
|
||||
IEnumerable<string> colorNames = ColorStrings.GetW3CColorNames ();
|
||||
Assert.NotEmpty (colorNames);
|
||||
|
||||
// W3CColors.GetColorNames also calls ColorStrings.GetW3CColorNames
|
||||
colorNames = new W3CColors ().GetColorNames ().ToArray ();
|
||||
Assert.Contains (DODGER_BLUE_COLOR_NAME, colorNames);
|
||||
Assert.DoesNotContain (NO_TRANSLATED_VALUE, colorNames);
|
||||
|
||||
// ColorStrings.TryParseW3CColorName method uses GetResourceSet method to retrieve a color value
|
||||
Assert.True (ColorStrings.TryParseW3CColorName (DODGER_BLUE_COLOR_NAME, out Color color));
|
||||
Assert.Equal (DODGER_BLUE_COLOR_KEY, color.ToString ());
|
||||
|
||||
// W3CColors.GetColorNames also calls ColorStrings.GetW3CColorNames for no-named colors
|
||||
colorNames = new W3CColors ().GetColorNames ().ToArray ();
|
||||
Assert.DoesNotContain (NO_NAMED_COLOR_NAME, colorNames);
|
||||
|
||||
// ColorStrings.TryParseW3CColorName method uses GetResourceSet method to retrieve a color value for no-named colors
|
||||
Assert.True (ColorStrings.TryParseW3CColorName (NO_NAMED_COLOR_NAME, out color));
|
||||
Assert.Equal (NO_NAMED_COLOR_KEY, color.ToString ());
|
||||
|
||||
RestoreCurrentCultures ();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetResourceSet_With_Filter_Does_Not_Overflows_If_Key_Does_Not_Exist ()
|
||||
{
|
||||
|
||||
@@ -749,7 +749,15 @@ public class ColorPickerTests
|
||||
// Auto complete the color name
|
||||
Application.RaiseKeyDownEvent (Key.Tab);
|
||||
|
||||
Assert.Equal ("Aquamarine", name.Text);
|
||||
// Match cyan alternative name
|
||||
Assert.Equal ("Aqua", name.Text);
|
||||
|
||||
Assert.True (name.HasFocus);
|
||||
|
||||
Application.RaiseKeyDownEvent (Key.Tab);
|
||||
|
||||
// Resolves to cyan color
|
||||
Assert.Equal ("Cyan", name.Text);
|
||||
|
||||
// Tab out of the text field
|
||||
Application.RaiseKeyDownEvent (Key.Tab);
|
||||
@@ -757,7 +765,7 @@ public class ColorPickerTests
|
||||
Assert.False (name.HasFocus);
|
||||
Assert.NotSame (name, cp.Focused);
|
||||
|
||||
Assert.Equal ("#7FFFD4", hex.Text);
|
||||
Assert.Equal ("#00FFFF", hex.Text);
|
||||
|
||||
Application.Top?.Dispose ();
|
||||
Application.ResetState (true);
|
||||
@@ -817,14 +825,6 @@ public class ColorPickerTests
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestColorNames ()
|
||||
{
|
||||
var colors = new W3CColors ();
|
||||
Assert.Contains ("Aquamarine", colors.GetColorNames ());
|
||||
Assert.DoesNotContain ("Save as", colors.GetColorNames ());
|
||||
}
|
||||
|
||||
private ColorBar GetColorBar (ColorPicker cp, ColorPickerPart toGet)
|
||||
{
|
||||
if (toGet <= ColorPickerPart.Bar3)
|
||||
@@ -845,7 +845,7 @@ public class ColorPickerTests
|
||||
|
||||
Application.Navigation = new ();
|
||||
|
||||
Application.Top = new() { Width = 20, Height = 5 };
|
||||
Application.Top = new () { Width = 20, Height = 5 };
|
||||
Application.Top.Add (cp);
|
||||
|
||||
Application.Top.LayoutSubViews ();
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Terminal.Gui.DrawingTests;
|
||||
|
||||
public class AnsiColorNameResolverTests
|
||||
{
|
||||
private readonly AnsiColorNameResolver _candidate = new();
|
||||
|
||||
[Fact]
|
||||
public void GetNames_Returns16ColorNames ()
|
||||
{
|
||||
string[] expected = Enum.GetNames<ColorName16>();
|
||||
|
||||
string[] actual = _candidate.GetColorNames ().ToArray();
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (0, 0, 0, nameof (ColorName16.Black))]
|
||||
[InlineData (0, 0, 255, nameof (ColorName16.Blue))]
|
||||
[InlineData (59, 120, 255, nameof (ColorName16.BrightBlue))]
|
||||
[InlineData (97, 214, 214, nameof (ColorName16.BrightCyan))]
|
||||
[InlineData (22, 198, 12, nameof (ColorName16.BrightGreen))]
|
||||
[InlineData (180, 0, 158, nameof (ColorName16.BrightMagenta))]
|
||||
[InlineData (231, 72, 86, nameof (ColorName16.BrightRed))]
|
||||
[InlineData (249, 241, 165, nameof (ColorName16.BrightYellow))]
|
||||
[InlineData (0, 255, 255, nameof (ColorName16.Cyan))]
|
||||
[InlineData (118, 118, 118, nameof (ColorName16.DarkGray))]
|
||||
[InlineData (128, 128, 128, nameof (ColorName16.Gray))]
|
||||
[InlineData (0, 128, 0, nameof (ColorName16.Green))]
|
||||
[InlineData (255, 0, 255, nameof (ColorName16.Magenta))]
|
||||
[InlineData (255, 0, 0, nameof (ColorName16.Red))]
|
||||
[InlineData (255, 255, 255, nameof (ColorName16.White))]
|
||||
[InlineData (255, 255, 0, nameof (ColorName16.Yellow))]
|
||||
public void TryNameColor_ReturnsExpectedColorName (byte r, byte g, byte b, string expectedName)
|
||||
{
|
||||
var expected = (true, expectedName);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor(new Color(r, g, b), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_NoMatchFails ()
|
||||
{
|
||||
(bool, string?) expected = (false, null);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor (new Color (1, 2, 3), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (nameof (ColorName16.Black), 0, 0, 0)]
|
||||
[InlineData (nameof (ColorName16.Blue), 0, 0, 255)]
|
||||
[InlineData (nameof (ColorName16.BrightBlue), 59, 120, 255)]
|
||||
[InlineData (nameof (ColorName16.BrightCyan), 97, 214, 214)]
|
||||
[InlineData (nameof (ColorName16.BrightGreen), 22, 198, 12)]
|
||||
[InlineData (nameof (ColorName16.BrightMagenta), 180, 0, 158)]
|
||||
[InlineData (nameof (ColorName16.BrightRed), 231, 72, 86)]
|
||||
[InlineData (nameof (ColorName16.BrightYellow), 249, 241, 165)]
|
||||
[InlineData (nameof (ColorName16.Cyan), 0, 255, 255)]
|
||||
[InlineData (nameof (ColorName16.DarkGray), 118, 118, 118)]
|
||||
[InlineData (nameof (ColorName16.Gray), 128, 128, 128)]
|
||||
[InlineData (nameof (ColorName16.Green), 0, 128, 0)]
|
||||
[InlineData (nameof (ColorName16.Magenta), 255, 0, 255)]
|
||||
[InlineData (nameof (ColorName16.Red), 255, 0, 0)]
|
||||
[InlineData (nameof (ColorName16.White), 255, 255, 255)]
|
||||
[InlineData (nameof (ColorName16.Yellow), 255, 255, 0)]
|
||||
// Case-insensitive
|
||||
[InlineData ("BRIGHTBLUE", 59, 120, 255)]
|
||||
[InlineData ("brightblue", 59, 120, 255)]
|
||||
public void TryParseColor_ReturnsExpectedColor (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
var expected = (true, new Color(r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("12", 231, 72, 86)] // ColorName16.BrightRed
|
||||
public void TryParseColor_ResolvesValidEnumNumber (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
var expected = (true, new Color(r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (null)]
|
||||
[InlineData ("")]
|
||||
[InlineData ("brightlight")]
|
||||
public void TryParseColor_FailsOnInvalidColorName (string? invalidName)
|
||||
{
|
||||
var expected = (false, default(Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("-12")]
|
||||
public void TryParseColor_FailsOnInvalidEnumNumber (string invalidName)
|
||||
{
|
||||
var expected = (false, default(Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Terminal.Gui.DrawingTests;
|
||||
|
||||
public class MultiStandardColorNameResolverTests
|
||||
{
|
||||
private readonly MultiStandardColorNameResolver _candidate = new();
|
||||
|
||||
[Theory]
|
||||
// ANSI color names.
|
||||
[InlineData (nameof (ColorName16.Black))]
|
||||
[InlineData (nameof (ColorName16.White))]
|
||||
[InlineData (nameof (ColorName16.Red))]
|
||||
[InlineData (nameof (ColorName16.Green))]
|
||||
[InlineData (nameof (ColorName16.Blue))]
|
||||
[InlineData (nameof (ColorName16.Cyan))]
|
||||
[InlineData (nameof (ColorName16.Magenta))]
|
||||
[InlineData (nameof (ColorName16.DarkGray))]
|
||||
[InlineData (nameof (ColorName16.BrightGreen))]
|
||||
[InlineData (nameof (ColorName16.BrightMagenta))]
|
||||
// Regular W3C color.
|
||||
[InlineData (nameof (W3cColor.AliceBlue))]
|
||||
[InlineData (nameof (W3cColor.BlanchedAlmond))]
|
||||
[InlineData (nameof (W3cColor.CadetBlue))]
|
||||
[InlineData (nameof (W3cColor.DarkBlue))]
|
||||
[InlineData (nameof (W3cColor.FireBrick))]
|
||||
[InlineData (nameof (W3cColor.Gainsboro))]
|
||||
[InlineData (nameof (W3cColor.HoneyDew))]
|
||||
[InlineData (nameof (W3cColor.Indigo))]
|
||||
[InlineData (nameof (W3cColor.Khaki))]
|
||||
[InlineData (nameof (W3cColor.Lavender))]
|
||||
[InlineData (nameof (W3cColor.Maroon))]
|
||||
[InlineData (nameof (W3cColor.Navy))]
|
||||
[InlineData (nameof (W3cColor.Olive))]
|
||||
[InlineData (nameof (W3cColor.Plum))]
|
||||
[InlineData (nameof (W3cColor.RoyalBlue))]
|
||||
[InlineData (nameof (W3cColor.Silver))]
|
||||
[InlineData (nameof (W3cColor.Tomato))]
|
||||
[InlineData (nameof (W3cColor.Violet))]
|
||||
[InlineData (nameof (W3cColor.WhiteSmoke))]
|
||||
[InlineData (nameof (W3cColor.YellowGreen))]
|
||||
// W3C alternatives.
|
||||
[InlineData (nameof (W3cColor.Grey))]
|
||||
[InlineData (nameof (W3cColor.DarkGrey))]
|
||||
[InlineData (nameof (W3cColor.Aqua))]
|
||||
[InlineData (nameof (W3cColor.Fuchsia))]
|
||||
[InlineData (nameof (W3cColor.DarkSlateGray))]
|
||||
[InlineData (nameof (W3cColor.DarkSlateGrey))]
|
||||
[InlineData (nameof (W3cColor.DimGray))]
|
||||
[InlineData (nameof (W3cColor.DimGrey))]
|
||||
[InlineData (nameof (W3cColor.LightGray))]
|
||||
[InlineData (nameof (W3cColor.LightGrey))]
|
||||
[InlineData (nameof (W3cColor.SlateGray))]
|
||||
[InlineData (nameof (W3cColor.SlateGrey))]
|
||||
public void GetNames_ContainsCombinationOfAnsiAndW3cNames (string name)
|
||||
{
|
||||
string[] names = _candidate.GetColorNames ().ToArray();
|
||||
Assert.Contains (name, names);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// ANSI color names
|
||||
[InlineData (0, 0, 0, nameof (ColorName16.Black))]
|
||||
[InlineData (0, 0, 255, nameof (ColorName16.Blue))]
|
||||
[InlineData (59, 120, 255, nameof (ColorName16.BrightBlue))]
|
||||
[InlineData (97, 214, 214, nameof (ColorName16.BrightCyan))]
|
||||
[InlineData (22, 198, 12, nameof (ColorName16.BrightGreen))]
|
||||
[InlineData (180, 0, 158, nameof (ColorName16.BrightMagenta))]
|
||||
[InlineData (231, 72, 86, nameof (ColorName16.BrightRed))]
|
||||
[InlineData (249, 241, 165, nameof (ColorName16.BrightYellow))]
|
||||
[InlineData (0, 255, 255, nameof (ColorName16.Cyan))]
|
||||
[InlineData (118, 118, 118, nameof (ColorName16.DarkGray))]
|
||||
[InlineData (128, 128, 128, nameof (ColorName16.Gray))]
|
||||
[InlineData (0, 128, 0, nameof (ColorName16.Green))]
|
||||
[InlineData (255, 0, 255, nameof (ColorName16.Magenta))]
|
||||
[InlineData (255, 0, 0, nameof (ColorName16.Red))]
|
||||
[InlineData (255, 255, 255, nameof (ColorName16.White))]
|
||||
[InlineData (255, 255, 0, nameof (ColorName16.Yellow))]
|
||||
// W3C color names
|
||||
[InlineData (240, 248, 255, nameof (W3cColor.AliceBlue))]
|
||||
[InlineData (255, 235, 205, nameof (W3cColor.BlanchedAlmond))]
|
||||
[InlineData (95, 158, 160, nameof (W3cColor.CadetBlue))]
|
||||
[InlineData (0, 0, 139, nameof (W3cColor.DarkBlue))]
|
||||
[InlineData (178, 34, 34, nameof (W3cColor.FireBrick))]
|
||||
[InlineData (220, 220, 220, nameof (W3cColor.Gainsboro))]
|
||||
[InlineData (240, 255, 240, nameof (W3cColor.HoneyDew))]
|
||||
[InlineData (75, 0, 130, nameof (W3cColor.Indigo))]
|
||||
[InlineData (240, 230, 140, nameof (W3cColor.Khaki))]
|
||||
[InlineData (230, 230, 250, nameof (W3cColor.Lavender))]
|
||||
[InlineData (128, 0, 0, nameof (W3cColor.Maroon))]
|
||||
[InlineData (0, 0, 128, nameof (W3cColor.Navy))]
|
||||
[InlineData (128, 128, 0, nameof (W3cColor.Olive))]
|
||||
[InlineData (221, 160, 221, nameof (W3cColor.Plum))]
|
||||
[InlineData (65, 105, 225, nameof (W3cColor.RoyalBlue))]
|
||||
[InlineData (192, 192, 192, nameof (W3cColor.Silver))]
|
||||
[InlineData (255, 99, 71, nameof (W3cColor.Tomato))]
|
||||
[InlineData (238, 130, 238, nameof (W3cColor.Violet))]
|
||||
[InlineData (245, 245, 245, nameof (W3cColor.WhiteSmoke))]
|
||||
[InlineData (154, 205, 50, nameof (W3cColor.YellowGreen))]
|
||||
public void TryNameColor_ReturnsExpectedColorNames (byte r, byte g, byte b, string expectedName)
|
||||
{
|
||||
var expected = (true, expectedName);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor(new Color(r, g, b), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (169, 169, 169)] // W3cColor.DarkGr(a|e)y
|
||||
public void TryNameColor_OmitsBlockedW3cColors (byte r, byte g, byte b)
|
||||
{
|
||||
(bool, string?) expected = (false, null);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor (new Color (r, g, b), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_NoMatchFails ()
|
||||
{
|
||||
(bool, string?) expected = (false, null);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor (new Color (1, 2, 3), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// ANSI colors
|
||||
[InlineData (nameof (ColorName16.Black), 0, 0, 0)]
|
||||
[InlineData (nameof (ColorName16.Blue), 0, 0, 255)]
|
||||
[InlineData (nameof (ColorName16.BrightBlue), 59, 120, 255)]
|
||||
[InlineData (nameof (ColorName16.BrightCyan), 97, 214, 214)]
|
||||
[InlineData (nameof (ColorName16.BrightGreen), 22, 198, 12)]
|
||||
[InlineData (nameof (ColorName16.BrightMagenta), 180, 0, 158)]
|
||||
[InlineData (nameof (ColorName16.BrightRed), 231, 72, 86)]
|
||||
[InlineData (nameof (ColorName16.BrightYellow), 249, 241, 165)]
|
||||
[InlineData (nameof (ColorName16.Cyan), 0, 255, 255)]
|
||||
[InlineData (nameof (ColorName16.DarkGray), 118, 118, 118)]
|
||||
[InlineData (nameof (ColorName16.Gray), 128, 128, 128)]
|
||||
[InlineData (nameof (ColorName16.Green), 0, 128, 0)]
|
||||
[InlineData (nameof (ColorName16.Magenta), 255, 0, 255)]
|
||||
[InlineData (nameof (ColorName16.Red), 255, 0, 0)]
|
||||
[InlineData (nameof (ColorName16.White), 255, 255, 255)]
|
||||
[InlineData (nameof (ColorName16.Yellow), 255, 255, 0)]
|
||||
// W3C color name => substituted ANSI color
|
||||
[InlineData (nameof (W3cColor.Fuchsia), 255, 0, 255)] // ANSI Magenta
|
||||
[InlineData (nameof (W3cColor.DarkGrey), 118, 118, 118)] // ANSI Dark Gray
|
||||
[InlineData (nameof (W3cColor.Grey), 128, 128, 128)] // ANSI Gray
|
||||
[InlineData (nameof (W3cColor.Aqua), 0, 255, 255)] // ANSI Cyan
|
||||
// W3C colors
|
||||
[InlineData (nameof (W3cColor.AliceBlue), 240, 248, 255)]
|
||||
[InlineData (nameof (W3cColor.BlanchedAlmond), 255, 235, 205)]
|
||||
[InlineData (nameof (W3cColor.CadetBlue), 95, 158, 160)]
|
||||
[InlineData (nameof (W3cColor.DarkBlue), 0, 0, 139)]
|
||||
[InlineData (nameof (W3cColor.FireBrick), 178, 34, 34)]
|
||||
[InlineData (nameof (W3cColor.Gainsboro), 220, 220, 220)]
|
||||
[InlineData (nameof (W3cColor.HoneyDew), 240, 255, 240)]
|
||||
[InlineData (nameof (W3cColor.Indigo), 75, 0, 130)]
|
||||
[InlineData (nameof (W3cColor.Khaki), 240, 230, 140)]
|
||||
[InlineData (nameof (W3cColor.Lavender), 230, 230, 250)]
|
||||
[InlineData (nameof (W3cColor.Maroon), 128, 0, 0)]
|
||||
[InlineData (nameof (W3cColor.Navy), 0, 0, 128)]
|
||||
[InlineData (nameof (W3cColor.Olive), 128, 128, 0)]
|
||||
[InlineData (nameof (W3cColor.Plum), 221, 160, 221)]
|
||||
[InlineData (nameof (W3cColor.RoyalBlue), 65, 105, 225)]
|
||||
[InlineData (nameof (W3cColor.Silver), 192, 192, 192)]
|
||||
[InlineData (nameof (W3cColor.Tomato), 255, 99, 71)]
|
||||
[InlineData (nameof (W3cColor.Violet), 238, 130, 238)]
|
||||
[InlineData (nameof (W3cColor.WhiteSmoke), 245, 245, 245)]
|
||||
[InlineData (nameof (W3cColor.YellowGreen), 154, 205, 50)]
|
||||
// Case-insensitive
|
||||
[InlineData ("BRIGHTBLUE", 59, 120, 255)]
|
||||
[InlineData ("brightblue", 59, 120, 255)]
|
||||
[InlineData ("TOMATO", 255, 99, 71)]
|
||||
[InlineData ("tomato", 255, 99, 71)]
|
||||
|
||||
public void TryParseColor_ResolvesCombinationOfAnsiAndW3cColors (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
var expected = (true, new Color(r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("12", 231, 72, 86)] // ColorName16.BrightRed
|
||||
[InlineData ("16737095", 255, 99, 71)] // W3cColor.Tomato
|
||||
public void TryParseColor_ResolvesValidEnumNumber (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
var expected = (true, new Color(r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (null)]
|
||||
[InlineData ("")]
|
||||
[InlineData ("brightlight")]
|
||||
public void TryParseColor_FailsOnInvalidColorName (string? invalidName)
|
||||
{
|
||||
var expected = (false, default(Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("-12")]
|
||||
[InlineData ("-16737095")]
|
||||
public void TryParseColor_FailsOnInvalidEnumNumber (string invalidName)
|
||||
{
|
||||
var expected = (false, default(Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Terminal.Gui.DrawingTests;
|
||||
|
||||
public class W3cColorNameResolverTests
|
||||
{
|
||||
private readonly W3cColorNameResolver _candidate = new();
|
||||
|
||||
[Fact]
|
||||
public void GetColorNames_NamesAreInAlphabeticalOrder ()
|
||||
{
|
||||
string[] alphabeticallyOrderedNames = Enum.GetNames<W3cColor> ().Order ().ToArray ();
|
||||
|
||||
Assert.Equal (alphabeticallyOrderedNames, _candidate.GetColorNames ());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (nameof (W3cColor.Aqua))]
|
||||
[InlineData (nameof (W3cColor.Cyan))]
|
||||
[InlineData (nameof (W3cColor.DarkGray))]
|
||||
[InlineData (nameof (W3cColor.DarkGrey))]
|
||||
[InlineData (nameof (W3cColor.DarkSlateGray))]
|
||||
[InlineData (nameof (W3cColor.DarkSlateGrey))]
|
||||
[InlineData (nameof (W3cColor.DimGray))]
|
||||
[InlineData (nameof (W3cColor.DimGrey))]
|
||||
[InlineData (nameof (W3cColor.Fuchsia))]
|
||||
[InlineData (nameof (W3cColor.LightGray))]
|
||||
[InlineData (nameof (W3cColor.LightGrey))]
|
||||
[InlineData (nameof (W3cColor.LightSlateGray))]
|
||||
[InlineData (nameof (W3cColor.LightSlateGrey))]
|
||||
[InlineData (nameof (W3cColor.Magenta))]
|
||||
[InlineData (nameof (W3cColor.SlateGray))]
|
||||
[InlineData (nameof (W3cColor.SlateGrey))]
|
||||
public void GetColorNames_IncludesNamesWithSameValues (string name)
|
||||
{
|
||||
string[] names = _candidate.GetColorNames ().ToArray();
|
||||
|
||||
Assert.True (names.Contains (name), $"W3C color names is missing '{name}'.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (240, 248, 255, nameof (W3cColor.AliceBlue))]
|
||||
[InlineData (0, 255, 255, nameof (W3cColor.Aqua))]
|
||||
[InlineData (255, 0, 0, nameof (W3cColor.Red))]
|
||||
[InlineData (0, 128, 0, nameof (W3cColor.Green))]
|
||||
[InlineData (0, 0, 255, nameof (W3cColor.Blue))]
|
||||
[InlineData (0, 255, 0, nameof (W3cColor.Lime))]
|
||||
[InlineData (0, 0, 0, nameof (W3cColor.Black))]
|
||||
[InlineData (255, 255, 255, nameof (W3cColor.White))]
|
||||
[InlineData (154, 205, 50, nameof (W3cColor.YellowGreen))]
|
||||
public void TryNameColor_ReturnsExpectedColorName (int r, int g, int b, string expectedName)
|
||||
{
|
||||
var expected = (true, expectedName);
|
||||
|
||||
Color inputColor = new(r, g, b);
|
||||
bool actualSuccess = _candidate.TryNameColor (inputColor, out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryNameColor_NoMatchFails ()
|
||||
{
|
||||
(bool, string?) expected = (false, null);
|
||||
|
||||
bool actualSuccess = _candidate.TryNameColor (new Color (1, 2, 3), out string? actualName);
|
||||
var actual = (actualSuccess, actualName);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (nameof (W3cColor.AliceBlue), 240, 248, 255)]
|
||||
[InlineData (nameof (W3cColor.BlanchedAlmond), 255, 235, 205)]
|
||||
[InlineData (nameof (W3cColor.CadetBlue), 95, 158, 160)]
|
||||
[InlineData (nameof (W3cColor.DarkBlue), 0, 0, 139)]
|
||||
[InlineData (nameof (W3cColor.FireBrick), 178, 34, 34)]
|
||||
[InlineData (nameof (W3cColor.Gainsboro), 220, 220, 220)]
|
||||
[InlineData (nameof (W3cColor.HoneyDew), 240, 255, 240)]
|
||||
[InlineData (nameof (W3cColor.Indigo), 75, 0, 130)]
|
||||
[InlineData (nameof (W3cColor.Khaki), 240, 230, 140)]
|
||||
[InlineData (nameof (W3cColor.Lavender), 230, 230, 250)]
|
||||
[InlineData (nameof (W3cColor.Maroon), 128, 0, 0)]
|
||||
[InlineData (nameof (W3cColor.Navy), 0, 0, 128)]
|
||||
[InlineData (nameof (W3cColor.Olive), 128, 128, 0)]
|
||||
[InlineData (nameof (W3cColor.Plum), 221, 160, 221)]
|
||||
[InlineData (nameof (W3cColor.RoyalBlue), 65, 105, 225)]
|
||||
[InlineData (nameof (W3cColor.Silver), 192, 192, 192)]
|
||||
[InlineData (nameof (W3cColor.Tomato), 255, 99, 71)]
|
||||
[InlineData (nameof (W3cColor.Violet), 238, 130, 238)]
|
||||
[InlineData (nameof (W3cColor.WhiteSmoke), 245, 245, 245)]
|
||||
[InlineData (nameof (W3cColor.YellowGreen), 154, 205, 50)]
|
||||
// Aliases also work
|
||||
[InlineData (nameof (W3cColor.Aqua), 0, 255, 255)]
|
||||
[InlineData (nameof (W3cColor.Cyan), 0, 255, 255)]
|
||||
[InlineData (nameof (W3cColor.DarkGray), 169, 169, 169)]
|
||||
[InlineData (nameof (W3cColor.DarkGrey), 169, 169, 169)]
|
||||
// Case-insensitive
|
||||
[InlineData ("Red", 255, 0, 0)]
|
||||
[InlineData ("red", 255, 0, 0)]
|
||||
[InlineData ("RED", 255, 0, 0)]
|
||||
public void TryParseColor_ReturnsExpectedColor (string inputName, int r, int g, int b)
|
||||
{
|
||||
var expected = (true, new Color(r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("16737095", 255, 99, 71)] // W3cColor.Tomato
|
||||
public void TryParseColor_ResolvesValidEnumNumber (string inputName, byte r, byte g, byte b)
|
||||
{
|
||||
var expected = (true, new Color(r, g, b));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (inputName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData (null)]
|
||||
[InlineData ("")]
|
||||
[InlineData ("brightlight")]
|
||||
public void TryParseColor_FailsOnInvalidColorName (string? invalidName)
|
||||
{
|
||||
var expected = (false, default(Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData ("-16737095")]
|
||||
public void TryParseColor_FailsOnInvalidEnumNumber (string invalidName)
|
||||
{
|
||||
var expected = (false, default(Color));
|
||||
|
||||
bool actualSuccess = _candidate.TryParseColor (invalidName, out Color actualColor);
|
||||
var actual = (actualSuccess, actualColor);
|
||||
|
||||
Assert.Equal (expected, actual);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user