Browse Source

Fixes #4331 - Use Application.Screen and ScreenContents to reduce Driver coupling (#4336)

* Initial plan

* Replace direct Driver access with ViewBase helper methods

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

* Update documentation to reference View methods instead of Driver

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

* Fix documentation wording to avoid driver reference

* Fix missed Driver accesses in Slider.cs

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

* Use Application.Screen instead of ScreenRows/ScreenCols, keep MoveToScreen/FillRectScreen internal for ViewBase only

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

* Remove MoveToScreen and FillRectScreen helper methods, use Driver directly in ViewBase classes

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

* Improve documentation clarity and grammar per CONTRIBUTING.md guidelines

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

* Add MoveToScreenPosition helper to eliminate Driver.Move calls in View subclasses

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

* Remove MoveToScreenPosition helper method, Menu.cs accesses Driver directly

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

* Replace Driver.Move with View.Move in Menu.cs

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

* Update documentation to reflect Driver encapsulation changes

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

* Add PR warnings policy to CONTRIBUTING.md

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

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: Tig <[email protected]>
Co-authored-by: tig <[email protected]>
Copilot 1 tháng trước cách đây
mục cha
commit
f068709d13

+ 6 - 0
CONTRIBUTING.md

@@ -241,6 +241,11 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
 - **Tests**: Add tests for new functionality (see [Testing Requirements](#testing-requirements))
 - **Coverage**: Maintain or increase code coverage
 - **Scenarios**: Update UICatalog scenarios when adding features
+- **Warnings**: **CRITICAL - PRs must not introduce any new warnings**
+  - Any file modified in a PR that currently generates warnings **MUST** be fixed to remove those warnings
+  - Exception: Warnings caused by `[Obsolete]` attributes can remain
+  - Expected baseline: ~326 warnings (mostly nullable reference warnings, unused variables, xUnit suggestions)
+  - Action: Before submitting a PR, verify your changes don't add new warnings and fix any warnings in files you modify
 
 ---
 
@@ -396,6 +401,7 @@ Key documentation:
 - ❌ Don't decrease code coverage
 - ❌ **Don't use `var` for anything but built-in simple types** (use explicit types)
 - ❌ **Don't use redundant type names with `new`** (**ALWAYS PREFER** target-typed `new ()`)
+- ❌ **Don't introduce new warnings** (fix warnings in files you modify; exception: `[Obsolete]` warnings)
 
 ---
 

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

@@ -95,12 +95,12 @@ internal class ShadowView : View
         {
             for (int c = Math.Max (0, screen.X + 1); c < screen.X + screen.Width; c++)
             {
-                Driver?.Move (c, r);
+                Driver.Move (c, r);
                 SetAttribute (GetAttributeUnderLocation (new (c, r)));
 
-                if (c < Driver?.Contents!.GetLength (1) && r < Driver?.Contents?.GetLength (0))
+                if (c < ScreenContents?.GetLength (1) && r < ScreenContents?.GetLength (0))
                 {
-                    Driver.AddRune (Driver.Contents [r, c].Rune);
+                    AddRune (ScreenContents [r, c].Rune);
                 }
             }
         }
@@ -129,12 +129,12 @@ internal class ShadowView : View
         {
             for (int r = Math.Max (0, screen.Y); r < screen.Y + viewport.Height; r++)
             {
-                Driver?.Move (c, r);
+                Driver.Move (c, r);
                 SetAttribute (GetAttributeUnderLocation (new (c, r)));
 
-                if (Driver?.Contents is { } && screen.X < Driver.Contents.GetLength (1) && r < Driver.Contents.GetLength (0))
+                if (ScreenContents is { } && screen.X < ScreenContents.GetLength (1) && r < ScreenContents.GetLength (0))
                 {
-                    Driver.AddRune (Driver.Contents [r, c].Rune);
+                    AddRune (ScreenContents [r, c].Rune);
                 }
             }
         }
@@ -151,14 +151,14 @@ internal class ShadowView : View
             return Attribute.Default;
         }
 
-        if (Driver?.Contents == null ||
-            location.Y < 0 || location.Y >= Driver.Contents.GetLength (0) ||
-            location.X < 0 || location.X >= Driver.Contents.GetLength (1))
+        if (ScreenContents == null ||
+            location.Y < 0 || location.Y >= ScreenContents.GetLength (0) ||
+            location.X < 0 || location.X >= ScreenContents.GetLength (1))
         {
             return Attribute.Default;
         }
 
-        Attribute attr = Driver!.Contents! [location.Y, location.X].Attribute!.Value;
+        Attribute attr = ScreenContents [location.Y, location.X].Attribute!.Value;
 
         var newAttribute =
             new Attribute (

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

@@ -658,7 +658,7 @@ public partial class View // Drawing APIs
                     Driver.Move (p.Key.X, p.Key.Y);
 
                     // TODO: #2616 - Support combining sequences that don't normalize
-                    Driver.AddRune (p.Value.Value.Rune);
+                    AddRune (p.Value.Value.Rune);
                 }
             }
 

