瀏覽代碼

Fixes #4289 - Simplify Drawing/Color: unify named color handling under StandardColor and remove layered resolvers (#4432)

* Initial plan

* Delete AnsiColorNameResolver and MultiStandardColorNameResolver, add legacy 16-color names to StandardColor

Co-authored-by: tig <[email protected]>

* Refactor and enhance tests for Color, Region, and Lines

Refactored `Color` struct by removing unused methods and simplifying logic. Updated namespaces for better organization. Enhanced test coverage for `Color`, `Region`, and `LineCanvas` with new test cases, parameterized tests, and edge case handling.

Added `StraightLineExtensionsTests`, `StraightLineTests`, and `RegionClassTests` to validate behavior under various scenarios. Improved `MergeRectangles` stability and addressed crash patterns. Removed legacy features and unused code. Enhanced documentation and optimized performance in key methods.

* Improve Color struct and StandardColors functionality

Enhanced the Color struct to fully support the alpha channel for rendering intent while maintaining semantic color identity. Updated TryNameColor to ignore alpha when matching colors, ensuring transparency does not affect color resolution. Expanded XML documentation to clarify alpha channel usage and future alpha blending support.

Improved drawing documentation to explain the lifecycle, deferred rendering, and color support, including 24-bit true color and legacy 16-color compatibility. Added a new section on transparency and its role in rendering.

Revised StandardColors implementation to use modern C# features and ensure consistent ARGB mapping. Added comprehensive tests for StandardColors and Color, covering alpha handling, color parsing, thread safety, and aliased color resolution. Removed outdated tests relying on legacy behavior.

Enhanced code readability, maintainability, and test coverage to ensure correctness and backward compatibility.

* Code cleanup

* Code cleanup

* Fix warnings. Code cleanup

* Add comprehensive unit tests for ColorStrings class

Introduced a new test class `ColorStringsTests` under the
`DrawingTests.ColorTests` namespace to validate the functionality
of the `ColorStrings` class.

Key changes include:
- Added tests for `GetColorName` to verify behavior for standard
  and non-standard colors, ignoring alpha channels, and handling
  known colors.
- Added tests for `GetStandardColorNames` to ensure the method
  returns a non-empty, alphabetically sorted collection containing
  all `StandardColor` enum values.
- Implemented tests for `TryParseStandardColorName` to validate
  case-insensitive parsing, hex color support, handling invalid
  input, and `ReadOnlySpan<char>` compatibility.
- Added tests for `TryParseNamedColor` to verify parsing of named
  and hex colors, handling of aliases, and `ReadOnlySpan<char>`
  support.
- Added round-trip tests to ensure consistency between
  `GetColorName`, `TryParseNamedColor`, `GetStandardColorNames`,
  and `TryParseStandardColorName`.

These tests ensure robust validation of color parsing and naming
functionality.

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: tig <[email protected]>
Co-authored-by: Tig <[email protected]>
Copilot 1 周之前
父節點
當前提交
6d53276be2
共有 43 個文件被更改,包括 951 次插入835 次删除
  1. 108 119
      Examples/UICatalog/Scenarios/ColorPicker.cs
  2. 0 68
      Terminal.Gui/Drawing/Color/AnsiColorNameResolver.cs
  3. 34 50
      Terminal.Gui/Drawing/Color/Color.cs
  4. 6 5
      Terminal.Gui/Drawing/Color/ColorModel.cs
  5. 3 3
      Terminal.Gui/Drawing/Color/ColorQuantizer.cs
  6. 6 53
      Terminal.Gui/Drawing/Color/ColorStrings.cs
  7. 0 83
      Terminal.Gui/Drawing/Color/MultiStandardColorNameResolver.cs
  8. 60 1
      Terminal.Gui/Drawing/Color/StandardColor.cs
  9. 5 2
      Terminal.Gui/Drawing/Color/StandardColors.cs
  10. 0 2
      Terminal.Gui/Views/Color/BBar.cs
  11. 1 4
      Terminal.Gui/Views/Color/ColorBar.cs
  12. 28 45
      Terminal.Gui/Views/Color/ColorModelStrategy.cs
  13. 0 3
      Terminal.Gui/Views/Color/ColorPicker.Style.cs
  14. 0 2
      Terminal.Gui/Views/Color/GBar.cs
  15. 1 2
      Terminal.Gui/Views/Color/IColorBar.cs
  16. 0 2
      Terminal.Gui/Views/Color/LightnessBar.cs
  17. 0 2
      Terminal.Gui/Views/Color/RBar.cs
  18. 0 2
      Terminal.Gui/Views/Color/SaturationBar.cs
  19. 1 0
      Terminal.sln.DotSettings
  20. 1 1
      Tests/StressTests/ApplicationStressTests.cs
  21. 1 1
      Tests/UnitTestsParallelizable/Application/TimeoutTests.cs
  22. 3 3
      Tests/UnitTestsParallelizable/Configuration/ColorJsonConverterTests.cs
  23. 6 6
      Tests/UnitTestsParallelizable/Configuration/SourcesManagerTests.cs
  24. 0 168
      Tests/UnitTestsParallelizable/Drawing/Color/AnsiColorNameResolverTests.cs
  25. 2 2
      Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.Constructors.cs
  26. 2 2
      Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.Operators.cs
  27. 2 2
      Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.ParsingAndFormatting.cs
  28. 2 2
      Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.TypeChecks.cs
  29. 3 4
      Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.cs
  30. 0 27
      Tests/UnitTestsParallelizable/Drawing/Color/ColorStandardColorTests.cs
  31. 326 0
      Tests/UnitTestsParallelizable/Drawing/Color/ColorStringsTests.cs
  32. 0 156
      Tests/UnitTestsParallelizable/Drawing/Color/MultiStandardColorNameResolverTests.cs
  33. 2 4
      Tests/UnitTestsParallelizable/Drawing/Color/StandardColorNameResolverTests.cs
  34. 268 0
      Tests/UnitTestsParallelizable/Drawing/Color/StandardColorsTests.cs
  35. 1 1
      Tests/UnitTestsParallelizable/Drawing/Lines/LineCanvasTests.cs
  36. 1 1
      Tests/UnitTestsParallelizable/Drawing/Lines/StraightLineExtensionsTests.cs
  37. 1 1
      Tests/UnitTestsParallelizable/Drawing/Lines/StraightLineTests.cs
  38. 1 1
      Tests/UnitTestsParallelizable/Drawing/Region/DifferenceTests.cs
  39. 1 1
      Tests/UnitTestsParallelizable/Drawing/Region/DrawOuterBoundaryTests.cs
  40. 1 1
      Tests/UnitTestsParallelizable/Drawing/Region/MergeRectanglesTests.cs
  41. 2 2
      Tests/UnitTestsParallelizable/Drawing/Region/RegionClassTests.cs
  42. 1 1
      Tests/UnitTestsParallelizable/Drawing/Region/SubtractRectangleTests.cs
  43. 71 0
      docfx/docs/drawing.md

+ 108 - 119
Examples/UICatalog/Scenarios/ColorPicker.cs

@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-
-namespace UICatalog.Scenarios;
+namespace UICatalog.Scenarios;
 
 [ScenarioMetadata ("ColorPicker", "Color Picker and TrueColor demonstration.")]
 [ScenarioCategory ("Colors")]
@@ -18,25 +15,25 @@ public class ColorPickers : Scenario
     private Label _foregroundColorLabel;
 
     /// <summary>Background ColorPicker.</summary>
-    private ColorPicker backgroundColorPicker;
+    private ColorPicker _backgroundColorPicker;
 
     /// <summary>Foreground ColorPicker.</summary>
-    private ColorPicker foregroundColorPicker;
+    private ColorPicker _foregroundColorPicker;
 
     /// <summary>Background ColorPicker.</summary>
-    private ColorPicker16 backgroundColorPicker16;
+    private ColorPicker16 _backgroundColorPicker16;
 
     /// <summary>Foreground ColorPicker.</summary>
-    private ColorPicker16 foregroundColorPicker16;
+    private ColorPicker16 _foregroundColorPicker16;
 
-    /// <summary>Setup the scenario.</summary>
+    /// <summary>Set up the scenario.</summary>
     public override void Main ()
     {
         Application.Init ();
 
         Window app = new ()
         {
-            Title = GetQuitKeyAndName (),
+            Title = GetQuitKeyAndName ()
         };
 
         ///////////////////////////////////////
@@ -44,23 +41,23 @@ public class ColorPickers : Scenario
         ///////////////////////////////////////
 
         // Foreground ColorPicker.
-        foregroundColorPicker = new ColorPicker
+        _foregroundColorPicker = new ()
         {
             Title = "_Foreground Color",
             BorderStyle = LineStyle.Single,
             Width = Dim.Percent (50)
         };
-        foregroundColorPicker.ColorChanged += ForegroundColor_ColorChanged;
-        app.Add (foregroundColorPicker);
+        _foregroundColorPicker.ColorChanged += ForegroundColor_ColorChanged;
+        app.Add (_foregroundColorPicker);
 
-        _foregroundColorLabel = new Label
+        _foregroundColorLabel = new ()
         {
-            X = Pos.Left (foregroundColorPicker), Y = Pos.Bottom (foregroundColorPicker) + 1
+            X = Pos.Left (_foregroundColorPicker), Y = Pos.Bottom (_foregroundColorPicker) + 1
         };
         app.Add (_foregroundColorLabel);
 
         // Background ColorPicker.
-        backgroundColorPicker = new ColorPicker
+        _backgroundColorPicker = new ()
         {
             Title = "_Background Color",
             X = Pos.AnchorEnd (),
@@ -68,49 +65,47 @@ public class ColorPickers : Scenario
             BorderStyle = LineStyle.Single
         };
 
-        backgroundColorPicker.ColorChanged += BackgroundColor_ColorChanged;
-        app.Add (backgroundColorPicker);
-        _backgroundColorLabel = new Label ()
+        _backgroundColorPicker.ColorChanged += BackgroundColor_ColorChanged;
+        app.Add (_backgroundColorPicker);
+
+        _backgroundColorLabel = new ()
         {
             X = Pos.AnchorEnd (),
-            Y = Pos.Bottom (backgroundColorPicker) + 1
+            Y = Pos.Bottom (_backgroundColorPicker) + 1
         };
 
         app.Add (_backgroundColorLabel);
 
-
         ///////////////////////////////////////
         // 16 Color Pickers
         ///////////////////////////////////////
 
-
         // Foreground ColorPicker 16.
-        foregroundColorPicker16 = new ColorPicker16
+        _foregroundColorPicker16 = new ()
         {
             Title = "_Foreground Color",
             BorderStyle = LineStyle.Single,
             Width = Dim.Percent (50),
-            Visible = false  // We default to HSV so hide old one
+            Visible = false // We default to HSV so hide old one
         };
-        foregroundColorPicker16.ColorChanged += ForegroundColor_ColorChanged;
-        app.Add (foregroundColorPicker16);
+        _foregroundColorPicker16.ColorChanged += ForegroundColor_ColorChanged;
+        app.Add (_foregroundColorPicker16);
 
         // Background ColorPicker 16.
-        backgroundColorPicker16 = new ColorPicker16
+        _backgroundColorPicker16 = new ()
         {
             Title = "_Background Color",
             X = Pos.AnchorEnd (),
             Width = Dim.Percent (50),
             BorderStyle = LineStyle.Single,
-            Visible = false  // We default to HSV so hide old one
+            Visible = false // We default to HSV so hide old one
         };
 
-        backgroundColorPicker16.ColorChanged += BackgroundColor_ColorChanged;
-        app.Add (backgroundColorPicker16);
-
+        _backgroundColorPicker16.ColorChanged += BackgroundColor_ColorChanged;
+        app.Add (_backgroundColorPicker16);
 
         // Demo Label.
-        _demoView = new View
+        _demoView = new ()
         {
             Title = "Color Sample",
             Text = "Lorem Ipsum",
@@ -124,8 +119,7 @@ public class ColorPickers : Scenario
         };
         app.Add (_demoView);
 
-
-        var osColorModel = new OptionSelector ()
+        var osColorModel = new OptionSelector
         {
             Y = Pos.Bottom (_demoView),
             Width = Dim.Auto (),
@@ -137,87 +131,38 @@ public class ColorPickers : Scenario
                 "H_SL",
                 "_16 Colors"
             ],
-            Value = (int)foregroundColorPicker.Style.ColorModel,
+            Value = (int)_foregroundColorPicker.Style.ColorModel
         };
 
