From b7f1d64f95e91aa41f22272ed2bd470634ec0416 Mon Sep 17 00:00:00 2001 From: Tigger Kindel Date: Wed, 11 Oct 2023 11:12:22 -0600 Subject: [PATCH] Refactored argb->rgba to match ARGB32 standards --- Terminal.Gui/Drawing/Color.cs | 134 ++++++++++++++++++-------------- UnitTests/Drawing/ColorTests.cs | 26 +++---- 2 files changed, 87 insertions(+), 73 deletions(-) diff --git a/Terminal.Gui/Drawing/Color.cs b/Terminal.Gui/Drawing/Color.cs index 47d0884f3..459f3e8be 100644 --- a/Terminal.Gui/Drawing/Color.cs +++ b/Terminal.Gui/Drawing/Color.cs @@ -10,7 +10,8 @@ using System.Text.RegularExpressions; namespace Terminal.Gui { /// - /// Defines the 16 legacy color names and values that can be used to set the foreground and background colors in Terminal.Gui apps. Used with . + /// Defines the 16 legacy color names and values that can be used to set the + /// foreground and background colors in Terminal.Gui apps. Used with . /// /// /// @@ -91,39 +92,25 @@ namespace Terminal.Gui { /// /// Initializes a new instance of the class. /// - /// - /// - /// - public Color (int red, int green, int blue) + /// The red 8-bits. + /// The green 8-bits. + /// The blue 8-bits. + /// Optional; defaults to 0xFF. The Alpha channel is not supported by Terminal.Gui. + public Color (int red, int green, int blue, int alpha = 0xFF) { - A = 0xFF; R = red; G = green; B = blue; - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - public Color (int alpha, int red, int green, int blue) - { A = alpha; - R = red; - G = green; - B = blue; } /// /// Initializes a new instance of the class with an encoded 24-bit color value. /// - /// The encoded 24-bit color value. - public Color (int argb) + /// The encoded 24-bit color value (see ). + public Color (int rgba) { - Value = argb; + Rgba = rgba; } /// @@ -133,10 +120,26 @@ namespace Terminal.Gui { public Color (ColorNames colorName) { var c = Color.FromColorName (colorName); - A = c.A; R = c.R; G = c.G; B = c.B; + A = c.A; + } + + /// + /// Initializes a new instance of the color from string. See for details. + /// + /// + /// + public Color (string colorString) + { + if (!TryParse (colorString, out var c)) { + throw new ArgumentOutOfRangeException (nameof (colorString)); + } + R = c.R; + G = c.G; + B = c.B; + A = c.A; } /// @@ -144,10 +147,10 @@ namespace Terminal.Gui { /// public Color () { - A = 0xFF; R = 0; G = 0; B = 0; + A = 0xFF; } /// @@ -167,17 +170,17 @@ namespace Terminal.Gui { /// Alpha color component. /// /// - /// Not currently supported; here for completeness. + /// The Alpha channel is not supported by Terminal.Gui. /// - public int A { get; set; } + public int A { get; set; } = 0xFF; // Not currently supported; here for completeness. /// - /// Gets or sets the color value encoded using the following code: + /// Gets or sets the color value encoded as ARGB32. /// /// (<see cref="A"/> << 24) | (<see cref="R"/> << 16) | (<see cref="G"/> << 8) | <see cref="B"/> /// /// - public int Value { + public int Rgba { get => (A << 24) | (R << 16) | (G << 8) | B; set { A = (byte)((value >> 24) & 0xFF); @@ -194,6 +197,7 @@ namespace Terminal.Gui { /// internal static readonly ImmutableDictionary _colorNames = new Dictionary () { // using "Windows 10 Console/PowerShell 6" here: https://i.stack.imgur.com/9UVnC.png + // See also: https://en.wikipedia.org/wiki/ANSI_escape_code { new Color (12, 12, 12),ColorNames.Black }, { new Color (0, 55, 218),ColorNames.Blue }, { new Color (19, 161, 14),ColorNames.Green}, @@ -260,10 +264,10 @@ namespace Terminal.Gui { set { var c = FromColorName (value); - A = c.A; R = c.R; G = c.G; B = c.B; + A = c.A; } } @@ -337,11 +341,16 @@ namespace Terminal.Gui { #endregion /// - /// Converts the provided text to a new instance. + /// Converts the provided string to a new instance. /// - /// The text to analyze. + /// The text to analyze. Formats supported are + /// "#RGB", "#RRGGBB", "#RGBA", "#RRGGBBAA", "rgb(r,g,b)", "rgb(r,g,b,a)", and any of the + /// . /// The parsed value. - /// A boolean value indicating whether it was successful. + /// A boolean value indicating whether parsing was successful. + /// + /// While supports the alpha channel , Terminal.Gui does not. + /// public static bool TryParse (string text, [NotNullWhen (true)] out Color color) { // empty color @@ -370,25 +379,25 @@ namespace Terminal.Gui { return true; } - // #AARRGGBB, #ARGB + // #RRGGBB, #RGBA if ((text [0] == '#') && text.Length is 8 or 5) { if (text.Length == 7) { - var a = Convert.ToInt32 (text.Substring (1, 2), 16); - var r = Convert.ToInt32 (text.Substring (3, 2), 16); - var g = Convert.ToInt32 (text.Substring (5, 2), 16); - var b = Convert.ToInt32 (text.Substring (7, 2), 16); + var r = Convert.ToInt32 (text.Substring (1, 2), 16); + var g = Convert.ToInt32 (text.Substring (3, 2), 16); + var b = Convert.ToInt32 (text.Substring (5, 2), 16); + var a = Convert.ToInt32 (text.Substring (7, 2), 16); color = new Color (a, r, g, b); } else { - var aText = char.ToString (text [1]); - var rText = char.ToString (text [2]); - var gText = char.ToString (text [3]); - var bText = char.ToString (text [4]); + var rText = char.ToString (text [1]); + var gText = char.ToString (text [2]); + var bText = char.ToString (text [3]); + var aText = char.ToString (text [4]); - var a = Convert.ToInt32 (aText + aText, 16); - var r = Convert.ToInt32 (rText + rText, 16); - var g = Convert.ToInt32 (gText + gText, 16); - var b = Convert.ToInt32 (bText + bText, 16); - color = new Color (a, r, g, b); + var r = Convert.ToInt32 (aText + aText, 16); + var g = Convert.ToInt32 (rText + rText, 16); + var b = Convert.ToInt32 (gText + gText, 16); + var a = Convert.ToInt32 (bText + bText, 16); + color = new Color (r, g, b, a); } return true; } @@ -403,14 +412,14 @@ namespace Terminal.Gui { return true; } - // rgb(a,r,g,b) + // rgb(r,g,b,a) match = Regex.Match (text, @"rgb\((\d+),(\d+),(\d+),(\d+)\)"); if (match.Success) { - var a = int.Parse (match.Groups [1].Value); - var r = int.Parse (match.Groups [2].Value); - var g = int.Parse (match.Groups [3].Value); - var b = int.Parse (match.Groups [4].Value); - color = new Color (a, r, g, b); + var r = int.Parse (match.Groups [1].Value); + var g = int.Parse (match.Groups [2].Value); + var b = int.Parse (match.Groups [3].Value); + var a = int.Parse (match.Groups [4].Value); + color = new Color (r, g, b, a); return true; } @@ -422,10 +431,10 @@ namespace Terminal.Gui { /// /// Cast from int. /// - /// - public static implicit operator Color (int argb) + /// + public static implicit operator Color (int rgba) { - return new Color (argb); + return new Color (rgba); } /// @@ -434,7 +443,7 @@ namespace Terminal.Gui { /// public static explicit operator int (Color color) { - return color.Value; + return color.Rgba; } /// @@ -546,16 +555,16 @@ namespace Terminal.Gui { public bool Equals (Color other) { return - A == other.A && R == other.R && G == other.G && - B == other.B; + B == other.B && + A == other.A; } /// public override int GetHashCode () { - return HashCode.Combine (A, R, G, B); + return HashCode.Combine (R, G, B, A); } #endregion @@ -563,7 +572,12 @@ namespace Terminal.Gui { /// Converts the color to a string representation. /// /// + /// /// If the color is a named color, the name is returned. Otherwise, the color is returned as a hex string. + /// + /// + /// (Alpha channel) is ignored and the returned string will not include it. + /// /// /// public override string ToString () diff --git a/UnitTests/Drawing/ColorTests.cs b/UnitTests/Drawing/ColorTests.cs index 41f74ce6f..c66288aef 100644 --- a/UnitTests/Drawing/ColorTests.cs +++ b/UnitTests/Drawing/ColorTests.cs @@ -108,29 +108,29 @@ public class ColorTests { int expectedB = 128; // Act - var color = new Color (expectedA, expectedR, expectedG, expectedB); + var color = new Color (expectedR, expectedG, expectedB, expectedA); // Assert - Assert.Equal (expectedA, color.A); Assert.Equal (expectedR, color.R); Assert.Equal (expectedG, color.G); Assert.Equal (expectedB, color.B); + Assert.Equal (expectedA, color.A); } [Fact] - public void Color_Constructor_WithArgbValue () + public void Color_Constructor_WithRgbaValue () { // Arrange - int expectedArgb = unchecked((int)0xFF804040); // Alpha: 255, R: 128, G: 64, B: 64 + int expectedRgba = unchecked((int)0xFF804040); // R: 128, G: 64, B: 64, Alpha: 255 // Act - var color = new Color (expectedArgb); + var color = new Color (expectedRgba); // Assert - Assert.Equal (255, color.A); Assert.Equal (128, color.R); Assert.Equal (64, color.G); Assert.Equal (64, color.B); + Assert.Equal (255, color.A); } [Fact] @@ -177,11 +177,11 @@ public class ColorTests { public void Color_ImplicitOperator_FromInt () { // Arrange - int argb = unchecked((int)0xFF804020); // Alpha: 255, R: 128, G: 64, B: 32 - var expectedColor = new Color (255, 128, 64, 32); + int Rgba = unchecked((int)0xFF804020); // R: 128, G: 64, B: 32, Alpha: 255 + var expectedColor = new Color (128, 64, 32); // Act - Color color = argb; + Color color = Rgba; // Assert Assert.Equal (expectedColor, color); @@ -191,14 +191,14 @@ public class ColorTests { public void Color_ExplicitOperator_ToInt () { // Arrange - var color = new Color (255, 128, 64, 32); - int expectedArgb = unchecked((int)0xFF804020); // Alpha: 255, R: 128, G: 64, B: 32 + var color = new Color (128, 64, 32); + int expectedRgba = unchecked((int)0xFF804020); // R: 128, G: 64, B: 32, Alpha: 255 // Act - int argb = (int)color; + int Rgba = (int)color; // Assert - Assert.Equal (expectedArgb, argb); + Assert.Equal (expectedRgba, Rgba); }