Browse Source

Fixed WindowsDriver cursor issue with true color

Tig 1 year ago
parent
commit
207c974327

+ 1 - 1
Terminal.Gui/ConsoleDrivers/NetDriver.cs

@@ -1315,7 +1315,7 @@ internal class NetDriver : ConsoleDriver
     {
         EnsureCursorVisibility ();
 
-        if (Col >= 0 && Col < Cols && Row >= 0 && Row < Rows)
+        if (Col >= 0 && Col < Cols && Row >= 0 && Row <= Rows)
         {
             SetCursorPosition (Col, Row);
             SetWindowPosition (0, Row);

+ 109 - 45
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -18,6 +18,7 @@
 using System.ComponentModel;
 using System.Diagnostics;
 using System.Runtime.InteropServices;
+using System.Text;
 using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping;
 
 namespace Terminal.Gui;
@@ -110,6 +111,7 @@ internal class WindowsConsole
             }
 
             _stringBuilder.Append (EscSeqUtils.CSI_RestoreCursorPosition);
+            _stringBuilder.Append (EscSeqUtils.CSI_HideCursor);
 
             var s = _stringBuilder.ToString ();
 
@@ -129,6 +131,11 @@ internal class WindowsConsole
         return result;
     }
 
+    public bool WriteANSI (string ansi)
+    {
+        return WriteConsole (_screenBuffer, ansi, (uint)ansi.Length, out uint _, null);
+    }
+
     public void ReadFromConsoleOutput (Size size, Coord coords, ref SmallRect window)
     {
         _screenBuffer = CreateConsoleScreenBuffer (
@@ -167,7 +174,10 @@ internal class WindowsConsole
         }
     }
 
-    public bool SetCursorPosition (Coord position) { return SetConsoleCursorPosition (_screenBuffer, position); }
+    public bool SetCursorPosition (Coord position)
+    {
+        return SetConsoleCursorPosition (_screenBuffer, position);
+    }
 
     public void SetInitialCursorVisibility ()
     {
@@ -574,14 +584,14 @@ internal class WindowsConsole
         public readonly override string ToString ()
         {
             return EventType switch
-                   {
-                       EventType.Focus => FocusEvent.ToString (),
-                       EventType.Key => KeyEvent.ToString (),
-                       EventType.Menu => MenuEvent.ToString (),
-                       EventType.Mouse => MouseEvent.ToString (),
-                       EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (),
-                       _ => "Unknown event type: " + EventType
-                   };
+            {
+                EventType.Focus => FocusEvent.ToString (),
+                EventType.Key => KeyEvent.ToString (),
+                EventType.Menu => MenuEvent.ToString (),
+                EventType.Mouse => MouseEvent.ToString (),
+                EventType.WindowBufferSize => WindowBufferSizeEvent.ToString (),
+                _ => "Unknown event type: " + EventType
+            };
         }
     }
 
@@ -954,7 +964,6 @@ internal class WindowsDriver : ConsoleDriver
 {
     private readonly bool _isWindowsTerminal;
 
-    private CursorVisibility _cachedCursorVisibility;
     private WindowsConsole.SmallRect _damageRegion;
     private bool _isButtonDoubleClicked;
     private bool _isButtonPressed;
@@ -997,9 +1006,6 @@ internal class WindowsDriver : ConsoleDriver
 
     public WindowsConsole WinConsole { get; private set; }
 
-    /// <inheritdoc/>
-    public override bool EnsureCursorVisibility () { return WinConsole is null || WinConsole.EnsureCursorVisibility (); }
-
     public WindowsConsole.KeyEventRecord FromVKPacketToKeyEventRecord (WindowsConsole.KeyEventRecord keyEvent)
     {
         if (keyEvent.wVirtualKeyCode != (VK)ConsoleKey.Packet)
@@ -1046,25 +1052,12 @@ internal class WindowsDriver : ConsoleDriver
         };
     }
 