+ 3 - 0
Terminal.Gui/ViewBase/View.cs

@@ -130,6 +130,9 @@ public partial class View : IDisposable, ISupportInitializeNotification
         set => _driver = value;
     }
 
+    /// <summary>Gets the screen buffer contents. This is a convenience property for Views that need direct access to the screen buffer.</summary>
+    protected Cell [,]? ScreenContents => Driver?.Contents;
+
     /// <summary>Initializes a new instance of <see cref="View"/>.</summary>
     /// <remarks>
     ///     <para>

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

@@ -92,7 +92,7 @@ internal abstract class ColorBar : View, IColorBar
         {
             Move (0, 0);
             SetAttribute (HasFocus ? GetAttributeForRole (VisualRole.Focus) : GetAttributeForRole (VisualRole.Normal));
-            Driver?.AddStr (Text);
+            AddStr (Text);
 
             // TODO: is there a better method than this? this is what it is in TableView
             xOffset = Text.EnumerateRunes ().Sum (c => c.GetColumns ());

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

@@ -427,9 +427,9 @@ public class FileDialog : Dialog, IDesignable
             Move (0, Viewport.Height / 2);
 
             SetAttribute (new (Color.Red, GetAttributeForRole (VisualRole.Normal).Background));
-            Driver!.AddStr (new (' ', feedbackPadLeft));
-            Driver.AddStr (_feedback);
-            Driver.AddStr (new (' ', feedbackPadRight));
+            AddStr (new (' ', feedbackPadLeft));
+            AddStr (_feedback);
+            AddStr (new (' ', feedbackPadRight));
         }
 
         return true;
@@ -507,7 +507,7 @@ public class FileDialog : Dialog, IDesignable
             _allowedTypeMenuBar.DrawingContent += (s, e) =>
                                                   {
                                                       _allowedTypeMenuBar.Move (e.NewViewport.Width - 1, 0);
-                                                      Driver!.AddRune (Glyphs.DownArrow);
+                                                      AddRune (Glyphs.DownArrow);
                                                   };
 
             Add (_allowedTypeMenuBar);

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

@@ -213,7 +213,7 @@ public class GraphView : View, IDesignable
         for (var i = 0; i < Viewport.Height; i++)
         {
             Move (0, i);
-            Driver?.AddStr (new (' ', Viewport.Width));
+            AddStr (new (' ', Viewport.Width));
         }
 
         // If there is no data do not display a graph

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

@@ -18,7 +18,7 @@ public interface IAnnotation
 
     /// <summary>
     ///     Called once after series have been rendered (or before if <see cref="BeforeSeries"/> is true). Use
-    ///     <see cref="View.Driver"/> to draw and <see cref="View.Viewport"/> to avoid drawing outside of graph
+    ///     methods like <see cref="View.AddStr(string)"/> and <see cref="View.AddRune(Rune)"/> to draw. Use <see cref="View.Viewport"/> to avoid drawing outside of graph.
     /// </summary>
     /// <param name="graph"></param>
     void Render (GraphView graph);

+ 2 - 2
Terminal.Gui/Views/GraphView/TextAnnotation.cs