-        osColorModel.ValueChanged += (_, e) =>
-                                            {
-                                                // 16 colors
-                                                if (e.Value == 3)
-                                                {
-
-                                                    foregroundColorPicker16.Visible = true;
-                                                    foregroundColorPicker.Visible = false;
-
-                                                    backgroundColorPicker16.Visible = true;
-                                                    backgroundColorPicker.Visible = false;
-
-                                                    // Switching to 16 colors
-                                                    ForegroundColor_ColorChanged (null, null);
-                                                    BackgroundColor_ColorChanged (null, null);
-                                                }
-                                                else
-                                                {
-                                                    foregroundColorPicker16.Visible = false;
-                                                    foregroundColorPicker.Visible = true;
-
-                                                    if (e.Value is { })
-                                                    {
-                                                        foregroundColorPicker.Style.ColorModel = (ColorModel)e.Value;
-                                                        foregroundColorPicker.ApplyStyleChanges ();
-
-                                                        backgroundColorPicker16.Visible = false;
-                                                        backgroundColorPicker.Visible = true;
-                                                        backgroundColorPicker.Style.ColorModel = (ColorModel)e.Value;
-                                                    }
-
-                                                    backgroundColorPicker.ApplyStyleChanges ();
-
-
-                                                    // Switching to true colors
-                                                    foregroundColorPicker.SelectedColor = foregroundColorPicker16.SelectedColor;
-                                                    backgroundColorPicker.SelectedColor = backgroundColorPicker16.SelectedColor;
-                                                }
-                                            };
+        osColorModel.ValueChanged += OnOsColorModelOnValueChanged;
 
         app.Add (osColorModel);
 
         // Checkbox for switching show text fields on and off
-        var cbShowTextFields = new CheckBox ()
+        var cbShowTextFields = new CheckBox
         {
             Text = "Show _Text Fields",
             Y = Pos.Bottom (osColorModel) + 1,
             Width = Dim.Auto (),
             Height = Dim.Auto (),
-            CheckedState = foregroundColorPicker.Style.ShowTextFields ? CheckState.Checked : CheckState.UnChecked,
+            CheckedState = _foregroundColorPicker.Style.ShowTextFields ? CheckState.Checked : CheckState.UnChecked
         };
 
-        cbShowTextFields.CheckedStateChanging += (_, e) =>
-                                                {
-                                                    foregroundColorPicker.Style.ShowTextFields = e.Result == CheckState.Checked;
-                                                    foregroundColorPicker.ApplyStyleChanges ();
-                                                    backgroundColorPicker.Style.ShowTextFields = e.Result == CheckState.Checked;
-                                                    backgroundColorPicker.ApplyStyleChanges ();
-                                                };
+        cbShowTextFields.CheckedStateChanging += OnCbShowTextFieldsOnCheckedStateChanging;
         app.Add (cbShowTextFields);
 
         // Checkbox for switching show text fields on and off
-        var cbShowName = new CheckBox ()
+        var cbShowName = new CheckBox
         {
             Text = "Show Color _Name",
             Y = Pos.Bottom (cbShowTextFields) + 1,
             Width = Dim.Auto (),
             Height = Dim.Auto (),
-            CheckedState = foregroundColorPicker.Style.ShowColorName ? CheckState.Checked : CheckState.UnChecked,
+            CheckedState = _foregroundColorPicker.Style.ShowColorName ? CheckState.Checked : CheckState.UnChecked
         };
 
-        cbShowName.CheckedStateChanging += (_, e) =>
-                                           {
-                                               foregroundColorPicker.Style.ShowColorName = e.Result == CheckState.Checked;
-                                               foregroundColorPicker.ApplyStyleChanges ();
-                                               backgroundColorPicker.Style.ShowColorName = e.Result == CheckState.Checked;
-                                               backgroundColorPicker.ApplyStyleChanges ();
-                                           };
+        cbShowName.CheckedStateChanging += OnCbShowTextFieldsOnCheckedStateChanging;
+
         app.Add (cbShowName);
 
         var lblDriverName = new Label
@@ -247,41 +192,88 @@ public class ColorPickers : Scenario
         };
         cbUseTrueColor.CheckedStateChanging += (_, evt) => { Application.Force16Colors = evt.Result == CheckState.Checked; };
         app.Add (lblDriverName, cbSupportsTrueColor, cbUseTrueColor);
+
         // Set default colors.
-        foregroundColorPicker.SelectedColor = _demoView.SuperView!.GetAttributeForRole (VisualRole.Normal).Foreground.GetClosestNamedColor16 ();
-        backgroundColorPicker.SelectedColor = _demoView.SuperView.GetAttributeForRole (VisualRole.Normal).Background.GetClosestNamedColor16 ();
+        _foregroundColorPicker.SelectedColor = _demoView.SuperView!.GetAttributeForRole (VisualRole.Normal).Foreground.GetClosestNamedColor16 ();
+        _backgroundColorPicker.SelectedColor = _demoView.SuperView.GetAttributeForRole (VisualRole.Normal).Background.GetClosestNamedColor16 ();
 
         Application.Run (app);
         app.Dispose ();
         Application.Shutdown ();
+
+        return;
+
+        void OnCbShowTextFieldsOnCheckedStateChanging (object _, ResultEventArgs<CheckState> e)
+        {
+            _foregroundColorPicker.Style.ShowTextFields = e.Result == CheckState.Checked;
+            _foregroundColorPicker.ApplyStyleChanges ();
+            _backgroundColorPicker.Style.ShowTextFields = e.Result == CheckState.Checked;
+            _backgroundColorPicker.ApplyStyleChanges ();
+        }
+
+        void OnOsColorModelOnValueChanged (object _, EventArgs<int?> e)
+        {
+            // 16 colors
+            if (e.Value == 3)
+            {
+                _foregroundColorPicker16.Visible = true;
+                _foregroundColorPicker.Visible = false;
+
+                _backgroundColorPicker16.Visible = true;
+                _backgroundColorPicker.Visible = false;
+
+                // Switching to 16 colors
+                ForegroundColor_ColorChanged (null, null);
+                BackgroundColor_ColorChanged (null, null);
+            }
+            else
+            {
+                _foregroundColorPicker16.Visible = false;
+                _foregroundColorPicker.Visible = true;
+
+                if (e.Value is { })
+                {
+                    _foregroundColorPicker.Style.ColorModel = (ColorModel)e.Value;
+                    _foregroundColorPicker.ApplyStyleChanges ();
+
+                    _backgroundColorPicker16.Visible = false;
+                    _backgroundColorPicker.Visible = true;
+                    _backgroundColorPicker.Style.ColorModel = (ColorModel)e.Value;
+                }
+
+                _backgroundColorPicker.ApplyStyleChanges ();
+
+                // Switching to true colors
+                _foregroundColorPicker.SelectedColor = _foregroundColorPicker16.SelectedColor;
+                _backgroundColorPicker.SelectedColor = _backgroundColorPicker16.SelectedColor;
+            }
+        }
     }
 
     /// <summary>Fired when background color is changed.</summary>
     private void BackgroundColor_ColorChanged (object sender, ResultEventArgs<Color> e)
     {
-        UpdateColorLabel (_backgroundColorLabel,
-                          backgroundColorPicker.Visible ?
-                              backgroundColorPicker.SelectedColor :
-                              backgroundColorPicker16.SelectedColor
-                          );
+        UpdateColorLabel (
+                          _backgroundColorLabel,
+                          _backgroundColorPicker.Visible ? _backgroundColorPicker.SelectedColor : _backgroundColorPicker16.SelectedColor
+                         );
         UpdateDemoLabel ();
     }
 
     /// <summary>Fired when foreground color is changed.</summary>
     private void ForegroundColor_ColorChanged (object sender, ResultEventArgs<Color> e)
     {
-        UpdateColorLabel (_foregroundColorLabel,
-                          foregroundColorPicker.Visible ?
-                                 foregroundColorPicker.SelectedColor :
-                                 foregroundColorPicker16.SelectedColor
-                          );
+        UpdateColorLabel (
+                          _foregroundColorLabel,
+                          _foregroundColorPicker.Visible ? _foregroundColorPicker.SelectedColor : _foregroundColorPicker16.SelectedColor
+                         );
         UpdateDemoLabel ();
     }
 
     /// <summary>Update a color label from his ColorPicker.</summary>
     private void UpdateColorLabel (Label label, Color color)
     {
-        label.ClearViewport (null);
+        label.ClearViewport ();
 
         label.Text =
             $"{color} ({(int)color}) #{color.R:X2}{color.G:X2}{color.B:X2}";
@@ -290,17 +282,14 @@ public class ColorPickers : Scenario
     /// <summary>Update Demo Label.</summary>
     private void UpdateDemoLabel ()
     {
-        _demoView.SetScheme (new Scheme
-        {
-            Normal = new Attribute (
-                                    foregroundColorPicker.Visible ?
-                                        foregroundColorPicker.SelectedColor :
-                                        foregroundColorPicker16.SelectedColor,
-                                    backgroundColorPicker.Visible ?
-                                        backgroundColorPicker.SelectedColor :
-                                        backgroundColorPicker16.SelectedColor
-                                   )
-        });
+        _demoView.SetScheme (
+                             new ()
+                             {
+                                 Normal = new (
+                                               _foregroundColorPicker.Visible ? _foregroundColorPicker.SelectedColor : _foregroundColorPicker16.SelectedColor,
+                                               _backgroundColorPicker.Visible ? _backgroundColorPicker.SelectedColor : _backgroundColorPicker16.SelectedColor
+                                              )
+                             });
     }
 
     public override List<Key> GetDemoKeyStrokes ()
@@ -310,7 +299,7 @@ public class ColorPickers : Scenario
             Key.B.WithAlt
         ];
 
-        for (int i = 0; i < 200; i++)
+        for (var i = 0; i < 200; i++)
         {
             keys.Add (Key.CursorRight);
         }
@@ -318,7 +307,7 @@ public class ColorPickers : Scenario
         keys.Add (Key.Tab);
         keys.Add (Key.Tab);
 
-        for (int i = 0; i < 200; i++)
+        for (var i = 0; i < 200; i++)
         {
             keys.Add (Key.CursorLeft);
         }
@@ -326,7 +315,7 @@ public class ColorPickers : Scenario
         keys.Add (Key.Tab);
         keys.Add (Key.Tab);
 
-        for (int i = 0; i < 200; i++)
+        for (var i = 0; i < 200; i++)
         {
             keys.Add (Key.CursorLeft);
         }

+ 0 - 68
Terminal.Gui/Drawing/Color/AnsiColorNameResolver.cs

@@ -1,68 +0,0 @@
-using System.Collections.Immutable;
-using System.Diagnostics.CodeAnalysis;
-
-namespace Terminal.Gui.Drawing;
-
-/// <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.")
-        };
-    }
-}

+ 34 - 50
Terminal.Gui/Drawing/Color/Color.cs

@@ -11,8 +11,28 @@ namespace Terminal.Gui.Drawing;
 
 /// <summary>
 ///     Represents a 24-bit color encoded in ARGB32 format.
-///     <para/>
+///     <para>
+///         The RGB components define the color identity (what color it is), while the alpha channel defines
+///         rendering intent (how transparent it should be when drawn).
+///     </para>
 /// </summary>