-    /// <inheritdoc/>
-    public override bool GetCursorVisibility (out CursorVisibility visibility)
-    {
-        if (WinConsole is { })
-        {
-            return WinConsole.GetCursorVisibility (out visibility);
-        }
-
-        visibility = _cachedCursorVisibility;
-
-        return true;
-    }
-
     public override bool IsRuneSupported (Rune rune) { return base.IsRuneSupported (rune) && rune.IsBmp; }
 
     public override void Refresh ()
     {
         UpdateScreen ();
-        WinConsole?.SetInitialCursorVisibility ();
+        //WinConsole?.SetInitialCursorVisibility ();
         UpdateCursor ();
     }
 
@@ -1138,13 +1131,6 @@ internal class WindowsDriver : ConsoleDriver
         }
     }
 
-    /// <inheritdoc/>
-    public override bool SetCursorVisibility (CursorVisibility visibility)
-    {
-        _cachedCursorVisibility = visibility;
-
-        return WinConsole is null || WinConsole.SetCursorVisibility (visibility);
-    }
 
     #region Not Implemented
 
@@ -1168,9 +1154,13 @@ internal class WindowsDriver : ConsoleDriver
         return new WindowsConsole.ConsoleKeyInfoEx (cki, capslock, numlock, scrolllock);
     }
 
+    #region Cursor Handling
+
+    private CursorVisibility? _cachedCursorVisibility;
+
     public override void UpdateCursor ()
     {
-        if (Col < 0 || Row < 0 || Col > Cols || Row > Rows)
+        if (Col < 0 || Row < 0 || Col >= Cols || Row >= Rows)
         {
             GetCursorVisibility (out CursorVisibility cursorVisibility);
             _cachedCursorVisibility = cursorVisibility;
@@ -1179,16 +1169,90 @@ internal class WindowsDriver : ConsoleDriver
             return;
         }
 
-        SetCursorVisibility (_cachedCursorVisibility);
-
         var position = new WindowsConsole.Coord
         {
             X = (short)Col,
             Y = (short)Row
         };
-        WinConsole?.SetCursorPosition (position);
+
+        if (Force16Colors)
+        {
+            WinConsole?.SetCursorPosition (position);
+        }
+        else
+        {
+            var sb = new StringBuilder ();
+            sb.Append (EscSeqUtils.CSI_SetCursorPosition (position.Y + 1, position.X + 1));
+            WinConsole?.WriteANSI (sb.ToString ());
+        }
+
+        if (_cachedCursorVisibility is { })
+        {
+            SetCursorVisibility (_cachedCursorVisibility.Value);
+        }
+        //EnsureCursorVisibility ();
+    }
+
+    /// <inheritdoc/>
+    public override bool GetCursorVisibility (out CursorVisibility visibility)
+    {
+        if (WinConsole is { })
+        {
+            return WinConsole.GetCursorVisibility (out visibility);
+        }
+
+        visibility = _cachedCursorVisibility ?? CursorVisibility.Default;
+
+        return true;
+    }
+
+    /// <inheritdoc/>
+    public override bool SetCursorVisibility (CursorVisibility visibility)
+    {
+        _cachedCursorVisibility = visibility;
+
+        if (Force16Colors)
+        {
+            return WinConsole is null || WinConsole.SetCursorVisibility (visibility);
+        }
+        else
+        {
+            var sb = new StringBuilder ();
+            sb.Append (visibility != CursorVisibility.Invisible ? EscSeqUtils.CSI_ShowCursor : EscSeqUtils.CSI_HideCursor);
+            return WinConsole?.WriteANSI (sb.ToString ()) ?? false;
+        }
     }
 
