Browse Source

Merge branch 'v2_develop' into copilot/fix-3ee850b1-eb6b-46b0-964b-3b98d2c0c14e

Tig 1 week ago
parent
commit
11d7692aec
100 changed files with 1853 additions and 2097 deletions
  1. 3 16
      .github/workflows/api-docs.yml
  2. 2 11
      Examples/Example/Example.cs
  3. 35 0
      Examples/PowershellExample.ps1
  4. 1 1
      Examples/UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs
  5. 110 121
      Examples/UICatalog/Scenarios/ColorPicker.cs
  6. 1 4
      Examples/UICatalog/Scenarios/CombiningMarks.cs
  7. 1 1
      Examples/UICatalog/Scenarios/ContextMenus.cs
  8. 13 13
      Examples/UICatalog/Scenarios/CsvEditor.cs
  9. 2 2
      Examples/UICatalog/Scenarios/DynamicStatusBar.cs
  10. 9 9
      Examples/UICatalog/Scenarios/Editor.cs
  11. 5 5
      Examples/UICatalog/Scenarios/FileDialogExamples.cs
  12. 1 1
      Examples/UICatalog/Scenarios/Generic.cs
  13. 4 4
      Examples/UICatalog/Scenarios/HexEditor.cs
  14. 20 19
      Examples/UICatalog/Scenarios/Images.cs
  15. 1 1
      Examples/UICatalog/Scenarios/InteractiveTree.cs
  16. 4 4
      Examples/UICatalog/Scenarios/KeyBindings.cs
  17. 7 10
      Examples/UICatalog/Scenarios/LineDrawing.cs
  18. 1 1
      Examples/UICatalog/Scenarios/ListColumns.cs
  19. 14 2
      Examples/UICatalog/Scenarios/Menus.cs
  20. 2 2
      Examples/UICatalog/Scenarios/MessageBoxes.cs
  21. 1 1
      Examples/UICatalog/Scenarios/MultiColouredTable.cs
  22. 1 1
      Examples/UICatalog/Scenarios/Navigation.cs
  23. 2 2
      Examples/UICatalog/Scenarios/Notepad.cs
  24. 1 1
      Examples/UICatalog/Scenarios/RegionScenario.cs
  25. 3 3
      Examples/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
  26. 1 1
      Examples/UICatalog/Scenarios/Snake.cs
  27. 1 1
      Examples/UICatalog/Scenarios/TextEffectsScenario.cs
  28. 102 24
      Examples/UICatalog/Scenarios/Transparent.cs
  29. 1 1
      Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs
  30. 3 3
      Examples/UICatalog/Scenarios/WizardAsView.cs
  31. 9 5
      Examples/UICatalog/UICatalog.cs
  32. 52 46
      Examples/UICatalog/UICatalogRunnable.cs
  33. 72 36
      README.md
  34. 9 25
      Terminal.Gui/App/Application.Driver.cs
  35. 17 1
      Terminal.Gui/App/Application.Lifecycle.cs
  36. 0 117
      Terminal.Gui/App/Application.cd
  37. 13 9
      Terminal.Gui/App/ApplicationImpl.Driver.cs
  38. 5 25
      Terminal.Gui/App/ApplicationImpl.Lifecycle.cs
  39. 1 1
      Terminal.Gui/App/ApplicationImpl.Run.cs
  40. 28 45
      Terminal.Gui/App/ApplicationImpl.Screen.cs
  41. 2 15
      Terminal.Gui/App/ApplicationImpl.cs
  42. 0 13
      Terminal.Gui/App/IApplication.cs
  43. 12 48
      Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs
  44. 2 8
      Terminal.Gui/App/Mouse/MouseImpl.cs
  45. 32 17
      Terminal.Gui/App/Timeout/TimedEvents.cs
  46. 1 1
      Terminal.Gui/Drawing/Cell.cs
  47. 0 68
      Terminal.Gui/Drawing/Color/AnsiColorNameResolver.cs
  48. 34 50
      Terminal.Gui/Drawing/Color/Color.cs
  49. 6 5
      Terminal.Gui/Drawing/Color/ColorModel.cs
  50. 3 3
      Terminal.Gui/Drawing/Color/ColorQuantizer.cs
  51. 6 53
      Terminal.Gui/Drawing/Color/ColorStrings.cs
  52. 0 83
      Terminal.Gui/Drawing/Color/MultiStandardColorNameResolver.cs
  53. 60 1
      Terminal.Gui/Drawing/Color/StandardColor.cs
  54. 5 2
      Terminal.Gui/Drawing/Color/StandardColors.cs
  55. 23 0
      Terminal.Gui/Drawing/GraphemeHelper.cs
  56. 12 4
      Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs
  57. 5 4
      Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs
  58. 1 1
      Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs
  59. 31 0
      Terminal.Gui/Drivers/Driver.cs
  60. 181 163
      Terminal.Gui/Drivers/DriverImpl.cs
  61. 16 5
      Terminal.Gui/Drivers/FakeDriver/FakeOutput.cs
  62. 164 123
      Terminal.Gui/Drivers/IDriver.cs
  63. 13 2
      Terminal.Gui/Drivers/IOutput.cs
  64. 1 1
      Terminal.Gui/Drivers/ISizeMonitor.cs
  65. 84 25
      Terminal.Gui/Drivers/OutputBase.cs
  66. 1 1
      Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs
  67. 75 99
      Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs
  68. 5 5
      Terminal.Gui/Resources/config.json
  69. 76 26
      Terminal.Gui/Text/TextFormatter.cs
  70. 2 2
      Terminal.Gui/ViewBase/Adornment/Adornment.cs
  71. 1 3
      Terminal.Gui/ViewBase/Adornment/Border.cs
  72. 10 10
      Terminal.Gui/ViewBase/Adornment/Margin.cs
  73. 1 1
      Terminal.Gui/ViewBase/Adornment/ShadowView.cs
  74. 58 6
      Terminal.Gui/ViewBase/DrawContext.cs
  75. 10 10
      Terminal.Gui/ViewBase/Runnable/Runnable.cs
  76. 49 0
      Terminal.Gui/ViewBase/View.Command.cs
  77. 1 1
      Terminal.Gui/ViewBase/View.Content.cs
  78. 98 212
      Terminal.Gui/ViewBase/View.Drawing.cs
  79. 168 0
      Terminal.Gui/ViewBase/View.NeedsDraw.cs
  80. 0 79
      Terminal.Gui/Views/Autocomplete/Autocomplete.cd
  81. 1 1
      Terminal.Gui/Views/Autocomplete/PopupAutocomplete.PopUp.cs
  82. 1 1
      Terminal.Gui/Views/CharMap/CharMap.cs
  83. 0 124
      Terminal.Gui/Views/CollectionNavigation/CollectionNavigation.cd
  84. 0 2
      Terminal.Gui/Views/Color/BBar.cs
  85. 2 5
      Terminal.Gui/Views/Color/ColorBar.cs
  86. 28 45
      Terminal.Gui/Views/Color/ColorModelStrategy.cs
  87. 1 1
      Terminal.Gui/Views/Color/ColorPicker.16.cs
  88. 6 6
      Terminal.Gui/Views/Color/ColorPicker.Prompt.cs
  89. 0 3
      Terminal.Gui/Views/Color/ColorPicker.Style.cs
  90. 1 1
      Terminal.Gui/Views/Color/ColorPicker.cs
  91. 0 2
      Terminal.Gui/Views/Color/GBar.cs
  92. 1 2
      Terminal.Gui/Views/Color/IColorBar.cs
  93. 0 2
      Terminal.Gui/Views/Color/LightnessBar.cs
  94. 0 2
      Terminal.Gui/Views/Color/RBar.cs
  95. 0 2
      Terminal.Gui/Views/Color/SaturationBar.cs
  96. 2 2
      Terminal.Gui/Views/ComboBox.cs
  97. 0 168
      Terminal.Gui/Views/FileDialogs/FileDialog.cd
  98. 1 1
      Terminal.Gui/Views/FileDialogs/FileDialog.cs
  99. 1 1
      Terminal.Gui/Views/GraphView/GraphView.cs
  100. 1 1
      Terminal.Gui/Views/HexView.cs

+ 3 - 16
.github/workflows/api-docs.yml

@@ -1,8 +1,8 @@
-name: Build and publish API docs
+name: Build and publish v2 API docs
 
 on:
   push:
-    branches: [v1_release, v2_develop]
+    branches: [v2_develop]
 
 permissions:
   id-token: write 
@@ -10,7 +10,7 @@ permissions:
 
 jobs:
   deploy:
-    name: Build and Deploy API docs to github-pages ${{ github.ref_name }}
+    name: Build and Deploy v2 API docs to github-pages ${{ github.ref_name }}
     environment:
       name: github-pages
       url: ${{ steps.deployment.outputs.page_url }}
@@ -20,7 +20,6 @@ jobs:
       uses: actions/checkout@v4
 
     - name: DocFX Build
-      #if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       working-directory: docfx
       run: |
         dotnet tool install -g docfx
@@ -30,27 +29,15 @@ jobs:
       continue-on-error: false
 
     - name: Setup Pages
-      #if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       uses: actions/configure-pages@v5
       
     - name: Upload artifact
-      #if: github.ref_name == 'v1_release' ||  github.ref_name == 'v1_develop'
       uses: actions/upload-pages-artifact@v3
       with:
         path: docfx/_site
        
     - name: Deploy to GitHub Pages
-      if: github.ref_name == 'v2_release' ||  github.ref_name == 'v2_develop'
       id: deployment
       uses: actions/deploy-pages@v4
       with:
         token: ${{ secrets.GITHUB_TOKEN }}
-
-    # - name: v1_release Repository Dispatch ${{ github.ref_name }}
-    #   if: github.ref_name == 'v2_develop'
-    #   uses: peter-evans/repository-dispatch@v3
-    #   with:
-    #     token: ${{ secrets.V2DOCS_TOKEN }}
-    #     repository: gui-cs/Terminal.GuiV1Docs
-    #     event-type: v2_develop_push
-    #     client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'

+ 2 - 11
Examples/Example/Example.cs

@@ -8,8 +8,8 @@ using Terminal.Gui.Configuration;
 using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
 
-// Override the default configuration for the application to use the Light theme
-ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
+// Override the default configuration for the application to use the Amber Phosphor theme
+ConfigurationManager.RuntimeConfig = """{ "Theme": "Amber Phosphor" }""";
 ConfigurationManager.Enable (ConfigLocations.All);
 
 IApplication app = Application.Create ();
@@ -90,14 +90,5 @@ public sealed class ExampleWindow : Window
 
         // Add the views to the Window
         Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin);
-
-        var lv = new ListView
-        {
-            Y = Pos.AnchorEnd (),
-            Height = Dim.Auto (),
-            Width = Dim.Auto ()
-        };
-        lv.SetSource (["One", "Two", "Three", "Four"]);
-        Add (lv);
     }
 }

+ 35 - 0
Examples/PowershellExample.ps1

@@ -0,0 +1,35 @@
+using namespace Terminal.Gui.App        
+using namespace Terminal.Gui.ViewBase
+using namespace Terminal.Gui.Views
+
+$dllFolder = "..\Terminal.Gui\bin\Debug\net8.0"
+
+# For this to work all dependent DLLs need to be in the $dllFolder folder
+# Do this first:
+#   dotnet build -c Debug /p:CopyLocalLockFileAssemblies=true
+
+Get-ChildItem $dllFolder -Filter *.dll | ForEach-Object {
+    Add-Type -Path $_.FullName -ErrorAction SilentlyContinue
+}
+
+$app = [Application]::Create()
+
+$app.Init()
+
+$win = [Window]@{
+    Title  = "Terminal.Gui in Powershell"
+    Width  = [Dim]::Fill()
+    Height = [Dim]::Fill()
+}
+
+$lbl = [Label]@{
+    Text = "Hello from PowerShell + Terminal.Gui!`nPress ESC to quit"
+    X    = [Pos]::Center()
+    Y    = [Pos]::Center()
+}
+$win.Add($lbl)
+
+$app.Run($win)
+
+$win.Dispose()
+$app.Dispose()

+ 1 - 1
Examples/UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs

@@ -173,7 +173,7 @@ public class AnimationScenario : Scenario
         private Rectangle _oldSize = Rectangle.Empty;
         public void NextFrame () { _currentFrame = (_currentFrame + 1) % _frameCount; }
 
-        protected override bool OnDrawingContent ()
+        protected override bool OnDrawingContent (DrawContext? context)
         {
             if (_frameCount == 0)
             {

+ 110 - 121
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
@@ -241,47 +186,94 @@ public class ColorPickers : Scenario
         {
             X = Pos.Right (cbSupportsTrueColor) + 1,
             Y = Pos.Top (lblDriverName),
-            CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
+            CheckedState = Application.Driver.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
             Enabled = canTrueColor,
             Text = "Force16Colors"
         };
-        cbUseTrueColor.CheckedStateChanging += (_, evt) => { Application.Force16Colors = evt.Result == CheckState.Checked; };
+        cbUseTrueColor.CheckedStateChanging += (_, evt) => { Application.Driver!.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);
         }

+ 1 - 4
Examples/UICatalog/Scenarios/CombiningMarks.cs

@@ -10,11 +10,8 @@ public class CombiningMarks : Scenario
         Application.Init ();
         var top = new Runnable ();
 
-        top.DrawComplete += (s, e) =>
+        top.DrawingContent += (s, e) =>
         {
-            // Forces reset _lineColsOffset because we're dealing with direct draw
-            Application.TopRunnableView!.SetNeedsDraw ();
-
             var i = -1;
             top.Move (0, ++i);
             top.AddStr ("Terminal.Gui supports all combining sequences that can be rendered as an unique grapheme.");

+ 1 - 1
Examples/UICatalog/Scenarios/ContextMenus.cs

@@ -49,7 +49,7 @@ public class ContextMenus : Scenario
             var text = "Context Menu";
             var width = 20;
 
-            CreateWinContextMenu (ApplicationImpl.Instance);
+            CreateWinContextMenu (Application.Instance);
 
             var label = new Label
             {

+ 13 - 13
Examples/UICatalog/Scenarios/CsvEditor.cs

@@ -215,7 +215,7 @@ public class CsvEditor : Scenario
                                       _tableView.Table.Columns
                                      );
 
-            int? result = MessageBox.Query (ApplicationImpl.Instance,
+            int? result = MessageBox.Query (Application.Instance,
                                            "Column Type",
                                            "Pick a data type for the column",
                                            "Date",
@@ -308,7 +308,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }
@@ -320,7 +320,7 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Could not remove column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "Could not remove column", ex.Message, "Ok");
         }
     }
 
@@ -342,7 +342,7 @@ public class CsvEditor : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
+                MessageBox.ErrorQuery (Application.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
             }
 
             _tableView.Update ();
@@ -388,7 +388,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }
@@ -413,7 +413,7 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error moving column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "Error moving column", ex.Message, "Ok");
         }
     }
 
@@ -426,7 +426,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedRow == -1)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Rows", "No row selected", "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "No Rows", "No row selected", "Ok");
 
             return;
         }
@@ -462,7 +462,7 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error moving column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "Error moving column", ex.Message, "Ok");
         }
     }
 
@@ -470,7 +470,7 @@ public class CsvEditor : Scenario
     {
         if (_tableView?.Table is null)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Table Loaded", "No table has currently be opened", "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "No Table Loaded", "No table has currently be opened", "Ok");
 
             return true;
         }
@@ -582,7 +582,7 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance,
+            MessageBox.ErrorQuery (Application.Instance,
                                    "Open Failed",
                                    $"Error on line {lineNumber}{Environment.NewLine}{ex.Message}",
                                    "Ok"
@@ -612,7 +612,7 @@ public class CsvEditor : Scenario
     {
         if (_tableView?.Table is null || string.IsNullOrWhiteSpace (_currentFile) || _currentTable is null)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No file loaded", "No file is currently loaded", "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "No file loaded", "No file is currently loaded", "Ok");
 
             return;
         }
@@ -674,7 +674,7 @@ public class CsvEditor : Scenario
 
         if (col.DataType == typeof (string))
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance,
+            MessageBox.ErrorQuery (Application.Instance,
                                    "Cannot Format Column",
                                    "String columns cannot be Formatted, try adding a new column to the table with a date/numerical Type",
                                    "Ok"
@@ -711,7 +711,7 @@ public class CsvEditor : Scenario
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }

+ 2 - 2
Examples/UICatalog/Scenarios/DynamicStatusBar.cs

@@ -79,7 +79,7 @@ public class DynamicStatusBar : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (ApplicationImpl.Instance, "Binding Error", $"Binding failed: {ex}.", "Ok");
+                MessageBox.ErrorQuery (Application.Instance, "Binding Error", $"Binding failed: {ex}.", "Ok");
             }
         }
     }
@@ -140,7 +140,7 @@ public class DynamicStatusBar : Scenario
         public TextView TextAction { get; }
         public TextField TextShortcut { get; }
         public TextField TextTitle { get; }
-        public Action CreateAction (DynamicStatusItem item) { return () => MessageBox.ErrorQuery (ApplicationImpl.Instance, item.Title, item.Action, "Ok"); }
+        public Action CreateAction (DynamicStatusItem item) { return () => MessageBox.ErrorQuery (Application.Instance, item.Title, item.Action, "Ok"); }
 
         public void EditStatusItem (Shortcut statusItem)
         {

+ 9 - 9
Examples/UICatalog/Scenarios/Editor.cs

@@ -201,7 +201,7 @@ public class Editor : Scenario
         Debug.Assert (_textView.IsDirty);
 
         int? r = MessageBox.ErrorQuery (
-                                       ApplicationImpl.Instance,
+                                       Application.Instance,
                                        "Save File",
                                        $"Do you want save changes in {_appWindow.Title}?",
                                        "Yes",
@@ -236,7 +236,7 @@ public class Editor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.Message, "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "Error", ex.Message, "Ok");
         }
     }
 