@@ -68,11 +68,11 @@ public class TextAnnotation : IAnnotation
 
         if (Text.Length < availableWidth)
         {
-            graph.Driver?.AddStr (Text);
+            graph.AddStr (Text);
         }
         else
         {
-            graph.Driver?.AddStr (Text.Substring (0, availableWidth));
+            graph.AddStr (Text.Substring (0, availableWidth));
         }
     }
 }

+ 3 - 3
Terminal.Gui/Views/ListView.cs

@@ -750,7 +750,7 @@ public class ListView : View, IDesignable
             {
                 for (var c = 0; c < f.Width; c++)
                 {
-                    Driver?.AddRune ((Rune)' ');
+                    AddRune ((Rune)' ');
                 }
             }
             else
@@ -766,11 +766,11 @@ public class ListView : View, IDesignable
 
                 if (_allowsMarking)
                 {
-                    Driver?.AddRune (
+                    AddRune (
                                     _source.IsMarked (item) ? AllowsMultipleSelection ? Glyphs.CheckStateChecked : Glyphs.Selected :
                                     AllowsMultipleSelection ? Glyphs.CheckStateUnChecked : Glyphs.UnSelected
                                    );
-                    Driver?.AddRune ((Rune)' ');
+                    AddRune ((Rune)' ');
                 }
 
                 Source.Render (this, isSelected, item, col, row, f.Width - col, start);

+ 18 - 20
Terminal.Gui/Views/Menuv1/Menu.cs

@@ -847,7 +847,7 @@ internal sealed class Menu : View
                 continue;
             }
 
-            if (ViewportToScreen (Viewport).Y + i >= Driver.Rows)
+            if (ViewportToScreen (Viewport).Y + i >= Application.Screen.Height)
             {
                 break;
             }
@@ -863,11 +863,10 @@ internal sealed class Menu : View
 
             if (item is null && BorderStyle != LineStyle.None)
             {
-                Point s = ViewportToScreen (new Point (-1, i));
-                Driver.Move (s.X, s.Y);
-                Driver.AddRune (Glyphs.LeftTee);
+                Move (-1, i);
+                AddRune (Glyphs.LeftTee);
             }
-            else if (Frame.X < Driver.Cols)
+            else if (Frame.X < Application.Screen.Width)
             {
                 Move (0, i);
             }
@@ -882,28 +881,28 @@ internal sealed class Menu : View
                     continue;
                 }
 
-                if (ViewportToScreen (Viewport).X + p >= Driver.Cols)
+                if (ViewportToScreen (Viewport).X + p >= Application.Screen.Width)
                 {
                     break;
                 }
 
                 if (item is null)
                 {
-                    Driver.AddRune (Glyphs.HLine);
+                    AddRune (Glyphs.HLine);
                 }
                 else if (i == 0 && p == 0 && _host.UseSubMenusSingleFrame && item.Parent!.Parent is { })
                 {
-                    Driver.AddRune (Glyphs.LeftArrow);
+                    AddRune (Glyphs.LeftArrow);
                 }
 
                 // This `- 3` is left border + right border + one row in from right
                 else if (p == Frame.Width - 3 && _barItems?.SubMenu (_barItems.Children [i]!) is { })
                 {
-                    Driver.AddRune (Glyphs.RightArrow);
+                    AddRune (Glyphs.RightArrow);
                 }
                 else
                 {
-                    Driver.AddRune ((Rune)' ');
+                    AddRune ((Rune)' ');
                 }
             }
 
