浏览代码

PositionCursor unit tests and flashing cursor fixes

Tig 1 年之前
父节点
当前提交
a1249198bd
共有 37 个文件被更改,包括 334 次插入457 次删除
  1. 17 22
      Terminal.Gui/Application.cs
  2. 4 0
      Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
  3. 11 6
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  4. 4 3
      Terminal.Gui/View/View.cs
  5. 18 16
      Terminal.Gui/View/ViewSubViews.cs
  6. 1 10
      Terminal.Gui/Views/Button.cs
  7. 0 11
      Terminal.Gui/Views/CheckBox.cs
  8. 0 7
      Terminal.Gui/Views/ColorPicker.cs
  9. 0 11
      Terminal.Gui/Views/FrameView.cs
  10. 0 9
      Terminal.Gui/Views/GraphView/GraphView.cs
  11. 1 24
      Terminal.Gui/Views/HexView.cs
  12. 0 7
      Terminal.Gui/Views/Label.cs
  13. 1 6
      Terminal.Gui/Views/ListView.cs
  14. 2 9
      Terminal.Gui/Views/Menu/Menu.cs
  15. 2 9
      Terminal.Gui/Views/Menu/MenuBar.cs
  16. 0 8
      Terminal.Gui/Views/ProgressBar.cs
  17. 1 9
      Terminal.Gui/Views/RadioGroup.cs
  18. 0 7
      Terminal.Gui/Views/ScrollBarView.cs
  19. 1 12
      Terminal.Gui/Views/ScrollView.cs
  20. 2 21
      Terminal.Gui/Views/Slider.cs
  21. 0 8
      Terminal.Gui/Views/StatusBar.cs
  22. 0 7
      Terminal.Gui/Views/TabView.cs
  23. 0 3
      Terminal.Gui/Views/TableView/TableView.cs
  24. 2 12
      Terminal.Gui/Views/TextField.cs
  25. 0 24
      Terminal.Gui/Views/TextValidateField.cs
  26. 49 60
      Terminal.Gui/Views/TextView.cs
  27. 1 9
      Terminal.Gui/Views/TileView.cs
  28. 1 11
      Terminal.Gui/Views/Toplevel.cs
  29. 17 56
      Terminal.Gui/Views/TreeView/TreeView.cs
  30. 1 3
      UICatalog/Scenarios/CharacterMap.cs
  31. 10 11
      UICatalog/Scenarios/Editor.cs
  32. 1 1
      UICatalog/Scenarios/TreeViewFileSystem.cs
  33. 148 0
      UnitTests/Application/CursorTests.cs
  34. 32 4
      UnitTests/View/NavigationTests.cs
  35. 0 34
      UnitTests/Views/StatusBarTests.cs
  36. 2 2
      UnitTests/Views/TextViewTests.cs
  37. 5 5
      UnitTests/Views/TreeViewTests.cs

+ 17 - 22
Terminal.Gui/Application.cs

@@ -557,7 +557,7 @@ public static partial class Application
         return rs;
     }
 
-    private static CursorVisibility _cachedCursorVisibility;
+    //private static CursorVisibility _cachedCursorVisibility;
 
     /// <summary>
     /// Calls <see cref="View.PositionCursor"/> on the most focused view in the view starting with <paramref name="view"/>.
@@ -579,16 +579,14 @@ public static partial class Application
             return false;
         }
 
-        CursorVisibility cachedCursorVisibility;
 
         // If the view is not visible or enabled, don't position the cursor
         if (!mostFocused.Visible || !mostFocused.Enabled)
         {
-            Driver.GetCursorVisibility (out cachedCursorVisibility);
-
-            if (cachedCursorVisibility != CursorVisibility.Invisible)
+            Driver.GetCursorVisibility (out CursorVisibility current);
+            if (current != CursorVisibility.Invisible)
             {
-                _cachedCursorVisibility = cachedCursorVisibility;
+                //_cachedCursorVisibility = current;
                 Driver.SetCursorVisibility (CursorVisibility.Invisible);
             }
 
@@ -606,40 +604,37 @@ public static partial class Application
         Point? prevCursor = new (Driver.Row, Driver.Col);
         Point? cursor = mostFocused.PositionCursor ();
 
-        // If the cursor is not in a visible location in the SuperView, hide it
+        Driver.GetCursorVisibility (out CursorVisibility currentCursorVisibility);
+
         if (cursor is { })
         {
             // Convert cursor to screen coords
             cursor = mostFocused.ViewportToScreen (mostFocused.Viewport with { Location = cursor.Value }).Location;
+
+            // If the cursor is not in a visible location in the SuperView, hide it
             if (!superViewViewport.Contains (cursor.Value))
             {
-                Driver.GetCursorVisibility (out cachedCursorVisibility);
-
-                if (cachedCursorVisibility != CursorVisibility.Invisible)
+                if (currentCursorVisibility != CursorVisibility.Invisible)
                 {
-                    _cachedCursorVisibility = cachedCursorVisibility;
+                    //_cachedCursorVisibility = currentCursorVisibility;
+                    Driver.SetCursorVisibility (CursorVisibility.Invisible);
                 }
 
-                Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
                 return false;
             }
 
-            Driver.GetCursorVisibility (out cachedCursorVisibility);
-
-            if (cachedCursorVisibility == CursorVisibility.Invisible)
+            // Show it
+            if (currentCursorVisibility == CursorVisibility.Invisible/* && currentCursorVisibility != _cachedCursorVisibility*/)
             {
-                Driver.SetCursorVisibility (_cachedCursorVisibility);
+                Driver.SetCursorVisibility (mostFocused.CursorVisibility);
             }
 
-            return prevCursor != cursor;
+            return true;
         }
 
-        Driver.GetCursorVisibility (out cachedCursorVisibility);
-
-        if (cachedCursorVisibility != CursorVisibility.Invisible)
+        if (currentCursorVisibility != CursorVisibility.Invisible)
         {
-            _cachedCursorVisibility = cachedCursorVisibility;
+            //_cachedCursorVisibility = currentCursorVisibility;
             Driver.SetCursorVisibility (CursorVisibility.Invisible);
         }
 

+ 4 - 0
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -214,9 +214,13 @@ internal class CursesDriver : ConsoleDriver
         if (!RunningUnitTests && Col >= 0 && Col < Cols && Row >= 0 && Row < Rows)
         {
             Curses.move (Row, Col);
+            Curses.raw ();
+            Curses.noecho ();
+            Curses.refresh ();
         }
     }
 
+
     public override void UpdateScreen ()
     {
         for (var row = 0; row < Rows; row++)

+ 11 - 6
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -20,6 +20,7 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using System.Text;
 using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping;
+using static Terminal.Gui.SpinnerStyle;
 
 namespace Terminal.Gui;
 
@@ -156,10 +157,7 @@ internal class WindowsConsole
             }
         }
 
-        if (!_initialCursorVisibility.HasValue && GetCursorVisibility (out CursorVisibility visibility))
-        {
-            _initialCursorVisibility = visibility;
-        }
+        SetInitialCursorVisibility();
 
         if (!SetConsoleActiveScreenBuffer (_screenBuffer))
         {
@@ -216,11 +214,11 @@ internal class WindowsConsole
         }
         else if (info.dwSize > 50)
         {
-            visibility = CursorVisibility.Box;
+            visibility = CursorVisibility.Default;
         }
         else
         {
-            visibility = CursorVisibility.Underline;
+            visibility = CursorVisibility.Default;
         }
 
         return true;
