2
0
Эх сурвалжийг харах

Super rough sketch of what generics solution would look like

tznind 7 сар өмнө
parent
commit
bf8879537c

+ 1 - 1
Terminal.Gui/Input/Keyboard/KeyBinding.cs

@@ -11,7 +11,7 @@ namespace Terminal.Gui;
 /// <seealso cref="Application.KeyBindings"/>
 /// <seealso cref="View.KeyBindings"/>
 /// <seealso cref="Command"/>
-public record struct KeyBinding
+public record struct KeyBinding : IInputBinding
 {
     /// <summary>Initializes a new instance.</summary>
     /// <param name="commands">The commands this key binding will invoke.</param>

+ 7 - 0
Terminal.Gui/Input/Mouse/IInputBinding.cs

@@ -0,0 +1,7 @@
+#nullable enable
+namespace Terminal.Gui;
+
+public interface IInputBinding
+{
+    Command [] Commands { get; set; }
+}

+ 1 - 1
Terminal.Gui/Input/Mouse/MouseBinding.cs

@@ -6,7 +6,7 @@ namespace Terminal.Gui;
 /// Provides a collection of <see cref="Command"/> objects for mouse events.
 /// </summary>
 /// <seealso cref="Command"/>
-public record struct MouseBinding
+public record struct MouseBinding : IInputBinding
 {
     /// <summary>Initializes a new instance.</summary>
     /// <param name="commands">The commands this mouse binding will invoke.</param>

+ 37 - 1
Terminal.Gui/Input/Mouse/MouseBindings.cs

@@ -1,12 +1,48 @@
 #nullable enable
 namespace Terminal.Gui;
 
+public abstract class Bindings<TKey, TBind> where TKey: Enum where TBind : IInputBinding, new()
+{
+    private readonly Dictionary<TKey, TBind> _bindings = new ();
+
+    /// <summary>Adds a <see cref="MouseBinding"/> to the collection.</summary>
+    /// <param name="mouseEventArgs"></param>
+    /// <param name="binding"></param>
+    public void Add (TKey mouseEventArgs, TBind binding)
+    {
+        if (TryGet (mouseEventArgs, out TBind _))
+        {
+            throw new InvalidOperationException (@$"A binding for {mouseEventArgs} exists ({binding}).");
+        }
+
+        // IMPORTANT: Add a COPY of the mouseEventArgs. This is needed because ConfigurationManager.Apply uses DeepMemberWiseCopy 
+        // IMPORTANT: update the memory referenced by the key, and Dictionary uses caching for performance, and thus 
+        // IMPORTANT: Apply will update the Dictionary with the new mouseEventArgs, but the old mouseEventArgs will still be in the dictionary.
+        // IMPORTANT: See the ConfigurationManager.Illustrate_DeepMemberWiseCopy_Breaks_Dictionary test for details.
+        _bindings.Add (mouseEventArgs, binding);
+    }
+
+
+    /// <summary>Gets the commands bound with the specified <see cref="MouseFlags"/>.</summary>
+    /// <remarks></remarks>
+    /// <param name="mouseEventArgs">The key to check.</param>
+    /// <param name="binding">
+    ///     When this method returns, contains the commands bound with the specified mouse flags, if the mouse flags are
+    ///     found; otherwise, null. This parameter is passed uninitialized.
+    /// </param>
+    /// <returns><see langword="true"/> if the mouse flags are bound; otherwise <see langword="false"/>.</returns>
+    public bool TryGet (TKey mouseEventArgs, out TBind? binding)
+    {
+        return _bindings.TryGetValue (mouseEventArgs, out binding);
+    }
+}
+
 /// <summary>
 ///     Provides a collection of <see cref="MouseBinding"/> objects bound to a combination of <see cref="MouseFlags"/>.
 /// </summary>
 /// <seealso cref="View.MouseBindings"/>
 /// <seealso cref="Command"/>
-public class MouseBindings
+public class MouseBindings : Bindings<MouseFlags,MouseBinding>
 {
     /// <summary>
     ///     Initializes a new instance. This constructor is used when the <see cref="MouseBindings"/> are not bound to a