@@ -911,9 +910,8 @@ internal sealed class Menu : View
             {
                 if (BorderStyle != LineStyle.None && SuperView?.Frame.Right - Frame.X > Frame.Width)
                 {
-                    Point s = ViewportToScreen (new Point (Frame.Width - 2, i));
-                    Driver.Move (s.X, s.Y);
-                    Driver.AddRune (Glyphs.RightTee);
+                    Move (Frame.Width - 2, i);
+                    AddRune (Glyphs.RightTee);
                 }
 
                 continue;
@@ -950,9 +948,9 @@ internal sealed class Menu : View
 
             Point screen = ViewportToScreen (new Point (0, i));
 
-            if (screen.X < Driver.Cols)
+            if (screen.X < Application.Screen.Width)
             {
-                Driver.Move (screen.X + 1, screen.Y);
+                Move (1, i);
 
                 if (!item.IsEnabled ())
                 {
@@ -991,16 +989,16 @@ internal sealed class Menu : View
                 int col = Frame.Width - l - 3;
                 screen = ViewportToScreen (new Point (col, i));
 
-                if (screen.X < Driver.Cols)
+                if (screen.X < Application.Screen.Width)
                 {
-                    Driver.Move (screen.X, screen.Y);
-                    Driver.AddStr (item.Help);
+                    Move (col, i);
+                    AddStr (item.Help);
 
                     // The shortcut tag string
                     if (!string.IsNullOrEmpty (item.ShortcutTag))
                     {
-                        Driver.Move (screen.X + l - item.ShortcutTag.GetColumns (), screen.Y);
-                        Driver.AddStr (item.ShortcutTag);
+                        Move (col + l - item.ShortcutTag.GetColumns (), i);
+                        AddStr (item.ShortcutTag);
                     }
                 }
             }

+ 1 - 1
Terminal.Gui/Views/Menuv1/MenuBar.cs

@@ -697,7 +697,7 @@ public class MenuBar : View, IDesignable
     internal Point GetScreenOffset ()
     {
         // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
-        if (Driver is null)
+        if (Application.Screen.Height == 0)
         {
             return Point.Empty;
         }

+ 4 - 4
Terminal.Gui/Views/ProgressBar.cs

@@ -144,11 +144,11 @@ public class ProgressBar : View, IDesignable
             {
                 if (Array.IndexOf (_activityPos!, i) != -1)
                 {
-                    Driver?.AddRune (SegmentCharacter);
+                    AddRune (SegmentCharacter);
                 }
                 else
                 {
-                    Driver?.AddRune ((Rune)' ');
+                    AddRune ((Rune)' ');
                 }
             }
         }
@@ -159,12 +159,12 @@ public class ProgressBar : View, IDesignable
 
             for (i = 0; (i < mid) & (i < Viewport.Width); i++)
             {
-                Driver?.AddRune (SegmentCharacter);
+                AddRune (SegmentCharacter);
             }
 
             for (; i < Viewport.Width; i++)
             {
-                Driver?.AddRune ((Rune)' ');
+                AddRune ((Rune)' ');
             }
         }
 

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

@@ -375,7 +375,7 @@ public class RadioGroup : View, IDesignable, IOrientation
 
             string rl = _radioLabels [i];
             SetAttribute (GetAttributeForRole (VisualRole.Normal));
-            Driver?.AddStr ($"{(i == _selected ? Glyphs.Selected : Glyphs.UnSelected)} ");
+            AddStr ($"{(i == _selected ? Glyphs.Selected : Glyphs.UnSelected)} ");
             TextFormatter.FindHotKey (rl, HotKeySpecifier, out int hotPos, out Key hotKey);
 
             if (hotPos != -1 && hotKey != Key.Empty)

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

@@ -441,13 +441,13 @@ public class Slider<T> : View, IOrientation
     private void MoveAndAdd (int x, int y, Rune rune)
     {
         Move (x, y);
-        Driver?.AddRune (rune);
+        AddRune (rune);
     }
 
     private void MoveAndAdd (int x, int y, string str)
     {
         Move (x, y);
-        Driver?.AddStr (str);
+        AddStr (str);
     }
 
     /// <summary>Sets the dimensions of the Slider to the ideal values.</summary>

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

@@ -187,7 +187,7 @@ public class SpinnerView : View, IDesignable
         if (Sequence is { Length: > 0 } && _currentIdx < Sequence.Length)
         {
             Move (Viewport.X, Viewport.Y);
-            Driver?.AddStr (Sequence [_currentIdx]);
+            AddStr (Sequence [_currentIdx]);
         }
     }
 

+ 19 - 20
Terminal.Gui/Views/TableView/TableView.cs

@@ -943,7 +943,7 @@ public class TableView : View, IDesignable
         SetAttribute (GetAttributeForRole (VisualRole.Normal));
 
         //invalidate current row (prevents scrolling around leaving old characters in the frame