@@ -815,6 +813,11 @@ internal class WindowsConsole
     [StructLayout (LayoutKind.Sequential)]
     public struct ConsoleCursorInfo
     {
+        /// <summary>
+        /// The percentage of the character cell that is filled by the cursor.This value is between 1 and 100.
+        /// The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal
+        /// line at the bottom of the cell.
+        /// </summary>
         public uint dwSize;
         public bool bVisible;
     }
@@ -1436,6 +1439,8 @@ internal class WindowsDriver : ConsoleDriver
 #if HACK_CHECK_WINCHANGED
         _mainLoopDriver.WinChanged = ChangeWin;
 #endif
+
+        WinConsole?.SetInitialCursorVisibility ();
         return new MainLoop (_mainLoopDriver);
     }
 

+ 4 - 3
Terminal.Gui/View/View.cs

@@ -32,10 +32,11 @@ namespace Terminal.Gui;
 ///         <see cref="Enabled"/>, <see cref="Visible"/>, and <see cref="CanFocus"/> will receive focus.
 ///     </para>
 ///     <para>
-///         Views that are focusable should implement the <see cref="PositionCursor"/> to make sure that the cursor is
-///         placed in a location that makes sense. Unix terminals do not have a way of hiding the cursor, so it can be
+///         Views that are focusable should override <see cref="PositionCursor"/> to make sure that the cursor is
+///         placed in a location that makes sense. Some terminals do not have a way of hiding the cursor, so it can be
 ///         distracting to have the cursor left at the last focused view. So views should make sure that they place the
-///         cursor in a visually sensible place.
+///         cursor in a visually sensible place. The default implementation of <see cref="PositionCursor"/> will place the
+///         cursor at either the hotkey (if defined) or <c>0,0</c>.
 ///     </para>
 ///     <para>
 ///         The View defines the base functionality for user interface elements in Terminal.Gui. Views can contain one or

+ 18 - 16
Terminal.Gui/View/ViewSubViews.cs

@@ -484,7 +484,9 @@ public partial class View
         }
     }
 
-    /// <summary>Method invoked when a view gets focus.</summary>
+    /// <summary>
+    /// Called when a view gets focus.
+    /// </summary>
     /// <param name="view">The view that is losing focus.</param>
     /// <returns><c>true</c>, if the event was handled, <c>false</c> otherwise.</returns>
     public virtual bool OnEnter (View view)
@@ -513,18 +515,16 @@ public partial class View
             return true;
         }
 
-        // BUGBUG: This is a hack to ensure that the cursor is hidden when the view loses focus.
-        // BUGBUG: This is not needed as the minloop will take care of this.
-        //Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-
         return false;
     }
 
-    /// <summary>Returns the currently focused view inside this view, or null if nothing is focused.</summary>
+    // BUGBUG: This API is poorly defined and implemented. It does not specify what it means if THIS view is focused and has no subviews.
+    /// <summary>Returns the currently focused Subview inside this view, or null if nothing is focused.</summary>
     /// <value>The focused.</value>
     public View Focused { get; private set; }
 
-    /// <summary>Returns the most focused view in the chain of subviews (the leaf view that has the focus).</summary>
+    // BUGBUG: This API is poorly defined and implemented. It does not specify what it means if THIS view is focused and has no subviews.
+    /// <summary>Returns the most focused Subview in the chain of subviews (the leaf view that has the focus).</summary>
     /// <value>The most focused View.</value>
     public View MostFocused
     {
@@ -852,19 +852,21 @@ public partial class View
         return view.Focused is { } ? GetMostFocused (view.Focused) : view;
     }
 
+    /// <summary>
+    /// Gets or sets the cursor style to be used when the view is focused. The default is <see cref="CursorVisibility.Invisible"/>.
+    /// </summary>
+    public CursorVisibility CursorVisibility { get; set; } = CursorVisibility.Invisible;
+
     /// <summary>
     ///     Positions the cursor in the right position based on the currently focused view in the chain.
     /// </summary>
     /// <remarks>
     ///     <para>
-    ///         Views that are focusable and want the cursor visible should override <see cref="PositionCursor"/>,
-    ///         use <see cref="Move"/> to place the cursor in a location that makes sense, use
-    ///         <see cref="ConsoleDriver.SetCursorVisibility"/>
-    ///         to make the cursor visible, and return the position where the cursor was placed.
-    ///     </para>
-    ///     <para>
-    ///         Unix terminals do not have  a way of hiding the cursor, so it can be distracting to have the cursor left at
-    ///         the last focused view. Views should make sure that they place the cursor in a visually sensible place.
+    ///         Views that are focusable should override <see cref="PositionCursor"/> to make sure that the cursor is
+    ///         placed in a location that makes sense. Some terminals do not have a way of hiding the cursor, so it can be
+    ///         distracting to have the cursor left at the last focused view. So views should make sure that they place the
+    ///         cursor in a visually sensible place. The default implementation of <see cref="PositionCursor"/> will place the
+    ///         cursor at either the hotkey (if defined) or <c>0,0</c>.
     ///     </para>
     /// </remarks>
     /// <returns>Viewport-relative cursor position. Return <see langword="null"/> to ensure the cursor is not visible.</returns>
@@ -872,7 +874,7 @@ public partial class View
     {
         if (IsInitialized && CanFocus && HasFocus && ContentSize.HasValue)
         {
-            // Base class will position the cursor at the end of the text.
+            // By default, position the cursor at the hotkey (if any) or 0, 0.
             Point location = Viewport.Location;
             location.X = TextFormatter.HotKeyPos == -1 ? 0 : TextFormatter.CursorPosition;
             location.Y = 0;

+ 1 - 10
Terminal.Gui/Views/Button.cs

@@ -137,14 +137,6 @@ public class Button : View
     /// <summary></summary>
     public bool NoPadding { get; set; }
 
-    ///// <inheritdoc/>
-    //public override bool OnEnter (View view)
-    //{
-    //    Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-    //    return base.OnEnter (view);
-    //}
-
     /// <inheritdoc/>
     public override Point? PositionCursor ()
     {
@@ -155,8 +147,7 @@ public class Button : View
                 if (TextFormatter.Text [i] == Text [0])
                 {
                     Move (i, 0);
-
-                    return null;//new (i,0);
+                    return null; // Don't show the cursor
                 }
             }
         }

+ 0 - 11
Terminal.Gui/Views/CheckBox.cs

@@ -94,14 +94,6 @@ public class CheckBox : View
         }
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>Called when the <see cref="Checked"/> property changes. Invokes the <see cref="Toggled"/> event.</summary>
     /// <remarks>
     /// </remarks>
@@ -150,9 +142,6 @@ public class CheckBox : View
         return true;
     }
 
-    /// <inheritdoc/>
-    public override Point? PositionCursor () { Move (0, 0); return Point.Empty; }
-
     /// <summary>Toggled event, raised when the <see cref="CheckBox"/> is toggled.</summary>
     /// <remarks>
     /// <para>

+ 0 - 7
Terminal.Gui/Views/ColorPicker.cs

@@ -188,13 +188,6 @@ public class ColorPicker : View
         }
     }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
 
     /// <summary>Add the commands.</summary>
     private void AddCommands ()

+ 0 - 11
Terminal.Gui/Views/FrameView.cs

@@ -39,15 +39,4 @@ public class FrameView : View
     [SerializableConfigurationProperty (Scope = typeof (ThemeScope))]
     [JsonConverter (typeof (JsonStringEnumConverter))]
     public static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single;
-
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        if (Subviews.Count == 0 || !Subviews.Any (subview => subview.CanFocus))
-        {
-            Application.Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
-        return base.OnEnter (view);
-    }
 }

+ 0 - 9
Terminal.Gui/Views/GraphView/GraphView.cs