+/// <remarks>
+///     <para>
+///         When matching colors to standard color names (e.g., via <see cref="ColorStrings.GetColorName"/>),
+///         the alpha channel is ignored. This means colors with the same RGB values but different alpha values
+///         will resolve to the same color name. This design supports transparency features while maintaining
+///         semantic color identity.
+///     </para>
+///     <para>
+///         While Terminal.Gui does not currently support alpha blending during rendering, the alpha channel
+///         is used to indicate rendering intent:
+///         <list type="bullet">
+///             <item><description>Alpha = 0: Fully transparent (don't render)</description></item>
+///             <item><description>Alpha = 255: Fully opaque (normal rendering)</description></item>
+///             <item><description>Other values: Reserved for future alpha blending support</description></item>
+///         </list>
+///     </para>
+/// </remarks>
 /// <seealso cref="Attribute"/>
 /// <seealso cref="ColorExtensions"/>
 /// <seealso cref="ColorName16"/>
@@ -23,8 +43,16 @@ public readonly partial record struct Color : ISpanParsable<Color>, IUtf8SpanPar
 {
     /// <summary>The value of the alpha channel component</summary>
     /// <remarks>
-    ///     The alpha channel is not currently supported, so the value of the alpha channel bits will not affect
-    ///     rendering.
+    ///     <para>
+    ///         The alpha channel represents rendering intent (transparency) rather than color identity.
+    ///         Terminal.Gui does not currently perform alpha blending, but uses this value to determine
+    ///         whether to render the color at all (alpha = 0 means don't render).
+    ///     </para>
+    ///     <para>
+    ///         When matching colors to standard color names, the alpha channel is ignored. For example,
+    ///         <c>new Color(255, 0, 0, 255)</c> and <c>new Color(255, 0, 0, 128)</c> will both be
+    ///         identified as "Red".
+    ///     </para>
     /// </remarks>
     [JsonIgnore]
     [field: FieldOffset (3)]
@@ -32,8 +60,8 @@ public readonly partial record struct Color : ISpanParsable<Color>, IUtf8SpanPar
 
     /// <summary>The value of this <see cref="Color"/> as a <see langword="uint"/> in ARGB32 format.</summary>
     /// <remarks>
-    ///     The alpha channel is not currently supported, so the value of the alpha channel bits will not affect
-    ///     rendering.
+    ///     The alpha channel in the ARGB value represents rendering intent (transparency), not color identity.
+    ///     When matching to standard color names, only the RGB components are considered.
     /// </remarks>
     [JsonIgnore]
     [field: FieldOffset (0)]
@@ -134,8 +162,6 @@ public readonly partial record struct Color : ISpanParsable<Color>, IUtf8SpanPar
     /// <summary>Initializes a new instance of the <see cref="Color"/> with all channels set to 0.</summary>
     public Color () { Argb = 0u; }
 
-    // TODO: ColorName and AnsiColorCode are only needed when a driver is in Force16Color mode and we
-    // TODO: should be able to remove these from any non-Driver-specific usages.
     /// <summary>Gets or sets the 3-byte/6-character hexadecimal value for each of the legacy 16-color values.</summary>
     [ConfigurationProperty (Scope = typeof (SettingsScope), OmitClassName = true)]
     public static Dictionary<ColorName16, string> Colors16
@@ -203,31 +229,6 @@ public readonly partial record struct Color : ISpanParsable<Color>, IUtf8SpanPar
     [MethodImpl (MethodImplOptions.AggressiveInlining)]
     public bool IsClosestToNamedColor16 (in ColorName16 namedColor) { return GetClosestNamedColor16 () == namedColor; }
 
-    /// <summary>
-    ///     Determines if the closest named <see cref="Color"/> to <paramref name="color"/>/> is the provided
-    ///     <paramref name="namedColor"/>.
-    /// </summary>
-    /// <param name="color">
-    ///     The color to test against the <see cref="GetClosestNamedColor16(Color)"/> value in
-    ///     <paramref name="namedColor"/>.
-    /// </param>
-    /// <param name="namedColor">
-    ///     The <see cref="GetClosestNamedColor16(Color)"/> to check if this <see cref="Color"/> is closer
-    ///     to than any other configured named color.
-    /// </param>
-    /// <returns>
-    ///     <see langword="true"/> if the closest named color to <paramref name="color"/> is the provided value. <br/>
-    ///     <see langword="false"/> if any other named color is closer to <paramref name="color"/> than
-    ///     <paramref name="namedColor"/>.
-    /// </returns>
-    /// <remarks>
-    ///     If <paramref name="color"/> is equidistant from two named colors, the result of this method is not guaranteed
-    ///     to be determinate.
-    /// </remarks>
-    [Pure]
-    [MethodImpl (MethodImplOptions.AggressiveInlining)]
-    public static bool IsColorClosestToNamedColor16 (in Color color, in ColorName16 namedColor) { return color.IsClosestToNamedColor16 (in namedColor); }
-
     /// <summary>Gets the "closest" named color to this <see cref="Color"/> value.</summary>
     /// <param name="inputColor"></param>
     /// <remarks>
@@ -240,15 +241,6 @@ 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); }
 
@@ -297,16 +289,8 @@ public readonly partial record struct Color : ISpanParsable<Color>, IUtf8SpanPar
         HSL? hsl = ColorConverter.RgbToHsl (new (R, G, B));
 
         double lNorm = hsl.L / 255.0;
-        double newL;
 
-        if (lNorm < 0.5)
-        {
-            newL = Math.Min (1.0, lNorm + brightenAmount);
-        }
-        else
-        {
-            newL = Math.Max (0.0, lNorm - brightenAmount);
-        }
+        double newL = lNorm < 0.5 ? Math.Min (1.0, lNorm + brightenAmount) : Math.Max (0.0, lNorm - brightenAmount);
 
         if (Math.Abs (newL - lNorm) < 0.1)
         {

+ 6 - 5
Terminal.Gui/Drawing/Color/ColorModel.cs

@@ -1,23 +1,24 @@
+// ReSharper disable InconsistentNaming
+
 namespace Terminal.Gui.Drawing;
 
 /// <summary>
-/// Describes away of modelling color e.g. Hue
-/// Saturation Lightness.
+///     Describes a way of modelling color e.g. Hue, Saturation, and Lightness.
 /// </summary>
 public enum ColorModel
 {
     /// <summary>
-    /// Color modelled by storing Red, Green and Blue as (0-255) ints
+    ///     Color modelled by storing Red, Green and Blue as (0-255) ints
     /// </summary>
     RGB,
 
     /// <summary>
-    /// Color modelled by storing Hue (360 degrees), Saturation (100%) and Value (100%)
+    ///     Color modelled by storing Hue (360 degrees), Saturation (100%) and Value (100%)
     /// </summary>
     HSV,
 
     /// <summary>
-    /// Color modelled by storing Hue (360 degrees), Saturation (100%) and Lightness (100%)
+    ///     Color modelled by storing Hue (360 degrees), Saturation (100%) and Lightness (100%)
     /// </summary>
     HSL
 }

+ 3 - 3
Terminal.Gui/Drawing/Color/ColorQuantizer.cs

@@ -39,7 +39,7 @@ public class ColorQuantizer
     /// <param name="pixels"></param>
     public void BuildPalette (Color [,] pixels)
     {
-        List<Color> allColors = new ();
+        List<Color> allColors = [];
         int width = pixels.GetLength (0);
         int height = pixels.GetLength (1);
 
@@ -56,8 +56,8 @@ public class ColorQuantizer
     }
 
     /// <summary>
-    /// Returns the closest color in <see cref="Palette"/> that matches <paramref name="toTranslate"/>
-    /// based on the color comparison algorithm defined by <see cref="DistanceAlgorithm"/>
+    ///     Returns the closest color in <see cref="Palette"/> that matches <paramref name="toTranslate"/>
+    ///     based on the color comparison algorithm defined by <see cref="DistanceAlgorithm"/>
     /// </summary>
     /// <param name="toTranslate"></param>
     /// <returns></returns>

+ 6 - 53
Terminal.Gui/Drawing/Color/ColorStrings.cs

@@ -7,47 +7,16 @@ namespace Terminal.Gui.Drawing;
 /// </summary>
 public static class ColorStrings
 {
-    private static readonly AnsiColorNameResolver _ansi = new();
     private static readonly StandardColorsNameResolver _standard = new();
-    private static readonly MultiStandardColorNameResolver _multi = new();
 
     /// <summary>
-    ///     Gets the W3C+  standard string 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? GetStandardColorName (Color color)
-    {
-        if (_standard.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>
-    // ReSharper disable once InconsistentNaming
-    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"/>.
+    ///     Gets the 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))
+        if (_standard.TryNameColor (color, out string? name))
         {
             return name;
         }
@@ -80,30 +49,14 @@ public static class ColorStrings
     }
 
     /// <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.
+    ///     Parses <paramref name="name"/> and returns <paramref name="color"/> if name is a 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))
+        if (_standard.TryParseColor (name, out color))
         {
             return true;
         }
@@ -113,7 +66,7 @@ public static class ColorStrings
             return true;
         }
 
-        color = default;
+        color = default (Color);
         return false;
     }
 
@@ -130,7 +83,7 @@ public static class ColorStrings
             }
         }
 
-        color = default;
+        color = default (Color);
         return false;
     }
 }

+ 0 - 83
Terminal.Gui/Drawing/Color/MultiStandardColorNameResolver.cs

@@ -1,83 +0,0 @@
-using System.Collections.Frozen;
-using System.Collections.Immutable;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-
-namespace Terminal.Gui.Drawing;
-
-/// <summary>
-/// Color name resolver prioritizing Standard (W3C+) colors with fallback to ANSI 4-bit (16) colors.
-/// </summary>
-public class MultiStandardColorNameResolver : IColorNameResolver
-{
-    private static readonly AnsiColorNameResolver _ansi = new ();
-    private static readonly StandardColorsNameResolver _standard = new ();
-
-    private static readonly ImmutableArray<string> _combinedColorNames;
-    private static readonly FrozenDictionary<string, Color> _nameToColorMap;
-    private static readonly FrozenDictionary<uint, string> _colorToNameMap;
-
-    static MultiStandardColorNameResolver ()
-    {
-        Dictionary<string, Color> nameToColor = new (StringComparer.OrdinalIgnoreCase);
-        Dictionary<uint, string> colorToName = new ();
-
-        foreach (string name in _standard.GetColorNames ())
-        {
-            if (_standard.TryParseColor (name, out Color color))
-            {
-                if (nameToColor.TryAdd (name, color))
-                {
-                    _ = colorToName.TryAdd (color.Argb, name);
-                }
-            }
-        }
-
-        foreach (string name in _ansi.GetColorNames ())
-        {
-            if (_ansi.TryParseColor (name, out Color color))
-            {
-                nameToColor.TryAdd (name, color);
-                colorToName.TryAdd (color.Argb, name);
-            }
-        }
-
-        _nameToColorMap = nameToColor.ToFrozenDictionary ();
-        _colorToNameMap = colorToName.ToFrozenDictionary ();
-        _combinedColorNames = nameToColor.Keys.Order ().ToImmutableArray ();
-    }
-
-    /// <inheritdoc/>
-    public IEnumerable<string> GetColorNames () => _combinedColorNames;
-
-    /// <inheritdoc/>
-    public bool TryParseColor (ReadOnlySpan<char> name, out Color color)
-    {
-        if (name.StartsWith ("#") || name.StartsWith ("0x", StringComparison.OrdinalIgnoreCase))
-        {
-            try
-            {
-                color = Color.Parse (name.ToString (), CultureInfo.InvariantCulture);
-                return true;
-            }
-            catch
-            {
-                color = default;
-                return false;
-            }
-        }
-
-        if (_ansi.TryParseColor (name, out color)) return true;
-        if (_standard.TryParseColor (name, out color)) return true;
-
-        color = default;
-        return false;
-    }
-
-
-    /// <inheritdoc/>
-    public bool TryNameColor (Color color, [NotNullWhen (true)] out string? name)
-    {
-        return _colorToNameMap.TryGetValue (color.Argb, out name);
-    }
-}

+ 60 - 1
Terminal.Gui/Drawing/Color/StandardColor.cs