-        Driver?.AddStr (new (' ', Viewport.Width));
+        AddStr (new (' ', Viewport.Width));
 
         var line = 0;
 
@@ -1289,12 +1289,11 @@ public class TableView : View, IDesignable
     protected virtual void OnSelectedCellChanged (SelectedCellChangedEventArgs args) { SelectedCellChanged?.Invoke (this, args); }
 
     /// <summary>
-    ///     Override to provide custom multi colouring to cells.  Use <see cref="View.Driver"/> to with
-    ///     <see cref="IConsoleDriver.AddStr(string)"/>.  The driver will already be in the correct place when rendering and
-    ///     you
-    ///     must render the full <paramref name="render"/> or the view will not look right.  For simpler provision of color use
-    ///     <see cref="ColumnStyle.ColorGetter"/> For changing the content that is rendered use
-    ///     <see cref="ColumnStyle.RepresentationGetter"/>
+    ///     Override to provide custom multi-coloring to cells. Use methods like <see cref="View.AddStr(string)"/>.
+    ///     The cursor will already be in the correct position when rendering. You must render the full
+    ///     <paramref name="render"/> or the view will not look right. For simpler color provision use
+    ///     <see cref="ColumnStyle.ColorGetter"/>. For changing the content that is rendered use
+    ///     <see cref="ColumnStyle.RepresentationGetter"/>.
     /// </summary>
     /// <param name="cellAttribute"></param>
     /// <param name="render"></param>
@@ -1310,19 +1309,19 @@ public class TableView : View, IDesignable
             {
                 // invert the color of the current cell for the first character
                 SetAttribute (new (cellAttribute.Foreground, cellAttribute.Background, TextStyle.Reverse));
-                Driver?.AddRune ((Rune)render [0]);
+                AddRune ((Rune)render [0]);
 
                 if (render.Length > 1)
                 {
                     SetAttribute (cellAttribute);
-                    Driver?.AddStr (render.Substring (1));
+                    AddStr (render.Substring (1));
                 }
             }
         }
         else
         {
             SetAttribute (cellAttribute);
-            Driver?.AddStr (render);
+            AddStr (render);
         }
     }
 
@@ -1349,10 +1348,10 @@ public class TableView : View, IDesignable
     /// <returns></returns>
     internal int GetHeaderHeightIfAny () { return ShouldRenderHeaders () ? GetHeaderHeight () : 0; }
 
-    private void AddRuneAt (IConsoleDriver d, int col, int row, Rune ch)
+    private void AddRuneAt (int col, int row, Rune ch)
     {
         Move (col, row);
-        d?.AddRune (ch);
+        AddRune (ch);
     }
 
     /// <summary>
@@ -1534,14 +1533,14 @@ public class TableView : View, IDesignable
     /// <param name="width"></param>
     private void ClearLine (int row, int width)
     {
-        if (Driver is null)
+        if (Application.Screen.Height == 0)
         {
             return;
         }
 
         Move (0, row);
         SetAttribute (GetAttributeForRole (VisualRole.Normal));
-        Driver.AddStr (new (' ', width));
+        AddStr (new (' ', width));
     }
 
     private void ClearMultiSelectedRegions (bool keepToggledSelections)
@@ -1734,7 +1733,7 @@ public class TableView : View, IDesignable
                 }
             }
 
-            AddRuneAt (Driver, c, row, rune);
+            AddRuneAt (c, row, rune);
         }
     }
 
@@ -1762,7 +1761,7 @@ public class TableView : View, IDesignable
 
             Move (current.X, row);
 
-            Driver?.AddStr (TruncateOrPad (colName, colName, current.Width, colStyle));
+            AddStr (TruncateOrPad (colName, colName, current.Width, colStyle));
 
             if (Style.ExpandLastColumn == false && current.IsVeryLast)
             {
@@ -1810,9 +1809,9 @@ public class TableView : View, IDesignable
                 }
             }
 
-            if (Driver is { })
+            if (Application.Screen.Height > 0)
             {
-                AddRuneAt (Driver, c, row, rune);
+                AddRuneAt (c, row, rune);
             }
         }
     }