+    /// <inheritdoc/>
+    public override bool EnsureCursorVisibility ()
+    {
+        if (Force16Colors)
+        {
+            return WinConsole is null || WinConsole.EnsureCursorVisibility ();
+        }
+        else
+        {
+            var sb = new StringBuilder ();
+            sb.Append (_cachedCursorVisibility != CursorVisibility.Invisible ? EscSeqUtils.CSI_ShowCursor : EscSeqUtils.CSI_HideCursor);
+            return WinConsole?.WriteANSI (sb.ToString ()) ?? false;
+        }
+
+        if (!(Col >= 0 && Row >= 0 && Col < Cols && Row < Rows))
+        {
+            GetCursorVisibility (out CursorVisibility cursorVisibility);
+            _cachedCursorVisibility = cursorVisibility;
+            SetCursorVisibility (CursorVisibility.Invisible);
+
+            return false;
+        }
+
+        SetCursorVisibility (_cachedCursorVisibility ?? CursorVisibility.Default);
+
+        return _cachedCursorVisibility == CursorVisibility.Default;
+    }
+
+    #endregion Cursor Handling
+
     public override void UpdateScreen ()
     {
         Size windowSize = WinConsole?.GetConsoleBufferWindow (out Point _) ?? new Size (Cols, Rows);
@@ -1550,13 +1614,13 @@ internal class WindowsDriver : ConsoleDriver
                         // returned (e.g. on ENG OemPlus un-shifted is =, not +). This is important
                         // for key persistence ("Ctrl++" vs. "Ctrl+=").
                         mappedChar = keyInfo.Key switch
-                                     {
-                                         ConsoleKey.OemPeriod => '.',
-                                         ConsoleKey.OemComma => ',',
-                                         ConsoleKey.OemPlus => '+',
-                                         ConsoleKey.OemMinus => '-',
-                                         _ => mappedChar
-                                     };
+                        {
+                            ConsoleKey.OemPeriod => '.',
+                            ConsoleKey.OemComma => ',',
+                            ConsoleKey.OemPlus => '+',
+                            ConsoleKey.OemMinus => '-',
+                            _ => mappedChar
+                        };
                     }
 
                     // Return the mappedChar with they modifiers. Because mappedChar is un-shifted, if Shift was down

+ 25 - 0
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -64,6 +64,11 @@ public partial class View
         get => _frame;
         set
         {
+            if (_frame == value)
+            {
+                return;
+            }
+
             _frame = value with { Width = Math.Max (value.Width, 0), Height = Math.Max (value.Height, 0) };
 
             // If Frame gets set, by definition, the View is now LayoutStyle.Absolute, so
@@ -161,6 +166,11 @@ public partial class View
         set
         {
             _x = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (X)} cannot be null");
+
+            if (Equals (_x, value))
+            {
+                return;
+            }
             OnResizeNeeded ();
         }
     }
@@ -193,6 +203,11 @@ public partial class View
         get => VerifyIsInitialized (_y, nameof (Y));
         set
         {
+            if (Equals (_y, value))
+            {
+                return;
+            }
+
             _y = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Y)} cannot be null");
             OnResizeNeeded ();
         }
@@ -226,6 +241,11 @@ public partial class View
         get => VerifyIsInitialized (_height, nameof (Height));
         set
         {
+            if (Equals (_height, value))
+            {
+                return;
+            }
+
             _height = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Height)} cannot be null");
 
             if (AutoSize)
@@ -276,6 +296,11 @@ public partial class View
         get => VerifyIsInitialized (_width, nameof (Width));
         set
         {
+            if (Equals (_width, value))
+            {
+                return;
+            }
+
             _width = value ?? throw new ArgumentNullException (nameof (value), @$"{nameof (Width)} cannot be null");
 
             if (AutoSize)

+ 9 - 5
Terminal.Gui/View/ViewScrolling.cs

@@ -201,20 +201,24 @@ public partial class View
                     value.X = 0;
                 }
             }