@@ -1248,5 +1248,64 @@ public enum StandardColor
     ///         A bright yellowish-green color.
     ///     </para>
     /// </summary>
-    YellowGreen = 0x9ACD32
+    YellowGreen = 0x9ACD32,
+
+    // Legacy 16-color names for backwards compatibility
+    // These match the RGB values used in ColorName16 mapping
+
+    /// <summary>
+    ///     Bright Black RGB(118, 118, 118).
+    ///     <para>
+    ///         A bright black (dark gray) color from the legacy 16-color palette. This is the ColorName16.DarkGray color.
+    ///     </para>
+    /// </summary>
+    BrightBlack = 0x767676,
+
+    /// <summary>
+    ///     Bright Blue RGB(59, 120, 255).
+    ///     <para>
+    ///         A bright blue color from the legacy 16-color palette.
+    ///     </para>
+    /// </summary>
+    BrightBlue = 0x3B78FF,
+
+    /// <summary>
+    ///     Bright Cyan RGB(97, 214, 214).
+    ///     <para>
+    ///         A bright cyan color from the legacy 16-color palette.
+    ///     </para>
+    /// </summary>
+    BrightCyan = 0x61D6D6,
+
+    /// <summary>
+    ///     Bright Green RGB(22, 198, 12).
+    ///     <para>
+    ///         A bright green color from the legacy 16-color palette.
+    ///     </para>
+    /// </summary>
+    BrightGreen = 0x16C60C,
+
+    /// <summary>
+    ///     Bright Magenta RGB(180, 0, 158).
+    ///     <para>
+    ///         A bright magenta color from the legacy 16-color palette.
+    ///     </para>
+    /// </summary>
+    BrightMagenta = 0xB4009E,
+
+    /// <summary>
+    ///     Bright Red RGB(231, 72, 86).
+    ///     <para>
+    ///         A bright red color from the legacy 16-color palette.
+    ///     </para>
+    /// </summary>
+    BrightRed = 0xE74856,
+
+    /// <summary>
+    ///     Bright Yellow RGB(249, 241, 165).
+    ///     <para>
+    ///         A bright yellow color from the legacy 16-color palette.
+    ///     </para>
+    /// </summary>
+    BrightYellow = 0xF9F1A5
 }

+ 5 - 2
Terminal.Gui/Drawing/Color/StandardColors.cs

@@ -18,7 +18,7 @@ internal static class StandardColors
     {
         string [] standardNames = Enum.GetNames<StandardColor> ().Order ().ToArray ();
 
-        return ImmutableArray.Create (standardNames);
+        return [.. standardNames];
     }
 
     private static readonly Lazy<FrozenDictionary<uint, string>> _argbNameMap = new (
@@ -82,7 +82,10 @@ internal static class StandardColors
     /// <returns>True if conversion succeeded; otherwise false.</returns>
     public static bool TryNameColor (Color color, [NotNullWhen (true)] out string? name)
     {
-        if (_argbNameMap.Value.TryGetValue (color.Argb, out name))
+        // Ignore alpha channel when matching - alpha represents transparency, not color identity
+        uint opaqueArgb = color.Argb | 0xFF000000;
+
+        if (_argbNameMap.Value.TryGetValue (opaqueArgb, out name))
         {
             return true;
         }

+ 0 - 2
Terminal.Gui/Views/Color/BBar.cs

@@ -1,5 +1,3 @@
-
-
 using ColorHelper;
 
 namespace Terminal.Gui.Views;

+ 1 - 4
Terminal.Gui/Views/Color/ColorBar.cs

@@ -1,5 +1,3 @@
-
-
 using ColorHelper;
 
 namespace Terminal.Gui.Views;
@@ -15,7 +13,7 @@ internal abstract class ColorBar : View, IColorBar
     /// </summary>
     protected ColorBar ()
     {
-        Height = Dim.Auto(minimumContentDim: 1);
+        Height = Dim.Auto (minimumContentDim: 1);
         Width = Dim.Fill ();
         CanFocus = true;
 
@@ -135,7 +133,6 @@ internal abstract class ColorBar : View, IColorBar
 
             mouseEvent.Handled = true;
             SetFocus ();
-
         }
 
         return mouseEvent.Handled;

+ 28 - 45
Terminal.Gui/Views/Color/ColorModelStrategy.cs

@@ -1,5 +1,3 @@
-
-
 using ColorHelper;
 using ColorConverter = ColorHelper.ColorConverter;
 
@@ -7,39 +5,23 @@ namespace Terminal.Gui.Views;
 
 internal class ColorModelStrategy
 {
-    public IEnumerable<ColorBar> CreateBars (ColorModel model)
-    {
-        switch (model)
+    public IEnumerable<ColorBar> CreateBars (ColorModel model) =>
+        model switch
         {
-            case ColorModel.RGB:
-                return CreateRgbBars ();
-            case ColorModel.HSV:
-                return CreateHsvBars ();
-            case ColorModel.HSL:
-                return CreateHslBars ();
-            default:
-                throw new ArgumentOutOfRangeException (nameof (model), model, null);
-        }
-    }
+            ColorModel.RGB => CreateRgbBars (),
+            ColorModel.HSV => CreateHsvBars (),
+            ColorModel.HSL => CreateHslBars (),
+            _ => throw new ArgumentOutOfRangeException (nameof (model), model, null)
+        };
 
-    public Color GetColorFromBars (IList<IColorBar> bars, ColorModel model)
-    {
-        switch (model)
+    public Color GetColorFromBars (IList<IColorBar> bars, ColorModel model) =>
+        model switch
         {
-            case ColorModel.RGB:
-                return ToColor (new ((byte)bars [0].Value, (byte)bars [1].Value, (byte)bars [2].Value));
-            case ColorModel.HSV:
-                return ToColor (
-                                ColorConverter.HsvToRgb (new (bars [0].Value, (byte)bars [1].Value, (byte)bars [2].Value))
-                               );
-            case ColorModel.HSL:
-                return ToColor (
-                                ColorConverter.HslToRgb (new (bars [0].Value, (byte)bars [1].Value, (byte)bars [2].Value))
-                               );
-            default:
-                throw new ArgumentOutOfRangeException (nameof (model), model, null);
-        }
-    }
+            ColorModel.RGB => ToColor (new ((byte)bars [0].Value, (byte)bars [1].Value, (byte)bars [2].Value)),
+            ColorModel.HSV => ToColor (ColorConverter.HsvToRgb (new (bars [0].Value, (byte)bars [1].Value, (byte)bars [2].Value))),
+            ColorModel.HSL => ToColor (ColorConverter.HslToRgb (new (bars [0].Value, (byte)bars [1].Value, (byte)bars [2].Value))),
+            _ => throw new ArgumentOutOfRangeException (nameof (model), model, null)
+        };
 
     public void SetBarsToColor (IList<IColorBar> bars, Color newValue, ColorModel model)
     {
@@ -47,6 +29,7 @@ internal class ColorModelStrategy
         {
             return;
         }
+
         switch (model)
         {
             case ColorModel.RGB:
@@ -75,21 +58,21 @@ internal class ColorModelStrategy
         }
     }
 
-    private IEnumerable<ColorBar> CreateHslBars ()
+    private static IEnumerable<ColorBar> CreateHslBars ()
     {
-        var h = new HueBar
+        HueBar h = new ()
         {
             Text = "H:"
         };
 
         yield return h;
 
-        var s = new SaturationBar
+        SaturationBar s = new ()
         {
             Text = "S:"
         };
 
-        var l = new LightnessBar
+        LightnessBar l = new ()
         {
             Text = "L:"
         };
@@ -104,21 +87,21 @@ internal class ColorModelStrategy
         yield return l;
     }
 
-    private IEnumerable<ColorBar> CreateHsvBars ()
+    private static IEnumerable<ColorBar> CreateHsvBars ()
     {
-        var h = new HueBar
+        HueBar h = new ()
         {
             Text = "H:"
         };
 
         yield return h;
 
-        var s = new SaturationBar
+        SaturationBar s = new ()
         {
             Text = "S:"
         };
 
-        var v = new ValueBar
+        ValueBar v = new ()
         {
             Text = "V:"
         };
@@ -133,19 +116,19 @@ internal class ColorModelStrategy
         yield return v;
     }
 
-    private IEnumerable<ColorBar> CreateRgbBars ()
+    private static IEnumerable<ColorBar> CreateRgbBars ()
     {
-        var r = new RBar
+        RBar r = new ()
         {
             Text = "R:"
         };
 
-        var g = new GBar
+        GBar g = new ()
         {
             Text = "G:"
         };
 
-        var b = new BBar
+        BBar b = new ()
         {
             Text = "B:"
         };
@@ -163,5 +146,5 @@ internal class ColorModelStrategy
         yield return b;
     }
 
-    private Color ToColor (RGB rgb) { return new (rgb.R, rgb.G, rgb.B); }
+    private static Color ToColor (RGB rgb) { return new (rgb.R, rgb.G, rgb.B); }
 }

+ 0 - 3
Terminal.Gui/Views/Color/ColorPicker.Style.cs

@@ -1,6 +1,3 @@
-
-
-
 namespace Terminal.Gui.Views;
 
 /// <summary>

+ 0 - 2
Terminal.Gui/Views/Color/GBar.cs

@@ -1,5 +1,3 @@
-
-
 using ColorHelper;
 
 namespace Terminal.Gui.Views;

+ 1 - 2
Terminal.Gui/Views/Color/IColorBar.cs

