diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1684f416c..d6686b758 100644 --- a/CONTRIBUTING.md +++ b/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) --- diff --git a/Terminal.Gui/ViewBase/Adornment/ShadowView.cs b/Terminal.Gui/ViewBase/Adornment/ShadowView.cs index a2d2eb577..e2dbb7d46 100644 --- a/Terminal.Gui/ViewBase/Adornment/ShadowView.cs +++ b/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 ( diff --git a/Terminal.Gui/ViewBase/View.Drawing.cs b/Terminal.Gui/ViewBase/View.Drawing.cs index 6919b8e34..1f2756123 100644 --- a/Terminal.Gui/ViewBase/View.Drawing.cs +++ b/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); } } diff --git a/Terminal.Gui/ViewBase/View.cs b/Terminal.Gui/ViewBase/View.cs index a86589750..0a26aa37b 100644 --- a/Terminal.Gui/ViewBase/View.cs +++ b/Terminal.Gui/ViewBase/View.cs @@ -130,6 +130,9 @@ public partial class View : IDisposable, ISupportInitializeNotification set => _driver = value; } + /// Gets the screen buffer contents. This is a convenience property for Views that need direct access to the screen buffer. + protected Cell [,]? ScreenContents => Driver?.Contents; + /// Initializes a new instance of . /// /// diff --git a/Terminal.Gui/Views/Color/ColorBar.cs b/Terminal.Gui/Views/Color/ColorBar.cs index 262abc99e..ad15e231f 100644 --- a/Terminal.Gui/Views/Color/ColorBar.cs +++ b/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 ()); diff --git a/Terminal.Gui/Views/FileDialogs/FileDialog.cs b/Terminal.Gui/Views/FileDialogs/FileDialog.cs index 2d326cc5f..7fd813fb8 100644 --- a/Terminal.Gui/Views/FileDialogs/FileDialog.cs +++ b/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); diff --git a/Terminal.Gui/Views/GraphView/GraphView.cs b/Terminal.Gui/Views/GraphView/GraphView.cs index dfd6bab9b..92b31a60f 100644 --- a/Terminal.Gui/Views/GraphView/GraphView.cs +++ b/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 diff --git a/Terminal.Gui/Views/GraphView/IAnnotation.cs b/Terminal.Gui/Views/GraphView/IAnnotation.cs index 9ebfe4904..004339875 100644 --- a/Terminal.Gui/Views/GraphView/IAnnotation.cs +++ b/Terminal.Gui/Views/GraphView/IAnnotation.cs @@ -18,7 +18,7 @@ public interface IAnnotation /// /// Called once after series have been rendered (or before if is true). Use - /// to draw and to avoid drawing outside of graph + /// methods like and to draw. Use to avoid drawing outside of graph. /// /// void Render (GraphView graph); diff --git a/Terminal.Gui/Views/GraphView/TextAnnotation.cs b/Terminal.Gui/Views/GraphView/TextAnnotation.cs index 91ae17c98..98f1fec3e 100644 --- a/Terminal.Gui/Views/GraphView/TextAnnotation.cs +++ b/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)); } } } diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs index 5bfd9a5eb..b933af9e0 100644 --- a/Terminal.Gui/Views/ListView.cs +++ b/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); diff --git a/Terminal.Gui/Views/Menuv1/Menu.cs b/Terminal.Gui/Views/Menuv1/Menu.cs index a079418f1..ceb63d412 100644 --- a/Terminal.Gui/Views/Menuv1/Menu.cs +++ b/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); } } } diff --git a/Terminal.Gui/Views/Menuv1/MenuBar.cs b/Terminal.Gui/Views/Menuv1/MenuBar.cs index b08e61911..8b66a63dc 100644 --- a/Terminal.Gui/Views/Menuv1/MenuBar.cs +++ b/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; } diff --git a/Terminal.Gui/Views/ProgressBar.cs b/Terminal.Gui/Views/ProgressBar.cs index 0d78b2c93..3e27bd556 100644 --- a/Terminal.Gui/Views/ProgressBar.cs +++ b/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)' '); } } diff --git a/Terminal.Gui/Views/RadioGroup.cs b/Terminal.Gui/Views/RadioGroup.cs index b3c522b25..1040c6e83 100644 --- a/Terminal.Gui/Views/RadioGroup.cs +++ b/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) diff --git a/Terminal.Gui/Views/Slider/Slider.cs b/Terminal.Gui/Views/Slider/Slider.cs index b8642686f..ff0308a56 100644 --- a/Terminal.Gui/Views/Slider/Slider.cs +++ b/Terminal.Gui/Views/Slider/Slider.cs @@ -441,13 +441,13 @@ public class Slider : 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); } /// Sets the dimensions of the Slider to the ideal values. diff --git a/Terminal.Gui/Views/SpinnerView/SpinnerView.cs b/Terminal.Gui/Views/SpinnerView/SpinnerView.cs index 5ee1db270..00f723fe6 100644 --- a/Terminal.Gui/Views/SpinnerView/SpinnerView.cs +++ b/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]); } } diff --git a/Terminal.Gui/Views/TableView/TableView.cs b/Terminal.Gui/Views/TableView/TableView.cs index a269d69d0..272e7495d 100644 --- a/Terminal.Gui/Views/TableView/TableView.cs +++ b/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); } /// - /// Override to provide custom multi colouring to cells. Use to with - /// . The driver will already be in the correct place when rendering and - /// you - /// must render the full or the view will not look right. For simpler provision of color use - /// For changing the content that is rendered use - /// + /// Override to provide custom multi-coloring to cells. Use methods like . + /// The cursor will already be in the correct position when rendering. You must render the full + /// or the view will not look right. For simpler color provision use + /// . For changing the content that is rendered use + /// . /// /// /// @@ -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 /// 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); } /// @@ -1534,14 +1533,14 @@ public class TableView : View, IDesignable /// 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++) diff --git a/Terminal.Gui/Views/TableView/TreeTableSource.cs b/Terminal.Gui/Views/TableView/TreeTableSource.cs index c8c4a01fe..6cbb5b0a7 100644 --- a/Terminal.Gui/Views/TableView/TreeTableSource.cs +++ b/Terminal.Gui/Views/TableView/TreeTableSource.cs @@ -178,7 +178,7 @@ public class TreeTableSource : IEnumerableTableSource, IDisposable where T Branch branch = RowToBranch (hit.Value.Y); - if (branch.IsHitOnExpandableSymbol (Application.Driver, offsetX.Value)) + if (branch.IsHitOnExpandableSymbol (offsetX.Value)) { T m = branch.Model; diff --git a/Terminal.Gui/Views/TextInput/TextField.cs b/Terminal.Gui/Views/TextInput/TextField.cs index 73c449d81..70d7e007e 100644 --- a/Terminal.Gui/Views/TextInput/TextField.cs +++ b/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 text) diff --git a/Terminal.Gui/Views/TextInput/TextValidateField.cs b/Terminal.Gui/Views/TextInput/TextValidateField.cs index 1b32d5cf0..f7e897feb 100644 --- a/Terminal.Gui/Views/TextInput/TextValidateField.cs +++ b/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; diff --git a/Terminal.Gui/Views/TreeView/Branch.cs b/Terminal.Gui/Views/TreeView/Branch.cs index 5b628ef12..59b0475a6 100644 --- a/Terminal.Gui/Views/TreeView/Branch.cs +++ b/Terminal.Gui/Views/TreeView/Branch.cs @@ -454,7 +454,7 @@ internal class Branch where T : class /// /// /// - internal bool IsHitOnExpandableSymbol (IConsoleDriver driver, int x) + internal bool IsHitOnExpandableSymbol (int x) { // if leaf node then we cannot expand if (!CanExpand ()) diff --git a/Terminal.Gui/Views/TreeView/TreeView.cs b/Terminal.Gui/Views/TreeView/TreeView.cs index 858bc465d..c640b4e25 100644 --- a/Terminal.Gui/Views/TreeView/TreeView.cs +++ b/Terminal.Gui/Views/TreeView/TreeView.cs @@ -1065,7 +1065,7 @@ public class TreeView : 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 : 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 : 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)); } } diff --git a/docfx/docs/View.md b/docfx/docs/View.md index af69a5713..623650ca2 100644 --- a/docfx/docs/View.md +++ b/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). diff --git a/docfx/docs/drivers.md b/docfx/docs/drivers.md index 17b753984..3a78d597a 100644 --- a/docfx/docs/drivers.md +++ b/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 it's a v2 driver with facade -if (driver is IConsoleDriverFacade facade) +// Check if 24-bit color is supported +bool supportsTrueColor = Application.Driver?.SupportsTrueColor ?? false; + +// 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`: diff --git a/docfx/docs/migratingfromv1.md b/docfx/docs/migratingfromv1.md index 8bdbb903b..6677b0987 100644 --- a/docfx/docs/migratingfromv1.md +++ b/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.