@@ -1906,7 +1905,7 @@ public class TableView : View, IDesignable
                 }
             }
 
-            AddRuneAt (Driver, c, row, rune);
+            AddRuneAt (c, row, rune);
         }
     }
 
@@ -1934,7 +1933,7 @@ public class TableView : View, IDesignable
         }
 
         SetAttribute (attribute.Value);
-        Driver?.AddStr (new (' ', Viewport.Width));
+        AddStr (new (' ', Viewport.Width));
 
         // Render cells for each visible header for the current row
         for (var i = 0; i < columnsToRender.Length; i++)

+ 1 - 1
Terminal.Gui/Views/TableView/TreeTableSource.cs

@@ -178,7 +178,7 @@ public class TreeTableSource<T> : IEnumerableTableSource<T>, IDisposable where T
 
         Branch<T> branch = RowToBranch (hit.Value.Y);
 
-        if (branch.IsHitOnExpandableSymbol (Application.Driver, offsetX.Value))
+        if (branch.IsHitOnExpandableSymbol (offsetX.Value))
         {
             T m = branch.Model;
 

+ 3 - 3
Terminal.Gui/Views/TextInput/TextField.cs

@@ -973,7 +973,7 @@ public class TextField : View, IDesignable
 
             if (col + cols <= width)
             {
-                Driver?.AddRune (Secret ? Glyphs.Dot : rune);
+                AddRune (Secret ? Glyphs.Dot : rune);
             }
 
             if (!TextModel.SetCol (ref col, width, cols))
@@ -992,7 +992,7 @@ public class TextField : View, IDesignable
         // Fill rest of line with spaces
         for (int i = col; i < width; i++)
         {
-            Driver?.AddRune ((Rune)' ');
+            AddRune ((Rune)' ');
         }
 
         PositionCursor ();
@@ -1717,7 +1717,7 @@ public class TextField : View, IDesignable
             render = render [..Viewport.Width];
         }
 
-        Driver?.AddStr (render);
+        AddStr (render);
     }
 
     private void SetClipboard (IEnumerable<Rune> text)

+ 4 - 4
Terminal.Gui/Views/TextInput/TextValidateField.cs

@@ -177,7 +177,7 @@ public class TextValidateField : View, IDesignable
         if (_provider is null)
         {
             Move (0, 0);
-            Driver?.AddStr ("Error: ITextValidateProvider not set!");
+            AddStr ("Error: ITextValidateProvider not set!");
 
             return true;
         }
@@ -194,7 +194,7 @@ public class TextValidateField : View, IDesignable
 
         for (var i = 0; i < marginLeft; i++)
         {
-            Driver?.AddRune ((Rune)' ');
+            AddRune ((Rune)' ');
         }
 
         // Content
@@ -203,7 +203,7 @@ public class TextValidateField : View, IDesignable
         // Content
         for (var i = 0; i < _provider.DisplayText.Length; i++)
         {
-            Driver?.AddRune ((Rune)_provider.DisplayText [i]);
+            AddRune ((Rune)_provider.DisplayText [i]);
         }
 
         // Right Margin
@@ -211,7 +211,7 @@ public class TextValidateField : View, IDesignable
 
         for (var i = 0; i < marginRight; i++)
         {
-            Driver?.AddRune ((Rune)' ');
+            AddRune ((Rune)' ');
         }
 
         return true;

+ 1 - 1
Terminal.Gui/Views/TreeView/Branch.cs

@@ -454,7 +454,7 @@ internal class Branch<T> where T : class
     /// <param name="driver"></param>
     /// <param name="x"></param>
     /// <returns></returns>
-    internal bool IsHitOnExpandableSymbol (IConsoleDriver driver, int x)
+    internal bool IsHitOnExpandableSymbol (int x)
     {
         // if leaf node then we cannot expand
         if (!CanExpand ())

+ 3 - 3
Terminal.Gui/Views/TreeView/TreeView.cs

@@ -1065,7 +1065,7 @@ public class TreeView<T> : View, ITreeView where T : class
                 return false;
             }
 
