瀏覽代碼

Autocomplete

Tig 11 月之前
父節點
當前提交
04e569aabc

+ 3 - 6
Terminal.Gui/Text/Autocomplete/AutocompleteBase.cs

@@ -36,17 +36,14 @@ public abstract class AutocompleteBase : IAutocomplete
     /// <inheritdoc/>
     public abstract ColorScheme ColorScheme { get; set; }
 
-    // TODO: Update to use Key instead of KeyCode
     /// <inheritdoc/>
-    public virtual KeyCode SelectionKey { get; set; } = KeyCode.Enter;
+    public virtual Key SelectionKey { get; set; } = Key.Enter;
 
-    // TODO: Update to use Key instead of KeyCode
     /// <inheritdoc/>
-    public virtual KeyCode CloseKey { get; set; } = KeyCode.Esc;
+    public virtual Key CloseKey { get; set; } = Key.Esc;
 
-    // TODO: Update to use Key instead of KeyCode
     /// <inheritdoc/>
-    public virtual KeyCode Reopen { get; set; } = (KeyCode)Key.Space.WithCtrl.WithAlt;
+    public virtual Key Reopen { get; set; } = Key.Space.WithCtrl.WithAlt;
 
     /// <inheritdoc/>
     public virtual AutocompleteContext Context { get; set; }

+ 33 - 36
Terminal.Gui/Text/Autocomplete/IAutocomplete.cs

@@ -8,9 +8,11 @@ namespace Terminal.Gui;
 /// </summary>
 public interface IAutocomplete
 {
-    // TODO: Update to use Key instead of KeyCode
+    /// <summary>Clears <see cref="Suggestions"/></summary>
+    void ClearSuggestions ();
+
     /// <summary>The key that the user can press to close the currently popped autocomplete menu</summary>
-    KeyCode CloseKey { get; set; }
+    Key CloseKey { get; set; }
 
     /// <summary>
     ///     The colors to use to render the overlay. Accessing this property before the Application has been initialized
@@ -21,6 +23,12 @@ public interface IAutocomplete
     /// <summary>The context used by the autocomplete menu.</summary>
     AutocompleteContext Context { get; set; }
 
+    /// <summary>
+    ///     Populates <see cref="Suggestions"/> with all <see cref="Suggestion"/> proposed by
+    ///     <see cref="SuggestionGenerator"/> at the given <paramref name="context"/> (cursor position)
+    /// </summary>
+    void GenerateSuggestions (AutocompleteContext context);
+
     /// <summary>The host control that will use autocomplete.</summary>
     View HostControl { get; set; }
 
@@ -30,19 +38,38 @@ public interface IAutocomplete
     /// <summary>The maximum width of the autocomplete dropdown</summary>
     int MaxWidth { get; set; }
 
+    /// <summary>
+    ///     Handle mouse events before <see cref="HostControl"/> e.g. to make mouse events like report/click apply to the
+    ///     autocomplete control instead of changing the cursor position in the underlying text view.
+    /// </summary>
+    /// <param name="me">The mouse event.</param>
+    /// <param name="fromHost">If was called from the popup or from the host.</param>
+    /// <returns><c>true</c>if the mouse can be handled <c>false</c>otherwise.</returns>
+    bool OnMouseEvent (MouseEvent me, bool fromHost = false);
+
     /// <summary>Gets or sets where the popup will be displayed.</summary>
     bool PopupInsideContainer { get; set; }
 
-    // TODO: Update to use Key instead of KeyCode
+    /// <summary>
+    ///     Handle key events before <see cref="HostControl"/> e.g. to make key events like up/down apply to the
+    ///     autocomplete control instead of changing the cursor position in the underlying text view.
+    /// </summary>
+    /// <param name="a">The key event.</param>
+    /// <returns><c>true</c>if the key can be handled <c>false</c>otherwise.</returns>
+    bool ProcessKey (Key a);
+
+    /// <summary>Renders the autocomplete dialog inside the given <see cref="HostControl"/> at the given point.</summary>
+    /// <param name="renderAt"></param>
+    void RenderOverlay (Point renderAt);
+
     /// <summary>The key that the user can press to reopen the currently popped autocomplete menu</summary>
-    KeyCode Reopen { get; set; }
+    Key Reopen { get; set; }
 
     /// <summary>The currently selected index into <see cref="Suggestions"/> that the user has highlighted</summary>
     int SelectedIdx { get; set; }
 
-    // TODO: Update to use Key instead of KeyCode
     /// <summary>The key that the user must press to accept the currently selected autocomplete suggestion</summary>
-    KeyCode SelectionKey { get; set; }
+    Key SelectionKey { get; set; }
 
     /// <summary>
     ///     Gets or Sets the class responsible for generating <see cref="Suggestions"/> based on a given
@@ -55,34 +82,4 @@ public interface IAutocomplete
 
     /// <summary>True if the autocomplete should be considered open and visible</summary>
     bool Visible { get; set; }
-
-    /// <summary>Clears <see cref="Suggestions"/></summary>
-    void ClearSuggestions ();
-
-    /// <summary>
-    ///     Populates <see cref="Suggestions"/> with all <see cref="Suggestion"/> proposed by
-    ///     <see cref="SuggestionGenerator"/> at the given <paramref name="context"/> (cursor position)
-    /// </summary>
-    void GenerateSuggestions (AutocompleteContext context);
-
-    /// <summary>
-    ///     Handle mouse events before <see cref="HostControl"/> e.g. to make mouse events like report/click apply to the
-    ///     autocomplete control instead of changing the cursor position in the underlying text view.
-    /// </summary>
-    /// <param name="me">The mouse event.</param>
-    /// <param name="fromHost">If was called from the popup or from the host.</param>
-    /// <returns><c>true</c>if the mouse can be handled <c>false</c>otherwise.</returns>
-    bool OnMouseEvent (MouseEvent me, bool fromHost = false);
-
-    /// <summary>
-    ///     Handle key events before <see cref="HostControl"/> e.g. to make key events like up/down apply to the
-    ///     autocomplete control instead of changing the cursor position in the underlying text view.
-    /// </summary>
-    /// <param name="a">The key event.</param>
-    /// <returns><c>true</c>if the key can be handled <c>false</c>otherwise.</returns>
-    bool ProcessKey (Key a);
-
-    /// <summary>Renders the autocomplete dialog inside the given <see cref="HostControl"/> at the given point.</summary>
-    /// <param name="renderAt"></param>
-    void RenderOverlay (Point renderAt);
 }