@@ -277,15 +277,6 @@ public class GraphView : View
         }
     }
 
-    /// <inheritdoc/>
-    /// <remarks>Also ensures that cursor is invisible after entering the <see cref="GraphView"/>.</remarks>
-    public override bool OnEnter (View view)
-    {
-        Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>Scrolls the graph down 1 page.</summary>
     public void PageDown () { Scroll (0, -1 * CellSize.Y * Viewport.Height); }
 

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

@@ -31,7 +31,6 @@ public class HexView : View
     private const int displayWidth = 9;
 
     private int bpl;
-    private CursorVisibility desiredCursorVisibility = CursorVisibility.Default;
     private long displayStart, pos;
     private SortedDictionary<long, byte> edits = [];
     private bool firstNibble, leftSide;
@@ -50,6 +49,7 @@ public class HexView : View
         // BUG: This will always call the most-derived definition of CanFocus.
         // Either seal it or don't set it here.
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
         leftSide = true;
         firstNibble = true;
 
@@ -129,21 +129,6 @@ public class HexView : View
         }
     }
 
-    /// <summary>Get / Set the wished cursor when the field is focused</summary>
-    public CursorVisibility DesiredCursorVisibility
-    {
-        get => desiredCursorVisibility;
-        set
-        {
-            if (desiredCursorVisibility != value && HasFocus)
-            {
-                Application.Driver.SetCursorVisibility (value);
-            }
-
-            desiredCursorVisibility = value;
-        }
-    }
-
     /// <summary>
     ///     Sets or gets the offset into the <see cref="Stream"/> that will displayed at the top of the
     ///     <see cref="HexView"/>
@@ -462,14 +447,6 @@ public class HexView : View
     /// <param name="e">The key value pair.</param>
     public virtual void OnEdited (HexViewEditEventArgs e) { Edited?.Invoke (this, e); }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>
     ///     Method used to invoke the <see cref="PositionChanged"/> event passing the <see cref="HexViewEventArgs"/>
     ///     arguments.

+ 0 - 7
Terminal.Gui/Views/Label.cs

@@ -64,11 +64,4 @@ public class Label : View
 
         return true;
     }
-
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-        return base.OnEnter (view);
-    }
 }

+ 1 - 6
Terminal.Gui/Views/ListView.cs

@@ -700,11 +700,6 @@ public class ListView : View
     /// <inheritdoc/>
     public override bool OnEnter (View view)
     {
-        //if (IsInitialized)
-        //{
-        //    Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-        //}
-
         if (_lastSelectedItem != _selected)
         {
             EnsureSelectedItemVisible ();
@@ -792,7 +787,7 @@ public class ListView : View
 
         Move (x, y);
 
-        return null;//new Point (x, y);
+        return null; // Don't show the cursor
     }
 
     /// <summary>This event is invoked when this <see cref="ListView"/> is being drawn before rendering.</summary>

+ 2 - 9
Terminal.Gui/Views/Menu/Menu.cs

@@ -958,7 +958,8 @@ internal sealed class Menu : View
             {
                 Move (2, 1 + _currentChild);
 
-                return null;//new (2, 1 + _currentChild);
+                return null; // Don't show the cursor
+
             }
         }
 
@@ -1334,14 +1335,6 @@ internal sealed class Menu : View
         return pos;
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     protected override void Dispose (bool disposing)
     {
         if (Application.Current is { })

+ 2 - 9
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -621,7 +621,7 @@ public class MenuBar : View
                 pos++;
                 Move (pos + 1, 0);
 
-                return new (pos +1, 0);
+                return null; // Don't show the cursor
             }
 
             pos += _leftPadding
@@ -631,7 +631,7 @@ public class MenuBar : View
                           : 0)
                    + _rightPadding;
         }
-        return null;
+        return null; // Don't show the cursor
     }
 
     // Activates the menu, handles either first focus, or activating an entry when it was already active
@@ -1651,13 +1651,6 @@ public class MenuBar : View
 
     #region Mouse Handling
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
 
     /// <inheritdoc/>
     public override bool OnLeave (View view)

+ 0 - 8
Terminal.Gui/Views/ProgressBar.cs

@@ -198,14 +198,6 @@ public class ProgressBar : View
         }
     }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <summary>Notifies the <see cref="ProgressBar"/> that some progress has taken place.</summary>
     /// <remarks>
     ///     If the <see cref="ProgressBar"/> is percentage mode, it switches to activity mode. If is in activity mode, the

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

@@ -276,14 +276,6 @@ public class RadioGroup : View
         }
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool? OnInvokingKeyBindings (Key keyEvent)
     {
@@ -371,7 +363,7 @@ public class RadioGroup : View
         }
 
         Move (x, y);
-        return new Point (x, y);
+        return null; // Don't show the cursor
     }
 
     /// <summary>Allow to invoke the <see cref="SelectedItemChanged"/> after their creation.</summary>

+ 0 - 7
Terminal.Gui/Views/ScrollBarView.cs

@@ -667,13 +667,6 @@ public class ScrollBarView : View
         }
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
 
     /// <summary>Only used for a hosted view that will update and redraw the scrollbars.</summary>
     public virtual void Refresh () { ShowHideScrollBars (); }

+ 1 - 12
Terminal.Gui/Views/ScrollView.cs

@@ -384,17 +384,6 @@ public class ScrollView : View
         DrawScrollBars ();
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        if (Subviews.Count == 0 || !Subviews.Any (subview => subview.CanFocus))
-        {
-            Application.Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool OnKeyDown (Key a)
     {
@@ -461,7 +450,7 @@ public class ScrollView : View
         {
             Move (0, 0);
 
-            return null;//Point.Empty;
+            return null; // Don't show the cursor
         }
         return base.PositionCursor ();
     }

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

@@ -245,6 +245,7 @@ public class Slider<T> : View
         Width = Dim.Auto (Dim.DimAutoStyle.Content);
         Height = Dim.Auto (Dim.DimAutoStyle.Content);
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
 
         _options = options ?? new List<SliderOption<T>> ();
 
@@ -255,15 +256,6 @@ public class Slider<T> : View
         SetDefaultStyle ();
         SetCommands ();
 
-        // When we lose focus of the View(Slider), if we are range selecting we stop it.
-        Leave += (s, e) =>
-                 {
-                     //if (_settingRange == true) {
-                     //	_settingRange = false;
-                     //}
-                     Driver.SetCursorVisibility (CursorVisibility.Invisible);
-                 };
-
         Enter += (s, e) => { };
 
         // BUGBUG: This should not be needed - Need to ensure SetRelativeLayout gets called during EndInit
@@ -888,17 +880,6 @@ public class Slider<T> : View
     /// <inheritdoc/>
     public override Point? PositionCursor ()
     {
-        //base.PositionCursor ();
-
-        if (HasFocus)
-        {
-            Driver?.SetCursorVisibility (CursorVisibility.Default);
-        }
-        else
-        {
-            Driver?.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
         if (TryGetPositionByOption (FocusedOption, out (int x, int y) position))
         {
             if (IsInitialized && Viewport.Contains (position.x, position.y))
@@ -908,7 +889,7 @@ public class Slider<T> : View
                 return new (position.x, position.x);
             }
         }
-        return null;
+        return base.PositionCursor ();
     }
 
     /// <inheritdoc/>

+ 0 - 8
Terminal.Gui/Views/StatusBar.cs

@@ -215,14 +215,6 @@ public class StatusBar : View
         }
     }
 
-    ///<inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool? OnInvokingKeyBindings (Key keyEvent)
     {

+ 0 - 7
Terminal.Gui/Views/TabView.cs

@@ -1204,13 +1204,6 @@ public class TabView : View
             }
         }
 