-            bool isExpandToggleAttempt = clickedBranch.IsHitOnExpandableSymbol (Driver, me.Position.X);
+            bool isExpandToggleAttempt = clickedBranch.IsHitOnExpandableSymbol (me.Position.X);
 
             // If we are already selected (double click)
             if (Equals (SelectedObject, clickedBranch.Model))
@@ -1157,7 +1157,7 @@ public class TreeView<T> : View, ITreeView where T : class
         if (TreeBuilder is null)
         {
             Move (0, 0);
-            Driver?.AddStr (NoBuilderError);
+            AddStr (NoBuilderError);
 
             return true;
         }
@@ -1179,7 +1179,7 @@ public class TreeView<T> : View, ITreeView where T : class
                 // Else clear the line to prevent stale symbols due to scrolling etc
                 Move (0, line);
                 SetAttribute (GetAttributeForRole (VisualRole.Normal));
-                Driver?.AddStr (new (' ', Viewport.Width));
+                AddStr (new (' ', Viewport.Width));
             }
         }
 

+ 2 - 0
docfx/docs/View.md

@@ -36,6 +36,8 @@ See the [Layout Deep Dive](layout.md) and the [Arrangement Deep Dive](arrangemen
 
 See the [Drawing Deep Dive](drawing.md).
 
+Views should use viewport-relative coordinates for all drawing operations. The `View.Move(col, row)` method positions the cursor using viewport-relative coordinates. For screen dimensions, use @Terminal.Gui.App.Application.Screen instead of accessing the driver directly.
+
 ### Navigation
 
 See the [Navigation Deep Dive](navigation.md).

+ 23 - 7
docfx/docs/drivers.md

@@ -151,7 +151,7 @@ When `Application.Shutdown()` is called:
 
 ### IConsoleDriver
 
-The main driver interface that applications interact with. Provides:
+The main driver interface that the framework uses internally. Provides:
 
 - **Screen Management**: `Screen`, `Cols`, `Rows`, `Contents`
 - **Drawing Operations**: `AddRune()`, `AddStr()`, `Move()`, `FillRect()`
@@ -161,6 +161,12 @@ The main driver interface that applications interact with. Provides:
 - **Events**: `KeyDown`, `KeyUp`, `MouseEvent`, `SizeChanged`
 - **Platform Features**: `SupportsTrueColor`, `Force16Colors`, `Clipboard`
 
+**Note:** The driver is internal to Terminal.Gui. View classes should not access `Driver` directly. Instead:
+- Use @Terminal.Gui.App.Application.Screen to get screen dimensions
+- Use @Terminal.Gui.ViewBase.View.Move for positioning (with viewport-relative coordinates)
+- Use @Terminal.Gui.ViewBase.View.AddRune and @Terminal.Gui.ViewBase.View.AddStr for drawing
+- ViewBase infrastructure classes (in `Terminal.Gui/ViewBase/`) can access Driver when needed for framework implementation
+
 ### IConsoleDriverFacade
 
 Extended interface for v2 drivers that exposes the internal components:
@@ -215,18 +221,23 @@ This ensures Terminal.Gui applications can be debugged directly in Visual Studio
 - Captures output for verification
 - Always used when `Application._forceFakeConsole` is true
 
-## Example: Accessing Driver Components
+## Example: Checking Driver Capabilities
 
 ```csharp
 Application.Init();
 
-// Access the driver
-IConsoleDriver driver = Application.Driver;
+// The driver is internal - access through Application properties
+// Check screen dimensions
+var screenWidth = Application.Screen.Width;
+var screenHeight = Application.Screen.Height;
+
+// Check if 24-bit color is supported
+bool supportsTrueColor = Application.Driver?.SupportsTrueColor ?? false;
 
-// Check if it's a v2 driver with facade
-if (driver is IConsoleDriverFacade facade)
+// Access advanced components (for framework/infrastructure code only)
+if (Application.Driver is IConsoleDriverFacade facade)
 {
-    // Access individual components
+    // Access individual components for advanced scenarios
     IInputProcessor inputProcessor = facade.InputProcessor;
     IOutputBuffer outputBuffer = facade.OutputBuffer;
     IWindowSizeMonitor sizeMonitor = facade.WindowSizeMonitor;
@@ -239,6 +250,11 @@ if (driver is IConsoleDriverFacade facade)
 }
 ```
 
+**Important:** View subclasses should not access `Application.Driver`. Use the View APIs instead:
+- `View.Move(col, row)` for positioning
+- `View.AddRune()` and `View.AddStr()` for drawing
+- `Application.Screen` for screen dimensions
+
 ## Custom Drivers
 
 To create a custom driver, implement `IComponentFactory<T>`:

+ 22 - 2
docfx/docs/migratingfromv1.md

@@ -225,7 +225,7 @@ The cursor and focus system has been redesigned in v2 to be more consistent and
 
 ### Cursor
 
-In v1, whether the cursor (the flashing caret) was visible or not was controlled by `View.CursorVisibility` which was an enum extracted from Ncruses/Terminfo. It only works in some cases on Linux, and only partially with `WindowsDriver`. The position of the cursor was the same as `ConsoleDriver.Row`/`Col` and determined by the last call to `ConsoleDriver.Move`. `View.PositionCursor()` could be overridden by views to cause `Application` to call `ConsoleDriver.Move` on behalf of the app and to manage setting `CursorVisibility`. This API was confusing and bug-prone.
+In v1, whether the cursor (the flashing caret) was visible or not was controlled by `View.CursorVisibility` which was an enum extracted from Ncruses/Terminfo. It only works in some cases on Linux, and only partially with `WindowsDriver`. The position of the cursor was determined by the last call to the driver's Move method. `View.PositionCursor()` could be overridden by views to cause `Application` to call the driver's positioning method on behalf of the app and to manage setting `CursorVisibility`. This API was confusing and bug-prone.
 
 In v2, the API is (NOT YET IMPLEMENTED) simplified. A view simply reports the style of cursor it wants and the Viewport-relative location:
 
@@ -237,7 +237,7 @@ In v2, the API is (NOT YET IMPLEMENTED) simplified. A view simply reports the st
 	- If `null` the default cursor style is used.
 	- If `{}` specifies the style of cursor. See [cursor.md](cursor.md) for more.
 * `Application` now has APIs for querying available cursor styles.
-* The details in `ConsoleDriver` are no longer available to applications.	
+* The driver details are no longer directly accessible to View subclasses.	
 
 #### How to Fix (Cursor API)
 
@@ -245,6 +245,26 @@ In v2, the API is (NOT YET IMPLEMENTED) simplified. A view simply reports the st
 * Set @Terminal.Gui.ViewBase.View.CursorVisibility to the cursor style you want to use.
 * Remove any overrides of `OnEnter` and `OnLeave` that explicitly change the cursor.
 
+### Driver Access
+
+In v1, Views could access `Driver` directly (e.g., `Driver.Move()`, `Driver.Rows`, `Driver.Cols`). In v2, `Driver` is internal and View subclasses should not access it directly. ViewBase provides all necessary abstractions for Views to function without needing direct driver access.
+
+#### How to Fix (Driver Access)
+
+* Replace `Driver.Rows` and `Driver.Cols` with @Terminal.Gui.App.Application.Screen.Height and @Terminal.Gui.App.Application.Screen.Width
+* Replace direct `Driver.Move(screenX, screenY)` calls with @Terminal.Gui.ViewBase.View.Move using viewport-relative coordinates
+* Use @Terminal.Gui.ViewBase.View.AddRune and @Terminal.Gui.ViewBase.View.AddStr for drawing
+* ViewBase infrastructure classes (in `Terminal.Gui/ViewBase/`) can still access Driver for framework implementation needs
+
+```diff
+- if (x >= Driver.Cols) return;
++ if (x >= Application.Screen.Width) return;
+
+- Point screenPos = ViewportToScreen(new Point(col, row));
+- Driver.Move(screenPos.X, screenPos.Y);
++ Move(col, row);  // Move handles viewport-to-screen conversion
+```
+
 ### Focus
 
 See [navigation.md](navigation.md) for more details.