@@ -315,11 +315,11 @@ public class Editor : Scenario
 
         if (!found)
         {
-            MessageBox.Query (ApplicationImpl.Instance, "Find", $"The following specified text was not found: '{_textToFind}'", "Ok");
+            MessageBox.Query (Application.Instance, "Find", $"The following specified text was not found: '{_textToFind}'", "Ok");
         }
         else if (gaveFullTurn)
         {
-            MessageBox.Query (ApplicationImpl.Instance,
+            MessageBox.Query (Application.Instance,
                               "Find",
                               $"No more occurrences were found for the following specified text: '{_textToFind}'",
                               "Ok"
@@ -895,7 +895,7 @@ public class Editor : Scenario
 
         if (_textView.ReplaceAllText (_textToFind, _matchCase, _matchWholeWord, _textToReplace))
         {
-            MessageBox.Query (ApplicationImpl.Instance,
+            MessageBox.Query (Application.Instance,
                               "Replace All",
                               $"All occurrences were replaced for the following specified text: '{_textToReplace}'",
                               "Ok"
@@ -903,7 +903,7 @@ public class Editor : Scenario
         }
         else
         {
-            MessageBox.Query (ApplicationImpl.Instance,
+            MessageBox.Query (Application.Instance,
                               "Replace All",
                               $"None of the following specified text was found: '{_textToFind}'",
                               "Ok"
@@ -1155,7 +1155,7 @@ public class Editor : Scenario
         {
             if (File.Exists (path))
             {
-                if (MessageBox.Query (ApplicationImpl.Instance,
+                if (MessageBox.Query (Application.Instance,
                                       "Save File",
                                       "File already exists. Overwrite any way?",
                                       "No",
@@ -1194,11 +1194,11 @@ public class Editor : Scenario
             _originalText = Encoding.Unicode.GetBytes (_textView.Text);
             _saved = true;
             _textView.ClearHistoryChanges ();
-            MessageBox.Query (ApplicationImpl.Instance, "Save File", "File was successfully saved.", "Ok");
+            MessageBox.Query (Application.Instance, "Save File", "File was successfully saved.", "Ok");
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.Message, "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "Error", ex.Message, "Ok");
 
             return false;
         }

+ 5 - 5
Examples/UICatalog/Scenarios/FileDialogExamples.cs

@@ -133,7 +133,7 @@ public class FileDialogExamples : Scenario
                              }
                              catch (Exception ex)
                              {
-                                 MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.ToString (), "_Ok");
+                                 MessageBox.ErrorQuery (Application.Instance, "Error", ex.ToString (), "_Ok");
                              }
                              finally
                              {
@@ -153,7 +153,7 @@ public class FileDialogExamples : Scenario
         {
             if (File.Exists (e.Dialog.Path))
             {
-                int? result = MessageBox.Query (ApplicationImpl.Instance, "Overwrite?", "File already exists", "_Yes", "_No");
+                int? result = MessageBox.Query (Application.Instance, "Overwrite?", "File already exists", "_Yes", "_No");
                 e.Cancel = result == 1;
             }
         }
@@ -248,7 +248,7 @@ public class FileDialogExamples : Scenario
 
             if (canceled)
             {
-                MessageBox.Query (ApplicationImpl.Instance,
+                MessageBox.Query (Application.Instance,
                                   "Canceled",
                                   "You canceled navigation and did not pick anything",
                                   "Ok"
@@ -256,7 +256,7 @@ public class FileDialogExamples : Scenario
             }
             else if (_cbAllowMultipleSelection.CheckedState == CheckState.Checked)
             {
-                MessageBox.Query (ApplicationImpl.Instance,
+                MessageBox.Query (Application.Instance,
                                   "Chosen!",
                                   "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, multiSelected.Select (m => m)),
                                   "Ok"
@@ -264,7 +264,7 @@ public class FileDialogExamples : Scenario
             }
             else
             {
-                MessageBox.Query (ApplicationImpl.Instance,
+                MessageBox.Query (Application.Instance,
                                   "Chosen!",
                                   "You chose:" + Environment.NewLine + path,
                                   "Ok"

+ 1 - 1
Examples/UICatalog/Scenarios/Generic.cs

@@ -29,7 +29,7 @@ public sealed class Generic : Scenario
                             {
                                 // When Accepting is handled, set e.Handled to true to prevent further processing.
                                 e.Handled = true;
-                                MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", "You pressed the button!", "_Ok");
+                                MessageBox.ErrorQuery (Application.Instance, "Error", "You pressed the button!", "_Ok");
                             };
 
         appWindow.Add (button);

+ 4 - 4
Examples/UICatalog/Scenarios/HexEditor.cs

@@ -181,7 +181,7 @@ public class HexEditor : Scenario
         }
     }
 
-    private void Copy () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
+    private void Copy () { MessageBox.ErrorQuery (Application.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
 
     private void CreateDemoFile (string fileName)
     {
@@ -208,7 +208,7 @@ public class HexEditor : Scenario
         ms.Close ();
     }
 
-    private void Cut () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
+    private void Cut () { MessageBox.ErrorQuery (Application.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
 
     private Stream LoadFile ()
     {
@@ -216,7 +216,7 @@ public class HexEditor : Scenario
 
         if (!_saved && _hexView!.Edits.Count > 0 && _hexView.Source is {})
         {
-            if (MessageBox.ErrorQuery (ApplicationImpl.Instance,
+            if (MessageBox.ErrorQuery (Application.Instance,
                                        "Save",
                                        "The changes were not saved. Want to open without saving?",
                                        "_Yes",
@@ -267,7 +267,7 @@ public class HexEditor : Scenario
         d.Dispose ();
     }
 
-    private void Paste () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "_Ok"); }
+    private void Paste () { MessageBox.ErrorQuery (Application.Instance, "Not Implemented", "Functionality not yet implemented.", "_Ok"); }
     private void Quit () { Application.RequestStop (); }
 
     private void Save ()

+ 20 - 19
Examples/UICatalog/Scenarios/Images.cs

@@ -122,11 +122,11 @@ public class Images : Scenario
         {
             X = Pos.Right (cbSupportsTrueColor) + 2,
             Y = 0,
-            CheckedState = !Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
+            CheckedState = !Driver.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
             Enabled = canTrueColor,
             Text = "Use true color"
         };
-        cbUseTrueColor.CheckedStateChanging += (_, evt) => Application.Force16Colors = evt.Result == CheckState.UnChecked;
+        cbUseTrueColor.CheckedStateChanging += (_, evt) => Driver.Force16Colors = evt.Result == CheckState.UnChecked;
         _win.Add (cbUseTrueColor);
 
         var btnOpenImage = new Button { X = Pos.Right (cbUseTrueColor) + 2, Y = 0, Text = "Open Image" };
@@ -183,7 +183,7 @@ public class Images : Scenario
 
         if (!_sixelSupportResult.SupportsTransparency)
         {
-            if (MessageBox.Query (ApplicationImpl.Instance,
+            if (MessageBox.Query (Application.Instance,
                                   "Transparency Not Supported",
                                   "It looks like your terminal does not support transparent sixel backgrounds. Do you want to try anyway?",
                                   "Yes",
@@ -219,18 +219,21 @@ public class Images : Scenario
         Color [,] bmp = _fire.GetFirePixels ();
 
         // TODO: Static way of doing this, suboptimal
-        if (_fireSixel != null)
+        // ConcurrentQueue doesn't support Remove, so we update the existing object
+        if (_fireSixel == null)
         {
-            Application.Sixel.Remove (_fireSixel);
+            _fireSixel = new ()
+            {
+                SixelData = _fireEncoder.EncodeSixel (bmp),
+                ScreenPosition = new (0, 0)
+            };
+            Application.GetSixels ().Enqueue (_fireSixel);
         }
-
-        _fireSixel = new ()
+        else
         {
-            SixelData = _fireEncoder.EncodeSixel (bmp),
-            ScreenPosition = new (0, 0)
-        };
-
-        Application.Sixel.Add (_fireSixel);
+            _fireSixel.SixelData = _fireEncoder.EncodeSixel (bmp);
+            _fireSixel.ScreenPosition = new (0, 0);
+        }
 
         _win.SetNeedsDraw ();
 
@@ -245,8 +248,6 @@ public class Images : Scenario
         _sixelNotSupported.Dispose ();
         _sixelSupported.Dispose ();
         _isDisposed = true;
-
-        Application.Sixel.Clear ();
     }
 
     private void OpenImage (object sender, CommandEventArgs e)
@@ -288,7 +289,7 @@ public class Images : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Could not open file", ex.Message, "Ok");
+            MessageBox.ErrorQuery (Application.Instance, "Could not open file", ex.Message, "Ok");
 
             return;
         }
@@ -492,7 +493,7 @@ public class Images : Scenario
     {
         if (_imageView.FullResImage == null)
         {
-            MessageBox.Query (ApplicationImpl.Instance, "No Image Loaded", "You must first open an image.  Use the 'Open Image' button above.", "Ok");
+            MessageBox.Query (Application.Instance, "No Image Loaded", "You must first open an image.  Use the 'Open Image' button above.", "Ok");
 
             return;
         }
@@ -513,7 +514,7 @@ public class Images : Scenario
                 ScreenPosition = _screenLocationForSixel
             };
 
-            Application.Sixel.Add (_sixelImage);
+            Application.GetSixels ().Enqueue (_sixelImage);
         }
         else
         {
@@ -631,7 +632,7 @@ public class Images : Scenario
         public Image<Rgba32> FullResImage;
         private Image<Rgba32> _matchSize;
 
-        protected override bool OnDrawingContent ()
+        protected override bool OnDrawingContent (DrawContext context)
         {
             if (FullResImage == null)
             {
@@ -708,7 +709,7 @@ public class Images : Scenario
             return (columns, rows);
         }
 
-        protected override bool OnDrawingContent ()
+        protected override bool OnDrawingContent (DrawContext context)
         {
             if (_palette == null || _palette.Count == 0)
             {

+ 1 - 1
Examples/UICatalog/Scenarios/InteractiveTree.cs

@@ -173,7 +173,7 @@ public class InteractiveTree : Scenario
 
                 if (parent is null)
                 {
-                    MessageBox.ErrorQuery (ApplicationImpl.Instance,
+                    MessageBox.ErrorQuery (Application.Instance,
                                            "Could not delete",
                                            $"Parent of '{toDelete}' was unexpectedly null",
                                            "Ok"

+ 4 - 4
Examples/UICatalog/Scenarios/KeyBindings.cs

@@ -164,17 +164,17 @@ public class KeyBindingsDemo : View
 
         AddCommand (Command.Save, ctx =>
                                  {
-                                     MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
+                                     MessageBox.Query (Application.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                      return true;
                                  });
         AddCommand (Command.New, ctx =>
                                 {
-                                    MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
+                                    MessageBox.Query (Application.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                     return true;
                                 });
         AddCommand (Command.HotKey, ctx =>
         {
-            MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
+            MessageBox.Query (Application.Instance, $"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
             SetFocus ();
             return true;
         });
@@ -189,7 +189,7 @@ public class KeyBindingsDemo : View
                                              {
                                                  return false;
                                              }
-                                             MessageBox.Query (ApplicationImpl.Instance, $"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
+                                             MessageBox.Query (Application.Instance, $"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
                                              Application.RequestStop ();
                                              return true;
                                          });

+ 7 - 10
Examples/UICatalog/Scenarios/LineDrawing.cs

@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Text;
 
 namespace UICatalog.Scenarios;
 
@@ -136,14 +133,14 @@ public class LineDrawing : Scenario
         var d = new Dialog
         {
             Title = title,
-            Width = Application.Force16Colors ? 35 : Dim.Auto (DimAutoStyle.Auto, Dim.Percent (80), Dim.Percent (90)),
+            Width = Driver.Force16Colors ? 35 : Dim.Auto (DimAutoStyle.Auto, Dim.Percent (80), Dim.Percent (90)),
             Height = 10
         };
 
         var btnOk = new Button
         {
             X = Pos.Center () - 5,
-            Y = Application.Force16Colors ? 6 : 4,
+            Y = Driver.Force16Colors ? 6 : 4,
             Text = "Ok",
             Width = Dim.Auto (),
             IsDefault = true
@@ -177,7 +174,7 @@ public class LineDrawing : Scenario
         d.AddButton (btnCancel);
 
         View cp;
-        if (Application.Force16Colors)
+        if (Driver.Force16Colors)
         {
             cp = new ColorPicker16
             {
@@ -200,7 +197,7 @@ public class LineDrawing : Scenario
 
         Application.Run (d);
         d.Dispose ();
-        newColor = Application.Force16Colors ? ((ColorPicker16)cp).SelectedColor : ((ColorPicker)cp).SelectedColor;
+        newColor = Driver.Force16Colors ? ((ColorPicker16)cp).SelectedColor : ((ColorPicker)cp).SelectedColor;
 
         return accept;
     }
@@ -273,7 +270,7 @@ public class DrawingArea : View
     public ITool CurrentTool { get; set; } = new DrawLineTool ();
     public DrawingArea () { AddLayer (); }
 
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext context)
     {
         foreach (LineCanvas canvas in Layers)
         {
@@ -380,7 +377,7 @@ public class AttributeView : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext context)
     {
         Color fg = Value.Foreground;
         Color bg = Value.Background;

+ 1 - 1
Examples/UICatalog/Scenarios/ListColumns.cs

@@ -336,7 +336,7 @@ public class ListColumns : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set", ex.Message, "Ok");
+                MessageBox.ErrorQuery (Application.Instance, 60, 20, "Failed to set", ex.Message, "Ok");
             }
         }
     }

+ 14 - 2
Examples/UICatalog/Scenarios/Menus.cs

@@ -253,7 +253,13 @@ public class Menus : Scenario
 
             // The source of truth is our status CB; any time it changes, update the menu item
             var enableOverwriteMenuItemCb = menuBar.GetMenuItemsWithTitle ("Overwrite").FirstOrDefault ()?.CommandView as CheckBox;
-            enableOverwriteStatusCb.CheckedStateChanged += (_, _) => enableOverwriteMenuItemCb!.CheckedState = enableOverwriteStatusCb.CheckedState;
+            enableOverwriteStatusCb.CheckedStateChanged += (_, _) =>
+                                                           {
+                                                               if (enableOverwriteMenuItemCb is { })
+                                                               {
+                                                                   enableOverwriteMenuItemCb.CheckedState = enableOverwriteStatusCb.CheckedState;
+                                                               }
+                                                           };
 
             menuBar.Accepted += (o, args) =>
                                 {
@@ -298,7 +304,13 @@ public class Menus : Scenario
 
             // The source of truth is our status CB; any time it changes, update the menu item
             var editModeMenuItemCb = menuBar.GetMenuItemsWithTitle ("EditMode").FirstOrDefault ()?.CommandView as CheckBox;
-            editModeStatusCb.CheckedStateChanged += (_, _) => editModeMenuItemCb!.CheckedState = editModeStatusCb.CheckedState;
+            editModeStatusCb.CheckedStateChanged += (_, _) =>
+                                                       {
+                                                           if (editModeMenuItemCb is { })
+                                                           {
+                                                               editModeMenuItemCb.CheckedState = editModeStatusCb.CheckedState;
+                                                           }
+                                                       };
 
             menuBar.Accepted += (o, args) =>
                                 {

+ 2 - 2
Examples/UICatalog/Scenarios/MessageBoxes.cs

@@ -251,7 +251,7 @@ public class MessageBoxes : Scenario
                                                {
                                                    buttonPressedLabel.Text =
                                                        $"{MessageBox.Query (
-                                                                            ApplicationImpl.Instance, width,
+                                                                            Application.Instance, width,
                                                                              height,
                                                                              titleEdit.Text,
                                                                              messageEdit.Text,
@@ -263,7 +263,7 @@ public class MessageBoxes : Scenario
                                                else
                                                {
                                                    buttonPressedLabel.Text =
-                                                       $"{MessageBox.ErrorQuery (ApplicationImpl.Instance,
+                                                       $"{MessageBox.ErrorQuery (Application.Instance,
                                                                                  width,
                                                                                  height,
                                                                                  titleEdit.Text,

+ 1 - 1
Examples/UICatalog/Scenarios/MultiColouredTable.cs

@@ -99,7 +99,7 @@ public class MultiColouredTable : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
+                MessageBox.ErrorQuery (Application.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
             }
 
             _tableView.Update ();

+ 1 - 1
Examples/UICatalog/Scenarios/Navigation.cs

@@ -59,7 +59,7 @@ public class Navigation : Scenario
             Y = 0,
             Title = $"TopButton _{GetNextHotKey ()}"
         };
-        button.Accepting += (sender, args) => MessageBox.Query (ApplicationImpl.Instance, "hi", button.Title, "_Ok");
+        button.Accepting += (sender, args) => MessageBox.Query (Application.Instance, "hi", button.Title, "_Ok");
 
         testFrame.Add (button);
 

+ 2 - 2
Examples/UICatalog/Scenarios/Notepad.cs

@@ -71,7 +71,7 @@ public class Notepad : Scenario
                                        new MenuItem
                                        {
                                            Title = "_About",
-                                           Action = () => MessageBox.Query (ApplicationImpl.Instance,  "Notepad", "About Notepad...", "Ok")
+                                           Action = () => MessageBox.Query (Application.Instance,  "Notepad", "About Notepad...", "Ok")
                                        }
                                    ]
                                   )
@@ -196,7 +196,7 @@ public class Notepad : Scenario
 
         if (tab.UnsavedChanges)
         {
-            int? result = MessageBox.Query (ApplicationImpl.Instance,
+            int? result = MessageBox.Query (Application.Instance,
                                             "Save Changes",
                                             $"Save changes to {tab.Text.TrimEnd ('*')}",
                                             "Yes",

+ 1 - 1
Examples/UICatalog/Scenarios/RegionScenario.cs

@@ -268,7 +268,7 @@ public class AttributeView : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         Color fg = Value?.Foreground ?? Color.Black;
         Color bg = Value?.Background ?? Color.Black;

+ 3 - 3
Examples/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs

@@ -166,7 +166,7 @@ public class RuneWidthGreaterThanOne : Scenario
     {
         if (_text is { })
         {
-            MessageBox.Query (ApplicationImpl.Instance, "Say Hello 你", $"Hello {_text.Text}", "Ok");
+            MessageBox.Query (Application.Instance, "Say Hello 你", $"Hello {_text.Text}", "Ok");
         }
     }
 
@@ -197,7 +197,7 @@ public class RuneWidthGreaterThanOne : Scenario
     {
         if (_text is { })
         {
-            MessageBox.Query (ApplicationImpl.Instance, "Say Hello", $"Hello {_text.Text}", "Ok");
+            MessageBox.Query (Application.Instance, "Say Hello", $"Hello {_text.Text}", "Ok");
         }
     }
 
@@ -252,7 +252,7 @@ public class RuneWidthGreaterThanOne : Scenario
     {
         if (_text is { })
         {
-            MessageBox.Query (ApplicationImpl.Instance, "こんにちはと言う", $"こんにちは {_text.Text}", "Ok");
+            MessageBox.Query (Application.Instance, "こんにちはと言う", $"こんにちは {_text.Text}", "Ok");
         }
     }
 

+ 1 - 1
Examples/UICatalog/Scenarios/Snake.cs

@@ -322,7 +322,7 @@ public class Snake : Scenario
 
         private SnakeState State { get; }
 
-        protected override bool OnDrawingContent ()
+        protected override bool OnDrawingContent (DrawContext context)
         {
             SetAttribute (white);
             ClearViewport ();

+ 1 - 1
Examples/UICatalog/Scenarios/TextEffectsScenario.cs

@@ -109,7 +109,7 @@ internal class GradientsView : View
     private const int LABEL_HEIGHT = 1;
     private const int GRADIENT_WITH_LABEL_HEIGHT = GRADIENT_HEIGHT + LABEL_HEIGHT + 1; // +1 for spacing
 
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext context)
     {
         DrawTopLineGradient (Viewport);
 

+ 102 - 24
Examples/UICatalog/Scenarios/Transparent.cs

@@ -1,8 +1,9 @@
+// ReSharper disable AccessToDisposedClosure
 #nullable enable
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Transparent", "Testing Transparency")]
+[ScenarioMetadata ("Transparent", "Demonstrates View Transparency")]
 public sealed class Transparent : Scenario
 {
     public override void Main ()
@@ -53,11 +54,19 @@ public sealed class Transparent : Scenario
 
         var tv = new TransparentView ()
         {
-            X = 3,
-            Y = 3,
-            Width = 50,
-            Height = 15
+            X = 2,
+            Y = 2,
+            Width = Dim.Fill (10),
+            Height = Dim.Fill (10)
         };
+
+        appWindow.ViewportChanged += (sender, args) =>
+                                      {
+                                          // Little hack to convert the Dim.Fill to actual size
+                                          // So resizing works
+                                          tv.Width = appWindow!.Frame.Width - 10;
+                                          tv.Height = appWindow!.Frame.Height - 10;
+                                      };
         appWindow.Add (tv);
 
         // Run - Start the application.
@@ -72,34 +81,31 @@ public sealed class Transparent : Scenario
     {
         public TransparentView ()
         {
-            Title = "Transparent View";
-            //base.Text = "View.Text.\nThis should be opaque.\nNote how clipping works?";
-            TextFormatter.Alignment = Alignment.Center;
-            TextFormatter.VerticalAlignment = Alignment.Center;
+            Title = "Transparent View - Move and Resize To See Transparency In Action";
+            base.Text = "View.Text.\nThis should be opaque. Note how clipping works?";
             Arrangement = ViewArrangement.Overlapped | ViewArrangement.Resizable | ViewArrangement.Movable;
-            ViewportSettings |= Terminal.Gui.ViewBase.ViewportSettingsFlags.Transparent | Terminal.Gui.ViewBase.ViewportSettingsFlags.TransparentMouse;
+            ViewportSettings |= ViewportSettingsFlags.Transparent | ViewportSettingsFlags.TransparentMouse;
             BorderStyle = LineStyle.RoundedDotted;
-            //SchemeName = "Base";
+            SchemeName = "Base";
 
             var transparentSubView = new View ()
             {
-                Text = "Sizable/Movable View with border. Should be opaque. No Shadow.",
+                Text = "Sizable/Movable SubView with border and shadow.",
                 Id = "transparentSubView",
-                X = 4,
-                Y = 8,
+                X = Pos.Center (),
+                Y = Pos.Center (),
                 Width = 20,
                 Height = 8,
                 BorderStyle = LineStyle.Dashed,
                 Arrangement = ViewArrangement.Movable | ViewArrangement.Resizable,
-                // ShadowStyle = ShadowStyle.Transparent,
+                ShadowStyle = ShadowStyle.Transparent,
             };
             transparentSubView.Border!.Thickness = new (1, 1, 1, 1);
             transparentSubView.SchemeName = "Dialog";
-            //transparentSubView.Visible = false;
 
             Button button = new Button ()
             {
-                Title = "_Opaque Shadows No Worky",
+                Title = "_Opaque Shadow",
                 X = Pos.Center (),
                 Y = 2,
                 SchemeName = "Dialog",
@@ -109,8 +115,6 @@ public sealed class Transparent : Scenario
                                     MessageBox.Query (App, "Clicked!", "Button in Transparent View", "_Ok");
                                     args.Handled = true;
                                 };
-            //button.Visible = false;
-
 
             var shortcut = new Shortcut ()
             {
@@ -121,7 +125,6 @@ public sealed class Transparent : Scenario
                 HelpText = "Help!",
                 Key = Key.F11,
                 SchemeName = "Base"
-
             };
 
             button.ClearingViewport += (sender, args) =>
@@ -129,16 +132,91 @@ public sealed class Transparent : Scenario
                                            args.Cancel = true;
                                        };
 
+            // Subscribe to DrawingContent event to draw "TUI" 
+            DrawingContent += TransparentView_DrawingContent;
 
             base.Add (button);
             base.Add (shortcut);
             base.Add (transparentSubView);
 
-            //Padding.Thickness = new (1);
-            //Padding.SchemeName = "Error";
+            Padding!.Thickness = new (1);
+            Padding.Text = "This is the Padding";
+        }
+
+        private void TransparentView_DrawingContent (object? sender, DrawEventArgs e)
+        {
+            // Draw "TUI" text using rectangular regions, positioned after "Hi"
+            // Letter "T"
+            Rectangle tTop = new (20, 5, 7, 2);      // Top horizontal bar
+            Rectangle tStem = new (23, 7, 2, 8);     // Vertical stem
+
+            // Letter "U"
+            Rectangle uLeft = new (30, 5, 2, 8);     // Left vertical bar
+            Rectangle uBottom = new (32, 13, 3, 2);  // Bottom horizontal bar
+            Rectangle uRight = new (35, 5, 2, 8);    // Right vertical bar
+
+            // Letter "I"
+            Rectangle iTop = new (39, 5, 4, 2);      // Bar on top
+            Rectangle iStem = new (40, 7, 2, 6);     // Vertical stem
+            Rectangle iBottom = new (39, 13, 4, 2);      // Bar on Bottom
+
+            // Draw "TUI" using the HotActive attribute
+            SetAttributeForRole (VisualRole.HotActive);
+            FillRect (tTop, Glyphs.BlackCircle);
+            FillRect (tStem, Glyphs.BlackCircle);
+            FillRect (uLeft, Glyphs.BlackCircle);
+            FillRect (uBottom, Glyphs.BlackCircle);
+            FillRect (uRight, Glyphs.BlackCircle);
+            FillRect (iTop, Glyphs.BlackCircle);
+            FillRect (iStem, Glyphs.BlackCircle);
+            FillRect (iBottom, Glyphs.BlackCircle);
+
+            Region tuiRegion = new Region (ViewportToScreen (tTop));
+            tuiRegion.Union (ViewportToScreen (tStem));
+            tuiRegion.Union (ViewportToScreen (uLeft));
+            tuiRegion.Union (ViewportToScreen (uBottom));
+            tuiRegion.Union (ViewportToScreen (uRight));
+            tuiRegion.Union (ViewportToScreen (iTop));
+            tuiRegion.Union (ViewportToScreen (iStem));
+            tuiRegion.Union (ViewportToScreen (iBottom));
+
+            // Register the drawn region for "TUI" to enable transparency effects
+            e.DrawContext?.AddDrawnRegion (tuiRegion);
+        }
 
-            Margin!.Thickness = new (1);
-           // Margin.ViewportSettings |= Terminal.Gui.ViewportSettingsFlags.Transparent;
+        /// <inheritdoc />
+        protected override bool OnDrawingContent (DrawContext? context)
+        {
+            base.OnDrawingContent (context);
+
+            // Draw "Hi" text using rectangular regions
+            // Letter "H"
+            Rectangle hLeft = new (5, 5, 2, 10);      // Left vertical bar
+            Rectangle hMiddle = new (7, 9, 3, 2);     // Middle horizontal bar
+            Rectangle hRight = new (10, 5, 2, 10);    // Right vertical bar
+
+            // Letter "i" (with some space between H and i)
+            Rectangle iDot = new (15, 5, 2, 2);       // Dot on top
+            Rectangle iStem = new (15, 9, 2, 6);      // Vertical stem
+
+            // Draw "Hi" using the Highlight attribute
+            SetAttributeForRole (VisualRole.Highlight);
+            FillRect (hLeft, Glyphs.BlackCircle);
+            FillRect (hMiddle, Glyphs.BlackCircle);
+            FillRect (hRight, Glyphs.BlackCircle);
+            FillRect (iDot, Glyphs.BlackCircle);
+            FillRect (iStem, Glyphs.BlackCircle);
+
+            // Register the drawn region for "Hi" to enable transparency effects
+            Region hiRegion = new Region (ViewportToScreen (hLeft));
+            hiRegion.Union (ViewportToScreen (hMiddle));
+            hiRegion.Union (ViewportToScreen (hRight));
+            hiRegion.Union (ViewportToScreen (iDot));
+            hiRegion.Union (ViewportToScreen (iStem));
+            context?.AddDrawnRegion (hiRegion);
+
+            // Return false to allow DrawingContent event to fire
+            return false;
         }
 
         /// <inheritdoc />

+ 1 - 1
Examples/UICatalog/Scenarios/WindowsAndFrameViews.cs

@@ -18,7 +18,7 @@ public class WindowsAndFrameViews : Scenario
 
         static int? About ()
         {
-            return MessageBox.Query (ApplicationImpl.Instance,
+            return MessageBox.Query (Application.Instance,
                                      "About UI Catalog",
                                      "UI Catalog is a comprehensive sample library for Terminal.Gui",
                                      "Ok"

+ 3 - 3
Examples/UICatalog/Scenarios/WizardAsView.cs

@@ -21,7 +21,7 @@ public class WizardAsView : Scenario
                                        {
                                            Title = "_Restart Configuration...",
                                            Action = () => MessageBox.Query (
-                                                                            ApplicationImpl.Instance,
+                                                                            Application.Instance,
                                                                             "Wizard",
                                                                             "Are you sure you want to reset the Wizard and start over?",
                                                                             "Ok",
@@ -32,7 +32,7 @@ public class WizardAsView : Scenario
                                        {
                                            Title = "Re_boot Server...",
                                            Action = () => MessageBox.Query (
-                                                                            ApplicationImpl.Instance,
+                                                                            Application.Instance,
                                                                             "Wizard",
                                                                             "Are you sure you want to reboot the server start over?",
                                                                             "Ok",
@@ -43,7 +43,7 @@ public class WizardAsView : Scenario
                                        {
                                            Title = "_Shutdown Server...",
                                            Action = () => MessageBox.Query (
-                                                                            ApplicationImpl.Instance,
+                                                                            Application.Instance,
                                                                             "Wizard",
                                                                             "Are you sure you want to cancel setup and shutdown?",
                                                                             "Ok",

+ 9 - 5
Examples/UICatalog/UICatalog.cs

@@ -196,7 +196,7 @@ public class UICatalog
 
         UICatalogMain (Options);
 
-        Debug.Assert (Application.ForceDriver == string.Empty);
+        Application.ForceDriver = string.Empty;
 
         return 0;
     }
@@ -433,8 +433,10 @@ public class UICatalog
 
             // This call to Application.Shutdown brackets the Application.Init call
             // made by Scenario.Init() above
-            // TODO: Throw if shutdown was not called already
-            Application.Shutdown ();
+            if (Application.Driver is { })
+            {
+                Application.Shutdown ();
+            }
 
             VerifyObjectsWereDisposed ();
 
@@ -482,8 +484,10 @@ public class UICatalog
 
         scenario.Dispose ();
 
-        // TODO: Throw if shutdown was not called already
-        Application.Shutdown ();
+        if (Application.Driver is { })
+        {
+            Application.Shutdown ();
+        }
 
         return results;
     }

+ 52 - 46
Examples/UICatalog/UICatalogRunnable.cs

@@ -43,9 +43,12 @@ public class UICatalogRunnable : Runnable
         IsRunningChanged += IsRunningChangedHandler;
 
         // Restore previous selections
-        if (_categoryList.Source?.Count > 0) {
+        if (_categoryList.Source?.Count > 0)
+        {
             _categoryList.SelectedItem = _cachedCategoryIndex ?? 0;
-        } else {
+        }
+        else
+        {
             _categoryList.SelectedItem = null;
         }
         _scenarioList.SelectedRow = _cachedScenarioIndex;
@@ -176,7 +179,7 @@ public class UICatalogRunnable : Runnable
             _force16ColorsMenuItemCb = new ()
             {
                 Title = "Force _16 Colors",
-                CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
+                CheckedState = Application.Driver!.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
                 // Best practice for CheckBoxes in menus is to disable focus and highlight states
                 CanFocus = false,
                 HighlightStates = MouseState.None
@@ -184,7 +187,7 @@ public class UICatalogRunnable : Runnable
 
             _force16ColorsMenuItemCb.CheckedStateChanging += (sender, args) =>
                                                              {
-                                                                 if (Application.Force16Colors
+                                                                 if (Application.Driver!.Force16Colors
                                                                      && args.Result == CheckState.UnChecked
                                                                      && !Application.Driver!.SupportsTrueColor)
                                                                  {
@@ -194,10 +197,10 @@ public class UICatalogRunnable : Runnable
 
             _force16ColorsMenuItemCb.CheckedStateChanged += (sender, args) =>
                                                             {
-                                                                Application.Force16Colors = args.Value == CheckState.Checked;
+                                                                Application.Driver!.Force16Colors = args.Value == CheckState.Checked;
 
                                                                 _force16ColorsShortcutCb!.CheckedState = args.Value;
-                                                                Application.LayoutAndDraw ();
+                                                                SetNeedsDraw ();
                                                             };
 
             menuItems.Add (
@@ -295,18 +298,25 @@ public class UICatalogRunnable : Runnable
             _diagnosticFlagsSelector.UsedHotKeys.Add (Key.D);
             _diagnosticFlagsSelector.AssignHotKeys = true;
             _diagnosticFlagsSelector.Value = Diagnostics;
-            _diagnosticFlagsSelector.ValueChanged += (sender, args) =>
-                                                     {
-                                                         _diagnosticFlags = (ViewDiagnosticFlags)_diagnosticFlagsSelector.Value;
-                                                         Diagnostics = _diagnosticFlags;
-                                                     };
+            _diagnosticFlagsSelector.Selecting += (sender, args) =>
+                                                  {
+                                                      _diagnosticFlags = (ViewDiagnosticFlags)((int)args.Context!.Source!.Data!);// (ViewDiagnosticFlags)_diagnosticFlagsSelector.Value;
+                                                      Diagnostics = _diagnosticFlags;
+                                                  };
 
-            menuItems.Add (
-                           new MenuItem
-                           {
-                               CommandView = _diagnosticFlagsSelector,
-                               HelpText = "View Diagnostics"
-                           });
+            MenuItem diagFlagMenuItem = new MenuItem ()
+            {
+                CommandView = _diagnosticFlagsSelector,
+                HelpText = "View Diagnostics"
+            };
+            diagFlagMenuItem.Accepting += (sender, args) =>
+                                         {
+                                             //_diagnosticFlags = (ViewDiagnosticFlags)_diagnosticFlagsSelector.Value;
+                                             //Diagnostics = _diagnosticFlags;
+                                             //args.Handled = true;
+                                         };
+
+            menuItems.Add (diagFlagMenuItem);
 
             menuItems.Add (new Line ());
 
@@ -319,8 +329,13 @@ public class UICatalogRunnable : Runnable
                 HighlightStates = MouseState.None
             };
 
-            _disableMouseCb.CheckedStateChanged += (_, args) => { Application.IsMouseDisabled = args.Value == CheckState.Checked; };
+            //_disableMouseCb.CheckedStateChanged += (_, args) => { Application.IsMouseDisabled = args.Value == CheckState.Checked; };
+            _disableMouseCb.Selecting += (sender, args) =>
+                                         {
+                                             Application.IsMouseDisabled = !Application.IsMouseDisabled;
+                                             _disableMouseCb.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.None;
 
+                                         };
             menuItems.Add (
                            new MenuItem
                            {
@@ -639,39 +654,30 @@ public class UICatalogRunnable : Runnable
         _force16ColorsShortcutCb = new ()
         {
             Title = "16 color mode",
-            CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
-            CanFocus = false
+            CheckedState = Application.Driver!.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
+            CanFocus = true
         };
 
-        _force16ColorsShortcutCb.CheckedStateChanging += (sender, args) =>
-                                                         {
-                                                             if (Application.Force16Colors
-                                                                 && args.Result == CheckState.UnChecked
-                                                                 && !Application.Driver!.SupportsTrueColor)
-                                                             {
-                                                                 // If the driver does not support TrueColor, we cannot disable 16 colors
-                                                                 args.Handled = true;
-                                                             }
-                                                         };
-
-        _force16ColorsShortcutCb.CheckedStateChanged += (sender, args) =>
-                                                         {
-                                                             Application.Force16Colors = args.Value == CheckState.Checked;
-                                                             _force16ColorsMenuItemCb!.CheckedState = args.Value;
-                                                             Application.LayoutAndDraw ();
-                                                         };
+        Shortcut force16ColorsShortcut = new ()
+        {
+            CanFocus = false,
+            CommandView = _force16ColorsShortcutCb,
+            HelpText = "",
+            BindKeyToApplication = true,
+            Key = Key.F7
+        };
 
+        force16ColorsShortcut.Accepting += (sender, args) =>
+                                           {
+                                               Application.Driver.Force16Colors = !Application.Driver.Force16Colors;
+                                               _force16ColorsMenuItemCb!.CheckedState = Application.Driver.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
+                                               SetNeedsDraw ();
+                                               args.Handled = true;
+                                           };
         statusBar.Add (
                        _shQuit,
                        statusBarShortcut,
-                       new Shortcut
-                       {
-                           CanFocus = false,
-                           CommandView = _force16ColorsShortcutCb,
-                           HelpText = "",
-                           BindKeyToApplication = true,
-                           Key = Key.F7
-                       },
+                       force16ColorsShortcut,
                        _shVersion
                       );
 
@@ -707,7 +713,7 @@ public class UICatalogRunnable : Runnable
         }
 
         _disableMouseCb!.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
-        _force16ColorsShortcutCb!.CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
+        _force16ColorsShortcutCb!.CheckedState = Application.Driver!.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
 
         Application.TopRunnableView?.SetNeedsDraw ();
     }

+ 72 - 36
README.md

@@ -6,27 +6,23 @@
 
 # Terminal.Gui v2
 
-The premier toolkit for building rich console apps for Windows, the Mac, and Linux/Unix.
+Cross-platform UI toolkit for building sophisticated terminal UI (TUI) applications on Windows, macOS, and Linux/Unix.
 
 ![logo](docfx/images/logo.png)
 
-* The current, stable, release of Terminal.Gui v1 is [![Version](https://img.shields.io/nuget/v/Terminal.Gui.svg)](https://www.nuget.org/packages/Terminal.Gui).
+* **v2 Alpha** (Current): ![NuGet Version](https://img.shields.io/nuget/vpre/Terminal.Gui) - Recommended for new projects
+* **v1 (Legacy)**: [![Version](https://img.shields.io/nuget/v/Terminal.Gui.svg)](https://www.nuget.org/packages/Terminal.Gui) - Maintenance mode only
 
-> :warning: **Note:**  
-> `v1` is in maintenance mode and we will only accept PRs for issues impacting existing functionality.
-
-* The current `Alpha` release of Terminal.Gui v2 is ![NuGet Version](https://img.shields.io/nuget/vpre/Terminal.Gui)
-
-> :warning: **Note:**  
-> Developers starting new TUI projects are encouraged to target `v2 Alpha`. The API is significantly changed, and significantly improved. There will be breaking changes in the API before Beta, but the core API is stable.
+> **Important:**
+> - **v1** is in maintenance mode - only critical bug fixes accepted
+> - **v2 Alpha** is recommended for new projects - API is stable with comprehensive features
+> - Breaking changes possible before Beta, but core architecture is solid
 
 ![Sample app](docfx/images/sample.gif)
 
 # Quick Start
 
-Paste these commands into your favorite terminal on Windows, Mac, or Linux. This will install the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates), create a new "Hello World" TUI app, and run it.
-
-(Press `CTRL-Q` to exit the app)
+Install the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates), create a new TUI app, and run it:
 
 ```powershell
 dotnet new --install Terminal.Gui.templates
@@ -35,60 +31,100 @@ cd myproj
 dotnet run
 ```
 
-To run the UICatalog demo app that shows all the controls and features of the toolkit, use the following command:
+Press `Esc` to exit (the default [QuitKey](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.Application.html#Terminal_Gui_App_Application_QuitKey)).
+
+Run the comprehensive [UI Catalog](Examples/UICatalog) demo to explore all controls:
 
 ```powershell
 dotnet run --project Examples/UICatalog/UICatalog.csproj
 ```
 
-There is also a [visual designer](https://github.com/gui-cs/TerminalGuiDesigner) (uses Terminal.Gui itself).
+# Simple Example
+
+```csharp
+using Terminal.Gui;
+
+using IApplication app = Application.Create ();
+app.Init ();
+
+using Window window = new () { Title = "Hello World (Esc to quit)" };
+Label label = new ()
+{
+    Text = "Hello, Terminal.Gui v2!",
+    X = Pos.Center (),
+    Y = Pos.Center ()
+};
+window.Add (label);
+
+app.Run (window);
+```
+
+See the [Examples](Examples/) directory for more.
+
+# Build Powerful Terminal Applications
+
+Terminal.Gui enables building sophisticated console applications with modern UIs:
+
+- **Rich Forms and Dialogs** - Text fields, buttons, checkboxes, radio buttons, and data validation
+- **Interactive Data Views** - Tables, lists, and trees with sorting, filtering, and in-place editing  
+- **Visualizations** - Charts, graphs, progress indicators, and color pickers with TrueColor support
+- **Text Editors** - Full-featured text editing with clipboard, undo/redo, and Unicode support
+- **File Management** - File and directory browsers with search and filtering
+- **Wizards and Multi-Step Processes** - Guided workflows with navigation and validation
+- **System Monitoring Tools** - Real-time dashboards with scrollable, resizable views
+- **Configuration UIs** - Settings editors with persistent themes and user preferences
+- **Cross-Platform CLI Tools** - Consistent experience on Windows, macOS, and Linux
+- **Server Management Interfaces** - SSH-compatible UIs for remote administration
+
+See the [Views Overview](https://gui-cs.github.io/Terminal.Gui/docs/views) for available controls and [What's New in v2](https://gui-cs.github.io/Terminal.Gui/docs/newinv2) for architectural improvements.
 
 # Documentation 
 
-The full developer documentation for Terminal.Gui is available at [gui-cs.github.io/Terminal.Gui](https://gui-cs.github.io/Terminal.Gui).
+Comprehensive documentation is at [gui-cs.github.io/Terminal.Gui](https://gui-cs.github.io/Terminal.Gui).
 
 ## Getting Started
 
-- [Getting Started](https://gui-cs.github.io/Terminal.Gui/docs/getting-started) - Quick start guide to create your first Terminal.Gui application
-- [Migrating from v1 to v2](https://gui-cs.github.io/Terminal.Gui/docs/migratingfromv1) - Complete guide for upgrading existing applications
-- [What's New in v2](https://gui-cs.github.io/Terminal.Gui/docs/newinv2) - Overview of new features and improvements
+- **[Getting Started Guide](https://gui-cs.github.io/Terminal.Gui/docs/getting-started)** - First Terminal.Gui application
+- **[API Reference](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.html)** - Complete API documentation
+- **[What's New in v2](https://gui-cs.github.io/Terminal.Gui/docs/newinv2)** - New features and improvements
 
-## API Reference
+## Migration & Deep Dives
 
-For detailed API documentation, see the [API Reference](https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.html).
+- **[Migrating from v1 to v2](https://gui-cs.github.io/Terminal.Gui/docs/migratingfromv1)** - Complete migration guide
+- **[Application Architecture](https://gui-cs.github.io/Terminal.Gui/docs/application)** - Instance-based model and IRunnable pattern
+- **[Layout System](https://gui-cs.github.io/Terminal.Gui/docs/layout)** - Positioning, sizing, and adornments
+- **[Keyboard Handling](https://gui-cs.github.io/Terminal.Gui/docs/keyboard)** - Key bindings and commands
+- **[View Documentation](https://gui-cs.github.io/Terminal.Gui/docs/View)** - View hierarchy and lifecycle
+- **[Configuration](https://gui-cs.github.io/Terminal.Gui/docs/config)** - Themes and persistent settings
 
-# Installing
+See the [documentation index](https://gui-cs.github.io/Terminal.Gui/docs/index) for all topics.
 
-Use NuGet to install the `Terminal.Gui` NuGet package: 
+# Installing
 
-## v2 Alpha 
+## v2 Alpha (Recommended)
 
-(Infrequently updated, but stable enough for production use)
-```
+```powershell
 dotnet add package Terminal.Gui --version "2.0.0-alpha.*"
 ```
 
-## v2 Develop
+## v2 Develop (Latest)
 
-(Frequently updated, but may have breaking changes)
-```
+```powershell
 dotnet add package Terminal.Gui --version "2.0.0-develop.*"
 ```
 
-## Legacy v1
+## v1 Legacy
 
-```
-dotnet add package Terminal.Gui --version "1.*
+```powershell
+dotnet add package Terminal.Gui --version "1.*"
 ```
 
-Or, you can use the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates).
+Or use the [Terminal.Gui.Templates](https://github.com/gui-cs/Terminal.Gui.templates).
 
 # Contributing
 
-See [CONTRIBUTING.md](CONTRIBUTING.md) for complete contribution guidelines.
-
-Debates on architecture and design can be found in Issues tagged with [design](https://github.com/gui-cs/Terminal.Gui/issues?q=is%3Aopen+is%3Aissue+label%3Av2+label%3Adesign).
+Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).
 
 # History
 
-See [gui-cs](https://github.com/gui-cs/) for how this project came to be.
+See [gui-cs](https://github.com/gui-cs/) for project history and origins.

+ 9 - 25
Terminal.Gui/App/Application.Driver.cs

@@ -1,4 +1,6 @@
 
+
+using System.Collections.Concurrent;
 using System.Diagnostics.CodeAnalysis;
 
 namespace Terminal.Gui.App;
@@ -13,30 +15,13 @@ public static partial class Application // Driver abstractions
         internal set => ApplicationImpl.Instance.Driver = value;
     }
 
-    private static bool _force16Colors = false; // Resources/config.json overrides
-
-    /// <inheritdoc cref="IApplication.Force16Colors"/>
-    [ConfigurationProperty (Scope = typeof (SettingsScope))]
-    [Obsolete ("The legacy static Application object is going away.")]
-    public static bool Force16Colors
-    {
-        get => _force16Colors;
-        set
-        {
-            bool oldValue = _force16Colors;
-            _force16Colors = value;
-            Force16ColorsChanged?.Invoke (null, new ValueChangedEventArgs<bool> (oldValue, _force16Colors));
-        }
-    }
-
-    /// <summary>Raised when <see cref="Force16Colors"/> changes.</summary>
-    public static event EventHandler<ValueChangedEventArgs<bool>>? Force16ColorsChanged;
-
+    // NOTE: ForceDriver is a configuration property (Application.ForceDriver).
+    // NOTE: IApplication also has a ForceDriver property, which is an instance property
+    // NOTE: set whenever this static property is set.
     private static string _forceDriver = string.Empty; // Resources/config.json overrides
 
     /// <inheritdoc cref="IApplication.ForceDriver"/>
     [ConfigurationProperty (Scope = typeof (SettingsScope))]
-    [Obsolete ("The legacy static Application object is going away.")]
     public static string ForceDriver
     {
         get => _forceDriver;
@@ -44,16 +29,15 @@ public static partial class Application // Driver abstractions
         {
             string oldValue = _forceDriver;
             _forceDriver = value;
-            ForceDriverChanged?.Invoke (null, new ValueChangedEventArgs<string> (oldValue, _forceDriver));
+            ForceDriverChanged?.Invoke (null, new (oldValue, _forceDriver));
         }
     }
 
     /// <summary>Raised when <see cref="ForceDriver"/> changes.</summary>
     public static event EventHandler<ValueChangedEventArgs<string>>? ForceDriverChanged;
 
-    /// <inheritdoc cref="IApplication.Sixel"/>
-    [Obsolete ("The legacy static Application object is going away.")] 
-    public static List<SixelToRender> Sixel => ApplicationImpl.Instance.Sixel;
+    /// <inheritdoc cref="IDriver.GetSixels"/>
+    public static ConcurrentQueue<SixelToRender> GetSixels () => ApplicationImpl.Instance.Driver?.GetSixels ()!;
 
     /// <summary>Gets a list of <see cref="IDriver"/> types and type names that are available.</summary>
     /// <returns></returns>
@@ -67,7 +51,7 @@ public static partial class Application // Driver abstractions
         // Only inspect the IDriver assembly
         var asm = typeof (IDriver).Assembly;
 
-        foreach (Type? type in asm.GetTypes ())
+        foreach (Type type in asm.GetTypes ())
         {
             if (typeof (IDriver).IsAssignableFrom (type) && type is { IsAbstract: false, IsClass: true })
             {

+ 17 - 1
Terminal.Gui/App/Application.Lifecycle.cs

@@ -10,6 +10,22 @@ namespace Terminal.Gui.App;
 
 public static partial class Application // Lifecycle (Init/Shutdown)
 {
+    /// <summary>
+    ///     Gets the singleton <see cref="IApplication"/> instance used by the legacy static Application model.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         For new code, prefer using <see cref="Create"/> to get an instance-based application.
+    ///         This property is provided for backward compatibility and internal use.
+    ///     </para>
+    ///     <para>
+    ///         This property returns the same singleton instance used by the legacy static <see cref="Application"/>
+    ///         methods like <see cref="Init"/> and <see cref="Run(IRunnable, Func{Exception, bool}?)"/>.
+    ///     </para>
+    /// </remarks>
+    [Obsolete ("The legacy static Application object is going away. Use Application.Create() for new code.")]
+    public static IApplication Instance => ApplicationImpl.Instance;
+
     /// <summary>
     ///     Creates a new <see cref="IApplication"/> instance.
     /// </summary>
@@ -49,7 +65,7 @@ public static partial class Application // Lifecycle (Init/Shutdown)
         internal set => ApplicationImpl.Instance.MainThreadId = value;
     }
 
-    /// <inheritdoc cref="IApplication.Dispose"/>
+    /// <inheritdoc cref="IDisposable.Dispose"/>
     [Obsolete ("The legacy static Application object is going away.")]
     public static void Shutdown () => ApplicationImpl.Instance.Dispose ();
 

+ 0 - 117
Terminal.Gui/App/Application.cd

@@ -1,117 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ClassDiagram MajorVersion="1" MinorVersion="1">
-  <Class Name="Terminal.Gui.App.Application">
-    <Position X="2.25" Y="1.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>gEK4FIgQOAQIuhQeBwoUgSCgAAJL0AACESIKoAiBWw8=</HashCode>
-      <FileName>App\Application.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.App.ApplicationNavigation" Collapsed="true">
-    <Position X="14.75" Y="2.75" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AABAAAAAAABCAAAAAAAAAAAAAAAAIgIAAAAAAAAAAAA=</HashCode>
-      <FileName>App\ApplicationNavigation.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.App.IterationEventArgs" Collapsed="true">
-    <Position X="17" Y="3" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
-      <FileName>App\IterationEventArgs.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.App.MainLoop" Collapsed="true" BaseTypeListCollapsed="true">
-    <Position X="11.25" Y="3.75" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAACAAAAAAAAAAAAAACBAAEAAIIAIAgAAAEAI=</HashCode>
-      <FileName>App\MainLoop.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" Collapsed="true" />
-  </Class>
-  <Class Name="Terminal.Gui.App.MainLoopSyncContext" Collapsed="true">
-    <Position X="13" Y="3.75" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAgAAAAAAAAAAAEAAAAAACAAAAAAAAAAAAAAAAAA=</HashCode>
-      <FileName>App\MainLoopSyncContext.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.App.SessionToken" Collapsed="true" BaseTypeListCollapsed="true">
-    <Position X="15.25" Y="4" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAACACAgAAAAAAAAAAAAAAAAACQAAAAAAAAAA=</HashCode>
-      <FileName>App\SessionToken.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" Collapsed="true" />
-  </Class>
-  <Class Name="Terminal.Gui.App.SessionTokenEventArgs" Collapsed="true">
-    <Position X="17" Y="4" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=</HashCode>
-      <FileName>App\SessionTokenEventArgs.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.App.Timeout" Collapsed="true">
-    <Position X="11.25" Y="4.75" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAQAA=</HashCode>
-      <FileName>App\Timeout.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.App.TimeoutEventArgs" Collapsed="true">
-    <Position X="13" Y="4.75" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAACAIAAAAAAAAAAAA=</HashCode>
-      <FileName>App\TimeoutEventArgs.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.App.ApplicationImpl" BaseTypeListCollapsed="true">
-    <Position X="4" Y="5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AABgAAAAIAAIAgQUAAAAAQAAAAAAAAAAQAAKgAAAEAI=</HashCode>
-      <FileName>App\ApplicationImpl.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.App.MouseGrabHandler" Collapsed="true">
-    <Position X="6.25" Y="9.25" Width="2" />
-    <TypeIdentifier>
-      <HashCode>BAAgAAAAgABAAoAAAAAAABAAACEAAAAAAABAAgAAAAA=</HashCode>
-      <FileName>App\MouseGrabHandler.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Interface Name="Terminal.Gui.App.IMainLoopDriver">
-    <Position X="11.25" Y="1.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAACAAAAAQAAAAABAAAAAAAEAAAAAAAAAAAAAA=</HashCode>
-      <FileName>App\MainLoop.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Interface Name="Terminal.Gui.App.IApplication">
-    <Position X="4" Y="1.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAgAAAAAAAIAgQUAAAAAQAAAAAAAAAAAAAKgAAAEAI=</HashCode>
-      <FileName>App\IApplication.cs</FileName>
-    </TypeIdentifier>
-    <ShowAsAssociation>
-      <Property Name="MouseGrabHandler" />
-      <Property Name="TimedEvents" />
-    </ShowAsAssociation>
-  </Interface>
-  <Interface Name="Terminal.Gui.App.IMouseGrabHandler">
-    <Position X="7" Y="1.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>BAAgAAAAAAAAAgAAAAAAABAAACEAAAAAAAAAAgAAAAA=</HashCode>
-      <FileName>App\IMouseGrabHandler.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Interface Name="Terminal.Gui.App.ITimedEvents">
-    <Position X="7" Y="4.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>BAAAIAAAAQAAAAAQACAAAIBAAQAAAAAAAAAIgAAAAAA=</HashCode>
-      <FileName>App\ITimedEvents.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Font Name="Segoe UI" Size="9" />
-</ClassDiagram>

+ 13 - 9
Terminal.Gui/App/ApplicationImpl.Driver.cs

@@ -2,20 +2,14 @@ using System.Collections.Concurrent;
 
 namespace Terminal.Gui.App;
 
-public partial class ApplicationImpl
+internal partial class ApplicationImpl
 {
     /// <inheritdoc/>
     public IDriver? Driver { get; set; }
 
-    /// <inheritdoc/>
-    public bool Force16Colors { get; set; }
-
     /// <inheritdoc/>
     public string ForceDriver { get; set; } = string.Empty;
 
-    /// <inheritdoc/>
-    public List<SixelToRender> Sixel { get; } = new ();
-
     /// <summary>
     ///     Creates the appropriate <see cref="IDriver"/> based on platform and driverName.
     /// </summary>
@@ -85,6 +79,8 @@ public partial class ApplicationImpl
         {
             throw new ("Driver was null even after booting MainLoopCoordinator");
         }
+
+        Driver.Force16Colors = Terminal.Gui.Drivers.Driver.Force16Colors;
     }
 
     private readonly IComponentFactory? _componentFactory;
@@ -149,7 +145,11 @@ public partial class ApplicationImpl
 
     internal void SubscribeDriverEvents ()
     {
-        ArgumentNullException.ThrowIfNull (Driver);
+        if (Driver is null)
+        {
+            Logging.Error($"Driver is null");
+            return;
+        }
 
         Driver.SizeChanged += Driver_SizeChanged;
         Driver.KeyDown += Driver_KeyDown;
@@ -159,7 +159,11 @@ public partial class ApplicationImpl
 
     internal void UnsubscribeDriverEvents ()
     {
-        ArgumentNullException.ThrowIfNull (Driver);
+        if (Driver is null)
+        {
+            Logging.Error ($"Driver is null");
+            return;
+        }
 
         Driver.SizeChanged -= Driver_SizeChanged;
         Driver.KeyDown -= Driver_KeyDown;

+ 5 - 25
Terminal.Gui/App/ApplicationImpl.Lifecycle.cs

@@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace Terminal.Gui.App;
 
-public partial class ApplicationImpl
+internal partial class ApplicationImpl
 {
     /// <inheritdoc/>
     public int? MainThreadId { get; set; }
@@ -87,7 +87,7 @@ public partial class ApplicationImpl
         _keyboard.PrevTabGroupKey = existingPrevTabGroupKey;
 
         CreateDriver (_driverName);
-        Screen = Driver!.Screen;
+
         Initialized = true;
 
         RaiseInitializedChanged (this, new (true));
@@ -269,14 +269,10 @@ public partial class ApplicationImpl
         if (Driver is { })
         {
             UnsubscribeDriverEvents ();
-            Driver?.End ();
+            Driver.Dispose ();
             Driver = null;
         }
 
-        // Reset screen
-        ResetScreen ();
-        _screen = null;
-
         // === 5. Clear run state ===
         Iteration = null;
         SessionBegun = null;
@@ -304,23 +300,11 @@ public partial class ApplicationImpl
         // === 7. Clear navigation and screen state ===
         ScreenChanged = null;
 
-        //Navigation = null;
-
         // === 8. Reset initialization state ===
         Initialized = false;
         MainThreadId = null;
 
-        // === 9. Clear graphics ===
-        Sixel.Clear ();
-
-        // === 10. Reset ForceDriver ===
-        // Note: ForceDriver and Force16Colors are reset
-        // If they need to persist across Init/Shutdown cycles
-        // then the user of the library should manage that state
-        Force16Colors = false;
-        ForceDriver = string.Empty;
-
-        // === 11. Reset synchronization context ===
+        // === 9. Reset synchronization context ===
         // IMPORTANT: Always reset sync context, even if not initialized
         // This ensures cleanup works correctly even if Shutdown is called without Init
         // Reset synchronization context to allow the user to run async/await,
@@ -329,7 +313,7 @@ public partial class ApplicationImpl
         // (https://github.com/gui-cs/Terminal.Gui/issues/1084).
         SynchronizationContext.SetSynchronizationContext (null);
 
-        // === 12. Unsubscribe from Application static property change events ===
+        // === 10. Unsubscribe from Application static property change events ===
         UnsubscribeApplicationEvents ();
     }
 
@@ -368,9 +352,6 @@ public partial class ApplicationImpl
     }
 #endif
 
-    // Event handlers for Application static property changes
-    private void OnForce16ColorsChanged (object? sender, ValueChangedEventArgs<bool> e) { Force16Colors = e.NewValue; }
-
     private void OnForceDriverChanged (object? sender, ValueChangedEventArgs<string> e) { ForceDriver = e.NewValue; }
 
     /// <summary>
@@ -378,7 +359,6 @@ public partial class ApplicationImpl
     /// </summary>
     private void UnsubscribeApplicationEvents ()
     {
-        Application.Force16ColorsChanged -= OnForce16ColorsChanged;
         Application.ForceDriverChanged -= OnForceDriverChanged;
     }
 }

+ 1 - 1
Terminal.Gui/App/ApplicationImpl.Run.cs

@@ -3,7 +3,7 @@ using System.Diagnostics.CodeAnalysis;
 
 namespace Terminal.Gui.App;
 
-public partial class ApplicationImpl
+internal partial class ApplicationImpl
 {
     // Lock object to protect session stack operations and cached state updates
     private readonly object _sessionStackLock = new ();

+ 28 - 45
Terminal.Gui/App/ApplicationImpl.Screen.cs

@@ -1,29 +1,14 @@
-
 namespace Terminal.Gui.App;
 
-public partial class ApplicationImpl
+internal partial class ApplicationImpl
 {
     /// <inheritdoc/>
     public event EventHandler<EventArgs<Rectangle>>? ScreenChanged;
 
-    private readonly object _lockScreen = new ();
-    private Rectangle? _screen;
-
     /// <inheritdoc/>
     public Rectangle Screen
     {
-        get
-        {
-            lock (_lockScreen)
-            {
-                if (_screen == null)
-                {
-                    _screen = Driver?.Screen ?? new (new (0, 0), new (2048, 2048));
-                }
-
-                return _screen.Value;
-            }
-        }
+        get => Driver?.Screen ?? new (new (0, 0), new (2048, 2048));
         set
         {
             if (value is { } && (value.X != 0 || value.Y != 0))
@@ -31,10 +16,7 @@ public partial class ApplicationImpl
                 throw new NotImplementedException ("Screen locations other than 0, 0 are not yet supported");
             }
 
-            lock (_lockScreen)
-            {
-                _screen = value;
-            }
+            Driver?.SetScreenSize (value.Width, value.Height);
         }
     }
 
@@ -114,16 +96,6 @@ public partial class ApplicationImpl
         return false;
     }
 
-    /// <summary>
-    ///     INTERNAL: Resets the Screen field to null so it will be recalculated on next access.
-    /// </summary>
-    private void ResetScreen ()
-    {
-        lock (_lockScreen)
-        {
-            _screen = null;
-        }
-    }
 
     /// <summary>
     ///     INTERNAL: Called when the application's screen has changed.
@@ -132,7 +104,7 @@ public partial class ApplicationImpl
     /// <param name="screen">The new screen size and position.</param>
     private void RaiseScreenChangedEvent (Rectangle screen)
     {
-        Screen = new (Point.Empty, screen.Size);
+        //Screen = new (Point.Empty, screen.Size);
 
         ScreenChanged?.Invoke (this, new (screen));
 
@@ -150,17 +122,6 @@ public partial class ApplicationImpl
     /// <inheritdoc/>
     public void LayoutAndDraw (bool forceRedraw = false)
     {
-        List<View?> tops = [.. SessionStack!.Select(r => r.Runnable! as View)!];
-
-        if (Popover?.GetActivePopover () as View is { Visible: true } visiblePopover)
-        {
-            visiblePopover.SetNeedsDraw ();
-            visiblePopover.SetNeedsLayout ();
-            tops.Insert (0, visiblePopover);
-        }
-
-        bool neededLayout = View.Layout (tops.ToArray ().Reverse ()!, Screen.Size);
-
         if (ClearScreenNextIteration)
         {
             forceRedraw = true;
@@ -172,12 +133,34 @@ public partial class ApplicationImpl
             Driver?.ClearContents ();
         }
 
-        if (Driver is { })
+        List<View?> views = [.. SessionStack!.Select (r => r.Runnable! as View)!];
+
+        if (Popover?.GetActivePopover () as View is { Visible: true } visiblePopover)
+        {
+            visiblePopover.SetNeedsDraw ();
+            visiblePopover.SetNeedsLayout ();
+            views.Insert (0, visiblePopover);
+        }
+
+        // Layout
+        bool neededLayout = View.Layout (views.ToArray ().Reverse ()!, Screen.Size);
+
+        // Draw
+        bool needsDraw = forceRedraw || views.Any (v => v is { NeedsDraw: true } or { SubViewNeedsDraw: true });
+
+        if (Driver is { } && (neededLayout || needsDraw))
         {
+            Logging.Redraws.Add (1);
+
             Driver.Clip = new (Screen);
 
-            View.Draw (views: tops!, neededLayout || forceRedraw);
+            // Only force a complete redraw if needed (needsLayout or forceRedraw).
+            // Otherwise, just redraw views that need it.
+            View.Draw (views: views.ToArray ().Cast<View> (), neededLayout || forceRedraw);
+
             Driver.Clip = new (Screen);
+
+            // Cause the driver to flush any pending updates to the terminal
             Driver?.Refresh ();
         }
     }

+ 2 - 15
Terminal.Gui/App/ApplicationImpl.cs

@@ -6,7 +6,7 @@ namespace Terminal.Gui.App;
 ///     Implementation of core <see cref="Application"/> methods using the modern
 ///     main loop architecture with component factories for different platforms.
 /// </summary>
-public partial class ApplicationImpl : IApplication
+internal partial class ApplicationImpl : IApplication
 {
     /// <summary>
     ///     INTERNAL: Creates a new instance of the Application backend and subscribes to Application configuration property
@@ -15,7 +15,6 @@ public partial class ApplicationImpl : IApplication
     internal ApplicationImpl ()
     {
         // Subscribe to Application static property change events
-        Application.Force16ColorsChanged += OnForce16ColorsChanged;
         Application.ForceDriverChanged += OnForceDriverChanged;
     }
 
@@ -75,7 +74,7 @@ public partial class ApplicationImpl : IApplication
     /// <summary>
     ///     Gets the currently configured backend implementation of <see cref="Application"/> gateway methods.
     /// </summary>
-    public static IApplication Instance
+    internal static IApplication Instance
     {
         get
         {
@@ -143,18 +142,6 @@ public partial class ApplicationImpl : IApplication
         // If an instance exists, reset it
         _instance?.ResetState (ignoreDisposed);
 
-        // Reset Application static properties to their defaults
-        // This ensures tests start with clean state
-        Application.ForceDriver = string.Empty;
-        Application.Force16Colors = false;
-        Application.IsMouseDisabled = false;
-        Application.QuitKey = Key.Esc;
-        Application.ArrangeKey = Key.F5.WithCtrl;
-        Application.NextTabGroupKey = Key.F6;
-        Application.NextTabKey = Key.Tab;
-        Application.PrevTabGroupKey = Key.F6.WithShift;
-        Application.PrevTabKey = Key.Tab.WithShift;
-
         // Always reset the model tracking to allow tests to use either model after reset
         ResetModelUsageTracking ();
     }

+ 0 - 13
Terminal.Gui/App/IApplication.cs

@@ -449,13 +449,6 @@ public interface IApplication : IDisposable
     /// </remarks>
     IClipboard? Clipboard { get; }
 
-    /// <summary>
-    ///     Gets or sets whether <see cref="Driver"/> will be forced to output only the 16 colors defined in
-    ///     <see cref="ColorName16"/>. The default is <see langword="false"/>, meaning 24-bit (TrueColor) colors will be
-    ///     output as long as the selected <see cref="IDriver"/> supports TrueColor.
-    /// </summary>
-    bool Force16Colors { get; set; }
-
     /// <summary>
     ///     Forces the use of the specified driver (one of "fake", "dotnet", "windows", or "unix"). If not
     ///     specified, the driver is selected based on the platform.
@@ -497,12 +490,6 @@ public interface IApplication : IDisposable
     /// </remarks>
     bool ClearScreenNextIteration { get; set; }
 
-    /// <summary>
-    ///     Collection of sixel images to write out to screen when updating.
-    ///     Only add to this collection if you are sure terminal supports sixel format.
-    /// </summary>
-    List<SixelToRender> Sixel { get; }
-
     #endregion Screen and Driver
 
     #region Keyboard

+ 12 - 48
Terminal.Gui/App/MainLoop/ApplicationMainLoop.cs

@@ -137,30 +137,18 @@ public class ApplicationMainLoop<TInputRecord> : IApplicationMainLoop<TInputReco
         // Pull any input events from the input queue and process them
         InputProcessor.ProcessQueue ();
 
-        if (App?.TopRunnableView != null)
-        {
-            bool needsDrawOrLayout = AnySubViewsNeedDrawn (App?.Popover?.GetActivePopover () as View)
-                                     || AnySubViewsNeedDrawn (App?.TopRunnableView)
-                                     || (App?.Mouse.MouseGrabView != null && AnySubViewsNeedDrawn (App?.Mouse.MouseGrabView));
-
-            bool sizeChanged = SizeMonitor.Poll ();
-
-            if (needsDrawOrLayout || sizeChanged)
-            {
-                Logging.Redraws.Add (1);
-
-                App?.LayoutAndDraw (true);
-
-                Output.Write (OutputBuffer);
+        // Check for any size changes; this will cause SizeChanged events
+        SizeMonitor.Poll ();
 
-                Output.SetCursorVisibility (CursorVisibility.Default);
-            }
+        // Layout and draw any views that need it
+        App?.LayoutAndDraw (forceRedraw: false);
 
-            SetCursor ();
-        }
+        // Update the cursor
+        SetCursor ();
 
-        var swCallbacks = Stopwatch.StartNew ();
+        Stopwatch swCallbacks = Stopwatch.StartNew ();
 
+        // Run any timeout callbacks that are due
         TimedEvents.RunTimers ();
 
         Logging.IterationInvokesAndTimeouts.Record (swCallbacks.Elapsed.Milliseconds);
@@ -168,10 +156,11 @@ public class ApplicationMainLoop<TInputRecord> : IApplicationMainLoop<TInputReco
 
     private void SetCursor ()
     {
-        View? mostFocused = App?.TopRunnableView!.MostFocused;
+        View? mostFocused = App?.TopRunnableView?.MostFocused;
 
         if (mostFocused == null)
         {
+            Output.SetCursorVisibility (CursorVisibility.Invisible);
             return;
         }
 
@@ -180,9 +169,9 @@ public class ApplicationMainLoop<TInputRecord> : IApplicationMainLoop<TInputReco
         if (to.HasValue)
         {
             // Translate to screen coordinates
-            to = mostFocused.ViewportToScreen (to.Value);
+            Point screenPos = mostFocused.ViewportToScreen (to.Value);
 
-            Output.SetCursorPosition (to.Value.X, to.Value.Y);
+            Output.SetCursorPosition (screenPos.X, screenPos.Y);
             Output.SetCursorVisibility (mostFocused.CursorVisibility);
         }
         else
@@ -191,31 +180,6 @@ public class ApplicationMainLoop<TInputRecord> : IApplicationMainLoop<TInputReco
         }
     }
 
-    private bool AnySubViewsNeedDrawn (View? v)
-    {
-        if (v is null)
-        {
-            return false;
-        }
-
-        if (v.NeedsDraw || v.NeedsLayout)
-        {
-            // Logging.Trace ($"{v.GetType ().Name} triggered redraw (NeedsDraw={v.NeedsDraw} NeedsLayout={v.NeedsLayout}) ");
-
-            return true;
-        }
-
-        foreach (View subview in v.SubViews)
-        {
-            if (AnySubViewsNeedDrawn (subview))
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     /// <inheritdoc/>
     public void Dispose ()
     {

+ 2 - 8
Terminal.Gui/App/Mouse/MouseImpl.cs

@@ -20,14 +20,8 @@ internal class MouseImpl : IMouse, IDisposable
         Application.IsMouseDisabledChanged += OnIsMouseDisabledChanged;
     }
 
-    private IApplication? _app;
-
     /// <inheritdoc/>
-    public IApplication? App
-    {
-        get => _app;
-        set => _app = value;
-    }
+    public IApplication? App { get; set; }
 
     /// <inheritdoc/>
     public Point? LastMousePosition { get; set; }
@@ -248,7 +242,7 @@ internal class MouseImpl : IMouse, IDisposable
                 continue;
             }
 
-            CancelEventArgs eventArgs = new System.ComponentModel.CancelEventArgs ();
+            CancelEventArgs eventArgs = new CancelEventArgs ();
             bool? cancelled = view.NewMouseEnterEvent (eventArgs);
 
             if (cancelled is true || eventArgs.Cancel)

+ 32 - 17
Terminal.Gui/App/Timeout/TimedEvents.cs

@@ -201,32 +201,47 @@ public class TimedEvents : ITimedEvents
     private void RunTimersImpl ()
     {
         long now = GetTimestampTicks ();
-        SortedList<long, Timeout> copy;
 
-        // lock prevents new timeouts being added
-        // after we have taken the copy but before
-        // we have allocated a new list (which would
-        // result in lost timeouts or errors during enumeration)
-        lock (_timeoutsLockToken)
+        // Process due timeouts one at a time, without blocking the entire queue
+        while (true)
         {
-            copy = _timeouts;
-            _timeouts = new ();
-        }
+            Timeout? timeoutToExecute = null;
+            long scheduledTime = 0;
 
-        foreach ((long k, Timeout timeout) in copy)
-        {
-            if (k < now)
+            // Find the next due timeout
+            lock (_timeoutsLockToken)
             {
-                if (timeout.Callback! ())
+                if (_timeouts.Count == 0)
+                {
+                    break; // No more timeouts
+                }
+
+                // Re-evaluate current time for each iteration
+                now = GetTimestampTicks ();
+                
+                // Check if the earliest timeout is due
+                scheduledTime = _timeouts.Keys [0];
+                
+                if (scheduledTime >= now)
                 {
-                    AddTimeout (timeout.Span, timeout);
+                    // Earliest timeout is not yet due, we're done
+                    break;
                 }
+
+                // This timeout is due - remove it from the queue
+                timeoutToExecute = _timeouts.Values [0];
+                _timeouts.RemoveAt (0);
             }
-            else
+
+            // Execute the callback outside the lock
+            // This allows nested Run() calls to access the timeout queue
+            if (timeoutToExecute != null)
             {
-                lock (_timeoutsLockToken)
+                bool repeat = timeoutToExecute.Callback! ();
+                
+                if (repeat)
                 {
-                    _timeouts.Add (NudgeToUniqueKey (k), timeout);
+                    AddTimeout (timeoutToExecute.Span, timeoutToExecute);
                 }
             }
         }

+ 1 - 1
Terminal.Gui/Drawing/Cell.cs

@@ -27,7 +27,7 @@ public record struct Cell (Attribute? Attribute = null, bool IsDirty = false, st
         readonly get => _grapheme;
         set
         {
-            if (GraphemeHelper.GetGraphemes(value).ToArray().Length > 1)
+            if (GraphemeHelper.GetGraphemeCount (value) > 1)
             {
                 throw new InvalidOperationException ($"Only a single {nameof (Grapheme)} cluster is allowed per Cell.");
             }

+ 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;
         }

+ 23 - 0
Terminal.Gui/Drawing/GraphemeHelper.cs

@@ -46,4 +46,27 @@ public static class GraphemeHelper
             yield return element;
         }
     }
+
+    /// <summary>
+    ///     Counts the number of grapheme clusters in a string without allocating intermediate collections.
+    /// </summary>
+    /// <param name="text">The string to count graphemes in.</param>
+    /// <returns>The number of grapheme clusters, or 0 if the string is null or empty.</returns>
+    public static int GetGraphemeCount (string text)
+    {
+        if (string.IsNullOrEmpty (text))
+        {
+            return 0;
+        }
+
+        TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator (text);
+        var count = 0;
+
+        while (enumerator.MoveNext ())
+        {
+            count++;
+        }
+
+        return count;
+    }
 }

+ 12 - 4
Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs

@@ -211,15 +211,23 @@ public class LineCanvas : IDisposable
     {
         Dictionary<Point, Rune> map = new ();
 
+        List<IntersectionDefinition> intersectionsBufferList = [];
+
         // walk through each pixel of the bitmap
         for (int y = inArea.Y; y < inArea.Y + inArea.Height; y++)
         {
             for (int x = inArea.X; x < inArea.X + inArea.Width; x++)
             {
-                IntersectionDefinition [] intersects = _lines
-                    .Select (l => l.Intersects (x, y))
-                    .OfType<IntersectionDefinition> () // automatically filters nulls and casts
-                    .ToArray ();
+                intersectionsBufferList.Clear ();
+                foreach (var line in _lines)
+                {
+                    if (line.Intersects (x, y) is { } intersect)
+                    {
+                        intersectionsBufferList.Add (intersect);
+                    }
+                }
+                // Safe as long as the list is not modified while the span is in use.
+                ReadOnlySpan<IntersectionDefinition> intersects = CollectionsMarshal.AsSpan(intersectionsBufferList);
 
                 Rune? rune = GetRuneForIntersects (intersects);
 

+ 5 - 4
Terminal.Gui/Drawing/Sixel/SixelSupportDetector.cs

@@ -32,8 +32,9 @@ public class SixelSupportDetector ()
     /// </returns>
     public void Detect (Action<SixelSupportResult> resultCallback)
     {
-        var result = new SixelSupportResult ();
-        result.SupportsTransparency = IsVirtualTerminal () || IsXtermWithTransparency ();
+        SixelSupportResult result = new SixelSupportResult ();
+        bool isLegacyConsole = IsLegacyConsole ();
+        result.SupportsTransparency = !isLegacyConsole || (!isLegacyConsole && IsXtermWithTransparency ());
         IsSixelSupportedByDar (result, resultCallback);
     }
 
@@ -155,9 +156,9 @@ public class SixelSupportDetector ()
 
     private static bool ResponseIndicatesSupport (string response) { return response.Split (';').Contains ("4"); }
 
-    private static bool IsVirtualTerminal ()
+    private bool IsLegacyConsole ()
     {
-        return !string.IsNullOrWhiteSpace (Environment.GetEnvironmentVariable ("WT_SESSION"));
+        return _driver is { IsLegacyConsole: true };
     }
 
     private static bool IsXtermWithTransparency ()

+ 1 - 1
Terminal.Gui/Drivers/DotNetDriver/NetOutput.cs

@@ -81,7 +81,7 @@ public class NetOutput : OutputBase, IOutput
     /// <inheritdoc/>
     protected override void AppendOrWriteAttribute (StringBuilder output, Attribute attr, TextStyle redrawTextStyle)
     {
-        if (Application.Force16Colors)
+        if (Force16Colors)
         {
             output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
             output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));

+ 31 - 0
Terminal.Gui/Drivers/Driver.cs

@@ -0,0 +1,31 @@
+namespace Terminal.Gui.Drivers;
+
+/// <summary>
+///     Holds global driver settings.
+/// </summary>
+public sealed class Driver
+{
+    private static bool _force16Colors = false; // Resources/config.json overrides
+
+    // NOTE: Force16Colors is a configuration property (Driver.Force16Colors).
+    // NOTE: IDriver also has a Force16Colors property, which is an instance property
+    // NOTE: set whenever this static property is set.
+    /// <summary>
+    ///     Determines if driver instances should use 16 colors instead of the default TrueColors.
+    /// </summary>
+    /// <seealso cref="IDriver.Force16Colors"/>
+    [ConfigurationProperty (Scope = typeof (SettingsScope))]
+    public static bool Force16Colors
+    {
+        get => _force16Colors;
+        set
+        {
+            bool oldValue = _force16Colors;
+            _force16Colors = value;
+            Force16ColorsChanged?.Invoke (null, new ValueChangedEventArgs<bool> (oldValue, _force16Colors));
+        }
+    }
+
+    /// <summary>Raised when <see cref="Force16Colors"/> changes.</summary>
+    public static event EventHandler<ValueChangedEventArgs<bool>>? Force16ColorsChanged;
+}

+ 181 - 163
Terminal.Gui/Drivers/DriverImpl.cs

@@ -1,4 +1,5 @@
-using System.Runtime.InteropServices;
+using System.Collections.Concurrent;
+using System.Runtime.InteropServices;
 
 namespace Terminal.Gui.Drivers;
 
@@ -28,10 +29,6 @@ namespace Terminal.Gui.Drivers;
 /// </remarks>
 internal class DriverImpl : IDriver
 {
-    private readonly IOutput _output;
-    private readonly AnsiRequestScheduler _ansiRequestScheduler;
-    private CursorVisibility _lastCursor = CursorVisibility.Default;
-
     /// <summary>
     ///     Initializes a new instance of the <see cref="DriverImpl"/> class.
     /// </summary>
@@ -63,19 +60,88 @@ internal class DriverImpl : IDriver
                                      };
 
         SizeMonitor = sizeMonitor;
+        SizeMonitor.SizeChanged += OnSizeMonitorOnSizeChanged;
 
-        sizeMonitor.SizeChanged += (_, e) =>
-                                   {
-                                       SetScreenSize (e.Size!.Value.Width, e.Size.Value.Height);
+        CreateClipboard ();
 
-                                       //SizeChanged?.Invoke (this, e);
-                                   };
+        Driver.Force16ColorsChanged += OnDriverOnForce16ColorsChanged;
+    }
 
-        CreateClipboard ();
+    #region Driver Lifecycle
+
+    /// <inheritdoc/>
+    public void Init () { throw new NotSupportedException (); }
+
+    /// <inheritdoc/>
+    public void Refresh () { _output.Write (OutputBuffer); }
+
+    /// <inheritdoc/>
+    public string? GetName () => InputProcessor.DriverName?.ToLowerInvariant ();
+
+    /// <inheritdoc/>
+    public virtual string GetVersionInfo ()
+    {
+        string type = InputProcessor.DriverName ?? throw new ArgumentNullException (nameof (InputProcessor.DriverName));
+
+        return type;
     }
 
     /// <inheritdoc/>
-    public event EventHandler<SizeChangedEventArgs>? SizeChanged;
+    public void Suspend ()
+    {
+        // BUGBUG: This is all platform-specific and should not be implemented here.
+        // BUGBUG: This needs to be in each platform's driver implementation.
+        if (Environment.OSVersion.Platform != PlatformID.Unix)
+        {
+            return;
+        }
+
+        Console.Out.Write (EscSeqUtils.CSI_DisableMouseEvents);
+
+        try
+        {
+            Console.ResetColor ();
+            Console.Clear ();
+
+            //Disable alternative screen buffer.
+            Console.Out.Write (EscSeqUtils.CSI_RestoreCursorAndRestoreAltBufferWithBackscroll);
+
+            //Set cursor key to cursor.
+            Console.Out.Write (EscSeqUtils.CSI_ShowCursor);
+
+            Platform.Suspend ();
+
+            //Enable alternative screen buffer.
+            Console.Out.Write (EscSeqUtils.CSI_SaveCursorAndActivateAltBufferNoBackscroll);
+        }
+        catch (Exception ex)
+        {
+            Logging.Error ($"Error suspending terminal: {ex.Message}");
+        }
+
+        Console.Out.Write (EscSeqUtils.CSI_EnableMouseEvents);
+    }
+
+    /// <inheritdoc/>
+    public bool IsLegacyConsole
+    {
+        get => _output.IsLegacyConsole;
+        set => _output.IsLegacyConsole = value;
+    }
+
+    /// <inheritdoc/>
+    public void Dispose ()
+    {
+        SizeMonitor.SizeChanged -= OnSizeMonitorOnSizeChanged;
+        Driver.Force16ColorsChanged -= OnDriverOnForce16ColorsChanged;
+        _output.Dispose ();
+    }
+
+    #endregion Driver Lifecycle
+
+    #region Driver Components
+
+    private readonly IOutput _output;
 
     /// <inheritdoc/>
     public IInputProcessor InputProcessor { get; }
@@ -86,6 +152,9 @@ internal class DriverImpl : IDriver
     /// <inheritdoc/>
     public ISizeMonitor SizeMonitor { get; }
 
+    /// <inheritdoc/>
+    public IClipboard? Clipboard { get; private set; } = new FakeClipboard ();
+
     private void CreateClipboard ()
     {
         if (InputProcessor.DriverName is { } && InputProcessor.DriverName.Contains ("fake"))
@@ -116,16 +185,12 @@ internal class DriverImpl : IDriver
         // Clipboard is set to FakeClipboard at initialization
     }
 
-    /// <inheritdoc/>
+    #endregion Driver Components
 
-    public Rectangle Screen =>
+    #region Screen and Display
 
-        //if (Application.RunningUnitTests && _output is WindowsConsoleOutput or NetOutput)
-        //{
-        //    // In unit tests, we don't have a real output, so we return an empty rectangle.
-        //    return Rectangle.Empty;
-        //}
-        new (0, 0, OutputBuffer.Cols, OutputBuffer.Rows);
+    /// <inheritdoc/>
+    public Rectangle Screen => new (0, 0, OutputBuffer.Cols, OutputBuffer.Rows);
 
     /// <inheritdoc/>
     public virtual void SetScreenSize (int width, int height)
@@ -136,23 +201,11 @@ internal class DriverImpl : IDriver
     }
 
     /// <inheritdoc/>
+    public event EventHandler<SizeChangedEventArgs>? SizeChanged;
 
-    public Region? Clip
-    {
-        get => OutputBuffer.Clip;
-        set => OutputBuffer.Clip = value;
-    }
-
-    /// <inheritdoc/>
-
-    public IClipboard? Clipboard { get; private set; } = new FakeClipboard ();
+    private void OnSizeMonitorOnSizeChanged (object? _, SizeChangedEventArgs e) { SetScreenSize (e.Size!.Value.Width, e.Size.Value.Height); }
 
     /// <inheritdoc/>
-
-    public int Col => OutputBuffer.Col;
-
-    /// <inheritdoc/>
-
     public int Cols
     {
         get => OutputBuffer.Cols;
@@ -160,15 +213,13 @@ internal class DriverImpl : IDriver
     }
 
     /// <inheritdoc/>
-
-    public Cell [,]? Contents
+    public int Rows
     {
-        get => OutputBuffer.Contents;
-        set => OutputBuffer.Contents = value;
+        get => OutputBuffer.Rows;
+        set => OutputBuffer.Rows = value;
     }
 
     /// <inheritdoc/>
-
     public int Left
     {
         get => OutputBuffer.Left;
@@ -176,55 +227,45 @@ internal class DriverImpl : IDriver
     }
 
     /// <inheritdoc/>
-
-    public int Row => OutputBuffer.Row;
-
-    /// <inheritdoc/>
-
-    public int Rows
-    {
-        get => OutputBuffer.Rows;
-        set => OutputBuffer.Rows = value;
-    }
-
-    /// <inheritdoc/>
-
     public int Top
     {
         get => OutputBuffer.Top;
         set => OutputBuffer.Top = value;
     }
 
-    // TODO: Probably not everyone right?
-
-    /// <inheritdoc/>
+    #endregion Screen and Display
 
-    public bool SupportsTrueColor => true;
+    #region Color Support
 
     /// <inheritdoc/>
+    public bool SupportsTrueColor => !IsLegacyConsole;
 
+    /// <inheritdoc/>
     public bool Force16Colors
     {
-        get => Application.Force16Colors || !SupportsTrueColor;
-        set => Application.Force16Colors = value || !SupportsTrueColor;
+        get => _output.Force16Colors;
+        set => _output.Force16Colors = value;
     }
 
-    /// <inheritdoc/>
+    private void OnDriverOnForce16ColorsChanged (object? _, ValueChangedEventArgs<bool> e) { Force16Colors = e.NewValue; }
 
-    public Attribute CurrentAttribute
-    {
-        get => OutputBuffer.CurrentAttribute;
-        set => OutputBuffer.CurrentAttribute = value;
-    }
+    #endregion Color Support
 
-    /// <inheritdoc/>
-    public void AddRune (Rune rune) { OutputBuffer.AddRune (rune); }
+    #region Content Buffer
 
     /// <inheritdoc/>
-    public void AddRune (char c) { OutputBuffer.AddRune (c); }
+    public Cell [,]? Contents
+    {
+        get => OutputBuffer.Contents;
+        set => OutputBuffer.Contents = value;
+    }
 
     /// <inheritdoc/>
-    public void AddStr (string str) { OutputBuffer.AddStr (str); }
+    public Region? Clip
+    {
+        get => OutputBuffer.Clip;
+        set => OutputBuffer.Clip = value;
+    }
 
     /// <summary>Clears the <see cref="IDriver.Contents"/> of the driver.</summary>
     public void ClearContents ()
@@ -236,20 +277,26 @@ internal class DriverImpl : IDriver
     /// <inheritdoc/>
     public event EventHandler<EventArgs>? ClearedContents;
 
+    #endregion Content Buffer
+
+    #region Drawing and Rendering
+
     /// <inheritdoc/>
-    public void FillRect (Rectangle rect, Rune rune = default) { OutputBuffer.FillRect (rect, rune); }
+    public int Col => OutputBuffer.Col;
 
     /// <inheritdoc/>
-    public void FillRect (Rectangle rect, char c) { OutputBuffer.FillRect (rect, c); }
+    public int Row => OutputBuffer.Row;
 
     /// <inheritdoc/>
-    public virtual string GetVersionInfo ()
+    public Attribute CurrentAttribute
     {
-        string type = InputProcessor.DriverName ?? throw new ArgumentNullException (nameof (InputProcessor.DriverName));
-
-        return type;
+        get => OutputBuffer.CurrentAttribute;
+        set => OutputBuffer.CurrentAttribute = value;
     }
 
+    /// <inheritdoc/>
+    public void Move (int col, int row) { OutputBuffer.Move (col, row); }
+
     /// <inheritdoc/>
     public bool IsRuneSupported (Rune rune) => Rune.IsValid (rune.Value);
 
@@ -262,77 +309,22 @@ internal class DriverImpl : IDriver
     ///     <see cref="IDriver.Clip"/>.
     ///     <see langword="true"/> otherwise.
     /// </returns>
-    public bool IsValidLocation (string text, int col, int row) { return OutputBuffer.IsValidLocation (text, col, row); }
+    public bool IsValidLocation (string text, int col, int row) => OutputBuffer.IsValidLocation (text, col, row);
 
     /// <inheritdoc/>
-    public void Move (int col, int row) { OutputBuffer.Move (col, row); }
-
-    // TODO: Probably part of output
-
-    /// <inheritdoc/>
-    public bool SetCursorVisibility (CursorVisibility visibility)
-    {
-        _lastCursor = visibility;
-        _output.SetCursorVisibility (visibility);
-
-        return true;
-    }
-
-    /// <inheritdoc/>
-    public bool GetCursorVisibility (out CursorVisibility current)
-    {
-        current = _lastCursor;
-
-        return true;
-    }
+    public void AddRune (Rune rune) { OutputBuffer.AddRune (rune); }
 
     /// <inheritdoc/>
-    public void Suspend ()
-    {
-        // BUGBUG: This is all platform-specific and should not be implemented here.
-        // BUGBUG: This needs to be in each platform's driver implementation.
-        if (Environment.OSVersion.Platform != PlatformID.Unix)
-        {
-            return;
-        }
-
-        Console.Out.Write (EscSeqUtils.CSI_DisableMouseEvents);
-
-        try
-        {
-            Console.ResetColor ();
-            Console.Clear ();
-
-            //Disable alternative screen buffer.
-            Console.Out.Write (EscSeqUtils.CSI_RestoreCursorAndRestoreAltBufferWithBackscroll);
-
-            //Set cursor key to cursor.
-            Console.Out.Write (EscSeqUtils.CSI_ShowCursor);
-
-            Platform.Suspend ();
-
-            //Enable alternative screen buffer.
-            Console.Out.Write (EscSeqUtils.CSI_SaveCursorAndActivateAltBufferNoBackscroll);
-        }
-        catch (Exception ex)
-        {
-            Logging.Error ($"Error suspending terminal: {ex.Message}");
-        }
-
-        Console.Out.Write (EscSeqUtils.CSI_EnableMouseEvents);
-    }
+    public void AddRune (char c) { OutputBuffer.AddRune (c); }
 
     /// <inheritdoc/>
-    public void UpdateCursor () { _output.SetCursorPosition (Col, Row); }
+    public void AddStr (string str) { OutputBuffer.AddStr (str); }
 
     /// <inheritdoc/>
-    public void Init () { throw new NotSupportedException (); }
+    public void FillRect (Rectangle rect, Rune rune = default) { OutputBuffer.FillRect (rect, rune); }
 
     /// <inheritdoc/>
-    public void End ()
-    {
-        // TODO: Nope
-    }
+    public void FillRect (Rectangle rect, char c) { OutputBuffer.FillRect (rect, c); }
 
     /// <inheritdoc/>
     public Attribute SetAttribute (Attribute newAttribute)
@@ -346,35 +338,11 @@ internal class DriverImpl : IDriver
     /// <inheritdoc/>
     public Attribute GetAttribute () => OutputBuffer.CurrentAttribute;
 
-    /// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="IDriver.KeyUp"/>.</summary>
-    public event EventHandler<Key>? KeyDown;
-
-    /// <inheritdoc/>
-    public event EventHandler<Key>? KeyUp;
-
-    /// <summary>Event fired when a mouse event occurs.</summary>
-    public event EventHandler<MouseEventArgs>? MouseEvent;
-
     /// <inheritdoc/>
     public void WriteRaw (string ansi) { _output.Write (ansi); }
 
     /// <inheritdoc/>
-    public void EnqueueKeyEvent (Key key) { InputProcessor.EnqueueKeyDownEvent (key); }
-
-    /// <inheritdoc/>
-    public void QueueAnsiRequest (AnsiEscapeSequenceRequest request) { _ansiRequestScheduler.SendOrSchedule (this, request); }
-
-    /// <inheritdoc/>
-    public AnsiRequestScheduler GetRequestScheduler () => _ansiRequestScheduler;
-
-    /// <inheritdoc/>
-    public void Refresh ()
-    {
-        // No need we will always draw when dirty
-    }
-
-    /// <inheritdoc/>
-    public string? GetName () => InputProcessor.DriverName?.ToLowerInvariant ();
+    public ConcurrentQueue<SixelToRender> GetSixels () => _output.GetSixels ();
 
     /// <inheritdoc/>
     public new string ToString ()
@@ -403,9 +371,59 @@ internal class DriverImpl : IDriver
         return sb.ToString ();
     }
 
-    /// <inheritdoc />
-    public string ToAnsi ()
+    /// <inheritdoc/>
+    public string ToAnsi () => _output.ToAnsi (OutputBuffer);
+
+    #endregion Drawing and Rendering
+
+    #region Cursor
+
+    private CursorVisibility _lastCursor = CursorVisibility.Default;
+
+    /// <inheritdoc/>
+    public void UpdateCursor () { _output.SetCursorPosition (Col, Row); }
+
+    /// <inheritdoc/>
+    public bool GetCursorVisibility (out CursorVisibility current)
     {
-        return _output.ToAnsi (OutputBuffer);
+        current = _lastCursor;
+
+        return true;
     }
+
+    /// <inheritdoc/>
+    public bool SetCursorVisibility (CursorVisibility visibility)
+    {
+        _lastCursor = visibility;
+        _output.SetCursorVisibility (visibility);
+
+        return true;
+    }
+
+    #endregion Cursor
+
+    #region Input Events
+
+    /// <summary>Event fired when a mouse event occurs.</summary>
+    public event EventHandler<MouseEventArgs>? MouseEvent;
+
+    /// <summary>Event fired when a key is pressed down. This is a precursor to <see cref="IDriver.KeyUp"/>.</summary>
+    public event EventHandler<Key>? KeyDown;
+
+    /// <inheritdoc/>
+    public event EventHandler<Key>? KeyUp;
+
+    /// <inheritdoc/>
+    public void EnqueueKeyEvent (Key key) { InputProcessor.EnqueueKeyDownEvent (key); }
+
+    #endregion Input Events
+
+    #region ANSI Escape Sequences
+
+    private readonly AnsiRequestScheduler _ansiRequestScheduler;
+
+    /// <inheritdoc/>
+    public virtual void QueueAnsiRequest (AnsiEscapeSequenceRequest request) { _ansiRequestScheduler.SendOrSchedule (this, request); }
+
+    #endregion ANSI Escape Sequences
 }

+ 16 - 5
Terminal.Gui/Drivers/FakeDriver/FakeOutput.cs

@@ -86,10 +86,21 @@ public class FakeOutput : OutputBase, IOutput
     /// <inheritdoc/>
     protected override void AppendOrWriteAttribute (StringBuilder output, Attribute attr, TextStyle redrawTextStyle)
     {
-        if (Application.Force16Colors)
+        if (Force16Colors)
         {
-            output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
-            output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));
+            if (!IsLegacyConsole)
+            {
+                output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
+                output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));
+
+                EscSeqUtils.CSI_AppendTextStyleChange (output, redrawTextStyle, attr.Style);
+            }
+            else
+            {
+                Write (output);
+                Console.ForegroundColor = (ConsoleColor)attr.Foreground.GetClosestNamedColor16 ();
+                Console.BackgroundColor = (ConsoleColor)attr.Background.GetClosestNamedColor16 ();
+            }
         }
         else
         {
@@ -106,9 +117,9 @@ public class FakeOutput : OutputBase, IOutput
                                                       attr.Background.G,
                                                       attr.Background.B
                                                      );
-        }
 
-        EscSeqUtils.CSI_AppendTextStyleChange (output, redrawTextStyle, attr.Style);
+            EscSeqUtils.CSI_AppendTextStyleChange (output, redrawTextStyle, attr.Style);
+        }
     }
 
     /// <inheritdoc/>

+ 164 - 123
Terminal.Gui/Drivers/IDriver.cs

@@ -1,3 +1,4 @@
+using System.Collections.Concurrent;
 
 namespace Terminal.Gui.Drivers;
 
@@ -5,92 +6,107 @@ namespace Terminal.Gui.Drivers;
 /// <remarks>
 ///     There are currently four implementations: UnixDriver, WindowsDriver, DotNetDriver, and FakeDriver
 /// </remarks>
-public interface IDriver
+public interface IDriver : IDisposable
 {
+    #region Driver Lifecycle
+
+    /// <summary>Initializes the driver</summary>
+    void Init ();
+
     /// <summary>
-    ///     Gets the name of the driver implementation.
+    ///     INTERNAL: Updates the terminal with the current output buffer. Should not be used by applications. Drawing occurs
+    ///     once each Application main loop iteration.
     /// </summary>
-    string? GetName ();
+    void Refresh ();
 
     /// <summary>
-    ///     Class responsible for processing native driver input objects
-    ///     e.g. <see cref="ConsoleKeyInfo"/> into <see cref="Key"/> events
-    ///     and detecting and processing ansi escape sequences.
+    ///     Gets the name of the driver implementation.
     /// </summary>
-    IInputProcessor InputProcessor { get; }
+    string? GetName ();
+
+    /// <summary>Returns the name of the driver and relevant library version information.</summary>
+    /// <returns></returns>
+    string GetVersionInfo ();
+
+    /// <summary>Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver.</summary>
+    /// <remarks>This is only implemented in UnixDriver.</remarks>
+    void Suspend ();
 
     /// <summary>
-    ///     Describes the desired screen state. Data source for <see cref="IOutput"/>.
+    ///     Gets whether the driver has detected the console requires legacy console API (Windows Console API without ANSI/VT
+    ///     support).
+    ///     Returns <see langword="true"/> for legacy consoles that don't support modern ANSI escape sequences (e.g. Windows
+    ///     conhost);
+    ///     <see langword="false"/> for modern terminals with ANSI/VT support.
     /// </summary>
-    IOutputBuffer OutputBuffer { get; }
+    /// <remarks>
+    ///     <para>
+    ///         This property indicates whether the terminal supports modern ANSI escape sequences for input/output.
+    ///         On Windows, this maps to whether Virtual Terminal processing is enabled.
+    ///         On Unix-like systems, this is typically <see langword="false"/> as they support ANSI by default.
+    ///     </para>
+    ///     <para>
+    ///         When <see langword="true"/>, the driver must use legacy Windows Console API functions
+    ///         (e.g., WriteConsoleW, SetConsoleTextAttribute) instead of ANSI escape sequences.
+    ///     </para>
+    /// </remarks>
+    bool IsLegacyConsole { get; internal set; }
+
+    #endregion Driver Lifecycle
+
+    #region Driver Components
 
     /// <summary>
-    ///     Interface for classes responsible for reporting the current
-    ///     size of the terminal window.
+    ///     Class responsible for processing native driver input objects
+    ///     e.g. <see cref="ConsoleKeyInfo"/> into <see cref="Key"/> events
+    ///     and detecting and processing ansi escape sequences.
     /// </summary>
-    ISizeMonitor SizeMonitor { get; }
+    IInputProcessor InputProcessor { get; }
 
     /// <summary>Get the operating system clipboard.</summary>
-    /// 
     IClipboard? Clipboard { get; }
 
+    #endregion Driver Components
+
+    #region Screen and Display
+
     /// <summary>Gets the location and size of the terminal screen.</summary>
     Rectangle Screen { get; }
 
     /// <summary>
-    /// Sets the screen size for testing purposes. Only supported by FakeDriver.
-    /// <see cref="Screen"/> is the source of truth for screen dimensions.
+    ///     Sets the screen size. <see cref="Screen"/> is the source of truth for screen dimensions.
     /// </summary>
     /// <param name="width">The new width in columns.</param>
     /// <param name="height">The new height in rows.</param>
-    /// <exception cref="NotSupportedException">Thrown when called on non-FakeDriver instances.</exception>
     void SetScreenSize (int width, int height);
 
     /// <summary>
-    ///     Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject
-    ///     to.
-    /// </summary>
-    /// <value>The rectangle describing the of <see cref="Clip"/> region.</value>
-    Region? Clip { get; set; }
-
-
-    /// <summary>
-    ///     Gets the column last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/> are used by
-    ///     <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
+    ///     The event fired when the screen changes (size, position, etc.).
+    ///     <see cref="Screen"/> is the source of truth for screen dimensions.
     /// </summary>
-    int Col { get; }
+    event EventHandler<SizeChangedEventArgs>? SizeChanged;
 
     /// <summary>The number of columns visible in the terminal.</summary>
     int Cols { get; set; }
 
-    // BUGBUG: This should not be publicly settable.
-    /// <summary>
-    ///     Gets or sets the contents of the application output. The driver outputs this buffer to the terminal.
-    ///     <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks>
-    /// </summary>
-    Cell [,]? Contents { get; set; }
+    /// <summary>The number of rows visible in the terminal.</summary>
+    int Rows { get; set; }
 
     /// <summary>The leftmost column in the terminal.</summary>
     int Left { get; set; }
 
-    /// <summary>
-    ///     Gets the row last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/> are used by
-    ///     <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
-    /// </summary>
-    int Row { get; }
-
-    /// <summary>The number of rows visible in the terminal.</summary>
-    int Rows { get; set; }
-
     /// <summary>The topmost row in the terminal.</summary>
     int Top { get; set; }
 
+    #endregion Screen and Display
+
+    #region Color Support
+
     /// <summary>Gets whether the <see cref="IDriver"/> supports TrueColor output.</summary>
     bool SupportsTrueColor { get; }
 
     /// <summary>
     ///     Gets or sets whether the <see cref="IDriver"/> should use 16 colors instead of the default TrueColors.
-    ///     See <see cref="Application.Force16Colors"/> to change this setting via <see cref="ConfigurationManager"/>.
     /// </summary>
     /// <remarks>
     ///     <para>
@@ -98,42 +114,57 @@ public interface IDriver
     ///         <see langword="false"/>, indicating that the <see cref="IDriver"/> cannot support TrueColor.
     ///     </para>
     /// </remarks>
+    /// <seealso cref="Driver.Force16Colors"/>
     bool Force16Colors { get; set; }
 
+    #endregion Color Support
+
+    #region Content Buffer
+
+    // BUGBUG: This should not be publicly settable.
     /// <summary>
-    ///     The <see cref="System.Attribute"/> that will be used for the next <see cref="AddRune(Rune)"/> or <see cref="AddStr"/>
-    ///     call.
+    ///     Gets or sets the contents of the application output. The driver outputs this buffer to the terminal.
+    ///     <remarks>The format of the array is rows, columns. The first index is the row, the second index is the column.</remarks>
     /// </summary>
-    Attribute CurrentAttribute { get; set; }
+    Cell [,]? Contents { get; set; }
 
-    /// <summary>Returns the name of the driver and relevant library version information.</summary>
-    /// <returns></returns>
-    string GetVersionInfo ();
+    /// <summary>
+    ///     Gets or sets the clip rectangle that <see cref="AddRune(Rune)"/> and <see cref="AddStr(string)"/> are subject
+    ///     to.
+    /// </summary>
+    /// <value>The rectangle describing the of <see cref="Clip"/> region.</value>
+    Region? Clip { get; set; }
+
+    /// <summary>Clears the <see cref="IDriver.Contents"/> of the driver.</summary>
+    void ClearContents ();
 
     /// <summary>
-    ///     Provide proper writing to send escape sequence recognized by the <see cref="IDriver"/>.
+    ///     Fills the specified rectangle with the specified rune, using <see cref="IDriver.CurrentAttribute"/>
     /// </summary>
-    /// <param name="ansi"></param>
-    void WriteRaw (string ansi);
+    event EventHandler<EventArgs> ClearedContents;
 
-    /// <summary>Tests if the specified rune is supported by the driver.</summary>
-    /// <param name="rune"></param>
-    /// <returns>
-    ///     <see langword="true"/> if the rune can be properly presented; <see langword="false"/> if the driver does not
-    ///     support displaying this rune.
-    /// </returns>
-    bool IsRuneSupported (Rune rune);
+    #endregion Content Buffer
 
-    /// <summary>Tests whether the specified coordinate are valid for drawing the specified Text.</summary>
-    /// <param name="text">Used to determine if one or two columns are required.</param>
-    /// <param name="col">The column.</param>
-    /// <param name="row">The row.</param>
-    /// <returns>
-    ///     <see langword="false"/> if the coordinate is outside the screen bounds or outside of
-    ///     <see cref="IDriver.Clip"/>.
-    ///     <see langword="true"/> otherwise.
-    /// </returns>
-    bool IsValidLocation (string text, int col, int row);
+    #region Drawing and Rendering
+
+    /// <summary>
+    ///     Gets the column last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/> are used by
+    ///     <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
+    /// </summary>
+    int Col { get; }
+
+    /// <summary>
+    ///     Gets the row last set by <see cref="Move"/>. <see cref="Col"/> and <see cref="Row"/> are used by
+    ///     <see cref="AddRune(Rune)"/> and <see cref="AddStr"/> to determine where to add content.
+    /// </summary>
+    int Row { get; }
+
+    /// <summary>
+    ///     The <see cref="System.Attribute"/> that will be used for the next <see cref="AddRune(Rune)"/> or
+    ///     <see cref="AddStr"/>
+    ///     call.
+    /// </summary>
+    Attribute CurrentAttribute { get; set; }
 
     /// <summary>
     ///     Updates <see cref="IDriver.Col"/> and <see cref="IDriver.Row"/> to the specified column and row in
@@ -153,6 +184,25 @@ public interface IDriver
     /// <param name="row">Row to move to.</param>
     void Move (int col, int row);
 
+    /// <summary>Tests if the specified rune is supported by the driver.</summary>
+    /// <param name="rune"></param>
+    /// <returns>
+    ///     <see langword="true"/> if the rune can be properly presented; <see langword="false"/> if the driver does not
+    ///     support displaying this rune.
+    /// </returns>
+    bool IsRuneSupported (Rune rune);
+
+    /// <summary>Tests whether the specified coordinate are valid for drawing the specified Text.</summary>
+    /// <param name="text">Used to determine if one or two columns are required.</param>
+    /// <param name="col">The column.</param>
+    /// <param name="row">The row.</param>
+    /// <returns>
+    ///     <see langword="false"/> if the coordinate is outside the screen bounds or outside of
+    ///     <see cref="IDriver.Clip"/>.
+    ///     <see langword="true"/> otherwise.
+    /// </returns>
+    bool IsValidLocation (string text, int col, int row);
+
     /// <summary>Adds the specified rune to the display at the current cursor position.</summary>
     /// <remarks>
     ///     <para>
@@ -193,14 +243,6 @@ public interface IDriver
     /// <param name="str">String.</param>
     void AddStr (string str);
 
-    /// <summary>Clears the <see cref="IDriver.Contents"/> of the driver.</summary>
-    void ClearContents ();
-
-    /// <summary>
-    ///     Fills the specified rectangle with the specified rune, using <see cref="IDriver.CurrentAttribute"/>
-    /// </summary>
-    event EventHandler<EventArgs> ClearedContents;
-
     /// <summary>Fills the specified rectangle with the specified rune, using <see cref="IDriver.CurrentAttribute"/></summary>
     /// <remarks>
     ///     The value of <see cref="IDriver.Clip"/> is honored. Any parts of the rectangle not in the clip will not be
@@ -218,29 +260,43 @@ public interface IDriver
     /// <param name="c"></param>
     void FillRect (Rectangle rect, char c);
 
+    /// <summary>Selects the specified attribute as the attribute to use for future calls to AddRune and AddString.</summary>
+    /// <remarks>Implementations should call <c>base.SetAttribute(c)</c>.</remarks>
+    /// <param name="c">C.</param>
+    Attribute SetAttribute (Attribute c);
 
-    /// <summary>Gets the terminal cursor visibility.</summary>
-    /// <param name="visibility">The current <see cref="CursorVisibility"/></param>
-    /// <returns><see langword="true"/> upon success</returns>
-    bool GetCursorVisibility (out CursorVisibility visibility);
+    /// <summary>Gets the current <see cref="Attribute"/>.</summary>
+    /// <returns>The current attribute.</returns>
+    Attribute GetAttribute ();
 
-    /// <summary>Updates the screen to reflect all the changes that have been done to the display buffer</summary>
-    void Refresh ();
+    /// <summary>
+    ///     Provide proper writing to send escape sequence recognized by the <see cref="IDriver"/>.
+    /// </summary>
+    /// <param name="ansi"></param>
+    void WriteRaw (string ansi);
 
-    /// <summary>Sets the terminal cursor visibility.</summary>
-    /// <param name="visibility">The wished <see cref="CursorVisibility"/></param>
-    /// <returns><see langword="true"/> upon success</returns>
-    bool SetCursorVisibility (CursorVisibility visibility);
+    /// <summary>
+    ///     Gets the queue of sixel images to write out to screen when updating.
+    ///     If the terminal does not support Sixel, adding to this queue has no effect.
+    /// </summary>
+    ConcurrentQueue<SixelToRender> GetSixels ();
 
     /// <summary>
-    /// The event fired when the screen changes (size, position, etc.).
-    /// <see cref="Screen"/> is the source of truth for screen dimensions.
+    ///     Gets a string representation of <see cref="Contents"/>.
     /// </summary>
-    event EventHandler<SizeChangedEventArgs>? SizeChanged;
+    /// <returns></returns>
+    public string ToString ();
 
-    /// <summary>Suspends the application (e.g. on Linux via SIGTSTP) and upon resume, resets the console driver.</summary>
-    /// <remarks>This is only implemented in UnixDriver.</remarks>
-    void Suspend ();
+    /// <summary>
+    ///     Gets an ANSI escape sequence representation of <see cref="Contents"/>. This is the
+    ///     same output as would be written to the terminal to recreate the current screen contents.
+    /// </summary>
+    /// <returns></returns>
+    public string ToAnsi ();
+
+    #endregion Drawing and Rendering
+
+    #region Cursor
 
     /// <summary>
     ///     Sets the position of the terminal cursor to <see cref="IDriver.Col"/> and
@@ -248,20 +304,19 @@ public interface IDriver
     /// </summary>
     void UpdateCursor ();
 
-    /// <summary>Initializes the driver</summary>
-    void Init ();
+    /// <summary>Gets the terminal cursor visibility.</summary>
+    /// <param name="visibility">The current <see cref="CursorVisibility"/></param>
+    /// <returns><see langword="true"/> upon success</returns>
+    bool GetCursorVisibility (out CursorVisibility visibility);
 
-    /// <summary>Ends the execution of the console driver.</summary>
-    void End ();
+    /// <summary>Sets the terminal cursor visibility.</summary>
+    /// <param name="visibility">The wished <see cref="CursorVisibility"/></param>
+    /// <returns><see langword="true"/> upon success</returns>
+    bool SetCursorVisibility (CursorVisibility visibility);
 
-    /// <summary>Selects the specified attribute as the attribute to use for future calls to AddRune and AddString.</summary>
-    /// <remarks>Implementations should call <c>base.SetAttribute(c)</c>.</remarks>
-    /// <param name="c">C.</param>
-    Attribute SetAttribute (Attribute c);
+    #endregion Cursor
 
-    /// <summary>Gets the current <see cref="Attribute"/>.</summary>
-    /// <returns>The current attribute.</returns>
-    Attribute GetAttribute ();
+    #region Input Events
 
     /// <summary>Event fired when a mouse event occurs.</summary>
     event EventHandler<MouseEventArgs>? MouseEvent;
@@ -283,29 +338,15 @@ public interface IDriver
     /// <param name="key"></param>
     void EnqueueKeyEvent (Key key);
 
+    #endregion Input Events
+
+    #region ANSI Escape Sequences
+
     /// <summary>
     ///     Queues the given <paramref name="request"/> for execution
     /// </summary>
     /// <param name="request"></param>
     public void QueueAnsiRequest (AnsiEscapeSequenceRequest request);
 
-    /// <summary>
-    ///     Gets the <see cref="AnsiRequestScheduler"/> for the driver
-    /// </summary>
-    /// <returns></returns>
-    public AnsiRequestScheduler GetRequestScheduler ();
-
-
-    /// <summary>
-    ///     Gets a string representation of <see cref="Contents"/>.
-    /// </summary>
-    /// <returns></returns>
-    public string ToString ();
-
-    /// <summary>
-    ///     Gets an ANSI escape sequence representation of <see cref="Contents"/>. This is the
-    ///     same output as would be written to the terminal to recreate the current screen contents.
-    /// </summary>
-    /// <returns></returns>
-    public string ToAnsi ();
+    #endregion ANSI Escape Sequences
 }

+ 13 - 2
Terminal.Gui/Drivers/IOutput.cs

@@ -1,4 +1,6 @@
-namespace Terminal.Gui.Drivers;
+using System.Collections.Concurrent;
+
+namespace Terminal.Gui.Drivers;
 
 /// <summary>
 ///     The low-level interface drivers implement to provide output capabilities; encapsulates platform-specific
@@ -6,6 +8,15 @@
 /// </summary>
 public interface IOutput : IDisposable
 {
+    /// <seealso cref="IDriver.Force16Colors"/>
+    bool Force16Colors { get; set; }
+
+    /// <seealso cref="IDriver.IsLegacyConsole"/>
+    bool IsLegacyConsole { get; set; }
+
+    /// <seealso cref="IDriver.GetSixels"/>
+    ConcurrentQueue<SixelToRender> GetSixels ();
+
     /// <summary>
     ///     Gets the current position of the console cursor.
     /// </summary>
@@ -17,7 +28,7 @@ public interface IOutput : IDisposable
     ///     of characters not pixels).
     /// </summary>
     /// <returns></returns>
-    public Size GetSize ();
+    Size GetSize ();
 
     /// <summary>
     ///     Moves the console cursor to the given location.

+ 1 - 1
Terminal.Gui/Drivers/ISizeMonitor.cs

@@ -14,6 +14,6 @@ public interface ISizeMonitor
     ///     Examines the current size of the terminal and raises <see cref="SizeChanged"/> if it is different
     ///     from last inspection.
     /// </summary>
-    /// <returns></returns>
+    /// <returns><see langword="true"/> if the size has changed; otherwise, <see langword="false"/>.</returns>
     bool Poll ();
 }

+ 84 - 25
Terminal.Gui/Drivers/OutputBase.cs

@@ -1,3 +1,5 @@
+using System.Collections.Concurrent;
+
 namespace Terminal.Gui.Drivers;
 
 /// <summary>
@@ -5,7 +7,44 @@ namespace Terminal.Gui.Drivers;
 /// </summary>
 public abstract class OutputBase
 {
-    private CursorVisibility? _cachedCursorVisibility;
+    private bool _force16Colors;
+
+    /// <inheritdoc cref="IOutput.Force16Colors"/>
+    public bool Force16Colors
+    {
+        get => _force16Colors;
+        set
+        {
+            if (IsLegacyConsole && !value)
+            {
+                return;
+            }
+
+            _force16Colors = value;
+        }
+    }
+
+    private bool _isLegacyConsole;
+
+    /// <inheritdoc cref="IOutput.IsLegacyConsole"/>
+    public bool IsLegacyConsole
+    {
+        get => _isLegacyConsole;
+        set
+        {
+            _isLegacyConsole = value;
+
+            if (value) // If legacy console (true), force 16 colors
+            {
+                Force16Colors = true;
+            }
+        }
+    }
+
+    private readonly ConcurrentQueue<SixelToRender> _sixels = [];
+
+    /// <inheritdoc cref="IOutput.GetSixels"/>>
+    public ConcurrentQueue<SixelToRender> GetSixels () => _sixels;
 
     // Last text style used, for updating style with EscSeqUtils.CSI_AppendTextStyleChange().
     private TextStyle _redrawTextStyle = TextStyle.None;
@@ -28,7 +67,6 @@ public abstract class OutputBase
         Attribute? redrawAttr = null;
         int lastCol = -1;
 
-        CursorVisibility? savedVisibility = _cachedCursorVisibility;
         SetCursorVisibility (CursorVisibility.Invisible);
 
         for (int row = top; row < rows; row++)
@@ -63,6 +101,8 @@ public abstract class OutputBase
                             lastCol++;
                         }
 
+                        SetCursorPositionImpl (lastCol, row);
+
                         continue;
                     }
 
@@ -82,27 +122,41 @@ public abstract class OutputBase
 
             if (output.Length > 0)
             {
-                SetCursorPositionImpl (lastCol, row);
+                if (IsLegacyConsole)
+                {
+                    Write (output);
+                }
+                else
+                {
+                    SetCursorPositionImpl (lastCol, row);
+
+                    // Wrap URLs with OSC 8 hyperlink sequences using the new Osc8UrlLinker
+                    StringBuilder processed = Osc8UrlLinker.WrapOsc8 (output);
+                    Write (processed);
+                }
+            }
+        }
+
+        if (IsLegacyConsole)
+        {
+            return;
+        }
 
-                // Wrap URLs with OSC 8 hyperlink sequences using the new Osc8UrlLinker
-                StringBuilder processed = Osc8UrlLinker.WrapOsc8 (output);
-                Write (processed);
+        foreach (SixelToRender s in GetSixels ())
+        {
+            if (string.IsNullOrWhiteSpace (s.SixelData))
+            {
+                continue;
             }
+
+            SetCursorPositionImpl (s.ScreenPosition.X, s.ScreenPosition.Y);
+            Write ((StringBuilder)new (s.SixelData));
         }
 
-        // BUGBUG: The Sixel impl depends on the legacy static Application object
-        // BUGBUG: Disabled for now
-        //foreach (SixelToRender s in  Application.Sixel)
-        //{
-        //    if (!string.IsNullOrWhiteSpace (s.SixelData))
-        //    {
-        //        SetCursorPositionImpl (s.ScreenPosition.X, s.ScreenPosition.Y);
-        //        Console.Out.Write (s.SixelData);
-        //    }
-        //}
-
-        SetCursorVisibility (savedVisibility ?? CursorVisibility.Default);
-        _cachedCursorVisibility = savedVisibility;
+
+        // DO NOT restore cursor visibility here - let ApplicationMainLoop.SetCursor() handle it
+        // The old code was saving/restoring visibility which caused flickering because
+        // it would restore to the old value even if the application wanted it hidden
     }
 
     /// <summary>
@@ -166,7 +220,7 @@ public abstract class OutputBase
                     continue;
                 }
 
-                Cell cell = buffer.Contents![row, col];
+                Cell cell = buffer.Contents! [row, col];
                 AppendCellAnsi (cell, output, ref lastAttr, ref redrawTextStyle, endCol, ref col);
             }
 
@@ -228,11 +282,16 @@ public abstract class OutputBase
 
     private void WriteToConsole (StringBuilder output, ref int lastCol, int row, ref int outputWidth)
     {
-        SetCursorPositionImpl (lastCol, row);
-
-        // Wrap URLs with OSC 8 hyperlink sequences using the new Osc8UrlLinker
-        StringBuilder processed = Osc8UrlLinker.WrapOsc8 (output);
-        Write (processed);
+        if (IsLegacyConsole)
+        {
+            Write (output);
+        }
+        else
+        {
+            // Wrap URLs with OSC 8 hyperlink sequences using the new Osc8UrlLinker
+            StringBuilder processed = Osc8UrlLinker.WrapOsc8 (output);
+            Write (processed);
+        }
 
         output.Clear ();
         lastCol += outputWidth;

+ 1 - 1
Terminal.Gui/Drivers/UnixDriver/UnixOutput.cs

@@ -39,7 +39,7 @@ internal class UnixOutput : OutputBase, IOutput
     /// <inheritdoc />
     protected override void AppendOrWriteAttribute (StringBuilder output, Attribute attr, TextStyle redrawTextStyle)
     {
-        if (Application.Force16Colors)
+        if (Force16Colors)
         {
             output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
             output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));

+ 75 - 99
Terminal.Gui/Drivers/WindowsDriver/WindowsOutput.cs

@@ -97,13 +97,12 @@ internal partial class WindowsOutput : OutputBase, IOutput
     private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;
     private readonly nint _outputHandle;
     private nint _screenBuffer;
-    private readonly bool _isVirtualTerminal;
     private readonly ConsoleColor _foreground;
     private readonly ConsoleColor _background;
 
     public WindowsOutput ()
     {
-        Logging.Logger.LogInformation ($"Creating {nameof (WindowsOutput)}");
+        Logging.Information ($"Creating {nameof (WindowsOutput)}");
 
         if (!RuntimeInformation.IsOSPlatform (OSPlatform.Windows))
         {
@@ -113,22 +112,9 @@ internal partial class WindowsOutput : OutputBase, IOutput
         // Get the standard output handle which is the current screen buffer.
         _outputHandle = GetStdHandle (STD_OUTPUT_HANDLE);
         GetConsoleMode (_outputHandle, out uint mode);
-        _isVirtualTerminal = (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0;
+        IsLegacyConsole = (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0;
 
-        if (_isVirtualTerminal)
-        {
-            if (Environment.GetEnvironmentVariable ("VSAPPIDNAME") is null)
-            {
-                //Enable alternative screen buffer.
-                Console.Out.Write (EscSeqUtils.CSI_SaveCursorAndActivateAltBufferNoBackscroll);
-            }
-            else
-            {
-                _foreground = Console.ForegroundColor;
-                _background = Console.BackgroundColor;
-            }
-        }
-        else
+        if (IsLegacyConsole)
         {
             CreateScreenBuffer ();
 
@@ -145,12 +131,19 @@ internal partial class WindowsOutput : OutputBase, IOutput
             {
                 throw new ApplicationException ($"Failed to set screenBuffer console mode, error code: {Marshal.GetLastWin32Error ()}.");
             }
-
-            // Force 16 colors if not in virtual terminal mode.
-            // BUGBUG: This is bad. It does not work if the app was crated without
-            // BUGBUG: Apis.
-            //ApplicationImpl.Instance.Force16Colors = true;
-
+        }
+        else
+        {
+            if (Environment.GetEnvironmentVariable ("VSAPPIDNAME") is null)
+            {
+                //Enable alternative screen buffer.
+                Console.Out.Write (EscSeqUtils.CSI_SaveCursorAndActivateAltBufferNoBackscroll);
+            }
+            else
+            {
+                _foreground = Console.ForegroundColor;
+                _background = Console.BackgroundColor;
+            }
         }
 
         GetSize ();
@@ -189,7 +182,7 @@ internal partial class WindowsOutput : OutputBase, IOutput
             return;
         }
 
-        if (!WriteConsole (_isVirtualTerminal ? _outputHandle : _screenBuffer, str, (uint)str.Length, out uint _, nint.Zero))
+        if (!WriteConsole (!IsLegacyConsole ? _outputHandle : _screenBuffer, str, (uint)str.Length, out uint _, nint.Zero))
         {
             throw new Win32Exception (Marshal.GetLastWin32Error (), "Failed to write to console screen buffer.");
         }
@@ -220,19 +213,19 @@ internal partial class WindowsOutput : OutputBase, IOutput
         var csbi = new WindowsConsole.CONSOLE_SCREEN_BUFFER_INFOEX ();
         csbi.cbSize = (uint)Marshal.SizeOf (csbi);
 
-        if (!GetConsoleScreenBufferInfoEx (_isVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
+        if (!GetConsoleScreenBufferInfoEx (!IsLegacyConsole ? _outputHandle : _screenBuffer, ref csbi))
         {
             throw new Win32Exception (Marshal.GetLastWin32Error ());
         }
 
-        WindowsConsole.Coord maxWinSize = GetLargestConsoleWindowSize (_isVirtualTerminal ? _outputHandle : _screenBuffer);
+        WindowsConsole.Coord maxWinSize = GetLargestConsoleWindowSize (!IsLegacyConsole ? _outputHandle : _screenBuffer);
         short newCols = Math.Min (cols, maxWinSize.X);
         short newRows = Math.Min (rows, maxWinSize.Y);
         csbi.dwSize = new (newCols, Math.Max (newRows, (short)1));
         csbi.srWindow = new (0, 0, newCols, newRows);
         csbi.dwMaximumWindowSize = new (newCols, newRows);
 
-        if (!SetConsoleScreenBufferInfoEx (_isVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
+        if (!SetConsoleScreenBufferInfoEx (!IsLegacyConsole ? _outputHandle : _screenBuffer, ref csbi))
         {
             throw new Win32Exception (Marshal.GetLastWin32Error ());
         }
@@ -252,11 +245,11 @@ internal partial class WindowsOutput : OutputBase, IOutput
 
     private void SetConsoleOutputWindow (WindowsConsole.CONSOLE_SCREEN_BUFFER_INFOEX csbi)
     {
-        if ((_isVirtualTerminal
+        if ((!IsLegacyConsole
                  ? _outputHandle
                  : _screenBuffer)
             != nint.Zero
-            && !SetConsoleScreenBufferInfoEx (_isVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
+            && !SetConsoleScreenBufferInfoEx (!IsLegacyConsole ? _outputHandle : _screenBuffer, ref csbi))
         {
             throw new Win32Exception (Marshal.GetLastWin32Error ());
         }
@@ -264,65 +257,52 @@ internal partial class WindowsOutput : OutputBase, IOutput
 
     public override void Write (IOutputBuffer outputBuffer)
     {
-        // BUGBUG: This is bad. It does not work if the app was crated without
-        // BUGBUG: Apis.
-        //_force16Colors = ApplicationImpl.Instance.Driver!.Force16Colors;
-        _force16Colors = false;
         _everythingStringBuilder.Clear ();
 
-        // for 16 color mode we will write to a backing buffer then flip it to the active one at the end to avoid jitter.
+        // for 16 color mode we will write to a backing buffer, then flip it to the active one at the end to avoid jitter.
         _consoleBuffer = 0;
 
-        if (_force16Colors)
+        if (Force16Colors)
         {
-            if (_isVirtualTerminal)
-            {
-                _consoleBuffer = _outputHandle;
-            }
-            else
-            {
-                _consoleBuffer = _screenBuffer;
-            }
+            _consoleBuffer = !IsLegacyConsole ? _outputHandle : _screenBuffer;
         }
         else
         {
             _consoleBuffer = _outputHandle;
         }
 
-        base.Write (outputBuffer);
-
         try
         {
-            if (_force16Colors && !_isVirtualTerminal)
-            {
-                SetConsoleActiveScreenBuffer (_consoleBuffer);
-            }
-            else
+            base.Write (outputBuffer);
+
+            ReadOnlySpan<char> span = _everythingStringBuilder.ToString ().AsSpan (); // still allocates the string
+
+            bool result = WriteConsole (_consoleBuffer, span, (uint)span.Length, out _, nint.Zero);
+
+            if (!result)
             {
-                ReadOnlySpan<char> span = _everythingStringBuilder.ToString ().AsSpan (); // still allocates the string
+                int err = Marshal.GetLastWin32Error ();
+
+                if (err == 1)
+                {
+                    Logging.Error ($"Error: {Marshal.GetLastWin32Error ()} in {nameof (WindowsOutput)}");
 
-                bool result = WriteConsole (_consoleBuffer, span, (uint)span.Length, out _, nint.Zero);
+                    return;
+                }
 
-                if (!result)
+                if (err != 0)
                 {
-                    int err = Marshal.GetLastWin32Error ();
-
-                    if (err == 1)
-                    {
-                        Logging.Logger.LogError ($"Error: {Marshal.GetLastWin32Error ()} in {nameof (WindowsOutput)}");
-
-                        return;
-                    }
-                    if (err != 0)
-                    {
-                        throw new Win32Exception (err);
-                    }
+                    throw new Win32Exception (err);
                 }
             }
         }
+        catch (DllNotFoundException)
+        {
+            // Running unit tests or in an environment where writing is not possible.
+        }
         catch (Exception e)
         {
-            Logging.Logger.LogError ($"Error: {e.Message} in {nameof (WindowsOutput)}");
+            Logging.Error ($"Error: {e.Message} in {nameof (WindowsOutput)}");
 
             if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows))
             {
@@ -341,7 +321,7 @@ internal partial class WindowsOutput : OutputBase, IOutput
 
         var str = output.ToString ();
 
-        if (_force16Colors && !_isVirtualTerminal)
+        if (Force16Colors && IsLegacyConsole)
         {
             char [] a = str.ToCharArray ();
             WriteConsole (_screenBuffer, a, (uint)a.Length, out _, nint.Zero);
@@ -355,23 +335,20 @@ internal partial class WindowsOutput : OutputBase, IOutput
     /// <inheritdoc/>
     protected override void AppendOrWriteAttribute (StringBuilder output, Attribute attr, TextStyle redrawTextStyle)
     {
-        // BUGBUG: This is bad. It does not work if the app was crated without
-        // BUGBUG: Apis.
-        // bool force16Colors = ApplicationImpl.Instance.Force16Colors;
-        bool force16Colors = false;
-
-        if (force16Colors)
+        if (Force16Colors)
         {
-            if (_isVirtualTerminal)
+            if (IsLegacyConsole)
             {
-                output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
-                output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));
-                EscSeqUtils.CSI_AppendTextStyleChange (output, redrawTextStyle, attr.Style);
+                Write (output);
+                output.Clear ();
+                var as16ColorInt = (ushort)((int)attr.Foreground.GetClosestNamedColor16 () | ((int)attr.Background.GetClosestNamedColor16 () << 4));
+                SetConsoleTextAttribute (_screenBuffer, as16ColorInt);
             }
             else
             {
-                var as16ColorInt = (ushort)((int)attr.Foreground.GetClosestNamedColor16 () | ((int)attr.Background.GetClosestNamedColor16 () << 4));
-                SetConsoleTextAttribute (_screenBuffer, as16ColorInt);
+                output.Append (EscSeqUtils.CSI_SetForegroundColor (attr.Foreground.GetAnsiColorCode ()));
+                output.Append (EscSeqUtils.CSI_SetBackgroundColor (attr.Background.GetAnsiColorCode ()));
+                EscSeqUtils.CSI_AppendTextStyleChange (output, redrawTextStyle, attr.Style);
             }
         }
         else
@@ -438,7 +415,7 @@ internal partial class WindowsOutput : OutputBase, IOutput
             var csbi = new WindowsConsole.CONSOLE_SCREEN_BUFFER_INFOEX ();
             csbi.cbSize = (uint)Marshal.SizeOf (csbi);
 
-            if (!GetConsoleScreenBufferInfoEx (_isVirtualTerminal ? _outputHandle : _screenBuffer, ref csbi))
+            if (!GetConsoleScreenBufferInfoEx (!IsLegacyConsole ? _outputHandle : _screenBuffer, ref csbi))
             {
                 //throw new System.ComponentModel.Win32Exception (Marshal.GetLastWin32Error ());
                 cursorPosition = default (WindowsConsole.Coord);
@@ -468,7 +445,7 @@ internal partial class WindowsOutput : OutputBase, IOutput
 
         try
         {
-            maxWinSize = GetLargestConsoleWindowSize (_isVirtualTerminal ? _outputHandle : _screenBuffer);
+            maxWinSize = GetLargestConsoleWindowSize (!IsLegacyConsole ? _outputHandle : _screenBuffer);
         }
         catch
         {
@@ -481,7 +458,7 @@ internal partial class WindowsOutput : OutputBase, IOutput
     /// <inheritdoc/>
     protected override bool SetCursorPositionImpl (int screenPositionX, int screenPositionY)
     {
-        if (_force16Colors && !_isVirtualTerminal)
+        if (Force16Colors && IsLegacyConsole)
         {
             SetConsoleCursorPosition (_screenBuffer, new ((short)screenPositionX, (short)screenPositionY));
         }
@@ -505,7 +482,7 @@ internal partial class WindowsOutput : OutputBase, IOutput
             return;
         }
 
-        if (!_isVirtualTerminal)
+        if (IsLegacyConsole)
         {
             var info = new WindowsConsole.ConsoleCursorInfo
             {
@@ -539,15 +516,15 @@ internal partial class WindowsOutput : OutputBase, IOutput
 
         _lastCursorPosition = new (col, row);
 
-        if (_isVirtualTerminal)
+        if (IsLegacyConsole)
         {
-            var sb = new StringBuilder ();
-            EscSeqUtils.CSI_AppendCursorPosition (sb, row + 1, col + 1);
-            Write (sb.ToString ());
+            SetConsoleCursorPosition (_screenBuffer, new ((short)col, (short)row));
         }
         else
         {
-            SetConsoleCursorPosition (_screenBuffer, new ((short)col, (short)row));
+            var sb = new StringBuilder ();
+            EscSeqUtils.CSI_AppendCursorPosition (sb, row + 1, col + 1);
+            Write (sb.ToString ());
         }
     }
 
@@ -558,7 +535,6 @@ internal partial class WindowsOutput : OutputBase, IOutput
     }
 
     private bool _isDisposed;
-    private bool _force16Colors;
     private nint _consoleBuffer;
     private readonly StringBuilder _everythingStringBuilder = new ();
 
@@ -570,7 +546,16 @@ internal partial class WindowsOutput : OutputBase, IOutput
             return;
         }
 
-        if (_isVirtualTerminal)
+        if (IsLegacyConsole)
+        {
+            if (_screenBuffer != nint.Zero)
+            {
+                CloseHandle (_screenBuffer);
+            }
+
+            _screenBuffer = nint.Zero;
+        }
+        else
         {
             if (Environment.GetEnvironmentVariable ("VSAPPIDNAME") is null)
             {
@@ -585,15 +570,6 @@ internal partial class WindowsOutput : OutputBase, IOutput
                 Console.Clear ();
             }
         }
-        else
-        {
-            if (_screenBuffer != nint.Zero)
-            {
-                CloseHandle (_screenBuffer);
-            }
-
-            _screenBuffer = nint.Zero;
-        }
 
         _isDisposed = true;
     }

+ 5 - 5
Terminal.Gui/Resources/config.json

@@ -19,8 +19,8 @@
   // --------------- Application Settings ---------------
   "Key.Separator": "+",
 
+  "Driver.Force16Colors": false,
   "Application.ArrangeKey": "Ctrl+F5",
-  "Application.Force16Colors": false,
   //"Application.ForceDriver": "", // TODO: ForceDriver should be nullable
   "Application.IsMouseDisabled": false,
   "Application.NextTabGroupKey": "F6",
@@ -136,14 +136,14 @@
                 "Foreground": "White",
                 "Background": "DarkBlue"
               }
-            },
+            }
           },
           {
             "Dialog": {
               "Normal": {
                 "Foreground": "BrightBlue",
                 "Background": "LightGray"
-              },
+              }
             }
           },
           {
@@ -152,7 +152,7 @@
                 "Foreground": "White",
                 "Background": "Blue",
                 "Style": "Bold"
-              },
+              }
             }
           },
           {
@@ -161,7 +161,7 @@
                 "Foreground": "Red",
                 "Background": "WhiteSmoke",
                 "Style": "Italic"
-              },
+              }
             }
           }
         ],

+ 76 - 26
Terminal.Gui/Text/TextFormatter.cs

@@ -123,11 +123,31 @@ public class TextFormatter
             }
 
             string strings = linesFormatted [line];
-            string[] graphemes = GraphemeHelper.GetGraphemes (strings).ToArray ();
+            
+            // Use ArrayPool to avoid per-draw allocations
+            int estimatedCount = strings.Length + 10; // Add buffer for grapheme clusters
+            string [] graphemes = ArrayPool<string>.Shared.Rent (estimatedCount);
+            var graphemeCount = 0;
 
-            // When text is justified, we lost left or right, so we use the direction to align.
+            try
+            {
+                foreach (string grapheme in GraphemeHelper.GetGraphemes (strings))
+                {
+                    if (graphemeCount >= graphemes.Length)
+                    {
+                        // Need larger array (rare case for complex text)
+                        string [] larger = ArrayPool<string>.Shared.Rent (graphemes.Length * 2);
+                        Array.Copy (graphemes, larger, graphemeCount);
+                        ArrayPool<string>.Shared.Return (graphemes, clearArray: true);
+                        graphemes = larger;
+                    }
+
+                    graphemes [graphemeCount++] = grapheme;
+                }
+
+                // When text is justified, we lost left or right, so we use the direction to align.
 
-            int x = 0, y = 0;
+                int x = 0, y = 0;
 
             // Horizontal Alignment
             if (Alignment is Alignment.End)
@@ -214,7 +234,7 @@ public class TextFormatter
             {
                 if (isVertical)
                 {
-                    y = screen.Bottom - graphemes.Length;
+                    y = screen.Bottom - graphemeCount;
                 }
                 else
                 {
@@ -250,7 +270,7 @@ public class TextFormatter
             {
                 if (isVertical)
                 {
-                    int s = (screen.Height - graphemes.Length) / 2;
+                    int s = (screen.Height - graphemeCount) / 2;
                     y = screen.Top + s;
                 }
                 else
@@ -292,17 +312,17 @@ public class TextFormatter
                         continue;
                     }
 
-                    if (!FillRemaining && idx > graphemes.Length - 1)
+                    if (!FillRemaining && idx > graphemeCount - 1)
                     {
                         break;
                     }
 
                     if ((!isVertical
                          && (current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset
-                             || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width)))
+                             || (idx < graphemeCount && graphemes [idx].GetColumns () > screen.Width)))
                         || (isVertical
                             && ((current > start + size + zeroLengthCount && idx > maxScreen.Top + maxScreen.Height - screen.Y)
-                                || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width))))
+                                || (idx < graphemeCount && graphemes [idx].GetColumns () > screen.Width))))
                     {
                         break;
                     }
@@ -317,7 +337,7 @@ public class TextFormatter
 
                 if (isVertical)
                 {
-                    if (idx >= 0 && idx < graphemes.Length)
+                    if (idx >= 0 && idx < graphemeCount)
                     {
                         text = graphemes [idx];
                     }
@@ -368,7 +388,7 @@ public class TextFormatter
                 {
                     driver?.Move (current, y);
 
-                    if (idx >= 0 && idx < graphemes.Length)
+                    if (idx >= 0 && idx < graphemeCount)
                     {
                         text = graphemes [idx];
                     }
@@ -428,15 +448,20 @@ public class TextFormatter
                     current += runeWidth;
                 }
 
-                int nextRuneWidth = idx + 1 > -1 && idx + 1 < graphemes.Length
+                int nextRuneWidth = idx + 1 > -1 && idx + 1 < graphemeCount
                                         ? graphemes [idx + 1].GetColumns ()
                                         : 0;
 
-                if (!isVertical && idx + 1 < graphemes.Length && current + nextRuneWidth > start + size)
+                if (!isVertical && idx + 1 < graphemeCount && current + nextRuneWidth > start + size)
                 {
                     break;
                 }
             }
+            }
+            finally
+            {
+                ArrayPool<string>.Shared.Return (graphemes, clearArray: true);
+            }
         }
     }
 
@@ -931,10 +956,30 @@ public class TextFormatter
             }
 
             string strings = linesFormatted [line];
-            string [] graphemes = GraphemeHelper.GetGraphemes (strings).ToArray ();
+            
+            // Use ArrayPool to avoid per-line allocations
+            int estimatedCount = strings.Length + 10; // Add buffer for grapheme clusters
+            string [] graphemes = ArrayPool<string>.Shared.Rent (estimatedCount);
+            var graphemeCount = 0;
 
-            // When text is justified, we lost left or right, so we use the direction to align.
-            int x = 0, y = 0;
+            try
+            {
+                foreach (string grapheme in GraphemeHelper.GetGraphemes (strings))
+                {
+                    if (graphemeCount >= graphemes.Length)
+                    {
+                        // Need larger array (rare case for complex text)
+                        string [] larger = ArrayPool<string>.Shared.Rent (graphemes.Length * 2);
+                        Array.Copy (graphemes, larger, graphemeCount);
+                        ArrayPool<string>.Shared.Return (graphemes, clearArray: true);
+                        graphemes = larger;
+                    }
+
+                    graphemes [graphemeCount++] = grapheme;
+                }
+
+                // When text is justified, we lost left or right, so we use the direction to align.
+                int x = 0, y = 0;
 
             switch (Alignment)
             {
@@ -1011,7 +1056,7 @@ public class TextFormatter
             {
                 // Vertical Alignment
                 case Alignment.End when isVertical:
-                    y = screen.Bottom - graphemes.Length;
+                    y = screen.Bottom - graphemeCount;
 
                     break;
                 case Alignment.End:
@@ -1041,7 +1086,7 @@ public class TextFormatter
                     }
                 case Alignment.Center when isVertical:
                     {
-                        int s = (screen.Height - graphemes.Length) / 2;
+                        int s = (screen.Height - graphemeCount) / 2;
                         y = screen.Top + s;
 
                         break;
@@ -1081,22 +1126,22 @@ public class TextFormatter
                     continue;
                 }
 
-                if (!FillRemaining && idx > graphemes.Length - 1)
+                if (!FillRemaining && idx > graphemeCount - 1)
                 {
                     break;
                 }
 
                 if ((!isVertical
                      && (current - start > maxScreen.Left + maxScreen.Width - screen.X + colOffset
-                         || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width)))
+                         || (idx < graphemeCount && graphemes [idx].GetColumns () > screen.Width)))
                     || (isVertical
                         && ((current > start + size + zeroLengthCount && idx > maxScreen.Top + maxScreen.Height - screen.Y)
-                            || (idx < graphemes.Length && graphemes [idx].GetColumns () > screen.Width))))
+                            || (idx < graphemeCount && graphemes [idx].GetColumns () > screen.Width))))
                 {
                     break;
                 }
 
-                string text = idx >= 0 && idx < graphemes.Length ? graphemes [idx] : " ";
+                string text = idx >= 0 && idx < graphemeCount ? graphemes [idx] : " ";
                 int runeWidth = GetStringWidth (text, TabWidth);
 
                 if (isVertical)
@@ -1116,20 +1161,25 @@ public class TextFormatter
 
                 current += isVertical && runeWidth > 0 ? 1 : runeWidth;
 
-                int nextStringWidth = idx + 1 > -1 && idx + 1 < graphemes.Length
+                int nextStringWidth = idx + 1 > -1 && idx + 1 < graphemeCount
                                         ? graphemes [idx + 1].GetColumns ()
                                         : 0;
 
-                if (!isVertical && idx + 1 < graphemes.Length && current + nextStringWidth > start + size)
+                if (!isVertical && idx + 1 < graphemeCount && current + nextStringWidth > start + size)
                 {
                     break;
                 }
             }
 
-            // Add the line's drawn region to the overall region
-            if (lineWidth > 0 && lineHeight > 0)
+                // Add the line's drawn region to the overall region
+                if (lineWidth > 0 && lineHeight > 0)
+                {
+                    drawnRegion.Union (new Rectangle (lineX, lineY, lineWidth, lineHeight));
+                }
+            }
+            finally
             {
-                drawnRegion.Union (new Rectangle (lineX, lineY, lineWidth, lineHeight));
+                ArrayPool<string>.Shared.Return (graphemes, clearArray: true);
             }
         }
 

+ 2 - 2
Terminal.Gui/ViewBase/Adornment/Adornment.cs

@@ -88,7 +88,7 @@ public class Adornment : View, IDesignable
     protected override IApplication? GetApp () => Parent?.App;
 
     /// <inheritdoc />
-    protected override IDriver? GetDriver () => Parent?.Driver ?? base.GetDriver();
+    protected override IDriver? GetDriver () => Parent?.Driver ?? base.GetDriver ();
 
     // If a scheme is explicitly set, use that. Otherwise, use the scheme of the parent view.
     private Scheme? _scheme;
@@ -187,7 +187,7 @@ public class Adornment : View, IDesignable
             Thickness.Draw (Driver, ViewportToScreen (Viewport), Diagnostics, ToString ());
         }
 
-        NeedsDraw = true;
+        SetNeedsDraw ();
 
         return true;
     }

+ 1 - 3
Terminal.Gui/ViewBase/Adornment/Border.cs

@@ -241,7 +241,7 @@ public partial class Border : Adornment
 
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         if (Thickness == Thickness.Empty)
         {
@@ -539,8 +539,6 @@ public partial class Border : Adornment
         }
 
         return true;
-
-        ;
     }
 
     /// <summary>

+ 10 - 10
Terminal.Gui/ViewBase/Adornment/Margin.cs

@@ -1,5 +1,6 @@
 
 
+using System.Diagnostics;
 using System.Runtime.InteropServices;
 
 namespace Terminal.Gui.ViewBase;
@@ -62,7 +63,6 @@ public class Margin : Adornment
         }
     }
 
-    // PERFORMANCE: Margins are ALWAYS drawn. This may be an issue for apps that have a large number of views with shadows.
     /// <summary>
     ///     INTERNAL API - Draws the margins for the specified views. This is called by the <see cref="Application"/> on each
     ///     iteration of the main loop after all Views have been drawn.
@@ -75,21 +75,21 @@ public class Margin : Adornment
 
         while (stack.Count > 0)
         {
-            var view = stack.Pop ();
+            View view = stack.Pop ();
 
-            if (view.Margin?.GetCachedClip () != null)
+            if (view.Margin is { } margin && margin.Thickness != Thickness.Empty && margin.GetCachedClip () != null)
             {
-                view.Margin!.NeedsDraw = true;
+                margin.SetNeedsDraw ();
                 Region? saved = view.GetClip ();
-                view.SetClip (view.Margin!.GetCachedClip ());
-                view.Margin!.Draw (); 
+                view.SetClip (margin.GetCachedClip ());
+                margin.Draw ();
                 view.SetClip (saved);
-                view.Margin!.ClearCachedClip ();
+                margin.ClearCachedClip ();
             }
 
-            view.NeedsDraw = false;
+            view.ClearNeedsDraw ();
 
-            foreach (var subview in view.SubViews)
+            foreach (View subview in view.SubViews)
             {
                 stack.Push (subview);
             }
@@ -225,7 +225,7 @@ public class Margin : Adornment
             return;
         }
 
-        bool pressed = args.Value.HasFlag (MouseState.Pressed) && parent.HighlightStates.HasFlag(MouseState.Pressed);
+        bool pressed = args.Value.HasFlag (MouseState.Pressed) && parent.HighlightStates.HasFlag (MouseState.Pressed);
         bool pressedOutside = args.Value.HasFlag (MouseState.PressedOutside) && parent.HighlightStates.HasFlag (MouseState.PressedOutside); ;
 
         if (pressedOutside)

+ 1 - 1
Terminal.Gui/ViewBase/Adornment/ShadowView.cs

@@ -20,7 +20,7 @@ internal class ShadowView : View
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         switch (ShadowStyle)
         {

+ 58 - 6
Terminal.Gui/ViewBase/DrawContext.cs

@@ -1,10 +1,43 @@
-
-namespace Terminal.Gui.ViewBase;
+namespace Terminal.Gui.ViewBase;
 
 /// <summary>
 ///     Tracks the region that has been drawn during <see cref="View.Draw(DrawContext?)"/>. This is primarily
 ///     in support of <see cref="ViewportSettingsFlags.Transparent"/>.
 /// </summary>
+/// <remarks>
+///     <para>
+///         When a <see cref="View"/> has <see cref="ViewportSettingsFlags.Transparent"/> set, the <see cref="DrawContext"/>
+///         is used to track exactly which areas of the screen have been drawn to. After drawing is complete, these drawn
+///         regions are excluded from the clip region, allowing views beneath the transparent view to show through in
+///         the areas that were not drawn.
+///     </para>
+///     <para>
+///         All coordinates tracked by <see cref="DrawContext"/> are in <b>screen-relative coordinates</b>. When reporting
+///         drawn areas from within <see cref="View.OnDrawingContent(DrawContext?)"/>, use <see cref="View.ViewportToScreen(in Rectangle)"/>
+///         or <see cref="View.ContentToScreen(in Point)"/> to convert viewport-relative or content-relative coordinates to
+///         screen-relative coordinates before calling <see cref="AddDrawnRectangle"/> or <see cref="AddDrawnRegion"/>.
+///     </para>
+///     <para>
+///         Example of reporting a non-rectangular drawn region for transparency:
+///     </para>
+///     <code>
+///         protected override bool OnDrawingContent (DrawContext? context)
+///         {
+///             // Draw some content in viewport-relative coordinates
+///             Rectangle rect1 = new Rectangle (5, 5, 10, 3);
+///             Rectangle rect2 = new Rectangle (8, 8, 4, 7);
+///             FillRect (rect1, Glyphs.BlackCircle);
+///             FillRect (rect2, Glyphs.BlackCircle);
+///             
+///             // Report the drawn region in screen-relative coordinates
+///             Region drawnRegion = new Region (ViewportToScreen (rect1));
+///             drawnRegion.Union (ViewportToScreen (rect2));
+///             context?.AddDrawnRegion (drawnRegion);
+///             
+///             return true;
+///         }
+///     </code>
+/// </remarks>
 public class DrawContext
 {
     private readonly Region _drawnRegion = new Region ();
@@ -12,12 +45,20 @@ public class DrawContext
     /// <summary>
     /// Gets a copy of the region drawn so far in this context.
     /// </summary>
+    /// <remarks>
+    ///     The returned region contains all areas that have been reported as drawn via <see cref="AddDrawnRectangle"/>
+    ///     or <see cref="AddDrawnRegion"/>, in screen-relative coordinates.
+    /// </remarks>
     public Region GetDrawnRegion () => _drawnRegion.Clone ();
 
     /// <summary>
     /// Reports that a rectangle has been drawn.
     /// </summary>
-    /// <param name="rect">The rectangle that was drawn.</param>
+    /// <param name="rect">The rectangle that was drawn, in screen-relative coordinates.</param>
+    /// <remarks>
+    ///     When called from within <see cref="View.OnDrawingContent(DrawContext?)"/>, ensure the rectangle is in
+    ///     screen-relative coordinates by using <see cref="View.ViewportToScreen(in Rectangle)"/> or similar methods.
+    /// </remarks>
     public void AddDrawnRectangle (Rectangle rect)
     {
         _drawnRegion.Combine (rect, RegionOp.Union);
@@ -26,7 +67,18 @@ public class DrawContext
     /// <summary>
     /// Reports that a region has been drawn.
     /// </summary>
-    /// <param name="region">The region that was drawn.</param>
+    /// <param name="region">The region that was drawn, in screen-relative coordinates.</param>
+    /// <remarks>
+    ///     <para>
+    ///         This method is useful for reporting non-rectangular drawn areas, which is important for
+    ///         proper transparency support with <see cref="ViewportSettingsFlags.Transparent"/>.
+    ///     </para>
+    ///     <para>
+    ///         When called from within <see cref="View.OnDrawingContent(DrawContext?)"/>, ensure the region is in
+    ///         screen-relative coordinates by using <see cref="View.ViewportToScreen(in Rectangle)"/> to convert each
+    ///         rectangle in the region.
+    ///     </para>
+    /// </remarks>
     public void AddDrawnRegion (Region region)
     {
         _drawnRegion.Combine (region, RegionOp.Union);
@@ -36,7 +88,7 @@ public class DrawContext
     /// Clips (intersects) the drawn region with the specified rectangle.
     /// This modifies the internal drawn region directly.
     /// </summary>
-    /// <param name="clipRect">The clipping rectangle.</param>
+    /// <param name="clipRect">The clipping rectangle, in screen-relative coordinates.</param>
     public void ClipDrawnRegion (Rectangle clipRect)
     {
         _drawnRegion.Intersect (clipRect);
@@ -46,7 +98,7 @@ public class DrawContext
     /// Clips (intersects) the drawn region with the specified region.
     /// This modifies the internal drawn region directly.
     /// </summary>
-    /// <param name="clipRegion">The clipping region.</param>
+    /// <param name="clipRegion">The clipping region, in screen-relative coordinates.</param>
     public void ClipDrawnRegion (Region clipRegion)
     {
         _drawnRegion.Intersect (clipRegion);

+ 10 - 10
Terminal.Gui/ViewBase/Runnable/Runnable.cs

@@ -170,16 +170,6 @@ public class Runnable : View, IRunnable
     /// <inheritdoc/>
     public void RaiseIsModalChangedEvent (bool newIsModal)
     {
-        // CWP Phase 3: Post-notification (work already done by Application)
-        OnIsModalChanged (newIsModal);
-
-        EventArgs<bool> args = new (newIsModal);
-        IsModalChanged?.Invoke (this, args);
-
-        // Layout may need to change when modal state changes
-        SetNeedsLayout ();
-        SetNeedsDraw ();
-
         if (newIsModal)
         {
             // Set focus to self if becoming modal
@@ -194,6 +184,16 @@ public class Runnable : View, IRunnable
                 App?.Driver?.UpdateCursor ();
             }
         }
+
+        // CWP Phase 3: Post-notification (work already done by Application)
+        OnIsModalChanged (newIsModal);
+
+        EventArgs<bool> args = new (newIsModal);
+        IsModalChanged?.Invoke (this, args);
+
+        // Layout may need to change when modal state changes
+        SetNeedsLayout ();
+        SetNeedsDraw ();
     }
 
     /// <inheritdoc/>

+ 49 - 0
Terminal.Gui/ViewBase/View.Command.cs

@@ -141,6 +141,13 @@ public partial class View // Command APIs
             Accepting?.Invoke (this, args);
         }
 
+        // If Accepting was handled, raise Accepted (non-cancelable event)
+        if (args.Handled)
+        {
+            Logging.Debug ($"{Title} ({ctx?.Source?.Title}) - Calling RaiseAccepted");
+            RaiseAccepted (ctx);
+        }
+
         // Accept is a special case where if the event is not canceled, the event is
         //  - Invoked on any peer-View with IsDefault == true
         //  - bubbled up the SuperView hierarchy.
@@ -201,6 +208,48 @@ public partial class View // Command APIs
     /// </remarks>
     public event EventHandler<CommandEventArgs>? Accepting;
 
+    /// <summary>
+    ///     Raises the <see cref="OnAccepted"/>/<see cref="Accepted"/> event indicating the View has been accepted.
+    ///     This is called after <see cref="Accepting"/> has been raised and not cancelled.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Unlike <see cref="Accepting"/>, this event cannot be cancelled. It is raised after the View has been accepted.
+    ///     </para>
+    /// </remarks>
+    /// <param name="ctx">The command context.</param>
+    protected void RaiseAccepted (ICommandContext? ctx)
+    {
+        CommandEventArgs args = new () { Context = ctx };
+
+        OnAccepted (args);
+        Accepted?.Invoke (this, args);
+    }
+
+    /// <summary>
+    ///     Called when the View has been accepted. This is called after <see cref="Accepting"/> has been raised and not cancelled.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Unlike <see cref="OnAccepting"/>, this method is called after the View has been accepted and cannot cancel the operation.
+    ///     </para>
+    /// </remarks>
+    /// <param name="args">The event arguments.</param>
+    protected virtual void OnAccepted (CommandEventArgs args) { }
+
+    /// <summary>
+    ///     Event raised when the View has been accepted. This is raised after <see cref="Accepting"/> has been raised and not cancelled.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///         Unlike <see cref="Accepting"/>, this event cannot be cancelled. It is raised after the View has been accepted.
+    ///     </para>
+    ///     <para>
+    ///         See <see cref="RaiseAccepted"/> for more information.
+    ///     </para>
+    /// </remarks>
+    public event EventHandler<CommandEventArgs>? Accepted;
+
     /// <summary>
     ///     Called when the user has performed an action (e.g. <see cref="Command.Select"/>) causing the View to change state.
     ///     Calls <see cref="OnSelecting"/> which can be cancelled; if not cancelled raises <see cref="Accepting"/>.

+ 1 - 1
Terminal.Gui/ViewBase/View.Content.cs

@@ -335,7 +335,7 @@ public partial class View
     ///     </para>
     ///     <para>
     ///         Altering the Viewport Size will eventually (when the view is next laid out) cause the
-    ///         <see cref="Layout()"/> and <see cref="OnDrawingContent()"/> methods to be called.
+    ///         <see cref="Layout()"/> and <see cref="OnDrawingContent(DrawContext)"/> methods to be called.
     ///     </para>
     /// </remarks>
     public virtual Rectangle Viewport

+ 98 - 212
Terminal.Gui/ViewBase/View.Drawing.cs

@@ -28,8 +28,35 @@ public partial class View // Drawing APIs
             view.Draw (context);
         }
 
-        // Draw the margins (those with Shadows) last to ensure they are drawn on top of the content.
+        // Draw the margins last to ensure they are drawn on top of the content.
         Margin.DrawMargins (viewsArray);
+
+        // DrawMargins may have caused some views have NeedsDraw/NeedsSubViewDraw set; clear them all.
+        foreach (View view in viewsArray)
+        {
+            view.ClearNeedsDraw ();
+        }
+
+        // After all peer views have been drawn and cleared, we can now clear the SuperView's SubViewNeedsDraw flag.
+        // ClearNeedsDraw() does not clear SuperView.SubViewNeedsDraw (by design, to avoid premature clearing
+        // when siblings still need drawing), so we must do it here after ALL peers are processed.
+        // We only clear the flag if ALL the SuperView's subviews no longer need drawing.
+        View? lastSuperView = null;
+        foreach (View view in viewsArray)
+        {
+            if (view is not Adornment && view.SuperView is { } && view.SuperView != lastSuperView)
+            {
+                // Check if ANY subview of this SuperView still needs drawing
+                bool anySubViewNeedsDrawing = view.SuperView.InternalSubViews.Any (v => v.NeedsDraw || v.SubViewNeedsDraw);
+
+                if (!anySubViewNeedsDrawing)
+                {
+                    view.SuperView.SubViewNeedsDraw = false;
+                }
+
+                lastSuperView = view.SuperView;
+            }
+        }
     }
 
     /// <summary>
@@ -73,7 +100,7 @@ public partial class View // Drawing APIs
             originalClip = AddViewportToClip ();
 
             // If no context ...
-            context ??= new DrawContext ();
+            context ??= new ();
 
             SetAttributeForRole (Enabled ? VisualRole.Normal : VisualRole.Disabled);
             DoClearViewport (context);
@@ -136,7 +163,6 @@ public partial class View // Drawing APIs
 
         // ------------------------------------
         // This causes the Margin to be drawn in a second pass if it has a ShadowStyle
-        // PERFORMANCE: If there is a Margin w/ Shadow, it will be redrawn each iteration of the main loop.
         Margin?.CacheClip ();
 
         // ------------------------------------
@@ -154,7 +180,7 @@ public partial class View // Drawing APIs
     {
         // NOTE: We do not support subviews of Margin?
 
-        if (Border?.SubViews is { } && Border.Thickness != Thickness.Empty)
+        if (Border?.SubViews is { } && Border.Thickness != Thickness.Empty && Border.NeedsDraw)
         {
             // PERFORMANCE: Get the check for DrawIndicator out of this somehow.
             foreach (View subview in Border.SubViews.Where (v => v.Visible || v.Id == "DrawIndicator"))
@@ -172,7 +198,7 @@ public partial class View // Drawing APIs
             SetClip (saved);
         }
 
-        if (Padding?.SubViews is { } && Padding.Thickness != Thickness.Empty)
+        if (Padding?.SubViews is { } && Padding.Thickness != Thickness.Empty && Padding.NeedsDraw)
         {
             foreach (View subview in Padding.SubViews)
             {
@@ -206,7 +232,7 @@ public partial class View // Drawing APIs
         {
             Margin.NeedsLayout = false;
             Margin?.Thickness.Draw (Driver, FrameToScreen ());
-            Margin?.Parent?.SetSubViewNeedsDraw ();
+            Margin?.Parent?.SetSubViewNeedsDrawDownHierarchy ();
         }
 
         if (SubViewNeedsDraw)
@@ -253,7 +279,7 @@ public partial class View // Drawing APIs
 
         if (Margin is { } && Margin.Thickness != Thickness.Empty/* && Margin.ShadowStyle == ShadowStyle.None*/)
         {
-           //Margin?.Draw ();
+            //Margin?.Draw ();
         }
     }
 
@@ -288,7 +314,7 @@ public partial class View // Drawing APIs
 
     internal void DoClearViewport (DrawContext? context = null)
     {
-        if (ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent) || OnClearingViewport ())
+        if (!NeedsDraw || ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent) || OnClearingViewport ())
         {
             return;
         }
@@ -407,8 +433,8 @@ public partial class View // Drawing APIs
 
         DrawText (context);
 
-        OnDrewText();
-        DrewText?.Invoke(this, EventArgs.Empty);
+        OnDrewText ();
+        DrewText?.Invoke (this, EventArgs.Empty);
     }
 
     /// <summary>
@@ -447,7 +473,7 @@ public partial class View // Drawing APIs
 
         if (Driver is { })
         {
-            TextFormatter?.Draw (
+            TextFormatter.Draw (
                                  Driver,
                                  drawRect,
                                  HasFocus ? GetAttributeForRole (VisualRole.Focus) : GetAttributeForRole (VisualRole.Normal),
@@ -456,7 +482,7 @@ public partial class View // Drawing APIs
         }
 
         // We assume that the text has been drawn over the entire area; ensure that the subviews are redrawn.
-        SetSubViewNeedsDraw ();
+        SetSubViewNeedsDrawDownHierarchy ();
     }
 
     /// <summary>
@@ -468,17 +494,12 @@ public partial class View // Drawing APIs
     public event EventHandler? DrewText;
 
     #endregion DrawText
+
     #region DrawContent
 
     private void DoDrawContent (DrawContext? context = null)
     {
-        if (OnDrawingContent (context))
-        {
-            return;
-        }
-
-        // TODO: Upgrade all overrides of OnDrawingContent to use DrawContext and remove this override
-        if (OnDrawingContent ())
+        if (!NeedsDraw || OnDrawingContent (context))
         {
             return;
         }
@@ -499,20 +520,66 @@ public partial class View // Drawing APIs
     /// </summary>
     /// <param name="context">The draw context to report drawn areas to.</param>
     /// <returns><see langword="true"/> to stop further drawing content.</returns>
+    /// <remarks>
+    ///     <para>
+    ///         Override this method to draw custom content for your View.
+    ///     </para>
+    ///     <para>
+    ///         <b>Transparency Support:</b> If your View has <see cref="ViewportSettings"/> with <see cref="ViewportSettingsFlags.Transparent"/>
+    ///         set, you should report the exact regions you draw to via the <paramref name="context"/> parameter. This allows
+    ///         the transparency system to exclude only the drawn areas from the clip region, letting views beneath show through
+    ///         in the areas you didn't draw.
+    ///     </para>
+    ///     <para>
+    ///         Use <see cref="DrawContext.AddDrawnRectangle"/> for simple rectangular areas, or <see cref="DrawContext.AddDrawnRegion"/>
+    ///         for complex, non-rectangular shapes. All coordinates passed to these methods must be in <b>screen-relative coordinates</b>.
+    ///         Use <see cref="View.ViewportToScreen(in Rectangle)"/> or <see cref="View.ContentToScreen(in Point)"/> to convert from
+    ///         viewport-relative or content-relative coordinates.
+    ///     </para>
+    ///     <para>
+    ///         Example of drawing custom content with transparency support:
+    ///     </para>
+    ///     <code>
+    ///         protected override bool OnDrawingContent (DrawContext? context)
+    ///         {
+    ///             base.OnDrawingContent (context);
+    ///             
+    ///             // Draw content in viewport-relative coordinates
+    ///             Rectangle rect1 = new Rectangle (5, 5, 10, 3);
+    ///             Rectangle rect2 = new Rectangle (8, 8, 4, 7);
+    ///             FillRect (rect1, Glyphs.BlackCircle);
+    ///             FillRect (rect2, Glyphs.BlackCircle);
+    ///             
+    ///             // Report drawn region in screen-relative coordinates for transparency
+    ///             if (ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent))
+    ///             {
+    ///                 Region drawnRegion = new Region (ViewportToScreen (rect1));
+    ///                 drawnRegion.Union (ViewportToScreen (rect2));
+    ///                 context?.AddDrawnRegion (drawnRegion);
+    ///             }
+    ///             
+    ///             return true;
+    ///         }
+    ///     </code>
+    /// </remarks>
     protected virtual bool OnDrawingContent (DrawContext? context) { return false; }
 
-    /// <summary>
-    ///     Called when the View's content is to be drawn. The default implementation does nothing.
-    /// </summary>
-    /// <returns><see langword="true"/> to stop further drawing content.</returns>
-    protected virtual bool OnDrawingContent () { return false; }
-
     /// <summary>Raised when the View's content is to be drawn.</summary>
     /// <remarks>
-    ///     <para>Will be invoked before any subviews added with <see cref="Add(View)"/> have been drawn.</para>
     ///     <para>
-    ///         Rect provides the view-relative rectangle describing the currently visible viewport into the
-    ///         <see cref="View"/> .
+    ///         Subscribe to this event to draw custom content for the View. Use the drawing methods available on <see cref="View"/>
+    ///         such as <see cref="View.AddRune(int, int, Rune)"/>, <see cref="View.AddStr(string)"/>, and <see cref="View.FillRect(Rectangle, Rune)"/>.
+    ///     </para>
+    ///     <para>
+    ///         The event is invoked after <see cref="ClearingViewport"/> and <see cref="Text"/> have been drawn, but before any <see cref="SubViews"/> are drawn.
+    ///     </para>
+    ///     <para>
+    ///         <b>Transparency Support:</b> If the View has <see cref="ViewportSettings"/> with <see cref="ViewportSettingsFlags.Transparent"/>
+    ///         set, use the <see cref="DrawEventArgs.DrawContext"/> to report which areas were actually drawn. This enables proper transparency
+    ///         by excluding only the drawn areas from the clip region. See <see cref="DrawContext"/> for details on reporting drawn regions.
+    ///     </para>
+    ///     <para>
+    ///         The <see cref="DrawEventArgs.NewViewport"/> property provides the view-relative rectangle describing the currently visible viewport into the View.
     ///     </para>
     /// </remarks>
     public event EventHandler<DrawEventArgs>? DrawingContent;
@@ -523,7 +590,7 @@ public partial class View // Drawing APIs
 
     private void DoDrawSubViews (DrawContext? context = null)
     {
-        if (OnDrawingSubViews (context))
+        if (!NeedsDraw || OnDrawingSubViews (context))
         {
             return;
         }
@@ -589,7 +656,7 @@ public partial class View // Drawing APIs
             // TODO: HACK - This forcing of SetNeedsDraw with SuperViewRendersLineCanvas enables auto line join to work, but is brute force.
             if (view.SuperViewRendersLineCanvas || view.ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent))
             {
-                view.SetNeedsDraw ();
+                //view.SetNeedsDraw ();
             }
             view.Draw (context);
 
@@ -607,7 +674,7 @@ public partial class View // Drawing APIs
 
     private void DoRenderLineCanvas ()
     {
-        if (OnRenderingLineCanvas ())
+        if (!NeedsDraw || OnRenderingLineCanvas ())
         {
             return;
         }
@@ -733,185 +800,4 @@ public partial class View // Drawing APIs
 
     #endregion DrawComplete
 
-    #region NeedsDraw
-
-    // TODO: Change NeedsDraw to use a Region instead of Rectangle
-    // TODO: Make _needsDrawRect nullable instead of relying on Empty
-    //      TODO: If null, it means ?
-    //      TODO: If Empty, it means no need to redraw
-    //      TODO: If not Empty, it means the region that needs to be redrawn
-    // The viewport-relative region that needs to be redrawn. Marked internal for unit tests.
-    internal Rectangle NeedsDrawRect { get; set; } = Rectangle.Empty;
-
-    /// <summary>Gets or sets whether the view needs to be redrawn.</summary>
-    /// <remarks>
-    ///     <para>
-    ///         Will be <see langword="true"/> if the <see cref="NeedsLayout"/> property is <see langword="true"/> or if
-    ///         any part of the view's <see cref="Viewport"/> needs to be redrawn.
-    ///     </para>
-    ///     <para>
-    ///         Setting has no effect on <see cref="NeedsLayout"/>.
-    ///     </para>
-    /// </remarks>
-    public bool NeedsDraw
-    {
-        get => Visible && (NeedsDrawRect != Rectangle.Empty || Margin?.NeedsDraw == true || Border?.NeedsDraw == true || Padding?.NeedsDraw == true);
-        set
-        {
-            if (value)
-            {
-                SetNeedsDraw ();
-            }
-            else
-            {
-                ClearNeedsDraw ();
-            }
-        }
-    }
-
-    /// <summary>Gets whether any SubViews need to be redrawn.</summary>
-    public bool SubViewNeedsDraw { get; private set; }
-
-    /// <summary>Sets that the <see cref="Viewport"/> of this View needs to be redrawn.</summary>
-    /// <remarks>
-    ///     If the view has not been initialized (<see cref="IsInitialized"/> is <see langword="false"/>), this method
-    ///     does nothing.
-    /// </remarks>
-    public void SetNeedsDraw ()
-    {
-        Rectangle viewport = Viewport;
-
-        if (!Visible || (NeedsDrawRect != Rectangle.Empty && viewport.IsEmpty))
-        {
-            // This handles the case where the view has not been initialized yet
-            return;
-        }
-
-        SetNeedsDraw (viewport);
-    }
-
-    /// <summary>Expands the area of this view needing to be redrawn to include <paramref name="viewPortRelativeRegion"/>.</summary>
-    /// <remarks>
-    ///     <para>
-    ///         The location of <paramref name="viewPortRelativeRegion"/> is relative to the View's <see cref="Viewport"/>.
-    ///     </para>
-    ///     <para>
-    ///         If the view has not been initialized (<see cref="IsInitialized"/> is <see langword="false"/>), the area to be
-    ///         redrawn will be the <paramref name="viewPortRelativeRegion"/>.
-    ///     </para>
-    /// </remarks>
-    /// <param name="viewPortRelativeRegion">The <see cref="Viewport"/>relative region that needs to be redrawn.</param>
-    public void SetNeedsDraw (Rectangle viewPortRelativeRegion)
-    {
-        if (!Visible)
-        {
-            return;
-        }
-
-        if (NeedsDrawRect.IsEmpty)
-        {
-            NeedsDrawRect = viewPortRelativeRegion;
-        }
-        else
-        {
-            int x = Math.Min (Viewport.X, viewPortRelativeRegion.X);
-            int y = Math.Min (Viewport.Y, viewPortRelativeRegion.Y);
-            int w = Math.Max (Viewport.Width, viewPortRelativeRegion.Width);
-            int h = Math.Max (Viewport.Height, viewPortRelativeRegion.Height);
-            NeedsDrawRect = new (x, y, w, h);
-        }
-
-        // Do not set on Margin - it will be drawn in a separate pass.
-
-        if (Border is { } && Border.Thickness != Thickness.Empty)
-        {
-            Border?.SetNeedsDraw ();
-        }
-
-        if (Padding is { } && Padding.Thickness != Thickness.Empty)
-        {
-            Padding?.SetNeedsDraw ();
-        }
-
-        SuperView?.SetSubViewNeedsDraw ();
-
-        if (this is Adornment adornment)
-        {
-            adornment.Parent?.SetSubViewNeedsDraw ();
-        }
-
-        // There was multiple enumeration error here, so calling new snapshot collection - probably a stop gap
-        foreach (View subview in InternalSubViews.Snapshot ())
-        {
-            if (subview.Frame.IntersectsWith (viewPortRelativeRegion))
-            {
-                Rectangle subviewRegion = Rectangle.Intersect (subview.Frame, viewPortRelativeRegion);
-                subviewRegion.X -= subview.Frame.X;
-                subviewRegion.Y -= subview.Frame.Y;
-                subview.SetNeedsDraw (subviewRegion);
-            }
-        }
-    }
-
-    /// <summary>Sets <see cref="SubViewNeedsDraw"/> to <see langword="true"/> for this View and all Superviews.</summary>
-    public void SetSubViewNeedsDraw ()
-    {
-        if (!Visible)
-        {
-            return;
-        }
-
-        SubViewNeedsDraw = true;
-
-        if (this is Adornment adornment)
-        {
-            adornment.Parent?.SetSubViewNeedsDraw ();
-        }
-
-        if (SuperView is { SubViewNeedsDraw: false })
-        {
-            SuperView.SetSubViewNeedsDraw ();
-        }
-    }
-
-    /// <summary>Clears <see cref="NeedsDraw"/> and <see cref="SubViewNeedsDraw"/>.</summary>
-    protected void ClearNeedsDraw ()
-    {
-        NeedsDrawRect = Rectangle.Empty;
-        SubViewNeedsDraw = false;
-
-        if (Margin is { } && (Margin.Thickness != Thickness.Empty || Margin.SubViewNeedsDraw || Margin.NeedsDraw))
-        {
-            Margin?.ClearNeedsDraw ();
-        }
-
-        if (Border is { } && (Border.Thickness != Thickness.Empty || Border.SubViewNeedsDraw || Border.NeedsDraw))
-        {
-            Border?.ClearNeedsDraw ();
-        }
-
-        if (Padding is { } && (Padding.Thickness != Thickness.Empty || Padding.SubViewNeedsDraw || Padding.NeedsDraw))
-        {
-            Padding?.ClearNeedsDraw ();
-        }
-
-        // There was multiple enumeration error here, so calling new snapshot collection - probably a stop gap
-        foreach (View subview in InternalSubViews.Snapshot ())
-        {
-            subview.ClearNeedsDraw ();
-        }
-
-        if (SuperView is { })
-        {
-            SuperView.SubViewNeedsDraw = false;
-        }
-
-        // This ensures LineCanvas' get redrawn
-        if (!SuperViewRendersLineCanvas)
-        {
-            LineCanvas.Clear ();
-        }
-    }
-
-    #endregion NeedsDraw
 }

+ 168 - 0
Terminal.Gui/ViewBase/View.NeedsDraw.cs

@@ -0,0 +1,168 @@
+namespace Terminal.Gui.ViewBase;
+
+public partial class View
+{
+    // NOTE: NeedsDrawRect is not currently used to clip drawing to only the invalidated region.
+    //       It is only used within SetNeedsDraw to propagate redraw requests to subviews.
+    // NOTE: Consider changing NeedsDrawRect from Rectangle to Region for more precise invalidation
+    //       NeedsDraw is already efficiently cached via NeedsDrawRect. It checks:
+    //       1. NeedsDrawRect (cached by SetNeedsDraw/ClearNeedsDraw)
+    //       2. Adornment NeedsDraw flags (each cached separately)
+    /// <summary>
+    ///     INTERNAL: Gets the viewport-relative region that needs to be redrawn.
+    /// </summary>
+    internal Rectangle NeedsDrawRect { get; private set; } = Rectangle.Empty;
+
+    /// <summary>Gets whether the view needs to be redrawn.</summary>
+    /// <remarks>
+    ///     <para>
+    ///         Will be <see langword="true"/> if the <see cref="NeedsLayout"/> property is <see langword="true"/> or if
+    ///         any part of the view's <see cref="Viewport"/> needs to be redrawn.
+    ///     </para>
+    /// </remarks>
+    public bool NeedsDraw => Visible && (NeedsDrawRect != Rectangle.Empty || Margin?.NeedsDraw == true || Border?.NeedsDraw == true || Padding?.NeedsDraw == true);
+
+    /// <summary>Sets <see cref="NeedsDraw"/> to <see langword="true"/> indicating the <see cref="Viewport"/> of this View needs to be redrawn.</summary>
+    /// <remarks>
+    ///     If the view is not visible (<see cref="Visible"/> is <see langword="false"/>), this method
+    ///     does nothing.
+    /// </remarks>
+    public void SetNeedsDraw ()
+    {
+        Rectangle viewport = Viewport;
+
+        if (!Visible || (NeedsDrawRect != Rectangle.Empty && viewport.IsEmpty))
+        {
+            // This handles the case where the view has not been initialized yet
+            return;
+        }
+
+        SetNeedsDraw (viewport);
+    }
+
+    /// <summary>Expands the area of this view needing to be redrawn to include <paramref name="viewPortRelativeRegion"/>.</summary>
+    /// <remarks>
+    ///     <para>
+    ///         The location of <paramref name="viewPortRelativeRegion"/> is relative to the View's <see cref="Viewport"/>.
+    ///     </para>
+    ///     <para>
+    ///         If the view has not been initialized (<see cref="IsInitialized"/> is <see langword="false"/>), the area to be
+    ///         redrawn will be the <paramref name="viewPortRelativeRegion"/>.
+    ///     </para>
+    /// </remarks>
+    /// <param name="viewPortRelativeRegion">The <see cref="Viewport"/>relative region that needs to be redrawn.</param>
+    public void SetNeedsDraw (Rectangle viewPortRelativeRegion)
+    {
+        if (!Visible)
+        {
+            return;
+        }
+
+        if (NeedsDrawRect.IsEmpty)
+        {
+            NeedsDrawRect = viewPortRelativeRegion;
+        }
+        else
+        {
+            int x = Math.Min (Viewport.X, viewPortRelativeRegion.X);
+            int y = Math.Min (Viewport.Y, viewPortRelativeRegion.Y);
+            int w = Math.Max (Viewport.Width, viewPortRelativeRegion.Width);
+            int h = Math.Max (Viewport.Height, viewPortRelativeRegion.Height);
+            NeedsDrawRect = new (x, y, w, h);
+        }
+
+        // Do not set on Margin - it will be drawn in a separate pass.
+
+        if (Border is { } && Border.Thickness != Thickness.Empty)
+        {
+            Border?.SetNeedsDraw ();
+        }
+
+        if (Padding is { } && Padding.Thickness != Thickness.Empty)
+        {
+            Padding?.SetNeedsDraw ();
+        }
+
+        SuperView?.SetSubViewNeedsDrawDownHierarchy ();
+
+        if (this is Adornment adornment)
+        {
+            adornment.Parent?.SetSubViewNeedsDrawDownHierarchy ();
+        }
+
+        foreach (View subview in InternalSubViews.Snapshot ())
+        {
+            if (subview.Frame.IntersectsWith (viewPortRelativeRegion))
+            {
+                Rectangle subviewRegion = Rectangle.Intersect (subview.Frame, viewPortRelativeRegion);
+                subviewRegion.X -= subview.Frame.X;
+                subviewRegion.Y -= subview.Frame.Y;
+                subview.SetNeedsDraw (subviewRegion);
+            }
+        }
+    }
+
+    /// <summary>INTERNAL: Clears <see cref="NeedsDraw"/> and <see cref="SubViewNeedsDraw"/> for this view and all SubViews.</summary>
+    /// <remarks>
+    ///     See <see cref="SubViewNeedsDraw"/> is a cached value that is set when any subview or adornment requests a redraw.
+    ///     It may not always be in sync with the actual state of the subviews.
+    /// </remarks>
+    internal void ClearNeedsDraw ()
+    {
+        NeedsDrawRect = Rectangle.Empty;
+
+        Margin?.ClearNeedsDraw ();
+        Border?.ClearNeedsDraw ();
+        Padding?.ClearNeedsDraw ();
+
+        foreach (View subview in InternalSubViews.Snapshot ())
+        {
+            subview.ClearNeedsDraw ();
+        }
+
+        SubViewNeedsDraw = false;
+
+        // This ensures LineCanvas' get redrawn
+        if (!SuperViewRendersLineCanvas)
+        {
+            LineCanvas.Clear ();
+        }
+    }
+
+    // NOTE: SubViewNeedsDraw is decoupled from the actual state of the subviews (and adornments).
+    //       It is a performance optimization to avoid having to traverse all subviews and adornments to check if any need redraw.
+    //       As a result the code is fragile and can get out of sync; care must be taken to ensure it is set and cleared correctly.
+    /// <summary>
+    ///     INTERNAL: Gets whether any SubViews need to be redrawn.
+    /// </summary>
+    /// <remarks>
+    ///     See <see cref="SubViewNeedsDraw"/> is a cached value that is set when any subview or adornment requests a redraw.
+    ///     It may not always be in sync with the actual state of the subviews.
+    /// </remarks>
+    internal bool SubViewNeedsDraw { get; private set; }
+
+    /// <summary>INTERNAL: Sets <see cref="SubViewNeedsDraw"/> to <see langword="true"/> for this View and all Superviews.</summary>
+    /// <remarks>
+    ///     See <see cref="SubViewNeedsDraw"/> is a cached value that is set when any subview or adornment requests a redraw.
+    ///     It may not always be in sync with the actual state of the subviews.
+    /// </remarks>
+    internal void SetSubViewNeedsDrawDownHierarchy ()
+    {
+        if (!Visible)
+        {
+            return;
+        }
+
+        SubViewNeedsDraw = true;
+
+        if (this is Adornment adornment)
+        {
+            adornment.Parent?.SetSubViewNeedsDrawDownHierarchy ();
+        }
+
+        if (SuperView is { SubViewNeedsDraw: false })
+        {
+            SuperView.SetSubViewNeedsDrawDownHierarchy ();
+        }
+    }
+}

+ 0 - 79
Terminal.Gui/Views/Autocomplete/Autocomplete.cd

@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ClassDiagram MajorVersion="1" MinorVersion="1">
-  <Class Name="Terminal.Gui.Views.AppendAutocomplete" Collapsed="true">
-    <Position X="0.5" Y="6.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAgAABAAQIAAAAAAAAAAAAABAAAIAQAgAEIAggAIAA=</HashCode>
-      <FileName>Core\Autocomplete\AppendAutocomplete.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.AutocompleteBase" Collapsed="true">
-    <Position X="1.75" Y="5.25" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAQgAAAAAUAAIAAAAAIAAAAAAAEAIAQIgQAIQAAAMBA=</HashCode>
-      <FileName>Core\Autocomplete\AutocompleteBase.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.PopupAutocomplete" Collapsed="true">
-    <Position X="2.75" Y="6.5" Width="1.5" />
-    <NestedTypes>
-      <Class Name="Terminal.Gui.Views.PopupAutocomplete.Popup" Collapsed="true">
-        <TypeIdentifier>
-          <NewMemberFileName>Core\Autocomplete\PopupAutocomplete.cs</NewMemberFileName>
-        </TypeIdentifier>
-      </Class>
-    </NestedTypes>
-    <TypeIdentifier>
-      <HashCode>IAEhAAQAASBEQAAAAAIBAAgYAAAAIAwAwKAAQACBAAA=</HashCode>
-      <FileName>Core\Autocomplete\PopupAutocomplete.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.SingleWordSuggestionGenerator" BaseTypeListCollapsed="true">
-    <Position X="6.25" Y="3.5" Width="3" />
-    <TypeIdentifier>
-      <HashCode>CEAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAIAA=</HashCode>
-      <FileName>Core\Autocomplete\SingleWordSuggestionGenerator.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.Suggestion">
-    <Position X="4.5" Y="2.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAEAAAAAABAAAAAAAAAAAAAAAAAAAAAE=</HashCode>
-      <FileName>Core\Autocomplete\Suggestion.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.TextFieldAutocomplete" Collapsed="true">
-    <Position X="1.5" Y="7.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAgAAAAAAAAAA=</HashCode>
-      <FileName>Views\TextField.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.TextViewAutocomplete" Collapsed="true">
-    <Position X="3.75" Y="7.5" Width="2.25" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAgAAAAAAAAAA=</HashCode>
-      <FileName>Views\TextView.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Interface Name="Terminal.Gui.Views.IAutocomplete">
-    <Position X="1.75" Y="0.5" Width="2.5" />
-    <TypeIdentifier>
-      <HashCode>AAQgAAAAAUAAIAAAAAAAAAAAAAEAIAQIgQAIQAAAMBA=</HashCode>
-      <FileName>Core\Autocomplete\IAutocomplete.cs</FileName>
-    </TypeIdentifier>
-    <ShowAsAssociation>
-      <Property Name="SuggestionGenerator" />
-    </ShowAsAssociation>
-  </Interface>
-  <Interface Name="Terminal.Gui.Views.ISuggestionGenerator">
-    <Position X="6.25" Y="1.75" Width="2.25" />
-    <TypeIdentifier>
-      <HashCode>AEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA=</HashCode>
-      <FileName>Core\Autocomplete\ISuggestionGenerator.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Font Name="Segoe UI" Size="9" />
-</ClassDiagram>

+ 1 - 1
Terminal.Gui/Views/Autocomplete/PopupAutocomplete.PopUp.cs

@@ -15,7 +15,7 @@ public abstract partial class PopupAutocomplete
 
         private readonly PopupAutocomplete _autoComplete;
 
-        protected override bool OnDrawingContent ()
+        protected override bool OnDrawingContent (DrawContext? context)
         {
             if (!_autoComplete.LastPopupPos.HasValue)
             {

+ 1 - 1
Terminal.Gui/Views/CharMap/CharMap.cs

@@ -580,7 +580,7 @@ public class CharMap : View, IDesignable
     private static int RowLabelWidth => $"U+{MAX_CODE_POINT:x5}".Length + 1;
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         if (Viewport.Height == 0 || Viewport.Width == 0)
         {

+ 0 - 124
Terminal.Gui/Views/CollectionNavigation/CollectionNavigation.cd

@@ -1,124 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ClassDiagram MajorVersion="1" MinorVersion="1">
-  <Comment CommentText="Views that use the CollectionNavigation system">
-    <Position X="0.5" Y="0.5" Height="0.458" Width="1.856" />
-  </Comment>
-  <Comment CommentText="Specialized navigators for each collection type (e.g. list, tree etc)">
-    <Position X="4.646" Y="0.5" Height="0.5" Width="3.169" />
-  </Comment>
-  <Comment CommentText="Shared matching component (users should provide alternative implementations of this class if they want to modify collection navigation behaviour)">
-    <Position X="9.448" Y="0.5" Height="0.708" Width="3.169" />
-  </Comment>
-  <Class Name="Terminal.Gui.Views.CollectionNavigatorBase" Collapsed="true">
-    <Position X="6.25" Y="1.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAgEAAAAAAAQAAAIAAEAAgAAAAAABAAEAAAAACwAAAA=</HashCode>
-      <FileName>Views\CollectionNavigation\CollectionNavigatorBase.cs</FileName>
-    </TypeIdentifier>
-    <ShowAsAssociation>
-      <Property Name="Matcher" />
-    </ShowAsAssociation>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.CollectionNavigator" Collapsed="true">
-    <Position X="4.5" Y="3.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAQAAAAAAAAgAAAAAAAAAEAAAAAAAAAAA=</HashCode>
-      <FileName>Views\CollectionNavigation\CollectionNavigator.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.DefaultCollectionNavigatorMatcher">
-    <Position X="9.5" Y="2.5" Width="2.75" />
-    <TypeIdentifier>
-      <HashCode>AAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAQA=</HashCode>
-      <FileName>Views\CollectionNavigation\DefaultCollectionNavigatorMatcher.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.TableCollectionNavigator" Collapsed="true">
-    <Position X="4.75" Y="6.5" Width="2.25" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAEAAAAIAAAAAA=</HashCode>
-      <FileName>Views\CollectionNavigation\TableCollectionNavigator.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.ListView" Collapsed="true">
-    <Position X="0.5" Y="4.25" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAE+ASAkEnAAABAAKGAggYAZJAIAABEAcBAaAwAQIAA=</HashCode>
-      <FileName>Views\ListView.cs</FileName>
-    </TypeIdentifier>
-    <ShowAsAssociation>
-      <Property Name="KeystrokeNavigator" />
-    </ShowAsAssociation>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.TableView" Collapsed="true" BaseTypeListCollapsed="true">
-    <Position X="0.5" Y="6.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>QwUeAxwgICIAcABIABeR0oBAkhoFGGOBDABgAN3oPEI=</HashCode>
-      <FileName>Views\TableView\TableView.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.TreeView" Collapsed="true">
-    <Position X="0.5" Y="3" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAA=</HashCode>
-      <FileName>Views\TreeView\TreeView.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.TreeView&lt;T&gt;" Collapsed="true">
-    <Position X="0.5" Y="2" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>UwAGySBgBSBGMAQgIiCaBDUItJIBSAWwRMQOSgQCwJI=</HashCode>
-      <FileName>Views\TreeView\TreeView.cs</FileName>
-    </TypeIdentifier>
-    <ShowAsAssociation>
-      <Property Name="KeystrokeNavigator" />
-    </ShowAsAssociation>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.FileDialog" Collapsed="true">
-    <Position X="0.5" Y="5.5" Width="1.75" />
-    <Compartments>
-      <Compartment Name="Nested Types" Collapsed="false" />
-    </Compartments>
-    <TypeIdentifier>
-      <HashCode>iIY4LQFUHDKVIHIESBoigQcFT6GxhBDABGJItBQAwAQ=</HashCode>
-      <FileName>Views\FileDialogs\FileDialog.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.FileDialogCollectionNavigator" Collapsed="true">
-    <Position X="4.75" Y="5.5" Width="2.25" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAA=</HashCode>
-      <FileName>Views\FileDialogs\FileDialogCollectionNavigator.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Interface Name="Terminal.Gui.Views.ICollectionNavigatorMatcher" Collapsed="true">
-    <Position X="9.5" Y="1.5" Width="2.75" />
-    <TypeIdentifier>
-      <HashCode>AAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAA=</HashCode>
-      <FileName>Views\CollectionNavigation\ICollectionNavigatorMatcher.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Interface Name="Terminal.Gui.Views.IListCollectionNavigator" Collapsed="true">
-    <Position X="3.75" Y="2.25" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
-      <FileName>Views\CollectionNavigation\IListCollectionNavigator.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Interface Name="Terminal.Gui.Views.ICollectionNavigator" Collapsed="true">
-    <Position X="3.75" Y="1.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAgAAAAAAAAAAAAIAAAAAAAAAAAABAAAAAAAACgAAAA=</HashCode>
-      <FileName>Views\CollectionNavigation\ICollectionNavigator.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Font Name="Segoe UI" Size="9" />
-</ClassDiagram>

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

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

+ 2 - 5
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;
 
@@ -103,7 +101,7 @@ internal abstract class ColorBar : View, IColorBar
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         if (!string.IsNullOrWhiteSpace (Text))
         {
@@ -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); }
 }

+ 1 - 1
Terminal.Gui/Views/Color/ColorPicker.16.cs

@@ -132,7 +132,7 @@ public class ColorPicker16 : View
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         SetAttribute (HasFocus ? GetAttributeForRole (VisualRole.Focus) : GetAttributeForRole (VisualRole.Normal));
         var colorIndex = 0;

+ 6 - 6
Terminal.Gui/Views/Color/ColorPicker.Prompt.cs

@@ -21,14 +21,14 @@ public partial class ColorPicker
         var d = new Dialog
         {
             Title = title,
-            Width = Application.Force16Colors ? 37 : Dim.Auto (DimAutoStyle.Auto, Dim.Percent (80), Dim.Percent (90)),
+            Width = app.Driver!.Force16Colors ? 37 : Dim.Auto (DimAutoStyle.Auto, Dim.Percent (80), Dim.Percent (90)),
             Height = 20
         };
 
         var btnOk = new Button
         {
             X = Pos.Center () - 5,
-            Y = Application.Force16Colors ? 6 : 4,
+            Y = app.Driver!.Force16Colors ? 6 : 4,
             Text = "Ok",
             Width = Dim.Auto (),
             IsDefault = true
@@ -63,7 +63,7 @@ public partial class ColorPicker
 
         View cpForeground;
 
-        if (Application.Force16Colors)
+        if (app.Driver!.Force16Colors)
         {
             cpForeground = new ColorPicker16
             {
@@ -88,7 +88,7 @@ public partial class ColorPicker
 
         View cpBackground;
 
-        if (Application.Force16Colors)
+        if (app.Driver!.Force16Colors)
         {
             cpBackground = new ColorPicker16
             {
@@ -117,8 +117,8 @@ public partial class ColorPicker
 
         app.Run (d);
         d.Dispose ();
-        Color newForeColor = Application.Force16Colors ? ((ColorPicker16)cpForeground).SelectedColor : ((ColorPicker)cpForeground).SelectedColor;
-        Color newBackColor = Application.Force16Colors ? ((ColorPicker16)cpBackground).SelectedColor : ((ColorPicker)cpBackground).SelectedColor;
+        Color newForeColor = app.Driver!.Force16Colors ? ((ColorPicker16)cpForeground).SelectedColor : ((ColorPicker)cpForeground).SelectedColor;
+        Color newBackColor = app.Driver!.Force16Colors ? ((ColorPicker16)cpBackground).SelectedColor : ((ColorPicker)cpBackground).SelectedColor;
         newAttribute = new (newForeColor, newBackColor);
         app.Dispose ();
         return accept;

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

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

+ 1 - 1
Terminal.Gui/Views/Color/ColorPicker.cs

@@ -99,7 +99,7 @@ public partial class ColorPicker : View, IDesignable
     public event EventHandler<ResultEventArgs<Color>>? ColorChanged;
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         Attribute normal = GetAttributeForRole (VisualRole.Normal);
         SetAttribute (new (SelectedColor, normal.Background, Enabled ? TextStyle.None : TextStyle.Faint));

+ 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;
 

+ 2 - 2
Terminal.Gui/Views/ComboBox.cs

@@ -287,7 +287,7 @@ public class ComboBox : View, IDesignable
     public virtual void OnCollapsed () { Collapsed?.Invoke (this, EventArgs.Empty); }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext context)
     {
 
         if (!_autoHide)
@@ -881,7 +881,7 @@ public class ComboBox : View, IDesignable
             return res;
         }
 
-        protected override bool OnDrawingContent ()
+        protected override bool OnDrawingContent (DrawContext context)
         {
             Attribute current = GetAttributeForRole (VisualRole.Focus);
             SetAttribute (current);

+ 0 - 168
Terminal.Gui/Views/FileDialogs/FileDialog.cd

@@ -1,168 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ClassDiagram MajorVersion="1" MinorVersion="1">
-  <Class Name="Terminal.Gui.FileServices.DefaultSearchMatcher" Collapsed="true" BaseTypeListCollapsed="true">
-    <Position X="9.25" Y="6" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAACAAAAAAgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
-      <FileName>FileServices\DefaultSearchMatcher.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.FileServices.FileSystemInfoStats">
-    <Position X="14" Y="0.5" Width="2.5" />
-    <TypeIdentifier>
-      <HashCode>ABAIQAIIIAAAAAACQAAAAIQAAAQAAIAAAQAAAAAIAAI=</HashCode>
-      <FileName>FileServices\FileSystemInfoStats.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.FileDialog">
-    <Position X="0.5" Y="0.5" Width="2.75" />
-    <Compartments>
-      <Compartment Name="Fields" Collapsed="true" />
-      <Compartment Name="Methods" Collapsed="true" />
-      <Compartment Name="Nested Types" Collapsed="false" />
-    </Compartments>
-    <NestedTypes>
-      <Class Name="Terminal.Gui.Views.FileDialog.SearchState" Collapsed="true">
-        <TypeIdentifier>
-          <NewMemberFileName>Views\FileDialogs\FileDialog.cs</NewMemberFileName>
-        </TypeIdentifier>
-      </Class>
-    </NestedTypes>
-    <TypeIdentifier>
-      <HashCode>iIY4LQFUHDKVIHIESBoigQcFT6GxhBDABGJItBQAwAQ=</HashCode>
-      <FileName>Views\FileDialogs\FileDialog.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.FileDialogStyle">
-    <Position X="3.5" Y="0.5" Width="2.75" />
-    <TypeIdentifier>
-      <HashCode>GgBAAAFHAAAAuAAAAAAAEAQQBYAAKREAAAAYQCCAAAA=</HashCode>
-      <FileName>Views\FileDialogs\FileDialogStyle.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.FilesSelectedEventArgs">
-    <Position X="6.5" Y="0.5" Width="2" />
-    <Compartments>
-      <Compartment Name="Methods" Collapsed="true" />
-    </Compartments>
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAA=</HashCode>
-      <FileName>Views\FileDialogs\FilesSelectedEventArgs.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.FileDialogHistory">
-    <Position X="9.25" Y="0.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AQABAgEAAAAAAAAAIACAAAAAAAAAAQAAAAAAAAAADAI=</HashCode>
-      <FileName>Views\FileDialogs\FileDialogHistory.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.FileDialogState">
-    <Position X="11.5" Y="0.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AABAABAAAAAAAAIAAAAEQAAAAAAAQAAAAgAAAAAAAAI=</HashCode>
-      <FileName>Views\FileDialogs\FileDialogState.cs</FileName>
-    </TypeIdentifier>
-    <ShowAsCollectionAssociation>
-      <Property Name="Children" />
-    </ShowAsCollectionAssociation>
-  </Class>
-  <Class Name="Terminal.Gui.Views.AllowedType" BaseTypeListCollapsed="true">
-    <Position X="13.25" Y="5.75" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAgAAAEAAAAAAAAAAAAAAAAAAgAAAAABAA=</HashCode>
-      <FileName>Views\FileDialogs\AllowedType.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.AllowedTypeAny" BaseTypeListCollapsed="true">
-    <Position X="11.75" Y="5.75" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAABAA=</HashCode>
-      <FileName>Views\FileDialogs\AllowedType.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Text.NerdFonts">
-    <Position X="9.25" Y="6.75" Width="2" />
-    <Compartments>
-      <Compartment Name="Fields" Collapsed="true" />
-    </Compartments>
-    <TypeIdentifier>
-      <HashCode>AIACAAABQAAAAAAAAAAACAAAIACAAAAAAAIAAAAAAAA=</HashCode>
-      <FileName>Text\NerdFonts.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.FileServices.FileSystemTreeBuilder" BaseTypeListCollapsed="true">
-    <Position X="0.5" Y="6.75" Width="1.75" />
-    <TypeIdentifier>
-      <HashCode>EAAAAAAAAAAAAAAAAAAABAAwAAAAQAAAAABAAAAACAA=</HashCode>
-      <FileName>FileServices\FileSystemTreeBuilder.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.Views.DefaultFileOperations" BaseTypeListCollapsed="true">
-    <Position X="7" Y="6" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAACAAAAAAACAAAAEAAAAAAAAAAAAAgAA=</HashCode>
-      <FileName>Views\FileDialogs\DefaultFileOperations.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Class Name="Terminal.Gui.FileServices.FileSystemColorProvider" Collapsed="true">
-    <Position X="7" Y="8.5" Width="2" />
-    <TypeIdentifier>
-      <HashCode>AgAAAAAAAEAAAAAAAAAAAAEAAAAAAACAAAAAAAAAAAA=</HashCode>
-      <FileName>FileServices\FileSystemColorProvider.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.FileServices.FileSystemIconProvider" Collapsed="true">
-    <Position X="7" Y="7.75" Width="2" />
-    <TypeIdentifier>
-      <HashCode>ABAAAAAAAACAQAAAAAAAAEAgAAAAAQAAAAAAAAAAAiA=</HashCode>
-      <FileName>FileServices\FileSystemIconProvider.cs</FileName>
-    </TypeIdentifier>
-  </Class>
-  <Class Name="Terminal.Gui.Views.FileDialogTableSource">
-    <Position X="2.5" Y="8" Width="2.5" />
-    <Compartments>
-      <Compartment Name="Fields" Collapsed="true" />
-    </Compartments>
-    <TypeIdentifier>
-      <HashCode>AQAAAAAAIAACAEAACAAAAAACAAAEAAAEAAAAgAgBBAA=</HashCode>
-      <FileName>Views\FileDialogs\FileDialogTableSource.cs</FileName>
-    </TypeIdentifier>
-    <Lollipop Position="0.2" />
-  </Class>
-  <Interface Name="Terminal.Gui.FileServices.IFileOperations">
-    <Position X="7" Y="4.25" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAACAAAAAAAAAAAAEAAAAAAAAAAAAAgAA=</HashCode>
-      <FileName>FileServices\IFileOperations.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Interface Name="Terminal.Gui.FileServices.ISearchMatcher">
-    <Position X="9.25" Y="4.25" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
-      <FileName>FileServices\ISearchMatcher.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Interface Name="Terminal.Gui.Views.IAllowedType" Collapsed="true">
-    <Position X="12" Y="4.25" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA=</HashCode>
-      <FileName>Views\FileDialogs\AllowedType.cs</FileName>
-    </TypeIdentifier>
-  </Interface>
-  <Enum Name="Terminal.Gui.Views.OpenMode">
-    <Position X="7.5" Y="2.5" Width="1.5" />
-    <TypeIdentifier>
-      <HashCode>AAAAABAAAAAAACAAAAAAAAAAAAAEAAAAAAAAAAAAAAA=</HashCode>
-      <FileName>Views\FileDialogs\OpenMode.cs</FileName>
-    </TypeIdentifier>
-  </Enum>
-  <Font Name="Segoe UI" Size="9" />
-</ClassDiagram>

+ 1 - 1
Terminal.Gui/Views/FileDialogs/FileDialog.cs

@@ -409,7 +409,7 @@ public class FileDialog : Dialog, IDesignable
     }
 
     /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         if (!string.IsNullOrWhiteSpace (_feedback))
         {

+ 1 - 1
Terminal.Gui/Views/GraphView/GraphView.cs

@@ -198,7 +198,7 @@ public class GraphView : View, IDesignable
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         if (CellSize.X == 0 || CellSize.Y == 0)
         {

+ 1 - 1
Terminal.Gui/Views/HexView.cs

@@ -431,7 +431,7 @@ public class HexView : View, IDesignable
     }
 
     ///<inheritdoc/>
-    protected override bool OnDrawingContent ()
+    protected override bool OnDrawingContent (DrawContext? context)
     {
         if (Source is null)
         {

Some files were not shown because too many files changed in this diff