@@ -1,5 +1,4 @@
-#nullable disable
-namespace Terminal.Gui.Views;
+namespace Terminal.Gui.Views;
 
 internal interface IColorBar
 {

+ 0 - 2
Terminal.Gui/Views/Color/LightnessBar.cs

@@ -1,5 +1,3 @@
-
-
 using ColorHelper;
 using ColorConverter = ColorHelper.ColorConverter;
 

+ 0 - 2
Terminal.Gui/Views/Color/RBar.cs

@@ -1,5 +1,3 @@
-
-
 using ColorHelper;
 
 namespace Terminal.Gui.Views;

+ 0 - 2
Terminal.Gui/Views/Color/SaturationBar.cs

@@ -1,5 +1,3 @@
-
-
 using ColorHelper;
 using ColorConverter = ColorHelper.ColorConverter;
 

+ 1 - 0
Terminal.sln.DotSettings

@@ -424,6 +424,7 @@
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=ogonek/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Quattro/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Roslynator/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/UserDictionary/Words/=RRGGBB/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=runnables/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Toplevel/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Runnables/@EntryIndexedValue">True</s:Boolean>

+ 1 - 1
Tests/StressTests/ApplicationStressTests.cs

@@ -5,7 +5,7 @@ using Xunit.Abstractions;
 
 namespace StressTests;
 
-public class ApplicationStressTests (ITestOutputHelper output)
+public class ApplicationStressTests
 {
     private const int NUM_INCREMENTS = 500;
 

+ 1 - 1
Tests/UnitTestsParallelizable/Application/TimeoutTests.cs

@@ -9,7 +9,7 @@ namespace ApplicationTests.Timeout;
 ///     These tests verify that timeouts fire correctly, can be added/removed,
 ///     handle exceptions properly, and work with Application.Run() calls.
 /// </summary>
-public class TimeoutTests (ITestOutputHelper output)
+public class TimeoutTests
 {
     [Fact]
     public void AddTimeout_Callback_Can_Add_New_Timeout ()

+ 3 - 3
Tests/UnitTestsParallelizable/Configuration/ColorJsonConverterTests.cs

@@ -52,7 +52,7 @@ public class ColorJsonConverterTests
     [InlineData (ColorName16.Red, "Red")]
     [InlineData (ColorName16.Magenta, "Fuchsia")]   // W3C+ Standard overrides
     [InlineData (ColorName16.Yellow, "Yellow")]
-    [InlineData (ColorName16.DarkGray, "DarkGray")]
+    [InlineData (ColorName16.DarkGray, "BrightBlack")] // Legacy ColorName16.DarkGray now serializes as BrightBlack (first alphabetical match)
     [InlineData (ColorName16.BrightBlue, "BrightBlue")]
     [InlineData (ColorName16.BrightGreen, "BrightGreen")]
     [InlineData (ColorName16.BrightCyan, "BrightCyan")]
@@ -98,7 +98,7 @@ public class ColorJsonConverterTests
     [InlineData ("BrightYellow", Color.BrightYellow)]
     [InlineData ("Yellow", Color.Yellow)]
     [InlineData ("Cyan", Color.Cyan)]
-    [InlineData ("DarkGray", Color.DarkGray)]
+    [InlineData ("BrightBlack", Color.DarkGray)] // Legacy ColorName16.DarkGray is now accessible as BrightBlack
     [InlineData ("Gray", Color.Gray)]
     [InlineData ("Green", Color.Green)]
     [InlineData ("Magenta", Color.Magenta)]
@@ -113,7 +113,7 @@ public class ColorJsonConverterTests
         var actualColor = JsonSerializer.Deserialize<Color> (json, JsonOptions);
 
         // Assert
-        Assert.Equal (new Color (expectedColor), actualColor);
+        Assert.Equal (new (expectedColor), actualColor);
     }
 
     [Fact]

+ 6 - 6
Tests/UnitTestsParallelizable/Configuration/SourcesManagerTests.cs

@@ -12,7 +12,7 @@ public class SourcesManagerTests
         // Arrange
         var sourcesManager = new SourcesManager ();
         var stream = new MemoryStream ();
-        var source = "test.json";
+        var source = "Load_WithNullSettingsScope_ReturnsFalse";
         var location = ConfigLocations.AppCurrent;
 
         // Act
@@ -37,7 +37,7 @@ public class SourcesManagerTests
                    }
                    """;
         var location = ConfigLocations.HardCoded;
-        var source = "stream";
+        var source = "Load_WithValidStream_UpdatesSettingsScope";
 
         var stream = new MemoryStream ();
         var writer = new StreamWriter (stream);
@@ -69,7 +69,7 @@ public class SourcesManagerTests
         writer.Flush ();
         stream.Position = 0;
 
-        var source = "test.json";
+        var source = "Load_WithInvalidJson_AddsJsonError";
         var location = ConfigLocations.AppCurrent;
 
         // Act
@@ -180,7 +180,7 @@ public class SourcesManagerTests
         var sourcesManager = new SourcesManager ();
 
         var settingsScope = new SettingsScope ();
-        var source = "test.json";
+        var source = "Load_WithNullOrEmptyJson_ReturnsFalse";
         var location = ConfigLocations.AppCurrent;
 
         // Act
@@ -206,7 +206,7 @@ public class SourcesManagerTests
                         "Application.QuitKey": "Ctrl+Z"
                    }
                    """;
-        var source = "test.json";
+        var source = "Load_WithValidJson_UpdatesSettingsScope";
         var location = ConfigLocations.HardCoded;
 
         // Act
@@ -233,7 +233,7 @@ public class SourcesManagerTests
     //                    "Button.DefaultShadowStyle": "None"
     //               }
     //               """;
-    //    var source = "test.json";
+    //    var source = "Update_WithValidJson_UpdatesThemeScope";
     //    var location = ConfigLocations.HardCoded;
 
     //    // Act

+ 0 - 168
Tests/UnitTestsParallelizable/Drawing/Color/AnsiColorNameResolverTests.cs

@@ -1,168 +0,0 @@
-#nullable enable
-
-namespace DrawingTests;
-
-public class AnsiColorNameResolverTests
-{
-    private readonly AnsiColorNameResolver _candidate = new ();
-    [Fact]
-    public void TryNameColor_Resolves_All_ColorName16 ()
-    {
-        var resolver = new AnsiColorNameResolver ();
-
-        foreach (ColorName16 name in Enum.GetValues<ColorName16> ())
-        {
-            var color = new Color (name);
-            bool success = resolver.TryNameColor (color, out string? resultName);
-
-            Assert.True (success, $"Expected TryNameColor to succeed for {name}");
-            Assert.Equal (name.ToString (), resultName);
-        }
-    }
-
-    [Fact]
-    public void TryParseColor_Resolves_All_ColorName16_Names ()
-    {
-        var resolver = new AnsiColorNameResolver ();
-
-        foreach (ColorName16 name in Enum.GetValues<ColorName16> ())
-        {
-            bool success = resolver.TryParseColor (name.ToString (), out Color parsed);
-
-            Assert.True (success, $"Expected TryParseColor to succeed for {name}");
-            Assert.Equal (new Color (name), parsed);
-        }
-    }
-
-    public static IEnumerable<object []> AnsiColorName16NumericValues =>
-        Enum.GetValues<ColorName16> ()
-            .Select (e => new object [] { ((int)e).ToString () });
-    [Theory]
-    [MemberData (nameof (AnsiColorName16NumericValues))]
-    public void TryParseColor_Accepts_Enum_UnderlyingNumbers (string numeric)
-    {
-        var resolver = new AnsiColorNameResolver ();
-
-        bool success = resolver.TryParseColor (numeric, out _);
-
-        Assert.True (success, $"Expected numeric enum value '{numeric}' to resolve successfully.");
-    }
-
-
-
-    [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);
-    }
-}

+ 2 - 2
Tests/UnitTestsParallelizable/Drawing/ColorTests.Constructors.cs → Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.Constructors.cs

@@ -1,6 +1,6 @@
-namespace DrawingTests;
+namespace DrawingTests.ColorTests;
 