-        public override bool OnEnter (View view)
-        {
-            Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-            return base.OnEnter (view);
-        }
-
         private int GetUnderlineYPosition ()
         {
             if (_host.Style.TabsOnBottom)

+ 0 - 3
Terminal.Gui/Views/TableView/TableView.cs

@@ -978,8 +978,6 @@ public class TableView : View
     {
         if (TableIsNullOrInvisible ())
         {
-            //PositionCursor ();
-
             return false;
         }
 
@@ -1530,7 +1528,6 @@ public class TableView : View
             SelectedRow = match;
             EnsureValidSelection ();
             EnsureSelectedCellIsVisible ();
-            //PositionCursor ();
             SetNeedsDisplay ();
 
             return true;

+ 2 - 12
Terminal.Gui/Views/TextField.cs

@@ -36,6 +36,7 @@ public class TextField : View
         Height = 1;
 
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
         Used = true;
         WantMousePositionReports = true;
 
@@ -931,7 +932,7 @@ public class TextField : View
             ShowContextMenu ();
         }
 
-        SetNeedsDisplay ();
+        //SetNeedsDisplay ();
 
         return true;
 
@@ -1035,17 +1036,6 @@ public class TextField : View
         _isDrawing = false;
     }
 
-    ///// <inheritdoc/>
-    //public override bool OnEnter (View view)
-    //{
-    //    if (IsInitialized)
-    //    {
-    //        Application.Driver.SetCursorVisibility (CursorVisibility.Default);
-    //    }
-
-    //    return base.OnEnter (view);
-    //}
-
     /// <inheritdoc/>
     public override bool? OnInvokingKeyBindings (Key a)
     {

+ 0 - 24
Terminal.Gui/Views/TextValidateField.cs

@@ -598,22 +598,6 @@ namespace Terminal.Gui
             }
         }
 
-        /// <inheritdoc/>
-        public override bool OnEnter (View view)
-        {
-            Application.Driver.SetCursorVisibility (CursorVisibility.Default);
-
-            return base.OnEnter (view);
-        }
-
-        /// <inheritdoc/>
-        public override bool OnLeave (View view)
-        {
-            Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
-            return base.OnLeave (view);
-        }
-
         /// <inheritdoc/>
         public override bool OnProcessKeyDown (Key a)
         {
@@ -659,14 +643,6 @@ namespace Terminal.Gui
             }
             Move (curPos, 0);
 
-            if (curPos < 0 || curPos >= Viewport.Width)
-            {
-                Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
-            }
-            else
-            {
-                Application.Driver.SetCursorVisibility (CursorVisibility.Default);
-            }
             return new (curPos, 0);
         }
 

+ 49 - 60
Terminal.Gui/Views/TextView.cs

@@ -243,7 +243,7 @@ internal class TextModel
 
         foreach (Rune rune in str.EnumerateRunes ())
         {
-            cells.Add (new() { Rune = rune, ColorScheme = colorScheme });
+            cells.Add (new () { Rune = rune, ColorScheme = colorScheme });
         }
 
         return cells;
@@ -906,7 +906,7 @@ internal class TextModel
 
         foreach (Rune rune in str.ToRunes ())
         {
-            cells.Add (new() { Rune = rune, ColorScheme = colorScheme });
+            cells.Add (new () { Rune = rune, ColorScheme = colorScheme });
         }
 
         return cells;
@@ -918,7 +918,7 @@ internal class TextModel
 
         foreach (Rune rune in runes)
         {
-            cells.Add (new() { Rune = rune, ColorScheme = colorScheme });
+            cells.Add (new () { Rune = rune, ColorScheme = colorScheme });
         }
 
         return cells;
@@ -1979,9 +1979,6 @@ public class TextView : View
     private WordWrapManager? _wrapManager;
     private bool _wrapNeeded;
 
-    /// <summary>Get or sets the cursor to be used when the text view has focus.</summary>
-
-    public CursorVisibility DesiredCursorVisibility { get; set; } = CursorVisibility.Default;
 
     /// <summary>
     ///     Initializes a <see cref="TextView"/> on the specified area, with dimensions controlled with the X, Y, Width
@@ -1990,6 +1987,7 @@ public class TextView : View
     public TextView ()
     {
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
         Used = true;
 
         _model.LinesLoaded += Model_LinesLoaded!;
@@ -2512,7 +2510,7 @@ public class TextView : View
 
         _currentCulture = Thread.CurrentThread.CurrentUICulture;
 
-        ContextMenu = new() { MenuItems = BuildContextMenuBarItem () };
+        ContextMenu = new () { MenuItems = BuildContextMenuBarItem () };
         ContextMenu.KeyChanged += ContextMenu_KeyChanged!;
 
         KeyBindings.Add ((KeyCode)ContextMenu.Key, KeyBindingScope.HotKey, Command.ShowContextMenu);
@@ -2782,7 +2780,7 @@ public class TextView : View
         }
     }
 
-    /// <summary>Get or sets the selecting.</summary>
+    /// <summary>Get or sets whether the user is currently selecting text.</summary>
     public bool Selecting { get; set; }
 
     /// <summary>Start column position of the selected text.</summary>