+ 4 - 4
Terminal.Gui/Text/Autocomplete/PopupAutocomplete.PopUp.cs

@@ -5,16 +5,14 @@ public abstract partial class PopupAutocomplete
 {
     private sealed class Popup : View
     {
-        private readonly PopupAutocomplete _autoComplete;
-
         public Popup (PopupAutocomplete autoComplete)
         {
-            this._autoComplete = autoComplete;
+            _autoComplete = autoComplete;
             CanFocus = true;
             WantMousePositionReports = true;
         }
 
-        protected internal override bool OnMouseEvent  (MouseEvent mouseEvent) { return _autoComplete.OnMouseEvent (mouseEvent); }
+        private readonly PopupAutocomplete _autoComplete;
 
         public override void OnDrawContent (Rectangle viewport)
         {
@@ -25,5 +23,7 @@ public abstract partial class PopupAutocomplete
 
             _autoComplete.RenderOverlay (_autoComplete.LastPopupPos.Value);
         }
+
+        protected internal override bool OnMouseEvent (MouseEvent mouseEvent) { return _autoComplete.OnMouseEvent (mouseEvent); }
     }
 }

+ 66 - 65
Terminal.Gui/Text/Autocomplete/PopupAutocomplete.cs

@@ -6,15 +6,16 @@ namespace Terminal.Gui;
 /// </summary>
 public abstract partial class PopupAutocomplete : AutocompleteBase
 {
-    private bool closed;
-    private ColorScheme colorScheme;
-    private View hostControl;
-    private View top, popup;
-    private int toRenderLength;
-
     /// <summary>Creates a new instance of the <see cref="PopupAutocomplete"/> class.</summary>
     public PopupAutocomplete () { PopupInsideContainer = true; }
 
+    private bool _closed;
+    private ColorScheme _colorScheme;
+    private View _hostControl;
+    private View _top; // _hostControl's SuperView
+    private View _popup;
+    private int toRenderLength;
+
     /// <summary>
     ///     The colors to use to render the overlay. Accessing this property before the Application has been initialized
     ///     will cause an error
@@ -23,44 +24,16 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
     {
         get
         {
-            if (colorScheme is null)
+            if (_colorScheme is null)
             {
-                colorScheme = Colors.ColorSchemes ["Menu"];
+                _colorScheme = Colors.ColorSchemes ["Menu"];
             }
 
-            return colorScheme;
+            return _colorScheme;
         }
-        set => colorScheme = value;
+        set => _colorScheme = value;
     }
 
-    /// <summary>The host control to handle.</summary>
-    public override View HostControl
-    {
-        get => hostControl;
-        set
-        {
-            hostControl = value;
-            top = hostControl.SuperView;
-
-            if (top is { })
-            {
-                top.DrawContent += Top_DrawContent;
-                top.DrawContentComplete += Top_DrawContentComplete;
-                top.Removed += Top_Removed;
-            }
-        }
-    }
-
-    /// <summary>
-    ///     When more suggestions are available than can be rendered the user can scroll down the dropdown list. This
-    ///     indicates how far down they have gone
-    /// </summary>
-    public virtual int ScrollOffset { get; set; }
-
-    #nullable enable
-    private Point? LastPopupPos { get; set; }
-    #nullable restore
-
     /// <inheritdoc/>
     public override void EnsureSelectedIdxIsValid ()
     {
@@ -79,6 +52,24 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
         }
     }
 