-public partial class ColorTests
+public partial class ColorClassTests
 {
     [Fact]
     public void Constructor_Empty_ReturnsColorWithZeroValue ()

+ 2 - 2
Tests/UnitTestsParallelizable/Drawing/ColorTests.Operators.cs → Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.Operators.cs

@@ -1,9 +1,9 @@
 using System.Numerics;
 using System.Reflection;
 
-namespace DrawingTests;
+namespace DrawingTests.ColorTests;
 
-public partial class ColorTests
+public partial class ColorClassTests
 {
     [Theory]
     [Trait ("Category", "Operators")]

+ 2 - 2
Tests/UnitTestsParallelizable/Drawing/ColorTests.ParsingAndFormatting.cs → Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.ParsingAndFormatting.cs

@@ -2,9 +2,9 @@
 using System.Buffers.Binary;
 using System.Globalization;
 
-namespace DrawingTests;
+namespace DrawingTests.ColorTests;
 
-public partial class ColorTests
+public partial class ColorClassTests
 {
     [Fact]
     public void Color_ToString_WithNamedColor ()

+ 2 - 2
Tests/UnitTestsParallelizable/Drawing/ColorTests.TypeChecks.cs → Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.TypeChecks.cs

@@ -1,9 +1,9 @@
 using System.Numerics;
 using System.Runtime.CompilerServices;
 
-namespace DrawingTests;
+namespace DrawingTests.ColorTests;
 
-public partial class ColorTests
+public partial class ColorClassTests
 {
     [Fact]
     [Trait ("Category", "Type Checks")]

+ 3 - 4
Tests/UnitTestsParallelizable/Drawing/ColorTests.cs → Tests/UnitTestsParallelizable/Drawing/Color/ColorClassTests.cs

@@ -1,8 +1,7 @@
-#nullable enable
+
+namespace DrawingTests.ColorTests;
 
-namespace DrawingTests;
-
-public partial class ColorTests
+public partial class ColorClassTests
 {
     [Theory]
     [CombinatorialData]

+ 0 - 27
Tests/UnitTestsParallelizable/Drawing/Color/ColorStandardColorTests.cs

@@ -1,27 +0,0 @@
-using Xunit;
-
-namespace DrawingTests;
-
-public class ColorStandardColorTests
-{
-    [Fact]
-    public void ToString_Returns_Standard_Name_For_StandardColor_CadetBlue()
-    {
-        // Without the fix, this uses Color(in StandardColor) -> this((int)colorName),
-        // which sets A=0x00 and prevents name resolution (expects A=0xFF).
-        var c = new Terminal.Gui.Drawing.Color(Terminal.Gui.Drawing.StandardColor.CadetBlue);
-
-        // Expected: named color
-        Assert.Equal("CadetBlue", c.ToString());
-    }
-
-    [Fact]
-    public void ToString_G_Prints_Opaque_ARGB_For_StandardColor_CadetBlue()
-    {
-        // Without the fix, A=0x00, so "G" prints "#005F9EA0" instead of "#FF5F9EA0".
-        var c = new Terminal.Gui.Drawing.Color(Terminal.Gui.Drawing.StandardColor.CadetBlue);
-
-        // Expected: #AARRGGBB with A=FF (opaque)
-        Assert.Equal("#FF5F9EA0", c.ToString("G", null));
-    }
-}

+ 326 - 0
Tests/UnitTestsParallelizable/Drawing/Color/ColorStringsTests.cs

@@ -0,0 +1,326 @@
+namespace DrawingTests.ColorTests;
+public class ColorStringsTests
+{
+    [Fact]
+    public void GetColorName_ReturnsNameForStandardColor ()
+    {
+        Color red = new (255, 0);
+        string? name = ColorStrings.GetColorName (red);
+
+        Assert.Equal ("Red", name);
+    }
+
+    [Fact]
+    public void GetColorName_ReturnsNullForNonStandardColor ()
+    {
+        Color custom = new (1, 2, 3);
+        string? name = ColorStrings.GetColorName (custom);
+
+        Assert.Null (name);
+    }
+
+    [Fact]
+    public void GetColorName_IgnoresAlphaChannel ()
+    {
+        Color opaqueRed = new (255, 0, 0, 255);
+        Color transparentRed = new (255, 0, 0, 128);
+        Color fullyTransparentRed = new (255, 0, 0, 0);
+
+        string? name1 = ColorStrings.GetColorName (opaqueRed);
+        string? name2 = ColorStrings.GetColorName (transparentRed);
+        string? name3 = ColorStrings.GetColorName (fullyTransparentRed);
+
+        Assert.Equal ("Red", name1);
+        Assert.Equal ("Red", name2);
+        Assert.Equal ("Red", name3);
+    }
+
+    [Theory]
+    [InlineData (240, 248, 255, "AliceBlue")]
+    [InlineData (0, 255, 255, "Aqua")]
+    [InlineData (0, 0, 0, "Black")]
+    [InlineData (0, 0, 255, "Blue")]
+    [InlineData (0, 128, 0, "Green")]
+    [InlineData (255, 0, 0, "Red")]
+    [InlineData (255, 255, 255, "White")]
+    [InlineData (255, 255, 0, "Yellow")]
+    public void GetColorName_ReturnsCorrectNameForKnownColors (int r, int g, int b, string expectedName)
+    {
+        Color color = new (r, g, b);
+        string? name = ColorStrings.GetColorName (color);
+
+        Assert.Equal (expectedName, name);
+    }
+
+    [Fact]
+    public void GetStandardColorNames_ReturnsNonEmptyCollection ()
+    {
+        IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
+
+        Assert.NotNull (names);
+        Assert.NotEmpty (names);
+    }
+
+    [Fact]
+    public void GetStandardColorNames_ReturnsAlphabeticallySortedNames ()
+    {
+        IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
+        string [] namesArray = names.ToArray ();
+        string [] sortedNames = namesArray.OrderBy (n => n).ToArray ();
+
+        Assert.Equal (sortedNames, namesArray);
+    }
+
+    [Fact]
+    public void GetStandardColorNames_ContainsKnownColors ()
+    {
+        IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
+        string [] namesArray = names.ToArray ();
+
+        Assert.Contains ("Red", namesArray);
+        Assert.Contains ("Green", namesArray);
+        Assert.Contains ("Blue", namesArray);
+        Assert.Contains ("White", namesArray);
+        Assert.Contains ("Black", namesArray);
+        Assert.Contains ("AliceBlue", namesArray);
+        Assert.Contains ("Tomato", namesArray);
+    }
+
+    [Fact]
+    public void GetStandardColorNames_ContainsAllStandardColorEnumValues ()
+    {
+        IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
+        string [] namesArray = names.ToArray ();
+        string [] enumNames = Enum.GetNames<StandardColor> ();
+
+        // All enum names should be in the returned collection
+        foreach (string enumName in enumNames)
+        {
+            Assert.Contains (enumName, namesArray);
+        }
+
+        // The counts should match
+        Assert.Equal (enumNames.Length, namesArray.Length);
+    }
+
+    [Theory]
+    [InlineData ("Red")]
+    [InlineData ("red")]
+    [InlineData ("RED")]
+    [InlineData ("Green")]
+    [InlineData ("green")]
+    [InlineData ("Blue")]
+    [InlineData ("AliceBlue")]
+    [InlineData ("aliceblue")]
+    [InlineData ("ALICEBLUE")]
+    public void TryParseStandardColorName_ParsesValidColorNamesCaseInsensitively (string colorName)
+    {
+        bool result = ColorStrings.TryParseStandardColorName (colorName, out Color color);
+
+        Assert.True (result);
+        Assert.NotEqual (default (Color), color);
+    }
+
+    [Theory]
+    [InlineData ("Red", 255, 0, 0)]
+    [InlineData ("Green", 0, 128, 0)]
+    [InlineData ("Blue", 0, 0, 255)]
+    [InlineData ("White", 255, 255, 255)]
+    [InlineData ("Black", 0, 0, 0)]
+    [InlineData ("AliceBlue", 240, 248, 255)]
+    [InlineData ("Tomato", 255, 99, 71)]
+    public void TryParseStandardColorName_ParsesCorrectRgbValues (string colorName, int expectedR, int expectedG, int expectedB)
+    {
+        bool result = ColorStrings.TryParseStandardColorName (colorName, out Color color);
+
+        Assert.True (result);
+        Assert.Equal (expectedR, color.R);
+        Assert.Equal (expectedG, color.G);
+        Assert.Equal (expectedB, color.B);
+    }
+
+    [Theory]
+    [InlineData ("#FF0000", 255, 0, 0)]
+    [InlineData ("#00FF00", 0, 255, 0)]
+    [InlineData ("#0000FF", 0, 0, 255)]
+    [InlineData ("#FFFFFF", 255, 255, 255)]
+    [InlineData ("#000000", 0, 0, 0)]
+    [InlineData ("#F0F8FF", 240, 248, 255)]
+    public void TryParseStandardColorName_ParsesHexColorFormat (string hexColor, int expectedR, int expectedG, int expectedB)
+    {
+        bool result = ColorStrings.TryParseStandardColorName (hexColor, out Color color);
+
+        Assert.True (result);
+        Assert.Equal (expectedR, color.R);
+        Assert.Equal (expectedG, color.G);
+        Assert.Equal (expectedB, color.B);
+    }
+
+    [Theory]
+    [InlineData ("#ff0000")]
+    [InlineData ("#FF0000")]
+    [InlineData ("#Ff0000")]
+    public void TryParseStandardColorName_ParsesHexColorCaseInsensitively (string hexColor)
+    {
+        bool result = ColorStrings.TryParseStandardColorName (hexColor, out Color color);
+
+        Assert.True (result);
+        Assert.Equal (255, color.R);
+        Assert.Equal (0, color.G);
+        Assert.Equal (0, color.B);
+    }
+
+    [Theory]
+    [InlineData ("")]
+    [InlineData ("NotAColor")]
+    [InlineData ("Invalid")]
+    [InlineData ("123")]
+    [InlineData ("#FF")]
+    [InlineData ("#FFFF")]
+    [InlineData ("#FFFFFFFF")]
+    [InlineData ("FF0000")]
+    public void TryParseStandardColorName_ReturnsFalseForInvalidInput (string invalidInput)
+    {
+        bool result = ColorStrings.TryParseStandardColorName (invalidInput, out Color color);
+
+        Assert.False (result);
+        Assert.Equal (default (Color), color);
+    }
+
+    [Fact]
+    public void TryParseStandardColorName_SetsAlphaToFullyOpaque ()
+    {
+        bool result = ColorStrings.TryParseStandardColorName ("Red", out Color color);
+
+        Assert.True (result);
+        Assert.Equal (255, color.A);
+    }
+
+    [Fact]
+    public void TryParseStandardColorName_WorksWithReadOnlySpan ()
+    {
+        ReadOnlySpan<char> span = "Red".AsSpan ();
+        bool result = ColorStrings.TryParseStandardColorName (span, out Color color);
+
+        Assert.True (result);
+        Assert.Equal (255, color.R);
+        Assert.Equal (0, color.G);
+        Assert.Equal (0, color.B);
+    }
+
+    [Theory]
+    [InlineData ("Red")]
+    [InlineData ("Green")]
+    [InlineData ("Blue")]
+    [InlineData ("AliceBlue")]
+    [InlineData ("#FF0000")]
+    public void TryParseNamedColor_ParsesValidColorNames (string colorName)
+    {
+        bool result = ColorStrings.TryParseNamedColor (colorName, out Color color);
+
+        Assert.True (result);
+        Assert.NotEqual (default (Color), color);
+    }
+
+    [Theory]
+    [InlineData ("Red", 255, 0, 0)]
+    [InlineData ("Green", 0, 128, 0)]
+    [InlineData ("Blue", 0, 0, 255)]
+    [InlineData ("#FF0000", 255, 0, 0)]
+    [InlineData ("#00FF00", 0, 255, 0)]
+    public void TryParseNamedColor_ParsesCorrectRgbValues (string colorName, int expectedR, int expectedG, int expectedB)
+    {
+        bool result = ColorStrings.TryParseNamedColor (colorName, out Color color);
+
+        Assert.True (result);
+        Assert.Equal (expectedR, color.R);
+        Assert.Equal (expectedG, color.G);
+        Assert.Equal (expectedB, color.B);
+    }
+
+    [Theory]
+    [InlineData ("")]
+    [InlineData ("NotAColor")]
+    [InlineData ("Invalid")]
+    [InlineData ("#ZZ0000")]
+    public void TryParseNamedColor_ReturnsFalseForInvalidInput (string invalidInput)
+    {
+        bool result = ColorStrings.TryParseNamedColor (invalidInput, out Color color);
+
+        Assert.False (result);
+        Assert.Equal (default (Color), color);
+    }
+
+    [Fact]
+    public void TryParseNamedColor_WorksWithReadOnlySpan ()
+    {
+        ReadOnlySpan<char> span = "Blue".AsSpan ();
+        bool result = ColorStrings.TryParseNamedColor (span, out Color color);
+
+        Assert.True (result);
+        Assert.Equal (0, color.R);
+        Assert.Equal (0, color.G);
+        Assert.Equal (255, color.B);
+    }
+
+    [Theory]
+    [InlineData (nameof (StandardColor.Aqua), nameof (StandardColor.Cyan))]
+    [InlineData (nameof (StandardColor.Fuchsia), nameof (StandardColor.Magenta))]
+    public void TryParseNamedColor_HandlesColorAliases (string name1, string name2)
+    {
+        bool result1 = ColorStrings.TryParseNamedColor (name1, out Color color1);
+        bool result2 = ColorStrings.TryParseNamedColor (name2, out Color color2);
+
+        Assert.True (result1);
+        Assert.True (result2);
+        Assert.Equal (color1.R, color2.R);
+        Assert.Equal (color1.G, color2.G);
+        Assert.Equal (color1.B, color2.B);
+    }
+
+    [Fact]
+    public void GetColorName_And_TryParseNamedColor_RoundTrip ()
+    {
+        // Get a standard color name
+        Color originalColor = new (255, 0);
+        string? colorName = ColorStrings.GetColorName (originalColor);
+
+        Assert.NotNull (colorName);
+
+        // Parse it back
+        bool result = ColorStrings.TryParseNamedColor (colorName, out Color parsedColor);
+
+        Assert.True (result);
+        Assert.Equal (originalColor.R, parsedColor.R);
+        Assert.Equal (originalColor.G, parsedColor.G);
+        Assert.Equal (originalColor.B, parsedColor.B);
+    }
+
+    [Fact]
+    public void GetStandardColorNames_And_TryParseStandardColorName_RoundTrip ()
+    {
+        // Get all standard color names
+        IEnumerable<string> names = ColorStrings.GetStandardColorNames ();
+
+        // Each name should parse successfully
+        foreach (string name in names)
+        {
+            bool result = ColorStrings.TryParseStandardColorName (name, out Color color);
+            Assert.True (result, $"Failed to parse standard color name: {name}");
+
+            // And should get the same name back (for non-aliases)
+            string? retrievedName = ColorStrings.GetColorName (color);
+            Assert.NotNull (retrievedName);
+
+            // The retrieved name should be one of the valid names for this color
+            // (could be different if there are aliases)
+            Assert.True (
+                         ColorStrings.TryParseStandardColorName (retrievedName, out Color retrievedColor),
+                         $"Retrieved name '{retrievedName}' should be parseable"
+                        );
+            Assert.Equal (color.R, retrievedColor.R);
+            Assert.Equal (color.G, retrievedColor.G);
+            Assert.Equal (color.B, retrievedColor.B);
+        }
+    }
+}

+ 0 - 156
Tests/UnitTestsParallelizable/Drawing/Color/MultiStandardColorNameResolverTests.cs

@@ -1,156 +0,0 @@
-#nullable enable
-
-using System.Collections.Generic;
-using Xunit.Abstractions;
-using Terminal.Gui;
-
-namespace DrawingTests;
-
-public class MultiStandardColorNameResolverTests (ITestOutputHelper output)
-{
-    private readonly MultiStandardColorNameResolver _candidate = new ();
-
-    public static IEnumerable<object []> StandardColors =>
-        Enum.GetValues<StandardColor> ().Select (sc => new object [] { sc });
-
-    [Theory]
-    [MemberData (nameof (StandardColors))]
-    public void TryParseColor_ResolvesAllStandardColorNames (StandardColor standardColor)
-    {
-        string name = standardColor.ToString ();
-        bool parsed = _candidate.TryParseColor (name, out Color actualColor);
-
-        Assert.True (parsed, $"TryParseColor should succeed for {name}");
-
-        Color expectedColor = new (Terminal.Gui.Drawing.StandardColors.GetArgb (standardColor));
-
-        Assert.Equal (expectedColor.R, actualColor.R);
-        Assert.Equal (expectedColor.G, actualColor.G);
-        Assert.Equal (expectedColor.B, actualColor.B);
-    }
-
-    [Theory]
-    [MemberData (nameof (StandardColors))]
-    public void TryNameColor_ResolvesAllStandardColors (StandardColor standardColor)
-    {
-        Color color = new (Terminal.Gui.Drawing.StandardColors.GetArgb (standardColor));
-
-        bool success = _candidate.TryNameColor (color, out string? resolvedName);
-
-        if (!success)
-        {
-            output.WriteLine ($"Unmapped: {standardColor} → {color}");
-        }
-
-        Assert.True (success, $"TryNameColor should succeed for {standardColor}");
-
-        List<string> expectedNames = Enum.GetNames<StandardColor> ()
-            .Where (name => Terminal.Gui.Drawing.StandardColors.GetArgb (Enum.Parse<StandardColor> (name)) == color.Argb)
-            .ToList ();
-
-        Assert.Contains (resolvedName, expectedNames);
-    }
-
-    [Fact]
-    public void TryNameColor_Logs_Unmapped_StandardColors ()
-    {
-        List<StandardColor> unmapped = new ();
-
-        foreach (StandardColor sc in Enum.GetValues<StandardColor> ())
-        {
-            Color color = new (Terminal.Gui.Drawing.StandardColors.GetArgb (sc));
-            if (!_candidate.TryNameColor (color, out _))
-            {
-                unmapped.Add (sc);
-            }
-        }
-
-        output.WriteLine ("Unmapped StandardColor entries:");
-        foreach (StandardColor sc in unmapped.Distinct ())
-        {
-            output.WriteLine ($"- {sc}");
-        }
-
-        Assert.True (unmapped.Count < 10, $"Too many StandardColor values are not name-resolvable. Got {unmapped.Count}.");
-    }
-
-    [Theory]
-    [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))]
-    [InlineData (nameof (StandardColor.AliceBlue))]
-    [InlineData (nameof (StandardColor.BlanchedAlmond))]
-    public void GetNames_ContainsKnownNames (string name)
-    {
-        string [] names = _candidate.GetColorNames ().ToArray ();
-        Assert.Contains (name, names);
-    }
-
-    [Theory]
-    [InlineData (0, 0, 0, nameof (ColorName16.Black))]
-    [InlineData (0, 0, 255, nameof (ColorName16.Blue))]
-    [InlineData (59, 120, 255, nameof (ColorName16.BrightBlue))]
-    [InlineData (255, 0, 0, nameof (ColorName16.Red))]
-    [InlineData (255, 255, 255, nameof (ColorName16.White))]
-    [InlineData (240, 248, 255, nameof (StandardColor.AliceBlue))]
-    [InlineData (178, 34, 34, nameof (StandardColor.FireBrick))]
-    [InlineData (245, 245, 245, nameof (StandardColor.WhiteSmoke))]
-    public void TryNameColor_ReturnsExpectedColorNames (byte r, byte g, byte b, string expectedName)
-    {
-        Color color = new (r, g, b);
-        bool actualSuccess = _candidate.TryNameColor (color, out string? actualName);
-
-        Assert.True (actualSuccess);
-        Assert.Equal (expectedName, actualName);
-    }
-
-    [Fact]
-    public void TryNameColor_NoMatchFails ()
-    {
-        Color input = new (1, 2, 3);
-        bool success = _candidate.TryNameColor (input, out string? actualName);
-        Assert.False (success);
-        Assert.Null (actualName);
-    }
-
-    [Theory]
-    [InlineData ("12", 231, 72, 86)] // ColorName16.BrightRed
-    [InlineData ("16737095", 255, 99, 71)] // StandardColor.Tomato
-    [InlineData ("#FF0000", 255, 0, 0)] // Red
-    public void TryParseColor_ResolvesValidEnumNumber (string inputName, byte r, byte g, byte b)
-    {
-        bool success = _candidate.TryParseColor (inputName, out Color actualColor);
-        Assert.True (success);
-        Assert.Equal (r, actualColor.R);
-        Assert.Equal (g, actualColor.G);
-        Assert.Equal (b, actualColor.B);
-    }
-
-    [Theory]
-    [InlineData (null)]
-    [InlineData ("")]
-    [InlineData ("brightlight")]
-    public void TryParseColor_FailsOnInvalidColorName (string? input)
-    {
-        bool success = _candidate.TryParseColor (input, out Color actualColor);
-        Assert.False (success);
-        Assert.Equal (default, actualColor);
-    }
-
-    [Theory]
-    [InlineData ("-12")]
-    [InlineData ("-16737095")]
-    public void TryParseColor_FailsOnInvalidEnumNumber (string input)
-    {
-        bool success = _candidate.TryParseColor (input, out Color actualColor);
-        Assert.False (success);
-        Assert.Equal (default, actualColor);
-    }
-}

+ 2 - 4
Tests/UnitTestsParallelizable/Drawing/Color/StandardColorNameResolverTests.cs

@@ -1,8 +1,6 @@
-#nullable enable
+using Xunit.Abstractions;
 
-using Xunit.Abstractions;
-
-namespace DrawingTests;
+namespace DrawingTests.ColorTests;
 
 public class StandardColorNameResolverTests (ITestOutputHelper output)
 {

+ 268 - 0
Tests/UnitTestsParallelizable/Drawing/Color/StandardColorsTests.cs

@@ -0,0 +1,268 @@
+#pragma warning disable xUnit1031
+
+namespace DrawingTests.ColorTests;
+
+public class StandardColorsTests
+{
+    [Fact]
+    public void GetArgb_HandlesAllStandardColorValues ()
+    {
+        foreach (StandardColor sc in Enum.GetValues<StandardColor> ())
+        {
+            uint argb = StandardColors.GetArgb (sc);
+
+            // Verify alpha is always 0xFF (fully opaque)
+            var alpha = (byte)((argb >> 24) & 0xFF);
+            Assert.Equal (255, alpha);
+
+            // Verify the RGB components match the enum value
+            var enumRgb = (int)sc;
+            uint expectedArgb = (uint)enumRgb | 0xFF000000;
+            Assert.Equal (expectedArgb, argb);
+        }
+    }
+
+    [Theory]
+    [InlineData (StandardColor.Red, 255, 0, 0)]
+    [InlineData (StandardColor.Green, 0, 128, 0)]
+    [InlineData (StandardColor.Blue, 0, 0, 255)]
+    [InlineData (StandardColor.White, 255, 255, 255)]
+    [InlineData (StandardColor.Black, 0, 0, 0)]
+    [InlineData (StandardColor.AliceBlue, 240, 248, 255)]
+    [InlineData (StandardColor.YellowGreen, 154, 205, 50)]
+    public void GetArgb_ReturnsCorrectArgbWithFullAlpha (StandardColor standardColor, byte r, byte g, byte b)
+    {
+        uint argb = StandardColors.GetArgb (standardColor);
+
+        var actualA = (byte)((argb >> 24) & 0xFF);
+        var actualR = (byte)((argb >> 16) & 0xFF);
+        var actualG = (byte)((argb >> 8) & 0xFF);
+        var actualB = (byte)(argb & 0xFF);
+
+        Assert.Equal (255, actualA);
+        Assert.Equal (r, actualR);
+        Assert.Equal (g, actualG);
+        Assert.Equal (b, actualB);
+    }
+
+    [Fact]
+    public void GetColorNames_ContainsAllStandardColorEnumValues ()
+    {
+        string [] enumNames = Enum.GetNames<StandardColor> ().Order ().ToArray ();
+        IReadOnlyList<string> colorNames = StandardColors.GetColorNames ();
+
+        Assert.Equal (enumNames.Length, colorNames.Count);
+        Assert.Equal (enumNames, colorNames);
+    }
+
+    [Fact]
+    public void GetColorNames_IsAlphabeticallySorted ()
+    {
+        IReadOnlyList<string> colorNames = StandardColors.GetColorNames ();
+        string [] sortedNames = colorNames.OrderBy (n => n).ToArray ();
+
+        Assert.Equal (sortedNames, colorNames);
+    }
+
+    [Fact]
+    public void LazyInitialization_IsThreadSafe ()
+    {
+        // Force initialization by calling GetColorNames multiple times in parallel
+        Task [] tasks = new Task [10];
+
+        for (var i = 0; i < tasks.Length; i++)
+        {
+            tasks [i] = Task.Run (() =>
+                                  {
+                                      IReadOnlyList<string> names = StandardColors.GetColorNames ();
+                                      Assert.NotNull (names);
+                                      Assert.NotEmpty (names);
+                                  }
+                                 );
+        }
+
+        Task.WaitAll (tasks);
+    }
+
+    [Fact]
+    public void MapValueFactory_CreatesConsistentMapping ()
+    {
+        // Call TryNameColor multiple times for the same color
+        var testColor = new Color (255, 0);
+
+        bool result1 = StandardColors.TryNameColor (testColor, out string? name1);
+        bool result2 = StandardColors.TryNameColor (testColor, out string? name2);
+
+        Assert.True (result1);
+        Assert.True (result2);
+        Assert.Equal (name1, name2);
+    }
+
+    [Fact]
+    public void ToString_G_Prints_Opaque_ARGB_For_StandardColor_CadetBlue ()
+    {
+        // Without the fix, A=0x00, so "G" prints "#005F9EA0" instead of "#FF5F9EA0".
+        var c = new Color (StandardColor.CadetBlue);
+
+        // Expected: #AARRGGBB with A=FF (opaque)
+        Assert.Equal ("#FF5F9EA0", c.ToString ("G"));
+    }
+
+    [Fact]
+    public void ToString_Returns_Standard_Name_For_StandardColor_CadetBlue ()
+    {
+        // Without the fix, this uses Color(in StandardColor) -> this((int)colorName),
+        // which sets A=0x00 and prevents name resolution (expects A=0xFF).
+        var c = new Color (StandardColor.CadetBlue);
+
+        // Expected: named color
+        Assert.Equal ("CadetBlue", c.ToString ());
+    }
+
+    [Fact]
+    public void TryNameColor_IgnoresAlphaChannel ()
+    {
+        var opaqueRed = new Color (255, 0, 0, 255);
+        var transparentRed = new Color (255, 0, 0, 128);
+
+        Assert.True (StandardColors.TryNameColor (opaqueRed, out string? name1));
+        Assert.True (StandardColors.TryNameColor (transparentRed, out string? name2));
+
+        Assert.Equal (name1, name2);
+        Assert.Equal ("Red", name1);
+    }
+
+    [Fact]
+    public void TryNameColor_ReturnsConsistentResultsForSameArgb ()
+    {
+        List<Color> colors = new ();
+
+        // Create multiple Color instances with the same ARGB values
+        for (var i = 0; i < 5; i++)
+        {
+            colors.Add (new (255, 0));
+        }
+
+        HashSet<string?> names = new ();
+
+        foreach (Color color in colors)
+        {
+            StandardColors.TryNameColor (color, out string? name);
+            names.Add (name);
+        }
+
+        // All should resolve to the same name
+        Assert.Single (names);
+        Assert.Equal ("Red", names.First ());
+    }
+
+    [Fact]
+    public void TryNameColor_ReturnsFalseForUnknownColor ()
+    {
+        var unknownColor = new Color (1, 2, 3);
+        bool result = StandardColors.TryNameColor (unknownColor, out string? name);
+
+        Assert.False (result);
+        Assert.Null (name);
+    }
+
+    [Fact]
+    public void TryNameColor_ReturnsFirstAlphabeticalNameForAliasedColors ()
+    {
+        // Aqua and Cyan have the same RGB values
+        var aqua = new Color (0, 255, 255);
+        Assert.True (StandardColors.TryNameColor (aqua, out string? name));
+
+        // Should return the alphabetically first name
+        Assert.Equal ("Aqua", name);
+    }
+
+    [Theory]
+    [InlineData (nameof (StandardColor.Aqua), nameof (StandardColor.Cyan))]
+    [InlineData (nameof (StandardColor.Fuchsia), nameof (StandardColor.Magenta))]
+    [InlineData (nameof (StandardColor.DarkGray), nameof (StandardColor.DarkGrey))]
+    [InlineData (nameof (StandardColor.DarkSlateGray), nameof (StandardColor.DarkSlateGrey))]
+    [InlineData (nameof (StandardColor.DimGray), nameof (StandardColor.DimGrey))]
+    [InlineData (nameof (StandardColor.Gray), nameof (StandardColor.Grey))]
+    [InlineData (nameof (StandardColor.LightGray), nameof (StandardColor.LightGrey))]
+    [InlineData (nameof (StandardColor.LightSlateGray), nameof (StandardColor.LightSlateGrey))]
+    [InlineData (nameof (StandardColor.SlateGray), nameof (StandardColor.SlateGrey))]
+    public void TryParseColor_HandlesColorAliases (string name1, string name2)
+    {
+        Assert.True (StandardColors.TryParseColor (name1, out Color color1));
+        Assert.True (StandardColors.TryParseColor (name2, out Color color2));
+
+        Assert.Equal (color1, color2);
+    }
+
+    [Theory]
+    [InlineData (StandardColor.AmberPhosphor, 255, 191, 0)]
+    [InlineData (StandardColor.GreenPhosphor, 0, 255, 102)]
+    [InlineData (StandardColor.GuppieGreen, 173, 255, 47)]
+    public void TryParseColor_HandlesNonW3CColors (StandardColor color, byte r, byte g, byte b)
+    {
+        bool result = StandardColors.TryParseColor (color.ToString (), out Color parsedColor);
+
+        Assert.True (result);
+        Assert.Equal (r, parsedColor.R);
+        Assert.Equal (g, parsedColor.G);
+        Assert.Equal (b, parsedColor.B);
+    }
+
+    [Fact]
+    public void TryParseColor_IsCaseInsensitive ()
+    {
+        Assert.True (StandardColors.TryParseColor ("RED", out Color upperColor));
+        Assert.True (StandardColors.TryParseColor ("red", out Color lowerColor));
+        Assert.True (StandardColors.TryParseColor ("Red", out Color mixedColor));
+
+        Assert.Equal (upperColor, lowerColor);
+        Assert.Equal (upperColor, mixedColor);
+        Assert.Equal (255, upperColor.R);
+        Assert.Equal (0, upperColor.G);
+        Assert.Equal (0, upperColor.B);
+    }
+
+    [Theory]
+    [InlineData ("")]
+    [InlineData ("NotAColor")]
+    [InlineData ("123456")]
+    [InlineData ("-1")]
+    public void TryParseColor_ReturnsFalseForInvalidInput (string invalidInput)
+    {
+        bool result = StandardColors.TryParseColor (invalidInput, out Color color);
+
+        Assert.False (result);
+        Assert.Equal (default (Color), color);
+    }
+
+    [Fact]
+    public void TryParseColor_SetsAlphaToFullyOpaque ()
+    {
+        Assert.True (StandardColors.TryParseColor ("Red", out Color color));
+
+        Assert.Equal (255, color.A);
+    }
+
+    [Fact]
+    public void TryParseColor_WithEmptySpan_ReturnsFalse ()
+    {
+        ReadOnlySpan<char> emptySpan = ReadOnlySpan<char>.Empty;
+        bool result = StandardColors.TryParseColor (emptySpan, out Color color);
+
+        Assert.False (result);
+        Assert.Equal (default (Color), color);
+    }
+
+    [Fact]
+    public void TryParseColor_WithReadOnlySpan_WorksCorrectly ()
+    {
+        ReadOnlySpan<char> span = "Red".AsSpan ();
+        bool result = StandardColors.TryParseColor (span, out Color color);
+
+        Assert.True (result);
+        Assert.Equal (255, color.R);
+        Assert.Equal (0, color.G);
+        Assert.Equal (0, color.B);
+    }
+}

+ 1 - 1
Tests/UnitTestsParallelizable/Drawing/LineCanvasTests.cs → Tests/UnitTestsParallelizable/Drawing/Lines/LineCanvasTests.cs

@@ -2,7 +2,7 @@
 using UnitTests;
 using Xunit.Abstractions;
 
-namespace DrawingTests;
+namespace DrawingTests.Lines;
 
 /// <summary>
 ///     Pure unit tests for <see cref="LineCanvas"/> that don't require Application.Driver or View context.

+ 1 - 1
Tests/UnitTestsParallelizable/Drawing/StraightLineExtensionsTests.cs → Tests/UnitTestsParallelizable/Drawing/Lines/StraightLineExtensionsTests.cs

@@ -1,7 +1,7 @@
 using UnitTests;
 using Xunit.Abstractions;
 
-namespace DrawingTests;
+namespace UnitTests.Parallelizable.Drawing.Lines;
 
 public class StraightLineExtensionsTests (ITestOutputHelper output)
 {

+ 1 - 1
Tests/UnitTestsParallelizable/Drawing/StraightLineTests.cs → Tests/UnitTestsParallelizable/Drawing/Lines/StraightLineTests.cs

@@ -1,6 +1,6 @@
 using Xunit.Abstractions;
 
-namespace DrawingTests;
+namespace UnitTests.Parallelizable.Drawing.Lines;
 
 public class StraightLineTests (ITestOutputHelper output)
 {

+ 1 - 1
Tests/UnitTestsParallelizable/Drawing/Region/DifferenceTests.cs

@@ -1,6 +1,6 @@
 using Xunit.Sdk;
 
-namespace DrawingTests;
+namespace DrawingTests.RegionTests;
 
 public class DifferenceTests
 {

+ 1 - 1
Tests/UnitTestsParallelizable/Drawing/Region/DrawOuterBoundaryTests.cs

@@ -1,7 +1,7 @@
 using System.Collections.Concurrent;
 using Xunit.Abstractions;
 
-namespace DrawingTests;
+namespace DrawingTests.RegionTests;
 
 /// <summary>
 ///     Tests for <see cref="Region.DrawOuterBoundary"/>.

+ 1 - 1
Tests/UnitTestsParallelizable/Drawing/Region/MergeRectanglesTests.cs

@@ -1,4 +1,4 @@
-namespace DrawingTests;
+namespace DrawingTests.RegionTests;
 
 
 public class MergeRectanglesTests

+ 2 - 2
Tests/UnitTestsParallelizable/Drawing/Region/RegionTests.cs → Tests/UnitTestsParallelizable/Drawing/Region/RegionClassTests.cs

@@ -1,6 +1,6 @@
-namespace DrawingTests;
+namespace DrawingTests.RegionTests;
 
-public class RegionTests
+public class RegionClassTests
 {
     [Fact]
     public void Clone_CreatesExactCopy ()

+ 1 - 1
Tests/UnitTestsParallelizable/Drawing/Region/SubtractRectangleTests.cs

@@ -1,4 +1,4 @@
-namespace DrawingTests;
+namespace DrawingTests.RegionTests;
 
 using Xunit;
 

+ 71 - 0
docfx/docs/drawing.md

@@ -10,6 +10,27 @@ Terminal.Gui provides a set of APIs for formatting text, line drawing, and chara
 
 Terminal.Gui apps draw using the @Terminal.Gui.ViewBase.View.Move(System.Int32,System.Int32) and @Terminal.Gui.ViewBase.View.AddRune(System.Text.Rune) APIs. Move selects the column and row of the cell and AddRune places the specified glyph in that cell using the @Terminal.Gui.Drawing.Attribute that was most recently set via @Terminal.Gui.ViewBase.View.SetAttribute(Terminal.Gui.Drawing.Attribute). The driver caches all changed Cells and efficiently outputs them to the terminal each iteration of the Application. In other words, Terminal.Gui uses deferred rendering. 
 
+## Drawing Lifecycle
+
+**Drawing occurs during Application MainLoop iterations**, not immediately when draw-related methods are called. This deferred rendering approach provides better performance and ensures visual consistency.
+
+### MainLoop Iteration Process
+
+Each iteration of the @Terminal.Gui.App.Application MainLoop (throttled to a maximum rate) performs these steps in order:
+
+1. **Layout** - Views that need layout are measured and positioned (@Terminal.Gui.ViewBase.View.LayoutSubviews is called)
+2. **Draw** - Views that need drawing update the driver's back buffer (@Terminal.Gui.ViewBase.View.Draw is called)
+3. **Write** - The driver writes changed portions of the back buffer to the actual terminal
+4. **Cursor** - The driver ensures the cursor is positioned correctly with appropriate visibility
+
+### When Drawing Actually Occurs
+
+- **Normal Operation**: Drawing happens automatically during MainLoop iterations when @Terminal.Gui.ViewBase.View.NeedsDraw or @Terminal.Gui.ViewBase.View.SubViewNeedsDraw is set
+- **Forced Update**: @Terminal.Gui.App.Application.LayoutAndDraw can be called to immediately trigger layout and drawing outside of the normal iteration cycle
+- **Testing**: Tests can call @Terminal.Gui.ViewBase.View.Draw directly to update the back buffer, then call @Terminal.Gui.Drivers.IDriver.Refresh to output to the terminal
+
+**Important**: Calling `View.Draw()` does not immediately update the terminal screen. It only updates the driver's back buffer. The actual terminal output occurs when the driver's `Refresh()` method is called, which happens automatically during MainLoop iterations.
+
 ## Coordinate System for Drawing
 
 The @Terminal.Gui.ViewBase.View draw APIs all take coordinates specified in *Viewport-Relative* coordinates. That is, `0, 0` is the top-left cell visible to the user.
@@ -60,6 +81,8 @@ Then, after the above steps have completed, the Mainloop will iterate through al
 
 If a View need to redraw because something changed within it's Content Area it can call @Terminal.Gui.ViewBase.View.SetNeedsDraw. If a View needs to be redrawn because something has changed the size of the Viewport, it can call @Terminal.Gui.ViewBase.View.SetNeedsLayout.
 
+**Note**: Calling `SetNeedsDraw()` does not immediately cause drawing to occur. It marks the view as needing to be redrawn, which will happen in the next MainLoop iteration. To force immediate drawing (typically only needed in tests), call @Terminal.Gui.App.Application.LayoutAndDraw.
+
 ## Clipping
 
 Clipping enables better performance and features like transparent margins by ensuring regions of the terminal that need to be drawn actually get drawn by the driver. Terminal.Gui supports non-rectangular clip regions with @Terminal.Gui.Drawing.Region. The driver.Clip is the application managed clip region and is managed by @Terminal.Gui.App.Application. Developers cannot change this directly, but can use @Terminal.Gui.ViewBase.View.SetClipToScreen, @Terminal.Gui.ViewBase.View.SetClip(Terminal.Gui.Drawing.Region), @Terminal.Gui.ViewBase.View.SetClipToFrame, etc...
@@ -98,6 +121,54 @@ SetAttributeForRole (VisualRole.Focus);
 AddStr ("Red on Black Underlined.");
 ```
 
+## Color
+
+Terminal.Gui supports 24-bit true color (16.7 million colors) via the @Terminal.Gui.Drawing.Color struct. The @Terminal.Gui.Drawing.Color struct represents colors in ARGB32 format, with separate bytes for Alpha (transparency), Red, Green, and Blue components.
+
+### Standard Colors (W3C+)
+
+Terminal.Gui provides comprehensive support for W3C standard color names plus additional common terminal colors via the @Terminal.Gui.Drawing.StandardColor enum. This includes all standard W3C colors (like `AliceBlue`, `Red`, `Tomato`, etc.) as well as classic terminal colors (like `AmberPhosphor`, `GreenPhosphor`).
+
+Colors can be created from standard color names:
+
+```cs
+var color1 = new Color(StandardColor.CornflowerBlue);
+var color2 = new Color(StandardColor.Tomato);
+var color3 = new Color("Red");  // Case-insensitive color name parsing
+```
+
+Standard colors can also be parsed from strings:
+
+```cs
+if (Color.TryParse("CornflowerBlue", out Color color))
+{
+    // Use the color
+}
+```
+
+### Alpha Channel and Transparency
+
+While @Terminal.Gui.Drawing.Color supports an alpha channel for transparency (values 0-255), **terminal rendering does not currently support alpha blending**. The alpha channel is primarily used to:
+
+- Indicate whether a color should be rendered at all (alpha = 0 means fully transparent/don't render)
+- Support future transparency features
+- Enable terminal background pass-through (see [#2381](https://github.com/gui-cs/Terminal.Gui/issues/2381) and [#4229](https://github.com/gui-cs/Terminal.Gui/issues/4229))
+
+**Important**: When matching colors to standard color names, the alpha channel is **ignored**. This means `Color(255, 0, 0, 255)` (opaque red) and `Color(255, 0, 0, 128)` (semi-transparent red) will both be recognized as "Red". This design decision supports the vision of enabling transparent backgrounds while still being able to identify colors semantically.
+
+```cs
+var opaqueRed = new Color(255, 0, 0, 255);
+var transparentRed = new Color(255, 0, 0, 0);
+
+// Both will resolve to "Red"
+ColorStrings.GetColorName(opaqueRed);      // Returns "Red"
+ColorStrings.GetColorName(transparentRed); // Returns "Red"
+```
+
+### Legacy 16-Color Support
+
+For backwards compatibility and terminals with limited color support, Terminal.Gui maintains the legacy 16-color system via @Terminal.Gui.Drawing.ColorName16. When true color is not available or when `Application.Force16Colors` is set, Terminal.Gui will map true colors to the nearest 16-color equivalent.
+
 ## VisualRole
 
 Represents the semantic visual role of a visual element rendered by a View (e.g., Normal text, Focused item, Active selection).