@@ -2970,7 +2968,7 @@ public class TextView : View
             ClearRegion ();
 
             _historyText.Add (
-                              new() { new (GetCurrentLine ()) },
+                              new () { new (GetCurrentLine ()) },
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -3009,14 +3007,14 @@ public class TextView : View
 
         if (Selecting)
         {
-            _historyText.Add (new() { new (GetCurrentLine ()) }, CursorPosition);
+            _historyText.Add (new () { new (GetCurrentLine ()) }, CursorPosition);
 
             ClearSelectedRegion ();
 
             List<RuneCell> currentLine = GetCurrentLine ();
 
             _historyText.Add (
-                              new() { new (currentLine) },
+                              new () { new (currentLine) },
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -3053,14 +3051,14 @@ public class TextView : View
 
         if (Selecting)
         {
-            _historyText.Add (new() { new (GetCurrentLine ()) }, CursorPosition);
+            _historyText.Add (new () { new (GetCurrentLine ()) }, CursorPosition);
 
             ClearSelectedRegion ();
 
             List<RuneCell> currentLine = GetCurrentLine ();
 
             _historyText.Add (
-                              new() { new (currentLine) },
+                              new () { new (currentLine) },
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -3314,7 +3312,7 @@ public class TextView : View
             && !ev.Flags.HasFlag (MouseFlags.Button1TripleClicked)
             && !ev.Flags.HasFlag (ContextMenu!.MouseFlags))
         {
-            return false;
+            return base.OnMouseEvent (ev);
         }
 
         if (!CanFocus)
@@ -3671,20 +3669,11 @@ public class TextView : View
             ClearRegion (viewport.Left, row, right, bottom);
         }
 
-        PositionCursor ();
+        //PositionCursor ();
 
         _isDrawing = false;
     }
 
-    /// <inheritdoc/>
-    public override bool OnEnter (View view)
-    {
-        //TODO: Improve it by handling read only mode of the text field
-        Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-
-        return base.OnEnter (view);
-    }
-
     /// <inheritdoc/>
     public override bool? OnInvokingKeyBindings (Key a)
     {
@@ -3777,7 +3766,7 @@ public class TextView : View
             List<RuneCell> runeList = contents is null ? new () : TextModel.ToRuneCellList (contents);
             List<RuneCell> currentLine = GetCurrentLine ();
 
-            _historyText.Add (new() { new (currentLine) }, CursorPosition);
+            _historyText.Add (new () { new (currentLine) }, CursorPosition);
 
             List<List<RuneCell>> addedLine = new () { new (currentLine), runeList };
 
@@ -3791,7 +3780,7 @@ public class TextView : View
             CurrentRow++;
 
             _historyText.Add (
-                              new() { new (GetCurrentLine ()) },
+                              new () { new (GetCurrentLine ()) },
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -3812,7 +3801,7 @@ public class TextView : View
             if (Selecting)
             {
                 _historyText.ReplaceLast (
-                                          new() { new (GetCurrentLine ()) },
+                                          new () { new (GetCurrentLine ()) },
                                           CursorPosition,
                                           HistoryText.LineStatus.Original
                                          );
@@ -3836,7 +3825,7 @@ public class TextView : View
             return null;
         }
 
-        if (Selecting)
+        if (Application.MouseGrabView == this && Selecting)
         {
             // BUGBUG: customized rect aren't supported now because the Redraw isn't using the Intersect method.
             //var minRow = Math.Min (Math.Max (Math.Min (selectionStartRow, currentRow) - topRow, 0), Frame.Height);
@@ -3882,7 +3871,7 @@ public class TextView : View
             return new (col, CurrentRow - _topRow);
         }
 
-        return null;
+        return null; // Hide cursor
     }
 
     /// <summary>Redoes the latest changes.</summary>
@@ -4276,7 +4265,7 @@ public class TextView : View
         var endCol = (int)(end & 0xffffffff);
         List<RuneCell> line = _model.GetLine (startRow);
 
-        _historyText.Add (new() { new (line) }, new (startCol, startRow));
+        _historyText.Add (new () { new (line) }, new (startCol, startRow));
 
         List<List<RuneCell>> removedLines = new ();
 
@@ -4366,7 +4355,7 @@ public class TextView : View
             // Delete backwards 
             List<RuneCell> currentLine = GetCurrentLine ();
 
-            _historyText.Add (new() { new (currentLine) }, CursorPosition);
+            _historyText.Add (new () { new (currentLine) }, CursorPosition);
 
             currentLine.RemoveAt (CurrentColumn - 1);
 
@@ -4378,7 +4367,7 @@ public class TextView : View
             CurrentColumn--;
 
             _historyText.Add (
-                              new() { new (currentLine) },
+                              new () { new (currentLine) },
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -4406,7 +4395,7 @@ public class TextView : View
             int prowIdx = CurrentRow - 1;
             List<RuneCell> prevRow = _model.GetLine (prowIdx);
 
-            _historyText.Add (new() { new (prevRow) }, CursorPosition);
+            _historyText.Add (new () { new (prevRow) }, CursorPosition);
 
             List<List<RuneCell>> removedLines = new () { new (prevRow) };
 
@@ -4430,7 +4419,7 @@ public class TextView : View
             CurrentRow--;
 
             _historyText.Add (
-                              new() { GetCurrentLine () },
+                              new () { GetCurrentLine () },
                               new (CurrentColumn, prowIdx),
                               HistoryText.LineStatus.Replaced
                              );
@@ -4459,7 +4448,7 @@ public class TextView : View
                 return true;
             }
 
-            _historyText.Add (new() { new (currentLine) }, CursorPosition);
+            _historyText.Add (new () { new (currentLine) }, CursorPosition);
 
             List<List<RuneCell>> removedLines = new () { new (currentLine) };
 
@@ -4473,7 +4462,7 @@ public class TextView : View
             _model.RemoveLine (CurrentRow + 1);
 
             _historyText.Add (
-                              new() { new (currentLine) },
+                              new () { new (currentLine) },
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -4487,12 +4476,12 @@ public class TextView : View
         }
         else
         {
-            _historyText.Add ([[..currentLine]], CursorPosition);
+            _historyText.Add ([ [.. currentLine]], CursorPosition);
 
             currentLine.RemoveAt (CurrentColumn);
 
             _historyText.Add (
-                              [[..currentLine]],
+                              [ [.. currentLine]],
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -4824,7 +4813,7 @@ public class TextView : View
 
         List<RuneCell> line = GetCurrentLine ();
 
-        _historyText.Add (new() { new (line) }, CursorPosition);
+        _historyText.Add (new () { new (line) }, CursorPosition);
 
         // Optimize single line
         if (lines.Count == 1)
@@ -4833,7 +4822,7 @@ public class TextView : View
             CurrentColumn += lines [0].Count;
 
             _historyText.Add (
-                              new() { new (line) },
+                              new () { new (line) },
                               CursorPosition,
                               HistoryText.LineStatus.Replaced
                              );
@@ -4903,7 +4892,7 @@ public class TextView : View
         Adjust ();
 
         _historyText.Add (
-                          new() { new (line) },
+                          new () { new (line) },
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -4922,7 +4911,7 @@ public class TextView : View
 
         SetWrapModel ();
 
-        _historyText.Add (new() { new (GetCurrentLine ()) }, CursorPosition);
+        _historyText.Add (new () { new (GetCurrentLine ()) }, CursorPosition);
 
         if (Selecting)
         {
@@ -4943,7 +4932,7 @@ public class TextView : View
         {
             if (Used)
             {
-                Insert (new() { Rune = a.AsRune, ColorScheme = colorScheme });
+                Insert (new () { Rune = a.AsRune, ColorScheme = colorScheme });
                 CurrentColumn++;
 
                 if (CurrentColumn >= _leftColumn + Frame.Width)
@@ -4954,13 +4943,13 @@ public class TextView : View
             }
             else
             {
-                Insert (new() { Rune = a.AsRune, ColorScheme = colorScheme });
+                Insert (new () { Rune = a.AsRune, ColorScheme = colorScheme });
                 CurrentColumn++;
             }
         }
 
         _historyText.Add (
-                          new() { new (GetCurrentLine ()) },
+                          new () { new (GetCurrentLine ()) },
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -4998,7 +4987,7 @@ public class TextView : View
             return;
         }
 
-        _historyText.Add (new() { new (currentLine) }, CursorPosition);
+        _historyText.Add (new () { new (currentLine) }, CursorPosition);
 
         if (currentLine.Count == 0)
         {
@@ -5057,7 +5046,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [[..GetCurrentLine ()]],
+                          [ [.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5097,7 +5086,7 @@ public class TextView : View
             return;
         }
 
-        _historyText.Add ([[..currentLine]], CursorPosition);
+        _historyText.Add ([ [.. currentLine]], CursorPosition);
 
         if (currentLine.Count == 0)
         {
@@ -5135,7 +5124,7 @@ public class TextView : View
                 ];
 
                 _historyText.Add (
-                                  [..removedLine],
+                                  [.. removedLine],
                                   CursorPosition,
                                   HistoryText.LineStatus.Removed
                                  );
@@ -5164,7 +5153,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [[..GetCurrentLine ()]],
+                          [ [.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5188,14 +5177,14 @@ public class TextView : View
 
         List<RuneCell> currentLine = GetCurrentLine ();
 
-        _historyText.Add ([[..GetCurrentLine ()]], CursorPosition);
+        _historyText.Add ([ [.. GetCurrentLine ()]], CursorPosition);
 
         if (CurrentColumn == 0)
         {
             DeleteTextBackwards ();
 
             _historyText.ReplaceLast (
-                                      [[..GetCurrentLine ()]],
+                                      [ [.. GetCurrentLine ()]],
                                       CursorPosition,
                                       HistoryText.LineStatus.Replaced
                                      );
@@ -5234,7 +5223,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [[..GetCurrentLine ()]],
+                          [ [.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5256,14 +5245,14 @@ public class TextView : View
 
         List<RuneCell> currentLine = GetCurrentLine ();
 
-        _historyText.Add ([[..GetCurrentLine ()]], CursorPosition);
+        _historyText.Add ([ [.. GetCurrentLine ()]], CursorPosition);
 
         if (currentLine.Count == 0 || CurrentColumn == currentLine.Count)
         {
             DeleteTextForwards ();
 
             _historyText.ReplaceLast (
-                                      [[..GetCurrentLine ()]],
+                                      [ [.. GetCurrentLine ()]],
                                       CursorPosition,
                                       HistoryText.LineStatus.Replaced
                                      );
@@ -5293,7 +5282,7 @@ public class TextView : View
         }
 
         _historyText.Add (
-                          [[..GetCurrentLine ()]],
+                          [ [.. GetCurrentLine ()]],
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );
@@ -5665,13 +5654,13 @@ public class TextView : View
 
             if (currentLine.Count > 0 && currentLine [CurrentColumn - 1].Rune.Value == '\t')
             {
-                _historyText.Add (new() { new (currentLine) }, CursorPosition);
+                _historyText.Add (new () { new (currentLine) }, CursorPosition);
 
                 currentLine.RemoveAt (CurrentColumn - 1);
                 CurrentColumn--;
 
                 _historyText.Add (
-                                  new() { new (GetCurrentLine ()) },
+                                  new () { new (GetCurrentLine ()) },
                                   CursorPosition,
                                   HistoryText.LineStatus.Replaced
                                  );
@@ -6112,7 +6101,7 @@ public class TextView : View
 
         List<RuneCell> currentLine = GetCurrentLine ();
 
-        _historyText.Add (new() { new (currentLine) }, CursorPosition);
+        _historyText.Add (new () { new (currentLine) }, CursorPosition);
 
         if (Selecting)
         {
@@ -6145,7 +6134,7 @@ public class TextView : View
         CurrentColumn = 0;
 
         _historyText.Add (
-                          new() { new (GetCurrentLine ()) },
+                          new () { new (GetCurrentLine ()) },
                           CursorPosition,
                           HistoryText.LineStatus.Replaced
                          );

+ 1 - 9
Terminal.Gui/Views/TileView.cs

@@ -979,14 +979,6 @@ public class TileView : View
             DrawSplitterSymbol ();
         }
 
-        //public override bool OnEnter (View view)
-        //{
-        //    Driver.SetCursorVisibility (CursorVisibility.Default);
-        //    PositionCursor ();
-
-        //    return base.OnEnter (view);
-        //}
-
         public override Point? PositionCursor ()
         {
             base.PositionCursor ();
@@ -994,7 +986,7 @@ public class TileView : View
             Point location = moveRuneRenderLocation ?? new Point (Viewport.Width / 2, Viewport.Height / 2);
             Move (location.X, location.Y);
 
-            return null; //location;
+            return null; // Hide cursor
         }
 
         /// <summary>

+ 1 - 11
Terminal.Gui/Views/Toplevel.cs

@@ -340,11 +340,6 @@ public partial class Toplevel : View
             if (Focused is null)
             {
                 EnsureFocus ();
-
-                if (Focused is null)
-                {
-                    Driver.SetCursorVisibility (CursorVisibility.Invisible);
-                }
             }
 
             return null;
@@ -368,12 +363,7 @@ public partial class Toplevel : View
 
         var cursor2 = base.PositionCursor ();
 
-        if (Focused is null)
-        {
-            Driver.SetCursorVisibility (CursorVisibility.Invisible);
-        }
-
-        return null;//cursor2;
+        return null; 
     }
 
     /// <summary>

+ 17 - 56
Terminal.Gui/Views/TreeView/TreeView.cs

@@ -64,8 +64,6 @@ public class TreeView<T> : View, ITreeView where T : class
     /// <summary>Cached result of <see cref="BuildLineMap"/></summary>
     private IReadOnlyCollection<Branch<T>> cachedLineMap;
 
-    private CursorVisibility desiredCursorVisibility = CursorVisibility.Invisible;
-
     private KeyCode objectActivationKey = KeyCode.Enter;
     private int scrollOffsetHorizontal;
     private int scrollOffsetVertical;
@@ -325,27 +323,6 @@ public class TreeView<T> : View, ITreeView where T : class
     /// <summary>The current number of rows in the tree (ignoring the controls bounds).</summary>
     public int ContentHeight => BuildLineMap ().Count ();
 
-    /// <summary>
-    ///     Get / Set the wished cursor when the tree is focused. Only applies when <see cref="MultiSelect"/> is true.
-    ///     Defaults to <see cref="CursorVisibility.Invisible"/>.
-    /// </summary>
-    public CursorVisibility DesiredCursorVisibility
-    {
-        get => MultiSelect ? desiredCursorVisibility : CursorVisibility.Invisible;
-        set
-        {
-            if (desiredCursorVisibility != value)
-            {
-                desiredCursorVisibility = value;
-
-                if (HasFocus)
-                {
-                    Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-                }
-            }
-        }
-    }
-
     /// <summary>
     ///     Gets the <see cref="CollectionNavigator"/> that searches the <see cref="Objects"/> collection as the user
     ///     types.
@@ -468,7 +445,6 @@ public class TreeView<T> : View, ITreeView where T : class
             // TODO: Should this be cancelable?
             ObjectActivatedEventArgs<T> e = new (this, o);
             OnObjectActivated (e);
-            //PositionCursor ();
             return true;
         }
         return false;
@@ -675,8 +651,6 @@ public class TreeView<T> : View, ITreeView where T : class
         // search for next branch that begins with that letter
         var characterAsStr = character.ToString ();
         AdjustSelectionToNext (b => AspectGetter (b.Model).StartsWith (characterAsStr, caseSensitivity));
-
-        //PositionCursor ();
     }
 
     /// <summary>
@@ -1183,8 +1157,6 @@ public class TreeView<T> : View, ITreeView where T : class
     ///<inheritdoc/>
     public override bool OnEnter (View view)
     {
-        Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
-
         if (SelectedObject is null && Objects.Any ())
         {
             SelectedObject = Objects.First ();
@@ -1201,37 +1173,27 @@ public class TreeView<T> : View, ITreeView where T : class
             return false;
         }
 
-        try
+        // BUGBUG: this should move to OnInvokingKeyBindings
+        // If not a keybinding, is the key a searchable key press?
+        if (CollectionNavigatorBase.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation)
         {
-            // BUGBUG: this should move to OnInvokingKeyBindings
-            // If not a keybinding, is the key a searchable key press?
-            if (CollectionNavigatorBase.IsCompatibleKey (keyEvent) && AllowLetterBasedNavigation)
-            {
-                IReadOnlyCollection<Branch<T>> map;
-
-                // If there has been a call to InvalidateMap since the last time
-                // we need a new one to reflect the new exposed tree state
-                map = BuildLineMap ();
+            IReadOnlyCollection<Branch<T>> map;
 
-                // Find the current selected object within the tree
-                int current = map.IndexOf (b => b.Model == SelectedObject);
-                int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)keyEvent);
+            // If there has been a call to InvalidateMap since the last time
+            // we need a new one to reflect the new exposed tree state
+            map = BuildLineMap ();
 
-                if (newIndex is int && newIndex != -1)
-                {
-                    SelectedObject = map.ElementAt ((int)newIndex).Model;
-                    EnsureVisible (selectedObject);
-                    SetNeedsDisplay ();
+            // Find the current selected object within the tree
+            int current = map.IndexOf (b => b.Model == SelectedObject);
+            int? newIndex = KeystrokeNavigator?.GetNextMatchingItem (current, (char)keyEvent);
 
-                    return true;
-                }
-            }
-        }
-        finally
-        {
-            if (IsInitialized)
+            if (newIndex is int && newIndex != -1)
             {
-                //PositionCursor ();
+                SelectedObject = map.ElementAt ((int)newIndex).Model;
+                EnsureVisible (selectedObject);
+                SetNeedsDisplay ();
+
+                return true;
             }
         }
 
@@ -1250,9 +1212,8 @@ public class TreeView<T> : View, ITreeView where T : class
             if (idx - ScrollOffsetVertical >= 0 && idx - ScrollOffsetVertical < Viewport.Height)
             {
                 Move (0, idx - ScrollOffsetVertical);
-                Application.Driver.SetCursorVisibility (DesiredCursorVisibility);
 
-                return null;//new Point (0, idx - ScrollOffsetVertical);
+                return MultiSelect ? new (0, idx - ScrollOffsetVertical) : null ;
             }
         }
         return base.PositionCursor ();

+ 1 - 3
UICatalog/Scenarios/CharacterMap.cs

@@ -326,6 +326,7 @@ internal class CharMap : View
     {
         ColorScheme = Colors.ColorSchemes ["Dialog"];
         CanFocus = true;
+        CursorVisibility = CursorVisibility.Default;
 
         ContentSize = new (RowWidth, (MaxCodePoint / 16 + 2) * _rowHeight);
 
@@ -810,13 +811,10 @@ internal class CharMap : View
             && Cursor.Y > 0
             && Cursor.Y < Viewport.Height)
         {
-            Driver.SetCursorVisibility (CursorVisibility.Default);
             Move (Cursor.X, Cursor.Y);
         }
         else
         {
-            Driver.SetCursorVisibility (CursorVisibility.Invisible);
-
             return null;
         }
 

+ 10 - 11
UICatalog/Scenarios/Editor.cs

@@ -267,7 +267,6 @@ public class Editor : Scenario
         _textView.UnwrappedCursorPosition += (s, e) =>
                                              {
                                                  siCursorPosition.Title = $"Ln {e.Point.Y + 1}, Col {e.Point.X + 1}";
-                                                 statusBar.SetNeedsDisplay ();
                                              };
 
         Top.Add (statusBar);
@@ -587,7 +586,7 @@ public class Editor : Scenario
                        new ("_Invisible", "", () => SetCursor (CursorVisibility.Invisible))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility
+                           Checked = _textView.CursorVisibility
                                      == CursorVisibility.Invisible
                        }
                       );
@@ -596,7 +595,7 @@ public class Editor : Scenario
                        new ("_Box", "", () => SetCursor (CursorVisibility.Box))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility == CursorVisibility.Box
+                           Checked = _textView.CursorVisibility == CursorVisibility.Box
                        }
                       );
 
@@ -604,7 +603,7 @@ public class Editor : Scenario
                        new ("_Underline", "", () => SetCursor (CursorVisibility.Underline))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility
+                           Checked = _textView.CursorVisibility
                                      == CursorVisibility.Underline
                        }
                       );
@@ -616,7 +615,7 @@ public class Editor : Scenario
                        new ("  _Default", "", () => SetCursor (CursorVisibility.Default))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility
+                           Checked = _textView.CursorVisibility
                                      == CursorVisibility.Default
                        }
                       );
@@ -625,7 +624,7 @@ public class Editor : Scenario
                        new ("  _Vertical", "", () => SetCursor (CursorVisibility.Vertical))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility
+                           Checked = _textView.CursorVisibility
                                      == CursorVisibility.Vertical
                        }
                       );