-            
-            _viewportLocation = value.Location;
 
             Thickness thickness = GetAdornmentsThickness ();
             Size newSize = new (value.Size.Width + thickness.Horizontal,
                                 value.Size.Height + thickness.Vertical);
             if (newSize == Frame.Size)
             {
-                // The change is not changing the Frame, so we don't need to update it. 
-                // Just call SetRelativeLayout6 to update the layout.
-                SetNeedsLayout ();
+                // The change is not changing the Frame, so we don't need to update it.
+                // Just call SetNeedsLayout to update the layout.
+                if (_viewportLocation != value.Location)
+                {
+                    _viewportLocation = value.Location;
+                    SetNeedsLayout ();
+                }
                 return;
             }
 
+            _viewportLocation = value.Location;
+
             // Update the Frame because we made it bigger or smaller which impacts subviews.
             Frame = Frame with
             {

+ 2 - 5
Terminal.Gui/View/ViewSubViews.cs

@@ -838,16 +838,13 @@ public partial class View
             return;
         }
 
-        // BUGBUG: v2 - This needs to support children of Frames too
+        // BUGBUG: v2 - This needs to support Subviews of Adornments too
 
         if (Focused is null && SuperView is { })
         {
             SuperView.EnsureFocus ();
         }
-        else if (Focused?.Visible == true
-                 && Focused?.Enabled == true
-                 && Focused?.Frame.Width > 0
-                 && Focused.Frame.Height > 0)
+        else if (Focused is { Visible: true, Enabled: true, Frame: { Width: > 0, Height: > 0 } })
         {
             Focused.PositionCursor ();
         }

+ 36 - 28
UICatalog/Scenarios/CharacterMap.cs

@@ -33,17 +33,24 @@ public class CharacterMap : Scenario
     private CharMap _charMap;
 
     // Don't create a Window, just return the top-level view
-    public override void Init ()
+    public override void Main ()
     {
         Application.Init ();
-        Top = new ();
-        Top.ColorScheme = Colors.ColorSchemes ["Base"];
-    }
 
-    public override void Setup ()
-    {
-        _charMap = new () { X = 0, Y = 1, Height = Dim.Fill () };
-        Top.Add (_charMap);
+        var top = new Window ()
+        {
+            BorderStyle = LineStyle.None
+        };
+
+        _charMap = new () { 
+            X = 0, 
+            Y = 0 ,
+            Width = Dim.Fill (),
+            Height = Dim.Fill () };
+        top.Add (_charMap);
+
+#if OTHER_CONTROLS
+        _charMap.Y = 1;
 
         var jumpLabel = new Label
         {
@@ -52,19 +59,19 @@ public class CharacterMap : Scenario
             HotKeySpecifier = (Rune)'_',
             Text = "_Jump To Code Point:"
         };
-        Top.Add (jumpLabel);
+        top.Add (jumpLabel);
 
         var jumpEdit = new TextField
         {
             X = Pos.Right (jumpLabel) + 1, Y = Pos.Y (_charMap), Width = 10, Caption = "e.g. 01BE3"
         };
-        Top.Add (jumpEdit);
+        top.Add (jumpEdit);
 
         _errorLabel = new ()
         {
             X = Pos.Right (jumpEdit) + 1, Y = Pos.Y (_charMap), ColorScheme = Colors.ColorSchemes ["error"], Text = "err"
         };
-        Top.Add (_errorLabel);
+        top.Add (_errorLabel);
 
 #if TEXT_CHANGED_TO_JUMP
         jumpEdit.TextChanged += JumpEdit_TextChanged;
@@ -80,7 +87,6 @@ public class CharacterMap : Scenario
         }
 #endif
         _categoryList = new () { X = Pos.Right (_charMap), Y = Pos.Bottom (jumpLabel), Height = Dim.Fill () };
-
         _categoryList.FullRowSelect = true;
 
         //jumpList.Style.ShowHeaders = false;
@@ -136,10 +142,8 @@ public class CharacterMap : Scenario
                                                  _charMap.StartCodePoint = table.Data.ToArray () [args.NewRow].Start;
                                              };
 