+    /// <summary>The host control to handle.</summary>
+    public override View HostControl
+    {
+        get => _hostControl;
+        set
+        {
+            _hostControl = value;
+            _top = _hostControl.SuperView;
+
+            if (_top is { })
+            {
+                _top.DrawContent += Top_DrawContent;
+                _top.DrawContentComplete += Top_DrawContentComplete;
+                _top.Removed += Top_Removed;
+            }
+        }
+    }
+
     /// <summary>
     ///     Handle mouse events before <see cref="HostControl"/> e.g. to make mouse events like report/click apply to the
     ///     autocomplete control instead of changing the cursor position in the underlying text view.
@@ -119,7 +110,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
             if (Visible && HostControl is { })
             {
                 Visible = false;
-                closed = false;
+                _closed = false;
             }
 
             HostControl?.SetNeedsDisplay ();
@@ -127,7 +118,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
             return false;
         }
 
-        if (popup is null || Suggestions.Count == 0)
+        if (_popup is null || Suggestions.Count == 0)
         {
             ManipulatePopup ();
 
@@ -177,7 +168,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
         {
             Visible = true;
             ManipulatePopup ();
-            closed = false;
+            _closed = false;
 
             return false;
         }
@@ -189,11 +180,11 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
             return ReopenSuggestions ();
         }
 