@@ -634,7 +633,7 @@ public class Editor : Scenario
                        new ("  V_ertical Fix", "", () => SetCursor (CursorVisibility.VerticalFix))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility == CursorVisibility.VerticalFix
+                           Checked = _textView.CursorVisibility == CursorVisibility.VerticalFix
                        }
                       );
 
@@ -642,7 +641,7 @@ public class Editor : Scenario
                        new ("  B_ox Fix", "", () => SetCursor (CursorVisibility.BoxFix))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility
+                           Checked = _textView.CursorVisibility
                                      == CursorVisibility.BoxFix
                        }
                       );
@@ -651,13 +650,13 @@ public class Editor : Scenario
                        new ("  U_nderline Fix", "", () => SetCursor (CursorVisibility.UnderlineFix))
                        {
                            CheckType = MenuItemCheckStyle.Radio,
-                           Checked = _textView.DesiredCursorVisibility == CursorVisibility.UnderlineFix
+                           Checked = _textView.CursorVisibility == CursorVisibility.UnderlineFix
                        }
                       );
 
         void SetCursor (CursorVisibility visibility)
         {
-            _textView.DesiredCursorVisibility = visibility;
+            _textView.CursorVisibility = visibility;
             var title = "";
 
             switch (visibility)
@@ -698,7 +697,7 @@ public class Editor : Scenario
 
             foreach (MenuItem menuItem in menuItems)
             {
-                menuItem.Checked = menuItem.Title.Equals (title) && visibility == _textView.DesiredCursorVisibility;
+                menuItem.Checked = menuItem.Title.Equals (title) && visibility == _textView.CursorVisibility;
             }
         }
 