-        Top.Add (_categoryList);
+        top.Add (_categoryList);
 
-        _charMap.SelectedCodePoint = 0;
-        _charMap.SetFocus ();
 
         // TODO: Replace this with Dim.Auto when that's ready
         _categoryList.Initialized += _categoryList_Initialized;
@@ -165,7 +169,14 @@ public class CharacterMap : Scenario
                     )
             ]
         };
-        Top.Add (menu);
+        top.Add (menu);
+#endif // OTHER_CONTROLS
+
+        _charMap.SelectedCodePoint = 0;
+        _charMap.SetFocus ();
+
+        Application.Run (top);
+        top.Dispose ();
     }
 
     private void _categoryList_Initialized (object sender, EventArgs e) { _charMap.Width = Dim.Fill () - _categoryList.Width; }
@@ -380,6 +391,7 @@ internal class CharMap : View
                         {
                             ScrollHorizontal (COLUMN_WIDTH);
                         }
+
                         return true;
                     }
                    );
@@ -424,6 +436,7 @@ internal class CharMap : View
                     {
                         SelectedCodePoint = MaxCodePoint;
                         Viewport = Viewport with { Y = SelectedCodePoint / 16 * _rowHeight };
+
                         return true;
                     }
                    );
@@ -496,7 +509,7 @@ internal class CharMap : View
         set => throw new NotImplementedException ();
     }
 
-    public static int MaxCodePoint = UnicodeRange.Ranges.Max(r => r.End);// 0x10FFFF;
+    public static int MaxCodePoint = UnicodeRange.Ranges.Max (r => r.End);
 
     /// <summary>
     ///     Specifies the starting offset for the character map. The default is 0x2500 which is the Box Drawing
@@ -507,6 +520,10 @@ internal class CharMap : View
         get => _selected;
         set
         {
+            if (_selected == value)
+            {
+                return;
+            }
             _selected = value;
 
             if (IsInitialized)
@@ -538,7 +555,6 @@ internal class CharMap : View
                     Viewport = Viewport with { X = col - width };
                 }
             }
-
             SetNeedsDisplay ();
             SelectedCodePointChanged?.Invoke (this, new (SelectedCodePoint, null));
         }
@@ -583,8 +599,6 @@ internal class CharMap : View
 
         ClearVisibleContent ();
 
-        Rectangle oldClip = ClipToViewport ();
-
         int cursorCol = Cursor.X + Viewport.X - RowLabelWidth - 1;
         int cursorRow = Cursor.Y + Viewport.Y - 1;
 
@@ -653,10 +667,6 @@ internal class CharMap : View
                     rune = new (scalar);
                 }
 
-                if (rune == (Rune)'!')
-                {
-
-                }
                 int width = rune.GetColumns ();
 
                 if (!ShowGlyphWidths || (y + Viewport.Y) % _rowHeight > 0)
@@ -711,7 +721,7 @@ internal class CharMap : View
             // Draw row label (U+XXXX_)
             Move (0, y);
 
-            Driver.SetAttribute (HasFocus && (y + Viewport.Y - 1 == cursorRow) ? ColorScheme.HotFocus : ColorScheme.HotNormal);
+            Driver.SetAttribute (HasFocus && y + Viewport.Y - 1 == cursorRow ? ColorScheme.HotFocus : ColorScheme.HotNormal);
 
             if (!ShowGlyphWidths || (y + Viewport.Y) % _rowHeight > 0)
             {
@@ -722,8 +732,6 @@ internal class CharMap : View
                 Driver.AddStr (new (' ', RowLabelWidth));
             }
         }
-
-       Driver.Clip = oldClip;
     }
 
     public override bool OnEnter (View view)
@@ -950,7 +958,7 @@ internal class CharMap : View
                                                         document.RootElement,
                                                         new
                                                             JsonSerializerOptions
-                                                            { WriteIndented = true }
+                                                        { WriteIndented = true }
                                                        );
             }