-        if (closed || Suggestions.Count == 0)
+        if (_closed || Suggestions.Count == 0)
         {
             Visible = false;
 
-            if (!closed)
+            if (!_closed)
             {
                 Close ();
             }
@@ -249,7 +240,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
     {
         if (!Context.Canceled && Suggestions.Count > 0 && !Visible && HostControl?.HasFocus == true)
         {
-            ProcessKey (new Key (Suggestions [0].Title [0]));
+            ProcessKey (new (Suggestions [0].Title [0]));
         }
         else if (!Visible || HostControl?.HasFocus == false || Suggestions.Count == 0)
         {
@@ -287,13 +278,13 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
         else
         {
             // don't overspill vertically
-            height = Math.Min (Math.Min (top.Viewport.Height - HostControl.Frame.Bottom, MaxHeight), Suggestions.Count);
+            height = Math.Min (Math.Min (_top.Viewport.Height - HostControl.Frame.Bottom, MaxHeight), Suggestions.Count);
 
             // There is no space below, lets see if can popup on top
-            if (height < Suggestions.Count && HostControl.Frame.Y - top.Frame.Y >= height)
+            if (height < Suggestions.Count && HostControl.Frame.Y - _top.Frame.Y >= height)
             {
                 // Verifies that the upper limit available is greater than the lower limit
-                if (HostControl.Frame.Y > top.Viewport.Height - HostControl.Frame.Y)
+                if (HostControl.Frame.Y > _top.Viewport.Height - HostControl.Frame.Y)
                 {
                     renderAt.Y = Math.Max (HostControl.Frame.Y - Math.Min (Suggestions.Count, MaxHeight), 0);
                     height = Math.Min (Math.Min (Suggestions.Count, MaxHeight), HostControl.Frame.Y);
@@ -340,37 +331,37 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
         else
         {
             // don't overspill horizontally, let's see if it can be displayed on the left
-            if (width > top.Viewport.Width - (renderAt.X + HostControl.Frame.X))
+            if (width > _top.Viewport.Width - (renderAt.X + HostControl.Frame.X))
             {
                 // Verifies that the left limit available is greater than the right limit
-                if (renderAt.X + HostControl.Frame.X > top.Viewport.Width - (renderAt.X + HostControl.Frame.X))
+                if (renderAt.X + HostControl.Frame.X > _top.Viewport.Width - (renderAt.X + HostControl.Frame.X))
                 {
                     renderAt.X -= Math.Min (width, LastPopupPos.Value.X);
                     width = Math.Min (width, LastPopupPos.Value.X);
                 }
                 else
                 {
-                    width = Math.Min (width, top.Viewport.Width - renderAt.X);
+                    width = Math.Min (width, _top.Viewport.Width - renderAt.X);
                 }
             }
         }
 
         if (PopupInsideContainer)
         {
-            popup.Frame = new (
+            _popup.Frame = new (
                                new (HostControl.Frame.X + renderAt.X, HostControl.Frame.Y + renderAt.Y),
                                new (width, height)
                               );
         }
         else
         {
-            popup.Frame = new (
+            _popup.Frame = new (
                                renderAt with { X = HostControl.Frame.X + renderAt.X },
                                new (width, height)
                               );
         }
 
-        popup.Move (0, 0);
+        _popup.Move (0, 0);
 
         for (var i = 0; i < toRender.Length; i++)
         {
@@ -383,7 +374,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
                 Application.Driver?.SetAttribute (ColorScheme.Normal);
             }
 
-            popup.Move (0, i);
+            _popup.Move (0, i);
 
             string text = TextFormatter.ClipOrPad (toRender [i].Title, width);
 
@@ -391,6 +382,12 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
         }
     }
 
+    /// <summary>
+    ///     When more suggestions are available than can be rendered the user can scroll down the dropdown list. This
+    ///     indicates how far down they have gone
+    /// </summary>
+    public virtual int ScrollOffset { get; set; }
+
     /// <summary>
     ///     Closes the Autocomplete context menu if it is showing and <see cref="IAutocomplete.ClearSuggestions"/>
     /// </summary>
@@ -398,7 +395,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
     {
         ClearSuggestions ();
         Visible = false;
-        closed = true;
+        _closed = true;
         HostControl?.SetNeedsDisplay ();
         ManipulatePopup ();
     }
@@ -486,7 +483,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
         if (Suggestions.Count > 0)
         {
             Visible = true;
-            closed = false;
+            _closed = false;
             HostControl?.SetNeedsDisplay ();
 
             return true;
@@ -516,25 +513,29 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
     /// <param name="column"></param>
     protected abstract void SetCursorPosition (int column);
 
+#nullable enable
+    private Point? LastPopupPos { get; set; }
+#nullable restore
+
     private void ManipulatePopup ()
     {
-        if (Visible && popup is null)
+        if (Visible && _popup is null)
         {
-            popup = new Popup (this) { Frame = Rectangle.Empty };
-            top?.Add (popup);
+            _popup = new Popup (this) { Frame = Rectangle.Empty };
+            _top?.Add (_popup);
         }
 
-        if (!Visible && popup is { })
+        if (!Visible && _popup is { })
         {
-            top?.Remove (popup);
-            popup.Dispose ();
-            popup = null;
+            _top?.Remove (_popup);
+            _popup.Dispose ();
+            _popup = null;
         }
     }
 
     private void Top_DrawContent (object sender, DrawEventArgs e)
     {
-        if (!closed)
+        if (!_closed)
         {
             ReopenSuggestions ();
         }
@@ -543,7 +544,7 @@ public abstract partial class PopupAutocomplete : AutocompleteBase
 
         if (Visible)
         {
-            top.BringSubviewToFront (popup);
+            _top.BringSubviewToFront (_popup);
         }
     }