+ 1 - 1
UICatalog/Scenarios/TreeViewFileSystem.cs

@@ -223,7 +223,7 @@ public class TreeViewFileSystem : Scenario
     {
         _miCursor.Checked = !_miCursor.Checked;
 
-        _treeViewFiles.DesiredCursorVisibility =
+        _treeViewFiles.CursorVisibility =
             _miCursor.Checked == true ? CursorVisibility.Default : CursorVisibility.Invisible;
     }
 

+ 148 - 0
UnitTests/Application/CursorTests.cs

@@ -0,0 +1,148 @@
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ApplicationTests;
+
+public class CursorTests
+{
+    private readonly ITestOutputHelper _output;
+
+    public CursorTests (ITestOutputHelper output)
+    {
+        _output = output;
+        ConsoleDriver.RunningUnitTests = true;
+    }
+
+    private class TestView : View
+    {
+        public Point? TestLocation { get; set; }
+
+        /// <inheritdoc />
+        public override Point? PositionCursor ()
+        {
+            if (TestLocation.HasValue && HasFocus)
+            {
+                Driver.SetCursorVisibility (CursorVisibility.Default);
+            }
+            return TestLocation;
+        }
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void PositionCursor_No_Focus_Returns_False ()
+    {
+        Assert.False (Application.PositionCursor (null));
+
+        TestView view = new ()
+        {
+            CanFocus = false,
+            Width = 1,
+            Height = 1,
+        };
+        view.TestLocation = new Point (0, 0);
+        Assert.False (Application.PositionCursor (view));
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void PositionCursor_No_Position_Returns_False ()
+    {
+        TestView view = new ()
+        {
+            CanFocus = false,
+            Width = 1,
+            Height = 1,
+        };
+
+        view.CanFocus = true;
+        view.SetFocus();
+        Assert.False (Application.PositionCursor (view));
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void PositionCursor_No_IntersectSuperView_Returns_False ()
+    {
+        View superView = new ()
+        {
+            Width = 1,
+            Height = 1,
+        };
+
+        TestView view = new ()
+        {
+            CanFocus = false,
+            X = 1,
+            Y =1,
+            Width = 1,
+            Height = 1,
+        };
+        superView.Add (view);
+
+        view.CanFocus = true;
+        view.SetFocus ();
+        view.TestLocation = new Point (0, 0);
+        Assert.False (Application.PositionCursor (view));
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void PositionCursor_Position_OutSide_SuperView_Returns_False ()
+    {
+        View superView = new ()
+        {
+            Width = 1,
+            Height = 1,
+        };
+
+        TestView view = new ()
+        {
+            CanFocus = false,
+            X = 0,
+            Y = 0,
+            Width = 2,
+            Height = 2,
+        };
+        superView.Add (view);
+
+        view.CanFocus = true;
+        view.SetFocus ();
+        view.TestLocation = new Point (1, 1);
+        Assert.False (Application.PositionCursor (view));
+    }
+
+    [Fact, Trait("BUGBUG", "Views without subviews don't support Focused or MostFocused")]
+    [SetupFakeDriver]
+    public void PositionCursor_Focused_With_Position_Returns_True ()
+    {
+        TestView view = new ()
+        {
+            CanFocus = false,
+            Width = 1,
+            Height = 1,
+        };
+        view.CanFocus = true;
+        view.SetFocus ();
+        view.TestLocation = new Point (0, 0);
+        Assert.False (Application.PositionCursor (view));  // BUGBUG: This should be true
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void PositionCursor_Defaults_Invisible ()
+    {
+        View view = new ()
+        {
+            CanFocus = true,
+            Width = 1,
+            Height = 1,
+        };
+        view.SetFocus();
+
+        Assert.True (view.HasFocus);
+        Assert.False (Application.PositionCursor (view));
+        Application.Driver.GetCursorVisibility (out CursorVisibility cursor);
+        Assert.Equal (CursorVisibility.Invisible, cursor);
+    }
+
+}

+ 32 - 4
UnitTests/View/NavigationTests.cs

@@ -869,7 +869,7 @@ public class NavigationTests
         Assert.Equal (0, screen.Y);
         var found = View.FindDeepestView (top, 0, 0);
         Assert.Equal (top.Border, found);
- 
+
         Assert.Equal (0, found.Frame.X);
         Assert.Equal (0, found.Frame.Y);
         Assert.Equal (new Point (3, 2), top.ScreenToFrame (3, 2));
@@ -934,14 +934,14 @@ public class NavigationTests
         Assert.Equal (3, screen.Y);
         found = View.FindDeepestView (top, 4, 3);
         Assert.Equal (view, found);
-        
+
         Assert.Equal (new Point (9, -1), view.ScreenToFrame (13, 2));
         screen = view.ViewportToScreen (new (10, 0, 0, 0));
         Assert.Equal (14, screen.X);
         Assert.Equal (3, screen.Y);
         found = View.FindDeepestView (top, 14, 3);
         Assert.Equal (top, found);
-        
+
         Assert.Equal (new Point (10, 0), view.ScreenToFrame (14, 3));
         screen = view.ViewportToScreen (new (11, 1, 0, 0));
         Assert.Equal (15, screen.X);
@@ -1042,7 +1042,7 @@ public class NavigationTests
         Assert.Equal (15, screen.X);
         Assert.Equal (4, screen.Y);
         Assert.Equal (top, View.FindDeepestView (top, 14, 3));
-        
+
         // view
         Assert.Equal (new Point (-7, -5), view.ScreenToFrame (0, 0));
         screen = view.Margin.ViewportToScreen (new (-6, -4, 0, 0));
@@ -1550,4 +1550,32 @@ public class NavigationTests
         // Assert does Not throw NullReferenceException
         top.SetFocus ();
     }
+
+    // View.Focused & View.MostFocused tests
+
+    // View.Focused - No subviews
+    [Fact, Trait("BUGBUG", "Fix in Issue #3444")]
+    public void Focused_NoSubviews ()
+    {
+        var view = new View ();
+        Assert.Null (view.Focused);
+
+        view.CanFocus = true;
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.Null (view.Focused); // BUGBUG: Should be view
+    }
+
+    // View.MostFocused - No subviews
+    [Fact, Trait ("BUGBUG", "Fix in Issue #3444")]
+    public void Most_Focused_NoSubviews ()
+    {
+        var view = new View ();
+        Assert.Null (view.Focused);
+
+        view.CanFocus = true;
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.Null (view.MostFocused); // BUGBUG: Should be view
+    }
 }

+ 0 - 34
UnitTests/Views/StatusBarTests.cs

@@ -190,40 +190,6 @@ CTRL-O Open {
         Assert.Equal ("AnchorEnd(1)", sb.Y.ToString ());
         Assert.Equal (Dim.Fill (), sb.Width);
         Assert.Equal (1, sb.Height);
-
-        var driver = new FakeDriver ();
-        Application.Init (driver);
-
-        sb = new StatusBar ();
-
-        driver.SetCursorVisibility (CursorVisibility.Default);
-        driver.GetCursorVisibility (out CursorVisibility cv);
-        Assert.Equal (CursorVisibility.Default, cv);
-        Assert.True (FakeConsole.CursorVisible);
-
-        Application.Iteration += (s, a) =>
-                                 {
-                                     Assert.Equal (24, sb.Frame.Y);
-
-                                     driver.SetWindowSize (driver.Cols, 15);
-
-                                     Assert.Equal (14, sb.Frame.Y);
-
-                                     sb.OnEnter (null);
-                                     driver.GetCursorVisibility (out cv);
-                                     Assert.Equal (CursorVisibility.Invisible, cv);
-                                     Assert.False (FakeConsole.CursorVisible);
-
-                                     Application.RequestStop ();
-                                 };
-
-        var top = new Toplevel ();
-       top.Add (sb);
-
-        Application.Run (top);
-
-        top.Dispose ();
-        Application.Shutdown ();
     }
 
     [Fact]

+ 2 - 2
UnitTests/Views/TextViewTests.cs

@@ -1072,7 +1072,7 @@ This is the second line.
         Assert.Equal (0, tv.LeftColumn);
         Assert.Equal (Point.Empty, tv.CursorPosition);
         Application.PositionCursor (top);
-        Assert.Equal (CursorVisibility.Default, tv.DesiredCursorVisibility);
+        Assert.Equal (CursorVisibility.Default, tv.CursorVisibility);
 
         for (var i = 0; i < 12; i++)
         {
@@ -1124,7 +1124,7 @@ This is the second line.
 
         Assert.Equal (0, tv.TopRow);
         Application.PositionCursor (top);
-        Assert.Equal (CursorVisibility.Default, tv.DesiredCursorVisibility);
+        Assert.Equal (CursorVisibility.Default, tv.CursorVisibility);
 
         for (var i = 0; i < 12; i++)
         {

+ 5 - 5
UnitTests/Views/TreeViewTests.cs

@@ -101,7 +101,7 @@ public class TreeViewTests
 
     [Fact]
     [AutoInitShutdown]
-    public void DesiredCursorVisibility_MultiSelect ()
+    public void CursorVisibility_MultiSelect ()
     {
         var tv = new TreeView { Width = 20, Height = 10 };
 
@@ -116,13 +116,13 @@ public class TreeViewTests
 
         Assert.True (tv.MultiSelect);
         Assert.True (tv.HasFocus);
-        Assert.Equal (CursorVisibility.Invisible, tv.DesiredCursorVisibility);
+        Assert.Equal (CursorVisibility.Invisible, tv.CursorVisibility);
 
         tv.SelectAll ();
-        tv.DesiredCursorVisibility = CursorVisibility.Default;
-        Application.Refresh ();
+        tv.CursorVisibility = CursorVisibility.Default;
+        Application.PositionCursor (top);
         Application.Driver.GetCursorVisibility (out CursorVisibility visibility);
-        Assert.Equal (CursorVisibility.Default, tv.DesiredCursorVisibility);
+        Assert.Equal (CursorVisibility.Default, tv.CursorVisibility);
         Assert.Equal (CursorVisibility.Default, visibility);
     }